Merge pull request #117073 from sternenseemann/inspircd-3.9.0

inspircd: init at 3.9.0

Changed files
+382
nixos
modules
services
networking
tests
pkgs
servers
irc
inspircd
top-level
+1
nixos/modules/module-list.nix
···
./services/networking/i2p.nix
./services/networking/icecream/scheduler.nix
./services/networking/icecream/daemon.nix
./services/networking/iodine.nix
./services/networking/iperf3.nix
./services/networking/ircd-hybrid/default.nix
···
./services/networking/i2p.nix
./services/networking/icecream/scheduler.nix
./services/networking/icecream/daemon.nix
+
./services/networking/inspircd.nix
./services/networking/iodine.nix
./services/networking/iperf3.nix
./services/networking/ircd-hybrid/default.nix
+62
nixos/modules/services/networking/inspircd.nix
···
···
+
{ config, lib, pkgs, ... }:
+
+
let
+
cfg = config.services.inspircd;
+
+
configFile = pkgs.writeText "inspircd.conf" cfg.config;
+
+
in {
+
meta = {
+
maintainers = [ lib.maintainers.sternenseemann ];
+
};
+
+
options = {
+
services.inspircd = {
+
enable = lib.mkEnableOption "InspIRCd";
+
+
package = lib.mkOption {
+
type = lib.types.package;
+
default = pkgs.inspircd;
+
defaultText = lib.literalExample "pkgs.inspircd";
+
example = lib.literalExample "pkgs.inspircdMinimal";
+
description = ''
+
The InspIRCd package to use. This is mainly useful
+
to specify an overridden version of the
+
<literal>pkgs.inspircd</literal> dervivation, for
+
example if you want to use a more minimal InspIRCd
+
distribution with less modules enabled or with
+
modules enabled which can't be distributed in binary
+
form due to licensing issues.
+
'';
+
};
+
+
config = lib.mkOption {
+
type = lib.types.lines;
+
description = ''
+
Verbatim <literal>inspircd.conf</literal> file.
+
For a list of options, consult the
+
<link xlink:href="https://docs.inspircd.org/3/configuration/">InspIRCd documentation</link>, the
+
<link xlink:href="https://docs.inspircd.org/3/modules/">Module documentation</link>
+
and the example configuration files distributed
+
with <literal>pkgs.inspircd.doc</literal>
+
'';
+
};
+
};
+
};
+
+
config = lib.mkIf cfg.enable {
+
systemd.services.inspircd = {
+
description = "InspIRCd - the stable, high-performance and modular Internet Relay Chat Daemon";
+
wantedBy = [ "multi-user.target" ];
+
requires = [ "network.target" ];
+
+
serviceConfig = {
+
Type = "simple";
+
ExecStart = ''
+
${lib.getBin cfg.package}/bin/inspircd start --config ${configFile} --nofork --nopid
+
'';
+
DynamicUser = true;
+
};
+
};
+
};
+
}
+1
nixos/tests/all-tests.nix
···
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrdNetwork = handleTest ./initrd-network.nix {};
initrd-secrets = handleTest ./initrd-secrets.nix {};
installer = handleTest ./installer.nix {};
iodine = handleTest ./iodine.nix {};
ipfs = handleTest ./ipfs.nix {};
···
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrdNetwork = handleTest ./initrd-network.nix {};
initrd-secrets = handleTest ./initrd-secrets.nix {};
+
inspircd = handleTest ./inspircd.nix {};
installer = handleTest ./installer.nix {};
iodine = handleTest ./iodine.nix {};
ipfs = handleTest ./ipfs.nix {};
+93
nixos/tests/inspircd.nix
···
···
+
let
+
clients = [
+
"ircclient1"
+
"ircclient2"
+
];
+
server = "inspircd";
+
ircPort = 6667;
+
channel = "nixos-cat";
+
iiDir = "/tmp/irc";
+
in
+
+
import ./make-test-python.nix ({ pkgs, lib, ... }: {
+
name = "inspircd";
+
nodes = {
+
"${server}" = {
+
networking.firewall.allowedTCPPorts = [ ircPort ];
+
services.inspircd = {
+
enable = true;
+
package = pkgs.inspircdMinimal;
+
config = ''
+
<bind address="" port="${toString ircPort}" type="clients">
+
<connect name="main" allow="*" pingfreq="15">
+
'';
+
};
+
};
+
} // lib.listToAttrs (builtins.map (client: lib.nameValuePair client {
+
imports = [
+
./common/user-account.nix
+
];
+
+
systemd.services.ii = {
+
requires = [ "network.target" ];
+
wantedBy = [ "default.target" ];
+
+
serviceConfig = {
+
Type = "simple";
+
ExecPreStartPre = "mkdir -p ${iiDir}";
+
ExecStart = ''
+
${lib.getBin pkgs.ii}/bin/ii -n ${client} -s ${server} -i ${iiDir}
+
'';
+
User = "alice";
+
};
+
};
+
}) clients);
+
+
testScript =
+
let
+
msg = client: "Hello, my name is ${client}";
+
clientScript = client: [
+
''
+
${client}.wait_for_unit("network.target")
+
${client}.systemctl("start ii")
+
${client}.wait_for_unit("ii")
+
${client}.wait_for_file("${iiDir}/${server}/out")
+
''
+
# wait until first PING from server arrives before joining,
+
# so we don't try it too early
+
''
+
${client}.wait_until_succeeds("grep 'PING' ${iiDir}/${server}/out")
+
''
+
# join ${channel}
+
''
+
${client}.succeed("echo '/j #${channel}' > ${iiDir}/${server}/in")
+
${client}.wait_for_file("${iiDir}/${server}/#${channel}/in")
+
''
+
# send a greeting
+
''
+
${client}.succeed(
+
"echo '${msg client}' > ${iiDir}/${server}/#${channel}/in"
+
)
+
''
+
# check that all greetings arrived on all clients
+
] ++ builtins.map (other: ''
+
${client}.succeed(
+
"grep '${msg other}$' ${iiDir}/${server}/#${channel}/out"
+
)
+
'') clients;
+
+
# foldl', but requires a non-empty list instead of a start value
+
reduce = f: list:
+
builtins.foldl' f (builtins.head list) (builtins.tail list);
+
in ''
+
start_all()
+
${server}.wait_for_open_port(${toString ircPort})
+
+
# run clientScript for all clients so that every list
+
# entry is executed by every client before advancing
+
# to the next one.
+
'' + lib.concatStrings
+
(reduce
+
(lib.zipListsWith (cs: c: cs + c))
+
(builtins.map clientScript clients));
+
})
+221
pkgs/servers/irc/inspircd/default.nix
···
···
+
let
+
# inspircd ships a few extra modules that users can load
+
# via configuration. Upstream thus recommends to ship as
+
# many of them as possible. There is however a problem:
+
# inspircd is licensed under the GPL version 2 only and
+
# some modules link libraries that are incompatible with
+
# the GPL 2. Therefore we can't provide them as binaries
+
# via our binary-caches, but users should still be able
+
# to override this package and build the incompatible
+
# modules themselves.
+
#
+
# This means for us we need to a) prevent hydra from
+
# building a module set with a GPL incompatibility
+
# and b) dynamically figure out the largest possible
+
# set of modules to use depending on stdenv, because
+
# the used libc needs to be compatible as well.
+
#
+
# For an overview of all modules and their licensing
+
# situation, see https://docs.inspircd.org/packaging/
+
+
# Predicate for checking license compatibility with
+
# GPLv2. Since this is _only_ used for libc compatibility
+
# checking, only whitelist licenses used by notable
+
# libcs in nixpkgs (musl and glibc).
+
compatible = lib: drv:
+
lib.any (lic: lic == drv.meta.license) [
+
lib.licenses.mit # musl
+
lib.licenses.lgpl2Plus # glibc
+
];
+
+
# compatible if libc is compatible
+
libcModules = [
+
"regex_posix"
+
"sslrehashsignal"
+
];
+
+
# compatible if libc++ is compatible
+
# TODO(sternenseemann):
+
# we could enable "regex_stdlib" automatically, but only if
+
# we are using libcxxStdenv which is compatible with GPLv2,
+
# since the gcc libstdc++ license is GPLv2-incompatible
+
libcxxModules = [
+
"regex_stdlib"
+
];
+
+
compatibleModules = lib: stdenv: [
+
# GPLv2 compatible dependencies
+
"argon2"
+
"ldap"
+
"mysql"
+
"pgsql"
+
"regex_pcre"
+
"regex_re2"
+
"regex_tre"
+
"sqlite3"
+
"ssl_gnutls"
+
] ++ lib.optionals (compatible lib stdenv.cc.libc) libcModules;
+
+
in
+
+
{ lib
+
, stdenv
+
, fetchFromGitHub
+
, nixosTests
+
, perl
+
, pkg-config
+
, libargon2
+
, openldap
+
, postgresql
+
, libmysqlclient
+
, pcre
+
, tre
+
, re2
+
, sqlite
+
, gnutls
+
, libmaxminddb
+
, openssl
+
, mbedtls
+
# For a full list of module names, see https://docs.inspircd.org/packaging/
+
, extraModules ? compatibleModules lib stdenv
+
}:
+
+
let
+
extras = {
+
# GPLv2 compatible
+
argon2 = [
+
(libargon2 // {
+
meta = libargon2.meta // {
+
# use libargon2 as CC0 since ASL20 is GPLv2-incompatible
+
# updating this here is important that meta.license is accurate
+
# libargon2 is licensed under either ASL20 or CC0.
+
license = lib.licenses.cc0;
+
};
+
})
+
];
+
ldap = [ openldap ];
+
mysql = [ libmysqlclient ];
+
pgsql = [ postgresql ];
+
regex_pcre = [ pcre ];
+
regex_re2 = [ re2 ];
+
regex_tre = [ tre ];
+
sqlite3 = [ sqlite ];
+
ssl_gnutls = [ gnutls ];
+
# depends on stdenv.cc.libc
+
regex_posix = [];
+
sslrehashsignal = [];
+
# depends on used libc++
+
regex_stdlib = [];
+
# GPLv2 incompatible
+
geo_maxmind = [ libmaxminddb ];
+
ssl_mbedtls = [ mbedtls ];
+
ssl_openssl = [ openssl ];
+
};
+
+
# buildInputs necessary for the enabled extraModules
+
extraInputs = lib.concatMap
+
(m: extras."${m}" or (builtins.throw "Unknown extra module ${m}"))
+
extraModules;
+
+
# if true, we can't provide a binary version of this
+
# package without violating the GPL 2
+
gpl2Conflict =
+
let
+
allowed = compatibleModules lib stdenv;
+
in
+
!lib.all (lib.flip lib.elem allowed) extraModules;
+
+
# return list of the license(s) of the given derivation
+
getLicenses = drv:
+
let
+
lics = drv.meta.license or [];
+
in
+
if lib.isAttrs lics || lib.isString lics
+
then [ lics ]
+
else lics;
+
+
# Whether any member of list1 is also member of list2, i. e. set intersection.
+
anyMembers = list1: list2:
+
lib.any (m1: lib.elem m1 list2) list1;
+
+
in
+
+
stdenv.mkDerivation rec {
+
pname = "inspircd";
+
version = "3.9.0";
+
+
src = fetchFromGitHub {
+
owner = pname;
+
repo = pname;
+
rev = "v${version}";
+
sha256 = "0x3paasf4ynx4ddky2nq613vyirbhfnxzkjq148k7154pz3q426s";
+
};
+
+
outputs = [ "bin" "lib" "man" "doc" "out" ];
+
+
nativeBuildInputs = [
+
perl
+
pkg-config
+
];
+
buildInputs = extraInputs;
+
+
configurePhase = ''
+
patchShebangs configure make/*.pl
+
+
# configure is executed twice, once to set the extras
+
# to use and once to do the Makefile setup
+
./configure \
+
--enable-extras \
+
${lib.escapeShellArg (lib.concatStringsSep " " extraModules)}
+
+
# this manually sets the flags instead of using configureFlags, because otherwise stdenv passes flags like --bindir, which make configure fail
+
./configure \
+
--disable-auto-extras \
+
--distribution-label nixpkgs${version} \
+
--uid 0 \
+
--gid 0 \
+
--binary-dir ${placeholder "bin"}/bin \
+
--config-dir /etc/inspircd \
+
--data-dir ${placeholder "lib"}/lib/inspircd \
+
--example-dir ${placeholder "doc"}/share/doc/inspircd \
+
--log-dir /var/log/inspircd \
+
--manual-dir ${placeholder "man"}/share/man/man1 \
+
--module-dir ${placeholder "lib"}/lib/inspircd \
+
--runtime-dir /var/run \
+
--script-dir ${placeholder "bin"}/share/inspircd \
+
'';
+
+
postInstall = ''
+
# for some reasons the executables are not executable
+
chmod +x $bin/bin/*
+
'';
+
+
enableParallelBuilding = true;
+
+
passthru.tests = {
+
nixos-test = nixosTests.inspircd;
+
};
+
+
meta = {
+
description = "A modular C++ IRC server";
+
license = [ lib.licenses.gpl2Only ]
+
++ lib.concatMap getLicenses extraInputs
+
++ lib.optionals (anyMembers extraModules libcModules) (getLicenses stdenv.cc.libc)
+
# FIXME(sternenseemann): get license of used lib(std)c++ somehow
+
++ lib.optional (anyMembers extraModules libcxxModules) "Unknown"
+
# Hack: Definitely prevent a hydra from building this package on
+
# a GPL 2 incompatibility even if it is not in a top-level attribute,
+
# but pulled in indirectly somehow.
+
++ lib.optional gpl2Conflict lib.licenses.unfree;
+
maintainers = [ lib.maintainers.sternenseemann ];
+
# windows is theoretically possible, but requires extra work
+
# which I am not willing to do and can't test.
+
# https://github.com/inspircd/inspircd/blob/master/win/README.txt
+
platforms = lib.platforms.unix;
+
homepage = "https://www.inspircd.org/";
+
} // lib.optionalAttrs gpl2Conflict {
+
# make sure we never distribute a GPLv2-violating module
+
# in binary form. They can be built locally of course.
+
hydraPlatforms = [];
+
};
+
}
+4
pkgs/top-level/all-packages.nix
···
theme-spring = callPackage ../servers/icingaweb2/theme-spring { };
};
imgproxy = callPackage ../servers/imgproxy { };
ircdog = callPackage ../applications/networking/irc/ircdog { };
···
theme-spring = callPackage ../servers/icingaweb2/theme-spring { };
};
+
inspircd = callPackage ../servers/irc/inspircd { };
+
+
inspircdMinimal = inspircd.override { extraModules = []; };
+
imgproxy = callPackage ../servers/imgproxy { };
ircdog = callPackage ../applications/networking/irc/ircdog { };