diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 144b277438a5..2a65b2f11a88 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -87,7 +87,32 @@
Other Notable Changes
-
-
+
+
+
+ The option
+ services.redis.servers
+ was added to support per-application
+ redis-server which is more secure since
+ Redis databases are only mere key prefixes without any
+ configuration or ACL of their own. Backward-compatibility is
+ preserved by mapping old
+ services.redis.settings to
+ services.redis.servers."".settings,
+ but you are strongly encouraged to name each
+ redis-server instance after the application
+ using it, instead of keeping that nameless one. Except for the
+ nameless
+ services.redis.servers."" still
+ accessible at 127.0.0.1:6379, and to the
+ members of the Unix group redis through the
+ Unix socket /run/redis/redis.sock, all
+ other services.redis.servers.${serverName}
+ are only accessible by default to the members of the Unix
+ group redis-${serverName} through the Unix
+ socket /run/redis-${serverName}/redis.sock.
+
+
+
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index 4418c8142a14..2c75718bb1ed 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -35,3 +35,19 @@ In addition to numerous new and upgraded packages, this release has the followin
Please switch to `claws-mail`, which is Claws Mail's latest release based on GTK+3 and Python 3.
## Other Notable Changes {#sec-release-22.05-notable-changes}
+
+- The option [services.redis.servers](#opt-services.redis.servers) was added
+ to support per-application `redis-server` which is more secure since Redis databases
+ are only mere key prefixes without any configuration or ACL of their own.
+ Backward-compatibility is preserved by mapping old `services.redis.settings`
+ to `services.redis.servers."".settings`, but you are strongly encouraged
+ to name each `redis-server` instance after the application using it,
+ instead of keeping that nameless one.
+ Except for the nameless `services.redis.servers.""`
+ still accessible at `127.0.0.1:6379`,
+ and to the members of the Unix group `redis`
+ through the Unix socket `/run/redis/redis.sock`,
+ all other `services.redis.servers.${serverName}`
+ are only accessible by default
+ to the members of the Unix group `redis-${serverName}`
+ through the Unix socket `/run/redis-${serverName}/redis.sock`.
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index 578d9d9ec8d7..c5513635392c 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -5,17 +5,18 @@ with lib;
let
cfg = config.services.redis;
- ulimitNofile = cfg.maxclients + 32;
-
mkValueString = value:
if value == true then "yes"
else if value == false then "no"
else generators.mkValueStringDefault { } value;
- redisConfig = pkgs.writeText "redis.conf" (generators.toKeyValue {
+ redisConfig = settings: pkgs.writeText "redis.conf" (generators.toKeyValue {
listsAsDuplicateKeys = true;
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " ";
- } cfg.settings);
+ } settings);
+
+ redisName = name: "redis" + optionalString (name != "") ("-"+name);
+ enabledServers = filterAttrs (name: conf: conf.enable) config.services.redis.servers;
in {
imports = [
@@ -24,7 +25,28 @@ in {
(mkRemovedOptionModule [ "services" "redis" "dbFilename" ] "The redis module now uses /var/lib/redis/dump.rdb as database dump location.")
(mkRemovedOptionModule [ "services" "redis" "appendOnlyFilename" ] "This option was never used.")
(mkRemovedOptionModule [ "services" "redis" "pidFile" ] "This option was removed.")
- (mkRemovedOptionModule [ "services" "redis" "extraConfig" ] "Use services.redis.settings instead.")
+ (mkRemovedOptionModule [ "services" "redis" "extraConfig" ] "Use services.redis.servers.*.settings instead.")
+ (mkRenamedOptionModule [ "services" "redis" "enable"] [ "services" "redis" "servers" "" "enable" ])
+ (mkRenamedOptionModule [ "services" "redis" "port"] [ "services" "redis" "servers" "" "port" ])
+ (mkRenamedOptionModule [ "services" "redis" "openFirewall"] [ "services" "redis" "servers" "" "openFirewall" ])
+ (mkRenamedOptionModule [ "services" "redis" "bind"] [ "services" "redis" "servers" "" "bind" ])
+ (mkRenamedOptionModule [ "services" "redis" "unixSocket"] [ "services" "redis" "servers" "" "unixSocket" ])
+ (mkRenamedOptionModule [ "services" "redis" "unixSocketPerm"] [ "services" "redis" "servers" "" "unixSocketPerm" ])
+ (mkRenamedOptionModule [ "services" "redis" "logLevel"] [ "services" "redis" "servers" "" "logLevel" ])
+ (mkRenamedOptionModule [ "services" "redis" "logfile"] [ "services" "redis" "servers" "" "logfile" ])
+ (mkRenamedOptionModule [ "services" "redis" "syslog"] [ "services" "redis" "servers" "" "syslog" ])
+ (mkRenamedOptionModule [ "services" "redis" "databases"] [ "services" "redis" "servers" "" "databases" ])
+ (mkRenamedOptionModule [ "services" "redis" "maxclients"] [ "services" "redis" "servers" "" "maxclients" ])
+ (mkRenamedOptionModule [ "services" "redis" "save"] [ "services" "redis" "servers" "" "save" ])
+ (mkRenamedOptionModule [ "services" "redis" "slaveOf"] [ "services" "redis" "servers" "" "slaveOf" ])
+ (mkRenamedOptionModule [ "services" "redis" "masterAuth"] [ "services" "redis" "servers" "" "masterAuth" ])
+ (mkRenamedOptionModule [ "services" "redis" "requirePass"] [ "services" "redis" "servers" "" "requirePass" ])
+ (mkRenamedOptionModule [ "services" "redis" "requirePassFile"] [ "services" "redis" "servers" "" "requirePassFile" ])
+ (mkRenamedOptionModule [ "services" "redis" "appendOnly"] [ "services" "redis" "servers" "" "appendOnly" ])
+ (mkRenamedOptionModule [ "services" "redis" "appendFsync"] [ "services" "redis" "servers" "" "appendFsync" ])
+ (mkRenamedOptionModule [ "services" "redis" "slowLogLogSlowerThan"] [ "services" "redis" "servers" "" "slowLogLogSlowerThan" ])
+ (mkRenamedOptionModule [ "services" "redis" "slowLogMaxLen"] [ "services" "redis" "servers" "" "slowLogMaxLen" ])
+ (mkRenamedOptionModule [ "services" "redis" "settings"] [ "services" "redis" "servers" "" "settings" ])
];
###### interface
@@ -32,18 +54,6 @@ in {
options = {
services.redis = {
-
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to enable the Redis server. Note that the NixOS module for
- Redis disables kernel support for Transparent Huge Pages (THP),
- because this features causes major performance problems for Redis,
- e.g. (https://redis.io/topics/latency).
- '';
- };
-
package = mkOption {
type = types.package;
default = pkgs.redis;
@@ -51,176 +61,226 @@ in {
description = "Which Redis derivation to use.";
};
- port = mkOption {
- type = types.port;
- default = 6379;
- description = "The port for Redis to listen to.";
- };
+ vmOverCommit = mkEnableOption ''
+ setting of vm.overcommit_memory to 1
+ (Suggested for Background Saving: http://redis.io/topics/faq)
+ '';
- vmOverCommit = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Set vm.overcommit_memory to 1 (Suggested for Background Saving: http://redis.io/topics/faq)
- '';
- };
-
- openFirewall = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to open ports in the firewall for the server.
- '';
- };
-
- bind = mkOption {
- type = with types; nullOr str;
- default = "127.0.0.1";
- description = ''
- The IP interface to bind to.
- null means "all interfaces".
- '';
- example = "192.0.2.1";
- };
-
- unixSocket = mkOption {
- type = with types; nullOr path;
- default = null;
- description = "The path to the socket to bind to.";
- example = "/run/redis/redis.sock";
- };
-
- unixSocketPerm = mkOption {
- type = types.int;
- default = 750;
- description = "Change permissions for the socket";
- example = 700;
- };
-
- logLevel = mkOption {
- type = types.str;
- default = "notice"; # debug, verbose, notice, warning
- example = "debug";
- description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
- };
-
- logfile = mkOption {
- type = types.str;
- default = "/dev/null";
- description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
- example = "/var/log/redis.log";
- };
-
- syslog = mkOption {
- type = types.bool;
- default = true;
- description = "Enable logging to the system logger.";
- };
-
- databases = mkOption {
- type = types.int;
- default = 16;
- description = "Set the number of databases.";
- };
-
- maxclients = mkOption {
- type = types.int;
- default = 10000;
- description = "Set the max number of connected clients at the same time.";
- };
-
- save = mkOption {
- type = with types; listOf (listOf int);
- default = [ [900 1] [300 10] [60 10000] ];
- description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
- };
-
- slaveOf = mkOption {
- type = with types; nullOr (submodule ({ ... }: {
+ servers = mkOption {
+ type = with types; attrsOf (submodule ({config, name, ...}@args: {
options = {
- ip = mkOption {
- type = str;
- description = "IP of the Redis master";
- example = "192.168.1.100";
+ enable = mkEnableOption ''
+ Redis server.
+
+ Note that the NixOS module for Redis disables kernel support
+ for Transparent Huge Pages (THP),
+ because this features causes major performance problems for Redis,
+ e.g. (https://redis.io/topics/latency).
+ '';
+
+ user = mkOption {
+ type = types.str;
+ default = redisName name;
+ defaultText = "\"redis\" or \"redis-\${name}\" if name != \"\"";
+ description = "The username and groupname for redis-server.";
};
port = mkOption {
- type = port;
- description = "port of the Redis master";
+ type = types.port;
default = 6379;
+ description = "The port for Redis to listen to.";
+ };
+
+ openFirewall = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to open ports in the firewall for the server.
+ '';
+ };
+
+ bind = mkOption {
+ type = with types; nullOr str;
+ default = if name == "" then "127.0.0.1" else null;
+ defaultText = "127.0.0.1 or null if name != \"\"";
+ description = ''
+ The IP interface to bind to.
+ null means "all interfaces".
+ '';
+ example = "192.0.2.1";
+ };
+
+ unixSocket = mkOption {
+ type = with types; nullOr path;
+ default = "/run/${redisName name}/redis.sock";
+ defaultText = "\"/run/redis/redis.sock\" or \"/run/redis-\${name}/redis.sock\" if name != \"\"";
+ description = "The path to the socket to bind to.";
+ };
+
+ unixSocketPerm = mkOption {
+ type = types.int;
+ default = 660;
+ description = "Change permissions for the socket";
+ example = 600;
+ };
+
+ logLevel = mkOption {
+ type = types.str;
+ default = "notice"; # debug, verbose, notice, warning
+ example = "debug";
+ description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
+ };
+
+ logfile = mkOption {
+ type = types.str;
+ default = "/dev/null";
+ description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
+ example = "/var/log/redis.log";
+ };
+
+ syslog = mkOption {
+ type = types.bool;
+ default = true;
+ description = "Enable logging to the system logger.";
+ };
+
+ databases = mkOption {
+ type = types.int;
+ default = 16;
+ description = "Set the number of databases.";
+ };
+
+ maxclients = mkOption {
+ type = types.int;
+ default = 10000;
+ description = "Set the max number of connected clients at the same time.";
+ };
+
+ save = mkOption {
+ type = with types; listOf (listOf int);
+ default = [ [900 1] [300 10] [60 10000] ];
+ description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
+ };
+
+ slaveOf = mkOption {
+ type = with types; nullOr (submodule ({ ... }: {
+ options = {
+ ip = mkOption {
+ type = str;
+ description = "IP of the Redis master";
+ example = "192.168.1.100";
+ };
+
+ port = mkOption {
+ type = port;
+ description = "port of the Redis master";
+ default = 6379;
+ };
+ };
+ }));
+
+ default = null;
+ description = "IP and port to which this redis instance acts as a slave.";
+ example = { ip = "192.168.1.100"; port = 6379; };
+ };
+
+ masterAuth = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''If the master is password protected (using the requirePass configuration)
+ it is possible to tell the slave to authenticate before starting the replication synchronization
+ process, otherwise the master will refuse the slave request.
+ (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
+ };
+
+ requirePass = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
+ Use requirePassFile to store it outside of the nix store in a dedicated file.
+ '';
+ example = "letmein!";
+ };
+
+ requirePassFile = mkOption {
+ type = with types; nullOr path;
+ default = null;
+ description = "File with password for the database.";
+ example = "/run/keys/redis-password";
+ };
+
+ appendOnly = mkOption {
+ type = types.bool;
+ default = false;
+ description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
+ };
+
+ appendFsync = mkOption {
+ type = types.str;
+ default = "everysec"; # no, always, everysec
+ description = "How often to fsync the append-only log, options: no, always, everysec.";
+ };
+
+ slowLogLogSlowerThan = mkOption {
+ type = types.int;
+ default = 10000;
+ description = "Log queries whose execution take longer than X in milliseconds.";
+ example = 1000;
+ };
+
+ slowLogMaxLen = mkOption {
+ type = types.int;
+ default = 128;
+ description = "Maximum number of items to keep in slow log.";
+ };
+
+ settings = mkOption {
+ # TODO: this should be converted to freeformType
+ type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
+ default = {};
+ description = ''
+ Redis configuration. Refer to
+
+ for details on supported values.
+ '';
+ example = literalExpression ''
+ {
+ loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
+ }
+ '';
};
};
+ config.settings = mkMerge [
+ {
+ port = if config.bind == null then 0 else config.port;
+ daemonize = false;
+ supervised = "systemd";
+ loglevel = config.logLevel;
+ logfile = config.logfile;
+ syslog-enabled = config.syslog;
+ databases = config.databases;
+ maxclients = config.maxclients;
+ save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") config.save;
+ dbfilename = "dump.rdb";
+ dir = "/var/lib/${redisName name}";
+ appendOnly = config.appendOnly;
+ appendfsync = config.appendFsync;
+ slowlog-log-slower-than = config.slowLogLogSlowerThan;
+ slowlog-max-len = config.slowLogMaxLen;
+ }
+ (mkIf (config.bind != null) { bind = config.bind; })
+ (mkIf (config.unixSocket != null) {
+ unixsocket = config.unixSocket;
+ unixsocketperm = toString config.unixSocketPerm;
+ })
+ (mkIf (config.slaveOf != null) { slaveof = "${config.slaveOf.ip} ${toString config.slaveOf.port}"; })
+ (mkIf (config.masterAuth != null) { masterauth = config.masterAuth; })
+ (mkIf (config.requirePass != null) { requirepass = config.requirePass; })
+ ];
}));
-
- default = null;
- description = "IP and port to which this redis instance acts as a slave.";
- example = { ip = "192.168.1.100"; port = 6379; };
- };
-
- masterAuth = mkOption {
- type = with types; nullOr str;
- default = null;
- description = ''If the master is password protected (using the requirePass configuration)
- it is possible to tell the slave to authenticate before starting the replication synchronization
- process, otherwise the master will refuse the slave request.
- (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
- };
-
- requirePass = mkOption {
- type = with types; nullOr str;
- default = null;
- description = ''
- Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
- Use requirePassFile to store it outside of the nix store in a dedicated file.
- '';
- example = "letmein!";
- };
-
- requirePassFile = mkOption {
- type = with types; nullOr path;
- default = null;
- description = "File with password for the database.";
- example = "/run/keys/redis-password";
- };
-
- appendOnly = mkOption {
- type = types.bool;
- default = false;
- description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
- };
-
- appendFsync = mkOption {
- type = types.str;
- default = "everysec"; # no, always, everysec
- description = "How often to fsync the append-only log, options: no, always, everysec.";
- };
-
- slowLogLogSlowerThan = mkOption {
- type = types.int;
- default = 10000;
- description = "Log queries whose execution take longer than X in milliseconds.";
- example = 1000;
- };
-
- slowLogMaxLen = mkOption {
- type = types.int;
- default = 128;
- description = "Maximum number of items to keep in slow log.";
- };
-
- settings = mkOption {
- type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
+ description = "Configuration of multiple redis-server instances.";
default = {};
- description = ''
- Redis configuration. Refer to
-
- for details on supported values.
- '';
- example = literalExpression ''
- {
- loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
- }
- '';
};
};
@@ -229,78 +289,61 @@ in {
###### implementation
- config = mkIf config.services.redis.enable {
- assertions = [{
- assertion = cfg.requirePass != null -> cfg.requirePassFile == null;
- message = "You can only set one services.redis.requirePass or services.redis.requirePassFile";
- }];
- boot.kernel.sysctl = (mkMerge [
+ config = mkIf (enabledServers != {}) {
+
+ assertions = attrValues (mapAttrs (name: conf: {
+ assertion = conf.requirePass != null -> conf.requirePassFile == null;
+ message = ''
+ You can only set one services.redis.servers.${name}.requirePass
+ or services.redis.servers.${name}.requirePassFile
+ '';
+ }) enabledServers);
+
+ boot.kernel.sysctl = mkMerge [
{ "vm.nr_hugepages" = "0"; }
( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
- ]);
+ ];
- networking.firewall = mkIf cfg.openFirewall {
- allowedTCPPorts = [ cfg.port ];
- };
-
- users.users.redis = {
- description = "Redis database user";
- group = "redis";
- isSystemUser = true;
- };
- users.groups.redis = {};
+ networking.firewall.allowedTCPPorts = concatMap (conf:
+ optional conf.openFirewall conf.port
+ ) (attrValues enabledServers);
environment.systemPackages = [ cfg.package ];
- services.redis.settings = mkMerge [
- {
- port = cfg.port;
- daemonize = false;
- supervised = "systemd";
- loglevel = cfg.logLevel;
- logfile = cfg.logfile;
- syslog-enabled = cfg.syslog;
- databases = cfg.databases;
- maxclients = cfg.maxclients;
- save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") cfg.save;
- dbfilename = "dump.rdb";
- dir = "/var/lib/redis";
- appendOnly = cfg.appendOnly;
- appendfsync = cfg.appendFsync;
- slowlog-log-slower-than = cfg.slowLogLogSlowerThan;
- slowlog-max-len = cfg.slowLogMaxLen;
- }
- (mkIf (cfg.bind != null) { bind = cfg.bind; })
- (mkIf (cfg.unixSocket != null) { unixsocket = cfg.unixSocket; unixsocketperm = "${toString cfg.unixSocketPerm}"; })
- (mkIf (cfg.slaveOf != null) { slaveof = "${cfg.slaveOf.ip} ${toString cfg.slaveOf.port}"; })
- (mkIf (cfg.masterAuth != null) { masterauth = cfg.masterAuth; })
- (mkIf (cfg.requirePass != null) { requirepass = cfg.requirePass; })
- ];
+ users.users = mapAttrs' (name: conf: nameValuePair (redisName name) {
+ description = "System user for the redis-server instance ${name}";
+ isSystemUser = true;
+ group = redisName name;
+ }) enabledServers;
+ users.groups = mapAttrs' (name: conf: nameValuePair (redisName name) {
+ }) enabledServers;
- systemd.services.redis = {
- description = "Redis Server";
+ systemd.services = mapAttrs' (name: conf: nameValuePair (redisName name) {
+ description = "Redis Server - ${redisName name}";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
- preStart = ''
- install -m 600 ${redisConfig} /run/redis/redis.conf
- '' + optionalString (cfg.requirePassFile != null) ''
- password=$(cat ${escapeShellArg cfg.requirePassFile})
- echo "requirePass $password" >> /run/redis/redis.conf
- '';
-
serviceConfig = {
- ExecStart = "${cfg.package}/bin/redis-server /run/redis/redis.conf";
+ ExecStart = "${cfg.package}/bin/redis-server /run/${redisName name}/redis.conf";
+ ExecStartPre = [("+"+pkgs.writeShellScript "${redisName name}-credentials" (''
+ install -o '${conf.user}' -m 600 ${redisConfig conf.settings} /run/${redisName name}/redis.conf
+ '' + optionalString (conf.requirePassFile != null) ''
+ {
+ printf requirePass' '
+ cat ${escapeShellArg conf.requirePassFile}
+ } >>/run/${redisName name}/redis.conf
+ '')
+ )];
Type = "notify";
# User and group
- User = "redis";
- Group = "redis";
+ User = conf.user;
+ Group = conf.user;
# Runtime directory and mode
- RuntimeDirectory = "redis";
+ RuntimeDirectory = redisName name;
RuntimeDirectoryMode = "0750";
# State directory and mode
- StateDirectory = "redis";
+ StateDirectory = redisName name;
StateDirectoryMode = "0700";
# Access write directories
UMask = "0077";
@@ -309,7 +352,7 @@ in {
# Security
NoNewPrivileges = true;
# Process Properties
- LimitNOFILE = "${toString ulimitNofile}";
+ LimitNOFILE = mkDefault "${toString (conf.maxclients + 32)}";
# Sandboxing
ProtectSystem = "strict";
ProtectHome = true;
@@ -322,7 +365,9 @@ in {
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
- RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+ RestrictAddressFamilies =
+ optionals (conf.bind != null) ["AF_INET" "AF_INET6"] ++
+ optional (conf.unixSocket != null) "AF_UNIX";
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
@@ -333,6 +378,7 @@ in {
SystemCallArchitectures = "native";
SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
};
- };
+ }) enabledServers;
+
};
}
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index d3e9a97c2120..3fbab8b94c93 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -146,6 +146,79 @@ sub fingerprintUnit {
return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
}
+sub handleModifiedUnit {
+ my ($unit, $baseName, $newUnitFile, $activePrev, $unitsToStop, $unitsToStart, $unitsToReload, $unitsToRestart, $unitsToSkip) = @_;
+
+ if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
+ # Do nothing. These cannot be restarted directly.
+
+ # Slices and Paths don't have to be restarted since
+ # properties (resource limits and inotify watches)
+ # seem to get applied on daemon-reload.
+ } elsif ($unit =~ /\.mount$/) {
+ # Reload the changed mount unit to force a remount.
+ $unitsToReload->{$unit} = 1;
+ recordUnit($reloadListFile, $unit);
+ } elsif ($unit =~ /\.socket$/) {
+ # FIXME: do something?
+ # Attempt to fix this: https://github.com/NixOS/nixpkgs/pull/141192
+ # Revert of the attempt: https://github.com/NixOS/nixpkgs/pull/147609
+ # More details: https://github.com/NixOS/nixpkgs/issues/74899#issuecomment-981142430
+ } else {
+ my $unitInfo = parseUnit($newUnitFile);
+ if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
+ $unitsToReload->{$unit} = 1;
+ recordUnit($reloadListFile, $unit);
+ }
+ elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
+ $unitsToSkip->{$unit} = 1;
+ } else {
+ # It doesn't make sense to stop and start non-services because
+ # they can't have ExecStop=
+ if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes") || $unit !~ /\.service$/) {
+ # This unit should be restarted instead of
+ # stopped and started.
+ $unitsToRestart->{$unit} = 1;
+ recordUnit($restartListFile, $unit);
+ } else {
+ # If this unit is socket-activated, then stop the
+ # socket unit(s) as well, and restart the
+ # socket(s) instead of the service.
+ my $socketActivated = 0;
+ if ($unit =~ /\.service$/) {
+ my @sockets = split / /, ($unitInfo->{Sockets} // "");
+ if (scalar @sockets == 0) {
+ @sockets = ("$baseName.socket");
+ }
+ foreach my $socket (@sockets) {
+ if (defined $activePrev->{$socket}) {
+ $unitsToStop->{$socket} = 1;
+ # Only restart sockets that actually
+ # exist in new configuration:
+ if (-e "$out/etc/systemd/system/$socket") {
+ $unitsToStart->{$socket} = 1;
+ recordUnit($startListFile, $socket);
+ $socketActivated = 1;
+ }
+ }
+ }
+ }
+
+ # If the unit is not socket-activated, record
+ # that this unit needs to be started below.
+ # We write this to a file to ensure that the
+ # service gets restarted if we're interrupted.
+ if (!$socketActivated) {
+ $unitsToStart->{$unit} = 1;
+ recordUnit($startListFile, $unit);
+ }
+
+ $unitsToStop->{$unit} = 1;
+ }
+ }
+ }
+}
+
# Figure out what units need to be stopped, started, restarted or reloaded.
my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
@@ -218,69 +291,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
}
elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
- if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
- # Do nothing. These cannot be restarted directly.
-
- # Slices and Paths don't have to be restarted since
- # properties (resource limits and inotify watches)
- # seem to get applied on daemon-reload.
- } elsif ($unit =~ /\.mount$/) {
- # Reload the changed mount unit to force a remount.
- $unitsToReload{$unit} = 1;
- recordUnit($reloadListFile, $unit);
- } elsif ($unit =~ /\.socket$/) {
- # FIXME: do something?
- } else {
- my $unitInfo = parseUnit($newUnitFile);
- if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
- $unitsToReload{$unit} = 1;
- recordUnit($reloadListFile, $unit);
- }
- elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
- $unitsToSkip{$unit} = 1;
- } else {
- if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {
- # This unit should be restarted instead of
- # stopped and started.
- $unitsToRestart{$unit} = 1;
- recordUnit($restartListFile, $unit);
- } else {
- # If this unit is socket-activated, then stop the
- # socket unit(s) as well, and restart the
- # socket(s) instead of the service.
- my $socketActivated = 0;
- if ($unit =~ /\.service$/) {
- my @sockets = split / /, ($unitInfo->{Sockets} // "");
- if (scalar @sockets == 0) {
- @sockets = ("$baseName.socket");
- }
- foreach my $socket (@sockets) {
- if (defined $activePrev->{$socket}) {
- $unitsToStop{$socket} = 1;
- # Only restart sockets that actually
- # exist in new configuration:
- if (-e "$out/etc/systemd/system/$socket") {
- $unitsToStart{$socket} = 1;
- recordUnit($startListFile, $socket);
- $socketActivated = 1;
- }
- }
- }
- }
-
- # If the unit is not socket-activated, record
- # that this unit needs to be started below.
- # We write this to a file to ensure that the
- # service gets restarted if we're interrupted.
- if (!$socketActivated) {
- $unitsToStart{$unit} = 1;
- recordUnit($startListFile, $unit);
- }
-
- $unitsToStop{$unit} = 1;
- }
- }
- }
+ handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip);
}
}
}
diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix
index 62deb3864951..008a5edd071d 100644
--- a/nixos/tests/prometheus-exporters.nix
+++ b/nixos/tests/prometheus-exporters.nix
@@ -939,7 +939,7 @@ let
exporterConfig = {
enable = true;
};
- metricProvider.services.redis.enable = true;
+ metricProvider.services.redis.servers."".enable = true;
exporterTest = ''
wait_for_unit("redis.service")
wait_for_unit("prometheus-redis-exporter.service")
diff --git a/nixos/tests/redis.nix b/nixos/tests/redis.nix
index 28b6058c2c02..7b70c239ad6e 100644
--- a/nixos/tests/redis.nix
+++ b/nixos/tests/redis.nix
@@ -1,7 +1,4 @@
import ./make-test-python.nix ({ pkgs, ... }:
-let
- redisSocket = "/run/redis/redis.sock";
-in
{
name = "redis";
meta = with pkgs.lib.maintainers; {
@@ -10,35 +7,40 @@ in
nodes = {
machine =
- { pkgs, ... }:
+ { pkgs, lib, ... }: with lib;
{
- services.redis.enable = true;
- services.redis.unixSocket = redisSocket;
+ services.redis.servers."".enable = true;
+ services.redis.servers."test".enable = true;
- # Allow access to the unix socket for the "redis" group.
- services.redis.unixSocketPerm = 770;
-
- users.users."member" = {
+ users.users = listToAttrs (map (suffix: nameValuePair "member${suffix}" {
createHome = false;
- description = "A member of the redis group";
+ description = "A member of the redis${suffix} group";
isNormalUser = true;
- extraGroups = [
- "redis"
- ];
- };
+ extraGroups = [ "redis${suffix}" ];
+ }) ["" "-test"]);
};
};
- testScript = ''
+ testScript = { nodes, ... }: let
+ inherit (nodes.machine.config.services) redis;
+ in ''
start_all()
machine.wait_for_unit("redis")
+ machine.wait_for_unit("redis-test")
+
+ # The unnamed Redis server still opens a port for backward-compatibility
machine.wait_for_open_port("6379")
+ machine.wait_for_file("${redis.servers."".unixSocket}")
+ machine.wait_for_file("${redis.servers."test".unixSocket}")
+
# The unix socket is accessible to the redis group
machine.succeed('su member -c "redis-cli ping | grep PONG"')
+ machine.succeed('su member-test -c "redis-cli ping | grep PONG"')
machine.succeed("redis-cli ping | grep PONG")
- machine.succeed("redis-cli -s ${redisSocket} ping | grep PONG")
+ machine.succeed("redis-cli -s ${redis.servers."".unixSocket} ping | grep PONG")
+ machine.succeed("redis-cli -s ${redis.servers."test".unixSocket} ping | grep PONG")
'';
})
diff --git a/nixos/tests/switch-test.nix b/nixos/tests/switch-test.nix
index 78adf7ffa7da..daad9134885f 100644
--- a/nixos/tests/switch-test.nix
+++ b/nixos/tests/switch-test.nix
@@ -3,21 +3,138 @@
import ./make-test-python.nix ({ pkgs, ...} : {
name = "switch-test";
meta = with pkgs.lib.maintainers; {
- maintainers = [ gleber ];
+ maintainers = [ gleber das_j ];
};
nodes = {
- machine = { ... }: {
+ machine = { pkgs, lib, ... }: {
users.mutableUsers = false;
+
+ specialisation = rec {
+ simpleService.configuration = {
+ systemd.services.test = {
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "${pkgs.coreutils}/bin/true";
+ };
+ };
+ };
+
+ simpleServiceModified.configuration = {
+ imports = [ simpleService.configuration ];
+ systemd.services.test.serviceConfig.X-Test = true;
+ };
+
+ simpleServiceNostop.configuration = {
+ imports = [ simpleService.configuration ];
+ systemd.services.test.stopIfChanged = false;
+ };
+
+ simpleServiceReload.configuration = {
+ imports = [ simpleService.configuration ];
+ systemd.services.test = {
+ reloadIfChanged = true;
+ serviceConfig.ExecReload = "${pkgs.coreutils}/bin/true";
+ };
+ };
+
+ simpleServiceNorestart.configuration = {
+ imports = [ simpleService.configuration ];
+ systemd.services.test.restartIfChanged = false;
+ };
+
+ mount.configuration = {
+ systemd.mounts = [
+ {
+ description = "Testmount";
+ what = "tmpfs";
+ type = "tmpfs";
+ where = "/testmount";
+ options = "size=1M";
+ wantedBy = [ "local-fs.target" ];
+ }
+ ];
+ };
+
+ mountModified.configuration = {
+ systemd.mounts = [
+ {
+ description = "Testmount";
+ what = "tmpfs";
+ type = "tmpfs";
+ where = "/testmount";
+ options = "size=10M";
+ wantedBy = [ "local-fs.target" ];
+ }
+ ];
+ };
+
+ timer.configuration = {
+ systemd.timers.test-timer = {
+ wantedBy = [ "timers.target" ];
+ timerConfig.OnCalendar = "@1395716396"; # chosen by fair dice roll
+ };
+ systemd.services.test-timer = {
+ serviceConfig = {
+ Type = "oneshot";
+ ExecStart = "${pkgs.coreutils}/bin/true";
+ };
+ };
+ };
+
+ timerModified.configuration = {
+ imports = [ timer.configuration ];
+ systemd.timers.test-timer.timerConfig.OnCalendar = lib.mkForce "Fri 2012-11-23 16:00:00";
+ };
+
+ path.configuration = {
+ systemd.paths.test-watch = {
+ wantedBy = [ "paths.target" ];
+ pathConfig.PathExists = "/testpath";
+ };
+ systemd.services.test-watch = {
+ serviceConfig = {
+ Type = "oneshot";
+ ExecStart = "${pkgs.coreutils}/bin/touch /testpath-modified";
+ };
+ };
+ };
+
+ pathModified.configuration = {
+ imports = [ path.configuration ];
+ systemd.paths.test-watch.pathConfig.PathExists = lib.mkForce "/testpath2";
+ };
+
+ slice.configuration = {
+ systemd.slices.testslice.sliceConfig.MemoryMax = "1"; # don't allow memory allocation
+ systemd.services.testservice = {
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "${pkgs.coreutils}/bin/true";
+ Slice = "testslice.slice";
+ };
+ };
+ };
+
+ sliceModified.configuration = {
+ imports = [ slice.configuration ];
+ systemd.slices.testslice.sliceConfig.MemoryMax = lib.mkForce null;
+ };
+ };
};
- other = { ... }: {
+
+ other = {
users.mutableUsers = true;
};
};
- testScript = {nodes, ...}: let
+ testScript = { nodes, ... }: let
originalSystem = nodes.machine.config.system.build.toplevel;
otherSystem = nodes.other.config.system.build.toplevel;
+ machine = nodes.machine.config.system.build.toplevel;
# Ensures failures pass through using pipefail, otherwise failing to
# switch-to-configuration is hidden by the success of `tee`.
@@ -27,12 +144,186 @@ import ./make-test-python.nix ({ pkgs, ...} : {
set -o pipefail
exec env -i "$@" | tee /dev/stderr
'';
- in ''
+ in /* python */ ''
+ def switch_to_specialisation(system, name, action="test"):
+ if name == "":
+ stc = f"{system}/bin/switch-to-configuration"
+ else:
+ stc = f"{system}/specialisation/{name}/bin/switch-to-configuration"
+ out = machine.succeed(f"{stc} {action} 2>&1")
+ assert_lacks(out, "switch-to-configuration line") # Perl warnings
+ return out
+
+ def assert_contains(haystack, needle):
+ if needle not in haystack:
+ print("The haystack that will cause the following exception is:")
+ print("---")
+ print(haystack)
+ print("---")
+ raise Exception(f"Expected string '{needle}' was not found")
+
+ def assert_lacks(haystack, needle):
+ if needle in haystack:
+ print("The haystack that will cause the following exception is:")
+ print("---")
+ print(haystack, end="")
+ print("---")
+ raise Exception(f"Unexpected string '{needle}' was found")
+
+
machine.succeed(
"${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
)
machine.succeed(
"${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
)
+
+ with subtest("services"):
+ switch_to_specialisation("${machine}", "")
+ # Nothing happens when nothing is changed
+ out = switch_to_specialisation("${machine}", "")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+
+ # Start a simple service
+ out = switch_to_specialisation("${machine}", "simpleService")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_contains(out, "reloading the following units: dbus.service\n") # huh
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_contains(out, "the following new units were started: test.service\n")
+ assert_lacks(out, "as well:")
+
+ # Not changing anything doesn't do anything
+ out = switch_to_specialisation("${machine}", "simpleService")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+
+ # Restart the simple service
+ out = switch_to_specialisation("${machine}", "simpleServiceModified")
+ assert_contains(out, "stopping the following units: test.service\n")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_contains(out, "\nstarting the following units: test.service\n")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+
+ # Restart the service with stopIfChanged=false
+ out = switch_to_specialisation("${machine}", "simpleServiceNostop")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_contains(out, "\nrestarting the following units: test.service\n")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+
+ # Reload the service with reloadIfChanged=true
+ out = switch_to_specialisation("${machine}", "simpleServiceReload")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_contains(out, "reloading the following units: test.service\n")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+
+ # Nothing happens when restartIfChanged=false
+ out = switch_to_specialisation("${machine}", "simpleServiceNorestart")
+ assert_lacks(out, "stopping the following units:")
+ assert_contains(out, "NOT restarting the following changed units: test.service\n")
+ assert_lacks(out, "reloading the following units:")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+
+ # Dry mode shows different messages
+ out = switch_to_specialisation("${machine}", "simpleService", action="dry-activate")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+ assert_contains(out, "would start the following units: test.service\n")
+
+ with subtest("mounts"):
+ switch_to_specialisation("${machine}", "mount")
+ out = machine.succeed("mount | grep 'on /testmount'")
+ assert_contains(out, "size=1024k")
+ out = switch_to_specialisation("${machine}", "mountModified")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_contains(out, "reloading the following units: testmount.mount\n")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+ # It changed
+ out = machine.succeed("mount | grep 'on /testmount'")
+ assert_contains(out, "size=10240k")
+
+ with subtest("timers"):
+ switch_to_specialisation("${machine}", "timer")
+ out = machine.succeed("systemctl show test-timer.timer")
+ assert_contains(out, "OnCalendar=2014-03-25 02:59:56 UTC")
+ out = switch_to_specialisation("${machine}", "timerModified")
+ assert_lacks(out, "stopping the following units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_contains(out, "restarting the following units: test-timer.timer\n")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_lacks(out, "the following new units were started:")
+ assert_lacks(out, "as well:")
+ # It changed
+ out = machine.succeed("systemctl show test-timer.timer")
+ assert_contains(out, "OnCalendar=Fri 2012-11-23 16:00:00")
+
+ with subtest("paths"):
+ out = switch_to_specialisation("${machine}", "path")
+ assert_contains(out, "stopping the following units: test-timer.timer\n")
+ assert_lacks(out, "NOT restarting the following changed units:")
+ assert_lacks(out, "reloading the following units:")
+ assert_lacks(out, "\nrestarting the following units:")
+ assert_lacks(out, "\nstarting the following units:")
+ assert_contains(out, "the following new units were started: test-watch.path")
+ assert_lacks(out, "as well:")
+ machine.fail("test -f /testpath-modified")
+
+ # touch the file, unit should be triggered
+ machine.succeed("touch /testpath")
+ machine.wait_until_succeeds("test -f /testpath-modified")
+ machine.succeed("rm /testpath /testpath-modified")
+ switch_to_specialisation("${machine}", "pathModified")
+ machine.succeed("touch /testpath")
+ machine.fail("test -f /testpath-modified")
+ machine.succeed("touch /testpath2")
+ machine.wait_until_succeeds("test -f /testpath-modified")
+
+ # This test ensures that changes to slice configuration get applied.
+ # We test this by having a slice that allows no memory allocation at
+ # all and starting a service within it. If the service crashes, the slice
+ # is applied and if we modify the slice to allow memory allocation, the
+ # service should successfully start.
+ with subtest("slices"):
+ machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom") # allow OOMing
+ out = switch_to_specialisation("${machine}", "slice")
+ machine.fail("systemctl start testservice.service")
+ out = switch_to_specialisation("${machine}", "sliceModified")
+ machine.succeed("systemctl start testservice.service")
+ machine.succeed("echo 1 > /proc/sys/vm/panic_on_oom") # disallow OOMing
'';
})
diff --git a/nixos/tests/txredisapi.nix b/nixos/tests/txredisapi.nix
index bc3814a71375..7c6b36a5c47d 100644
--- a/nixos/tests/txredisapi.nix
+++ b/nixos/tests/txredisapi.nix
@@ -10,17 +10,19 @@ import ./make-test-python.nix ({ pkgs, ... }:
{ pkgs, ... }:
{
- services.redis.enable = true;
- services.redis.unixSocket = "/run/redis/redis.sock";
+ services.redis.servers."".enable = true;
environment.systemPackages = with pkgs; [ (python38.withPackages (ps: [ ps.twisted ps.txredisapi ps.mock ]))];
};
};
- testScript = ''
+ testScript = { nodes, ... }: let
+ inherit (nodes.machine.config.services) redis;
+ in ''
start_all()
machine.wait_for_unit("redis")
- machine.wait_for_open_port("6379")
+ machine.wait_for_file("${redis.servers."".unixSocket}")
+ machine.succeed("ln -s ${redis.servers."".unixSocket} /tmp/redis.sock")
tests = machine.succeed("PYTHONPATH=\"${pkgs.python3Packages.txredisapi.src}\" python -m twisted.trial ${pkgs.python3Packages.txredisapi.src}/tests")
'';
diff --git a/pkgs/applications/editors/emacs/generic.nix b/pkgs/applications/editors/emacs/generic.nix
index db043140e77a..2a1ed2f8b1a4 100644
--- a/pkgs/applications/editors/emacs/generic.nix
+++ b/pkgs/applications/editors/emacs/generic.nix
@@ -10,7 +10,7 @@
, Xaw3d, libXcursor, pkg-config, gettext, libXft, dbus, libpng, libjpeg, giflib
, libtiff, librsvg, gconf, libxml2, imagemagick, gnutls, libselinux
, alsa-lib, cairo, acl, gpm, AppKit, GSS, ImageIO, m17n_lib, libotf
-, sigtool, jansson, harfbuzz
+, sigtool, jansson, harfbuzz, sqlite
, dontRecurseIntoAttrs ,emacsPackagesFor
, libgccjit, targetPlatform, makeWrapper # native-comp params
, systemd ? null
@@ -20,6 +20,7 @@
, withGTK3 ? true, gtk3-x11 ? null, gsettings-desktop-schemas ? null
, withXwidgets ? false, webkitgtk ? null, wrapGAppsHook ? null, glib-networking ? null
, withMotif ? false, motif ? null
+, withSQLite3 ? false
, withCsrc ? true
, srcRepo ? false, autoreconfHook ? null, texinfo ? null
, siteStart ? ./site-start.el
@@ -116,6 +117,7 @@ let emacs = stdenv.mkDerivation (lib.optionalAttrs nativeComp {
++ lib.optional (withX && withGTK2) gtk2-x11
++ lib.optionals (withX && withGTK3) [ gtk3-x11 gsettings-desktop-schemas ]
++ lib.optional (withX && withMotif) motif
+ ++ lib.optional withSQLite3 sqlite
++ lib.optionals (withX && withXwidgets) [ webkitgtk glib-networking ]
++ lib.optionals withNS [ AppKit GSS ImageIO ]
++ lib.optionals stdenv.isDarwin [ sigtool ]
diff --git a/pkgs/applications/misc/latte-dock/default.nix b/pkgs/applications/misc/latte-dock/default.nix
index b1ba73566999..6451a3efb70a 100644
--- a/pkgs/applications/misc/latte-dock/default.nix
+++ b/pkgs/applications/misc/latte-dock/default.nix
@@ -3,11 +3,11 @@
mkDerivation rec {
pname = "latte-dock";
- version = "0.10.0";
+ version = "0.10.4";
src = fetchurl {
url = "https://download.kde.org/stable/${pname}/${pname}-${version}.tar.xz";
- sha256 = "04kq86qmrjbzidrkknj000pv1b5z0r7nfidhy2zv67ks8fdi4zln";
+ sha256 = "XRop+MNcbeCcbnL2LM1i67QvMudW3CjWYEPLkT/qbGM=";
name = "${pname}-${version}.tar.xz";
};
diff --git a/pkgs/applications/networking/cluster/kubelogin-oidc/default.nix b/pkgs/applications/networking/cluster/kubelogin-oidc/default.nix
index e552113310f5..ce1974fe2148 100644
--- a/pkgs/applications/networking/cluster/kubelogin-oidc/default.nix
+++ b/pkgs/applications/networking/cluster/kubelogin-oidc/default.nix
@@ -2,18 +2,18 @@
buildGoModule rec {
pname = "kubelogin";
- version = "1.23.3";
+ version = "1.25.0";
src = fetchFromGitHub {
owner = "int128";
repo = pname;
rev = "v${version}";
- sha256 = "sha256-qhdt/j1yFlCr+CCM3VQHxRVMEelZDsjhDJW9CYNCx2U=";
+ sha256 = "sha256-orclZtmkdplTRvYkN7VotbynSQ9L2kvAPqP20j8QJ2s=";
};
subPackages = ["."];
- vendorSha256 = "sha256-RxIrnwIHDi9umu9bqpz3lnpNFdIWoTP657Te9iBv4IA=";
+ vendorSha256 = "sha256-i46G0lsRvh/PmM+pMYuAjoLMHWF1Uzbd8+EkjIId8KE=";
# Rename the binary instead of symlinking to avoid conflict with the
# Azure version of kubelogin
diff --git a/pkgs/applications/networking/instant-messengers/nheko/default.nix b/pkgs/applications/networking/instant-messengers/nheko/default.nix
index 2a2c25e5593c..0af9cf7d1843 100644
--- a/pkgs/applications/networking/instant-messengers/nheko/default.nix
+++ b/pkgs/applications/networking/instant-messengers/nheko/default.nix
@@ -12,6 +12,7 @@
, qtkeychain
, qtmacextras
, qtmultimedia
+, qtimageformats
, qttools
, qtquickcontrols2
, qtgraphicaleffects
@@ -57,6 +58,7 @@ mkDerivation rec {
cmark
qtbase
qtmultimedia
+ qtimageformats
qttools
qtquickcontrols2
qtgraphicaleffects
diff --git a/pkgs/applications/networking/instant-messengers/schildichat/pin.json b/pkgs/applications/networking/instant-messengers/schildichat/pin.json
index 299598063c01..30ca1e9f475a 100644
--- a/pkgs/applications/networking/instant-messengers/schildichat/pin.json
+++ b/pkgs/applications/networking/instant-messengers/schildichat/pin.json
@@ -1,6 +1,6 @@
{
- "version": "1.9.0-sc.1",
- "srcHash": "10swz5gwz1izryzllmjm8mhhd0vqk2cp8qjcmmr5gbzspj7p3xgw",
- "webYarnHash": "134llyh0197andpnbmfcxnidcgi3xxnb9v10bwfvrqysgnhb5z8v",
- "desktopYarnHash": "150jc6p9kbdz599bdkinrhbhncpamhz35j6rcc008qxg2d9qfhwr"
+ "version": "1.9.7-sc.1",
+ "srcHash": "0qrjjwcxa141phsgdz325rrkfmjqdmxc3h917cs9c9kf6cblkxaq",
+ "webYarnHash": "19c594pql2yz1z15phfdlkwcvrcbm8k058fcq7p0k6840dhif5fd",
+ "desktopYarnHash": "058ihkljb1swjzvgf8gqci5ghvwapmpcf2bsab3yr66lhps7fhci"
}
diff --git a/pkgs/applications/terminal-emulators/foot/default.nix b/pkgs/applications/terminal-emulators/foot/default.nix
index 9290f8ce6144..591b16ee8226 100644
--- a/pkgs/applications/terminal-emulators/foot/default.nix
+++ b/pkgs/applications/terminal-emulators/foot/default.nix
@@ -27,7 +27,7 @@
}:
let
- version = "1.10.2";
+ version = "1.10.3";
# build stimuli file for PGO build and the script to generate it
# independently of the foot's build, so we can cache the result
@@ -99,7 +99,7 @@ stdenv.mkDerivation rec {
owner = "dnkl";
repo = pname;
rev = version;
- sha256 = "00096c2m8pn4gpafvmg9lhyprwgnsis62bq4qmagnbb49bj5kr9v";
+ sha256 = "13v6xqaw3xn1x84dn4gnkiimcsllb19mrbvcdj2fnm8klnrys3gs";
};
depsBuildBuild = [
diff --git a/pkgs/development/libraries/bctoolbox/default.nix b/pkgs/development/libraries/bctoolbox/default.nix
index c1d2813a4f2a..f03014b2cd70 100644
--- a/pkgs/development/libraries/bctoolbox/default.nix
+++ b/pkgs/development/libraries/bctoolbox/default.nix
@@ -7,7 +7,7 @@
stdenv.mkDerivation rec {
pname = "bctoolbox";
- version = "5.0.0";
+ version = "5.0.55";
nativeBuildInputs = [ cmake bcunit ];
buildInputs = [ mbedtls ];
@@ -18,7 +18,7 @@ stdenv.mkDerivation rec {
group = "BC";
repo = pname;
rev = version;
- sha256 = "sha256-/jv59ZeELfP7PokzthvZNL4FS3tyzRmCHp4I/Lp8BJM=";
+ sha256 = "sha256-fZ+8XBTZ6/wNd8odzg20dAXtbjRudI6Nw0hKC9bopGo=";
};
# Do not build static libraries
diff --git a/pkgs/development/libraries/olm/default.nix b/pkgs/development/libraries/olm/default.nix
index 252bebd9eff5..e5c2d66827bf 100644
--- a/pkgs/development/libraries/olm/default.nix
+++ b/pkgs/development/libraries/olm/default.nix
@@ -2,14 +2,14 @@
stdenv.mkDerivation rec {
pname = "olm";
- version = "3.2.6";
+ version = "3.2.8";
src = fetchFromGitLab {
domain = "gitlab.matrix.org";
owner = "matrix-org";
repo = pname;
rev = version;
- sha256 = "1srmw36nxi0z2y5d9adks09p950qm0fscbnrq1fl37fdypvjl1sk";
+ sha256 = "1jfhydfcnqpksb2bhi960v3h10prf4v5gx42mm2rp6p0jfbqcy50";
};
nativeBuildInputs = [ cmake ];
diff --git a/pkgs/development/python-modules/asyncio-rlock/default.nix b/pkgs/development/python-modules/asyncio-rlock/default.nix
new file mode 100644
index 000000000000..5ad616180cee
--- /dev/null
+++ b/pkgs/development/python-modules/asyncio-rlock/default.nix
@@ -0,0 +1,28 @@
+{ lib
+, buildPythonPackage
+, fetchPypi
+, pytestCheckHook
+}:
+
+buildPythonPackage rec {
+ pname = "asyncio-rlock";
+ version = "0.1.0";
+
+ src = fetchPypi {
+ pname = "asyncio_rlock";
+ inherit version;
+ sha256 = "7e29824331619873e10d5d99dcc46d7b8f196c4a11b203f4eeccc0c091039d43";
+ };
+
+ # no tests on PyPI, no tags on GitLab
+ doCheck = false;
+
+ pythonImportsCheck = [ "asyncio_rlock" ];
+
+ meta = with lib; {
+ description = "Rlock like in threading module but for asyncio";
+ homepage = "https://gitlab.com/heckad/asyncio_rlock";
+ license = licenses.mit;
+ maintainers = with maintainers; [ dotlambda ];
+ };
+}
diff --git a/pkgs/development/python-modules/fastecdsa/default.nix b/pkgs/development/python-modules/fastecdsa/default.nix
index e7dbea075870..e305f1e6d658 100644
--- a/pkgs/development/python-modules/fastecdsa/default.nix
+++ b/pkgs/development/python-modules/fastecdsa/default.nix
@@ -7,12 +7,12 @@
buildPythonPackage rec {
pname = "fastecdsa";
- version = "2.2.2";
+ version = "2.2.3";
format = "setuptools";
src = fetchPypi {
inherit pname version;
- sha256 = "1eb6f3ac86ec483a10df62fcda1fb9a9d5d895a436871a8aa935dd20ccd82c6f";
+ sha256 = "269bdb0f618b38f8f6aec9d23d23db518046c3cee01a954fa6aa7322a1a7db8f";
};
buildInputs = [ gmp ];
diff --git a/pkgs/development/python-modules/ircrobots/default.nix b/pkgs/development/python-modules/ircrobots/default.nix
index 38cedf939a39..e16ac2449a7d 100644
--- a/pkgs/development/python-modules/ircrobots/default.nix
+++ b/pkgs/development/python-modules/ircrobots/default.nix
@@ -3,6 +3,7 @@
, fetchFromGitHub
, pythonOlder
, anyio
+, asyncio-rlock
, asyncio-throttle
, dataclasses
, ircstates
@@ -13,23 +14,26 @@
buildPythonPackage rec {
pname = "ircrobots";
- version = "0.3.8";
+ version = "0.4.6";
disabled = pythonOlder "3.6";
src = fetchFromGitHub {
owner = "jesopo";
repo = pname;
rev = "v${version}";
- sha256 = "06q86dqllxvi3nssfplmjk9yxaybighwh87lrxfpfhl8yy4z68jz";
+ sha256 = "sha256-+BrS1+ZkgwT/qvqD0PwRZi2LF+31biS738SzKH1dy7w=";
};
postPatch = ''
# too specific pins https://github.com/jesopo/ircrobots/issues/3
sed -iE 's/anyio.*/anyio/' requirements.txt
+ sed -iE 's/ircstates.*/ircstates/' requirements.txt
+ sed -iE 's/async_timeout.*/async_timeout/' requirements.txt
'';
propagatedBuildInputs = [
anyio
+ asyncio-rlock
asyncio-throttle
ircstates
async_stagger
diff --git a/pkgs/development/python-modules/lsassy/default.nix b/pkgs/development/python-modules/lsassy/default.nix
index 38f0e218b91b..421c1f481e8a 100644
--- a/pkgs/development/python-modules/lsassy/default.nix
+++ b/pkgs/development/python-modules/lsassy/default.nix
@@ -9,13 +9,13 @@
buildPythonPackage rec {
pname = "lsassy";
- version = "3.1.0";
+ version = "3.1.1";
src = fetchFromGitHub {
owner = "Hackndo";
repo = pname;
rev = "v${version}";
- sha256 = "0xycpyzjbzr7836hjzcbmf7sri0r2az65yc6yrgy6kay0v75j4p6";
+ sha256 = "0jd0kmp0mc8jn5qmgrspdx05vy6nyq773cj4yid1qyr8dmyx6a7n";
};
propagatedBuildInputs = [
diff --git a/pkgs/development/python-modules/youtube-transcript-api/default.nix b/pkgs/development/python-modules/youtube-transcript-api/default.nix
index cd40f800c1b4..088ee476e3f0 100644
--- a/pkgs/development/python-modules/youtube-transcript-api/default.nix
+++ b/pkgs/development/python-modules/youtube-transcript-api/default.nix
@@ -2,14 +2,14 @@
buildPythonPackage rec {
pname = "youtube-transcript-api";
- version = "0.4.2";
+ version = "0.4.3";
# PyPI tarball is missing some test files
src = fetchFromGitHub {
owner = "jdepoix";
repo = "youtube-transcript-api";
rev = "v${version}";
- sha256 = "04x7mfp4q17w3n8dnklbxblz22496g7g4879nz0wzgijg3m6cwlp";
+ sha256 = "1krak5j2faj6951cl13h7hg9i3kyp6nslcbi608k8hxlbd80hc5h";
};
propagatedBuildInputs = [ requests ];
diff --git a/pkgs/development/tools/rocminfo/default.nix b/pkgs/development/tools/rocminfo/default.nix
index cef5d7e3666f..2734cfa09317 100644
--- a/pkgs/development/tools/rocminfo/default.nix
+++ b/pkgs/development/tools/rocminfo/default.nix
@@ -7,13 +7,13 @@
# compilers to determine the desired target.
, defaultTargets ? []}:
stdenv.mkDerivation rec {
- version = "4.3.1";
+ version = "4.5.2";
pname = "rocminfo";
src = fetchFromGitHub {
owner = "RadeonOpenCompute";
repo = "rocminfo";
rev = "rocm-${version}";
- sha256 = "sha256-n80tiSVaPTFl4imZvoFENM4KhPLxgDKz5VlOvhEYlV0=";
+ sha256 = "sha256-VIlHYiGLen4xmdP7kpmObj5wKy6Qq7iupJFtPa4Zd98=";
};
enableParallelBuilding = true;
diff --git a/pkgs/os-specific/linux/systemd/default.nix b/pkgs/os-specific/linux/systemd/default.nix
index 5a458cd04ecb..e22b8f877bf6 100644
--- a/pkgs/os-specific/linux/systemd/default.nix
+++ b/pkgs/os-specific/linux/systemd/default.nix
@@ -2,6 +2,7 @@
{ stdenv
, lib
+, nixosTests
, fetchFromGitHub
, fetchpatch
, fetchzip
@@ -603,6 +604,10 @@ stdenv.mkDerivation {
# runtime; otherwise we can't and we need to reboot.
passthru.interfaceVersion = 2;
+ passthru.tests = {
+ inherit (nixosTests) switchTest;
+ };
+
meta = with lib; {
homepage = "https://www.freedesktop.org/wiki/Software/systemd/";
description = "A system and service manager for Linux";
diff --git a/pkgs/os-specific/solo5/default.nix b/pkgs/os-specific/solo5/default.nix
index 71584aff7760..d45a2f0665de 100644
--- a/pkgs/os-specific/solo5/default.nix
+++ b/pkgs/os-specific/solo5/default.nix
@@ -1,7 +1,7 @@
{ lib, stdenv, fetchurl, pkg-config, libseccomp, util-linux, qemu }:
let
- version = "0.6.8";
+ version = "0.6.9";
# list of all theoretically available targets
targets = [
"genode"
@@ -19,9 +19,8 @@ in stdenv.mkDerivation {
buildInputs = lib.optional (stdenv.hostPlatform.isLinux) libseccomp;
src = fetchurl {
- url =
- "https://github.com/Solo5/solo5/releases/download/v${version}/solo5-v${version}.tar.gz";
- sha256 = "sha256-zrxNCXJIuEbtE3YNRK8Bxu2koHsQkcF+xItoIyhj9Uc=";
+ url = "https://github.com/Solo5/solo5/releases/download/v${version}/solo5-v${version}.tar.gz";
+ sha256 = "03lvk9mab3yxrmi73wrvvhykqcydjrsda0wj6aasnjm5lx9jycpr";
};
hardeningEnable = [ "pie" ];
diff --git a/pkgs/shells/zsh/oh-my-zsh/default.nix b/pkgs/shells/zsh/oh-my-zsh/default.nix
index ddf89b38d5de..deec8d9b838b 100644
--- a/pkgs/shells/zsh/oh-my-zsh/default.nix
+++ b/pkgs/shells/zsh/oh-my-zsh/default.nix
@@ -5,15 +5,15 @@
, git, nix, nixfmt, jq, coreutils, gnused, curl, cacert }:
stdenv.mkDerivation rec {
- version = "2021-12-07";
+ version = "2021-12-13";
pname = "oh-my-zsh";
- rev = "5b987e59d0fce1a74bcfd51750c6f52d7c29c647";
+ rev = "9a3d853481645ae0f961e9cc8421fc5d84e2c3c3";
src = fetchFromGitHub {
inherit rev;
owner = "ohmyzsh";
repo = "ohmyzsh";
- sha256 = "JNAuWsD03F8fbhHwwDnDh+2pPjJsyFnT/oboZIhk3rc=";
+ sha256 = "TFktV7xBm3KaRfW+cUGdwIZZD7TfU0gaq4J8cKBjtMM=";
};
installPhase = ''
diff --git a/pkgs/tools/misc/graylog/default.nix b/pkgs/tools/misc/graylog/default.nix
index 729cfbc283f9..3fd00a5e411d 100644
--- a/pkgs/tools/misc/graylog/default.nix
+++ b/pkgs/tools/misc/graylog/default.nix
@@ -2,11 +2,11 @@
stdenv.mkDerivation rec {
pname = "graylog";
- version = "3.3.14";
+ version = "3.3.15";
src = fetchurl {
url = "https://packages.graylog2.org/releases/graylog/graylog-${version}.tgz";
- sha256 = "04dslbvgrraacsw7wydbiv8jc753as2g54wn9sgh3lsryvzrfqfa";
+ sha256 = "sha256-/ECHhgLhmLoZ9fjpwGQrGuOW5PBtkB3JUCC9Bgvxr30=";
};
dontBuild = true;
diff --git a/pkgs/tools/security/fierce/default.nix b/pkgs/tools/security/fierce/default.nix
index 95be0dcaedde..9b8d8735b079 100644
--- a/pkgs/tools/security/fierce/default.nix
+++ b/pkgs/tools/security/fierce/default.nix
@@ -1,31 +1,40 @@
-{ lib, fetchFromGitHub, python3 }:
+{ lib
+, fetchFromGitHub
+, python3
+}:
python3.pkgs.buildPythonApplication rec {
pname = "fierce";
- version = "1.4.0";
+ version = "1.5.0";
+ format = "setuptools";
src = fetchFromGitHub {
owner = "mschwager";
repo = pname;
rev = version;
- sha256 = "11yaz8ap9swx95j3wpqh0b6jhw6spqgfnsyn1liw9zqi4jwgiax7";
+ sha256 = "sha256-9VTPD5i203BTl2nADjq131W9elgnaHNIWGIUuCiYlHg=";
};
- postPatch = ''
- substituteInPlace requirements.txt --replace 'dnspython==1.16.0' 'dnspython'
- '';
+ propagatedBuildInputs = with python3.pkgs; [
+ dnspython
+ ];
- propagatedBuildInputs = [ python3.pkgs.dnspython ];
+ postPatch = ''
+ substituteInPlace requirements.txt \
+ --replace 'dnspython==1.16.0' 'dnspython'
+ '';
# tests require network access
doCheck = false;
- pythonImportsCheck = [ "fierce" ];
+
+ pythonImportsCheck = [
+ "fierce"
+ ];
meta = with lib; {
- homepage = "https://github.com/mschwager/fierce";
description = "DNS reconnaissance tool for locating non-contiguous IP space";
+ homepage = "https://github.com/mschwager/fierce";
license = licenses.gpl3Plus;
maintainers = with maintainers; [ c0bw3b ];
- platforms = platforms.all;
};
}
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index 535ab5955e17..f375f6dda845 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -676,6 +676,8 @@ in {
asyncio-nats-client = callPackage ../development/python-modules/asyncio-nats-client { };
+ asyncio-rlock = callPackage ../development/python-modules/asyncio-rlock { };
+
asyncmy = callPackage ../development/python-modules/asyncmy { };
asyncio-throttle = callPackage ../development/python-modules/asyncio-throttle { };