diff options
author | Matthew Bauer <mjbauer95@gmail.com> | 2019-02-09 12:14:06 -0500 |
---|---|---|
committer | Matthew Bauer <mjbauer95@gmail.com> | 2019-02-09 12:14:06 -0500 |
commit | 5c09d977c794d9243ddac17f6c429b5432431f8f (patch) | |
tree | 1acbd7e7f0c01546d955d47c6a8fddfec8e632b6 /nixos | |
parent | 21d991b1fd78214023551a0dada17b129cbd5cd5 (diff) | |
parent | 18d059a4ac001fbaa9c2abc750a2830a52e1dae5 (diff) | |
download | nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.tar nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.tar.gz nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.tar.bz2 nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.tar.lz nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.tar.xz nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.tar.zst nixlib-5c09d977c794d9243ddac17f6c429b5432431f8f.zip |
Merge remote-tracking branch 'origin/master' into staging
Diffstat (limited to 'nixos')
38 files changed, 1304 insertions, 227 deletions
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index faae4f205443..02b91773f5da 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -265,6 +265,7 @@ in rec { xsltproc \ ${manualXsltprocOptions} \ --stringparam target.database.document "${olinkDB}/olinkdb.xml" \ + --stringparam id.warnings "1" \ --nonet --output $dst/ \ ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \ ${manual-combined}/manual-combined.xml diff --git a/nixos/doc/manual/release-notes/rl-1903.xml b/nixos/doc/manual/release-notes/rl-1903.xml index 5050c10ff3e7..270acda9b042 100644 --- a/nixos/doc/manual/release-notes/rl-1903.xml +++ b/nixos/doc/manual/release-notes/rl-1903.xml @@ -410,6 +410,23 @@ (<link xlink:href="https://github.com/NixOS/nixpkgs/pull/54637">#54637</link>) </para> </listitem> + <listitem> + <para> + <literal>matrix-synapse</literal> has been updated to version 0.99. It will + <link xlink:href="https://github.com/matrix-org/synapse/pull/4509">no longer generate a self-signed certificate on first launch</link> + and will be <link xlink:href="https://matrix.org/blog/2019/02/05/synapse-0-99-0/">the last version to accept self-signed certificates</link>. + As such, it is now recommended to use a proper certificate verified by a + root CA (for example Let's Encrypt). + </para> + </listitem> + <listitem> + <para> + <literal>mailutils</literal> now works by default when + <literal>sendmail</literal> is not in a setuid wrapper. As a consequence, + the <literal>sendmailPath</literal> argument, having lost its main use, has + been removed. + </para> + </listitem> </itemizedlist> </section> @@ -464,6 +481,11 @@ </listitem> <listitem> <para> + The astah-community package was removed from nixpkgs due to it being discontinued and the downloads not being available anymore. + </para> + </listitem> + <listitem> + <para> The httpd service now saves log files with a .log file extension by default for easier integration with the logrotate service. </para> @@ -503,6 +525,28 @@ </para> </note> </listitem> + <listitem> + <para> + The <link xlink:href="https://github.com/DanielAdolfsson/ndppd"><literal>ndppd</literal></link> module + now supports <link linkend="opt-services.ndppd.enable">all config options</link> provided by the current + upstream version as service options. Additionally the <literal>ndppd</literal> package doesn't contain + the systemd unit configuration from upstream anymore, the unit is completely configured by the NixOS module now. + </para> + </listitem> + <listitem> + <para> + New installs of NixOS will default to the Redmine 4.x series unless otherwise specified in + <literal>services.redmine.package</literal> while existing installs of NixOS will default to + the Redmine 3.x series. + </para> + </listitem> + <listitem> + <para> + The <link linkend="opt-services.grafana.enable">Grafana module</link> now supports declarative + <link xlink:href="http://docs.grafana.org/administration/provisioning/">datasource and dashboard</link> + provisioning. + </para> + </listitem> </itemizedlist> </section> </section> diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix index e68563ef48d2..a13e76a69560 100644 --- a/nixos/lib/testing.nix +++ b/nixos/lib/testing.nix @@ -3,7 +3,7 @@ # Use a minimal kernel? , minimal ? false # Ignored -, config ? null +, config ? {} # Modules to add to each VM , extraConfigurations ? [] }: diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 9475da23b1ff..e78e290e7438 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -339,11 +339,11 @@ let # dates (cp -p, touch, mcopy -m, faketime for label), IDs (mkfs.vfat -i) '' mkdir ./contents && cd ./contents - cp -rp "${efiDir}"/* . + cp -rp "${efiDir}"/EFI . mkdir ./boot cp -p "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}" \ "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}" ./boot/ - touch --date=@0 ./* + touch --date=@0 ./EFI ./boot usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]') # Make the image 110% as big as the files need to make up for FAT overhead @@ -355,7 +355,7 @@ let echo "Image size: $image_size" truncate --size=$image_size "$out" ${pkgs.libfaketime}/bin/faketime "2000-01-01 00:00:00" ${pkgs.dosfstools}/sbin/mkfs.vfat -i 12345678 -n EFIBOOT "$out" - mcopy -psvm -i "$out" ./* :: + mcopy -psvm -i "$out" ./EFI ./boot :: # Verify the FAT partition. ${pkgs.dosfstools}/sbin/fsck.vfat -vn "$out" ''; # */ diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index e58392ad05b4..3bcf90258d79 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -340,6 +340,8 @@ foreach my $fs (read_file("/proc/self/mountinfo")) { chomp $fs; my @fields = split / /, $fs; my $mountPoint = $fields[4]; + $mountPoint =~ s/\\040/ /g; # account for mount points with spaces in the name (\040 is the escape character) + $mountPoint =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character) next unless -d $mountPoint; my @mountOptions = split /,/, $fields[5]; @@ -355,6 +357,8 @@ foreach my $fs (read_file("/proc/self/mountinfo")) { my $fsType = $fields[$n]; my $device = $fields[$n + 1]; my @superOptions = split /,/, $fields[$n + 2]; + $device =~ s/\\040/ /g; # account for devices with spaces in the name (\040 is the escape character) + $device =~ s/\\011/\t/g; # account for mount points with tabs in the name (\011 is the escape character) # Skip the read-only bind-mount on /nix/store. next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions); diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 915281cf863e..003b9df95d72 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -101,6 +101,7 @@ ./programs/gnupg.nix ./programs/gphoto2.nix ./programs/iftop.nix + ./programs/iotop.nix ./programs/java.nix ./programs/kbdlight.nix ./programs/less.nix diff --git a/nixos/modules/programs/iotop.nix b/nixos/modules/programs/iotop.nix new file mode 100644 index 000000000000..5512dbc62f72 --- /dev/null +++ b/nixos/modules/programs/iotop.nix @@ -0,0 +1,17 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.iotop; +in { + options = { + programs.iotop.enable = mkEnableOption "iotop + setcap wrapper"; + }; + config = mkIf cfg.enable { + security.wrappers.iotop = { + source = "${pkgs.iotop}/bin/iotop"; + capabilities = "cap_net_admin+p"; + }; + }; +} diff --git a/nixos/modules/programs/sway-beta.nix b/nixos/modules/programs/sway-beta.nix index 7fc5979a38aa..3c235de0ce63 100644 --- a/nixos/modules/programs/sway-beta.nix +++ b/nixos/modules/programs/sway-beta.nix @@ -60,10 +60,11 @@ in { extraPackages = mkOption { type = with types; listOf package; default = with pkgs; [ + swaylock swayidle xwayland rxvt_unicode dmenu ]; defaultText = literalExample '' - with pkgs; [ xwayland rxvt_unicode dmenu ]; + with pkgs; [ swaylock swayidle xwayland rxvt_unicode dmenu ]; ''; example = literalExample '' with pkgs; [ diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix index f50d2897843a..7d26d1501650 100644 --- a/nixos/modules/services/games/minecraft-server.nix +++ b/nixos/modules/services/games/minecraft-server.nix @@ -4,8 +4,41 @@ with lib; let cfg = config.services.minecraft-server; -in -{ + + # We don't allow eula=false anyways + eulaFile = builtins.toFile "eula.txt" '' + # eula.txt managed by NixOS Configuration + eula=true + ''; + + whitelistFile = pkgs.writeText "whitelist.json" + (builtins.toJSON + (mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist)); + + cfgToString = v: if builtins.isBool v then boolToString v else toString v; + + serverPropertiesFile = pkgs.writeText "server.properties" ('' + # server.properties managed by NixOS configuration + '' + concatStringsSep "\n" (mapAttrsToList + (n: v: "${n}=${cfgToString v}") cfg.serverProperties)); + + + # To be able to open the firewall, we need to read out port values in the + # server properties, but fall back to the defaults when those don't exist. + # These defaults are from https://minecraft.gamepedia.com/Server.properties#Java_Edition_3 + defaultServerPort = 25565; + + serverPort = cfg.serverProperties.server-port or defaultServerPort; + + rconPort = if cfg.serverProperties.enable-rcon or false + then cfg.serverProperties."rcon.port" or 25575 + else null; + + queryPort = if cfg.serverProperties.enable-query or false + then cfg.serverProperties."query.port" or 25565 + else null; + +in { options = { services.minecraft-server = { @@ -13,10 +46,32 @@ in type = types.bool; default = false; description = '' - If enabled, start a Minecraft Server. The listening port for - the server is always <literal>25565</literal>. The server + If enabled, start a Minecraft Server. The server data will be loaded from and saved to - <literal>${cfg.dataDir}</literal>. + <option>services.minecraft-server.dataDir</option>. + ''; + }; + + declarative = mkOption { + type = types.bool; + default = false; + description = '' + Whether to use a declarative Minecraft server configuration. + Only if set to <literal>true</literal>, the options + <option>services.minecraft-server.whitelist</option> and + <option>services.minecraft-server.serverProperties</option> will be + applied. + ''; + }; + + eula = mkOption { + type = types.bool; + default = false; + description = '' + Whether you agree to + <link xlink:href="https://account.mojang.com/documents/minecraft_eula"> + Mojangs EULA</link>. This option must be set to + <literal>true</literal> to run Minecraft server. ''; }; @@ -24,7 +79,7 @@ in type = types.path; default = "/var/lib/minecraft"; description = '' - Directory to store minecraft database and other state/data files. + Directory to store Minecraft database and other state/data files. ''; }; @@ -32,21 +87,84 @@ in type = types.bool; default = false; description = '' - Whether to open ports in the firewall (if enabled) for the server. + Whether to open ports in the firewall for the server. + ''; + }; + + whitelist = mkOption { + type = let + minecraftUUID = types.strMatching + "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // { + description = "Minecraft UUID"; + }; + in types.attrsOf minecraftUUID; + default = {}; + description = '' + Whitelisted players, only has an effect when + <option>services.minecraft-server.declarative</option> is + <literal>true</literal> and the whitelist is enabled + via <option>services.minecraft-server.serverProperties</option> by + setting <literal>white-list</literal> to <literal>true</literal>. + This is a mapping from Minecraft usernames to UUIDs. + You can use <link xlink:href="https://mcuuid.net/"/> to get a + Minecraft UUID for a username. + ''; + example = literalExample '' + { + username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; + username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"; + }; + ''; + }; + + serverProperties = mkOption { + type = with types; attrsOf (either bool (either int str)); + default = {}; + example = literalExample '' + { + server-port = 43000; + difficulty = 3; + gamemode = 1; + max-players = 5; + motd = "NixOS Minecraft server!"; + white-list = true; + enable-rcon = true; + "rcon.password" = "hunter2"; + } + ''; + description = '' + Minecraft server properties for the server.properties file. Only has + an effect when <option>services.minecraft-server.declarative</option> + is set to <literal>true</literal>. See + <link xlink:href="https://minecraft.gamepedia.com/Server.properties#Java_Edition_3"/> + for documentation on these values. ''; }; + package = mkOption { + type = types.package; + default = pkgs.minecraft-server; + defaultText = "pkgs.minecraft-server"; + example = literalExample "pkgs.minecraft-server_1_12_2"; + description = "Version of minecraft-server to run."; + }; + jvmOpts = mkOption { - type = types.str; + type = types.separatedString " "; default = "-Xmx2048M -Xms2048M"; - description = "JVM options for the Minecraft Service."; + # Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script + example = "-Xmx2048M -Xms4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing " + + "-XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 " + + "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10"; + description = "JVM options for the Minecraft server."; }; }; }; config = mkIf cfg.enable { + users.users.minecraft = { - description = "Minecraft Server Service user"; + description = "Minecraft server service user"; home = cfg.dataDir; createHome = true; uid = config.ids.uids.minecraft; @@ -57,17 +175,60 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - serviceConfig.Restart = "always"; - serviceConfig.User = "minecraft"; - script = '' - cd ${cfg.dataDir} - exec ${pkgs.minecraft-server}/bin/minecraft-server ${cfg.jvmOpts} - ''; - }; + serviceConfig = { + ExecStart = "${cfg.package}/bin/minecraft-server ${cfg.jvmOpts}"; + Restart = "always"; + User = "minecraft"; + WorkingDirectory = cfg.dataDir; + }; + + preStart = '' + ln -sf ${eulaFile} eula.txt + '' + (if cfg.declarative then '' + + if [ -e .declarative ]; then + + # Was declarative before, no need to back up anything + ln -sf ${whitelistFile} whitelist.json + cp -f ${serverPropertiesFile} server.properties + + else - networking.firewall = mkIf cfg.openFirewall { - allowedUDPPorts = [ 25565 ]; - allowedTCPPorts = [ 25565 ]; + # Declarative for the first time, backup stateful files + ln -sb --suffix=.stateful ${whitelistFile} whitelist.json + cp -b --suffix=.stateful ${serverPropertiesFile} server.properties + + # server.properties must have write permissions, because every time + # the server starts it first parses the file and then regenerates it.. + chmod +w server.properties + echo "Autogenerated file that signifies that this server configuration is managed declaratively by NixOS" \ + > .declarative + + fi + '' else '' + if [ -e .declarative ]; then + rm .declarative + fi + ''); }; + + networking.firewall = mkIf cfg.openFirewall (if cfg.declarative then { + allowedUDPPorts = [ serverPort ]; + allowedTCPPorts = [ serverPort ] + ++ optional (! isNull queryPort) queryPort + ++ optional (! isNull rconPort) rconPort; + } else { + allowedUDPPorts = [ defaultServerPort ]; + allowedTCPPorts = [ defaultServerPort ]; + }); + + assertions = [ + { assertion = cfg.eula; + message = "You must agree to Mojangs EULA to run minecraft-server." + + " Read https://account.mojang.com/documents/minecraft_eula and" + + " set `services.minecraft-server.eula` to `true` if you agree."; + } + ]; + }; } diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix index 6d81c7374f4d..66b1c1e3e6f9 100644 --- a/nixos/modules/services/mail/roundcube.nix +++ b/nixos/modules/services/mail/roundcube.nix @@ -25,6 +25,20 @@ in description = "Hostname to use for the nginx vhost"; }; + package = mkOption { + type = types.package; + default = pkgs.roundcube; + + example = literalExample '' + roundcube.withPlugins (plugins: [ plugins.persistent_login ]) + ''; + + description = '' + The package which contains roundcube's sources. Can be overriden to create + an environment which contains roundcube and third-party plugins. + ''; + }; + database = { username = mkOption { type = types.str; @@ -86,7 +100,7 @@ in forceSSL = mkDefault true; enableACME = mkDefault true; locations."/" = { - root = pkgs.roundcube; + root = cfg.package; index = "index.php"; extraConfig = '' location ~* \.php$ { @@ -140,12 +154,12 @@ in ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create database ${cfg.database.dbname} with owner ${cfg.database.username}"; fi PGPASSWORD=${cfg.database.password} ${pkgs.postgresql}/bin/psql -U ${cfg.database.username} \ - -f ${pkgs.roundcube}/SQL/postgres.initial.sql \ + -f ${cfg.package}/SQL/postgres.initial.sql \ -h ${cfg.database.host} ${cfg.database.dbname} touch /var/lib/roundcube/db-created fi - ${pkgs.php}/bin/php ${pkgs.roundcube}/bin/update.sh + ${pkgs.php}/bin/php ${cfg.package}/bin/update.sh ''; serviceConfig.Type = "oneshot"; }; diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix index 9a3966ab30aa..f3d90e532c88 100644 --- a/nixos/modules/services/misc/docker-registry.nix +++ b/nixos/modules/services/misc/docker-registry.nix @@ -18,7 +18,7 @@ let delete.enabled = cfg.enableDelete; }; http = { - addr = ":${builtins.toString cfg.port}"; + addr = "${cfg.listenAddress}:${builtins.toString cfg.port}"; headers.X-Content-Type-Options = ["nosniff"]; }; health.storagedriver = { diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 769a9526cf64..25c258ebe134 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -497,7 +497,12 @@ in { systemd.services.gitaly = { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv cfg.packages.gitaly.rubyEnv.wrappedRuby ]; + path = with pkgs; [ + openssh + gitAndTools.git + cfg.packages.gitaly.rubyEnv + cfg.packages.gitaly.rubyEnv.wrappedRuby + ]; serviceConfig = { Type = "simple"; User = cfg.user; diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index 2e9aa33aeeee..4ccfa22c89e7 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -6,9 +6,18 @@ let cfg = config.services.home-assistant; # cfg.config != null can be assumed here - configFile = pkgs.writeText "configuration.json" + configJSON = pkgs.writeText "configuration.json" (builtins.toJSON (if cfg.applyDefaultConfig then - (lib.recursiveUpdate defaultConfig cfg.config) else cfg.config)); + (recursiveUpdate defaultConfig cfg.config) else cfg.config)); + configFile = pkgs.runCommand "configuration.yaml" { } '' + ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out + ''; + + lovelaceConfigJSON = pkgs.writeText "ui-lovelace.json" + (builtins.toJSON cfg.lovelaceConfig); + lovelaceConfigFile = pkgs.runCommand "ui-lovelace.yaml" { } '' + ${pkgs.remarshal}/bin/json2yaml -i ${lovelaceConfigJSON} -o $out + ''; availableComponents = pkgs.home-assistant.availableComponents; @@ -44,7 +53,9 @@ let # If you are changing this, please update the description in applyDefaultConfig defaultConfig = { homeassistant.time_zone = config.time.timeZone; - http.server_port = (toString cfg.port); + http.server_port = cfg.port; + } // optionalAttrs (cfg.lovelaceConfig != null) { + lovelace.mode = "yaml"; }; in { @@ -99,6 +110,53 @@ in { ''; }; + configWritable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to make <filename>configuration.yaml</filename> writable. + This only has an effect if <option>config</option> is set. + This will allow you to edit it from Home Assistant's web interface. + However, bear in mind that it will be overwritten at every start of the service. + ''; + }; + + lovelaceConfig = mkOption { + default = null; + type = with types; nullOr attrs; + # from https://www.home-assistant.io/lovelace/yaml-mode/ + example = literalExample '' + { + title = "My Awesome Home"; + views = [ { + title = "Example"; + cards = [ { + type = "markdown"; + title = "Lovelace"; + content = "Welcome to your **Lovelace UI**."; + } ]; + } ]; + } + ''; + description = '' + Your <filename>ui-lovelace.yaml</filename> as a Nix attribute set. + Setting this option will automatically add + <literal>lovelace.mode = "yaml";</literal> to your <option>config</option>. + Beware that setting this option will delete your previous <filename>ui-lovelace.yaml</filename> + ''; + }; + + lovelaceConfigWritable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to make <filename>ui-lovelace.yaml</filename> writable. + This only has an effect if <option>lovelaceConfig</option> is set. + This will allow you to edit it from Home Assistant's web interface. + However, bear in mind that it will be overwritten at every start of the service. + ''; + }; + package = mkOption { default = pkgs.home-assistant; defaultText = "pkgs.home-assistant"; @@ -144,12 +202,17 @@ in { systemd.services.home-assistant = { description = "Home Assistant"; after = [ "network.target" ]; - preStart = lib.optionalString (cfg.config != null) '' - config=${cfg.configDir}/configuration.yaml - rm -f $config - ${pkgs.remarshal}/bin/json2yaml -i ${configFile} -o $config - chmod 444 $config - ''; + preStart = optionalString (cfg.config != null) (if cfg.configWritable then '' + cp --no-preserve=mode ${configFile} "${cfg.configDir}/configuration.yaml" + '' else '' + rm -f "${cfg.configDir}/configuration.yaml" + ln -s ${configFile} "${cfg.configDir}/configuration.yaml" + '') + optionalString (cfg.lovelaceConfig != null) (if cfg.lovelaceConfigWritable then '' + cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml" + '' else '' + rm -f "${cfg.configDir}/ui-lovelace.yaml" + ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml" + ''); serviceConfig = { ExecStart = "${package}/bin/hass --config '${cfg.configDir}'"; User = "hass"; diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix index 18e13f6ac030..a01e34d73629 100644 --- a/nixos/modules/services/misc/matrix-synapse.nix +++ b/nixos/modules/services/misc/matrix-synapse.nix @@ -651,12 +651,16 @@ in { services.postgresql.enable = mkIf usePostgresql (mkDefault true); - systemd.services.matrix-synapse = { + systemd.services.matrix-synapse = + let + python = (pkgs.python3.withPackages (ps: with ps; [ (ps.toPythonModule cfg.package) ])); + in + { description = "Synapse Matrix homeserver"; after = [ "network.target" "postgresql.service" ]; wantedBy = [ "multi-user.target" ]; preStart = '' - ${cfg.package}/bin/homeserver \ + ${python.interpreter} -m synapse.app.homeserver \ --config-path ${configFile} \ --keys-directory ${cfg.dataDir} \ --generate-keys @@ -687,10 +691,11 @@ in { WorkingDirectory = cfg.dataDir; PermissionsStartOnly = true; ExecStart = '' - ${cfg.package}/bin/homeserver \ + ${python.interpreter} -m synapse.app.homeserver \ ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } --keys-directory ${cfg.dataDir} ''; + ExecReload = "${pkgs.utillinux}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; }; }; diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix index 3c322ba1c3e6..98e9c8953c84 100644 --- a/nixos/modules/services/misc/redmine.nix +++ b/nixos/modules/services/misc/redmine.nix @@ -30,6 +30,13 @@ let ${cfg.extraConfig} ''; + additionalEnvironment = pkgs.writeText "additional_environment.rb" '' + config.logger = Logger.new("${cfg.stateDir}/log/production.log", 14, 1048576) + config.logger.level = Logger::INFO + + ${cfg.extraEnv} + ''; + unpackTheme = unpack "theme"; unpackPlugin = unpack "plugin"; unpack = id: (name: source: @@ -54,12 +61,20 @@ in description = "Enable the Redmine service."; }; + # default to the 4.x series not forcing major version upgrade of those on the 3.x series package = mkOption { type = types.package; - default = pkgs.redmine; + default = if versionAtLeast config.system.stateVersion "19.03" + then pkgs.redmine_4 + else pkgs.redmine + ; defaultText = "pkgs.redmine"; - description = "Which Redmine package to use."; - example = "pkgs.redmine.override { ruby = pkgs.ruby_2_3; }"; + description = '' + Which Redmine package to use. This defaults to version 3.x if + <literal>system.stateVersion < 19.03</literal> and version 4.x + otherwise. + ''; + example = "pkgs.redmine_4.override { ruby = pkgs.ruby_2_4; }"; }; user = mkOption { @@ -103,6 +118,19 @@ in ''; }; + extraEnv = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration in additional_environment.rb. + + See https://svn.redmine.org/redmine/trunk/config/additional_environment.rb.example + ''; + example = literalExample '' + config.logger.level = Logger::DEBUG + ''; + }; + themes = mkOption { type = types.attrsOf types.path; default = {}; @@ -249,6 +277,9 @@ in # link in the application configuration ln -fs ${configurationYml} "${cfg.stateDir}/config/configuration.yml" + # link in the additional environment configuration + ln -fs ${additionalEnvironment} "${cfg.stateDir}/config/additional_environment.rb" + # link in all user specified themes rm -rf "${cfg.stateDir}/public/themes/"* diff --git a/nixos/modules/services/misc/weechat.xml b/nixos/modules/services/misc/weechat.xml index b7f755bbc5c7..7255edfb9da3 100644 --- a/nixos/modules/services/misc/weechat.xml +++ b/nixos/modules/services/misc/weechat.xml @@ -8,7 +8,7 @@ <link xlink:href="https://weechat.org/">WeeChat</link> is a fast and extensible IRC client. </para> - <section> + <section xml:id="module-services-weechat-basic-usage"> <title>Basic Usage</title> <para> @@ -35,7 +35,7 @@ in the state directory <literal>/var/lib/weechat</literal>. </para> </section> - <section> + <section xml:id="module-services-weechat-reattach"> <title>Re-attaching to WeeChat</title> <para> diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 5fb3e3771221..85879cfe0b33 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -50,6 +50,158 @@ let SMTP_FROM_ADDRESS = cfg.smtp.fromAddress; } // cfg.extraOptions; + datasourceConfiguration = { + apiVersion = 1; + datasources = cfg.provision.datasources; + }; + + datasourceFile = pkgs.writeText "datasource.yaml" (builtins.toJSON datasourceConfiguration); + + dashboardConfiguration = { + apiVersion = 1; + providers = cfg.provision.dashboards; + }; + + dashboardFile = pkgs.writeText "dashboard.yaml" (builtins.toJSON dashboardConfiguration); + + provisionConfDir = pkgs.runCommand "grafana-provisioning" { } '' + mkdir -p $out/{datasources,dashboards} + ln -sf ${datasourceFile} $out/datasources/datasource.yaml + ln -sf ${dashboardFile} $out/dashboards/dashboard.yaml + ''; + + # Get a submodule without any embedded metadata: + _filter = x: filterAttrs (k: v: k != "_module") x; + + # http://docs.grafana.org/administration/provisioning/#datasources + grafanaTypes.datasourceConfig = types.submodule { + options = { + name = mkOption { + type = types.str; + description = "Name of the datasource. Required"; + }; + type = mkOption { + type = types.enum ["graphite" "prometheus" "cloudwatch" "elasticsearch" "influxdb" "opentsdb" "mysql" "mssql" "postgres" "loki"]; + description = "Datasource type. Required"; + }; + access = mkOption { + type = types.enum ["proxy" "direct"]; + default = "proxy"; + description = "Access mode. proxy or direct (Server or Browser in the UI). Required"; + }; + orgId = mkOption { + type = types.int; + default = 1; + description = "Org id. will default to orgId 1 if not specified"; + }; + url = mkOption { + type = types.str; + description = "Url of the datasource"; + }; + password = mkOption { + type = types.nullOr types.str; + default = null; + description = "Database password, if used"; + }; + user = mkOption { + type = types.nullOr types.str; + default = null; + description = "Database user, if used"; + }; + database = mkOption { + type = types.nullOr types.str; + default = null; + description = "Database name, if used"; + }; + basicAuth = mkOption { + type = types.nullOr types.bool; + default = null; + description = "Enable/disable basic auth"; + }; + basicAuthUser = mkOption { + type = types.nullOr types.str; + default = null; + description = "Basic auth username"; + }; + basicAuthPassword = mkOption { + type = types.nullOr types.str; + default = null; + description = "Basic auth password"; + }; + withCredentials = mkOption { + type = types.bool; + default = false; + description = "Enable/disable with credentials headers"; + }; + isDefault = mkOption { + type = types.bool; + default = false; + description = "Mark as default datasource. Max one per org"; + }; + jsonData = mkOption { + type = types.nullOr types.attrs; + default = null; + description = "Datasource specific configuration"; + }; + secureJsonData = mkOption { + type = types.nullOr types.attrs; + default = null; + description = "Datasource specific secure configuration"; + }; + version = mkOption { + type = types.int; + default = 1; + description = "Version"; + }; + editable = mkOption { + type = types.bool; + default = false; + description = "Allow users to edit datasources from the UI."; + }; + }; + }; + + # http://docs.grafana.org/administration/provisioning/#dashboards + grafanaTypes.dashboardConfig = types.submodule { + options = { + name = mkOption { + type = types.str; + default = "default"; + description = "Provider name"; + }; + orgId = mkOption { + type = types.int; + default = 1; + description = "Organization ID"; + }; + folder = mkOption { + type = types.str; + default = ""; + description = "Add dashboards to the speciied folder"; + }; + type = mkOption { + type = types.str; + default = "file"; + description = "Dashboard provider type"; + }; + disableDeletion = mkOption { + type = types.bool; + default = false; + description = "Disable deletion when JSON file is removed"; + }; + updateIntervalSeconds = mkOption { + type = types.int; + default = 10; + description = "How often Grafana will scan for changed dashboards"; + }; + options = { + path = mkOption { + type = types.path; + description = "Path grafana will watch for dashboards"; + }; + }; + }; + }; in { options.services.grafana = { enable = mkEnableOption "grafana"; @@ -175,6 +327,22 @@ in { }; }; + provision = { + enable = mkEnableOption "provision"; + datasources = mkOption { + description = "Grafana datasources configuration"; + default = []; + type = types.listOf grafanaTypes.datasourceConfig; + apply = x: map _filter x; + }; + dashboards = mkOption { + description = "Grafana dashboard configuration"; + default = []; + type = types.listOf grafanaTypes.dashboardConfig; + apply = x: map _filter x; + }; + }; + security = { adminUser = mkOption { description = "Default admin username."; @@ -313,10 +481,15 @@ in { }; config = mkIf cfg.enable { - warnings = optional ( - cfg.database.password != opt.database.password.default || - cfg.security.adminPassword != opt.security.adminPassword.default - ) "Grafana passwords will be stored as plaintext in the Nix store!"; + warnings = flatten [ + (optional ( + cfg.database.password != opt.database.password.default || + cfg.security.adminPassword != opt.security.adminPassword.default + ) "Grafana passwords will be stored as plaintext in the Nix store!") + (optional ( + any (x: x.password != null || x.basicAuthPassword != null || x.secureJsonData != null) cfg.provision.datasources + ) "Datasource passwords will be stored as plaintext in the Nix store!") + ]; environment.systemPackages = [ cfg.package ]; @@ -359,6 +532,9 @@ in { ${optionalString (cfg.smtp.passwordFile != null) '' export GF_SMTP_PASSWORD="$(cat ${escapeShellArg cfg.smtp.passwordFile})" ''} + ${optionalString cfg.provision.enable '' + export GF_PATHS_PROVISIONING=${provisionConfDir}; + ''} exec ${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir} ''; serviceConfig = { diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix index 2b265d5b5a90..f67986327245 100644 --- a/nixos/modules/services/monitoring/munin.nix +++ b/nixos/modules/services/monitoring/munin.nix @@ -4,7 +4,7 @@ # TODO: LWP/Pg perl libs aren't recognized # TODO: support fastcgi -# http://munin-monitoring.org/wiki/CgiHowto2 +# http://guide.munin-monitoring.org/en/latest/example/webserver/apache-cgi.html # spawn-fcgi -s /run/munin/fastcgi-graph.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph # spawn-fcgi -s /run/munin/fastcgi-html.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-html # https://paste.sh/vofcctHP#-KbDSXVeWoifYncZmLfZzgum @@ -24,6 +24,8 @@ let logdir /var/log/munin rundir /run/munin + ${lib.optionalString (cronCfg.extraCSS != "") "staticdir ${customStaticDir}"} + ${cronCfg.extraGlobalConfig} ${cronCfg.hosts} @@ -63,6 +65,11 @@ let [ipmi*] user root group root + + [munin*] + env.UPDATE_STATSFILE /var/lib/munin/munin-update.stats + + ${nodeCfg.extraPluginConfig} ''; pluginConfDir = pkgs.stdenv.mkDerivation { @@ -72,6 +79,54 @@ let ln -s ${pluginConf} $out/nixos-config ''; }; + + # Copy one Munin plugin into the Nix store with a specific name. + # This is suitable for use with plugins going directly into /etc/munin/plugins, + # i.e. munin.extraPlugins. + internOnePlugin = name: path: + "cp -a '${path}' '${name}'"; + + # Copy an entire tree of Munin plugins into a single directory in the Nix + # store, with no renaming. + # This is suitable for use with munin-node-configure --suggest, i.e. + # munin.extraAutoPlugins. + internManyPlugins = name: path: + "find '${path}' -type f -perm /a+x -exec cp -a -t . '{}' '+'"; + + # Use the appropriate intern-fn to copy the plugins into the store and patch + # them afterwards in an attempt to get them to run on NixOS. + internAndFixPlugins = name: intern-fn: paths: + pkgs.runCommand name {} '' + mkdir -p "$out" + cd "$out" + ${lib.concatStringsSep "\n" + (lib.attrsets.mapAttrsToList intern-fn paths)} + chmod -R u+w . + find . -type f -exec sed -E -i ' + s,(/usr)?/s?bin/,/run/current-system/sw/bin/,g + ' '{}' '+' + ''; + + # TODO: write a derivation for munin-contrib, so that for contrib plugins + # you can just refer to them by name rather than needing to include a copy + # of munin-contrib in your nixos configuration. + extraPluginDir = internAndFixPlugins "munin-extra-plugins.d" + internOnePlugin nodeCfg.extraPlugins; + + extraAutoPluginDir = internAndFixPlugins "munin-extra-auto-plugins.d" + internManyPlugins + (builtins.listToAttrs + (map + (path: { name = baseNameOf path; value = path; }) + nodeCfg.extraAutoPlugins)); + + customStaticDir = pkgs.runCommand "munin-custom-static-data" {} '' + cp -a "${pkgs.munin}/etc/opt/munin/static" "$out" + cd "$out" + chmod -R u+w . + echo "${cronCfg.extraCSS}" >> style.css + echo "${cronCfg.extraCSS}" >> style-new.css + ''; in { @@ -82,11 +137,12 @@ in enable = mkOption { default = false; + type = types.bool; description = '' Enable Munin Node agent. Munin node listens on 0.0.0.0 and by default accepts connections only from 127.0.0.1 for security reasons. - See <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />. + See <link xlink:href='http://guide.munin-monitoring.org/en/latest/architecture/index.html' />. ''; }; @@ -95,18 +151,108 @@ in type = types.lines; description = '' <filename>munin-node.conf</filename> extra configuration. See - <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' /> + <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin-node.conf.html' /> + ''; + }; + + extraPluginConfig = mkOption { + default = ""; + type = types.lines; + description = '' + <filename>plugin-conf.d</filename> extra plugin configuration. See + <link xlink:href='http://guide.munin-monitoring.org/en/latest/plugin/use.html' /> + ''; + example = '' + [fail2ban_*] + user root ''; }; - # TODO: add option to add additional plugins + extraPlugins = mkOption { + default = {}; + type = with types; attrsOf path; + description = '' + Additional Munin plugins to activate. Keys are the name of the plugin + symlink, values are the path to the underlying plugin script. You + can use the same plugin script multiple times (e.g. for wildcard + plugins). + + Note that these plugins do not participate in autoconfiguration. If + you want to autoconfigure additional plugins, use + <option>services.munin-node.extraAutoPlugins</option>. + + Plugins enabled in this manner take precedence over autoconfigured + plugins. + + Plugins will be copied into the Nix store, and it will attempt to + modify them to run properly by fixing hardcoded references to + <literal>/bin</literal>, <literal>/usr/bin</literal>, + <literal>/sbin</literal>, and <literal>/usr/sbin</literal>. + ''; + example = literalExample '' + { + zfs_usage_bigpool = /src/munin-contrib/plugins/zfs/zfs_usage_; + zfs_usage_smallpool = /src/munin-contrib/plugins/zfs/zfs_usage_; + zfs_list = /src/munin-contrib/plugins/zfs/zfs_list; + }; + ''; + }; + extraAutoPlugins = mkOption { + default = []; + type = with types; listOf path; + description = '' + Additional Munin plugins to autoconfigure, using + <literal>munin-node-configure --suggest</literal>. These should be + the actual paths to the plugin files (or directories containing them), + not just their names. + + If you want to manually enable individual plugins instead, use + <option>services.munin-node.extraPlugins</option>. + + Note that only plugins that have the 'autoconfig' capability will do + anything if listed here, since plugins that cannot autoconfigure + won't be automatically enabled by + <literal>munin-node-configure</literal>. + + Plugins will be copied into the Nix store, and it will attempt to + modify them to run properly by fixing hardcoded references to + <literal>/bin</literal>, <literal>/usr/bin</literal>, + <literal>/sbin</literal>, and <literal>/usr/sbin</literal>. + ''; + example = literalExample '' + [ + /src/munin-contrib/plugins/zfs + /src/munin-contrib/plugins/ssh + ]; + ''; + }; + + disabledPlugins = mkOption { + # TODO: figure out why Munin isn't writing the log file and fix it. + # In the meantime this at least suppresses a useless graph full of + # NaNs in the output. + default = [ "munin_stats" ]; + type = with types; listOf string; + description = '' + Munin plugins to disable, even if + <literal>munin-node-configure --suggest</literal> tries to enable + them. To disable a wildcard plugin, use an actual wildcard, as in + the example. + + munin_stats is disabled by default as it tries to read + <literal>/var/log/munin/munin-update.log</literal> for timing + information, and the NixOS build of Munin does not write this file. + ''; + example = [ "diskstats" "zfs_usage_*" ]; + }; }; services.munin-cron = { enable = mkOption { default = false; + type = types.bool; description = '' Enable munin-cron. Takes care of all heavy lifting to collect data from nodes and draws graphs to html. Runs munin-update, munin-limits, @@ -119,11 +265,12 @@ in extraGlobalConfig = mkOption { default = ""; + type = types.lines; description = '' <filename>munin.conf</filename> extra global configuration. - See <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' />. + See <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html' />. Useful to setup notifications, see - <link xlink:href='http://munin-monitoring.org/wiki/HowToContact' /> + <link xlink:href='http://guide.munin-monitoring.org/en/latest/tutorial/alert.html' /> ''; example = '' contact.email.command mail -s "Munin notification for ''${var:host}" someone@example.com @@ -131,14 +278,34 @@ in }; hosts = mkOption { + default = ""; + type = types.lines; + description = '' + Definitions of hosts of nodes to collect data from. Needs at least one + host for cron to succeed. See + <link xlink:href='http://guide.munin-monitoring.org/en/latest/reference/munin.conf.html' /> + ''; example = '' [''${config.networking.hostName}] address localhost ''; + }; + + extraCSS = mkOption { + default = ""; + type = types.lines; description = '' - Definitions of hosts of nodes to collect data from. Needs at least one - hosts for cron to succeed. See - <link xlink:href='http://munin-monitoring.org/wiki/munin.conf' /> + Custom styling for the HTML that munin-cron generates. This will be + appended to the CSS files used by munin-cron and will thus take + precedence over the builtin styles. + ''; + example = '' + /* A simple dark theme. */ + html, body { background: #222222; } + #header, #footer { background: #333333; } + img.i, img.iwarn, img.icrit, img.iunkn { + filter: invert(100%) hue-rotate(-30deg); + } ''; }; @@ -155,6 +322,7 @@ in description = "Munin monitoring user"; group = "munin"; uid = config.ids.uids.munin; + home = "/var/lib/munin"; }]; users.groups = [{ @@ -173,14 +341,27 @@ in environment.MUNIN_PLUGSTATE = "/run/munin"; environment.MUNIN_LOGDIR = "/var/log/munin"; preStart = '' - echo "updating munin plugins..." + echo "Updating munin plugins..." mkdir -p /etc/munin/plugins rm -rf /etc/munin/plugins/* + + # Autoconfigure builtin plugins ${pkgs.munin}/bin/munin-node-configure --suggest --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${pkgs.munin}/lib/plugins --servicedir=/etc/munin/plugins --sconfdir=${pluginConfDir} 2>/dev/null | ${pkgs.bash}/bin/bash - # NOTE: we disable disktstats because plugin seems to fail and it hangs html generation (100% CPU + memory leak) - rm /etc/munin/plugins/diskstats || true + # Autoconfigure extra plugins + ${pkgs.munin}/bin/munin-node-configure --suggest --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${extraAutoPluginDir} --servicedir=/etc/munin/plugins --sconfdir=${pluginConfDir} 2>/dev/null | ${pkgs.bash}/bin/bash + + ${lib.optionalString (nodeCfg.extraPlugins != {}) '' + # Link in manually enabled plugins + ln -f -s -t /etc/munin/plugins ${extraPluginDir}/* + ''} + + ${lib.optionalString (nodeCfg.disabledPlugins != []) '' + # Disable plugins + cd /etc/munin/plugins + rm -f ${toString nodeCfg.disabledPlugins} + ''} ''; serviceConfig = { ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/ --sconfdir=${pluginConfDir}"; @@ -192,6 +373,10 @@ in }) (mkIf cronCfg.enable { + # Munin is hardcoded to use DejaVu Mono and the graphs come out wrong if + # it's not available. + fonts.fonts = [ pkgs.dejavu_fonts ]; + systemd.timers.munin-cron = { description = "batch Munin master programs"; wantedBy = [ "timers.target" ]; diff --git a/nixos/modules/services/networking/ndppd.nix b/nixos/modules/services/networking/ndppd.nix index 1d6c48dd8d37..ba17f1ba825a 100644 --- a/nixos/modules/services/networking/ndppd.nix +++ b/nixos/modules/services/networking/ndppd.nix @@ -5,43 +5,163 @@ with lib; let cfg = config.services.ndppd; - configFile = pkgs.runCommand "ndppd.conf" {} '' - substitute ${pkgs.ndppd}/etc/ndppd.conf $out \ - --replace eth0 ${cfg.interface} \ - --replace 1111:: ${cfg.network} - ''; -in { - options = { - services.ndppd = { - enable = mkEnableOption "daemon that proxies NDP (Neighbor Discovery Protocol) messages between interfaces"; + render = s: f: concatStringsSep "\n" (mapAttrsToList f s); + prefer = a: b: if a != null then a else b; + + ndppdConf = prefer cfg.configFile (pkgs.writeText "ndppd.conf" '' + route-ttl ${toString cfg.routeTTL} + ${render cfg.proxies (proxyInterfaceName: proxy: '' + proxy ${prefer proxy.interface proxyInterfaceName} { + router ${boolToString proxy.router} + timeout ${toString proxy.timeout} + ttl ${toString proxy.ttl} + ${render proxy.rules (ruleNetworkName: rule: '' + rule ${prefer rule.network ruleNetworkName} { + ${rule.method}${if rule.method == "iface" then " ${rule.interface}" else ""} + }'')} + }'')} + ''); + + proxy = types.submodule { + options = { interface = mkOption { - type = types.string; - default = "eth0"; - example = "ens3"; - description = "Interface which is on link-level with router."; + type = types.nullOr types.str; + description = '' + Listen for any Neighbor Solicitation messages on this interface, + and respond to them according to a set of rules. + Defaults to the name of the attrset. + ''; + default = null; + }; + router = mkOption { + type = types.bool; + description = '' + Turns on or off the router flag for Neighbor Advertisement Messages. + ''; + default = true; + }; + timeout = mkOption { + type = types.int; + description = '' + Controls how long to wait for a Neighbor Advertisment Message before + invalidating the entry, in milliseconds. + ''; + default = 500; + }; + ttl = mkOption { + type = types.int; + description = '' + Controls how long a valid or invalid entry remains in the cache, in + milliseconds. + ''; + default = 30000; }; + rules = mkOption { + type = types.attrsOf rule; + description = '' + This is a rule that the target address is to match against. If no netmask + is provided, /128 is assumed. You may have several rule sections, and the + addresses may or may not overlap. + ''; + default = {}; + }; + }; + }; + + rule = types.submodule { + options = { network = mkOption { - type = types.string; - default = "1111::"; - example = "2001:DB8::/32"; - description = "Network that we proxy."; + type = types.nullOr types.str; + description = '' + This is the target address is to match against. If no netmask + is provided, /128 is assumed. The addresses of serveral rules + may or may not overlap. + Defaults to the name of the attrset. + ''; + default = null; + }; + method = mkOption { + type = types.enum [ "static" "iface" "auto" ]; + description = '' + static: Immediately answer any Neighbor Solicitation Messages + (if they match the IP rule). + iface: Forward the Neighbor Solicitation Message through the specified + interface and only respond if a matching Neighbor Advertisement + Message is received. + auto: Same as iface, but instead of manually specifying the outgoing + interface, check for a matching route in /proc/net/ipv6_route. + ''; + default = "auto"; }; - configFile = mkOption { - type = types.nullOr types.path; + interface = mkOption { + type = types.nullOr types.str; + description = "Interface to use when method is iface."; default = null; - description = "Path to configuration file."; }; }; }; +in { + options.services.ndppd = { + enable = mkEnableOption "daemon that proxies NDP (Neighbor Discovery Protocol) messages between interfaces"; + interface = mkOption { + type = types.nullOr types.str; + description = '' + Interface which is on link-level with router. + (Legacy option, use services.ndppd.proxies.<interface>.rules.<network> instead) + ''; + default = null; + example = "eth0"; + }; + network = mkOption { + type = types.nullOr types.str; + description = '' + Network that we proxy. + (Legacy option, use services.ndppd.proxies.<interface>.rules.<network> instead) + ''; + default = null; + example = "1111::/64"; + }; + configFile = mkOption { + type = types.nullOr types.path; + description = "Path to configuration file."; + default = null; + }; + routeTTL = mkOption { + type = types.int; + description = '' + This tells 'ndppd' how often to reload the route file /proc/net/ipv6_route, + in milliseconds. + ''; + default = 30000; + }; + proxies = mkOption { + type = types.attrsOf proxy; + description = '' + This sets up a listener, that will listen for any Neighbor Solicitation + messages, and respond to them according to a set of rules. + ''; + default = {}; + example = { "eth0".rules."1111::/64" = {}; }; + }; + }; + config = mkIf cfg.enable { - systemd.packages = [ pkgs.ndppd ]; - environment.etc."ndppd.conf".source = if (cfg.configFile != null) then cfg.configFile else configFile; + warnings = mkIf (cfg.interface != null && cfg.network != null) [ '' + The options services.ndppd.interface and services.ndppd.network will probably be removed soon, + please use services.ndppd.proxies.<interface>.rules.<network> instead. + '' ]; + + services.ndppd.proxies = mkIf (cfg.interface != null && cfg.network != null) { + "${cfg.interface}".rules."${cfg.network}" = {}; + }; + systemd.services.ndppd = { - serviceConfig.RuntimeDirectory = [ "ndppd" ]; + description = "NDP Proxy Daemon"; + documentation = [ "man:ndppd(1)" "man:ndppd.conf(5)" ]; + after = [ "network-pre.target" ]; wantedBy = [ "multi-user.target" ]; + serviceConfig.ExecStart = "${pkgs.ndppd}/bin/ndppd -c ${ndppdConf}"; }; }; - - meta.maintainers = with maintainers; [ gnidorah ]; } diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index b2ef1885a955..702481ec5177 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -122,7 +122,7 @@ in { systemd.packages = [ pkgs.syncthing ]; - users = mkIf (cfg.user == defaultUser) { + users = mkIf (cfg.systemService && cfg.user == defaultUser) { users."${defaultUser}" = { group = cfg.group; home = cfg.dataDir; diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix index 89b9ac4eadf5..c82e0af2803d 100644 --- a/nixos/modules/services/networking/unifi.nix +++ b/nixos/modules/services/networking/unifi.nix @@ -121,11 +121,12 @@ in }; networking.firewall = mkIf cfg.openPorts { - # https://help.ubnt.com/hc/en-us/articles/204910084-UniFi-Change-Default-Ports-for-Controller-and-UAPs + # https://help.ubnt.com/hc/en-us/articles/218506997 allowedTCPPorts = [ 8080 # Port for UAP to inform controller. 8880 # Port for HTTP portal redirect, if guest portal is enabled. 8843 # Port for HTTPS portal redirect, ditto. + 6789 # Port for UniFi mobile speed test. ]; allowedUDPPorts = [ 3478 # UDP port used for STUN. diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index ecb1c5615d58..ee1354d6a997 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -426,7 +426,7 @@ in { "~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\\.php(?:$|/)" = { priority = 500; extraConfig = '' - include ${pkgs.nginxMainline}/conf/fastcgi.conf; + include ${config.services.nginx.package}/conf/fastcgi.conf; fastcgi_split_path_info ^(.+\.php)(/.*)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix index d1ee076e9185..efec943c0075 100644 --- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix +++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix @@ -6,12 +6,14 @@ let dmcfg = config.services.xserver.displayManager; ldmcfg = dmcfg.lightdm; + xcfg = config.services.xserver; cfg = ldmcfg.greeters.gtk; inherit (pkgs) writeText; theme = cfg.theme.package; icons = cfg.iconTheme.package; + cursors = cfg.cursorTheme.package; # The default greeter provided with this expression is the GTK greeter. # Again, we need a few things in the environment for the greeter to run with @@ -28,7 +30,8 @@ let --set GTK_EXE_PREFIX "${theme}" \ --set GTK_DATA_PREFIX "${theme}" \ --set XDG_DATA_DIRS "${theme}/share:${icons}/share" \ - --set XDG_CONFIG_HOME "${theme}/share" + --set XDG_CONFIG_HOME "${theme}/share" \ + --set XCURSOR_PATH "${cursors}/share/icons" cat - > $out/lightdm-gtk-greeter.desktop << EOF [Desktop Entry] @@ -44,9 +47,12 @@ let [greeter] theme-name = ${cfg.theme.name} icon-theme-name = ${cfg.iconTheme.name} + cursor-theme-name = ${cfg.cursorTheme.name} + cursor-theme-size = ${toString cfg.cursorTheme.size} background = ${ldmcfg.background} ${optionalString (cfg.clock-format != null) "clock-format = ${cfg.clock-format}"} ${optionalString (cfg.indicators != null) "indicators = ${concatStringsSep ";" cfg.indicators}"} + ${optionalString (xcfg.dpi != null) "xft-dpi=${toString xcfg.dpi}"} ${cfg.extraConfig} ''; @@ -106,6 +112,33 @@ in }; + cursorTheme = { + + package = mkOption { + default = pkgs.gnome3.defaultIconTheme; + defaultText = "pkgs.gnome3.defaultIconTheme"; + description = '' + The package path that contains the cursor theme given in the name option. + ''; + }; + + name = mkOption { + type = types.str; + default = "Adwaita"; + description = '' + Name of the cursor theme to use for the lightdm-gtk-greeter. + ''; + }; + + size = mkOption { + type = types.int; + default = 16; + description = '' + Size of the cursor theme to use for the lightdm-gtk-greeter. + ''; + }; + }; + clock-format = mkOption { type = types.nullOr types.str; default = null; diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix index 047651dc6426..7db60daa60b8 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix @@ -33,7 +33,7 @@ let avoid_warnings=1 '' + optional isAarch64 '' # Boot in 64-bit mode. - arm_control=0x200 + arm_64bit=1 '' + (if cfg.uboot.enable then '' kernel=u-boot-rpi.bin '' else '' diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix index 7b756b70e2fc..d225778a3878 100644 --- a/nixos/modules/tasks/auto-upgrade.nix +++ b/nixos/modules/tasks/auto-upgrade.nix @@ -78,7 +78,7 @@ let cfg = config.system.autoUpgrade; in HOME = "/root"; } // config.networking.proxy.envVars; - path = [ pkgs.gnutar pkgs.xz.bin config.nix.package.out ]; + path = [ pkgs.gnutar pkgs.xz.bin pkgs.gitMinimal config.nix.package.out ]; script = '' ${config.system.build.nixos-rebuild}/bin/nixos-rebuild switch ${toString cfg.flags} diff --git a/nixos/modules/tasks/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix index 2ffbb8777068..2c9231f55236 100644 --- a/nixos/modules/tasks/encrypted-devices.nix +++ b/nixos/modules/tasks/encrypted-devices.nix @@ -19,21 +19,21 @@ let description = "The block device is backed by an encrypted one, adds this device as a initrd luks entry."; }; - options.blkDev = mkOption { + blkDev = mkOption { default = null; example = "/dev/sda1"; type = types.nullOr types.str; description = "Location of the backing encrypted device."; }; - options.label = mkOption { + label = mkOption { default = null; example = "rootfs"; type = types.nullOr types.str; description = "Label of the unlocked encrypted device. Set <literal>fileSystems.<name?>.device</literal> to <literal>/dev/mapper/<label></literal> to mount the unlocked device."; }; - options.keyFile = mkOption { + keyFile = mkOption { default = null; example = "/mnt-root/root/.swapkey"; type = types.nullOr types.str; diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index 9e4057b50897..07f8214cea2c 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -231,7 +231,7 @@ in fsToSkipCheck = [ "none" "bindfs" "btrfs" "zfs" "tmpfs" "nfs" "vboxsf" "glusterfs" ]; skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck; # https://wiki.archlinux.org/index.php/fstab#Filepath_spaces - escape = string: builtins.replaceStrings [ " " ] [ "\\040" ] string; + escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string; in '' # This is a generated file. Do not edit! # diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 08eea32c6b84..fb68159d6677 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -129,6 +129,7 @@ in matrix-synapse = handleTest ./matrix-synapse.nix {}; memcached = handleTest ./memcached.nix {}; mesos = handleTest ./mesos.nix {}; + minio = handleTest ./minio.nix {}; misc = handleTest ./misc.nix {}; mongodb = handleTest ./mongodb.nix {}; morty = handleTest ./morty.nix {}; @@ -142,6 +143,8 @@ in nat.firewall = handleTest ./nat.nix { withFirewall = true; }; nat.firewall-conntrack = handleTest ./nat.nix { withFirewall = true; withConntrackHelpers = true; }; nat.standalone = handleTest ./nat.nix { withFirewall = false; }; + ndppd = handleTest ./ndppd.nix {}; + neo4j = handleTest ./neo4j.nix {}; netdata = handleTest ./netdata.nix {}; networking.networkd = handleTest ./networking.nix { networkd = true; }; networking.scripted = handleTest ./networking.nix { networkd = false; }; @@ -161,6 +164,7 @@ in opensmtpd = handleTest ./opensmtpd.nix {}; openssh = handleTest ./openssh.nix {}; osquery = handleTest ./osquery.nix {}; + osrm-backend = handleTest ./osrm-backend.nix {}; ostree = handleTest ./ostree.nix {}; pam-oath-login = handleTest ./pam-oath-login.nix {}; pam-u2f = handleTest ./pam-u2f.nix {}; diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index 2febdd7b2870..a93360b252f6 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -50,6 +50,18 @@ in { } ]; }; + lovelaceConfig = { + title = "My Awesome Home"; + views = [ { + title = "Example"; + cards = [ { + type = "markdown"; + title = "Lovelace"; + content = "Welcome to your **Lovelace UI**."; + } ]; + } ]; + }; + lovelaceConfigWritable = true; }; }; }; @@ -59,8 +71,10 @@ in { $hass->waitForUnit("home-assistant.service"); # The config is specified using a Nix attribute set, - # but then converted from JSON to YAML - $hass->succeed("test -f ${configDir}/configuration.yaml"); + # converted from JSON to YAML, and linked to the config dir + $hass->succeed("test -L ${configDir}/configuration.yaml"); + # The lovelace config is copied because lovelaceConfigWritable = true + $hass->succeed("test -f ${configDir}/ui-lovelace.yaml"); # Check that Home Assistant's web interface and API can be reached $hass->waitForOpenPort(8123); diff --git a/nixos/tests/hydra/default.nix b/nixos/tests/hydra/default.nix index db4e97e0039b..882bced86d39 100644 --- a/nixos/tests/hydra/default.nix +++ b/nixos/tests/hydra/default.nix @@ -1,77 +1,91 @@ -import ../make-test.nix ({ pkgs, ...} : +{ system ? builtins.currentSystem +, config ? { } +, pkgs ? import ../../.. { inherit system config; } +}: let - trivialJob = pkgs.writeTextDir "trivial.nix" '' - { trivial = builtins.derivation { - name = "trivial"; - system = "x86_64-linux"; - builder = "/bin/sh"; - args = ["-c" "echo success > $out; exit 0"]; - }; - } - ''; - - createTrivialProject = pkgs.stdenv.mkDerivation { - name = "create-trivial-project"; - unpackPhase = ":"; - buildInputs = [ pkgs.makeWrapper ]; - installPhase = "install -m755 -D ${./create-trivial-project.sh} $out/bin/create-trivial-project.sh"; - postFixup = '' - wrapProgram "$out/bin/create-trivial-project.sh" --prefix PATH ":" ${pkgs.stdenv.lib.makeBinPath [ pkgs.curl ]} --set EXPR_PATH ${trivialJob} - ''; - }; - -in { - name = "hydra-init-localdb"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ pstn lewo ma27 ]; - }; - machine = - { pkgs, ... }: - - { - virtualisation.memorySize = 1024; - time.timeZone = "UTC"; - - environment.systemPackages = [ createTrivialProject pkgs.jq ]; - services.hydra = { - enable = true; - - #Hydra needs those settings to start up, so we add something not harmfull. - hydraURL = "example.com"; - notificationSender = "example@example.com"; - }; - nix = { - buildMachines = [{ - hostName = "localhost"; - systems = [ "x86_64-linux" ]; - }]; - - binaryCaches = []; - }; - }; - - testScript = - '' - # let the system boot up - $machine->waitForUnit("multi-user.target"); - # test whether the database is running - $machine->succeed("systemctl status postgresql.service"); - # test whether the actual hydra daemons are running - $machine->succeed("systemctl status hydra-queue-runner.service"); - $machine->succeed("systemctl status hydra-init.service"); - $machine->succeed("systemctl status hydra-evaluator.service"); - $machine->succeed("systemctl status hydra-send-stats.service"); - - $machine->succeed("hydra-create-user admin --role admin --password admin"); - - # create a project with a trivial job - $machine->waitForOpenPort(3000); - - # make sure the build as been successfully built - $machine->succeed("create-trivial-project.sh"); - - $machine->waitUntilSucceeds('curl -L -s http://localhost:3000/build/1 -H "Accept: application/json" | jq .buildstatus | xargs test 0 -eq'); + trivialJob = pkgs.writeTextDir "trivial.nix" '' + { trivial = builtins.derivation { + name = "trivial"; + system = "x86_64-linux"; + builder = "/bin/sh"; + args = ["-c" "echo success > $out; exit 0"]; + }; + } + ''; + + createTrivialProject = pkgs.stdenv.mkDerivation { + name = "create-trivial-project"; + unpackPhase = ":"; + buildInputs = [ pkgs.makeWrapper ]; + installPhase = "install -m755 -D ${./create-trivial-project.sh} $out/bin/create-trivial-project.sh"; + postFixup = '' + wrapProgram "$out/bin/create-trivial-project.sh" --prefix PATH ":" ${pkgs.stdenv.lib.makeBinPath [ pkgs.curl ]} --set EXPR_PATH ${trivialJob} ''; -}) + }; + + callTest = f: f { inherit system pkgs; }; + + hydraPkgs = { + inherit (pkgs) nixStable nixUnstable; + }; + + tests = pkgs.lib.flip pkgs.lib.mapAttrs hydraPkgs (name: nix: + callTest (import ../make-test.nix ({ pkgs, lib, ... }: + { + name = "hydra-with-${name}"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ pstn lewo ma27 ]; + }; + + machine = { pkgs, ... }: + { + virtualisation.memorySize = 1024; + time.timeZone = "UTC"; + + environment.systemPackages = [ createTrivialProject pkgs.jq ]; + services.hydra = { + enable = true; + + #Hydra needs those settings to start up, so we add something not harmfull. + hydraURL = "example.com"; + notificationSender = "example@example.com"; + + package = pkgs.hydra.override { inherit nix; }; + }; + nix = { + buildMachines = [{ + hostName = "localhost"; + systems = [ "x86_64-linux" ]; + }]; + + binaryCaches = []; + }; + }; + + testScript = '' + # let the system boot up + $machine->waitForUnit("multi-user.target"); + # test whether the database is running + $machine->succeed("systemctl status postgresql.service"); + # test whether the actual hydra daemons are running + $machine->succeed("systemctl status hydra-queue-runner.service"); + $machine->succeed("systemctl status hydra-init.service"); + $machine->succeed("systemctl status hydra-evaluator.service"); + $machine->succeed("systemctl status hydra-send-stats.service"); + + $machine->succeed("hydra-create-user admin --role admin --password admin"); + + # create a project with a trivial job + $machine->waitForOpenPort(3000); + + # make sure the build as been successfully built + $machine->succeed("create-trivial-project.sh"); + + $machine->waitUntilSucceeds('curl -L -s http://localhost:3000/build/1 -H "Accept: application/json" | jq .buildstatus | xargs test 0 -eq'); + ''; + }))); + +in + tests diff --git a/nixos/tests/matrix-synapse.nix b/nixos/tests/matrix-synapse.nix index 8504a7c0d057..882e4b75814b 100644 --- a/nixos/tests/matrix-synapse.nix +++ b/nixos/tests/matrix-synapse.nix @@ -1,4 +1,32 @@ -import ./make-test.nix ({ pkgs, ... } : { +import ./make-test.nix ({ pkgs, ... } : let + + + runWithOpenSSL = file: cmd: pkgs.runCommand file { + buildInputs = [ pkgs.openssl ]; + } cmd; + + + ca_key = runWithOpenSSL "ca-key.pem" "openssl genrsa -out $out 2048"; + ca_pem = runWithOpenSSL "ca.pem" '' + openssl req \ + -x509 -new -nodes -key ${ca_key} \ + -days 10000 -out $out -subj "/CN=snakeoil-ca" + ''; + key = runWithOpenSSL "matrix_key.pem" "openssl genrsa -out $out 2048"; + csr = runWithOpenSSL "matrix.csr" '' + openssl req \ + -new -key ${key} \ + -out $out -subj "/CN=localhost" \ + ''; + cert = runWithOpenSSL "matrix_cert.pem" '' + openssl x509 \ + -req -in ${csr} \ + -CA ${ca_pem} -CAkey ${ca_key} \ + -CAcreateserial -out $out \ + -days 365 + ''; + +in { name = "matrix-synapse"; meta = with pkgs.stdenv.lib.maintainers; { @@ -8,23 +36,31 @@ import ./make-test.nix ({ pkgs, ... } : { nodes = { # Since 0.33.0, matrix-synapse doesn't allow underscores in server names serverpostgres = args: { - services.matrix-synapse.enable = true; - services.matrix-synapse.database_type = "psycopg2"; + services.matrix-synapse = { + enable = true; + database_type = "psycopg2"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + }; }; serversqlite = args: { - services.matrix-synapse.enable = true; - services.matrix-synapse.database_type = "sqlite3"; + services.matrix-synapse = { + enable = true; + database_type = "sqlite3"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + }; }; }; testScript = '' startAll; $serverpostgres->waitForUnit("matrix-synapse.service"); - $serverpostgres->waitUntilSucceeds("curl -Lk https://localhost:8448/"); + $serverpostgres->waitUntilSucceeds("curl -L --cacert ${ca_pem} https://localhost:8448/"); $serverpostgres->requireActiveUnit("postgresql.service"); $serversqlite->waitForUnit("matrix-synapse.service"); - $serversqlite->waitUntilSucceeds("curl -Lk https://localhost:8448/"); + $serversqlite->waitUntilSucceeds("curl -L --cacert ${ca_pem} https://localhost:8448/"); $serversqlite->mustSucceed("[ -e /var/lib/matrix-synapse/homeserver.db ]"); ''; diff --git a/nixos/tests/munin.nix b/nixos/tests/munin.nix index 9f66005292ab..95cecf17b8cc 100644 --- a/nixos/tests/munin.nix +++ b/nixos/tests/munin.nix @@ -15,9 +15,7 @@ import ./make-test.nix ({ pkgs, ...} : { munin-node = { enable = true; # disable a failing plugin to prevent irrelevant error message, see #23049 - extraConfig = '' - ignore_file ^apc_nis$ - ''; + disabledPlugins = [ "apc_nis" ]; }; munin-cron = { enable = true; diff --git a/nixos/tests/ndppd.nix b/nixos/tests/ndppd.nix new file mode 100644 index 000000000000..9f24eb6d9d45 --- /dev/null +++ b/nixos/tests/ndppd.nix @@ -0,0 +1,61 @@ +import ./make-test.nix ({ pkgs, lib, ...} : { + name = "ndppd"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ fpletz ]; + }; + + nodes = { + upstream = { pkgs, ... }: { + environment.systemPackages = [ pkgs.tcpdump ]; + networking.useDHCP = false; + networking.interfaces = { + eth1 = { + ipv6.addresses = [ + { address = "fd23::1"; prefixLength = 112; } + ]; + ipv6.routes = [ + { address = "fd42::"; + prefixLength = 112; + } + ]; + }; + }; + }; + server = { pkgs, ... }: { + boot.kernel.sysctl = { + "net.ipv6.conf.all.forwarding" = "1"; + "net.ipv6.conf.default.forwarding" = "1"; + }; + environment.systemPackages = [ pkgs.tcpdump ]; + networking.useDHCP = false; + networking.interfaces = { + eth1 = { + ipv6.addresses = [ + { address = "fd23::2"; prefixLength = 112; } + ]; + }; + }; + services.ndppd = { + enable = true; + interface = "eth1"; + network = "fd42::/112"; + }; + containers.client = { + autoStart = true; + privateNetwork = true; + hostAddress = "192.168.255.1"; + localAddress = "192.168.255.2"; + hostAddress6 = "fd42::1"; + localAddress6 = "fd42::2"; + config = {}; + }; + }; + }; + + testScript = '' + startAll; + $server->waitForUnit("multi-user.target"); + $upstream->waitForUnit("multi-user.target"); + $upstream->waitUntilSucceeds("ping -c5 fd42::2"); + ''; +}) diff --git a/nixos/tests/neo4j.nix b/nixos/tests/neo4j.nix new file mode 100644 index 000000000000..86ed8970517c --- /dev/null +++ b/nixos/tests/neo4j.nix @@ -0,0 +1,20 @@ +import ./make-test.nix { + name = "neo4j"; + + nodes = { + master = + { ... }: + + { + services.neo4j.enable = true; + }; + }; + + testScript = '' + startAll; + + $master->waitForUnit("neo4j"); + $master->sleep(20); # Hopefully this is long enough!! + $master->succeed("curl http://localhost:7474/"); + ''; +} diff --git a/nixos/tests/osrm-backend.nix b/nixos/tests/osrm-backend.nix new file mode 100644 index 000000000000..6e2d098d4adb --- /dev/null +++ b/nixos/tests/osrm-backend.nix @@ -0,0 +1,53 @@ +import ./make-test.nix ({ pkgs, lib, ... }: +let + port = 5000; +in { + name = "osrm-backend"; + meta.maintainers = [ lib.maintainers.erictapen ]; + + machine = { config, pkgs, ... }:{ + + services.osrm = { + enable = true; + inherit port; + dataFile = let + filename = "monaco"; + osrm-data = pkgs.stdenv.mkDerivation { + name = "osrm-data"; + + buildInputs = [ pkgs.osrm-backend ]; + + # This is a pbf file of monaco, downloaded at 2019-01-04 from + # http://download.geofabrik.de/europe/monaco-latest.osm.pbf + # as apparently no provider of OSM files guarantees immutability, + # this is hosted as a gist on GitHub. + src = pkgs.fetchgit { + url = "https://gist.github.com/erictapen/01e39f73a6c856eac53ba809a94cdb83"; + rev = "9b1ff0f24deb40e5cf7df51f843dbe860637b8ce"; + sha256 = "1scqhmrfnpwsy5i2a9jpggqnvfgj4hv9p4qyvc79321pzkbv59nx"; + }; + + buildCommand = '' + cp $src/${filename}.osm.pbf . + ${pkgs.osrm-backend}/bin/osrm-extract -p ${pkgs.osrm-backend}/share/osrm/profiles/car.lua ${filename}.osm.pbf + ${pkgs.osrm-backend}/bin/osrm-partition ${filename}.osrm + ${pkgs.osrm-backend}/bin/osrm-customize ${filename}.osrm + mkdir -p $out + cp ${filename}* $out/ + ''; + }; + in "${osrm-data}/${filename}.osrm"; + }; + + environment.systemPackages = [ pkgs.jq ]; + }; + + testScript = let + query = "http://localhost:${toString port}/route/v1/driving/7.41720,43.73304;7.42463,43.73886?steps=true"; + in '' + $machine->waitForUnit("osrm.service"); + $machine->waitForOpenPort(${toString port}); + $machine->succeed("curl --silent '${query}' | jq .waypoints[0].name | grep -F 'Boulevard Rainier III'"); + $machine->succeed("curl --silent '${query}' | jq .waypoints[1].name | grep -F 'Avenue de la Costa'"); + ''; +}) diff --git a/nixos/tests/postgresql.nix b/nixos/tests/postgresql.nix index 9e1f4f235af0..ae5d6d095ea2 100644 --- a/nixos/tests/postgresql.nix +++ b/nixos/tests/postgresql.nix @@ -7,7 +7,7 @@ with import ../lib/testing.nix { inherit system pkgs; }; with pkgs.lib; let - postgresql-versions = import ../../pkgs/servers/sql/postgresql pkgs pkgs; + postgresql-versions = import ../../pkgs/servers/sql/postgresql pkgs; test-sql = pkgs.writeText "postgresql-test" '' CREATE EXTENSION pgcrypto; -- just to check if lib loading works CREATE TABLE sth ( @@ -67,12 +67,7 @@ let }; in - (mapAttrs' (name: package: { inherit name; value=make-postgresql-test name package false;}) postgresql-versions) // ( - # just pick one version for the dump all test - let - first = head (attrNames postgresql-versions); - name = "${first}-backup-all"; - in { - ${name} = make-postgresql-test name postgresql-versions.${first} true; - } - ) + (mapAttrs' (name: package: { inherit name; value=make-postgresql-test name package false;}) postgresql-versions) // { + postgresql_11-backup-all = make-postgresql-test "postgresql_11-backup-all" postgresql-versions.postgresql_11 true; + } + diff --git a/nixos/tests/redmine.nix b/nixos/tests/redmine.nix index 330f72854cac..ea72a0121d11 100644 --- a/nixos/tests/redmine.nix +++ b/nixos/tests/redmine.nix @@ -1,40 +1,58 @@ -import ./make-test.nix ({ pkgs, lib, ... }: -{ - name = "redmine"; - meta.maintainers = [ lib.maintainers.aanderse ]; +{ system ? builtins.currentSystem, + config ? {}, + pkgs ? import ../.. { inherit system config; } +}: + +with import ../lib/testing.nix { inherit system pkgs; }; +with pkgs.lib; - machine = - { config, pkgs, ... }: - { services.mysql.enable = true; - services.mysql.package = pkgs.mariadb; - services.mysql.ensureDatabases = [ "redmine" ]; - services.mysql.ensureUsers = [ - { name = "redmine"; - ensurePermissions = { "redmine.*" = "ALL PRIVILEGES"; }; - } - ]; +let + redmineTest = package: makeTest { + machine = + { config, pkgs, ... }: + { services.mysql.enable = true; + services.mysql.package = pkgs.mariadb; + services.mysql.ensureDatabases = [ "redmine" ]; + services.mysql.ensureUsers = [ + { name = "redmine"; + ensurePermissions = { "redmine.*" = "ALL PRIVILEGES"; }; + } + ]; - services.redmine.enable = true; - services.redmine.database.socket = "/run/mysqld/mysqld.sock"; - services.redmine.plugins = { - redmine_env_auth = pkgs.fetchurl { - url = https://github.com/Intera/redmine_env_auth/archive/0.6.zip; - sha256 = "0yyr1yjd8gvvh832wdc8m3xfnhhxzk2pk3gm2psg5w9jdvd6skak"; + services.redmine.enable = true; + services.redmine.package = package; + services.redmine.database.socket = "/run/mysqld/mysqld.sock"; + services.redmine.plugins = { + redmine_env_auth = pkgs.fetchurl { + url = https://github.com/Intera/redmine_env_auth/archive/0.7.zip; + sha256 = "1xb8lyarc7mpi86yflnlgyllh9hfwb9z304f19dx409gqpia99sc"; + }; }; - }; - services.redmine.themes = { - dkuk-redmine_alex_skin = pkgs.fetchurl { - url = https://bitbucket.org/dkuk/redmine_alex_skin/get/1842ef675ef3.zip; - sha256 = "0hrin9lzyi50k4w2bd2b30vrf1i4fi1c0gyas5801wn8i7kpm9yl"; + services.redmine.themes = { + dkuk-redmine_alex_skin = pkgs.fetchurl { + url = https://bitbucket.org/dkuk/redmine_alex_skin/get/1842ef675ef3.zip; + sha256 = "0hrin9lzyi50k4w2bd2b30vrf1i4fi1c0gyas5801wn8i7kpm9yl"; + }; }; }; - }; - testScript = '' - startAll; + testScript = '' + startAll; + + $machine->waitForUnit('redmine.service'); + $machine->waitForOpenPort('3000'); + $machine->succeed("curl --fail http://localhost:3000/"); + ''; + }; +in +{ + redmine_3 = redmineTest pkgs.redmine // { + name = "redmine_3"; + meta.maintainers = [ maintainers.aanderse ]; + }; - $machine->waitForUnit('redmine.service'); - $machine->waitForOpenPort('3000'); - $machine->succeed("curl --fail http://localhost:3000/"); - ''; -}) + redmine_4 = redmineTest pkgs.redmine_4 // { + name = "redmine_4"; + meta.maintainers = [ maintainers.aanderse ]; + }; +} diff --git a/nixos/tests/roundcube.nix b/nixos/tests/roundcube.nix index 178134fd9b30..ed0ebd7dd19d 100644 --- a/nixos/tests/roundcube.nix +++ b/nixos/tests/roundcube.nix @@ -10,6 +10,8 @@ import ./make-test.nix ({ pkgs, ...} : { enable = true; hostName = "roundcube"; database.password = "notproduction"; + package = pkgs.roundcube.withPlugins (plugins: [ plugins.persistent_login ]); + plugins = [ "persistent_login" ]; }; services.nginx.virtualHosts.roundcube = { forceSSL = false; @@ -23,6 +25,6 @@ import ./make-test.nix ({ pkgs, ...} : { $roundcube->waitForUnit("postgresql.service"); $roundcube->waitForUnit("phpfpm-roundcube.service"); $roundcube->waitForUnit("nginx.service"); - $roundcube->succeed("curl -sSfL http://roundcube/"); + $roundcube->succeed("curl -sSfL http://roundcube/ | grep 'Keep me logged in'"); ''; }) |