Merge master into staging-next
This commit is contained in:
commit
420df1e082
|
@ -87,7 +87,32 @@
|
||||||
</section>
|
</section>
|
||||||
<section xml:id="sec-release-22.05-notable-changes">
|
<section xml:id="sec-release-22.05-notable-changes">
|
||||||
<title>Other Notable Changes</title>
|
<title>Other Notable Changes</title>
|
||||||
<para>
|
<itemizedlist spacing="compact">
|
||||||
</para>
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The option
|
||||||
|
<link linkend="opt-services.redis.servers">services.redis.servers</link>
|
||||||
|
was added to support per-application
|
||||||
|
<literal>redis-server</literal> 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
|
||||||
|
<literal>services.redis.settings</literal> to
|
||||||
|
<literal>services.redis.servers."".settings</literal>,
|
||||||
|
but you are strongly encouraged to name each
|
||||||
|
<literal>redis-server</literal> instance after the application
|
||||||
|
using it, instead of keeping that nameless one. Except for the
|
||||||
|
nameless
|
||||||
|
<literal>services.redis.servers.""</literal> still
|
||||||
|
accessible at <literal>127.0.0.1:6379</literal>, and to the
|
||||||
|
members of the Unix group <literal>redis</literal> through the
|
||||||
|
Unix socket <literal>/run/redis/redis.sock</literal>, all
|
||||||
|
other <literal>services.redis.servers.${serverName}</literal>
|
||||||
|
are only accessible by default to the members of the Unix
|
||||||
|
group <literal>redis-${serverName}</literal> through the Unix
|
||||||
|
socket <literal>/run/redis-${serverName}/redis.sock</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -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.
|
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}
|
## 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`.
|
||||||
|
|
|
@ -5,17 +5,18 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.services.redis;
|
cfg = config.services.redis;
|
||||||
|
|
||||||
ulimitNofile = cfg.maxclients + 32;
|
|
||||||
|
|
||||||
mkValueString = value:
|
mkValueString = value:
|
||||||
if value == true then "yes"
|
if value == true then "yes"
|
||||||
else if value == false then "no"
|
else if value == false then "no"
|
||||||
else generators.mkValueStringDefault { } value;
|
else generators.mkValueStringDefault { } value;
|
||||||
|
|
||||||
redisConfig = pkgs.writeText "redis.conf" (generators.toKeyValue {
|
redisConfig = settings: pkgs.writeText "redis.conf" (generators.toKeyValue {
|
||||||
listsAsDuplicateKeys = true;
|
listsAsDuplicateKeys = true;
|
||||||
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " ";
|
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 {
|
in {
|
||||||
imports = [
|
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" "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" "appendOnlyFilename" ] "This option was never used.")
|
||||||
(mkRemovedOptionModule [ "services" "redis" "pidFile" ] "This option was removed.")
|
(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
|
###### interface
|
||||||
|
@ -32,18 +54,6 @@ in {
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
services.redis = {
|
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 {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.redis;
|
default = pkgs.redis;
|
||||||
|
@ -51,176 +61,226 @@ in {
|
||||||
description = "Which Redis derivation to use.";
|
description = "Which Redis derivation to use.";
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
vmOverCommit = mkEnableOption ''
|
||||||
type = types.port;
|
setting of vm.overcommit_memory to 1
|
||||||
default = 6379;
|
(Suggested for Background Saving: http://redis.io/topics/faq)
|
||||||
description = "The port for Redis to listen to.";
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
vmOverCommit = mkOption {
|
servers = mkOption {
|
||||||
type = types.bool;
|
type = with types; attrsOf (submodule ({config, name, ...}@args: {
|
||||||
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.
|
|
||||||
<literal>null</literal> 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 ({ ... }: {
|
|
||||||
options = {
|
options = {
|
||||||
ip = mkOption {
|
enable = mkEnableOption ''
|
||||||
type = str;
|
Redis server.
|
||||||
description = "IP of the Redis master";
|
|
||||||
example = "192.168.1.100";
|
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 {
|
port = mkOption {
|
||||||
type = port;
|
type = types.port;
|
||||||
description = "port of the Redis master";
|
|
||||||
default = 6379;
|
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.
|
||||||
|
<literal>null</literal> 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
|
||||||
|
<link xlink:href="https://redis.io/topics/config"/>
|
||||||
|
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; })
|
||||||
|
];
|
||||||
}));
|
}));
|
||||||
|
description = "Configuration of multiple <literal>redis-server</literal> instances.";
|
||||||
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) ]);
|
|
||||||
default = {};
|
default = {};
|
||||||
description = ''
|
|
||||||
Redis configuration. Refer to
|
|
||||||
<link xlink:href="https://redis.io/topics/config"/>
|
|
||||||
for details on supported values.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
{
|
|
||||||
loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -229,78 +289,61 @@ in {
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkIf config.services.redis.enable {
|
config = mkIf (enabledServers != {}) {
|
||||||
assertions = [{
|
|
||||||
assertion = cfg.requirePass != null -> cfg.requirePassFile == null;
|
assertions = attrValues (mapAttrs (name: conf: {
|
||||||
message = "You can only set one services.redis.requirePass or services.redis.requirePassFile";
|
assertion = conf.requirePass != null -> conf.requirePassFile == null;
|
||||||
}];
|
message = ''
|
||||||
boot.kernel.sysctl = (mkMerge [
|
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"; }
|
{ "vm.nr_hugepages" = "0"; }
|
||||||
( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
|
( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
|
||||||
]);
|
];
|
||||||
|
|
||||||
networking.firewall = mkIf cfg.openFirewall {
|
networking.firewall.allowedTCPPorts = concatMap (conf:
|
||||||
allowedTCPPorts = [ cfg.port ];
|
optional conf.openFirewall conf.port
|
||||||
};
|
) (attrValues enabledServers);
|
||||||
|
|
||||||
users.users.redis = {
|
|
||||||
description = "Redis database user";
|
|
||||||
group = "redis";
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
users.groups.redis = {};
|
|
||||||
|
|
||||||
environment.systemPackages = [ cfg.package ];
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
services.redis.settings = mkMerge [
|
users.users = mapAttrs' (name: conf: nameValuePair (redisName name) {
|
||||||
{
|
description = "System user for the redis-server instance ${name}";
|
||||||
port = cfg.port;
|
isSystemUser = true;
|
||||||
daemonize = false;
|
group = redisName name;
|
||||||
supervised = "systemd";
|
}) enabledServers;
|
||||||
loglevel = cfg.logLevel;
|
users.groups = mapAttrs' (name: conf: nameValuePair (redisName name) {
|
||||||
logfile = cfg.logfile;
|
}) enabledServers;
|
||||||
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; })
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services.redis = {
|
systemd.services = mapAttrs' (name: conf: nameValuePair (redisName name) {
|
||||||
description = "Redis Server";
|
description = "Redis Server - ${redisName name}";
|
||||||
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.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 = {
|
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";
|
Type = "notify";
|
||||||
# User and group
|
# User and group
|
||||||
User = "redis";
|
User = conf.user;
|
||||||
Group = "redis";
|
Group = conf.user;
|
||||||
# Runtime directory and mode
|
# Runtime directory and mode
|
||||||
RuntimeDirectory = "redis";
|
RuntimeDirectory = redisName name;
|
||||||
RuntimeDirectoryMode = "0750";
|
RuntimeDirectoryMode = "0750";
|
||||||
# State directory and mode
|
# State directory and mode
|
||||||
StateDirectory = "redis";
|
StateDirectory = redisName name;
|
||||||
StateDirectoryMode = "0700";
|
StateDirectoryMode = "0700";
|
||||||
# Access write directories
|
# Access write directories
|
||||||
UMask = "0077";
|
UMask = "0077";
|
||||||
|
@ -309,7 +352,7 @@ in {
|
||||||
# Security
|
# Security
|
||||||
NoNewPrivileges = true;
|
NoNewPrivileges = true;
|
||||||
# Process Properties
|
# Process Properties
|
||||||
LimitNOFILE = "${toString ulimitNofile}";
|
LimitNOFILE = mkDefault "${toString (conf.maxclients + 32)}";
|
||||||
# Sandboxing
|
# Sandboxing
|
||||||
ProtectSystem = "strict";
|
ProtectSystem = "strict";
|
||||||
ProtectHome = true;
|
ProtectHome = true;
|
||||||
|
@ -322,7 +365,9 @@ in {
|
||||||
ProtectKernelModules = true;
|
ProtectKernelModules = true;
|
||||||
ProtectKernelTunables = true;
|
ProtectKernelTunables = true;
|
||||||
ProtectControlGroups = 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;
|
RestrictNamespaces = true;
|
||||||
LockPersonality = true;
|
LockPersonality = true;
|
||||||
MemoryDenyWriteExecute = true;
|
MemoryDenyWriteExecute = true;
|
||||||
|
@ -333,6 +378,7 @@ in {
|
||||||
SystemCallArchitectures = "native";
|
SystemCallArchitectures = "native";
|
||||||
SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
|
SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
|
||||||
};
|
};
|
||||||
};
|
}) enabledServers;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,79 @@ sub fingerprintUnit {
|
||||||
return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
|
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.
|
# Figure out what units need to be stopped, started, restarted or reloaded.
|
||||||
my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
|
my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
|
||||||
|
|
||||||
|
@ -218,69 +291,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
|
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$/) {
|
handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip);
|
||||||
# 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -939,7 +939,7 @@ let
|
||||||
exporterConfig = {
|
exporterConfig = {
|
||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
metricProvider.services.redis.enable = true;
|
metricProvider.services.redis.servers."".enable = true;
|
||||||
exporterTest = ''
|
exporterTest = ''
|
||||||
wait_for_unit("redis.service")
|
wait_for_unit("redis.service")
|
||||||
wait_for_unit("prometheus-redis-exporter.service")
|
wait_for_unit("prometheus-redis-exporter.service")
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import ./make-test-python.nix ({ pkgs, ... }:
|
import ./make-test-python.nix ({ pkgs, ... }:
|
||||||
let
|
|
||||||
redisSocket = "/run/redis/redis.sock";
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
name = "redis";
|
name = "redis";
|
||||||
meta = with pkgs.lib.maintainers; {
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
@ -10,35 +7,40 @@ in
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
machine =
|
machine =
|
||||||
{ pkgs, ... }:
|
{ pkgs, lib, ... }: with lib;
|
||||||
|
|
||||||
{
|
{
|
||||||
services.redis.enable = true;
|
services.redis.servers."".enable = true;
|
||||||
services.redis.unixSocket = redisSocket;
|
services.redis.servers."test".enable = true;
|
||||||
|
|
||||||
# Allow access to the unix socket for the "redis" group.
|
users.users = listToAttrs (map (suffix: nameValuePair "member${suffix}" {
|
||||||
services.redis.unixSocketPerm = 770;
|
|
||||||
|
|
||||||
users.users."member" = {
|
|
||||||
createHome = false;
|
createHome = false;
|
||||||
description = "A member of the redis group";
|
description = "A member of the redis${suffix} group";
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
extraGroups = [
|
extraGroups = [ "redis${suffix}" ];
|
||||||
"redis"
|
}) ["" "-test"]);
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = { nodes, ... }: let
|
||||||
|
inherit (nodes.machine.config.services) redis;
|
||||||
|
in ''
|
||||||
start_all()
|
start_all()
|
||||||
machine.wait_for_unit("redis")
|
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_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
|
# The unix socket is accessible to the redis group
|
||||||
machine.succeed('su member -c "redis-cli ping | grep PONG"')
|
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 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")
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,21 +3,138 @@
|
||||||
import ./make-test-python.nix ({ pkgs, ...} : {
|
import ./make-test-python.nix ({ pkgs, ...} : {
|
||||||
name = "switch-test";
|
name = "switch-test";
|
||||||
meta = with pkgs.lib.maintainers; {
|
meta = with pkgs.lib.maintainers; {
|
||||||
maintainers = [ gleber ];
|
maintainers = [ gleber das_j ];
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
machine = { ... }: {
|
machine = { pkgs, lib, ... }: {
|
||||||
users.mutableUsers = false;
|
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;
|
users.mutableUsers = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = {nodes, ...}: let
|
testScript = { nodes, ... }: let
|
||||||
originalSystem = nodes.machine.config.system.build.toplevel;
|
originalSystem = nodes.machine.config.system.build.toplevel;
|
||||||
otherSystem = nodes.other.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
|
# Ensures failures pass through using pipefail, otherwise failing to
|
||||||
# switch-to-configuration is hidden by the success of `tee`.
|
# switch-to-configuration is hidden by the success of `tee`.
|
||||||
|
@ -27,12 +144,186 @@ import ./make-test-python.nix ({ pkgs, ...} : {
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
exec env -i "$@" | tee /dev/stderr
|
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(
|
machine.succeed(
|
||||||
"${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
|
"${stderrRunner} ${originalSystem}/bin/switch-to-configuration test"
|
||||||
)
|
)
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"${stderrRunner} ${otherSystem}/bin/switch-to-configuration test"
|
"${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
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,17 +10,19 @@ import ./make-test-python.nix ({ pkgs, ... }:
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
services.redis.enable = true;
|
services.redis.servers."".enable = true;
|
||||||
services.redis.unixSocket = "/run/redis/redis.sock";
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [ (python38.withPackages (ps: [ ps.twisted ps.txredisapi ps.mock ]))];
|
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()
|
start_all()
|
||||||
machine.wait_for_unit("redis")
|
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")
|
tests = machine.succeed("PYTHONPATH=\"${pkgs.python3Packages.txredisapi.src}\" python -m twisted.trial ${pkgs.python3Packages.txredisapi.src}/tests")
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
, Xaw3d, libXcursor, pkg-config, gettext, libXft, dbus, libpng, libjpeg, giflib
|
, Xaw3d, libXcursor, pkg-config, gettext, libXft, dbus, libpng, libjpeg, giflib
|
||||||
, libtiff, librsvg, gconf, libxml2, imagemagick, gnutls, libselinux
|
, libtiff, librsvg, gconf, libxml2, imagemagick, gnutls, libselinux
|
||||||
, alsa-lib, cairo, acl, gpm, AppKit, GSS, ImageIO, m17n_lib, libotf
|
, alsa-lib, cairo, acl, gpm, AppKit, GSS, ImageIO, m17n_lib, libotf
|
||||||
, sigtool, jansson, harfbuzz
|
, sigtool, jansson, harfbuzz, sqlite
|
||||||
, dontRecurseIntoAttrs ,emacsPackagesFor
|
, dontRecurseIntoAttrs ,emacsPackagesFor
|
||||||
, libgccjit, targetPlatform, makeWrapper # native-comp params
|
, libgccjit, targetPlatform, makeWrapper # native-comp params
|
||||||
, systemd ? null
|
, systemd ? null
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
, withGTK3 ? true, gtk3-x11 ? null, gsettings-desktop-schemas ? null
|
, withGTK3 ? true, gtk3-x11 ? null, gsettings-desktop-schemas ? null
|
||||||
, withXwidgets ? false, webkitgtk ? null, wrapGAppsHook ? null, glib-networking ? null
|
, withXwidgets ? false, webkitgtk ? null, wrapGAppsHook ? null, glib-networking ? null
|
||||||
, withMotif ? false, motif ? null
|
, withMotif ? false, motif ? null
|
||||||
|
, withSQLite3 ? false
|
||||||
, withCsrc ? true
|
, withCsrc ? true
|
||||||
, srcRepo ? false, autoreconfHook ? null, texinfo ? null
|
, srcRepo ? false, autoreconfHook ? null, texinfo ? null
|
||||||
, siteStart ? ./site-start.el
|
, siteStart ? ./site-start.el
|
||||||
|
@ -116,6 +117,7 @@ let emacs = stdenv.mkDerivation (lib.optionalAttrs nativeComp {
|
||||||
++ lib.optional (withX && withGTK2) gtk2-x11
|
++ lib.optional (withX && withGTK2) gtk2-x11
|
||||||
++ lib.optionals (withX && withGTK3) [ gtk3-x11 gsettings-desktop-schemas ]
|
++ lib.optionals (withX && withGTK3) [ gtk3-x11 gsettings-desktop-schemas ]
|
||||||
++ lib.optional (withX && withMotif) motif
|
++ lib.optional (withX && withMotif) motif
|
||||||
|
++ lib.optional withSQLite3 sqlite
|
||||||
++ lib.optionals (withX && withXwidgets) [ webkitgtk glib-networking ]
|
++ lib.optionals (withX && withXwidgets) [ webkitgtk glib-networking ]
|
||||||
++ lib.optionals withNS [ AppKit GSS ImageIO ]
|
++ lib.optionals withNS [ AppKit GSS ImageIO ]
|
||||||
++ lib.optionals stdenv.isDarwin [ sigtool ]
|
++ lib.optionals stdenv.isDarwin [ sigtool ]
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "latte-dock";
|
pname = "latte-dock";
|
||||||
version = "0.10.0";
|
version = "0.10.4";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://download.kde.org/stable/${pname}/${pname}-${version}.tar.xz";
|
url = "https://download.kde.org/stable/${pname}/${pname}-${version}.tar.xz";
|
||||||
sha256 = "04kq86qmrjbzidrkknj000pv1b5z0r7nfidhy2zv67ks8fdi4zln";
|
sha256 = "XRop+MNcbeCcbnL2LM1i67QvMudW3CjWYEPLkT/qbGM=";
|
||||||
name = "${pname}-${version}.tar.xz";
|
name = "${pname}-${version}.tar.xz";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "kubelogin";
|
pname = "kubelogin";
|
||||||
version = "1.23.3";
|
version = "1.25.0";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "int128";
|
owner = "int128";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-qhdt/j1yFlCr+CCM3VQHxRVMEelZDsjhDJW9CYNCx2U=";
|
sha256 = "sha256-orclZtmkdplTRvYkN7VotbynSQ9L2kvAPqP20j8QJ2s=";
|
||||||
};
|
};
|
||||||
|
|
||||||
subPackages = ["."];
|
subPackages = ["."];
|
||||||
|
|
||||||
vendorSha256 = "sha256-RxIrnwIHDi9umu9bqpz3lnpNFdIWoTP657Te9iBv4IA=";
|
vendorSha256 = "sha256-i46G0lsRvh/PmM+pMYuAjoLMHWF1Uzbd8+EkjIId8KE=";
|
||||||
|
|
||||||
# Rename the binary instead of symlinking to avoid conflict with the
|
# Rename the binary instead of symlinking to avoid conflict with the
|
||||||
# Azure version of kubelogin
|
# Azure version of kubelogin
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
, qtkeychain
|
, qtkeychain
|
||||||
, qtmacextras
|
, qtmacextras
|
||||||
, qtmultimedia
|
, qtmultimedia
|
||||||
|
, qtimageformats
|
||||||
, qttools
|
, qttools
|
||||||
, qtquickcontrols2
|
, qtquickcontrols2
|
||||||
, qtgraphicaleffects
|
, qtgraphicaleffects
|
||||||
|
@ -57,6 +58,7 @@ mkDerivation rec {
|
||||||
cmark
|
cmark
|
||||||
qtbase
|
qtbase
|
||||||
qtmultimedia
|
qtmultimedia
|
||||||
|
qtimageformats
|
||||||
qttools
|
qttools
|
||||||
qtquickcontrols2
|
qtquickcontrols2
|
||||||
qtgraphicaleffects
|
qtgraphicaleffects
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"version": "1.9.0-sc.1",
|
"version": "1.9.7-sc.1",
|
||||||
"srcHash": "10swz5gwz1izryzllmjm8mhhd0vqk2cp8qjcmmr5gbzspj7p3xgw",
|
"srcHash": "0qrjjwcxa141phsgdz325rrkfmjqdmxc3h917cs9c9kf6cblkxaq",
|
||||||
"webYarnHash": "134llyh0197andpnbmfcxnidcgi3xxnb9v10bwfvrqysgnhb5z8v",
|
"webYarnHash": "19c594pql2yz1z15phfdlkwcvrcbm8k058fcq7p0k6840dhif5fd",
|
||||||
"desktopYarnHash": "150jc6p9kbdz599bdkinrhbhncpamhz35j6rcc008qxg2d9qfhwr"
|
"desktopYarnHash": "058ihkljb1swjzvgf8gqci5ghvwapmpcf2bsab3yr66lhps7fhci"
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
version = "1.10.2";
|
version = "1.10.3";
|
||||||
|
|
||||||
# build stimuli file for PGO build and the script to generate it
|
# build stimuli file for PGO build and the script to generate it
|
||||||
# independently of the foot's build, so we can cache the result
|
# independently of the foot's build, so we can cache the result
|
||||||
|
@ -99,7 +99,7 @@ stdenv.mkDerivation rec {
|
||||||
owner = "dnkl";
|
owner = "dnkl";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "00096c2m8pn4gpafvmg9lhyprwgnsis62bq4qmagnbb49bj5kr9v";
|
sha256 = "13v6xqaw3xn1x84dn4gnkiimcsllb19mrbvcdj2fnm8klnrys3gs";
|
||||||
};
|
};
|
||||||
|
|
||||||
depsBuildBuild = [
|
depsBuildBuild = [
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "bctoolbox";
|
pname = "bctoolbox";
|
||||||
version = "5.0.0";
|
version = "5.0.55";
|
||||||
|
|
||||||
nativeBuildInputs = [ cmake bcunit ];
|
nativeBuildInputs = [ cmake bcunit ];
|
||||||
buildInputs = [ mbedtls ];
|
buildInputs = [ mbedtls ];
|
||||||
|
@ -18,7 +18,7 @@ stdenv.mkDerivation rec {
|
||||||
group = "BC";
|
group = "BC";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "sha256-/jv59ZeELfP7PokzthvZNL4FS3tyzRmCHp4I/Lp8BJM=";
|
sha256 = "sha256-fZ+8XBTZ6/wNd8odzg20dAXtbjRudI6Nw0hKC9bopGo=";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Do not build static libraries
|
# Do not build static libraries
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "olm";
|
pname = "olm";
|
||||||
version = "3.2.6";
|
version = "3.2.8";
|
||||||
|
|
||||||
src = fetchFromGitLab {
|
src = fetchFromGitLab {
|
||||||
domain = "gitlab.matrix.org";
|
domain = "gitlab.matrix.org";
|
||||||
owner = "matrix-org";
|
owner = "matrix-org";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "1srmw36nxi0z2y5d9adks09p950qm0fscbnrq1fl37fdypvjl1sk";
|
sha256 = "1jfhydfcnqpksb2bhi960v3h10prf4v5gx42mm2rp6p0jfbqcy50";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ cmake ];
|
nativeBuildInputs = [ cmake ];
|
||||||
|
|
28
pkgs/development/python-modules/asyncio-rlock/default.nix
Normal file
28
pkgs/development/python-modules/asyncio-rlock/default.nix
Normal file
|
@ -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 ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,12 +7,12 @@
|
||||||
|
|
||||||
buildPythonPackage rec {
|
buildPythonPackage rec {
|
||||||
pname = "fastecdsa";
|
pname = "fastecdsa";
|
||||||
version = "2.2.2";
|
version = "2.2.3";
|
||||||
format = "setuptools";
|
format = "setuptools";
|
||||||
|
|
||||||
src = fetchPypi {
|
src = fetchPypi {
|
||||||
inherit pname version;
|
inherit pname version;
|
||||||
sha256 = "1eb6f3ac86ec483a10df62fcda1fb9a9d5d895a436871a8aa935dd20ccd82c6f";
|
sha256 = "269bdb0f618b38f8f6aec9d23d23db518046c3cee01a954fa6aa7322a1a7db8f";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildInputs = [ gmp ];
|
buildInputs = [ gmp ];
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
, fetchFromGitHub
|
, fetchFromGitHub
|
||||||
, pythonOlder
|
, pythonOlder
|
||||||
, anyio
|
, anyio
|
||||||
|
, asyncio-rlock
|
||||||
, asyncio-throttle
|
, asyncio-throttle
|
||||||
, dataclasses
|
, dataclasses
|
||||||
, ircstates
|
, ircstates
|
||||||
|
@ -13,23 +14,26 @@
|
||||||
|
|
||||||
buildPythonPackage rec {
|
buildPythonPackage rec {
|
||||||
pname = "ircrobots";
|
pname = "ircrobots";
|
||||||
version = "0.3.8";
|
version = "0.4.6";
|
||||||
disabled = pythonOlder "3.6";
|
disabled = pythonOlder "3.6";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "jesopo";
|
owner = "jesopo";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "06q86dqllxvi3nssfplmjk9yxaybighwh87lrxfpfhl8yy4z68jz";
|
sha256 = "sha256-+BrS1+ZkgwT/qvqD0PwRZi2LF+31biS738SzKH1dy7w=";
|
||||||
};
|
};
|
||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
# too specific pins https://github.com/jesopo/ircrobots/issues/3
|
# too specific pins https://github.com/jesopo/ircrobots/issues/3
|
||||||
sed -iE 's/anyio.*/anyio/' requirements.txt
|
sed -iE 's/anyio.*/anyio/' requirements.txt
|
||||||
|
sed -iE 's/ircstates.*/ircstates/' requirements.txt
|
||||||
|
sed -iE 's/async_timeout.*/async_timeout/' requirements.txt
|
||||||
'';
|
'';
|
||||||
|
|
||||||
propagatedBuildInputs = [
|
propagatedBuildInputs = [
|
||||||
anyio
|
anyio
|
||||||
|
asyncio-rlock
|
||||||
asyncio-throttle
|
asyncio-throttle
|
||||||
ircstates
|
ircstates
|
||||||
async_stagger
|
async_stagger
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
|
|
||||||
buildPythonPackage rec {
|
buildPythonPackage rec {
|
||||||
pname = "lsassy";
|
pname = "lsassy";
|
||||||
version = "3.1.0";
|
version = "3.1.1";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "Hackndo";
|
owner = "Hackndo";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "0xycpyzjbzr7836hjzcbmf7sri0r2az65yc6yrgy6kay0v75j4p6";
|
sha256 = "0jd0kmp0mc8jn5qmgrspdx05vy6nyq773cj4yid1qyr8dmyx6a7n";
|
||||||
};
|
};
|
||||||
|
|
||||||
propagatedBuildInputs = [
|
propagatedBuildInputs = [
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
buildPythonPackage rec {
|
buildPythonPackage rec {
|
||||||
pname = "youtube-transcript-api";
|
pname = "youtube-transcript-api";
|
||||||
version = "0.4.2";
|
version = "0.4.3";
|
||||||
|
|
||||||
# PyPI tarball is missing some test files
|
# PyPI tarball is missing some test files
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "jdepoix";
|
owner = "jdepoix";
|
||||||
repo = "youtube-transcript-api";
|
repo = "youtube-transcript-api";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "04x7mfp4q17w3n8dnklbxblz22496g7g4879nz0wzgijg3m6cwlp";
|
sha256 = "1krak5j2faj6951cl13h7hg9i3kyp6nslcbi608k8hxlbd80hc5h";
|
||||||
};
|
};
|
||||||
|
|
||||||
propagatedBuildInputs = [ requests ];
|
propagatedBuildInputs = [ requests ];
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
# compilers to determine the desired target.
|
# compilers to determine the desired target.
|
||||||
, defaultTargets ? []}:
|
, defaultTargets ? []}:
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
version = "4.3.1";
|
version = "4.5.2";
|
||||||
pname = "rocminfo";
|
pname = "rocminfo";
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "RadeonOpenCompute";
|
owner = "RadeonOpenCompute";
|
||||||
repo = "rocminfo";
|
repo = "rocminfo";
|
||||||
rev = "rocm-${version}";
|
rev = "rocm-${version}";
|
||||||
sha256 = "sha256-n80tiSVaPTFl4imZvoFENM4KhPLxgDKz5VlOvhEYlV0=";
|
sha256 = "sha256-VIlHYiGLen4xmdP7kpmObj5wKy6Qq7iupJFtPa4Zd98=";
|
||||||
};
|
};
|
||||||
|
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
{ stdenv
|
{ stdenv
|
||||||
, lib
|
, lib
|
||||||
|
, nixosTests
|
||||||
, fetchFromGitHub
|
, fetchFromGitHub
|
||||||
, fetchpatch
|
, fetchpatch
|
||||||
, fetchzip
|
, fetchzip
|
||||||
|
@ -616,6 +617,10 @@ stdenv.mkDerivation {
|
||||||
# runtime; otherwise we can't and we need to reboot.
|
# runtime; otherwise we can't and we need to reboot.
|
||||||
passthru.interfaceVersion = 2;
|
passthru.interfaceVersion = 2;
|
||||||
|
|
||||||
|
passthru.tests = {
|
||||||
|
inherit (nixosTests) switchTest;
|
||||||
|
};
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://www.freedesktop.org/wiki/Software/systemd/";
|
homepage = "https://www.freedesktop.org/wiki/Software/systemd/";
|
||||||
description = "A system and service manager for Linux";
|
description = "A system and service manager for Linux";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ lib, stdenv, fetchurl, pkg-config, libseccomp, util-linux, qemu }:
|
{ lib, stdenv, fetchurl, pkg-config, libseccomp, util-linux, qemu }:
|
||||||
|
|
||||||
let
|
let
|
||||||
version = "0.6.8";
|
version = "0.6.9";
|
||||||
# list of all theoretically available targets
|
# list of all theoretically available targets
|
||||||
targets = [
|
targets = [
|
||||||
"genode"
|
"genode"
|
||||||
|
@ -19,9 +19,8 @@ in stdenv.mkDerivation {
|
||||||
buildInputs = lib.optional (stdenv.hostPlatform.isLinux) libseccomp;
|
buildInputs = lib.optional (stdenv.hostPlatform.isLinux) libseccomp;
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url =
|
url = "https://github.com/Solo5/solo5/releases/download/v${version}/solo5-v${version}.tar.gz";
|
||||||
"https://github.com/Solo5/solo5/releases/download/v${version}/solo5-v${version}.tar.gz";
|
sha256 = "03lvk9mab3yxrmi73wrvvhykqcydjrsda0wj6aasnjm5lx9jycpr";
|
||||||
sha256 = "sha256-zrxNCXJIuEbtE3YNRK8Bxu2koHsQkcF+xItoIyhj9Uc=";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
hardeningEnable = [ "pie" ];
|
hardeningEnable = [ "pie" ];
|
||||||
|
|
|
@ -5,15 +5,15 @@
|
||||||
, git, nix, nixfmt, jq, coreutils, gnused, curl, cacert }:
|
, git, nix, nixfmt, jq, coreutils, gnused, curl, cacert }:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
version = "2021-12-07";
|
version = "2021-12-13";
|
||||||
pname = "oh-my-zsh";
|
pname = "oh-my-zsh";
|
||||||
rev = "5b987e59d0fce1a74bcfd51750c6f52d7c29c647";
|
rev = "9a3d853481645ae0f961e9cc8421fc5d84e2c3c3";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
inherit rev;
|
inherit rev;
|
||||||
owner = "ohmyzsh";
|
owner = "ohmyzsh";
|
||||||
repo = "ohmyzsh";
|
repo = "ohmyzsh";
|
||||||
sha256 = "JNAuWsD03F8fbhHwwDnDh+2pPjJsyFnT/oboZIhk3rc=";
|
sha256 = "TFktV7xBm3KaRfW+cUGdwIZZD7TfU0gaq4J8cKBjtMM=";
|
||||||
};
|
};
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "graylog";
|
pname = "graylog";
|
||||||
version = "3.3.14";
|
version = "3.3.15";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://packages.graylog2.org/releases/graylog/graylog-${version}.tgz";
|
url = "https://packages.graylog2.org/releases/graylog/graylog-${version}.tgz";
|
||||||
sha256 = "04dslbvgrraacsw7wydbiv8jc753as2g54wn9sgh3lsryvzrfqfa";
|
sha256 = "sha256-/ECHhgLhmLoZ9fjpwGQrGuOW5PBtkB3JUCC9Bgvxr30=";
|
||||||
};
|
};
|
||||||
|
|
||||||
dontBuild = true;
|
dontBuild = true;
|
||||||
|
|
|
@ -1,31 +1,40 @@
|
||||||
{ lib, fetchFromGitHub, python3 }:
|
{ lib
|
||||||
|
, fetchFromGitHub
|
||||||
|
, python3
|
||||||
|
}:
|
||||||
|
|
||||||
python3.pkgs.buildPythonApplication rec {
|
python3.pkgs.buildPythonApplication rec {
|
||||||
pname = "fierce";
|
pname = "fierce";
|
||||||
version = "1.4.0";
|
version = "1.5.0";
|
||||||
|
format = "setuptools";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "mschwager";
|
owner = "mschwager";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "11yaz8ap9swx95j3wpqh0b6jhw6spqgfnsyn1liw9zqi4jwgiax7";
|
sha256 = "sha256-9VTPD5i203BTl2nADjq131W9elgnaHNIWGIUuCiYlHg=";
|
||||||
};
|
};
|
||||||
|
|
||||||
postPatch = ''
|
propagatedBuildInputs = with python3.pkgs; [
|
||||||
substituteInPlace requirements.txt --replace 'dnspython==1.16.0' 'dnspython'
|
dnspython
|
||||||
'';
|
];
|
||||||
|
|
||||||
propagatedBuildInputs = [ python3.pkgs.dnspython ];
|
postPatch = ''
|
||||||
|
substituteInPlace requirements.txt \
|
||||||
|
--replace 'dnspython==1.16.0' 'dnspython'
|
||||||
|
'';
|
||||||
|
|
||||||
# tests require network access
|
# tests require network access
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
pythonImportsCheck = [ "fierce" ];
|
|
||||||
|
pythonImportsCheck = [
|
||||||
|
"fierce"
|
||||||
|
];
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://github.com/mschwager/fierce";
|
|
||||||
description = "DNS reconnaissance tool for locating non-contiguous IP space";
|
description = "DNS reconnaissance tool for locating non-contiguous IP space";
|
||||||
|
homepage = "https://github.com/mschwager/fierce";
|
||||||
license = licenses.gpl3Plus;
|
license = licenses.gpl3Plus;
|
||||||
maintainers = with maintainers; [ c0bw3b ];
|
maintainers = with maintainers; [ c0bw3b ];
|
||||||
platforms = platforms.all;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,6 +676,8 @@ in {
|
||||||
|
|
||||||
asyncio-nats-client = callPackage ../development/python-modules/asyncio-nats-client { };
|
asyncio-nats-client = callPackage ../development/python-modules/asyncio-nats-client { };
|
||||||
|
|
||||||
|
asyncio-rlock = callPackage ../development/python-modules/asyncio-rlock { };
|
||||||
|
|
||||||
asyncmy = callPackage ../development/python-modules/asyncmy { };
|
asyncmy = callPackage ../development/python-modules/asyncmy { };
|
||||||
|
|
||||||
asyncio-throttle = callPackage ../development/python-modules/asyncio-throttle { };
|
asyncio-throttle = callPackage ../development/python-modules/asyncio-throttle { };
|
||||||
|
|
Loading…
Reference in a new issue