diff options
Diffstat (limited to 'nixpkgs/nixos')
178 files changed, 6737 insertions, 2269 deletions
diff --git a/nixpkgs/nixos/doc/manual/configuration/matrix.xml b/nixpkgs/nixos/doc/manual/configuration/matrix.xml index 4c559a71e813..ef8d5cbda889 100644 --- a/nixpkgs/nixos/doc/manual/configuration/matrix.xml +++ b/nixpkgs/nixos/doc/manual/configuration/matrix.xml @@ -95,7 +95,7 @@ in { # forward all Matrix API calls to the synapse Matrix homeserver locations."/_matrix" = { - proxyPass = "http://[::1]:8008"; + proxyPass = "http://[::1]:8008"; # without a trailing / }; }; }; diff --git a/nixpkgs/nixos/doc/manual/configuration/x-windows.xml b/nixpkgs/nixos/doc/manual/configuration/x-windows.xml index 798d1fbdfd85..7cdc5196e0d2 100644 --- a/nixpkgs/nixos/doc/manual/configuration/x-windows.xml +++ b/nixpkgs/nixos/doc/manual/configuration/x-windows.xml @@ -125,10 +125,12 @@ You will need to reboot after enabling this driver to prevent a clash with other kernel modules. </para> + <note> <para> - Note: for recent AMD GPUs you most likely want to keep either the defaults + For recent AMD GPUs you most likely want to keep either the defaults or <literal>"amdgpu"</literal> (both free). </para> + </note> </simplesect> <simplesect xml:id="sec-x11-touchpads"> <title>Touchpads</title> @@ -157,4 +159,134 @@ versions. </para> </simplesect> + <simplesect xml:id="custom-xkb-layouts"> + <title>Custom XKB layouts</title> + <para> + It is possible to install custom + <link xlink:href="https://en.wikipedia.org/wiki/X_keyboard_extension"> + XKB + </link> + keyboard layouts using the option + <option> + <link linkend="opt-services.xserver.extraLayouts"> + services.xserver.extraLayouts + </link> + </option>. + As a first example, we are going to create a layout based on the basic US + layout, with an additional layer to type some greek symbols by pressing the + right-alt key. + </para> + <para> + To do this we are going to create a <literal>us-greek</literal> file + with a <literal>xkb_symbols</literal> section. + </para> +<programlisting> +xkb_symbols "us-greek" +{ + include "us(basic)" // includes the base US keys + include "level3(ralt_switch)" // configures right alt as a third level switch + + key <LatA> { [ a, A, Greek_alpha ] }; + key <LatB> { [ b, B, Greek_beta ] }; + key <LatG> { [ g, G, Greek_gamma ] }; + key <LatD> { [ d, D, Greek_delta ] }; + key <LatZ> { [ z, Z, Greek_zeta ] }; +}; +</programlisting> + <para> + To install the layout, the filepath, a description and the list of + languages must be given: + </para> +<programlisting> +<xref linkend="opt-services.xserver.extraLayouts"/>.us-greek = { + description = "US layout with alt-gr greek"; + languages = [ "eng" ]; + symbolsFile = /path/to/us-greek; +} +</programlisting> + <note> + <para> + The name should match the one given to the + <literal>xkb_symbols</literal> block. + </para> + </note> + <para> + The layout should now be installed and ready to use: try it by + running <literal>setxkbmap us-greek</literal> and type + <literal><alt>+a</literal>. To change the default the usual + <option> + <link linkend="opt-services.xserver.layout"> + services.xserver.layout + </link> + </option> + option can still be used. + </para> + <para> + A layout can have several other components besides + <literal>xkb_symbols</literal>, for example we will define new + keycodes for some multimedia key and bind these to some symbol. + </para> + <para> + Use the <emphasis>xev</emphasis> utility from + <literal>pkgs.xorg.xev</literal> to find the codes of the keys of + interest, then create a <literal>media-key</literal> file to hold + the keycodes definitions + </para> +<programlisting> +xkb_keycodes "media" +{ + <volUp> = 123; + <volDown> = 456; +} +</programlisting> + <para> + Now use the newly define keycodes in <literal>media-sym</literal>: + </para> +<programlisting> +xkb_symbols "media" +{ + key.type = "ONE_LEVEL"; + key <volUp> { [ XF86AudioLowerVolume ] }; + key <volDown> { [ XF86AudioRaiseVolume ] }; +} +</programlisting> + <para> + As before, to install the layout do + </para> +<programlisting> +<xref linkend="opt-services.xserver.extraLayouts"/>.media = { + description = "Multimedia keys remapping"; + languages = [ "eng" ]; + symbolsFile = /path/to/media-key; + keycodesFile = /path/to/media-sym; +}; +</programlisting> + <note> + <para> + The function <literal>pkgs.writeText <filename> <content> + </literal> can be useful if you prefer to keep the layout definitions + inside the NixOS configuration. + </para> + </note> + <para> + Unfortunately, the Xorg server does not (currently) support setting a + keymap directly but relies instead on XKB rules to select the matching + components (keycodes, types, ...) of a layout. This means that components + other than symbols won't be loaded by default. As a workaround, you + can set the keymap using <literal>setxkbmap</literal> at the start of the + session with: + </para> +<programlisting> +<xref linkend="opt-services.xserver.displayManager.sessionCommands"/> = "setxkbmap -keycodes media"; +</programlisting> + <para> + To learn how to write layouts take a look at the XKB + <link xlink:href="https://www.x.org/releases/current/doc/xorg-docs/input/XKB-Enhancing.html#Defining_New_Layouts"> + documentation + </link>. More example layouts can also be found + <link xlink:href="https://wiki.archlinux.org/index.php/X_KeyBoard_extension#Basic_examples"> + here + </link>. + </para> +</simplesect> </chapter> diff --git a/nixpkgs/nixos/doc/manual/default.nix b/nixpkgs/nixos/doc/manual/default.nix index 7fc0ad702f84..f9de2db1a084 100644 --- a/nixpkgs/nixos/doc/manual/default.nix +++ b/nixpkgs/nixos/doc/manual/default.nix @@ -5,55 +5,6 @@ with pkgs; let lib = pkgs.lib; - # Remove invisible and internal options. - optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options); - - # Replace functions by the string <function> - substFunction = x: - if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x - else if builtins.isList x then map substFunction x - else if lib.isFunction x then "<function>" - else x; - - # Generate DocBook documentation for a list of packages. This is - # what `relatedPackages` option of `mkOption` from - # ../../../lib/options.nix influences. - # - # Each element of `relatedPackages` can be either - # - a string: that will be interpreted as an attribute name from `pkgs`, - # - a list: that will be interpreted as an attribute path from `pkgs`, - # - an attrset: that can specify `name`, `path`, `package`, `comment` - # (either of `name`, `path` is required, the rest are optional). - genRelatedPackages = packages: - let - unpack = p: if lib.isString p then { name = p; } - else if lib.isList p then { path = p; } - else p; - describe = args: - let - title = args.title or null; - name = args.name or (lib.concatStringsSep "." args.path); - path = args.path or [ args.name ]; - package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs); - in "<listitem>" - + "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>" - + lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>" - + ": ${package.meta.description or "???"}.</para>" - + lib.optionalString (args ? comment) "\n<para>${args.comment}</para>" - # Lots of `longDescription's break DocBook, so we just wrap them into <programlisting> - + lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>" - + "</listitem>"; - in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>"; - - optionsListDesc = lib.flip map optionsListVisible (opt: opt // { - # Clean up declaration sites to not refer to the NixOS source tree. - declarations = map stripAnyPrefixes opt.declarations; - } - // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; } - // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; } - // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; } - // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; }); - # We need to strip references to /nix/store/* from options, # including any `extraSources` if some modules came from elsewhere, # or else the build will fail. @@ -63,37 +14,13 @@ let prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources); stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip; - # Custom "less" that pushes up all the things ending in ".enable*" - # and ".package*" - optionLess = a: b: - let - ise = lib.hasPrefix "enable"; - isp = lib.hasPrefix "package"; - cmp = lib.splitByAndCompare ise lib.compare - (lib.splitByAndCompare isp lib.compare lib.compare); - in lib.compareLists cmp a.loc b.loc < 0; - - # Customly sort option list for the man page. - optionsList = lib.sort optionLess optionsListDesc; - - # Convert the list of options into an XML file. - optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList); - - optionsDocBook = runCommand "options-db.xml" {} '' - optionsXML=${optionsXML} - if grep /nixpkgs/nixos/modules $optionsXML; then - echo "The manual appears to depend on the location of Nixpkgs, which is bad" - echo "since this prevents sharing via the NixOS channel. This is typically" - echo "caused by an option default that refers to a relative path (see above" - echo "for hints about the offending path)." - exit 1 - fi - ${buildPackages.libxslt.bin}/bin/xsltproc \ - --stringparam revision '${revision}' \ - -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML - ${buildPackages.libxslt.bin}/bin/xsltproc \ - -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml - ''; + optionsDoc = buildPackages.nixosOptionsDoc { + inherit options revision; + transformOptions = opt: opt // { + # Clean up declaration sites to not refer to the NixOS source tree. + declarations = map stripAnyPrefixes opt.declarations; + }; + }; sources = lib.sourceFilesBySuffices ./. [".xml"]; @@ -108,7 +35,7 @@ let generatedSources = runCommand "generated-docbook" {} '' mkdir $out ln -s ${modulesDoc} $out/modules.xml - ln -s ${optionsDocBook} $out/options-db.xml + ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml printf "%s" "${version}" > $out/version ''; @@ -234,22 +161,7 @@ let in rec { inherit generatedSources; - # The NixOS options in JSON format. - optionsJSON = runCommand "options-json" - { meta.description = "List of NixOS options in JSON format"; - } - '' - # Export list of options in different format. - dst=$out/share/doc/nixos - mkdir -p $dst - - cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON - (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList)))) - } $dst/options.json - - mkdir -p $out/nix-support - echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products - ''; # */ + inherit (optionsDoc) optionsJSON optionsXML optionsDocBook; # Generate the NixOS manual. manualHTML = runCommand "nixos-manual-html" diff --git a/nixpkgs/nixos/doc/manual/development/releases.xml b/nixpkgs/nixos/doc/manual/development/releases.xml index f45fecd16c35..3cb16d33cd48 100755 --- a/nixpkgs/nixos/doc/manual/development/releases.xml +++ b/nixpkgs/nixos/doc/manual/development/releases.xml @@ -100,6 +100,16 @@ </listitem> <listitem> <para> + Remove attributes that we know we will not be able to support, + especially if there is a stable alternative. E.g. Check that our + Linux kernels' + <link xlink:href="https://www.kernel.org/category/releases.html"> + projected end-of-life</link> are after our release projected + end-of-life + </para> + </listitem> + <listitem> + <para> Edit changelog at <literal>nixos/doc/manual/release-notes/rl-1709.xml</literal> (double check desktop versions are noted) diff --git a/nixpkgs/nixos/doc/manual/man-pages.xml b/nixpkgs/nixos/doc/manual/man-pages.xml index 0390dda6468f..f5a1dd2d69f4 100644 --- a/nixpkgs/nixos/doc/manual/man-pages.xml +++ b/nixpkgs/nixos/doc/manual/man-pages.xml @@ -6,7 +6,7 @@ <author><personname><firstname>Eelco</firstname><surname>Dolstra</surname></personname> <contrib>Author</contrib> </author> - <copyright><year>2007-2018</year><holder>Eelco Dolstra</holder> + <copyright><year>2007-2019</year><holder>Eelco Dolstra</holder> </copyright> </info> <xi:include href="man-configuration.xml" /> diff --git a/nixpkgs/nixos/doc/manual/release-notes/rl-1909.xml b/nixpkgs/nixos/doc/manual/release-notes/rl-1909.xml index 53f5b8bb7321..b12858cfc963 100644 --- a/nixpkgs/nixos/doc/manual/release-notes/rl-1909.xml +++ b/nixpkgs/nixos/doc/manual/release-notes/rl-1909.xml @@ -33,6 +33,15 @@ PHP 7.1 is no longer supported due to upstream not supporting this version for the entire lifecycle of the 19.09 release. </para> </listitem> + <listitem> + <para> + The binfmt module is now easier to use. Additional systems can + be added through <option>boot.binfmt.emulatedSystems</option>. + For instance, <literal>boot.binfmt.emulatedSystems = [ + "wasm32-wasi" "x86_64-windows" "aarch64-linux" ];</literal> will + set up binfmt interpreters for each of those listed systems. + </para> + </listitem> </itemizedlist> </section> @@ -47,6 +56,13 @@ The following new services were added since the last release: </para> + <itemizedlist> + <listitem> + <para> + <literal>./programs/dwm-status.nix</literal> + </para> + </listitem> + </itemizedlist> </section> <section xmlns="http://docbook.org/ns/docbook" @@ -123,6 +139,19 @@ </para> </listitem> <listitem> + <para> + IPv6 Privacy Extensions are now enabled by default for undeclared + interfaces. The previous behaviour was quite misleading — even though + the default value for + <option>networking.interfaces.*.preferTempAddress</option> was + <literal>true</literal>, undeclared interfaces would not prefer temporary + addresses. Now, interfaces not mentioned in the config will prefer + temporary addresses. EUI64 addresses can still be set as preferred by + explicitly setting the option to <literal>false</literal> for the + interface in question. + </para> + </listitem> + <listitem> <para> Since Bittorrent Sync was superseded by Resilio Sync in 2016, the <literal>bittorrentSync</literal>, <literal>bittorrentSync14</literal>, @@ -136,10 +165,22 @@ </listitem> <listitem> <para> - Several of the apache subservices have been replaced with full NixOS - modules including LimeSurvey and WordPress. - These modules can be enabled using the <option>services.limesurvey.enable</option> - and <option>services.wordpress.enable</option> options. + The httpd service no longer attempts to start the postgresql service. If you have come to depend + on this behaviour then you can preserve the behavior with the following configuration: + <literal>systemd.services.httpd.after = [ "postgresql.service" ];</literal> + </para> + <para> + The option <option>services.httpd.extraSubservices</option> has been + marked as deprecated. You may still use this feature, but it will be + removed in a future release of NixOS. You are encouraged to convert any + httpd subservices you may have written to a full NixOS module. + </para> + <para> + Most of the httpd subservices packaged with NixOS have been replaced with + full NixOS modules including LimeSurvey, WordPress, and Zabbix. These + modules can be enabled using the <option>services.limesurvey.enable</option>, + <option>services.mediawiki.enable</option>, <option>services.wordpress.enable</option>, + and <option>services.zabbixWeb.enable</option> options. </para> </listitem> <listitem> @@ -182,6 +223,31 @@ <xref linkend="opt-programs.zsh.loginShellInit" /> and <xref linkend="opt-programs.zsh.promptInit" /> may break if it relies on those options being set. </para> </listitem> + <listitem> + <para> + The <literal>prometheus-nginx-exporter</literal> package now uses the offical exporter provided by NGINX Inc. + Its metrics are differently structured and are incompatible to the old ones. For information about the metrics, + have a look at the <link xlink:href="https://github.com/nginxinc/nginx-prometheus-exporter">official repo</link>. + </para> + </listitem> + <listitem> + <para> + Nodejs 8 is scheduled EOL under the lifetime of 19.09 and has been dropped. + </para> + </listitem> + <listitem> + <para> + By default, prometheus exporters are now run with <literal>DynamicUser</literal> enabled. + Exporters that need a real user, now run under a seperate user and group which follow the pattern <literal><exporter-name>-exporter</literal>, instead of the previous default <literal>nobody</literal> and <literal>nogroup</literal>. + Only some exporters are affected by the latter, namely the exporters <literal>dovecot</literal>, <literal>node</literal>, <literal>postfix</literal> and <literal>varnish</literal>. + </para> + </listitem> + <listitem> + <para> + The <literal>ibus-qt</literal> package is not installed by default anymore when <xref linkend="opt-i18n.inputMethod.enabled" /> is set to <literal>ibus</literal>. + If IBus support in Qt 4.x applications is required, add the <literal>ibus-qt</literal> package to your <xref linkend="opt-environment.systemPackages" /> manually. + </para> + </listitem> </itemizedlist> </section> @@ -318,6 +384,31 @@ The <literal>mercurial</literal> <literal>httpd.extraSubservice</literal> has been removed from nixpkgs due to lack of maintainer. </para> </listitem> + <listitem> + <para> + The <literal>trac</literal> <literal>httpd.extraSubservice</literal> has been removed from nixpkgs because it was unmaintained. + </para> + </listitem> + <listitem> + <para> + The <literal>foswiki</literal> package and associated <literal>httpd.extraSubservice</literal> have been removed + from nixpkgs due to lack of maintainer. + </para> + </listitem> + <listitem> + <para> + The <literal>tomcat-connector</literal> <literal>httpd.extraSubservice</literal> has been removed from nixpkgs. + </para> + </listitem> + <listitem> + <para> + It's now possible to change configuration in + <link linkend="opt-services.nextcloud.enable">services.nextcloud</link> after the initial deploy + since all config parameters are persisted in an additional config file generated by the module. + Previously core configuration like database parameters were set using their imperative + installer after creating <literal>/var/lib/nextcloud</literal>. + </para> + </listitem> </itemizedlist> </section> </section> diff --git a/nixpkgs/nixos/lib/build-vms.nix b/nixpkgs/nixos/lib/build-vms.nix index 6c92aa1ffa2f..b622a4d59e89 100644 --- a/nixpkgs/nixos/lib/build-vms.nix +++ b/nixpkgs/nixos/lib/build-vms.nix @@ -67,7 +67,7 @@ rec { in { key = "ip-address"; config = - { networking.hostName = m.fst; + { networking.hostName = mkDefault m.fst; networking.interfaces = listToAttrs interfaces; diff --git a/nixpkgs/nixos/lib/make-options-doc/default.nix b/nixpkgs/nixos/lib/make-options-doc/default.nix new file mode 100644 index 000000000000..c22c7500335d --- /dev/null +++ b/nixpkgs/nixos/lib/make-options-doc/default.nix @@ -0,0 +1,125 @@ +/* Generate JSON, XML and DocBook documentation for given NixOS options. + + Minimal example: + + { pkgs, }: + + let + eval = import (pkgs.path + "/nixos/lib/eval-config.nix") { + baseModules = [ + ../module.nix + ]; + modules = []; + }; + in pkgs.nixosOptionsDoc { + options = eval.options; + } + +*/ +{ pkgs +, lib +, options +, transformOptions ? lib.id # function for additional tranformations of the options +, revision ? "" # Specify revision for the options +}: + +let + # Replace functions by the string <function> + substFunction = x: + if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x + else if builtins.isList x then map substFunction x + else if lib.isFunction x then "<function>" + else x; + + optionsListDesc = lib.flip map optionsListVisible + (opt: transformOptions opt + // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; } + // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; } + // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; } + // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; } + ); + + # Generate DocBook documentation for a list of packages. This is + # what `relatedPackages` option of `mkOption` from + # ../../../lib/options.nix influences. + # + # Each element of `relatedPackages` can be either + # - a string: that will be interpreted as an attribute name from `pkgs`, + # - a list: that will be interpreted as an attribute path from `pkgs`, + # - an attrset: that can specify `name`, `path`, `package`, `comment` + # (either of `name`, `path` is required, the rest are optional). + genRelatedPackages = packages: + let + unpack = p: if lib.isString p then { name = p; } + else if lib.isList p then { path = p; } + else p; + describe = args: + let + title = args.title or null; + name = args.name or (lib.concatStringsSep "." args.path); + path = args.path or [ args.name ]; + package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs); + in "<listitem>" + + "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>" + + lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>" + + ": ${package.meta.description or "???"}.</para>" + + lib.optionalString (args ? comment) "\n<para>${args.comment}</para>" + # Lots of `longDescription's break DocBook, so we just wrap them into <programlisting> + + lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>" + + "</listitem>"; + in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>"; + + # Custom "less" that pushes up all the things ending in ".enable*" + # and ".package*" + optionLess = a: b: + let + ise = lib.hasPrefix "enable"; + isp = lib.hasPrefix "package"; + cmp = lib.splitByAndCompare ise lib.compare + (lib.splitByAndCompare isp lib.compare lib.compare); + in lib.compareLists cmp a.loc b.loc < 0; + + # Remove invisible and internal options. + optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options); + + # Customly sort option list for the man page. + optionsList = lib.sort optionLess optionsListDesc; + + # Convert the list of options into an XML file. + optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList); + +in rec { + # The NixOS options in JSON format. + optionsJSON = pkgs.runCommand "options.json" + { meta.description = "List of NixOS options in JSON format"; + } + '' + # Export list of options in different format. + dst=$out/share/doc/nixos + mkdir -p $dst + + cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON + (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList)))) + } $dst/options.json + + mkdir -p $out/nix-support + echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products + ''; # */ + + optionsDocBook = pkgs.runCommand "options-docbook.xml" {} '' + optionsXML=${optionsXML} + if grep /nixpkgs/nixos/modules $optionsXML; then + echo "The manual appears to depend on the location of Nixpkgs, which is bad" + echo "since this prevents sharing via the NixOS channel. This is typically" + echo "caused by an option default that refers to a relative path (see above" + echo "for hints about the offending path)." + exit 1 + fi + + ${pkgs.libxslt.bin}/bin/xsltproc \ + --stringparam revision '${revision}' \ + -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML + ${pkgs.libxslt.bin}/bin/xsltproc \ + -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml + ''; +} diff --git a/nixpkgs/nixos/doc/manual/options-to-docbook.xsl b/nixpkgs/nixos/lib/make-options-doc/options-to-docbook.xsl index 72ac89d4ff62..72ac89d4ff62 100644 --- a/nixpkgs/nixos/doc/manual/options-to-docbook.xsl +++ b/nixpkgs/nixos/lib/make-options-doc/options-to-docbook.xsl diff --git a/nixpkgs/nixos/doc/manual/postprocess-option-descriptions.xsl b/nixpkgs/nixos/lib/make-options-doc/postprocess-option-descriptions.xsl index 1201c7612c2e..1201c7612c2e 100644 --- a/nixpkgs/nixos/doc/manual/postprocess-option-descriptions.xsl +++ b/nixpkgs/nixos/lib/make-options-doc/postprocess-option-descriptions.xsl diff --git a/nixpkgs/nixos/lib/test-driver/Machine.pm b/nixpkgs/nixos/lib/test-driver/Machine.pm index 006da889671e..4d3d63cd2dbf 100644 --- a/nixpkgs/nixos/lib/test-driver/Machine.pm +++ b/nixpkgs/nixos/lib/test-driver/Machine.pm @@ -31,9 +31,17 @@ sub new { if (!$startCommand) { # !!! merge with qemu-vm.nix. + my $netBackend = "-netdev user,id=net0"; + my $netFrontend = "-device virtio-net-pci,netdev=net0"; + + $netBackend .= "," . $args->{netBackendArgs} + if defined $args->{netBackendArgs}; + + $netFrontend .= "," . $args->{netFrontendArgs} + if defined $args->{netFrontendArgs}; + $startCommand = - "qemu-kvm -m 384 " . - "-net nic,model=virtio \$QEMU_OPTS "; + "qemu-kvm -m 384 $netBackend $netFrontend \$QEMU_OPTS "; if (defined $args->{hda}) { if ($args->{hdaInterface} eq "scsi") { diff --git a/nixpkgs/nixos/modules/config/timezone.nix b/nixpkgs/nixos/modules/config/locale.nix index b15948f6e2e5..6f0565881877 100644 --- a/nixpkgs/nixos/modules/config/timezone.nix +++ b/nixpkgs/nixos/modules/config/locale.nix @@ -9,6 +9,8 @@ let timezone = types.nullOr (types.addCheck types.str nospace) // { description = "null or string without spaces"; }; + lcfg = config.location; + in { @@ -37,12 +39,45 @@ in }; }; + + location = { + + latitude = mkOption { + type = types.float; + description = '' + Your current latitude, between + <literal>-90.0</literal> and <literal>90.0</literal>. Must be provided + along with longitude. + ''; + }; + + longitude = mkOption { + type = types.float; + description = '' + Your current longitude, between + between <literal>-180.0</literal> and <literal>180.0</literal>. Must be + provided along with latitude. + ''; + }; + + provider = mkOption { + type = types.enum [ "manual" "geoclue2" ]; + default = "manual"; + description = '' + The location provider to use for determining your location. If set to + <literal>manual</literal> you must also provide latitude/longitude. + ''; + }; + + }; }; config = { environment.sessionVariables.TZDIR = "/etc/zoneinfo"; + services.geoclue2.enable = mkIf (lcfg.provider == "geoclue2") true; + # This way services are restarted when tzdata changes. systemd.globalEnvironment.TZDIR = tzdir; diff --git a/nixpkgs/nixos/modules/config/networking.nix b/nixpkgs/nixos/modules/config/networking.nix index eab4e73e19a1..4b9086022ed5 100644 --- a/nixpkgs/nixos/modules/config/networking.nix +++ b/nixpkgs/nixos/modules/config/networking.nix @@ -7,16 +7,6 @@ with lib; let cfg = config.networking; - dnsmasqResolve = config.services.dnsmasq.enable && - config.services.dnsmasq.resolveLocalQueries; - hasLocalResolver = config.services.bind.enable || - config.services.unbound.enable || - dnsmasqResolve; - - resolvconfOptions = cfg.resolvconfOptions - ++ optional cfg.dnsSingleRequest "single-request" - ++ optional cfg.dnsExtensionMechanism "edns0"; - localhostMapped4 = cfg.hosts ? "127.0.0.1" && elem "localhost" cfg.hosts."127.0.0.1"; localhostMapped6 = cfg.hosts ? "::1" && elem "localhost" cfg.hosts."::1"; @@ -64,48 +54,6 @@ in ''; }; - networking.dnsSingleRequest = lib.mkOption { - type = types.bool; - default = false; - description = '' - Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA) - address queries at the same time, from the same port. Sometimes upstream - routers will systemically drop the ipv4 queries. The symptom of this problem is - that 'getent hosts example.com' only returns ipv6 (or perhaps only ipv4) addresses. The - workaround for this is to specify the option 'single-request' in - /etc/resolv.conf. This option enables that. - ''; - }; - - networking.dnsExtensionMechanism = lib.mkOption { - type = types.bool; - default = true; - description = '' - Enable the <code>edns0</code> option in <filename>resolv.conf</filename>. With - that option set, <code>glibc</code> supports use of the extension mechanisms for - DNS (EDNS) specified in RFC 2671. The most popular user of that feature is DNSSEC, - which does not work without it. - ''; - }; - - networking.extraResolvconfConf = lib.mkOption { - type = types.lines; - default = ""; - example = "libc=NO"; - description = '' - Extra configuration to append to <filename>resolvconf.conf</filename>. - ''; - }; - - networking.resolvconfOptions = lib.mkOption { - type = types.listOf types.str; - default = []; - example = [ "ndots:1" "rotate" ]; - description = '' - Set the options in <filename>/etc/resolv.conf</filename>. - ''; - }; - networking.timeServers = mkOption { default = [ "0.nixos.pool.ntp.org" @@ -240,35 +188,6 @@ in # /etc/host.conf: resolver configuration file "host.conf".text = cfg.hostConf; - # /etc/resolvconf.conf: Configuration for openresolv. - "resolvconf.conf".text = - '' - # This is the default, but we must set it here to prevent - # a collision with an apparently unrelated environment - # variable with the same name exported by dhcpcd. - interface_order='lo lo[0-9]*' - '' + optionalString config.services.nscd.enable '' - # Invalidate the nscd cache whenever resolv.conf is - # regenerated. - libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service 2> /dev/null' - '' + optionalString (length resolvconfOptions > 0) '' - # Options as described in resolv.conf(5) - resolv_conf_options='${concatStringsSep " " resolvconfOptions}' - '' + optionalString hasLocalResolver '' - # This hosts runs a full-blown DNS resolver. - name_servers='127.0.0.1' - '' + optionalString dnsmasqResolve '' - dnsmasq_conf=/etc/dnsmasq-conf.conf - dnsmasq_resolv=/etc/dnsmasq-resolv.conf - '' + cfg.extraResolvconfConf + '' - ''; - - } // optionalAttrs config.services.resolved.enable { - # symlink the dynamic stub resolver of resolv.conf as recommended by upstream: - # https://www.freedesktop.org/software/systemd/man/systemd-resolved.html#/etc/resolv.conf - "resolv.conf".source = "/run/systemd/resolve/stub-resolv.conf"; - } // optionalAttrs (config.services.resolved.enable && dnsmasqResolve) { - "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf"; } // optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") { # /etc/rpc: RPC program numbers. "rpc".source = pkgs.glibc.out + "/etc/rpc"; @@ -295,29 +214,6 @@ in # Install the proxy environment variables environment.sessionVariables = cfg.proxy.envVars; - # This is needed when /etc/resolv.conf is being overriden by networkd - # and other configurations. If the file is destroyed by an environment - # activation then it must be rebuilt so that applications which interface - # with /etc/resolv.conf directly don't break. - system.activationScripts.resolvconf = stringAfter [ "etc" "specialfs" "var" ] - '' - # Systemd resolved controls its own resolv.conf - rm -f /run/resolvconf/interfaces/systemd - ${optionalString config.services.resolved.enable '' - rm -rf /run/resolvconf/interfaces - mkdir -p /run/resolvconf/interfaces - ln -s /run/systemd/resolve/resolv.conf /run/resolvconf/interfaces/systemd - ''} - - # Make sure resolv.conf is up to date if not managed manually, by systemd or - # by NetworkManager - ${optionalString (!config.environment.etc?"resolv.conf" && - (cfg.networkmanager.enable -> - cfg.networkmanager.rc-manager == "resolvconf")) '' - ${pkgs.openresolv}/bin/resolvconf -u - ''} - ''; - }; } diff --git a/nixpkgs/nixos/modules/config/no-x-libs.nix b/nixpkgs/nixos/modules/config/no-x-libs.nix index aad02a9ca4e3..74cf74d74181 100644 --- a/nixpkgs/nixos/modules/config/no-x-libs.nix +++ b/nixpkgs/nixos/modules/config/no-x-libs.nix @@ -34,7 +34,7 @@ with lib; networkmanager-openvpn = super.networkmanager-openvpn.override { withGnome = false; }; networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; }; networkmanager-iodine = super.networkmanager-iodine.override { withGnome = false; }; - pinentry = super.pinentry.override { gtk2 = null; gcr = null; qt = null; }; + pinentry = super.pinentry.override { gtk2 = null; gcr = null; qt4 = null; qt5 = null; }; gobject-introspection = super.gobject-introspection.override { x11Support = false; }; })); }; diff --git a/nixpkgs/nixos/modules/config/resolvconf.nix b/nixpkgs/nixos/modules/config/resolvconf.nix new file mode 100644 index 000000000000..406c6a7ac329 --- /dev/null +++ b/nixpkgs/nixos/modules/config/resolvconf.nix @@ -0,0 +1,149 @@ +# /etc files related to networking, such as /etc/services. + +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.networking.resolvconf; + + resolvconfOptions = cfg.extraOptions + ++ optional cfg.dnsSingleRequest "single-request" + ++ optional cfg.dnsExtensionMechanism "edns0"; + + configText = + '' + # This is the default, but we must set it here to prevent + # a collision with an apparently unrelated environment + # variable with the same name exported by dhcpcd. + interface_order='lo lo[0-9]*' + '' + optionalString config.services.nscd.enable '' + # Invalidate the nscd cache whenever resolv.conf is + # regenerated. + libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service 2> /dev/null' + '' + optionalString (length resolvconfOptions > 0) '' + # Options as described in resolv.conf(5) + resolv_conf_options='${concatStringsSep " " resolvconfOptions}' + '' + optionalString cfg.useLocalResolver '' + # This hosts runs a full-blown DNS resolver. + name_servers='127.0.0.1' + '' + cfg.extraConfig; + +in + +{ + + options = { + + networking.resolvconf = { + + enable = mkOption { + type = types.bool; + default = false; + internal = true; + description = '' + DNS configuration is managed by resolvconf. + ''; + }; + + useHostResolvConf = mkOption { + type = types.bool; + default = false; + description = '' + In containers, whether to use the + <filename>resolv.conf</filename> supplied by the host. + ''; + }; + + dnsSingleRequest = lib.mkOption { + type = types.bool; + default = false; + description = '' + Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA) + address queries at the same time, from the same port. Sometimes upstream + routers will systemically drop the ipv4 queries. The symptom of this problem is + that 'getent hosts example.com' only returns ipv6 (or perhaps only ipv4) addresses. The + workaround for this is to specify the option 'single-request' in + /etc/resolv.conf. This option enables that. + ''; + }; + + dnsExtensionMechanism = mkOption { + type = types.bool; + default = true; + description = '' + Enable the <code>edns0</code> option in <filename>resolv.conf</filename>. With + that option set, <code>glibc</code> supports use of the extension mechanisms for + DNS (EDNS) specified in RFC 2671. The most popular user of that feature is DNSSEC, + which does not work without it. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = "libc=NO"; + description = '' + Extra configuration to append to <filename>resolvconf.conf</filename>. + ''; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = []; + example = [ "ndots:1" "rotate" ]; + description = '' + Set the options in <filename>/etc/resolv.conf</filename>. + ''; + }; + + useLocalResolver = mkOption { + type = types.bool; + default = false; + description = '' + Use local DNS server for resolving. + ''; + }; + + }; + + }; + + config = mkMerge [ + { + networking.resolvconf.enable = !(config.environment.etc ? "resolv.conf"); + + environment.etc."resolvconf.conf".text = + if !cfg.enable then + # Force-stop any attempts to use resolvconf + '' + echo "resolvconf is disabled on this system but was used anyway:" >&2 + echo "$0 $*" >&2 + exit 1 + '' + else configText; + } + + (mkIf cfg.enable { + environment.systemPackages = [ pkgs.openresolv ]; + + systemd.services.resolvconf = { + description = "resolvconf update"; + + before = [ "network-pre.target" ]; + wants = [ "network-pre.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ config.environment.etc."resolvconf.conf".source ]; + + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.openresolv}/bin/resolvconf -u"; + RemainAfterExit = true; + }; + }; + + }) + ]; + +} diff --git a/nixpkgs/nixos/modules/config/xdg/portal.nix b/nixpkgs/nixos/modules/config/xdg/portal.nix new file mode 100644 index 000000000000..bdbbfda2bb42 --- /dev/null +++ b/nixpkgs/nixos/modules/config/xdg/portal.nix @@ -0,0 +1,58 @@ +{ config, pkgs ,lib ,... }: + +with lib; + +{ + options.xdg.portal = { + enable = + mkEnableOption "<link xlink:href='https://github.com/flatpak/xdg-desktop-portal'>xdg desktop integration</link>"//{ + default = false; + }; + + extraPortals = mkOption { + type = types.listOf types.package; + default = []; + description = '' + List of additional portals to add to path. Portals allow interaction + with system, like choosing files or taking screenshots. At minimum, + a desktop portal implementation should be listed. GNOME and KDE already + adds <package>xdg-desktop-portal-gtk</package>; and + <package>xdg-desktop-portal-kde</package> respectively. On other desktop + environments you probably want to add them yourself. + ''; + }; + + gtkUsePortal = mkOption { + type = types.bool; + default = false; + description = '' + Sets environment variable <literal>GTK_USE_PORTAL</literal> to <literal>1</literal>. + This is needed for packages ran outside Flatpak to respect and use XDG Desktop Portals. + For example, you'd need to set this for non-flatpak Firefox to use native filechoosers. + Defaults to <literal>false</literal> to respect its opt-in nature. + ''; + }; + }; + + config = + let + cfg = config.xdg.portal; + packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals; + + in mkIf cfg.enable { + + assertions = [ + { assertion = (cfg.gtkUsePortal -> cfg.extraPortals != []); + message = "Setting xdg.portal.gtkUsePortal to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde."; + } + ]; + + services.dbus.packages = packages; + systemd.packages = packages; + + environment.variables = { + GTK_USE_PORTAL = mkIf cfg.gtkUsePortal "1"; + XDG_DESKTOP_PORTAL_PATH = map (p: "${p}/share/xdg-desktop-portal/portals") cfg.extraPortals; + }; + }; +} diff --git a/nixpkgs/nixos/modules/hardware/opengl.nix b/nixpkgs/nixos/modules/hardware/opengl.nix index 2defab51bc3a..57cac56bd8ab 100644 --- a/nixpkgs/nixos/modules/hardware/opengl.nix +++ b/nixpkgs/nixos/modules/hardware/opengl.nix @@ -118,6 +118,19 @@ in set. This can be used to add OpenCL drivers, VA-API/VDPAU drivers etc. ''; }; + + setLdLibraryPath = mkOption { + type = types.bool; + internal = true; + default = false; + description = '' + Whether the <literal>LD_LIBRARY_PATH</literal> environment variable + should be set to the locations of driver libraries. Drivers which + rely on overriding libraries should set this to true. Drivers which + support <literal>libglvnd</literal> and other dispatch libraries + instead of overriding libraries should not set this. + ''; + }; }; }; @@ -145,11 +158,8 @@ in ) ]; - environment.sessionVariables.LD_LIBRARY_PATH = - [ "/run/opengl-driver/lib" ] ++ optional cfg.driSupport32Bit "/run/opengl-driver-32/lib"; - - environment.variables.XDG_DATA_DIRS = - [ "/run/opengl-driver/share" ] ++ optional cfg.driSupport32Bit "/run/opengl-driver-32/share"; + environment.sessionVariables.LD_LIBRARY_PATH = mkIf cfg.setLdLibraryPath + ([ "/run/opengl-driver/lib" ] ++ optional cfg.driSupport32Bit "/run/opengl-driver-32/lib"); hardware.opengl.package = mkDefault (makePackage pkgs); hardware.opengl.package32 = mkDefault (makePackage pkgs.pkgsi686Linux); diff --git a/nixpkgs/nixos/modules/hardware/video/amdgpu-pro.nix b/nixpkgs/nixos/modules/hardware/video/amdgpu-pro.nix index ab9e0c92020e..8e91e9d2baa9 100644 --- a/nixpkgs/nixos/modules/hardware/video/amdgpu-pro.nix +++ b/nixpkgs/nixos/modules/hardware/video/amdgpu-pro.nix @@ -30,10 +30,11 @@ in nixpkgs.config.xorg.abiCompat = "1.19"; services.xserver.drivers = singleton - { name = "amdgpu"; modules = [ package ]; libPath = [ package ]; }; + { name = "amdgpu"; modules = [ package ]; }; hardware.opengl.package = package; hardware.opengl.package32 = package32; + hardware.opengl.setLdLibraryPath = true; boot.extraModulePackages = [ package ]; diff --git a/nixpkgs/nixos/modules/hardware/video/ati.nix b/nixpkgs/nixos/modules/hardware/video/ati.nix index 6102919f0155..f867bba80630 100644 --- a/nixpkgs/nixos/modules/hardware/video/ati.nix +++ b/nixpkgs/nixos/modules/hardware/video/ati.nix @@ -21,10 +21,11 @@ in nixpkgs.config.xorg.abiCompat = "1.17"; services.xserver.drivers = singleton - { name = "fglrx"; modules = [ ati_x11 ]; libPath = [ "${ati_x11}/lib" ]; }; + { name = "fglrx"; modules = [ ati_x11 ]; }; hardware.opengl.package = ati_x11; hardware.opengl.package32 = pkgs.pkgsi686Linux.linuxPackages.ati_drivers_x11.override { libsOnly = true; kernel = null; }; + hardware.opengl.setLdLibraryPath = true; environment.systemPackages = [ ati_x11 ]; diff --git a/nixpkgs/nixos/modules/hardware/video/nvidia.nix b/nixpkgs/nixos/modules/hardware/video/nvidia.nix index a5740929a310..da3c8ee5a9fa 100644 --- a/nixpkgs/nixos/modules/hardware/video/nvidia.nix +++ b/nixpkgs/nixos/modules/hardware/video/nvidia.nix @@ -138,7 +138,6 @@ in services.xserver.drivers = singleton { name = "nvidia"; modules = [ nvidia_x11.bin ]; - libPath = [ nvidia_x11 ]; deviceSection = optionalString optimusCfg.enable '' BusID "${optimusCfg.nvidiaBusId}" diff --git a/nixpkgs/nixos/modules/i18n/input-method/ibus.nix b/nixpkgs/nixos/modules/i18n/input-method/ibus.nix index f8e021f551e8..8109ef76c402 100644 --- a/nixpkgs/nixos/modules/i18n/input-method/ibus.nix +++ b/nixpkgs/nixos/modules/i18n/input-method/ibus.nix @@ -55,7 +55,7 @@ in # Without dconf enabled it is impossible to use IBus environment.systemPackages = with pkgs; [ - ibus-qt gnome3.dconf ibusAutostart + gnome3.dconf ibusAutostart ]; environment.variables = { diff --git a/nixpkgs/nixos/modules/installer/netboot/netboot.nix b/nixpkgs/nixos/modules/installer/netboot/netboot.nix index cdfba5ab9e31..f9b8d95c684d 100644 --- a/nixpkgs/nixos/modules/installer/netboot/netboot.nix +++ b/nixpkgs/nixos/modules/installer/netboot/netboot.nix @@ -84,7 +84,7 @@ with lib; system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" '' #!ipxe - kernel ${pkgs.stdenv.hostPlatform.platform.kernelTarget} init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} + kernel ${pkgs.stdenv.hostPlatform.platform.kernelTarget} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} initrd initrd boot ''; diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl index c09def1fceae..cfdbdaabf5c5 100644 --- a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl @@ -607,90 +607,7 @@ EOF } write_file($fn, <<EOF); -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running ‘nixos-help’). - -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - -$bootLoaderConfig - # networking.hostName = "nixos"; # Define your hostname. - # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. - - # Configure network proxy if necessary - # networking.proxy.default = "http://user:password\@proxy:port/"; - # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; - - # Select internationalisation properties. - # i18n = { - # consoleFont = "Lat2-Terminus16"; - # consoleKeyMap = "us"; - # defaultLocale = "en_US.UTF-8"; - # }; - - # Set your time zone. - # time.timeZone = "Europe/Amsterdam"; - - # List packages installed in system profile. To search, run: - # \$ nix search wget - # environment.systemPackages = with pkgs; [ - # wget vim - # ]; - - # Some programs need SUID wrappers, can be configured further or are - # started in user sessions. - # programs.mtr.enable = true; - # programs.gnupg.agent = { enable = true; enableSSHSupport = true; }; - - # List services that you want to enable: - - # Enable the OpenSSH daemon. - # services.openssh.enable = true; - - # Open ports in the firewall. - # networking.firewall.allowedTCPPorts = [ ... ]; - # networking.firewall.allowedUDPPorts = [ ... ]; - # Or disable the firewall altogether. - # networking.firewall.enable = false; - - # Enable CUPS to print documents. - # services.printing.enable = true; - - # Enable sound. - # sound.enable = true; - # hardware.pulseaudio.enable = true; - - # Enable the X11 windowing system. - # services.xserver.enable = true; - # services.xserver.layout = "us"; - # services.xserver.xkbOptions = "eurosign:e"; - - # Enable touchpad support. - # services.xserver.libinput.enable = true; - - # Enable the KDE Desktop Environment. - # services.xserver.displayManager.sddm.enable = true; - # services.xserver.desktopManager.plasma5.enable = true; - - # Define a user account. Don't forget to set a password with ‘passwd’. - # users.users.jane = { - # isNormalUser = true; - # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. - # }; - - # This value determines the NixOS release with which your system is to be - # compatible, in order to avoid breaking some software such as database - # servers. You should change this only after NixOS release notes say you - # should. - system.stateVersion = "${\(qw(@release@))}"; # Did you read the comment? - -} +@configuration@ EOF } else { print STDERR "warning: not overwriting existing $fn\n"; diff --git a/nixpkgs/nixos/modules/installer/tools/tools.nix b/nixpkgs/nixos/modules/installer/tools/tools.nix index 59eb4a63af40..05add59117d1 100644 --- a/nixpkgs/nixos/modules/installer/tools/tools.nix +++ b/nixpkgs/nixos/modules/installer/tools/tools.nix @@ -38,7 +38,7 @@ let src = ./nixos-generate-config.pl; path = lib.optionals (lib.elem "btrfs" config.boot.supportedFilesystems) [ pkgs.btrfs-progs ]; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/${pkgs.perl.libPrefix}"; - inherit (config.system.nixos) release; + inherit (config.system.nixos-generate-config) configuration; }; nixos-option = makeProg { @@ -61,8 +61,111 @@ in { + options.system.nixos-generate-config.configuration = mkOption { + internal = true; + type = types.str; + description = '' + The NixOS module that <literal>nixos-generate-config</literal> + saves to <literal>/etc/nixos/configuration.nix</literal>. + + This is an internal option. No backward compatibility is guaranteed. + Use at your own risk! + + Note that this string gets spliced into a Perl script. The perl + variable <literal>$bootLoaderConfig</literal> can be used to + splice in the boot loader configuration. + ''; + }; + config = { + system.nixos-generate-config.configuration = mkDefault '' + # Edit this configuration file to define what should be installed on + # your system. Help is available in the configuration.nix(5) man page + # and in the NixOS manual (accessible by running ‘nixos-help’). + + { config, pkgs, ... }: + + { + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + $bootLoaderConfig + # networking.hostName = "nixos"; # Define your hostname. + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password\@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Select internationalisation properties. + # i18n = { + # consoleFont = "Lat2-Terminus16"; + # consoleKeyMap = "us"; + # defaultLocale = "en_US.UTF-8"; + # }; + + # Set your time zone. + # time.timeZone = "Europe/Amsterdam"; + + # List packages installed in system profile. To search, run: + # \$ nix search wget + # environment.systemPackages = with pkgs; [ + # wget vim + # ]; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + # programs.gnupg.agent = { enable = true; enableSSHSupport = true; }; + + # List services that you want to enable: + + # Enable the OpenSSH daemon. + # services.openssh.enable = true; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # Enable CUPS to print documents. + # services.printing.enable = true; + + # Enable sound. + # sound.enable = true; + # hardware.pulseaudio.enable = true; + + # Enable the X11 windowing system. + # services.xserver.enable = true; + # services.xserver.layout = "us"; + # services.xserver.xkbOptions = "eurosign:e"; + + # Enable touchpad support. + # services.xserver.libinput.enable = true; + + # Enable the KDE Desktop Environment. + # services.xserver.displayManager.sddm.enable = true; + # services.xserver.desktopManager.plasma5.enable = true; + + # Define a user account. Don't forget to set a password with ‘passwd’. + # users.users.jane = { + # isNormalUser = true; + # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + # }; + + # This value determines the NixOS release with which your system is to be + # compatible, in order to avoid breaking some software such as database + # servers. You should change this only after NixOS release notes say you + # should. + system.stateVersion = "${config.system.nixos.release}"; # Did you read the comment? + + } + ''; + environment.systemPackages = [ nixos-build-vms nixos-install diff --git a/nixpkgs/nixos/modules/misc/ids.nix b/nixpkgs/nixos/modules/misc/ids.nix index 08f7b827948d..d7599a1e2b7a 100644 --- a/nixpkgs/nixos/modules/misc/ids.nix +++ b/nixpkgs/nixos/modules/misc/ids.nix @@ -516,7 +516,7 @@ tss = 176; #memcached = 177; # unused, removed 2018-01-03 #ntp = 179; # unused - #zabbix = 180; # unused + zabbix = 180; #redis = 181; # unused, removed 2018-01-03 #unifi = 183; # unused #uptimed = 184; # unused diff --git a/nixpkgs/nixos/modules/misc/nixpkgs.nix b/nixpkgs/nixos/modules/misc/nixpkgs.nix index e0c192246c0c..afb74581e239 100644 --- a/nixpkgs/nixos/modules/misc/nixpkgs.nix +++ b/nixpkgs/nixos/modules/misc/nixpkgs.nix @@ -19,7 +19,7 @@ let lhs = optCall lhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; }; in - lhs // rhs // + recursiveUpdate lhs rhs // optionalAttrs (lhs ? packageOverrides) { packageOverrides = pkgs: optCall lhs.packageOverrides pkgs // diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix index 1c4cf4da4097..b077deb332c2 100644 --- a/nixpkgs/nixos/modules/module-list.nix +++ b/nixpkgs/nixos/modules/module-list.nix @@ -11,6 +11,7 @@ ./config/xdg/icons.nix ./config/xdg/menus.nix ./config/xdg/mime.nix + ./config/xdg/portal.nix ./config/appstream.nix ./config/xdg/sounds.nix ./config/gtk/gtk-icon-cache.nix @@ -19,19 +20,20 @@ ./config/iproute2.nix ./config/krb5/default.nix ./config/ldap.nix + ./config/locale.nix ./config/malloc.nix ./config/networking.nix ./config/no-x-libs.nix ./config/nsswitch.nix ./config/power-management.nix ./config/pulseaudio.nix + ./config/resolvconf.nix ./config/shells-environment.nix ./config/swap.nix ./config/sysctl.nix ./config/system-environment.nix ./config/system-path.nix ./config/terminfo.nix - ./config/timezone.nix ./config/unix-odbc-drivers.nix ./config/users-groups.nix ./config/vpnc.nix @@ -104,9 +106,14 @@ ./programs/digitalbitbox/default.nix ./programs/dmrconfig.nix ./programs/environment.nix + ./programs/evince.nix + ./programs/file-roller.nix ./programs/firejail.nix ./programs/fish.nix ./programs/freetds.nix + ./programs/gnome-disks.nix + ./programs/gnome-documents.nix + ./programs/gpaste.nix ./programs/gnupg.nix ./programs/gphoto2.nix ./programs/iftop.nix @@ -138,6 +145,7 @@ ./programs/sway.nix ./programs/thefuck.nix ./programs/tmux.nix + ./programs/tsm-client.nix ./programs/udevil.nix ./programs/venus.nix ./programs/vim.nix @@ -195,6 +203,7 @@ ./services/audio/slimserver.nix ./services/audio/snapserver.nix ./services/audio/squeezelite.nix + ./services/audio/spotifyd.nix ./services/audio/ympd.nix ./services/backup/automysqlbackup.nix ./services/backup/bacula.nix @@ -205,10 +214,12 @@ ./services/backup/duplicity.nix ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix + ./services/backup/postgresql-wal-receiver.nix ./services/backup/restic.nix ./services/backup/restic-rest-server.nix ./services/backup/rsnapshot.nix ./services/backup/tarsnap.nix + ./services/backup/tsm.nix ./services/backup/znapzend.nix ./services/cluster/hadoop/default.nix ./services/cluster/kubernetes/addons/dns.nix @@ -275,12 +286,8 @@ ./services/desktops/pipewire.nix ./services/desktops/gnome3/at-spi2-core.nix ./services/desktops/gnome3/chrome-gnome-shell.nix - ./services/desktops/gnome3/evince.nix ./services/desktops/gnome3/evolution-data-server.nix - ./services/desktops/gnome3/file-roller.nix ./services/desktops/gnome3/glib-networking.nix - ./services/desktops/gnome3/gnome-disks.nix - ./services/desktops/gnome3/gnome-documents.nix ./services/desktops/gnome3/gnome-keyring.nix ./services/desktops/gnome3/gnome-online-accounts.nix ./services/desktops/gnome3/gnome-remote-desktop.nix @@ -288,7 +295,6 @@ ./services/desktops/gnome3/gnome-settings-daemon.nix ./services/desktops/gnome3/gnome-terminal-server.nix ./services/desktops/gnome3/gnome-user-share.nix - ./services/desktops/gnome3/gpaste.nix ./services/desktops/gnome3/gvfs.nix ./services/desktops/gnome3/rygel.nix ./services/desktops/gnome3/seahorse.nix @@ -398,6 +404,7 @@ ./services/misc/couchpotato.nix ./services/misc/devmon.nix ./services/misc/dictd.nix + ./services/misc/dwm-status.nix ./services/misc/dysnomia.nix ./services/misc/disnix.nix ./services/misc/docker-registry.nix @@ -419,6 +426,7 @@ ./services/misc/gollum.nix ./services/misc/gpsd.nix ./services/misc/headphones.nix + ./services/misc/greenclip.nix ./services/misc/home-assistant.nix ./services/misc/ihaskell.nix ./services/misc/irkerd.nix @@ -470,6 +478,7 @@ ./services/misc/synergy.nix ./services/misc/sysprof.nix ./services/misc/taskserver + ./services/misc/tiddlywiki.nix ./services/misc/tzupdate.nix ./services/misc/uhub.nix ./services/misc/weechat.nix @@ -513,10 +522,12 @@ ./services/monitoring/systemhealth.nix ./services/monitoring/teamviewer.nix ./services/monitoring/telegraf.nix + ./services/monitoring/thanos.nix ./services/monitoring/ups.nix ./services/monitoring/uptime.nix ./services/monitoring/vnstat.nix ./services/monitoring/zabbix-agent.nix + ./services/monitoring/zabbix-proxy.nix ./services/monitoring/zabbix-server.nix ./services/network-filesystems/beegfs.nix ./services/network-filesystems/cachefilesd.nix @@ -686,6 +697,7 @@ ./services/networking/tcpcrypt.nix ./services/networking/teamspeak3.nix ./services/networking/tedicross.nix + ./services/networking/thelounge.nix ./services/networking/tinc.nix ./services/networking/tinydns.nix ./services/networking/tftpd.nix @@ -772,6 +784,7 @@ ./services/web-apps/icingaweb2/module-monitoring.nix ./services/web-apps/limesurvey.nix ./services/web-apps/mattermost.nix + ./services/web-apps/mediawiki.nix ./services/web-apps/miniflux.nix ./services/web-apps/nextcloud.nix ./services/web-apps/nexus.nix @@ -783,6 +796,7 @@ ./services/web-apps/virtlyst.nix ./services/web-apps/wordpress.nix ./services/web-apps/youtrack.nix + ./services/web-apps/zabbix.nix ./services/web-servers/apache-httpd/default.nix ./services/web-servers/caddy.nix ./services/web-servers/fcgiwrap.nix @@ -806,6 +820,8 @@ ./services/web-servers/uwsgi.nix ./services/web-servers/varnish/default.nix ./services/web-servers/zope2.nix + ./services/x11/extra-layouts.nix + ./services/x11/clight.nix ./services/x11/colord.nix ./services/x11/compton.nix ./services/x11/unclutter.nix diff --git a/nixpkgs/nixos/modules/profiles/hardened.nix b/nixpkgs/nixos/modules/profiles/hardened.nix index 97279a78a57b..9e9ddd4f3788 100644 --- a/nixpkgs/nixos/modules/profiles/hardened.nix +++ b/nixpkgs/nixos/modules/profiles/hardened.nix @@ -26,7 +26,9 @@ with lib; security.allowSimultaneousMultithreading = mkDefault false; - security.virtualization.flushL1DataCache = mkDefault "always"; + security.forcePageTableIsolation = mkDefault true; + + security.virtualisation.flushL1DataCache = mkDefault "always"; security.apparmor.enable = mkDefault true; @@ -42,9 +44,6 @@ with lib; # Disable legacy virtual syscalls "vsyscall=none" - - # Enable PTI even if CPU claims to be safe from meltdown - "pti=on" ]; boot.blacklistedKernelModules = [ diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/evince.nix b/nixpkgs/nixos/modules/programs/evince.nix index 5f040a16f067..473fddb09d02 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome3/evince.nix +++ b/nixpkgs/nixos/modules/programs/evince.nix @@ -6,14 +6,21 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "evince" "enable" ] + [ "programs" "evince" "enable" ]) + ]; + ###### interface options = { - services.gnome3.evince = { + programs.evince = { enable = mkEnableOption - "systemd and dbus services for Evince, the GNOME document viewer"; + "Evince, the GNOME document viewer"; }; @@ -22,7 +29,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.evince.enable { + config = mkIf config.programs.evince.enable { environment.systemPackages = [ pkgs.evince ]; diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/file-roller.nix b/nixpkgs/nixos/modules/programs/file-roller.nix index 7fb558a98953..64f6a94e7641 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome3/file-roller.nix +++ b/nixpkgs/nixos/modules/programs/file-roller.nix @@ -6,11 +6,18 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "file-roller" "enable" ] + [ "programs" "file-roller" "enable" ]) + ]; + ###### interface options = { - services.gnome3.file-roller = { + programs.file-roller = { enable = mkEnableOption "File Roller, an archive manager for GNOME"; @@ -21,7 +28,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.file-roller.enable { + config = mkIf config.programs.file-roller.enable { environment.systemPackages = [ pkgs.gnome3.file-roller ]; diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-disks.nix b/nixpkgs/nixos/modules/programs/gnome-disks.nix index 139534cdb892..1cf839a6ddb0 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-disks.nix +++ b/nixpkgs/nixos/modules/programs/gnome-disks.nix @@ -1,4 +1,4 @@ -# GNOME Disks daemon. +# GNOME Disks. { config, pkgs, lib, ... }: @@ -6,17 +6,24 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "gnome-disks" "enable" ] + [ "programs" "gnome-disks" "enable" ]) + ]; + ###### interface options = { - services.gnome3.gnome-disks = { + programs.gnome-disks = { enable = mkOption { type = types.bool; default = false; description = '' - Whether to enable GNOME Disks daemon, a service designed to + Whether to enable GNOME Disks daemon, a program designed to be a UDisks2 graphical front-end. ''; }; @@ -28,7 +35,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.gnome-disks.enable { + config = mkIf config.programs.gnome-disks.enable { environment.systemPackages = [ pkgs.gnome3.gnome-disk-utility ]; diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-documents.nix b/nixpkgs/nixos/modules/programs/gnome-documents.nix index f6efb6684240..bfa3d409ee30 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-documents.nix +++ b/nixpkgs/nixos/modules/programs/gnome-documents.nix @@ -1,4 +1,4 @@ -# GNOME Documents daemon. +# GNOME Documents. { config, pkgs, lib, ... }: @@ -6,17 +6,24 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "gnome-documents" "enable" ] + [ "programs" "gnome-documents" "enable" ]) + ]; + ###### interface options = { - services.gnome3.gnome-documents = { + programs.gnome-documents = { enable = mkOption { type = types.bool; default = false; description = '' - Whether to enable GNOME Documents services, a document + Whether to enable GNOME Documents, a document manager application for GNOME. ''; }; @@ -28,7 +35,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.gnome-documents.enable { + config = mkIf config.programs.gnome-documents.enable { environment.systemPackages = [ pkgs.gnome3.gnome-documents ]; diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/gpaste.nix b/nixpkgs/nixos/modules/programs/gpaste.nix index 5a8258775e0a..4f6deb77e5eb 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome3/gpaste.nix +++ b/nixpkgs/nixos/modules/programs/gpaste.nix @@ -1,12 +1,20 @@ -# GPaste daemon. +# GPaste. { config, lib, pkgs, ... }: with lib; { + + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "gpaste" "enable" ] + [ "programs" "gpaste" "enable" ]) + ]; + ###### interface options = { - services.gnome3.gpaste = { + programs.gpaste = { enable = mkOption { type = types.bool; default = false; @@ -18,10 +26,9 @@ with lib; }; ###### implementation - config = mkIf config.services.gnome3.gpaste.enable { + config = mkIf config.programs.gpaste.enable { environment.systemPackages = [ pkgs.gnome3.gpaste ]; services.dbus.packages = [ pkgs.gnome3.gpaste ]; - services.xserver.desktopManager.gnome3.sessionPath = [ pkgs.gnome3.gpaste ]; systemd.packages = [ pkgs.gnome3.gpaste ]; }; } diff --git a/nixpkgs/nixos/modules/programs/nylas-mail.nix b/nixpkgs/nixos/modules/programs/nylas-mail.nix deleted file mode 100644 index 08a6cd0a6049..000000000000 --- a/nixpkgs/nixos/modules/programs/nylas-mail.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.nylas-mail; -in { - ###### interface - options = { - services.nylas-mail = { - - enable = mkEnableOption '' - nylas-mail - Open-source mail client built on the modern web with Electron, React, and Flux - ''; - - gnome3-keyring = mkOption { - type = types.bool; - default = true; - description = "Enable gnome3 keyring for nylas-mail."; - }; - }; - }; - - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ pkgs.nylas-mail-bin ]; - - services.gnome3.gnome-keyring = mkIf cfg.gnome3-keyring { - enable = true; - }; - - }; -} diff --git a/nixpkgs/nixos/modules/programs/shell.nix b/nixpkgs/nixos/modules/programs/shell.nix index 9842e2bef643..b7f7b91b5fbe 100644 --- a/nixpkgs/nixos/modules/programs/shell.nix +++ b/nixpkgs/nixos/modules/programs/shell.nix @@ -12,7 +12,7 @@ with lib; '' # Set up the per-user profile. mkdir -m 0755 -p "$NIX_USER_PROFILE_DIR" - if [ "$(stat --printf '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then + if [ "$(stat -c '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then echo "WARNING: the per-user profile dir $NIX_USER_PROFILE_DIR should belong to user id $(id -u)" >&2 fi @@ -34,7 +34,7 @@ with lib; # Create the per-user garbage collector roots directory. NIX_USER_GCROOTS_DIR="/nix/var/nix/gcroots/per-user/$USER" mkdir -m 0755 -p "$NIX_USER_GCROOTS_DIR" - if [ "$(stat --printf '%u' "$NIX_USER_GCROOTS_DIR")" != "$(id -u)" ]; then + if [ "$(stat -c '%u' "$NIX_USER_GCROOTS_DIR")" != "$(id -u)" ]; then echo "WARNING: the per-user gcroots dir $NIX_USER_GCROOTS_DIR should belong to user id $(id -u)" >&2 fi diff --git a/nixpkgs/nixos/modules/programs/ssh.nix b/nixpkgs/nixos/modules/programs/ssh.nix index 46965dd35b71..733b8f7636fd 100644 --- a/nixpkgs/nixos/modules/programs/ssh.nix +++ b/nixpkgs/nixos/modules/programs/ssh.nix @@ -21,7 +21,7 @@ let knownHostsText = (flip (concatMapStringsSep "\n") knownHosts (h: assert h.hostNames != []; - concatStringsSep "," h.hostNames + " " + optionalString h.certAuthority "@cert-authority " + concatStringsSep "," h.hostNames + " " + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) )) + "\n"; @@ -128,6 +128,14 @@ in default = {}; type = types.loaOf (types.submodule ({ name, ... }: { options = { + certAuthority = mkOption { + type = types.bool; + default = false; + description = '' + This public key is an SSH certificate authority, rather than an + individual host's key. + ''; + }; hostNames = mkOption { type = types.listOf types.str; default = []; @@ -227,6 +235,7 @@ in systemd.user.services.ssh-agent = mkIf cfg.startAgent { description = "SSH Agent"; wantedBy = [ "default.target" ]; + unitConfig.ConditionUser = "!@system"; serviceConfig = { ExecStartPre = "${pkgs.coreutils}/bin/rm -f %t/ssh-agent"; ExecStart = diff --git a/nixpkgs/nixos/modules/programs/tsm-client.nix b/nixpkgs/nixos/modules/programs/tsm-client.nix new file mode 100644 index 000000000000..eb6f12475286 --- /dev/null +++ b/nixpkgs/nixos/modules/programs/tsm-client.nix @@ -0,0 +1,287 @@ +{ config, lib, pkgs, ... }: + +let + + inherit (builtins) length map; + inherit (lib.attrsets) attrNames filterAttrs hasAttr mapAttrs mapAttrsToList optionalAttrs; + inherit (lib.modules) mkDefault mkIf; + inherit (lib.options) literalExample mkEnableOption mkOption; + inherit (lib.strings) concatStringsSep optionalString toLower; + inherit (lib.types) addCheck attrsOf lines loaOf nullOr package path port str strMatching submodule; + + # Checks if given list of strings contains unique + # elements when compared without considering case. + # Type: checkIUnique :: [string] -> bool + # Example: checkIUnique ["foo" "Foo"] => false + checkIUnique = lst: + let + lenUniq = l: length (lib.lists.unique l); + in + lenUniq lst == lenUniq (map toLower lst); + + # TSM rejects servername strings longer than 64 chars. + servernameType = strMatching ".{1,64}"; + + serverOptions = { name, config, ... }: { + options.name = mkOption { + type = servernameType; + example = "mainTsmServer"; + description = '' + Local name of the IBM TSM server, + must be uncapitalized and no longer than 64 chars. + The value will be used for the + <literal>server</literal> + directive in <filename>dsm.sys</filename>. + ''; + }; + options.server = mkOption { + type = strMatching ".+"; + example = "tsmserver.company.com"; + description = '' + Host/domain name or IP address of the IBM TSM server. + The value will be used for the + <literal>tcpserveraddress</literal> + directive in <filename>dsm.sys</filename>. + ''; + }; + options.port = mkOption { + type = addCheck port (p: p<=32767); + default = 1500; # official default + description = '' + TCP port of the IBM TSM server. + The value will be used for the + <literal>tcpport</literal> + directive in <filename>dsm.sys</filename>. + TSM does not support ports above 32767. + ''; + }; + options.node = mkOption { + type = strMatching ".+"; + example = "MY-TSM-NODE"; + description = '' + Target node name on the IBM TSM server. + The value will be used for the + <literal>nodename</literal> + directive in <filename>dsm.sys</filename>. + ''; + }; + options.genPasswd = mkEnableOption '' + automatic client password generation. + This option influences the + <literal>passwordaccess</literal> + directive in <filename>dsm.sys</filename>. + The password will be stored in the directory + given by the option <option>passwdDir</option>. + <emphasis>Caution</emphasis>: + If this option is enabled and the server forces + to renew the password (e.g. on first connection), + a random password will be generated and stored + ''; + options.passwdDir = mkOption { + type = path; + example = "/home/alice/tsm-password"; + description = '' + Directory that holds the TSM + node's password information. + The value will be used for the + <literal>passworddir</literal> + directive in <filename>dsm.sys</filename>. + ''; + }; + options.includeExclude = mkOption { + type = lines; + default = ""; + example = '' + exclude.dir /nix/store + include.encrypt /home/.../* + ''; + description = '' + <literal>include.*</literal> and + <literal>exclude.*</literal> directives to be + used when sending files to the IBM TSM server. + The lines will be written into a file that the + <literal>inclexcl</literal> + directive in <filename>dsm.sys</filename> points to. + ''; + }; + options.extraConfig = mkOption { + # TSM option keys are case insensitive; + # we have to ensure there are no keys that + # differ only by upper and lower case. + type = addCheck + (attrsOf (nullOr str)) + (attrs: checkIUnique (attrNames attrs)); + default = {}; + example.compression = "yes"; + example.passwordaccess = null; + description = '' + Additional key-value pairs for the server stanza. + Values must be strings, or <literal>null</literal> + for the key not to be used in the stanza + (e.g. to overrule values generated by other options). + ''; + }; + options.text = mkOption { + type = lines; + example = literalExample + ''lib.modules.mkAfter "compression no"''; + description = '' + Additional text lines for the server stanza. + This option can be used if certion configuration keys + must be used multiple times or ordered in a certain way + as the <option>extraConfig</option> option can't + control the order of lines in the resulting stanza. + Note that the <literal>server</literal> + line at the beginning of the stanza is + not part of this option's value. + ''; + }; + options.stanza = mkOption { + type = str; + internal = true; + visible = false; + description = "Server stanza text generated from the options."; + }; + config.name = mkDefault name; + # Client system-options file directives are explained here: + # https://www.ibm.com/support/knowledgecenter/SSEQVQ_8.1.8/client/c_opt_usingopts.html + config.extraConfig = + mapAttrs (lib.trivial.const mkDefault) ( + { + commmethod = "v6tcpip"; # uses v4 or v6, based on dns lookup result + tcpserveraddress = config.server; + tcpport = builtins.toString config.port; + nodename = config.node; + passwordaccess = if config.genPasswd then "generate" else "prompt"; + passworddir = ''"${config.passwdDir}"''; + } // optionalAttrs (config.includeExclude!="") { + inclexcl = ''"${pkgs.writeText "inclexcl.dsm.sys" config.includeExclude}"''; + } + ); + config.text = + let + attrset = filterAttrs (k: v: v!=null) config.extraConfig; + mkLine = k: v: k + optionalString (v!="") " ${v}"; + lines = mapAttrsToList mkLine attrset; + in + concatStringsSep "\n" lines; + config.stanza = '' + server ${config.name} + ${config.text} + ''; + }; + + options.programs.tsmClient = { + enable = mkEnableOption '' + IBM Spectrum Protect (Tivoli Storage Manager, TSM) + client command line applications with a + client system-options file "dsm.sys" + ''; + servers = mkOption { + type = loaOf (submodule [ serverOptions ]); + default = {}; + example.mainTsmServer = { + server = "tsmserver.company.com"; + node = "MY-TSM-NODE"; + extraConfig.compression = "yes"; + }; + description = '' + Server definitions ("stanzas") + for the client system-options file. + ''; + }; + defaultServername = mkOption { + type = nullOr servernameType; + default = null; + example = "mainTsmServer"; + description = '' + If multiple server stanzas are declared with + <option>programs.tsmClient.servers</option>, + this option may be used to name a default + server stanza that IBM TSM uses in the absence of + a user-defined <filename>dsm.opt</filename> file. + This option translates to a + <literal>defaultserver</literal> configuration line. + ''; + }; + dsmSysText = mkOption { + type = lines; + readOnly = true; + description = '' + This configuration key contains the effective text + of the client system-options file "dsm.sys". + It should not be changed, but may be + used to feed the configuration into other + TSM-depending packages used on the system. + ''; + }; + package = mkOption { + type = package; + default = pkgs.tsm-client; + defaultText = "pkgs.tsm-client"; + example = literalExample "pkgs.tsm-client-withGui"; + description = '' + The TSM client derivation to be + added to the system environment. + It will called with <literal>.override</literal> + to add paths to the client system-options file. + ''; + }; + wrappedPackage = mkOption { + type = package; + readOnly = true; + description = '' + The TSM client derivation, wrapped with the path + to the client system-options file "dsm.sys". + This option is to provide the effective derivation + for other modules that want to call TSM executables. + ''; + }; + }; + + cfg = config.programs.tsmClient; + + assertions = [ + { + assertion = checkIUnique (mapAttrsToList (k: v: v.name) cfg.servers); + message = '' + TSM servernames contain duplicate name + (note that case doesn't matter!) + ''; + } + { + assertion = (cfg.defaultServername!=null)->(hasAttr cfg.defaultServername cfg.servers); + message = "TSM defaultServername not found in list of servers"; + } + ]; + + dsmSysText = '' + **** IBM Spectrum Protect (Tivoli Storage Manager) + **** client system-options file "dsm.sys". + **** Do not edit! + **** This file is generated by NixOS configuration. + + ${optionalString (cfg.defaultServername!=null) "defaultserver ${cfg.defaultServername}"} + + ${concatStringsSep "\n" (mapAttrsToList (k: v: v.stanza) cfg.servers)} + ''; + +in + +{ + + inherit options; + + config = mkIf cfg.enable { + inherit assertions; + programs.tsmClient.dsmSysText = dsmSysText; + programs.tsmClient.wrappedPackage = cfg.package.override rec { + dsmSysCli = pkgs.writeText "dsm.sys" cfg.dsmSysText; + dsmSysApi = dsmSysCli; + }; + environment.systemPackages = [ cfg.wrappedPackage ]; + }; + + meta.maintainers = [ lib.maintainers.yarny ]; + +} diff --git a/nixpkgs/nixos/modules/programs/xonsh.nix b/nixpkgs/nixos/modules/programs/xonsh.nix index ceab9b5db931..5cd2a49f8073 100644 --- a/nixpkgs/nixos/modules/programs/xonsh.nix +++ b/nixpkgs/nixos/modules/programs/xonsh.nix @@ -26,6 +26,7 @@ in package = mkOption { type = types.package; + default = pkgs.xonsh; example = literalExample "pkgs.xonsh.override { configFile = \"/path/to/xonshrc\"; }"; description = '' xonsh package to use. @@ -46,11 +47,11 @@ in environment.etc."xonshrc".text = cfg.config; - environment.systemPackages = [ pkgs.xonsh ]; + environment.systemPackages = [ cfg.package ]; environment.shells = [ "/run/current-system/sw/bin/xonsh" - "${pkgs.xonsh}/bin/xonsh" + "${cfg.package}/bin/xonsh" ]; }; diff --git a/nixpkgs/nixos/modules/rename.nix b/nixpkgs/nixos/modules/rename.nix index 1b77a895d717..7734209973b2 100644 --- a/nixpkgs/nixos/modules/rename.nix +++ b/nixpkgs/nixos/modules/rename.nix @@ -19,6 +19,7 @@ with lib; let value = getAttrFromPath [ "services" "ddclient" "domain" ] config; in if value != "" then [ value ] else [])) (mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "") + (mkRenamedOptionModule [ "services" "flatpak" "extraPortals" ] [ "xdg" "portal" "extraPortals" ]) (mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ]) (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "admissionControl" ] [ "services" "kubernetes" "apiserver" "enableAdmissionPlugins" ]) (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "address" ] ["services" "kubernetes" "apiserver" "bindAddress"]) @@ -50,6 +51,10 @@ with lib; (mkRemovedOptionModule [ "services" "misc" "nzbget" "openFirewall" ] "The port used by nzbget is managed through the web interface so you should adjust your firewall rules accordingly.") (mkRemovedOptionModule [ "services" "prometheus" "alertmanager" "user" ] "The alertmanager service is now using systemd's DynamicUser mechanism which obviates a user setting.") (mkRemovedOptionModule [ "services" "prometheus" "alertmanager" "group" ] "The alertmanager service is now using systemd's DynamicUser mechanism which obviates a group setting.") + (mkRemovedOptionModule [ "services" "prometheus2" "alertmanagerURL" ] '' + Due to incompatibility, the alertmanagerURL option has been removed, + please use 'services.prometheus2.alertmanagers' instead. + '') (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ]) (mkRenamedOptionModule [ "services" "vmwareGuest" ] [ "virtualisation" "vmware" "guest" ]) (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ]) @@ -62,6 +67,8 @@ with lib; (mkRemovedOptionModule [ "security" "setuidOwners" ] "Use security.wrappers instead") (mkRemovedOptionModule [ "security" "setuidPrograms" ] "Use security.wrappers instead") + (mkRenamedOptionModule [ "security" "virtualization" "flushL1DataCache" ] [ "security" "virtualisation" "flushL1DataCache" ]) + # PAM (mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ]) @@ -171,6 +178,9 @@ with lib; The starting time can be configured via <literal>services.postgresqlBackup.startAt</literal>. '') + # zabbixServer + (mkRenamedOptionModule [ "services" "zabbixServer" "dbServer" ] [ "services" "zabbixServer" "database" "host" ]) + # Profile splitting (mkRenamedOptionModule [ "virtualisation" "growPartition" ] [ "boot" "growPartition" ]) @@ -214,6 +224,7 @@ with lib; (mkRemovedOptionModule [ "services" "winstone" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd") (mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") + (mkRemovedOptionModule [ "services" "zabbixServer" "dbPassword" ] "Use services.zabbixServer.database.passwordFile instead.") # ZSH (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) @@ -244,6 +255,26 @@ with lib; # KSM (mkRenamedOptionModule [ "hardware" "enableKSM" ] [ "hardware" "ksm" "enable" ]) + # resolvconf + (mkRenamedOptionModule [ "networking" "dnsSingleRequest" ] [ "networking" "resolvconf" "dnsSingleRequest" ]) + (mkRenamedOptionModule [ "networking" "dnsExtensionMechanism" ] [ "networking" "resolvconf" "dnsExtensionMechanism" ]) + (mkRenamedOptionModule [ "networking" "extraResolvconfConf" ] [ "networking" "resolvconf" "extraConfig" ]) + (mkRenamedOptionModule [ "networking" "resolvconfOptions" ] [ "networking" "resolvconf" "extraOptions" ]) + + # Redshift + (mkChangedOptionModule [ "services" "redshift" "latitude" ] [ "location" "latitude" ] + (config: + let value = getAttrFromPath [ "services" "redshift" "latitude" ] config; + in if value == null then + throw "services.redshift.latitude is set to null, you can remove this" + else builtins.fromJSON value)) + (mkChangedOptionModule [ "services" "redshift" "longitude" ] [ "location" "longitude" ] + (config: + let value = getAttrFromPath [ "services" "redshift" "longitude" ] config; + in if value == null then + throw "services.redshift.longitude is set to null, you can remove this" + else builtins.fromJSON value)) + ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter" "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" "snmpExporter" "unifiExporter" "varnishExporter" ] diff --git a/nixpkgs/nixos/modules/security/misc.nix b/nixpkgs/nixos/modules/security/misc.nix index bf474ac0a546..16e3bfb14199 100644 --- a/nixpkgs/nixos/modules/security/misc.nix +++ b/nixpkgs/nixos/modules/security/misc.nix @@ -48,13 +48,25 @@ with lib; e.g., shared caches). This attack vector is unproven. Disabling SMT is a supplement to the L1 data cache flushing mitigation - (see <xref linkend="opt-security.virtualization.flushL1DataCache"/>) + (see <xref linkend="opt-security.virtualisation.flushL1DataCache"/>) versus malicious VM guests (SMT could "bring back" previously flushed data). ''; }; - security.virtualization.flushL1DataCache = mkOption { + security.forcePageTableIsolation = mkOption { + type = types.bool; + default = false; + description = '' + Whether to force-enable the Page Table Isolation (PTI) Linux kernel + feature even on CPU models that claim to be safe from Meltdown. + + This hardening feature is most beneficial to systems that run untrusted + workloads that rely on address space isolation for security. + ''; + }; + + security.virtualisation.flushL1DataCache = mkOption { type = types.nullOr (types.enum [ "never" "cond" "always" ]); default = null; description = '' @@ -114,8 +126,12 @@ with lib; boot.kernelParams = [ "nosmt" ]; }) - (mkIf (config.security.virtualization.flushL1DataCache != null) { - boot.kernelParams = [ "kvm-intel.vmentry_l1d_flush=${config.security.virtualization.flushL1DataCache}" ]; + (mkIf config.security.forcePageTableIsolation { + boot.kernelParams = [ "pti=on" ]; + }) + + (mkIf (config.security.virtualisation.flushL1DataCache != null) { + boot.kernelParams = [ "kvm-intel.vmentry_l1d_flush=${config.security.virtualisation.flushL1DataCache}" ]; }) ]; } diff --git a/nixpkgs/nixos/modules/services/audio/spotifyd.nix b/nixpkgs/nixos/modules/services/audio/spotifyd.nix new file mode 100644 index 000000000000..e3556b2559c2 --- /dev/null +++ b/nixpkgs/nixos/modules/services/audio/spotifyd.nix @@ -0,0 +1,42 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.spotifyd; + spotifydConf = pkgs.writeText "spotifyd.conf" cfg.config; +in +{ + options = { + services.spotifyd = { + enable = mkEnableOption "spotifyd, a Spotify playing daemon"; + + config = mkOption { + default = ""; + type = types.lines; + description = '' + Configuration for Spotifyd. For syntax and directives, see + https://github.com/Spotifyd/spotifyd#Configuration. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.spotifyd = { + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" "sound.target" ]; + description = "spotifyd, a Spotify playing daemon"; + serviceConfig = { + ExecStart = "${pkgs.spotifyd}/bin/spotifyd --no-daemon --cache_path /var/cache/spotifyd --config ${spotifydConf}"; + Restart = "always"; + RestartSec = 12; + DynamicUser = true; + CacheDirectory = "spotifyd"; + SupplementaryGroups = ["audio"]; + }; + }; + }; + + meta.maintainers = [ maintainers.anderslundstedt ]; +} diff --git a/nixpkgs/nixos/modules/services/backup/postgresql-wal-receiver.nix b/nixpkgs/nixos/modules/services/backup/postgresql-wal-receiver.nix new file mode 100644 index 000000000000..d9a37037992e --- /dev/null +++ b/nixpkgs/nixos/modules/services/backup/postgresql-wal-receiver.nix @@ -0,0 +1,203 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + receiverSubmodule = { + options = { + postgresqlPackage = mkOption { + type = types.package; + example = literalExample "pkgs.postgresql_11"; + description = '' + PostgreSQL package to use. + ''; + }; + + directory = mkOption { + type = types.path; + example = literalExample "/mnt/pg_wal/main/"; + description = '' + Directory to write the output to. + ''; + }; + + statusInterval = mkOption { + type = types.int; + default = 10; + description = '' + Specifies the number of seconds between status packets sent back to the server. + This allows for easier monitoring of the progress from server. + A value of zero disables the periodic status updates completely, + although an update will still be sent when requested by the server, to avoid timeout disconnect. + ''; + }; + + slot = mkOption { + type = types.str; + default = ""; + example = "some_slot_name"; + description = '' + Require <command>pg_receivewal</command> to use an existing replication slot (see + <link xlink:href="https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION-SLOTS">Section 26.2.6 of the PostgreSQL manual</link>). + When this option is used, <command>pg_receivewal</command> will report a flush position to the server, + indicating when each segment has been synchronized to disk so that the server can remove that segment if it is not otherwise needed. + + When the replication client of <command>pg_receivewal</command> is configured on the server as a synchronous standby, + then using a replication slot will report the flush position to the server, but only when a WAL file is closed. + Therefore, that configuration will cause transactions on the primary to wait for a long time and effectively not work satisfactorily. + The option <option>synchronous</option> must be specified in addition to make this work correctly. + ''; + }; + + synchronous = mkOption { + type = types.bool; + default = false; + description = '' + Flush the WAL data to disk immediately after it has been received. + Also send a status packet back to the server immediately after flushing, regardless of <option>statusInterval</option>. + + This option should be specified if the replication client of <command>pg_receivewal</command> is configured on the server as a synchronous standby, + to ensure that timely feedback is sent to the server. + ''; + }; + + compress = mkOption { + type = types.ints.between 0 9; + default = 0; + description = '' + Enables gzip compression of write-ahead logs, and specifies the compression level + (<literal>0</literal> through <literal>9</literal>, <literal>0</literal> being no compression and <literal>9</literal> being best compression). + The suffix <literal>.gz</literal> will automatically be added to all filenames. + + This option requires PostgreSQL >= 10. + ''; + }; + + connection = mkOption { + type = types.str; + example = "postgresql://user@somehost"; + description = '' + Specifies parameters used to connect to the server, as a connection string. + See <link xlink:href="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING">Section 34.1.1 of the PostgreSQL manual</link> for more information. + + Because <command>pg_receivewal</command> doesn't connect to any particular database in the cluster, + database name in the connection string will be ignored. + ''; + }; + + extraArgs = mkOption { + type = with types; listOf str; + default = [ ]; + example = literalExample '' + [ + "--no-sync" + ] + ''; + description = '' + A list of extra arguments to pass to the <command>pg_receivewal</command> command. + ''; + }; + + environment = mkOption { + type = with types; attrsOf str; + default = { }; + example = literalExample '' + { + PGPASSFILE = "/private/passfile"; + PGSSLMODE = "require"; + } + ''; + description = '' + Environment variables passed to the service. + Usable parameters are listed in <link xlink:href="https://www.postgresql.org/docs/current/libpq-envars.html">Section 34.14 of the PostgreSQL manual</link>. + ''; + }; + }; + }; + +in { + options = { + services.postgresqlWalReceiver = { + receivers = mkOption { + type = with types; attrsOf (submodule receiverSubmodule); + default = { }; + example = literalExample '' + { + main = { + postgresqlPackage = pkgs.postgresql_11; + directory = /mnt/pg_wal/main/; + slot = "main_wal_receiver"; + connection = "postgresql://user@somehost"; + }; + } + ''; + description = '' + PostgreSQL WAL receivers. + Stream write-ahead logs from a PostgreSQL server using <command>pg_receivewal</command> (formerly <command>pg_receivexlog</command>). + See <link xlink:href="https://www.postgresql.org/docs/current/app-pgreceivewal.html">the man page</link> for more information. + ''; + }; + }; + }; + + config = let + receivers = config.services.postgresqlWalReceiver.receivers; + in mkIf (receivers != { }) { + users = { + users.postgres = { + uid = config.ids.uids.postgres; + group = "postgres"; + description = "PostgreSQL server user"; + }; + + groups.postgres = { + gid = config.ids.gids.postgres; + }; + }; + + assertions = concatLists (attrsets.mapAttrsToList (name: config: [ + { + assertion = config.compress > 0 -> versionAtLeast config.postgresqlPackage.version "10"; + message = "Invalid configuration for WAL receiver \"${name}\": compress requires PostgreSQL version >= 10."; + } + ]) receivers); + + systemd.tmpfiles.rules = mapAttrsToList (name: config: '' + d ${escapeShellArg config.directory} 0750 postgres postgres - - + '') receivers; + + systemd.services = with attrsets; mapAttrs' (name: config: nameValuePair "postgresql-wal-receiver-${name}" { + description = "PostgreSQL WAL receiver (${name})"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "postgres"; + Group = "postgres"; + KillSignal = "SIGINT"; + Restart = "always"; + RestartSec = 30; + }; + + inherit (config) environment; + + script = let + receiverCommand = postgresqlPackage: + if (versionAtLeast postgresqlPackage.version "10") + then "${postgresqlPackage}/bin/pg_receivewal" + else "${postgresqlPackage}/bin/pg_receivexlog"; + in '' + ${receiverCommand config.postgresqlPackage} \ + --no-password \ + --directory=${escapeShellArg config.directory} \ + --status-interval=${toString config.statusInterval} \ + --dbname=${escapeShellArg config.connection} \ + ${optionalString (config.compress > 0) "--compress=${toString config.compress}"} \ + ${optionalString (config.slot != "") "--slot=${escapeShellArg config.slot}"} \ + ${optionalString config.synchronous "--synchronous"} \ + ${concatStringsSep " " config.extraArgs} + ''; + }) receivers; + }; + + meta.maintainers = with maintainers; [ pacien ]; +} diff --git a/nixpkgs/nixos/modules/services/backup/tsm.nix b/nixpkgs/nixos/modules/services/backup/tsm.nix new file mode 100644 index 000000000000..3b2bb37491b5 --- /dev/null +++ b/nixpkgs/nixos/modules/services/backup/tsm.nix @@ -0,0 +1,106 @@ +{ config, lib, ... }: + +let + + inherit (lib.attrsets) hasAttr; + inherit (lib.modules) mkDefault mkIf; + inherit (lib.options) mkEnableOption mkOption; + inherit (lib.types) nullOr strMatching; + + options.services.tsmBackup = { + enable = mkEnableOption '' + automatic backups with the + IBM Spectrum Protect (Tivoli Storage Manager, TSM) client. + This also enables + <option>programs.tsmClient.enable</option> + ''; + command = mkOption { + type = strMatching ".+"; + default = "backup"; + example = "incr"; + description = '' + The actual command passed to the + <literal>dsmc</literal> executable to start the backup. + ''; + }; + servername = mkOption { + type = strMatching ".+"; + example = "mainTsmServer"; + description = '' + Create a systemd system service + <literal>tsm-backup.service</literal> that starts + a backup based on the given servername's stanza. + Note that this server's + <option>passwdDir</option> will default to + <filename>/var/lib/tsm-backup/password</filename> + (but may be overridden); + also, the service will use + <filename>/var/lib/tsm-backup</filename> as + <literal>HOME</literal> when calling + <literal>dsmc</literal>. + ''; + }; + autoTime = mkOption { + type = nullOr (strMatching ".+"); + default = null; + example = "12:00"; + description = '' + The backup service will be invoked + automatically at the given date/time, + which must be in the format described in + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>5</manvolnum></citerefentry>. + The default <literal>null</literal> + disables automatic backups. + ''; + }; + }; + + cfg = config.services.tsmBackup; + cfgPrg = config.programs.tsmClient; + + assertions = [ + { + assertion = hasAttr cfg.servername cfgPrg.servers; + message = "TSM service servername not found in list of servers"; + } + { + assertion = cfgPrg.servers.${cfg.servername}.genPasswd; + message = "TSM service requires automatic password generation"; + } + ]; + +in + +{ + + inherit options; + + config = mkIf cfg.enable { + inherit assertions; + programs.tsmClient.enable = true; + programs.tsmClient.servers."${cfg.servername}".passwdDir = + mkDefault "/var/lib/tsm-backup/password"; + systemd.services.tsm-backup = { + description = "IBM Spectrum Protect (Tivoli Storage Manager) Backup"; + # DSM_LOG needs a trailing slash to have it treated as a directory. + # `/var/log` would be littered with TSM log files otherwise. + environment.DSM_LOG = "/var/log/tsm-backup/"; + # TSM needs a HOME dir to store certificates. + environment.HOME = "/var/lib/tsm-backup"; + # for exit status description see + # https://www.ibm.com/support/knowledgecenter/en/SSEQVQ_8.1.8/client/c_sched_rtncode.html + serviceConfig.SuccessExitStatus = "4 8"; + # The `-se` option must come after the command. + # The `-optfile` option suppresses a `dsm.opt`-not-found warning. + serviceConfig.ExecStart = + "${cfgPrg.wrappedPackage}/bin/dsmc ${cfg.command} -se='${cfg.servername}' -optfile=/dev/null"; + serviceConfig.LogsDirectory = "tsm-backup"; + serviceConfig.StateDirectory = "tsm-backup"; + serviceConfig.StateDirectoryMode = "0750"; + startAt = mkIf (cfg.autoTime!=null) cfg.autoTime; + }; + }; + + meta.maintainers = [ lib.maintainers.yarny ]; + +} diff --git a/nixpkgs/nixos/modules/services/backup/zfs-replication.nix b/nixpkgs/nixos/modules/services/backup/zfs-replication.nix new file mode 100644 index 000000000000..785cedb98694 --- /dev/null +++ b/nixpkgs/nixos/modules/services/backup/zfs-replication.nix @@ -0,0 +1,90 @@ +{ lib, pkgs, config, ... }: + +with lib; + +let + cfg = config.services.zfs.autoReplication; + recursive = optionalString cfg.recursive " --recursive"; + followDelete = optionalString cfg.followDelete " --follow-delete"; +in { + options = { + services.zfs.autoReplication = { + enable = mkEnableOption "ZFS snapshot replication."; + + followDelete = mkOption { + description = "Remove remote snapshots that don't have a local correspondant."; + default = true; + type = types.bool; + }; + + host = mkOption { + description = "Remote host where snapshots should be sent."; + example = "example.com"; + type = types.str; + }; + + identityFilePath = mkOption { + description = "Path to SSH key used to login to host."; + example = "/home/username/.ssh/id_rsa"; + type = types.path; + }; + + localFilesystem = mkOption { + description = "Local ZFS fileystem from which snapshots should be sent. Defaults to the attribute name."; + example = "pool/file/path"; + type = types.str; + }; + + remoteFilesystem = mkOption { + description = "Remote ZFS filesystem where snapshots should be sent."; + example = "pool/file/path"; + type = types.str; + }; + + recursive = mkOption { + description = "Recursively discover snapshots to send."; + default = true; + type = types.bool; + }; + + username = mkOption { + description = "Username used by SSH to login to remote host."; + example = "username"; + type = types.str; + }; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + pkgs.lz4 + ]; + + systemd.services."zfs-replication" = { + after = [ + "zfs-snapshot-daily.service" + "zfs-snapshot-frequent.service" + "zfs-snapshot-hourly.service" + "zfs-snapshot-monthly.service" + "zfs-snapshot-weekly.service" + ]; + description = "ZFS Snapshot Replication"; + documentation = [ + "https://github.com/alunduil/zfs-replicate" + ]; + restartIfChanged = false; + serviceConfig.ExecStart = "${pkgs.zfs-replicate}/bin/zfs-replicate${recursive} -l ${escapeShellArg cfg.username} -i ${escapeShellArg cfg.identityFilePath}${followDelete} ${escapeShellArg cfg.host} ${escapeShellArg cfg.remoteFilesystem} ${escapeShellArg cfg.localFilesystem}"; + wantedBy = [ + "zfs-snapshot-daily.service" + "zfs-snapshot-frequent.service" + "zfs-snapshot-hourly.service" + "zfs-snapshot-monthly.service" + "zfs-snapshot-weekly.service" + ]; + }; + }; + + meta = { + maintainers = with lib.maintainers; [ alunduil ]; + }; +} diff --git a/nixpkgs/nixos/modules/services/databases/couchdb.nix b/nixpkgs/nixos/modules/services/databases/couchdb.nix index 5ddf8ba4bfbd..77e404116c8a 100644 --- a/nixpkgs/nixos/modules/services/databases/couchdb.nix +++ b/nixpkgs/nixos/modules/services/databases/couchdb.nix @@ -160,7 +160,7 @@ in { systemd.tmpfiles.rules = [ "d '${dirOf cfg.uriFile}' - ${cfg.user} ${cfg.group} - -" - "d '${dirOf cfg.logFile}' - ${cfg.user} ${cfg.group} - -" + "f '${cfg.logFile}' - ${cfg.user} ${cfg.group} - -" "d '${cfg.databaseDir}' - ${cfg.user} ${cfg.group} - -" "d '${cfg.viewIndexDir}' - ${cfg.user} ${cfg.group} - -" ]; @@ -169,11 +169,9 @@ in { description = "CouchDB Server"; wantedBy = [ "multi-user.target" ]; - preStart = - '' + preStart = '' touch ${cfg.configFile} - touch -a ${cfg.logFile} - ''; + ''; environment = mkIf useVersion2 { # we are actually specifying 4 configuration files: diff --git a/nixpkgs/nixos/modules/services/databases/openldap.nix b/nixpkgs/nixos/modules/services/databases/openldap.nix index c2f458c03794..d8e2c715afb9 100644 --- a/nixpkgs/nixos/modules/services/databases/openldap.nix +++ b/nixpkgs/nixos/modules/services/databases/openldap.nix @@ -237,8 +237,8 @@ in config = mkIf cfg.enable { assertions = [ { - assertion = cfg.rootpwFile != null || cfg.rootpw != null; - message = "Either services.openldap.rootpw or services.openldap.rootpwFile must be set"; + assertion = cfg.configDir != null || cfg.rootpwFile != null || cfg.rootpw != null; + message = "services.openldap: Unless configDir is set, either rootpw or rootpwFile must be set"; } ]; diff --git a/nixpkgs/nixos/modules/services/databases/postgresql.nix b/nixpkgs/nixos/modules/services/databases/postgresql.nix index 5661edbee2db..10250bb5193a 100644 --- a/nixpkgs/nixos/modules/services/databases/postgresql.nix +++ b/nixpkgs/nixos/modules/services/databases/postgresql.nix @@ -6,23 +6,10 @@ let cfg = config.services.postgresql; - # see description of extraPlugins - postgresqlAndPlugins = pg: - if cfg.extraPlugins == [] then pg - else pkgs.buildEnv { - name = "postgresql-and-plugins-${(builtins.parseDrvName pg.name).version}"; - paths = [ pg pg.lib ] ++ cfg.extraPlugins; - buildInputs = [ pkgs.makeWrapper ]; - postBuild = - '' - mkdir -p $out/bin - rm $out/bin/{pg_config,postgres,pg_ctl} - cp --target-directory=$out/bin ${pg}/bin/{postgres,pg_config,pg_ctl} - wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib - ''; - }; - - postgresql = postgresqlAndPlugins cfg.package; + postgresql = + if cfg.extraPlugins == [] + then cfg.package + else cfg.package.withPackages (_: cfg.extraPlugins); # The main PostgreSQL configuration file. configFile = pkgs.writeText "postgresql.conf" @@ -55,7 +42,7 @@ in package = mkOption { type = types.package; - example = literalExample "pkgs.postgresql_9_6"; + example = literalExample "pkgs.postgresql_11"; description = '' PostgreSQL package to use. ''; @@ -71,7 +58,7 @@ in dataDir = mkOption { type = types.path; - example = "/var/lib/postgresql/9.6"; + example = "/var/lib/postgresql/11"; description = '' Data directory for PostgreSQL. ''; @@ -192,17 +179,11 @@ in extraPlugins = mkOption { type = types.listOf types.path; default = []; - example = literalExample "[ (pkgs.postgis.override { postgresql = pkgs.postgresql_9_4; }) ]"; + example = literalExample "with pkgs.postgresql_11.pkgs; [ postgis pg_repack ]"; description = '' - When this list contains elements a new store path is created. - PostgreSQL and the elements are symlinked into it. Then pg_config, - postgres and pg_ctl are copied to make them use the new - $out/lib directory as pkglibdir. This makes it possible to use postgis - without patching the .sql files which reference $libdir/postgis-1.5. + List of PostgreSQL plugins. PostgreSQL version for each plugin should + match version for <literal>services.postgresql.package</literal> value. ''; - # Note: the duplication of executables is about 4MB size. - # So a nicer solution was patching postgresql to allow setting the - # libdir explicitely. }; extraConfig = mkOption { @@ -270,6 +251,10 @@ in environment.systemPackages = [ postgresql ]; + environment.pathsToLink = [ + "/share/postgresql" + ]; + systemd.services.postgresql = { description = "PostgreSQL Server"; @@ -345,13 +330,13 @@ in fi '' + optionalString (cfg.ensureDatabases != []) '' ${concatMapStrings (database: '' - $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc "CREATE DATABASE ${database}" + $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${database}"' '') cfg.ensureDatabases} '' + '' ${concatMapStrings (user: '' $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc "CREATE USER ${user.name}" ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' - $PSQL -tAc "GRANT ${permission} ON ${database} TO ${user.name}" + $PSQL -tAc 'GRANT ${permission} ON ${database} TO ${user.name}' '') user.ensurePermissions)} '') cfg.ensureUsers} ''; diff --git a/nixpkgs/nixos/modules/services/databases/postgresql.xml b/nixpkgs/nixos/modules/services/databases/postgresql.xml index 00bb02dcc5bf..72d4a8249a32 100644 --- a/nixpkgs/nixos/modules/services/databases/postgresql.xml +++ b/nixpkgs/nixos/modules/services/databases/postgresql.xml @@ -27,10 +27,10 @@ <filename>configuration.nix</filename>: <programlisting> <xref linkend="opt-services.postgresql.enable"/> = true; -<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_9_4; +<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_11; </programlisting> Note that you are required to specify the desired version of PostgreSQL - (e.g. <literal>pkgs.postgresql_9_4</literal>). Since upgrading your + (e.g. <literal>pkgs.postgresql_11</literal>). Since upgrading your PostgreSQL version requires a database dump and reload (see below), NixOS cannot provide a default value for <xref linkend="opt-services.postgresql.package"/> such as the most recent @@ -52,7 +52,7 @@ Type "help" for help. <para> By default, PostgreSQL stores its databases in - <filename>/var/db/postgresql</filename>. You can override this using + <filename>/var/lib/postgresql/$psqlSchema</filename>. You can override this using <xref linkend="opt-services.postgresql.dataDir"/>, e.g. <programlisting> <xref linkend="opt-services.postgresql.dataDir"/> = "/data/postgresql"; @@ -74,4 +74,70 @@ Type "help" for help. <link linkend="opt-services.postgresql.enable">here</link>. </para> </section> + <section xml:id="module-services-postgres-plugins"> + <title>Plugins</title> + + <para> + Plugins collection for each PostgreSQL version can be accessed with + <literal>.pkgs</literal>. For example, for + <literal>pkgs.postgresql_11</literal> package, its plugin collection is + accessed by <literal>pkgs.postgresql_11.pkgs</literal>: +<screen> +<prompt>$ </prompt>nix repl '<nixpkgs>' + +Loading '<nixpkgs>'... +Added 10574 variables. + +<prompt>nix-repl> </prompt>postgresql_11.pkgs.<TAB><TAB> +postgresql_11.pkgs.cstore_fdw postgresql_11.pkgs.pg_repack +postgresql_11.pkgs.pg_auto_failover postgresql_11.pkgs.pg_safeupdate +postgresql_11.pkgs.pg_bigm postgresql_11.pkgs.pg_similarity +postgresql_11.pkgs.pg_cron postgresql_11.pkgs.pg_topn +postgresql_11.pkgs.pg_hll postgresql_11.pkgs.pgjwt +postgresql_11.pkgs.pg_partman postgresql_11.pkgs.pgroonga +... +</screen> + </para> + <para> + To add plugins via NixOS configuration, set <literal>services.postgresql.extraPlugins</literal>: +<programlisting> +<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_11; +<xref linkend="opt-services.postgresql.extraPlugins"/> = with pkgs.postgresql_11.pkgs; [ + pg_repack + postgis +]; +</programlisting> + </para> + <para> + You can build custom PostgreSQL-with-plugins (to be used outside of NixOS) using + function <literal>.withPackages</literal>. For example, creating a custom + PostgreSQL package in an overlay can look like: +<programlisting> +self: super: { + postgresql_custom = self.postgresql_11.withPackages (ps: [ + ps.pg_repack + ps.postgis + ]); +} +</programlisting> + </para> + <para> + Here's a recipe on how to override a particular plugin through an overlay: +<programlisting> +self: super: { + postgresql_11 = super.postgresql_11.override { this = self.postgresql_11; } // { + pkgs = super.postgresql_11.pkgs // { + pg_repack = super.postgresql_11.pkgs.pg_repack.overrideAttrs (_: { + name = "pg_repack-v20181024"; + src = self.fetchzip { + url = "https://github.com/reorg/pg_repack/archive/923fa2f3c709a506e111cc963034bf2fd127aa00.tar.gz"; + sha256 = "17k6hq9xaax87yz79j773qyigm4fwk8z4zh5cyp6z0sxnwfqxxw5"; + }; + }); + }; + }; +} +</programlisting> + </para> + </section> </chapter> diff --git a/nixpkgs/nixos/modules/services/desktops/flatpak.nix b/nixpkgs/nixos/modules/services/desktops/flatpak.nix index cfca1893bd82..1492d855aa03 100644 --- a/nixpkgs/nixos/modules/services/desktops/flatpak.nix +++ b/nixpkgs/nixos/modules/services/desktops/flatpak.nix @@ -15,38 +15,28 @@ in { options = { services.flatpak = { enable = mkEnableOption "flatpak"; - - extraPortals = mkOption { - type = types.listOf types.package; - default = []; - description = '' - List of additional portals to add to path. Portals allow interaction - with system, like choosing files or taking screenshots. At minimum, - a desktop portal implementation should be listed. GNOME already - adds <package>xdg-desktop-portal-gtk</package>; for KDE, there - is <package>xdg-desktop-portal-kde</package>. Other desktop - environments will probably want to do the same. - ''; - }; }; }; ###### implementation config = mkIf cfg.enable { + + assertions = [ + { assertion = (config.xdg.portal.enable == true); + message = "To use Flatpak you must enable XDG Desktop Portals with xdg.portal.enable."; + } + ]; + environment.systemPackages = [ pkgs.flatpak ]; - services.dbus.packages = [ pkgs.flatpak pkgs.xdg-desktop-portal ] ++ cfg.extraPortals; + services.dbus.packages = [ pkgs.flatpak ]; - systemd.packages = [ pkgs.flatpak pkgs.xdg-desktop-portal ] ++ cfg.extraPortals; + systemd.packages = [ pkgs.flatpak ]; environment.profiles = [ "$HOME/.local/share/flatpak/exports" "/var/lib/flatpak/exports" ]; - - environment.variables = { - XDG_DESKTOP_PORTAL_PATH = map (p: "${p}/share/xdg-desktop-portal/portals") cfg.extraPortals; - }; }; } diff --git a/nixpkgs/nixos/modules/services/desktops/flatpak.xml b/nixpkgs/nixos/modules/services/desktops/flatpak.xml index fb27bd1f62b2..8f080b250228 100644 --- a/nixpkgs/nixos/modules/services/desktops/flatpak.xml +++ b/nixpkgs/nixos/modules/services/desktops/flatpak.xml @@ -29,7 +29,7 @@ in other cases, you will need to add something like the following to your <filename>configuration.nix</filename>: <programlisting> - <xref linkend="opt-services.flatpak.extraPortals"/> = [ pkgs.xdg-desktop-portal-gtk ]; + <xref linkend="opt-xdg.portal.extraPortals"/> = [ pkgs.xdg-desktop-portal-gtk ]; </programlisting> </para> <para> diff --git a/nixpkgs/nixos/modules/services/desktops/tumbler.nix b/nixpkgs/nixos/modules/services/desktops/tumbler.nix index ccbb6d1434d9..d18088d4634b 100644 --- a/nixpkgs/nixos/modules/services/desktops/tumbler.nix +++ b/nixpkgs/nixos/modules/services/desktops/tumbler.nix @@ -23,7 +23,7 @@ in package = mkOption { type = types.package; - default = pkgs.xfce4-13.tumbler; + default = pkgs.xfce4-14.tumbler; description = "Which tumbler package to use"; example = pkgs.xfce4-12.tumbler; }; diff --git a/nixpkgs/nixos/modules/services/development/bloop.nix b/nixpkgs/nixos/modules/services/development/bloop.nix index 56904b7c40e6..226718a9e80a 100644 --- a/nixpkgs/nixos/modules/services/development/bloop.nix +++ b/nixpkgs/nixos/modules/services/development/bloop.nix @@ -9,6 +9,20 @@ let in { options.services.bloop = { + extraOptions = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ + "-J-Xmx2G" + "-J-XX:MaxInlineLevel=20" + "-J-XX:+UseParallelGC" + ]; + description = '' + Specifies additional command line argument to pass to bloop + java process. + ''; + }; + install = mkOption { type = types.bool; default = false; @@ -25,10 +39,13 @@ in { systemd.user.services.bloop = { description = "Bloop Scala build server"; + environment = { + PATH = mkForce "${makeBinPath [ config.programs.java.package ]}"; + }; serviceConfig = { - Type = "simple"; - ExecStart = ''${pkgs.bloop}/bin/blp-server''; - Restart = "always"; + Type = "simple"; + ExecStart = ''${pkgs.bloop}/bin/bloop server''; + Restart = "always"; }; }; diff --git a/nixpkgs/nixos/modules/services/editors/emacs.xml b/nixpkgs/nixos/modules/services/editors/emacs.xml index 88d7c4e1daf0..a3041ae22e78 100644 --- a/nixpkgs/nixos/modules/services/editors/emacs.xml +++ b/nixpkgs/nixos/modules/services/editors/emacs.xml @@ -95,7 +95,8 @@ also available in Nixpkgs: <link xlink:href="https://www.gnu.org/software/zile/">Zile</link>, <link xlink:href="http://homepage.boetes.org/software/mg/">mg</link>, - <link xlink:href="http://yi-editor.github.io/">Yi</link>. + <link xlink:href="http://yi-editor.github.io/">Yi</link>, + <link xlink:href="https://joe-editor.sourceforge.io/">jmacs</link>. </para> </section> diff --git a/nixpkgs/nixos/modules/services/hardware/throttled.nix b/nixpkgs/nixos/modules/services/hardware/throttled.nix index cd5b01450e44..13fc5e4792e6 100644 --- a/nixpkgs/nixos/modules/services/hardware/throttled.nix +++ b/nixpkgs/nixos/modules/services/hardware/throttled.nix @@ -8,6 +8,12 @@ in { options = { services.throttled = { enable = mkEnableOption "fix for Intel CPU throttling"; + + extraConfig = mkOption { + type = types.str; + default = ""; + description = "Alternative configuration"; + }; }; }; @@ -16,6 +22,9 @@ in { # The upstream package has this in Install, but that's not enough, see the NixOS manual systemd.services."lenovo_fix".wantedBy = [ "multi-user.target" ]; - environment.etc."lenovo_fix.conf".source = "${pkgs.throttled}/etc/lenovo_fix.conf"; + environment.etc."lenovo_fix.conf".source = + if cfg.extraConfig != "" + then pkgs.writeText "lenovo_fix.conf" cfg.extraConfig + else "${pkgs.throttled}/etc/lenovo_fix.conf"; }; } diff --git a/nixpkgs/nixos/modules/services/logging/graylog.nix b/nixpkgs/nixos/modules/services/logging/graylog.nix index c8c4a9ff06db..a889a44d4b2b 100644 --- a/nixpkgs/nixos/modules/services/logging/graylog.nix +++ b/nixpkgs/nixos/modules/services/logging/graylog.nix @@ -150,6 +150,9 @@ in rm -rf /var/lib/graylog/plugins || true mkdir -p /var/lib/graylog/plugins -m 755 + mkdir -p "$(dirname ${cfg.nodeIdFile})" + chown -R ${cfg.user} "$(dirname ${cfg.nodeIdFile})" + for declarativeplugin in `ls ${glPlugins}/bin/`; do ln -sf ${glPlugins}/bin/$declarativeplugin /var/lib/graylog/plugins/$declarativeplugin done diff --git a/nixpkgs/nixos/modules/services/mail/postfix.nix b/nixpkgs/nixos/modules/services/mail/postfix.nix index d43733484ffa..dab1b29aa4be 100644 --- a/nixpkgs/nixos/modules/services/mail/postfix.nix +++ b/nixpkgs/nixos/modules/services/mail/postfix.nix @@ -13,6 +13,7 @@ let || cfg.extraAliases != ""; haveTransport = cfg.transport != ""; haveVirtual = cfg.virtual != ""; + haveLocalRecipients = cfg.localRecipients != null; clientAccess = optional (cfg.dnsBlacklistOverrides != "") @@ -244,6 +245,7 @@ let aliasesFile = pkgs.writeText "postfix-aliases" aliases; virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual; + localRecipientMapFile = pkgs.writeText "postfix-local-recipient-map" (concatMapStrings (x: x + " ACCEPT\n") cfg.localRecipients); checkClientAccessFile = pkgs.writeText "postfix-check-client-access" cfg.dnsBlacklistOverrides; mainCfFile = pkgs.writeText "postfix-main.cf" mainCf; masterCfFile = pkgs.writeText "postfix-master.cf" masterCfContent; @@ -506,6 +508,19 @@ in ''; }; + localRecipients = mkOption { + type = with types; nullOr (listOf string); + default = null; + description = '' + List of accepted local users. Specify a bare username, an + <literal>"@domain.tld"</literal> wild-card, or a complete + <literal>"user@domain.tld"</literal> address. If set, these names end + up in the local recipient map -- see the local(8) man-page -- and + effectively replace the system user database lookup that's otherwise + used by default. + ''; + }; + transport = mkOption { default = ""; description = " @@ -742,6 +757,7 @@ in // optionalAttrs haveAliases { alias_maps = [ "${cfg.aliasMapType}:/etc/postfix/aliases" ]; } // optionalAttrs haveTransport { transport_maps = [ "hash:/etc/postfix/transport" ]; } // optionalAttrs haveVirtual { virtual_alias_maps = [ "${cfg.virtualMapType}:/etc/postfix/virtual" ]; } + // optionalAttrs haveLocalRecipients { local_recipient_maps = [ "hash:/etc/postfix/local_recipients" ] ++ optional haveAliases "$alias_maps"; } // optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; } // optionalAttrs cfg.useSrs { sender_canonical_maps = [ "tcp:127.0.0.1:10001" ]; @@ -869,6 +885,9 @@ in (mkIf haveVirtual { services.postfix.mapFiles."virtual" = virtualFile; }) + (mkIf haveLocalRecipients { + services.postfix.mapFiles."local_recipients" = localRecipientMapFile; + }) (mkIf cfg.enableHeaderChecks { services.postfix.mapFiles."header_checks" = headerChecksFile; }) diff --git a/nixpkgs/nixos/modules/services/misc/dwm-status.nix b/nixpkgs/nixos/modules/services/misc/dwm-status.nix new file mode 100644 index 000000000000..b98a42e6a6d2 --- /dev/null +++ b/nixpkgs/nixos/modules/services/misc/dwm-status.nix @@ -0,0 +1,73 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.dwm-status; + + order = concatMapStringsSep "," (feature: ''"${feature}"'') cfg.order; + + configFile = pkgs.writeText "dwm-status.toml" '' + order = [${order}] + + ${cfg.extraConfig} + ''; +in + +{ + + ###### interface + + options = { + + services.dwm-status = { + + enable = mkEnableOption "dwm-status user service"; + + package = mkOption { + type = types.package; + default = pkgs.dwm-status; + defaultText = "pkgs.dwm-status"; + example = "pkgs.dwm-status.override { enableAlsaUtils = false; }"; + description = '' + Which dwm-status package to use. + ''; + }; + + order = mkOption { + type = types.listOf (types.enum [ "audio" "backlight" "battery" "cpu_load" "network" "time" ]); + description = '' + List of enabled features in order. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra config in TOML format. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + services.upower.enable = elem "battery" cfg.order; + + systemd.user.services.dwm-status = { + description = "Highly performant and configurable DWM status service"; + wantedBy = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + + serviceConfig.ExecStart = "${cfg.package}/bin/dwm-status ${configFile}"; + }; + + }; + +} diff --git a/nixpkgs/nixos/modules/services/misc/gitea.nix b/nixpkgs/nixos/modules/services/misc/gitea.nix index 5a964e672ede..59c1c104b9b9 100644 --- a/nixpkgs/nixos/modules/services/misc/gitea.nix +++ b/nixpkgs/nixos/modules/services/misc/gitea.nix @@ -55,6 +55,11 @@ let [service] DISABLE_REGISTRATION = ${boolToString cfg.disableRegistration} + ${optionalString (cfg.mailerPasswordFile != null) '' + [mailer] + PASSWD = #mailerpass# + ''} + ${cfg.extraConfig} ''; in @@ -255,6 +260,13 @@ in description = "Upper level of template and static files path."; }; + mailerPasswordFile = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/secrets/gitea/mailpw"; + description = "Path to a file containing the SMTP password."; + }; + disableRegistration = mkEnableOption "the registration lock" // { description = '' By default any user can create an account on this <literal>gitea</literal> instance. @@ -344,9 +356,15 @@ in KEY="$(head -n1 ${secretKey})" DBPASS="$(head -n1 ${cfg.database.passwordFile})" JWTSECRET="$(head -n1 ${jwtSecret})" + ${if (cfg.mailerPasswordFile == null) then '' + MAILERPASSWORD="#mailerpass#" + '' else '' + MAILERPASSWORD="$(head -n1 ${cfg.mailerPasswordFile} || :)" + ''} sed -e "s,#secretkey#,$KEY,g" \ -e "s,#dbpass#,$DBPASS,g" \ -e "s,#jwtsecet#,$JWTSECET,g" \ + -e "s,#mailerpass#,$MAILERPASSWORD,g" \ -i ${runConfig} chmod 640 ${runConfig} ${secretKey} ${jwtSecret} ''} diff --git a/nixpkgs/nixos/modules/services/misc/gitlab.nix b/nixpkgs/nixos/modules/services/misc/gitlab.nix index 576ca7bfc055..087630f21776 100644 --- a/nixpkgs/nixos/modules/services/misc/gitlab.nix +++ b/nixpkgs/nixos/modules/services/misc/gitlab.nix @@ -52,7 +52,7 @@ let gitlab_url = "http+unix://${pathUrlQuote gitlabSocket}"; http_settings.self_signed_cert = false; repos_path = "${cfg.statePath}/repositories"; - secret_file = "${cfg.statePath}/config/gitlab_shell_secret"; + secret_file = "${cfg.statePath}/gitlab_shell_secret"; log_file = "${cfg.statePath}/log/gitlab-shell.log"; custom_hooks_dir = "${cfg.statePath}/custom_hooks"; redis = { @@ -109,7 +109,7 @@ let gitlab_shell = { path = "${cfg.packages.gitlab-shell}"; hooks_path = "${cfg.statePath}/shell/hooks"; - secret_file = "${cfg.statePath}/config/gitlab_shell_secret"; + secret_file = "${cfg.statePath}/gitlab_shell_secret"; upload_pack = true; receive_pack = true; }; @@ -132,14 +132,9 @@ let HOME = "${cfg.statePath}/home"; UNICORN_PATH = "${cfg.statePath}/"; GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/"; - GITLAB_STATE_PATH = cfg.statePath; - GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads"; SCHEMA = "${cfg.statePath}/db/schema.rb"; + GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads"; GITLAB_LOG_PATH = "${cfg.statePath}/log"; - GITLAB_SHELL_PATH = "${cfg.packages.gitlab-shell}"; - GITLAB_SHELL_CONFIG_PATH = "${cfg.statePath}/shell/config.yml"; - GITLAB_SHELL_SECRET_PATH = "${cfg.statePath}/config/gitlab_shell_secret"; - GITLAB_SHELL_HOOKS_PATH = "${cfg.statePath}/shell/hooks"; GITLAB_REDIS_CONFIG_FILE = pkgs.writeText "redis.yml" (builtins.toJSON redisConfig); prometheus_multiproc_dir = "/run/gitlab"; RAILS_ENV = "production"; @@ -502,23 +497,44 @@ in { systemd.tmpfiles.rules = [ "d /run/gitlab 0755 ${cfg.user} ${cfg.group} -" "d ${gitlabEnv.HOME} 0750 ${cfg.user} ${cfg.group} -" + "z ${gitlabEnv.HOME}/.ssh/authorized_keys 0600 ${cfg.user} ${cfg.group} -" "d ${cfg.backupPath} 0750 ${cfg.user} ${cfg.group} -" + "d ${cfg.statePath} 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/builds 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/config 0750 ${cfg.user} ${cfg.group} -" + "D ${cfg.statePath}/config/initializers 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/db 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/log 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/repositories 2770 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/shell 0750 ${cfg.user} ${cfg.group} -" + "d ${cfg.statePath}/tmp 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/tmp/pids 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/tmp/sockets 0750 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/uploads 0700 ${cfg.user} ${cfg.group} -" + "d ${cfg.statePath}/custom_hooks 0700 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/custom_hooks/pre-receive.d 0700 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/custom_hooks/post-receive.d 0700 ${cfg.user} ${cfg.group} -" "d ${cfg.statePath}/custom_hooks/update.d 0700 ${cfg.user} ${cfg.group} -" + "d ${gitlabConfig.production.shared.path} 0750 ${cfg.user} ${cfg.group} -" "d ${gitlabConfig.production.shared.path}/artifacts 0750 ${cfg.user} ${cfg.group} -" "d ${gitlabConfig.production.shared.path}/lfs-objects 0750 ${cfg.user} ${cfg.group} -" "d ${gitlabConfig.production.shared.path}/pages 0750 ${cfg.user} ${cfg.group} -" - ]; + "L+ ${cfg.statePath}/lib - - - - ${cfg.packages.gitlab}/share/gitlab/lib" + "L+ /run/gitlab/config - - - - ${cfg.statePath}/config" + "L+ /run/gitlab/log - - - - ${cfg.statePath}/log" + "L+ /run/gitlab/tmp - - - - ${cfg.statePath}/tmp" + "L+ /run/gitlab/uploads - - - - ${cfg.statePath}/uploads" + + "L+ /run/gitlab/shell-config.yml - - - - ${pkgs.writeText "config.yml" (builtins.toJSON gitlabShellConfig)}" + + "L+ ${cfg.statePath}/config/gitlab.yml - - - - ${pkgs.writeText "gitlab.yml" (builtins.toJSON gitlabConfig)}" + "L+ ${cfg.statePath}/config/database.yml - - - - ${pkgs.writeText "database.yml" (builtins.toJSON databaseConfig)}" + "L+ ${cfg.statePath}/config/secrets.yml - - - - ${pkgs.writeText "secrets.yml" (builtins.toJSON secretsConfig)}" + "L+ ${cfg.statePath}/config/unicorn.rb - - - - ${./defaultUnicornConfig.rb}" + + "L+ ${cfg.statePath}/config/initializers/extra-gitlab.rb - - - - ${extraGitlabRb}" + ] ++ optional cfg.smtp.enable + "L+ ${cfg.statePath}/config/initializers/smtp_settings.rb - - - - ${smtpSettings}" ; systemd.services.gitlab-sidekiq = { after = [ "network.target" "redis.service" "gitlab.service" ]; @@ -570,6 +586,7 @@ in { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; path = with pkgs; [ + exiftool gitAndTools.git gnutar gzip @@ -609,40 +626,14 @@ in { gnupg ]; preStart = '' - cp -rf ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db - rm -rf ${cfg.statePath}/config - mkdir ${cfg.statePath}/config - if [ -e ${cfg.statePath}/lib ]; then - rm ${cfg.statePath}/lib - fi + ${pkgs.sudo}/bin/sudo -u ${cfg.user} cp -f ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION + ${pkgs.sudo}/bin/sudo -u ${cfg.user} rm -rf ${cfg.statePath}/db/* + ${pkgs.sudo}/bin/sudo -u ${cfg.user} cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config + ${pkgs.sudo}/bin/sudo -u ${cfg.user} cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db - ln -sf ${cfg.packages.gitlab}/share/gitlab/lib ${cfg.statePath}/lib - [ -L /run/gitlab/config ] || ln -sf ${cfg.statePath}/config /run/gitlab/config - [ -L /run/gitlab/log ] || ln -sf ${cfg.statePath}/log /run/gitlab/log - [ -L /run/gitlab/tmp ] || ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp - [ -L /run/gitlab/uploads ] || ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads - cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION - cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config - ln -sf ${extraGitlabRb} ${cfg.statePath}/config/initializers/extra-gitlab.rb - ${optionalString cfg.smtp.enable '' - ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb - ''} - ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/config/gitlab_shell_secret - - # JSON is a subset of YAML - ln -sf ${pkgs.writeText "gitlab.yml" (builtins.toJSON gitlabConfig)} ${cfg.statePath}/config/gitlab.yml - ln -sf ${pkgs.writeText "database.yml" (builtins.toJSON databaseConfig)} ${cfg.statePath}/config/database.yml - ln -sf ${pkgs.writeText "secrets.yml" (builtins.toJSON secretsConfig)} ${cfg.statePath}/config/secrets.yml - ln -sf ${./defaultUnicornConfig.rb} ${cfg.statePath}/config/unicorn.rb - - # Install the shell required to push repositories - ln -sf ${pkgs.writeText "config.yml" (builtins.toJSON gitlabShellConfig)} /run/gitlab/shell-config.yml - [ -L ${cfg.statePath}/shell/hooks ] || ln -sf ${cfg.packages.gitlab-shell}/hooks ${cfg.statePath}/shell/hooks - ${cfg.packages.gitlab-shell}/bin/install - - chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}/ - chmod -R ug+rwX,o-rwx+X ${cfg.statePath}/ - chown -R ${cfg.user}:${cfg.group} /run/gitlab + ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/gitlab_shell_secret + + ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${cfg.packages.gitlab-shell}/bin/install if ! test -e "${cfg.statePath}/db-created"; then if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then @@ -655,7 +646,7 @@ in { ${pkgs.sudo}/bin/sudo -u ${cfg.user} -H ${gitlab-rake}/bin/gitlab-rake db:schema:load - touch "${cfg.statePath}/db-created" + ${pkgs.sudo}/bin/sudo -u ${cfg.user} touch "${cfg.statePath}/db-created" fi # Always do the db migrations just to be sure the database is up-to-date @@ -664,22 +655,13 @@ in { if ! test -e "${cfg.statePath}/db-seeded"; then ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${gitlab-rake}/bin/gitlab-rake db:seed_fu \ GITLAB_ROOT_PASSWORD='${cfg.initialRootPassword}' GITLAB_ROOT_EMAIL='${cfg.initialRootEmail}' - touch "${cfg.statePath}/db-seeded" + ${pkgs.sudo}/bin/sudo -u ${cfg.user} touch "${cfg.statePath}/db-seeded" fi - # The gitlab:shell:create_hooks task seems broken for fixing links - # so we instead delete all the hooks and create them anew + # We remove potentially broken links to old gitlab-shell versions rm -f ${cfg.statePath}/repositories/**/*.git/hooks - ${pkgs.sudo}/bin/sudo -u ${cfg.user} -H ${gitlab-rake}/bin/gitlab-rake gitlab:shell:create_hooks ${pkgs.sudo}/bin/sudo -u ${cfg.user} -H ${pkgs.git}/bin/git config --global core.autocrlf "input" - - # Change permissions in the last step because some of the - # intermediary scripts like to create directories as root. - chmod -R u+rwX,go-rwx+X ${gitlabEnv.HOME} - chmod -R ug+rwX,o-rwx ${cfg.statePath}/repositories - chmod -R ug-s ${cfg.statePath}/repositories - find ${cfg.statePath}/repositories -type d -print0 | xargs -0 chmod g+s ''; serviceConfig = { diff --git a/nixpkgs/nixos/modules/services/misc/gitolite.nix b/nixpkgs/nixos/modules/services/misc/gitolite.nix index c7f2a168f8ab..cbe2c06ab651 100644 --- a/nixpkgs/nixos/modules/services/misc/gitolite.nix +++ b/nixpkgs/nixos/modules/services/misc/gitolite.nix @@ -143,21 +143,37 @@ in users.users.${cfg.user} = { description = "Gitolite user"; home = cfg.dataDir; - createHome = true; uid = config.ids.uids.gitolite; group = cfg.group; useDefaultShell = true; }; users.groups."${cfg.group}".gid = config.ids.gids.gitolite; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -" + "d '${cfg.dataDir}'/.gitolite - ${cfg.user} ${cfg.group} - -" + "d '${cfg.dataDir}'/.gitolite/logs - ${cfg.user} ${cfg.group} - -" + + "Z ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -" + ]; + systemd.services."gitolite-init" = { description = "Gitolite initialization"; wantedBy = [ "multi-user.target" ]; unitConfig.RequiresMountsFor = cfg.dataDir; - serviceConfig.User = "${cfg.user}"; - serviceConfig.Type = "oneshot"; - serviceConfig.RemainAfterExit = true; + environment = { + GITOLITE_RC = ".gitolite.rc"; + GITOLITE_RC_DEFAULT = "${rcDir}/gitolite.rc.default"; + }; + + serviceConfig = { + Type = "oneshot"; + User = cfg.user; + Group = cfg.group; + WorkingDirectory = "~"; + RemainAfterExit = true; + }; path = [ pkgs.gitolite pkgs.git pkgs.perl pkgs.bash pkgs.diffutils config.programs.ssh.package ]; script = @@ -187,11 +203,6 @@ in ''; in '' - cd ${cfg.dataDir} - mkdir -p .gitolite/logs - - GITOLITE_RC=.gitolite.rc - GITOLITE_RC_DEFAULT=${rcDir}/gitolite.rc.default if ( [[ ! -e "$GITOLITE_RC" ]] && [[ ! -L "$GITOLITE_RC" ]] ) || ( [[ -f "$GITOLITE_RC" ]] && diff -q "$GITOLITE_RC" "$GITOLITE_RC_DEFAULT" >/dev/null ) || ( [[ -L "$GITOLITE_RC" ]] && [[ "$(readlink "$GITOLITE_RC")" =~ ^/nix/store/ ]] ) diff --git a/nixpkgs/nixos/modules/services/misc/greenclip.nix b/nixpkgs/nixos/modules/services/misc/greenclip.nix new file mode 100644 index 000000000000..9152a782d7f0 --- /dev/null +++ b/nixpkgs/nixos/modules/services/misc/greenclip.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.greenclip; +in { + + options.services.greenclip = { + enable = mkEnableOption "Greenclip daemon"; + + package = mkOption { + type = types.package; + default = pkgs.haskellPackages.greenclip; + defaultText = "pkgs.haskellPackages.greenclip"; + description = "greenclip derivation to use."; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.greenclip = { + enable = true; + description = "greenclip daemon"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig.ExecStart = "${cfg.package}/bin/greenclip daemon"; + }; + + environment.systemPackages = [ cfg.package ]; + }; +} diff --git a/nixpkgs/nixos/modules/services/misc/nix-daemon.nix b/nixpkgs/nixos/modules/services/misc/nix-daemon.nix index d8f90f1539c1..6bc88c66dc19 100644 --- a/nixpkgs/nixos/modules/services/misc/nix-daemon.nix +++ b/nixpkgs/nixos/modules/services/misc/nix-daemon.nix @@ -467,7 +467,7 @@ in fi ''; - nix.nrBuildUsers = mkDefault (lib.max 32 cfg.maxJobs); + nix.nrBuildUsers = mkDefault (lib.max 32 (if cfg.maxJobs == "auto" then 0 else cfg.maxJobs)); users.users = nixbldUsers; diff --git a/nixpkgs/nixos/modules/services/misc/redmine.nix b/nixpkgs/nixos/modules/services/misc/redmine.nix index 91ddf2c3edf3..24b9e27ac2da 100644 --- a/nixpkgs/nixos/modules/services/misc/redmine.nix +++ b/nixpkgs/nixos/modules/services/misc/redmine.nix @@ -1,8 +1,10 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkDefault mkEnableOption mkIf mkOption types; + inherit (lib) concatStringsSep literalExample mapAttrsToList; + inherit (lib) optional optionalAttrs optionalString singleton versionAtLeast; + cfg = config.services.redmine; bundle = "${cfg.package}/share/redmine/bin/bundle"; @@ -11,11 +13,11 @@ let production: adapter: ${cfg.database.type} database: ${cfg.database.name} - host: ${cfg.database.host} + host: ${if (cfg.database.type == "postgresql" && cfg.database.socket != null) then cfg.database.socket else cfg.database.host} port: ${toString cfg.database.port} username: ${cfg.database.user} password: #dbpass# - ${optionalString (cfg.database.socket != null) "socket: ${cfg.database.socket}"} + ${optionalString (cfg.database.type == "mysql2" && cfg.database.socket != null) "socket: ${cfg.database.socket}"} ''; configurationYml = pkgs.writeText "configuration.yml" '' @@ -50,16 +52,15 @@ let ''; }); + mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql2"; + pgsqlLocal = cfg.database.createLocally && cfg.database.type == "postgresql"; + in { options = { services.redmine = { - enable = mkOption { - type = types.bool; - default = false; - description = "Enable the Redmine service."; - }; + enable = mkEnableOption "Redmine"; # default to the 4.x series not forcing major version upgrade of those on the 3.x series package = mkOption { @@ -107,7 +108,8 @@ in description = '' Extra configuration in configuration.yml. - See https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration + See <link xlink:href="https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration"/> + for details. ''; example = literalExample '' email_delivery: @@ -124,7 +126,8 @@ in description = '' Extra configuration in additional_environment.rb. - See https://svn.redmine.org/redmine/trunk/config/additional_environment.rb.example + See <link xlink:href="https://svn.redmine.org/redmine/trunk/config/additional_environment.rb.example"/> + for details. ''; example = literalExample '' config.logger.level = Logger::DEBUG @@ -169,13 +172,14 @@ in host = mkOption { type = types.str; - default = (if cfg.database.socket != null then "localhost" else "127.0.0.1"); + default = "localhost"; description = "Database host address."; }; port = mkOption { type = types.int; - default = 3306; + default = if cfg.database.type == "postgresql" then 5432 else 3306; + defaultText = "3306"; description = "Database host port."; }; @@ -213,10 +217,20 @@ in socket = mkOption { type = types.nullOr types.path; - default = null; + default = + if mysqlLocal then "/run/mysqld/mysqld.sock" + else if pgsqlLocal then "/run/postgresql" + else null; + defaultText = "/run/mysqld/mysqld.sock"; example = "/run/mysqld/mysqld.sock"; description = "Path to the unix socket file to use for authentication."; }; + + createLocally = mkOption { + type = types.bool; + default = true; + description = "Create the database and database user locally."; + }; }; }; }; @@ -227,12 +241,37 @@ in { assertion = cfg.database.passwordFile != null || cfg.database.password != "" || cfg.database.socket != null; message = "one of services.redmine.database.socket, services.redmine.database.passwordFile, or services.redmine.database.password must be set"; } - { assertion = cfg.database.socket != null -> (cfg.database.type == "mysql2"); - message = "Socket authentication is only available for the mysql2 database type"; + { assertion = cfg.database.createLocally -> cfg.database.user == cfg.user; + message = "services.redmine.database.user must be set to ${cfg.user} if services.redmine.database.createLocally is set true"; + } + { assertion = cfg.database.createLocally -> cfg.database.socket != null; + message = "services.redmine.database.socket must be set if services.redmine.database.createLocally is set to true"; + } + { assertion = cfg.database.createLocally -> cfg.database.host == "localhost"; + message = "services.redmine.database.host must be set to localhost if services.redmine.database.createLocally is set to true"; } ]; - environment.systemPackages = [ cfg.package ]; + services.mysql = mkIf mysqlLocal { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }; + } + ]; + }; + + services.postgresql = mkIf pgsqlLocal { + enable = true; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; }; + } + ]; + }; # create symlinks for the basic directory layout the redmine package expects systemd.tmpfiles.rules = [ @@ -259,7 +298,7 @@ in ]; systemd.services.redmine = { - after = [ "network.target" (if cfg.database.type == "mysql2" then "mysql.service" else "postgresql.service") ]; + after = [ "network.target" ] ++ optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; wantedBy = [ "multi-user.target" ]; environment.RAILS_ENV = "production"; environment.RAILS_CACHE = "${cfg.stateDir}/cache"; diff --git a/nixpkgs/nixos/modules/services/misc/taskserver/default.nix b/nixpkgs/nixos/modules/services/misc/taskserver/default.nix index 07dbee69db0c..8a57277fafe7 100644 --- a/nixpkgs/nixos/modules/services/misc/taskserver/default.nix +++ b/nixpkgs/nixos/modules/services/misc/taskserver/default.nix @@ -411,7 +411,7 @@ in { } else { cert = "${cfg.pki.manual.server.cert}"; key = "${cfg.pki.manual.server.key}"; - crl = "${cfg.pki.manual.server.crl}"; + ${mapNullable (_: "crl") cfg.pki.manual.server.crl} = "${cfg.pki.manual.server.crl}"; }); ca.cert = if needToCreateCA then "${cfg.dataDir}/keys/ca.cert" diff --git a/nixpkgs/nixos/modules/services/misc/tiddlywiki.nix b/nixpkgs/nixos/modules/services/misc/tiddlywiki.nix new file mode 100644 index 000000000000..2adc08f6cfed --- /dev/null +++ b/nixpkgs/nixos/modules/services/misc/tiddlywiki.nix @@ -0,0 +1,52 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.tiddlywiki; + listenParams = concatStrings (mapAttrsToList (n: v: " '${n}=${toString v}' ") cfg.listenOptions); + exe = "${pkgs.nodePackages.tiddlywiki}/lib/node_modules/.bin/tiddlywiki"; + name = "tiddlywiki"; + dataDir = "/var/lib/" + name; + +in { + + options.services.tiddlywiki = { + + enable = mkEnableOption "TiddlyWiki nodejs server"; + + listenOptions = mkOption { + type = types.attrs; + default = {}; + example = { + credentials = "../credentials.csv"; + readers="(authenticated)"; + port = 3456; + }; + description = '' + Parameters passed to <literal>--listen</literal> command. + Refer to <link xlink:href="https://tiddlywiki.com/#WebServer"/> + for details on supported values. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd = { + services.tiddlywiki = { + description = "TiddlyWiki nodejs server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Restart = "on-failure"; + DynamicUser = true; + StateDirectory = name; + ExecStartPre = "-${exe} ${dataDir} --init server"; + ExecStart = "${exe} ${dataDir} --listen ${listenParams}"; + }; + }; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix b/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix index ce3d53fb2c17..7f78db74677c 100644 --- a/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix +++ b/nixpkgs/nixos/modules/services/monitoring/datadog-agent.nix @@ -42,9 +42,9 @@ let # Apply the configured extraIntegrations to the provided agent # package. See the documentation of `dd-agent/integrations-core.nix` # for detailed information on this. - datadogPkg = cfg.package.overrideAttrs(_: { - python = (pkgs.datadog-integrations-core cfg.extraIntegrations).python; - }); + datadogPkg = cfg.package.override { + pythonPackages = pkgs.datadog-integrations-core cfg.extraIntegrations; + }; in { options.services.datadog-agent = { enable = mkOption { @@ -60,7 +60,7 @@ in { defaultText = "pkgs.datadog-agent"; description = '' Which DataDog v6 agent package to use. Note that the provided - package is expected to have an overridable `python`-attribute + package is expected to have an overridable `pythonPackages`-attribute which configures the Python environment with the Datadog checks. ''; diff --git a/nixpkgs/nixos/modules/services/monitoring/grafana.nix b/nixpkgs/nixos/modules/services/monitoring/grafana.nix index 5d3f2e6ac28f..bf1084eecc3a 100644 --- a/nixpkgs/nixos/modules/services/monitoring/grafana.nix +++ b/nixpkgs/nixos/modules/services/monitoring/grafana.nix @@ -503,12 +503,12 @@ in { message = "Cannot set both adminPassword and adminPasswordFile"; } { - assertion = cfg.security.secretKeyFile != opt.security.secretKeyFile.default -> cfg.security.secretKeyFile == null; + assertion = cfg.security.secretKey != opt.security.secretKey.default -> cfg.security.secretKeyFile == null; message = "Cannot set both secretKey and secretKeyFile"; } { assertion = cfg.smtp.password != opt.smtp.password.default -> cfg.smtp.passwordFile == null; - message = "Cannot set both password and secretKeyFile"; + message = "Cannot set both password and passwordFile"; } ]; @@ -552,6 +552,8 @@ in { description = "Grafana user"; home = cfg.dataDir; createHome = true; + group = "grafana"; }; + users.groups.grafana = {}; }; } diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix index d8384e0d35b3..647d67533b89 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix @@ -79,12 +79,8 @@ let (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg2.rules)) ]); scrape_configs = filterValidPrometheus cfg2.scrapeConfigs; - alerting = optionalAttrs (cfg2.alertmanagerURL != []) { - alertmanagers = [{ - static_configs = [{ - targets = cfg2.alertmanagerURL; - }]; - }]; + alerting = { + inherit (cfg2) alertmanagers; }; }; @@ -738,11 +734,23 @@ in { ''; }; - alertmanagerURL = mkOption { - type = types.listOf types.str; + alertmanagers = mkOption { + type = types.listOf types.attrs; + example = literalExample '' + [ { + scheme = "https"; + path_prefix = "/alertmanager"; + static_configs = [ { + targets = [ + "prometheus.domain.tld" + ]; + } ]; + } ] + ''; default = []; description = '' - List of Alertmanager URLs to send notifications to. + A list of alertmanagers to send alerts to. + See <link xlink:href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alertmanager_config">the official documentation</link> for more information. ''; }; diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix index 20e7eba43412..2ab8910ff9db 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -1,8 +1,10 @@ -{ config, pkgs, lib, ... }: - -with lib; +{ config, pkgs, lib, options, ... }: let + inherit (lib) concatStrings foldl foldl' genAttrs literalExample maintainers + mapAttrsToList mkDefault mkEnableOption mkIf mkMerge mkOption + optional types; + cfg = config.services.prometheus.exporters; # each attribute in `exporterOpts` is expected to have specified: @@ -17,25 +19,30 @@ let # Note that `extraOpts` is optional, but a script for the exporter's # systemd service must be provided by specifying either # `serviceOpts.script` or `serviceOpts.serviceConfig.ExecStart` - exporterOpts = { - blackbox = import ./exporters/blackbox.nix { inherit config lib pkgs; }; - collectd = import ./exporters/collectd.nix { inherit config lib pkgs; }; - dnsmasq = import ./exporters/dnsmasq.nix { inherit config lib pkgs; }; - dovecot = import ./exporters/dovecot.nix { inherit config lib pkgs; }; - fritzbox = import ./exporters/fritzbox.nix { inherit config lib pkgs; }; - json = import ./exporters/json.nix { inherit config lib pkgs; }; - minio = import ./exporters/minio.nix { inherit config lib pkgs; }; - nginx = import ./exporters/nginx.nix { inherit config lib pkgs; }; - node = import ./exporters/node.nix { inherit config lib pkgs; }; - postfix = import ./exporters/postfix.nix { inherit config lib pkgs; }; - snmp = import ./exporters/snmp.nix { inherit config lib pkgs; }; - surfboard = import ./exporters/surfboard.nix { inherit config lib pkgs; }; - tor = import ./exporters/tor.nix { inherit config lib pkgs; }; - unifi = import ./exporters/unifi.nix { inherit config lib pkgs; }; - varnish = import ./exporters/varnish.nix { inherit config lib pkgs; }; - bind = import ./exporters/bind.nix { inherit config lib pkgs; }; - wireguard = import ./exporters/wireguard.nix { inherit config lib pkgs; }; - }; + + exporterOpts = genAttrs [ + "bind" + "blackbox" + "collectd" + "dnsmasq" + "dovecot" + "fritzbox" + "json" + "mail" + "minio" + "nginx" + "node" + "postfix" + "postgres" + "snmp" + "surfboard" + "tor" + "unifi" + "varnish" + "wireguard" + ] (name: + import (./. + "/exporters/${name}.nix") { inherit config lib pkgs options; } + ); mkExporterOpts = ({ name, port }: { enable = mkEnableOption "the prometheus ${name} exporter"; @@ -81,7 +88,7 @@ let }; user = mkOption { type = types.str; - default = "nobody"; + default = "${name}-exporter"; description = '' User name under which the ${name} exporter shall be run. Has no effect when <option>systemd.services.prometheus-${name}-exporter.serviceConfig.DynamicUser</option> is true. @@ -89,7 +96,7 @@ let }; group = mkOption { type = types.str; - default = "nobody"; + default = "${name}-exporter"; description = '' Group under which the ${name} exporter shall be run. Has no effect when <option>systemd.services.prometheus-${name}-exporter.serviceConfig.DynamicUser</option> is true. @@ -97,9 +104,10 @@ let }; }); - mkSubModule = { name, port, extraOpts, ... }: { + mkSubModule = { name, port, extraOpts, imports }: { ${name} = mkOption { type = types.submodule { + inherit imports; options = (mkExporterOpts { inherit name port; } // extraOpts); @@ -112,13 +120,30 @@ let mkSubModules = (foldl' (a: b: a//b) {} (mapAttrsToList (name: opts: mkSubModule { inherit name; - inherit (opts) port serviceOpts; + inherit (opts) port; extraOpts = opts.extraOpts or {}; + imports = opts.imports or []; }) exporterOpts) ); mkExporterConf = { name, conf, serviceOpts }: + let + enableDynamicUser = serviceOpts.serviceConfig.DynamicUser or true; + in mkIf conf.enable { + warnings = conf.warnings or []; + users.users = (mkIf (conf.user == "${name}-exporter" && !enableDynamicUser) { + "${name}-exporter" = { + description = '' + Prometheus ${name} exporter service user + ''; + isSystemUser = true; + inherit (conf) group; + }; + }); + users.groups = (mkIf (conf.group == "${name}-exporter" && !enableDynamicUser) { + "${name}-exporter" = {}; + }); networking.firewall.extraCommands = mkIf conf.openFirewall (concatStrings [ "ip46tables -A nixos-fw ${conf.firewallFilter} " "-m comment --comment ${name}-exporter -j nixos-fw-accept" @@ -129,7 +154,8 @@ let serviceConfig.Restart = mkDefault "always"; serviceConfig.PrivateTmp = mkDefault true; serviceConfig.WorkingDirectory = mkDefault /tmp; - } serviceOpts ] ++ optional (!(serviceOpts.serviceConfig.DynamicUser or false)) { + serviceConfig.DynamicUser = mkDefault enableDynamicUser; + } serviceOpts ] ++ optional (!enableDynamicUser) { serviceConfig.User = conf.user; serviceConfig.Group = conf.group; }); @@ -154,13 +180,19 @@ in }; config = mkMerge ([{ - assertions = [{ + assertions = [ { assertion = (cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null); message = '' Please ensure you have either `services.prometheus.exporters.snmp.configuration' or `services.prometheus.exporters.snmp.configurationPath' set! ''; - }]; + } { + assertion = (cfg.mail.configFile == null) != (cfg.mail.configuration == {}); + message = '' + Please specify either 'services.prometheus.exporters.mail.configuration' + or 'services.prometheus.exporters.mail.configFile'. + ''; + } ]; }] ++ [(mkIf config.services.minio.enable { services.prometheus.exporters.minio.minioAddress = mkDefault "http://localhost:9000"; services.prometheus.exporters.minio.minioAccessKey = mkDefault config.services.minio.accessKey; diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.xml b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.xml index 81ac998729be..c2d4b05996a4 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.xml +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.xml @@ -17,7 +17,7 @@ exporter</link>, it provides hardware and OS metrics from the host it's running on. The exporter could be configured as follows: <programlisting> - services.promtheus.exporters.node = { + services.prometheus.exporters.node = { enable = true; enabledCollectors = [ "logind" @@ -113,7 +113,7 @@ specific options and configuration: <programlisting> # nixpgs/nixos/modules/services/prometheus/exporters/postfix.nix -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -159,8 +159,10 @@ in # `serviceOpts.script` and `serviceOpts.serviceConfig.ExecStart` # has to be specified here. This will be merged with the default # service confiuration. + # Note that by default 'DynamicUser' is 'true'. serviceOpts = { serviceConfig = { + DynamicUser = false; ExecStart = '' ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ @@ -184,4 +186,42 @@ in </listitem> </itemizedlist> </section> + <section xml:id="module-services-prometheus-exporters-update-exporter-module"> + <title>Updating an exporter module</title> + <para> + Should an exporter option change at some point, it is possible to add + information about the change to the exporter definition similar to + <literal>nixpkgs/nixos/modules/rename.nix</literal>: +<programlisting> +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.nginx; +in +{ + port = 9113; + extraOpts = { + # additional module options + # ... + }; + serviceOpts = { + # service configuration + # ... + }; + imports = [ + # 'services.prometheus.exporters.nginx.telemetryEndpoint' -> 'services.prometheus.exporters.nginx.telemetryPath' + (mkRenamedOptionModule [ "telemetryEndpoint" ] [ "telemetryPath" ]) + + # removed option 'services.prometheus.exporters.nginx.insecure' + (mkRemovedOptionModule [ "insecure" ] '' + This option was replaced by 'prometheus.exporters.nginx.sslVerify' which defaults to true. + '') + ({ options.warnings = options.warnings; }) + ]; +} +</programlisting> + </para> + </section> </chapter> diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix index a9746c4d65d5..972632b5a24a 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/bind.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -39,7 +39,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-bind-exporter}/bin/bind_exporter \ -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix index d09d1c4f3663..ca4366121e12 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix @@ -1,9 +1,16 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; let cfg = config.services.prometheus.exporters.blackbox; + + checkConfig = file: pkgs.runCommand "checked-blackbox-exporter.conf" { + preferLocalBuild = true; + buildInputs = [ pkgs.buildPackages.prometheus-blackbox-exporter ]; } '' + ln -s ${file} $out + blackbox_exporter --config.check --config.file $out + ''; in { port = 9115; @@ -18,11 +25,10 @@ in serviceOpts = { serviceConfig = { AmbientCapabilities = [ "CAP_NET_RAW" ]; # for ping probes - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ - --config.file ${cfg.configFile} \ + --config.file ${checkConfig cfg.configFile} \ ${concatStringsSep " \\\n " cfg.extraFlags} ''; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix index 0eba3527162d..1cc346418091 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -64,7 +64,6 @@ in '' else ""; in { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \ -log.format ${cfg.logFormat} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix index b1fab85109af..e9fa26cb1f5a 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -26,7 +26,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-dnsmasq-exporter}/bin/dnsmasq_exporter \ --listen ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix index c47e87a3dc35..a01074758ff8 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -39,8 +39,8 @@ in mail_plugins = $mail_plugins old_stats service old-stats { unix_listener old-stats { - user = nobody - group = nobody + user = dovecot-exporter + group = dovecot-exporter } } '''; @@ -59,6 +59,7 @@ in }; serviceOpts = { serviceConfig = { + DynamicUser = false; ExecStart = '' ${pkgs.prometheus-dovecot-exporter}/bin/dovecot_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix index 530206681d36..9526597b8c96 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -26,7 +26,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-fritzbox-exporter}/bin/exporter \ -listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix index a5494e85e016..82a55bafc982 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -24,7 +24,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \ --port ${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix new file mode 100644 index 000000000000..7d8c6fb61404 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix @@ -0,0 +1,157 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.mail; + + configurationFile = pkgs.writeText "prometheus-mail-exporter.conf" (builtins.toJSON ( + # removes the _module attribute, null values and converts attrNames to lowercase + mapAttrs' (name: value: + if name == "servers" + then nameValuePair (toLower name) + ((map (srv: (mapAttrs' (n: v: nameValuePair (toLower n) v) + (filterAttrs (n: v: !(n == "_module" || v == null)) srv) + ))) value) + else nameValuePair (toLower name) value + ) (filterAttrs (n: _: !(n == "_module")) cfg.configuration) + )); + + serverOptions.options = { + name = mkOption { + type = types.str; + description = '' + Value for label 'configname' which will be added to all metrics. + ''; + }; + server = mkOption { + type = types.str; + description = '' + Hostname of the server that should be probed. + ''; + }; + port = mkOption { + type = types.int; + example = 587; + description = '' + Port to use for SMTP. + ''; + }; + from = mkOption { + type = types.str; + example = "exporteruser@domain.tld"; + description = '' + Content of 'From' Header for probing mails. + ''; + }; + to = mkOption { + type = types.str; + example = "exporteruser@domain.tld"; + description = '' + Content of 'To' Header for probing mails. + ''; + }; + detectionDir = mkOption { + type = types.path; + example = "/var/spool/mail/exporteruser/new"; + description = '' + Directory in which new mails for the exporter user are placed. + Note that this needs to exist when the exporter starts. + ''; + }; + login = mkOption { + type = types.nullOr types.str; + default = null; + example = "exporteruser@domain.tld"; + description = '' + Username to use for SMTP authentication. + ''; + }; + passphrase = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Password to use for SMTP authentication. + ''; + }; + }; + + exporterOptions.options = { + monitoringInterval = mkOption { + type = types.str; + example = "10s"; + description = '' + Time interval between two probe attempts. + ''; + }; + mailCheckTimeout = mkOption { + type = types.str; + description = '' + Timeout until mails are considered "didn't make it". + ''; + }; + disableFileDelition = mkOption { + type = types.bool; + default = false; + description = '' + Disables the exporter's function to delete probing mails. + ''; + }; + servers = mkOption { + type = types.listOf (types.submodule serverOptions); + default = []; + example = literalExample '' + [ { + name = "testserver"; + server = "smtp.domain.tld"; + port = 587; + from = "exporteruser@domain.tld"; + to = "exporteruser@domain.tld"; + detectionDir = "/path/to/Maildir/new"; + } ] + ''; + description = '' + List of servers that should be probed. + ''; + }; + }; +in +{ + port = 9225; + extraOpts = { + configFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Specify the mailexporter configuration file to use. + ''; + }; + configuration = mkOption { + type = types.submodule exporterOptions; + default = {}; + description = '' + Specify the mailexporter configuration file to use. + ''; + }; + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = '' + Path under which to expose metrics. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = false; + ExecStart = '' + ${pkgs.prometheus-mail-exporter}/bin/mailexporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --config.file ${ + if cfg.configuration != {} then configurationFile else cfg.configFile + } \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix index 3cc4ffdbc8fd..ab3e3d7d5d50 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -50,7 +50,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \ -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix index 431dd8b4ead7..554377df37ba 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -16,32 +16,39 @@ in Can be enabled with services.nginx.statusPage = true. ''; }; - telemetryEndpoint = mkOption { + telemetryPath = mkOption { type = types.str; default = "/metrics"; description = '' Path under which to expose metrics. ''; }; - insecure = mkOption { + sslVerify = mkOption { type = types.bool; default = true; description = '' - Ignore server certificate if using https. + Whether to perform certificate verification for https. ''; }; + }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' - ${pkgs.prometheus-nginx-exporter}/bin/nginx_exporter \ - --nginx.scrape_uri '${cfg.scrapeUri}' \ - --telemetry.address ${cfg.listenAddress}:${toString cfg.port} \ - --telemetry.endpoint ${cfg.telemetryEndpoint} \ - --insecure ${toString cfg.insecure} \ + ${pkgs.prometheus-nginx-exporter}/bin/nginx-prometheus-exporter \ + --nginx.scrape-uri '${cfg.scrapeUri}' \ + --nginx.ssl-verify ${toString cfg.sslVerify} \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ ${concatStringsSep " \\\n " cfg.extraFlags} ''; }; }; + imports = [ + (mkRenamedOptionModule [ "telemetryEndpoint" ] [ "telemetryPath" ]) + (mkRemovedOptionModule [ "insecure" ] '' + This option was replaced by 'prometheus.exporters.nginx.sslVerify'. + '') + ({ options.warnings = options.warnings; }) + ]; } diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix index 8c4128f9b634..7e394e8463e0 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/node.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -27,6 +27,7 @@ in }; serviceOpts = { serviceConfig = { + DynamicUser = false; RuntimeDirectory = "prometheus-node-exporter"; ExecStart = '' ${pkgs.prometheus-node-exporter}/bin/node_exporter \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix index efe78ebcba86..f40819e826b0 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -62,6 +62,7 @@ in }; serviceOpts = { serviceConfig = { + DynamicUser = false; ExecStart = '' ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postgres.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postgres.nix new file mode 100644 index 000000000000..1ece73a1159a --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postgres.nix @@ -0,0 +1,47 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.postgres; +in +{ + port = 9187; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = '' + Path under which to expose metrics. + ''; + }; + dataSourceName = mkOption { + type = types.str; + default = "user=postgres database=postgres host=/run/postgresql sslmode=disable"; + example = "postgresql://username:password@localhost:5432/postgres?sslmode=disable"; + description = '' + Accepts PostgreSQL URI form and key=value form arguments. + ''; + }; + runAsLocalSuperUser = mkOption { + type = types.bool; + default = false; + description = '' + Whether to run the exporter as the local 'postgres' super user. + ''; + }; + }; + serviceOpts = { + environment.DATA_SOURCE_NAME = cfg.dataSourceName; + serviceConfig = { + DynamicUser = false; + User = mkIf cfg.runAsLocalSuperUser (mkForce "postgres"); + ExecStart = '' + ${pkgs.prometheus-postgres-exporter}/bin/postgres_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix index 0d9194124325..fe7ae8a8ac90 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -57,7 +57,6 @@ in else "${pkgs.writeText "snmp-eporter-conf.yml" (builtins.toJSON cfg.configuration)}"; in { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \ --config.file=${configFile} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix index 715dba06a3dc..81c5c70ed93f 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/surfboard.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -20,7 +20,6 @@ in description = "Prometheus exporter for surfboard cable modem"; unitConfig.Documentation = "https://github.com/ipstatic/surfboard_exporter"; serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-surfboard-exporter}/bin/surfboard_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix index e0ae83802425..36c473677efa 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/tor.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -26,7 +26,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-tor-exporter}/bin/prometheus-tor-exporter \ -b ${cfg.listenAddress} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix index 011dcbe208e4..9aa0f1b85aac 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -51,7 +51,6 @@ in }; serviceOpts = { serviceConfig = { - DynamicUser = true; ExecStart = '' ${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \ -telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix index aaed76175b84..12153fa021ec 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -68,8 +68,8 @@ in serviceOpts = { path = [ pkgs.varnish ]; serviceConfig = { - DynamicUser = true; RestartSec = mkDefault 1; + DynamicUser = false; ExecStart = '' ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix index c5b84e574b8d..8ae2c927b58c 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs }: +{ config, lib, pkgs, options }: with lib; @@ -23,20 +23,39 @@ in { to set the peers up. ''; }; + + singleSubnetPerField = mkOption { + type = types.bool; + default = false; + description = '' + By default, all allowed IPs and subnets are comma-separated in the + <literal>allowed_ips</literal> field. With this option enabled, + a single IP and subnet will be listed in fields like <literal>allowed_ip_0</literal>, + <literal>allowed_ip_1</literal> and so on. + ''; + }; + + withRemoteIp = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not the remote IP of a WireGuard peer should be exposed via prometheus. + ''; + }; }; serviceOpts = { - script = '' - ${pkgs.prometheus-wireguard-exporter}/bin/prometheus_wireguard_exporter \ - -p ${toString cfg.port} \ - ${optionalString cfg.verbose "-v"} \ - ${optionalString (cfg.wireguardConfig != null) "-n ${cfg.wireguardConfig}"} - ''; - path = [ pkgs.wireguard-tools ]; serviceConfig = { - DynamicUser = true; AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + ExecStart = '' + ${pkgs.prometheus-wireguard-exporter}/bin/prometheus_wireguard_exporter \ + -p ${toString cfg.port} \ + ${optionalString cfg.verbose "-v"} \ + ${optionalString cfg.singleSubnetPerField "-s"} \ + ${optionalString cfg.withRemoteIp "-r"} \ + ${optionalString (cfg.wireguardConfig != null) "-n ${cfg.wireguardConfig}"} + ''; }; }; } diff --git a/nixpkgs/nixos/modules/services/monitoring/thanos.nix b/nixpkgs/nixos/modules/services/monitoring/thanos.nix new file mode 100644 index 000000000000..b41e99b76477 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/thanos.nix @@ -0,0 +1,801 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.thanos; + + nullOpt = type: description: mkOption { + type = types.nullOr type; + default = null; + inherit description; + }; + + optionToArgs = opt: v : optional (v != null) ''--${opt}="${toString v}"''; + flagToArgs = opt: v : optional v ''--${opt}''; + listToArgs = opt: vs : map (v: ''--${opt}="${v}"'') vs; + attrsToArgs = opt: kvs: mapAttrsToList (k: v: ''--${opt}=${k}=\"${v}\"'') kvs; + + mkParamDef = type: default: description: mkParam type (description + '' + + Defaults to <literal>${toString default}</literal> in Thanos + when set to <literal>null</literal>. + ''); + + mkParam = type: description: { + toArgs = optionToArgs; + option = nullOpt type description; + }; + + mkFlagParam = description: { + toArgs = flagToArgs; + option = mkOption { + type = types.bool; + default = false; + inherit description; + }; + }; + + mkListParam = opt: description: { + toArgs = _opt: listToArgs opt; + option = mkOption { + type = types.listOf types.str; + default = []; + inherit description; + }; + }; + + mkAttrsParam = opt: description: { + toArgs = _opt: attrsToArgs opt; + option = mkOption { + type = types.attrsOf types.str; + default = {}; + inherit description; + }; + }; + + mkStateDirParam = opt: default: description: { + toArgs = _opt: stateDir: optionToArgs opt "/var/lib/${stateDir}"; + option = mkOption { + type = types.str; + inherit default; + inherit description; + }; + }; + + toYAML = name: attrs: pkgs.runCommandNoCC name { + preferLocalBuild = true; + json = builtins.toFile "${name}.json" (builtins.toJSON attrs); + nativeBuildInputs = [ pkgs.remarshal ]; + } ''json2yaml -i $json -o $out''; + + thanos = cmd: "${cfg.package}/bin/thanos ${cmd}" + + (let args = cfg."${cmd}".arguments; + in optionalString (length args != 0) (" \\\n " + + concatStringsSep " \\\n " args)); + + argumentsOf = cmd: concatLists (collect isList + (flip mapParamsRecursive params."${cmd}" (path: param: + let opt = concatStringsSep "." path; + v = getAttrFromPath path cfg."${cmd}"; + in param.toArgs opt v))); + + mkArgumentsOption = cmd: mkOption { + type = types.listOf types.str; + default = argumentsOf cmd; + description = '' + Arguments to the <literal>thanos ${cmd}</literal> command. + + Defaults to a list of arguments formed by converting the structured + options of <option>services.thanos.${cmd}</option> to a list of arguments. + + Overriding this option will cause none of the structured options to have + any effect. So only set this if you know what you're doing! + ''; + }; + + mapParamsRecursive = + let noParam = attr: !(attr ? "toArgs" && attr ? "option"); + in mapAttrsRecursiveCond noParam; + + paramsToOptions = mapParamsRecursive (_path: param: param.option); + + params = { + + log = { + + log.level = mkParamDef (types.enum ["debug" "info" "warn" "error" "fatal"]) "info" '' + Log filtering level. + ''; + + log.format = mkParam types.str '' + Log format to use. + ''; + }; + + tracing = cfg: { + tracing.config-file = { + toArgs = _opt: path: optionToArgs "tracing.config-file" path; + option = mkOption { + type = with types; nullOr str; + default = if cfg.tracing.config == null then null + else toString (toYAML "tracing.yaml" cfg.tracing.config); + defaultText = '' + if config.services.thanos.<cmd>.tracing.config == null then null + else toString (toYAML "tracing.yaml" config.services.thanos.<cmd>.tracing.config); + ''; + description = '' + Path to YAML file that contains tracing configuration. + ''; + }; + }; + + tracing.config = + { + toArgs = _opt: _attrs: []; + option = nullOpt types.attrs '' + Tracing configuration. + + When not <literal>null</literal> the attribute set gets converted to + a YAML file and stored in the Nix store. The option + <option>tracing.config-file</option> will default to its path. + + If <option>tracing.config-file</option> is set this option has no effect. + ''; + }; + }; + + common = cfg: params.log // params.tracing cfg // { + + http-address = mkParamDef types.str "0.0.0.0:10902" '' + Listen <literal>host:port</literal> for HTTP endpoints. + ''; + + grpc-address = mkParamDef types.str "0.0.0.0:10901" '' + Listen <literal>ip:port</literal> address for gRPC endpoints (StoreAPI). + + Make sure this address is routable from other components. + ''; + + grpc-server-tls-cert = mkParam types.str '' + TLS Certificate for gRPC server, leave blank to disable TLS + ''; + + grpc-server-tls-key = mkParam types.str '' + TLS Key for the gRPC server, leave blank to disable TLS + ''; + + grpc-server-tls-client-ca = mkParam types.str '' + TLS CA to verify clients against. + + If no client CA is specified, there is no client verification on server side. + (tls.NoClientCert) + ''; + }; + + objstore = cfg: { + + objstore.config-file = { + toArgs = _opt: path: optionToArgs "objstore.config-file" path; + option = mkOption { + type = with types; nullOr str; + default = if cfg.objstore.config == null then null + else toString (toYAML "objstore.yaml" cfg.objstore.config); + defaultText = '' + if config.services.thanos.<cmd>.objstore.config == null then null + else toString (toYAML "objstore.yaml" config.services.thanos.<cmd>.objstore.config); + ''; + description = '' + Path to YAML file that contains object store configuration. + ''; + }; + }; + + objstore.config = + { + toArgs = _opt: _attrs: []; + option = nullOpt types.attrs '' + Object store configuration. + + When not <literal>null</literal> the attribute set gets converted to + a YAML file and stored in the Nix store. The option + <option>objstore.config-file</option> will default to its path. + + If <option>objstore.config-file</option> is set this option has no effect. + ''; + }; + }; + + sidecar = params.common cfg.sidecar // params.objstore cfg.sidecar // { + + prometheus.url = mkParamDef types.str "http://localhost:9090" '' + URL at which to reach Prometheus's API. + + For better performance use local network. + ''; + + tsdb.path = { + toArgs = optionToArgs; + option = mkOption { + type = types.str; + default = "/var/lib/${config.services.prometheus2.stateDir}/data"; + defaultText = "/var/lib/\${config.services.prometheus2.stateDir}/data"; + description = '' + Data directory of TSDB. + ''; + }; + }; + + reloader.config-file = mkParam types.str '' + Config file watched by the reloader. + ''; + + reloader.config-envsubst-file = mkParam types.str '' + Output file for environment variable substituted config file. + ''; + + reloader.rule-dirs = mkListParam "reloader.rule-dir" '' + Rule directories for the reloader to refresh. + ''; + + }; + + store = params.common cfg.store // params.objstore cfg.store // { + + stateDir = mkStateDirParam "data-dir" "thanos-store" '' + Data directory relative to <literal>/var/lib</literal> + in which to cache remote blocks. + ''; + + index-cache-size = mkParamDef types.str "250MB" '' + Maximum size of items held in the index cache. + ''; + + chunk-pool-size = mkParamDef types.str "2GB" '' + Maximum size of concurrently allocatable bytes for chunks. + ''; + + store.grpc.series-sample-limit = mkParamDef types.int 0 '' + Maximum amount of samples returned via a single Series call. + + <literal>0</literal> means no limit. + + NOTE: for efficiency we take 120 as the number of samples in chunk (it + cannot be bigger than that), so the actual number of samples might be + lower, even though the maximum could be hit. + ''; + + store.grpc.series-max-concurrency = mkParamDef types.int 20 '' + Maximum number of concurrent Series calls. + ''; + + sync-block-duration = mkParamDef types.str "3m" '' + Repeat interval for syncing the blocks between local and remote view. + ''; + + block-sync-concurrency = mkParamDef types.int 20 '' + Number of goroutines to use when syncing blocks from object storage. + ''; + }; + + query = params.common cfg.query // { + + grpc-client-tls-secure = mkFlagParam '' + Use TLS when talking to the gRPC server + ''; + + grpc-client-tls-cert = mkParam types.str '' + TLS Certificates to use to identify this client to the server + ''; + + grpc-client-tls-key = mkParam types.str '' + TLS Key for the client's certificate + ''; + + grpc-client-tls-ca = mkParam types.str '' + TLS CA Certificates to use to verify gRPC servers + ''; + + grpc-client-server-name = mkParam types.str '' + Server name to verify the hostname on the returned gRPC certificates. + See <link xlink:href="https://tools.ietf.org/html/rfc4366#section-3.1"/> + ''; + + web.route-prefix = mkParam types.str '' + Prefix for API and UI endpoints. + + This allows thanos UI to be served on a sub-path. This option is + analogous to <option>web.route-prefix</option> of Promethus. + ''; + + web.external-prefix = mkParam types.str '' + Static prefix for all HTML links and redirect URLs in the UI query web + interface. + + Actual endpoints are still served on / or the + <option>web.route-prefix</option>. This allows thanos UI to be served + behind a reverse proxy that strips a URL sub-path. + ''; + + web.prefix-header = mkParam types.str '' + Name of HTTP request header used for dynamic prefixing of UI links and + redirects. + + This option is ignored if the option + <literal>web.external-prefix</literal> is set. + + Security risk: enable this option only if a reverse proxy in front of + thanos is resetting the header. + + The setting <literal>web.prefix-header="X-Forwarded-Prefix"</literal> + can be useful, for example, if Thanos UI is served via Traefik reverse + proxy with <literal>PathPrefixStrip</literal> option enabled, which + sends the stripped prefix value in <literal>X-Forwarded-Prefix</literal> + header. This allows thanos UI to be served on a sub-path. + ''; + + query.timeout = mkParamDef types.str "2m" '' + Maximum time to process query by query node. + ''; + + query.max-concurrent = mkParamDef types.int 20 '' + Maximum number of queries processed concurrently by query node. + ''; + + query.replica-label = mkParam types.str '' + Label to treat as a replica indicator along which data is + deduplicated. + + Still you will be able to query without deduplication using + <literal>dedup=false</literal> parameter. + ''; + + selector-labels = mkAttrsParam "selector-label" '' + Query selector labels that will be exposed in info endpoint. + ''; + + store.addresses = mkListParam "store" '' + Addresses of statically configured store API servers. + + The scheme may be prefixed with <literal>dns+</literal> or + <literal>dnssrv+</literal> to detect store API servers through + respective DNS lookups. + ''; + + store.sd-files = mkListParam "store.sd-files" '' + Path to files that contain addresses of store API servers. The path + can be a glob pattern. + ''; + + store.sd-interval = mkParamDef types.str "5m" '' + Refresh interval to re-read file SD files. It is used as a resync fallback. + ''; + + store.sd-dns-interval = mkParamDef types.str "30s" '' + Interval between DNS resolutions. + ''; + + store.unhealthy-timeout = mkParamDef types.str "5m" '' + Timeout before an unhealthy store is cleaned from the store UI page. + ''; + + query.auto-downsampling = mkFlagParam '' + Enable automatic adjustment (step / 5) to what source of data should + be used in store gateways if no + <literal>max_source_resolution</literal> param is specified. + ''; + + query.partial-response = mkFlagParam '' + Enable partial response for queries if no + <literal>partial_response</literal> param is specified. + ''; + + query.default-evaluation-interval = mkParamDef types.str "1m" '' + Set default evaluation interval for sub queries. + ''; + + store.response-timeout = mkParamDef types.str "0ms" '' + If a Store doesn't send any data in this specified duration then a + Store will be ignored and partial data will be returned if it's + enabled. <literal>0</literal> disables timeout. + ''; + }; + + rule = params.common cfg.rule // params.objstore cfg.rule // { + + labels = mkAttrsParam "label" '' + Labels to be applied to all generated metrics. + + Similar to external labels for Prometheus, + used to identify ruler and its blocks as unique source. + ''; + + stateDir = mkStateDirParam "data-dir" "thanos-rule" '' + Data directory relative to <literal>/var/lib</literal>. + ''; + + rule-files = mkListParam "rule-file" '' + Rule files that should be used by rule manager. Can be in glob format. + ''; + + eval-interval = mkParamDef types.str "30s" '' + The default evaluation interval to use. + ''; + + tsdb.block-duration = mkParamDef types.str "2h" '' + Block duration for TSDB block. + ''; + + tsdb.retention = mkParamDef types.str "48h" '' + Block retention time on local disk. + ''; + + alertmanagers.urls = mkListParam "alertmanagers.url" '' + Alertmanager replica URLs to push firing alerts. + + Ruler claims success if push to at least one alertmanager from + discovered succeeds. The scheme may be prefixed with + <literal>dns+</literal> or <literal>dnssrv+</literal> to detect + Alertmanager IPs through respective DNS lookups. The port defaults to + <literal>9093</literal> or the SRV record's value. The URL path is + used as a prefix for the regular Alertmanager API path. + ''; + + alertmanagers.send-timeout = mkParamDef types.str "10s" '' + Timeout for sending alerts to alertmanager. + ''; + + alert.query-url = mkParam types.str '' + The external Thanos Query URL that would be set in all alerts 'Source' field. + ''; + + alert.label-drop = mkListParam "alert.label-drop" '' + Labels by name to drop before sending to alertmanager. + + This allows alert to be deduplicated on replica label. + + Similar Prometheus alert relabelling + ''; + + web.route-prefix = mkParam types.str '' + Prefix for API and UI endpoints. + + This allows thanos UI to be served on a sub-path. + + This option is analogous to <literal>--web.route-prefix</literal> of Promethus. + ''; + + web.external-prefix = mkParam types.str '' + Static prefix for all HTML links and redirect URLs in the UI query web + interface. + + Actual endpoints are still served on / or the + <option>web.route-prefix</option>. This allows thanos UI to be served + behind a reverse proxy that strips a URL sub-path. + ''; + + web.prefix-header = mkParam types.str '' + Name of HTTP request header used for dynamic prefixing of UI links and + redirects. + + This option is ignored if the option + <option>web.external-prefix</option> is set. + + Security risk: enable this option only if a reverse proxy in front of + thanos is resetting the header. + + The header <literal>X-Forwarded-Prefix</literal> can be useful, for + example, if Thanos UI is served via Traefik reverse proxy with + <literal>PathPrefixStrip</literal> option enabled, which sends the + stripped prefix value in <literal>X-Forwarded-Prefix</literal> + header. This allows thanos UI to be served on a sub-path. + ''; + + query.addresses = mkListParam "query" '' + Addresses of statically configured query API servers. + + The scheme may be prefixed with <literal>dns+</literal> or + <literal>dnssrv+</literal> to detect query API servers through + respective DNS lookups. + ''; + + query.sd-files = mkListParam "query.sd-files" '' + Path to file that contain addresses of query peers. + The path can be a glob pattern. + ''; + + query.sd-interval = mkParamDef types.str "5m" '' + Refresh interval to re-read file SD files. (used as a fallback) + ''; + + query.sd-dns-interval = mkParamDef types.str "30s" '' + Interval between DNS resolutions. + ''; + }; + + compact = params.log // params.tracing cfg.compact // params.objstore cfg.compact // { + + http-address = mkParamDef types.str "0.0.0.0:10902" '' + Listen <literal>host:port</literal> for HTTP endpoints. + ''; + + stateDir = mkStateDirParam "data-dir" "thanos-compact" '' + Data directory relative to <literal>/var/lib</literal> + in which to cache blocks and process compactions. + ''; + + consistency-delay = mkParamDef types.str "30m" '' + Minimum age of fresh (non-compacted) blocks before they are being + processed. Malformed blocks older than the maximum of consistency-delay + and 30m0s will be removed. + ''; + + retention.resolution-raw = mkParamDef types.str "0d" '' + How long to retain raw samples in bucket. + + <literal>0d</literal> - disables this retention + ''; + + retention.resolution-5m = mkParamDef types.str "0d" '' + How long to retain samples of resolution 1 (5 minutes) in bucket. + + <literal>0d</literal> - disables this retention + ''; + + retention.resolution-1h = mkParamDef types.str "0d" '' + How long to retain samples of resolution 2 (1 hour) in bucket. + + <literal>0d</literal> - disables this retention + ''; + + startAt = { + toArgs = _opt: startAt: flagToArgs "wait" (startAt == null); + option = nullOpt types.str '' + When this option is set to a <literal>systemd.time</literal> + specification the Thanos compactor will run at the specified period. + + When this option is <literal>null</literal> the Thanos compactor service + will run continuously. So it will not exit after all compactions have + been processed but wait for new work. + ''; + }; + + block-sync-concurrency = mkParamDef types.int 20 '' + Number of goroutines to use when syncing block metadata from object storage. + ''; + + compact.concurrency = mkParamDef types.int 1 '' + Number of goroutines to use when compacting groups. + ''; + }; + + downsample = params.log // params.tracing cfg.downsample // params.objstore cfg.downsample // { + + stateDir = mkStateDirParam "data-dir" "thanos-downsample" '' + Data directory relative to <literal>/var/lib</literal> + in which to cache blocks and process downsamplings. + ''; + + }; + + receive = params.common cfg.receive // params.objstore cfg.receive // { + + remote-write.address = mkParamDef types.str "0.0.0.0:19291" '' + Address to listen on for remote write requests. + ''; + + stateDir = mkStateDirParam "tsdb.path" "thanos-receive" '' + Data directory relative to <literal>/var/lib</literal> of TSDB. + ''; + + labels = mkAttrsParam "labels" '' + External labels to announce. + + This flag will be removed in the future when handling multiple tsdb + instances is added. + ''; + + tsdb.retention = mkParamDef types.str "15d" '' + How long to retain raw samples on local storage. + + <literal>0d</literal> - disables this retention + ''; + }; + + }; + + assertRelativeStateDir = cmd: { + assertions = [ + { + assertion = !hasPrefix "/" cfg."${cmd}".stateDir; + message = + "The option services.thanos.${cmd}.stateDir should not be an absolute directory." + + " It should be a directory relative to /var/lib."; + } + ]; + }; + +in { + + options.services.thanos = { + + package = mkOption { + type = types.package; + default = pkgs.thanos; + defaultText = "pkgs.thanos"; + description = '' + The thanos package that should be used. + ''; + }; + + sidecar = paramsToOptions params.sidecar // { + enable = mkEnableOption + "the Thanos sidecar for Prometheus server"; + arguments = mkArgumentsOption "sidecar"; + }; + + store = paramsToOptions params.store // { + enable = mkEnableOption + "the Thanos store node giving access to blocks in a bucket provider."; + arguments = mkArgumentsOption "store"; + }; + + query = paramsToOptions params.query // { + enable = mkEnableOption + ("the Thanos query node exposing PromQL enabled Query API " + + "with data retrieved from multiple store nodes"); + arguments = mkArgumentsOption "query"; + }; + + rule = paramsToOptions params.rule // { + enable = mkEnableOption + ("the Thanos ruler service which evaluates Prometheus rules against" + + " given Query nodes, exposing Store API and storing old blocks in bucket"); + arguments = mkArgumentsOption "rule"; + }; + + compact = paramsToOptions params.compact // { + enable = mkEnableOption + "the Thanos compactor which continuously compacts blocks in an object store bucket"; + arguments = mkArgumentsOption "compact"; + }; + + downsample = paramsToOptions params.downsample // { + enable = mkEnableOption + "the Thanos downsampler which continuously downsamples blocks in an object store bucket"; + arguments = mkArgumentsOption "downsample"; + }; + + receive = paramsToOptions params.receive // { + enable = mkEnableOption + ("the Thanos receiver which accept Prometheus remote write API requests " + + "and write to local tsdb (EXPERIMENTAL, this may change drastically without notice)"); + arguments = mkArgumentsOption "receive"; + }; + }; + + config = mkMerge [ + + (mkIf cfg.sidecar.enable { + assertions = [ + { + assertion = config.services.prometheus2.enable; + message = + "Please enable services.prometheus2 when enabling services.thanos.sidecar."; + } + { + assertion = !(config.services.prometheus2.globalConfig.external_labels == null || + config.services.prometheus2.globalConfig.external_labels == {}); + message = + "services.thanos.sidecar requires uniquely identifying external labels " + + "to be configured in the Prometheus server. " + + "Please set services.prometheus2.globalConfig.external_labels."; + } + ]; + systemd.services.thanos-sidecar = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "prometheus2.service" ]; + serviceConfig = { + User = "prometheus"; + Restart = "always"; + ExecStart = thanos "sidecar"; + }; + }; + }) + + (mkIf cfg.store.enable (mkMerge [ + (assertRelativeStateDir "store") + { + systemd.services.thanos-store = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + StateDirectory = cfg.store.stateDir; + Restart = "always"; + ExecStart = thanos "store"; + }; + }; + } + ])) + + (mkIf cfg.query.enable { + systemd.services.thanos-query = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + Restart = "always"; + ExecStart = thanos "query"; + }; + }; + }) + + (mkIf cfg.rule.enable (mkMerge [ + (assertRelativeStateDir "rule") + { + systemd.services.thanos-rule = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + StateDirectory = cfg.rule.stateDir; + Restart = "always"; + ExecStart = thanos "rule"; + }; + }; + } + ])) + + (mkIf cfg.compact.enable (mkMerge [ + (assertRelativeStateDir "compact") + { + systemd.services.thanos-compact = + let wait = cfg.compact.startAt == null; in { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Type = if wait then "simple" else "oneshot"; + Restart = if wait then "always" else "no"; + DynamicUser = true; + StateDirectory = cfg.compact.stateDir; + ExecStart = thanos "compact"; + }; + } // optionalAttrs (!wait) { inherit (cfg.compact) startAt; }; + } + ])) + + (mkIf cfg.downsample.enable (mkMerge [ + (assertRelativeStateDir "downsample") + { + systemd.services.thanos-downsample = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + StateDirectory = cfg.downsample.stateDir; + Restart = "always"; + ExecStart = thanos "downsample"; + }; + }; + } + ])) + + (mkIf cfg.receive.enable (mkMerge [ + (assertRelativeStateDir "receive") + { + systemd.services.thanos-receive = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + DynamicUser = true; + StateDirectory = cfg.receive.stateDir; + Restart = "always"; + ExecStart = thanos "receive"; + }; + }; + } + ])) + + ]; +} diff --git a/nixpkgs/nixos/modules/services/monitoring/zabbix-agent.nix b/nixpkgs/nixos/modules/services/monitoring/zabbix-agent.nix index 0519e7c2ad6a..b1645f861101 100644 --- a/nixpkgs/nixos/modules/services/monitoring/zabbix-agent.nix +++ b/nixpkgs/nixos/modules/services/monitoring/zabbix-agent.nix @@ -1,73 +1,118 @@ -# Zabbix agent daemon. { config, lib, pkgs, ... }: -with lib; - let - cfg = config.services.zabbixAgent; - zabbix = cfg.package; - - stateDir = "/run/zabbix"; - - logDir = "/var/log/zabbix"; - - pidFile = "${stateDir}/zabbix_agentd.pid"; + inherit (lib) mkDefault mkEnableOption mkIf mkOption; + inherit (lib) attrValues concatMapStringsSep literalExample optionalString types; - configFile = pkgs.writeText "zabbix_agentd.conf" - '' - Server = ${cfg.server} + user = "zabbix-agent"; + group = "zabbix-agent"; - LogFile = ${logDir}/zabbix_agentd - - PidFile = ${pidFile} - - StartAgents = 1 + moduleEnv = pkgs.symlinkJoin { + name = "zabbix-agent-module-env"; + paths = attrValues cfg.modules; + }; - ${config.services.zabbixAgent.extraConfig} - ''; + configFile = pkgs.writeText "zabbix_agent.conf" '' + LogType = console + Server = ${cfg.server} + ListenIP = ${cfg.listen.ip} + ListenPort = ${toString cfg.listen.port} + ${optionalString (cfg.modules != {}) "LoadModulePath = ${moduleEnv}/lib"} + ${concatMapStringsSep "\n" (name: "LoadModule = ${name}") (builtins.attrNames cfg.modules)} + ${cfg.extraConfig} + ''; in { - - ###### interface + # interface options = { services.zabbixAgent = { + enable = mkEnableOption "the Zabbix Agent"; - enable = mkOption { - default = false; + package = mkOption { + type = types.package; + default = pkgs.zabbix.agent; + defaultText = "pkgs.zabbix.agent"; + description = "The Zabbix package to use."; + }; + + extraPackages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ nettools ]; + defaultText = "[ nettools ]"; + example = "[ nettools mysql ]"; description = '' - Whether to run the Zabbix monitoring agent on this machine. - It will send monitoring data to a Zabbix server. + Packages to be added to the Zabbix <envar>PATH</envar>. + Typically used to add executables for scripts, but can be anything. ''; }; - package = mkOption { - type = types.attrs; # Note: pkgs.zabbixXY isn't a derivation, but an attrset of { server = ...; agent = ...; }. - default = pkgs.zabbix; - defaultText = "pkgs.zabbix"; - example = literalExample "pkgs.zabbix34"; - description = '' - The Zabbix package to use. + modules = mkOption { + type = types.attrsOf types.package; + description = "A set of modules to load."; + default = {}; + example = literalExample '' + { + "dummy.so" = pkgs.stdenv.mkDerivation { + name = "zabbix-dummy-module-''${cfg.package.version}"; + src = cfg.package.src; + buildInputs = [ cfg.package ]; + sourceRoot = "zabbix-''${cfg.package.version}/src/modules/dummy"; + installPhase = ''' + mkdir -p $out/lib + cp dummy.so $out/lib/ + '''; + }; + } ''; }; server = mkOption { - default = "127.0.0.1"; + type = types.str; description = '' The IP address or hostname of the Zabbix server to connect to. ''; }; + listen = { + ip = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + List of comma delimited IP addresses that the agent should listen on. + ''; + }; + + port = mkOption { + type = types.port; + default = 10050; + description = '' + Agent will listen on this port for connections from the server. + ''; + }; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open ports in the firewall for the Zabbix Agent. + ''; + }; + + # TODO: for bonus points migrate this to https://github.com/NixOS/rfcs/pull/42 extraConfig = mkOption { default = ""; type = types.lines; description = '' - Configuration that is injected verbatim into the configuration file. + Configuration that is injected verbatim into the configuration file. Refer to + <link xlink:href="https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_agentd"/> + for details on supported values. ''; }; @@ -75,38 +120,38 @@ in }; - - ###### implementation + # implementation config = mkIf cfg.enable { - users.users = mkIf (!config.services.zabbixServer.enable) (singleton - { name = "zabbix"; - uid = config.ids.uids.zabbix; - description = "Zabbix daemon user"; - }); + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.listen.port ]; + }; - systemd.services."zabbix-agent" = - { description = "Zabbix Agent"; + users.users.${user} = { + description = "Zabbix Agent daemon user"; + inherit group; + }; - wantedBy = [ "multi-user.target" ]; + users.groups.${group} = { }; - path = [ pkgs.nettools ]; + systemd.services."zabbix-agent" = { + description = "Zabbix Agent"; - preStart = - '' - mkdir -m 0755 -p ${stateDir} ${logDir} - chown zabbix ${stateDir} ${logDir} - ''; + wantedBy = [ "multi-user.target" ]; - serviceConfig.ExecStart = "@${zabbix.agent}/sbin/zabbix_agentd zabbix_agentd --config ${configFile}"; - serviceConfig.Type = "forking"; - serviceConfig.RemainAfterExit = true; - serviceConfig.Restart = "always"; - serviceConfig.RestartSec = 2; - }; + path = [ "/run/wrappers" ] ++ cfg.extraPackages; + + serviceConfig = { + ExecStart = "@${cfg.package}/sbin/zabbix_agentd zabbix_agentd -f --config ${configFile}"; + Restart = "always"; + RestartSec = 2; - environment.systemPackages = [ zabbix.agent ]; + User = user; + Group = group; + PrivateTmp = true; + }; + }; }; diff --git a/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix b/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix new file mode 100644 index 000000000000..9cfcd1697c11 --- /dev/null +++ b/nixpkgs/nixos/modules/services/monitoring/zabbix-proxy.nix @@ -0,0 +1,298 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.zabbixProxy; + pgsql = config.services.postgresql; + mysql = config.services.mysql; + + inherit (lib) mkDefault mkEnableOption mkIf mkOption; + inherit (lib) attrValues concatMapStringsSep literalExample optional optionalAttrs optionalString types; + + user = "zabbix"; + group = "zabbix"; + runtimeDir = "/run/zabbix"; + stateDir = "/var/lib/zabbix"; + passwordFile = "${runtimeDir}/zabbix-dbpassword.conf"; + + moduleEnv = pkgs.symlinkJoin { + name = "zabbix-proxy-module-env"; + paths = attrValues cfg.modules; + }; + + configFile = pkgs.writeText "zabbix_proxy.conf" '' + LogType = console + ListenIP = ${cfg.listen.ip} + ListenPort = ${toString cfg.listen.port} + Server = ${cfg.server} + # TODO: set to cfg.database.socket if database type is pgsql? + DBHost = ${optionalString (cfg.database.createLocally != true) cfg.database.host} + ${optionalString (cfg.database.createLocally != true) "DBPort = ${cfg.database.port}"} + DBName = ${cfg.database.name} + DBUser = ${cfg.database.user} + ${optionalString (cfg.database.passwordFile != null) "Include ${passwordFile}"} + ${optionalString (mysqlLocal && cfg.database.socket != null) "DBSocket = ${cfg.database.socket}"} + SocketDir = ${runtimeDir} + FpingLocation = /run/wrappers/bin/fping + ${optionalString (cfg.modules != {}) "LoadModulePath = ${moduleEnv}/lib"} + ${concatMapStringsSep "\n" (name: "LoadModule = ${name}") (builtins.attrNames cfg.modules)} + ${cfg.extraConfig} + ''; + + mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql"; + pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql"; + +in + +{ + # interface + + options = { + + services.zabbixProxy = { + enable = mkEnableOption "the Zabbix Proxy"; + + server = mkOption { + type = types.str; + description = '' + The IP address or hostname of the Zabbix server to connect to. + ''; + }; + + package = mkOption { + type = types.package; + default = + if cfg.database.type == "mysql" then pkgs.zabbix.proxy-mysql + else if cfg.database.type == "pgsql" then pkgs.zabbix.proxy-pgsql + else pkgs.zabbix.proxy-sqlite; + defaultText = "pkgs.zabbix.proxy-pgsql"; + description = "The Zabbix package to use."; + }; + + extraPackages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ nettools nmap traceroute ]; + defaultText = "[ nettools nmap traceroute ]"; + description = '' + Packages to be added to the Zabbix <envar>PATH</envar>. + Typically used to add executables for scripts, but can be anything. + ''; + }; + + modules = mkOption { + type = types.attrsOf types.package; + description = "A set of modules to load."; + default = {}; + example = literalExample '' + { + "dummy.so" = pkgs.stdenv.mkDerivation { + name = "zabbix-dummy-module-''${cfg.package.version}"; + src = cfg.package.src; + buildInputs = [ cfg.package ]; + sourceRoot = "zabbix-''${cfg.package.version}/src/modules/dummy"; + installPhase = ''' + mkdir -p $out/lib + cp dummy.so $out/lib/ + '''; + }; + } + ''; + }; + + database = { + type = mkOption { + type = types.enum [ "mysql" "pgsql" "sqlite" ]; + example = "mysql"; + default = "pgsql"; + description = "Database engine to use."; + }; + + host = mkOption { + type = types.str; + default = "localhost"; + description = "Database host address."; + }; + + port = mkOption { + type = types.int; + default = if cfg.database.type == "mysql" then mysql.port else pgsql.port; + description = "Database host port."; + }; + + name = mkOption { + type = types.str; + default = "zabbix"; + description = "Database name."; + }; + + user = mkOption { + type = types.str; + default = "zabbix"; + description = "Database user."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/zabbix-dbpassword"; + description = '' + A file containing the password corresponding to + <option>database.user</option>. + ''; + }; + + socket = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/postgresql"; + description = "Path to the unix socket file to use for authentication."; + }; + + createLocally = mkOption { + type = types.bool; + default = true; + description = "Whether to create a local database automatically."; + }; + }; + + listen = { + ip = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + List of comma delimited IP addresses that the trapper should listen on. + Trapper will listen on all network interfaces if this parameter is missing. + ''; + }; + + port = mkOption { + type = types.port; + default = 10051; + description = '' + Listen port for trapper. + ''; + }; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open ports in the firewall for the Zabbix Proxy. + ''; + }; + + # TODO: for bonus points migrate this to https://github.com/NixOS/rfcs/pull/42 + extraConfig = mkOption { + default = ""; + type = types.lines; + description = '' + Configuration that is injected verbatim into the configuration file. Refer to + <link xlink:href="https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_proxy"/> + for details on supported values. + ''; + }; + + }; + + }; + + # implementation + + config = mkIf cfg.enable { + + assertions = [ + { assertion = !config.services.zabbixServer.enable; + message = "Please choose one of services.zabbixServer or services.zabbixProxy."; + } + { assertion = cfg.database.createLocally -> cfg.database.user == user; + message = "services.zabbixProxy.database.user must be set to ${user} if services.zabbixProxy.database.createLocally is set true"; + } + { assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; + message = "a password cannot be specified if services.zabbixProxy.database.createLocally is set to true"; + } + ]; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.listen.port ]; + }; + + services.mysql = optionalAttrs mysqlLocal { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }; + } + ]; + }; + + services.postgresql = optionalAttrs pgsqlLocal { + enable = true; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; }; + } + ]; + }; + + users.users.${user} = { + description = "Zabbix daemon user"; + uid = config.ids.uids.zabbix; + inherit group; + }; + + users.groups.${group} = { + gid = config.ids.gids.zabbix; + }; + + security.wrappers = { + fping.source = "${pkgs.fping}/bin/fping"; + }; + + systemd.services."zabbix-proxy" = { + description = "Zabbix Proxy"; + + wantedBy = [ "multi-user.target" ]; + after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; + + path = [ "/run/wrappers" ] ++ cfg.extraPackages; + preStart = optionalString pgsqlLocal '' + if ! test -e "${stateDir}/db-created"; then + cat ${cfg.package}/share/zabbix/database/postgresql/schema.sql | ${pgsql.package}/bin/psql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/postgresql/images.sql | ${pgsql.package}/bin/psql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/postgresql/data.sql | ${pgsql.package}/bin/psql ${cfg.database.name} + touch "${stateDir}/db-created" + fi + '' + optionalString mysqlLocal '' + if ! test -e "${stateDir}/db-created"; then + cat ${cfg.package}/share/zabbix/database/mysql/schema.sql | ${mysql.package}/bin/mysql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/mysql/images.sql | ${mysql.package}/bin/mysql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/mysql/data.sql | ${mysql.package}/bin/mysql ${cfg.database.name} + touch "${stateDir}/db-created" + fi + '' + optionalString (cfg.database.passwordFile != null) '' + # create a copy of the supplied password file in a format zabbix can consume + touch ${passwordFile} + chmod 0600 ${passwordFile} + echo -n "DBPassword = " > ${passwordFile} + cat ${cfg.database.passwordFile} >> ${passwordFile} + ''; + + serviceConfig = { + ExecStart = "@${cfg.package}/sbin/zabbix_proxy zabbix_proxy -f --config ${configFile}"; + Restart = "always"; + RestartSec = 2; + + User = user; + Group = group; + RuntimeDirectory = "zabbix"; + StateDirectory = "zabbix"; + PrivateTmp = true; + }; + }; + + }; + +} diff --git a/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix b/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix index fdeab6af4417..11311b466c3f 100644 --- a/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix +++ b/nixpkgs/nixos/modules/services/monitoring/zabbix-server.nix @@ -1,125 +1,292 @@ -# Zabbix server daemon. { config, lib, pkgs, ... }: -with lib; - let - cfg = config.services.zabbixServer; + pgsql = config.services.postgresql; + mysql = config.services.mysql; - stateDir = "/run/zabbix"; + inherit (lib) mkDefault mkEnableOption mkIf mkOption; + inherit (lib) attrValues concatMapStringsSep literalExample optional optionalAttrs optionalString types; - logDir = "/var/log/zabbix"; + user = "zabbix"; + group = "zabbix"; + runtimeDir = "/run/zabbix"; + stateDir = "/var/lib/zabbix"; + passwordFile = "${runtimeDir}/zabbix-dbpassword.conf"; - libDir = "/var/lib/zabbix"; + moduleEnv = pkgs.symlinkJoin { + name = "zabbix-server-module-env"; + paths = attrValues cfg.modules; + }; - pidFile = "${stateDir}/zabbix_server.pid"; + configFile = pkgs.writeText "zabbix_server.conf" '' + LogType = console + ListenIP = ${cfg.listen.ip} + ListenPort = ${toString cfg.listen.port} + # TODO: set to cfg.database.socket if database type is pgsql? + DBHost = ${optionalString (cfg.database.createLocally != true) cfg.database.host} + ${optionalString (cfg.database.createLocally != true) "DBPort = ${cfg.database.port}"} + DBName = ${cfg.database.name} + DBUser = ${cfg.database.user} + ${optionalString (cfg.database.passwordFile != null) "Include ${passwordFile}"} + ${optionalString (mysqlLocal && cfg.database.socket != null) "DBSocket = ${cfg.database.socket}"} + SocketDir = ${runtimeDir} + FpingLocation = /run/wrappers/bin/fping + ${optionalString (cfg.modules != {}) "LoadModulePath = ${moduleEnv}/lib"} + ${concatMapStringsSep "\n" (name: "LoadModule = ${name}") (builtins.attrNames cfg.modules)} + ${cfg.extraConfig} + ''; + + mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql"; + pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql"; - configFile = pkgs.writeText "zabbix_server.conf" - '' - LogFile = ${logDir}/zabbix_server +in - PidFile = ${pidFile} +{ + # interface - ${optionalString (cfg.dbServer != "localhost") '' - DBHost = ${cfg.dbServer} - ''} + options = { - DBName = zabbix + services.zabbixServer = { + enable = mkEnableOption "the Zabbix Server"; - DBUser = zabbix + package = mkOption { + type = types.package; + default = if cfg.database.type == "mysql" then pkgs.zabbix.server-mysql else pkgs.zabbix.server-pgsql; + defaultText = "pkgs.zabbix.server-pgsql"; + description = "The Zabbix package to use."; + }; - ${optionalString (cfg.dbPassword != "") '' - DBPassword = ${cfg.dbPassword} - ''} + extraPackages = mkOption { + type = types.listOf types.package; + default = with pkgs; [ nettools nmap traceroute ]; + defaultText = "[ nettools nmap traceroute ]"; + description = '' + Packages to be added to the Zabbix <envar>PATH</envar>. + Typically used to add executables for scripts, but can be anything. + ''; + }; - ${config.services.zabbixServer.extraConfig} - ''; + modules = mkOption { + type = types.attrsOf types.package; + description = "A set of modules to load."; + default = {}; + example = literalExample '' + { + "dummy.so" = pkgs.stdenv.mkDerivation { + name = "zabbix-dummy-module-''${cfg.package.version}"; + src = cfg.package.src; + buildInputs = [ cfg.package ]; + sourceRoot = "zabbix-''${cfg.package.version}/src/modules/dummy"; + installPhase = ''' + mkdir -p $out/lib + cp dummy.so $out/lib/ + '''; + }; + } + ''; + }; - useLocalPostgres = cfg.dbServer == "localhost" || cfg.dbServer == ""; + database = { + type = mkOption { + type = types.enum [ "mysql" "pgsql" ]; + example = "mysql"; + default = "pgsql"; + description = "Database engine to use."; + }; + + host = mkOption { + type = types.str; + default = "localhost"; + description = "Database host address."; + }; + + port = mkOption { + type = types.int; + default = if cfg.database.type == "mysql" then mysql.port else pgsql.port; + description = "Database host port."; + }; + + name = mkOption { + type = types.str; + default = "zabbix"; + description = "Database name."; + }; + + user = mkOption { + type = types.str; + default = "zabbix"; + description = "Database user."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/zabbix-dbpassword"; + description = '' + A file containing the password corresponding to + <option>database.user</option>. + ''; + }; + + socket = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/postgresql"; + description = "Path to the unix socket file to use for authentication."; + }; + + createLocally = mkOption { + type = types.bool; + default = true; + description = "Whether to create a local database automatically."; + }; + }; -in + listen = { + ip = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + List of comma delimited IP addresses that the trapper should listen on. + Trapper will listen on all network interfaces if this parameter is missing. + ''; + }; -{ + port = mkOption { + type = types.port; + default = 10051; + description = '' + Listen port for trapper. + ''; + }; + }; - ###### interface + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open ports in the firewall for the Zabbix Server. + ''; + }; - options = { + # TODO: for bonus points migrate this to https://github.com/NixOS/rfcs/pull/42 + extraConfig = mkOption { + default = ""; + type = types.lines; + description = '' + Configuration that is injected verbatim into the configuration file. Refer to + <link xlink:href="https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_server"/> + for details on supported values. + ''; + }; - services.zabbixServer.enable = mkOption { - default = false; - type = types.bool; - description = '' - Whether to run the Zabbix server on this machine. - ''; }; - services.zabbixServer.dbServer = mkOption { - default = "localhost"; - type = types.str; - description = '' - Hostname or IP address of the database server. - Use an empty string ("") to use peer authentication. - ''; - }; + }; - services.zabbixServer.dbPassword = mkOption { - default = ""; - type = types.str; - description = "Password used to connect to the database server."; - }; + # implementation - services.zabbixServer.extraConfig = mkOption { - default = ""; - type = types.lines; - description = '' - Configuration that is injected verbatim into the configuration file. - ''; + config = mkIf cfg.enable { + + assertions = [ + { assertion = cfg.database.createLocally -> cfg.database.user == user; + message = "services.zabbixServer.database.user must be set to ${user} if services.zabbixServer.database.createLocally is set true"; + } + { assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; + message = "a password cannot be specified if services.zabbixServer.database.createLocally is set to true"; + } + ]; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.listen.port ]; }; - }; + services.mysql = optionalAttrs mysqlLocal { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }; + } + ]; + }; - ###### implementation + services.postgresql = optionalAttrs pgsqlLocal { + enable = true; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; }; + } + ]; + }; - config = mkIf cfg.enable { + users.users.${user} = { + description = "Zabbix daemon user"; + uid = config.ids.uids.zabbix; + inherit group; + }; - services.postgresql.enable = useLocalPostgres; + users.groups.${group} = { + gid = config.ids.gids.zabbix; + }; - users.users = singleton - { name = "zabbix"; - uid = config.ids.uids.zabbix; - description = "Zabbix daemon user"; - }; + security.wrappers = { + fping.source = "${pkgs.fping}/bin/fping"; + }; - systemd.services."zabbix-server" = - { description = "Zabbix Server"; - - wantedBy = [ "multi-user.target" ]; - after = optional useLocalPostgres "postgresql.service"; - - preStart = - '' - mkdir -m 0755 -p ${stateDir} ${logDir} ${libDir} - chown zabbix ${stateDir} ${logDir} ${libDir} - - if ! test -e "${libDir}/db-created"; then - ${pkgs.su}/bin/su -s "$SHELL" ${config.services.postgresql.superUser} -c '${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole zabbix' || true - ${pkgs.su}/bin/su -s "$SHELL" ${config.services.postgresql.superUser} -c '${pkgs.postgresql}/bin/createdb --owner zabbix zabbix' || true - cat ${pkgs.zabbix.server}/share/zabbix/db/schema/postgresql.sql | ${pkgs.su}/bin/su -s "$SHELL" zabbix -c '${pkgs.postgresql}/bin/psql zabbix' - cat ${pkgs.zabbix.server}/share/zabbix/db/data/images_pgsql.sql | ${pkgs.su}/bin/su -s "$SHELL" zabbix -c '${pkgs.postgresql}/bin/psql zabbix' - cat ${pkgs.zabbix.server}/share/zabbix/db/data/data.sql | ${pkgs.su}/bin/su -s "$SHELL" zabbix -c '${pkgs.postgresql}/bin/psql zabbix' - touch "${libDir}/db-created" - fi - ''; + systemd.services."zabbix-server" = { + description = "Zabbix Server"; + + wantedBy = [ "multi-user.target" ]; + after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; + + path = [ "/run/wrappers" ] ++ cfg.extraPackages; + preStart = '' + # pre 19.09 compatibility + if test -e "${runtimeDir}/db-created"; then + mv "${runtimeDir}/db-created" "${stateDir}/" + fi + '' + optionalString pgsqlLocal '' + if ! test -e "${stateDir}/db-created"; then + cat ${cfg.package}/share/zabbix/database/postgresql/schema.sql | ${pgsql.package}/bin/psql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/postgresql/images.sql | ${pgsql.package}/bin/psql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/postgresql/data.sql | ${pgsql.package}/bin/psql ${cfg.database.name} + touch "${stateDir}/db-created" + fi + '' + optionalString mysqlLocal '' + if ! test -e "${stateDir}/db-created"; then + cat ${cfg.package}/share/zabbix/database/mysql/schema.sql | ${mysql.package}/bin/mysql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/mysql/images.sql | ${mysql.package}/bin/mysql ${cfg.database.name} + cat ${cfg.package}/share/zabbix/database/mysql/data.sql | ${mysql.package}/bin/mysql ${cfg.database.name} + touch "${stateDir}/db-created" + fi + '' + optionalString (cfg.database.passwordFile != null) '' + # create a copy of the supplied password file in a format zabbix can consume + touch ${passwordFile} + chmod 0600 ${passwordFile} + echo -n "DBPassword = " > ${passwordFile} + cat ${cfg.database.passwordFile} >> ${passwordFile} + ''; - path = [ pkgs.nettools ]; + serviceConfig = { + ExecStart = "@${cfg.package}/sbin/zabbix_server zabbix_server -f --config ${configFile}"; + Restart = "always"; + RestartSec = 2; - serviceConfig.ExecStart = "@${pkgs.zabbix.server}/sbin/zabbix_server zabbix_server --config ${configFile}"; - serviceConfig.Type = "forking"; - serviceConfig.Restart = "always"; - serviceConfig.RestartSec = 2; - serviceConfig.PIDFile = pidFile; + User = user; + Group = group; + RuntimeDirectory = "zabbix"; + StateDirectory = "zabbix"; + PrivateTmp = true; }; + }; + + systemd.services.httpd.after = + optional (config.services.zabbixWeb.enable && mysqlLocal) "mysql.service" ++ + optional (config.services.zabbixWeb.enable && pgsqlLocal) "postgresql.service"; }; diff --git a/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix index 7b2eea3b5850..263b70d04a56 100644 --- a/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix +++ b/nixpkgs/nixos/modules/services/network-filesystems/kbfs.nix @@ -48,6 +48,7 @@ in { requires = [ "keybase.service" ]; after = [ "keybase.service" ]; path = [ "/run/wrappers" ]; + unitConfig.ConditionUser = "!@system"; serviceConfig = { ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${cfg.mountPoint}"; ExecStart = "${pkgs.kbfs}/bin/kbfsfuse ${toString cfg.extraFlags} ${cfg.mountPoint}"; diff --git a/nixpkgs/nixos/modules/services/networking/bind.nix b/nixpkgs/nixos/modules/services/networking/bind.nix index 7f89cff22329..06af4dbcca4e 100644 --- a/nixpkgs/nixos/modules/services/networking/bind.nix +++ b/nixpkgs/nixos/modules/services/networking/bind.nix @@ -33,7 +33,7 @@ let ${cfg.extraConfig} ${ concatMapStrings - ({ name, file, master ? true, slaves ? [], masters ? [] }: + ({ name, file, master ? true, slaves ? [], masters ? [], extraConfig ? "" }: '' zone "${name}" { type ${if master then "master" else "slave"}; @@ -52,6 +52,7 @@ let '' } allow-query { any; }; + ${extraConfig} }; '') cfg.zones } @@ -131,6 +132,7 @@ in file = "/var/dns/example.com"; masters = ["192.168.0.1"]; slaves = []; + extraConfig = ""; }]; }; @@ -168,7 +170,9 @@ in ###### implementation - config = mkIf config.services.bind.enable { + config = mkIf cfg.enable { + + networking.resolvconf.useLocalResolver = mkDefault true; users.users = singleton { name = bindUser; diff --git a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix index c217ccaa405a..7b2786034552 100644 --- a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix +++ b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix @@ -162,7 +162,7 @@ in wantedBy = [ "multi-user.target" ] ++ optional (!hasDefaultGatewaySet) "network-online.target"; wants = [ "network.target" "systemd-udev-settle.service" ]; - before = [ "network.target" ]; + before = [ "network-online.target" ]; after = [ "systemd-udev-settle.service" ]; # Stopping dhcpcd during a reconfiguration is undesirable diff --git a/nixpkgs/nixos/modules/services/networking/dnsmasq.nix b/nixpkgs/nixos/modules/services/networking/dnsmasq.nix index 24d16046c63e..714a5903bff1 100644 --- a/nixpkgs/nixos/modules/services/networking/dnsmasq.nix +++ b/nixpkgs/nixos/modules/services/networking/dnsmasq.nix @@ -79,7 +79,7 @@ in ###### implementation - config = mkIf config.services.dnsmasq.enable { + config = mkIf cfg.enable { networking.nameservers = optional cfg.resolveLocalQueries "127.0.0.1"; @@ -92,6 +92,15 @@ in description = "Dnsmasq daemon user"; }; + networking.resolvconf = mkIf cfg.resolveLocalQueries { + useLocalResolver = mkDefault true; + + extraConfig = '' + dnsmasq_conf=/etc/dnsmasq-conf.conf + dnsmasq_resolv=/etc/dnsmasq-resolv.conf + ''; + }; + systemd.services.dnsmasq = { description = "Dnsmasq Daemon"; after = [ "network.target" "systemd-resolved.service" ]; diff --git a/nixpkgs/nixos/modules/services/networking/keybase.nix b/nixpkgs/nixos/modules/services/networking/keybase.nix index a149f16a84cb..85f52be8a6ac 100644 --- a/nixpkgs/nixos/modules/services/networking/keybase.nix +++ b/nixpkgs/nixos/modules/services/networking/keybase.nix @@ -26,6 +26,7 @@ in { systemd.user.services.keybase = { description = "Keybase service"; + unitConfig.ConditionUser = "!@system"; serviceConfig = { ExecStart = '' ${pkgs.keybase}/bin/keybase service --auto-forked diff --git a/nixpkgs/nixos/modules/services/networking/kresd.nix b/nixpkgs/nixos/modules/services/networking/kresd.nix index ca34ff9df4ef..fc516c01230a 100644 --- a/nixpkgs/nixos/modules/services/networking/kresd.nix +++ b/nixpkgs/nixos/modules/services/networking/kresd.nix @@ -80,8 +80,11 @@ in # Syntax depends on being IPv6 or IPv4. (iface: if elem ":" (stringToCharacters iface) then "[${iface}]:53" else "${iface}:53") cfg.interfaces; - socketConfig.ListenDatagram = listenStreams; - socketConfig.FreeBind = true; + socketConfig = { + ListenDatagram = listenStreams; + FreeBind = true; + FileDescriptorName = "dns"; + }; }; systemd.sockets.kresd-tls = mkIf (cfg.listenTLS != []) rec { diff --git a/nixpkgs/nixos/modules/services/networking/networkmanager.nix b/nixpkgs/nixos/modules/services/networking/networkmanager.nix index f1f8c9722e02..551636a33d25 100644 --- a/nixpkgs/nixos/modules/services/networking/networkmanager.nix +++ b/nixpkgs/nixos/modules/services/networking/networkmanager.nix @@ -1,6 +1,5 @@ { config, lib, pkgs, ... }: -with pkgs; with lib; let @@ -12,12 +11,13 @@ let # /var/lib/misc is for dnsmasq.leases. stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc"; - configFile = writeText "NetworkManager.conf" '' + configFile = pkgs.writeText "NetworkManager.conf" '' [main] plugins=keyfile dhcp=${cfg.dhcp} dns=${cfg.dns} - rc-manager=${cfg.rc-manager} + # If resolvconf is disabled that means that resolv.conf is managed by some other module. + rc-manager=${if config.networking.resolvconf.enable then "resolvconf" else "unmanaged"} [keyfile] ${optionalString (cfg.unmanaged != []) @@ -65,19 +65,19 @@ let }); ''; - ns = xs: writeText "nameservers" ( + ns = xs: pkgs.writeText "nameservers" ( concatStrings (map (s: "nameserver ${s}\n") xs) ); - overrideNameserversScript = writeScript "02overridedns" '' + overrideNameserversScript = pkgs.writeScript "02overridedns" '' #!/bin/sh - tmp=`${coreutils}/bin/mktemp` - ${gnused}/bin/sed '/nameserver /d' /etc/resolv.conf > $tmp - ${gnugrep}/bin/grep 'nameserver ' /etc/resolv.conf | \ - ${gnugrep}/bin/grep -vf ${ns (cfg.appendNameservers ++ cfg.insertNameservers)} > $tmp.ns - ${optionalString (cfg.appendNameservers != []) "${coreutils}/bin/cat $tmp $tmp.ns ${ns cfg.appendNameservers} > /etc/resolv.conf"} - ${optionalString (cfg.insertNameservers != []) "${coreutils}/bin/cat $tmp ${ns cfg.insertNameservers} $tmp.ns > /etc/resolv.conf"} - ${coreutils}/bin/rm -f $tmp $tmp.ns + PATH=${with pkgs; makeBinPath [ gnused gnugrep coreutils ]} + tmp=$(mktemp) + sed '/nameserver /d' /etc/resolv.conf > $tmp + grep 'nameserver ' /etc/resolv.conf | \ + grep -vf ${ns (cfg.appendNameservers ++ cfg.insertNameservers)} > $tmp.ns + cat $tmp ${ns cfg.insertNameservers} $tmp.ns ${ns cfg.appendNameservers} > /etc/resolv.conf + rm -f $tmp $tmp.ns ''; dispatcherTypesSubdirMap = { @@ -176,7 +176,8 @@ in { # Ugly hack for using the correct gnome3 packageSet basePackages = mkOption { type = types.attrsOf types.package; - default = { inherit networkmanager modemmanager wpa_supplicant + default = { inherit (pkgs) + networkmanager modemmanager wpa_supplicant crda networkmanager-openvpn networkmanager-vpnc networkmanager-openconnect networkmanager-fortisslvpn networkmanager-l2tp networkmanager-iodine; }; @@ -268,25 +269,6 @@ in { ''; }; - rc-manager = mkOption { - type = types.enum [ "symlink" "file" "resolvconf" "netconfig" "unmanaged" "none" ]; - default = "resolvconf"; - description = '' - Set the <literal>resolv.conf</literal> management mode. - </para> - <para> - A description of these modes can be found in the main section of - <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html"> - https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html - </link> - or in - <citerefentry> - <refentrytitle>NetworkManager.conf</refentrytitle> - <manvolnum>5</manvolnum> - </citerefentry>. - ''; - }; - dispatcherScripts = mkOption { type = types.listOf (types.submodule { options = { @@ -425,13 +407,10 @@ in { { source = "${networkmanager-l2tp}/lib/NetworkManager/VPN/nm-l2tp-service.name"; target = "NetworkManager/VPN/nm-l2tp-service.name"; } - { source = "${networkmanager_strongswan}/lib/NetworkManager/VPN/nm-strongswan-service.name"; - target = "NetworkManager/VPN/nm-strongswan-service.name"; - } { source = "${networkmanager-iodine}/lib/NetworkManager/VPN/nm-iodine-service.name"; target = "NetworkManager/VPN/nm-iodine-service.name"; } - ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == []) + ] ++ optional (cfg.appendNameservers != [] || cfg.insertNameservers != []) { source = overrideNameserversScript; target = "NetworkManager/dispatcher.d/02overridedns"; } @@ -440,11 +419,15 @@ in { target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; mode = "0544"; }) cfg.dispatcherScripts - ++ optional (dynamicHostsEnabled) + ++ optional dynamicHostsEnabled { target = "NetworkManager/dnsmasq.d/dyndns.conf"; text = concatMapStrings (n: '' hostsdir=/run/NetworkManager/hostsdirs/${n} '') (attrNames cfg.dynamicHosts.hostsDirs); + } + ++ optional cfg.enableStrongSwan + { source = "${pkgs.networkmanager_strongswan}/lib/NetworkManager/VPN/nm-strongswan-service.name"; + target = "NetworkManager/VPN/nm-strongswan-service.name"; }; environment.systemPackages = cfg.packages; @@ -512,7 +495,7 @@ in { networking = { useDHCP = false; # use mkDefault to trigger the assertion about the conflict above - wireless.enable = lib.mkDefault false; + wireless.enable = mkDefault false; }; security.polkit.extraConfig = polkitConf; diff --git a/nixpkgs/nixos/modules/services/networking/rdnssd.nix b/nixpkgs/nixos/modules/services/networking/rdnssd.nix index 887772f6e5f0..bccab805beeb 100644 --- a/nixpkgs/nixos/modules/services/networking/rdnssd.nix +++ b/nixpkgs/nixos/modules/services/networking/rdnssd.nix @@ -35,6 +35,11 @@ in config = mkIf config.services.rdnssd.enable { + assertions = [{ + assertion = config.networking.resolvconf.enable; + message = "rdnssd needs resolvconf to work (probably something sets up a static resolv.conf)"; + }]; + systemd.services.rdnssd = { description = "RDNSS daemon"; after = [ "network.target" ]; diff --git a/nixpkgs/nixos/modules/services/networking/syncthing.nix b/nixpkgs/nixos/modules/services/networking/syncthing.nix index d78a54a3327b..126f5b7b527b 100644 --- a/nixpkgs/nixos/modules/services/networking/syncthing.nix +++ b/nixpkgs/nixos/modules/services/networking/syncthing.nix @@ -291,7 +291,7 @@ in { group = mkOption { type = types.str; - default = "nogroup"; + default = defaultUser; description = '' Syncthing will be run under this group (group will not be created if it doesn't exist. This can be your user name). @@ -372,16 +372,18 @@ in { systemd.packages = [ pkgs.syncthing ]; - users = mkIf (cfg.systemService && cfg.user == defaultUser) { - users."${defaultUser}" = + users.users = mkIf (cfg.systemService && cfg.user == defaultUser) { + "${defaultUser}" = { group = cfg.group; home = cfg.dataDir; createHome = true; uid = config.ids.uids.syncthing; description = "Syncthing daemon user"; }; + }; - groups."${defaultUser}".gid = + users.groups = mkIf (cfg.systemService && cfg.group == defaultUser) { + "${defaultUser}".gid = config.ids.gids.syncthing; }; @@ -403,18 +405,12 @@ in { Group = cfg.group; ExecStartPre = mkIf (cfg.declarative.cert != null || cfg.declarative.key != null) "+${pkgs.writers.writeBash "syncthing-copy-keys" '' - mkdir -p ${cfg.configDir} - chown ${cfg.user}:${cfg.group} ${cfg.configDir} - chmod 700 ${cfg.configDir} + install -dm700 -o ${cfg.user} -g ${cfg.group} ${cfg.configDir} ${optionalString (cfg.declarative.cert != null) '' - cp ${toString cfg.declarative.cert} ${cfg.configDir}/cert.pem - chown ${cfg.user}:${cfg.group} ${cfg.configDir}/cert.pem - chmod 400 ${cfg.configDir}/cert.pem + install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.declarative.cert} ${cfg.configDir}/cert.pem ''} ${optionalString (cfg.declarative.key != null) '' - cp ${toString cfg.declarative.key} ${cfg.configDir}/key.pem - chown ${cfg.user}:${cfg.group} ${cfg.configDir}/key.pem - chmod 400 ${cfg.configDir}/key.pem + install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.declarative.key} ${cfg.configDir}/key.pem ''} ''}" ; diff --git a/nixpkgs/nixos/modules/services/networking/thelounge.nix b/nixpkgs/nixos/modules/services/networking/thelounge.nix new file mode 100644 index 000000000000..b1d23372955e --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/thelounge.nix @@ -0,0 +1,75 @@ +{ pkgs, lib, config, ... }: + +with lib; + +let + cfg = config.services.thelounge; + dataDir = "/var/lib/thelounge"; + configJsData = "module.exports = " + builtins.toJSON ( + { private = cfg.private; port = cfg.port; } // cfg.extraConfig + ); +in { + options.services.thelounge = { + enable = mkEnableOption "The Lounge web IRC client"; + + private = mkOption { + type = types.bool; + default = false; + description = '' + Make your The Lounge instance private. You will need to configure user + accounts by using the (<command>thelounge</command>) command or by adding + entries in <filename>${dataDir}/users</filename>. You might need to restart + The Lounge after making changes to the state directory. + ''; + }; + + port = mkOption { + type = types.port; + default = 9000; + description = "TCP port to listen on for http connections."; + }; + + extraConfig = mkOption { + default = {}; + type = types.attrs; + example = literalExample ''{ + reverseProxy = true; + defaults = { + name = "Your Network"; + host = "localhost"; + port = 6697; + }; + }''; + description = '' + The Lounge's <filename>config.js</filename> contents as attribute set (will be + converted to JSON to generate the configuration file). + + The options defined here will be merged to the default configuration file. + Note: In case of duplicate configuration, options from <option>extraConfig</option> have priority. + + Documentation: <link xlink:href="https://thelounge.chat/docs/server/configuration" /> + ''; + }; + }; + + config = mkIf cfg.enable { + users.users.thelounge = { + description = "thelounge service user"; + group = "thelounge"; + }; + users.groups.thelounge = {}; + systemd.services.thelounge = { + description = "The Lounge web IRC client"; + wantedBy = [ "multi-user.target" ]; + environment = { THELOUNGE_HOME = dataDir; }; + preStart = "ln -sf ${pkgs.writeText "config.js" configJsData} ${dataDir}/config.js"; + serviceConfig = { + User = "thelounge"; + StateDirectory = baseNameOf dataDir; + ExecStart = "${pkgs.thelounge}/bin/thelounge start"; + }; + }; + + environment.systemPackages = [ pkgs.thelounge ]; + }; +} diff --git a/nixpkgs/nixos/modules/services/networking/unbound.nix b/nixpkgs/nixos/modules/services/networking/unbound.nix index 1a35979ad44c..3cf82e8839bb 100644 --- a/nixpkgs/nixos/modules/services/networking/unbound.nix +++ b/nixpkgs/nixos/modules/services/networking/unbound.nix @@ -101,6 +101,8 @@ in isSystemUser = true; }; + networking.resolvconf.useLocalResolver = mkDefault true; + systemd.services.unbound = { description = "Unbound recursive Domain Name Server"; after = [ "network.target" ]; diff --git a/nixpkgs/nixos/modules/services/networking/unifi.nix b/nixpkgs/nixos/modules/services/networking/unifi.nix index 9057a1e12b33..6239c88b7e41 100644 --- a/nixpkgs/nixos/modules/services/networking/unifi.nix +++ b/nixpkgs/nixos/modules/services/networking/unifi.nix @@ -148,7 +148,7 @@ in systemd.tmpfiles.rules = [ "e '${stateDir}' 0700 unifi - - -" - "e '${stateDir}/data' 0700 unifi - - -" + "d '${stateDir}/data' 0700 unifi - - -" ]; systemd.services.unifi = { diff --git a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix index 0bd9edf4a41c..63e59e7c8fac 100644 --- a/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix @@ -204,6 +204,7 @@ in { environment.systemPackages = [ pkgs.wpa_supplicant ]; services.dbus.packages = [ pkgs.wpa_supplicant ]; + services.udev.packages = [ pkgs.crda ]; # FIXME: start a separate wpa_supplicant instance per interface. systemd.services.wpa_supplicant = let diff --git a/nixpkgs/nixos/modules/services/security/sshguard.nix b/nixpkgs/nixos/modules/services/security/sshguard.nix index 3892cd5c72b8..25cec5b5b105 100644 --- a/nixpkgs/nixos/modules/services/security/sshguard.nix +++ b/nixpkgs/nixos/modules/services/security/sshguard.nix @@ -107,8 +107,6 @@ in { path = with pkgs; [ iptables ipset iproute systemd ]; postStart = '' - ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard4 hash:ip family inet - ${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:ip family inet6 ${pkgs.iptables}/bin/iptables -I INPUT -m set --match-set sshguard4 src -j DROP ${pkgs.iptables}/bin/ip6tables -I INPUT -m set --match-set sshguard6 src -j DROP ''; diff --git a/nixpkgs/nixos/modules/services/security/tor.nix b/nixpkgs/nixos/modules/services/security/tor.nix index 6f4852c3ba1a..abdc0cd78b4d 100644 --- a/nixpkgs/nixos/modules/services/security/tor.nix +++ b/nixpkgs/nixos/modules/services/security/tor.nix @@ -81,7 +81,7 @@ let ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) '' BridgeRelay 1 - ServerTransportPlugin ${concatStringsSep "," cfg.relay.bridgeTransports} exec ${obfs4}/bin/obfs4proxy managed + ServerTransportPlugin ${concatStringsSep "," cfg.relay.bridgeTransports} exec ${pkgs.obfs4}/bin/obfs4proxy managed ExtORPort auto ${optionalString (cfg.relay.role == "private-bridge") '' ExtraInfoStatistics 0 diff --git a/nixpkgs/nixos/modules/services/system/nscd.conf b/nixpkgs/nixos/modules/services/system/nscd.conf index 603a5d01acce..2b7523a7346d 100644 --- a/nixpkgs/nixos/modules/services/system/nscd.conf +++ b/nixpkgs/nixos/modules/services/system/nscd.conf @@ -7,46 +7,28 @@ # is not aware of the path in which the nss modules live. As a workaround, we # have `enable-cache yes` with an explicit ttl of 0 server-user nscd -threads 1 -paranoia no -debug-level 0 enable-cache passwd yes positive-time-to-live passwd 0 negative-time-to-live passwd 0 -suggested-size passwd 211 -check-files passwd yes -persistent passwd no shared passwd yes enable-cache group yes positive-time-to-live group 0 negative-time-to-live group 0 -suggested-size group 211 -check-files group yes -persistent group no shared group yes enable-cache netgroup yes positive-time-to-live netgroup 0 negative-time-to-live netgroup 0 -suggested-size netgroup 211 -check-files netgroup yes -persistent netgroup no shared netgroup yes enable-cache hosts yes positive-time-to-live hosts 600 negative-time-to-live hosts 0 -suggested-size hosts 211 -check-files hosts yes -persistent hosts no shared hosts yes enable-cache services yes positive-time-to-live services 0 negative-time-to-live services 0 -suggested-size services 211 -check-files services yes -persistent services no shared services yes diff --git a/nixpkgs/nixos/modules/services/system/nscd.nix b/nixpkgs/nixos/modules/services/system/nscd.nix index fd1570d11980..e11f7e049d8f 100644 --- a/nixpkgs/nixos/modules/services/system/nscd.nix +++ b/nixpkgs/nixos/modules/services/system/nscd.nix @@ -39,11 +39,6 @@ in config = mkIf cfg.enable { environment.etc."nscd.conf".text = cfg.config; - users.users.nscd = - { isSystemUser = true; - description = "Name service cache daemon user"; - }; - systemd.services.nscd = { description = "Name Service Cache Daemon"; @@ -51,22 +46,23 @@ in environment = { LD_LIBRARY_PATH = nssModulesPath; }; - preStart = - '' - mkdir -m 0755 -p /run/nscd - rm -f /run/nscd/nscd.pid - mkdir -m 0755 -p /var/db/nscd - ''; - restartTriggers = [ config.environment.etc.hosts.source config.environment.etc."nsswitch.conf".source config.environment.etc."nscd.conf".source ]; + # We use DynamicUser because in default configurations nscd doesn't + # create any files that need to survive restarts. However, in some + # configurations, nscd needs to be started as root; it will drop + # privileges after all the NSS modules have read their configuration + # files. So prefix the ExecStart command with "!" to prevent systemd + # from dropping privileges early. See ExecStart in systemd.service(5). serviceConfig = - { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd"; + { ExecStart = "!@${pkgs.glibc.bin}/sbin/nscd nscd"; Type = "forking"; + DynamicUser = true; + RuntimeDirectory = "nscd"; PIDFile = "/run/nscd/nscd.pid"; Restart = "always"; ExecReload = @@ -75,15 +71,6 @@ in "${pkgs.glibc.bin}/sbin/nscd --invalidate hosts" ]; }; - - # Urgggggh... Nscd forks before opening its socket and writing - # its pid. So wait until it's ready. - postStart = - '' - while ! ${pkgs.glibc.bin}/sbin/nscd -g > /dev/null; do - sleep 0.2 - done - ''; }; }; diff --git a/nixpkgs/nixos/modules/services/torrent/deluge.nix b/nixpkgs/nixos/modules/services/torrent/deluge.nix index 01a5890a7845..48ec4d692e2f 100644 --- a/nixpkgs/nixos/modules/services/torrent/deluge.nix +++ b/nixpkgs/nixos/modules/services/torrent/deluge.nix @@ -118,36 +118,74 @@ in { more informations. ''; }; + + user = mkOption { + type = types.str; + default = "deluge"; + description = '' + User account under which deluge runs. + ''; + }; + + group = mkOption { + type = types.str; + default = "deluge"; + description = '' + Group under which deluge runs. + ''; + }; + + extraPackages = mkOption { + type = types.listOf types.package; + default = []; + description = '' + Extra packages available at runtime to enable Deluge's plugins. For example, + extraction utilities are required for the built-in "Extractor" plugin. + This always contains unzip, gnutar, xz, p7zip and bzip2. + ''; + }; }; deluge.web = { enable = mkEnableOption "Deluge Web daemon"; + port = mkOption { - type = types.port; + type = types.port; default = 8112; description = '' Deluge web UI port. ''; }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open ports in the firewall for deluge web daemon + ''; + }; }; }; }; config = mkIf cfg.enable { - systemd.tmpfiles.rules = [ "d '${configDir}' 0770 deluge deluge" ] + # Provide a default set of `extraPackages`. + services.deluge.extraPackages = with pkgs; [ unzip gnutar xz p7zip bzip2 ]; + + systemd.tmpfiles.rules = [ "d '${configDir}' 0770 ${cfg.user} ${cfg.group}" ] ++ optional (cfg.config ? "download_location") - "d '${cfg.config.download_location}' 0770 deluge deluge" + "d '${cfg.config.download_location}' 0770 ${cfg.user} ${cfg.group}" ++ optional (cfg.config ? "torrentfiles_location") - "d '${cfg.config.torrentfiles_location}' 0770 deluge deluge" + "d '${cfg.config.torrentfiles_location}' 0770 ${cfg.user} ${cfg.group}" ++ optional (cfg.config ? "move_completed_path") - "d '${cfg.config.move_completed_path}' 0770 deluge deluge"; + "d '${cfg.config.move_completed_path}' 0770 ${cfg.user} ${cfg.group}"; systemd.services.deluged = { after = [ "network.target" ]; description = "Deluge BitTorrent Daemon"; wantedBy = [ "multi-user.target" ]; - path = [ pkgs.deluge ]; + path = [ pkgs.deluge ] ++ cfg.extraPackages; serviceConfig = { ExecStart = '' ${pkgs.deluge}/bin/deluged \ @@ -157,8 +195,8 @@ in { # To prevent "Quit & shutdown daemon" from working; we want systemd to # manage it! Restart = "on-success"; - User = "deluge"; - Group = "deluge"; + User = cfg.user; + Group = cfg.group; UMask = "0002"; LimitNOFILE = cfg.openFilesLimit; }; @@ -177,26 +215,37 @@ in { --config ${configDir} \ --port ${toString cfg.web.port} ''; - User = "deluge"; - Group = "deluge"; + User = cfg.user; + Group = cfg.group; }; }; - networking.firewall = mkIf (cfg.declarative && cfg.openFirewall && !(cfg.config.random_port or true)) { - allowedTCPPortRanges = singleton (listToRange (cfg.config.listen_ports or listenPortsDefault)); - allowedUDPPortRanges = singleton (listToRange (cfg.config.listen_ports or listenPortsDefault)); - }; + networking.firewall = mkMerge [ + (mkIf (cfg.declarative && cfg.openFirewall && !(cfg.config.random_port or true)) { + allowedTCPPortRanges = singleton (listToRange (cfg.config.listen_ports or listenPortsDefault)); + allowedUDPPortRanges = singleton (listToRange (cfg.config.listen_ports or listenPortsDefault)); + }) + (mkIf (cfg.web.openFirewall) { + allowedTCPPorts = [ cfg.web.port ]; + }) + ]; environment.systemPackages = [ pkgs.deluge ]; - users.users.deluge = { - group = "deluge"; - uid = config.ids.uids.deluge; - home = cfg.dataDir; - createHome = true; - description = "Deluge Daemon user"; + users.users = mkIf (cfg.user == "deluge") { + deluge = { + group = cfg.group; + uid = config.ids.uids.deluge; + home = cfg.dataDir; + createHome = true; + description = "Deluge Daemon user"; + }; }; - users.groups.deluge.gid = config.ids.gids.deluge; + users.groups = mkIf (cfg.group == "deluge") { + deluge = { + gid = config.ids.gids.deluge; + }; + }; }; } diff --git a/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix b/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix new file mode 100644 index 000000000000..5bd5977e592b --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix @@ -0,0 +1,473 @@ +{ config, pkgs, lib, ... }: + +let + + inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption; + inherit (lib) concatStringsSep literalExample mapAttrsToList optional optionals optionalString types; + + cfg = config.services.mediawiki; + fpm = config.services.phpfpm.pools.mediawiki; + user = "mediawiki"; + group = config.services.httpd.group; + cacheDir = "/var/cache/mediawiki"; + stateDir = "/var/lib/mediawiki"; + + pkg = pkgs.stdenv.mkDerivation rec { + pname = "mediawiki-full"; + version = src.version; + src = cfg.package; + + installPhase = '' + mkdir -p $out + cp -r * $out/ + + rm -rf $out/share/mediawiki/skins/* + rm -rf $out/share/mediawiki/extensions/* + + ${concatStringsSep "\n" (mapAttrsToList (k: v: '' + ln -s ${v} $out/share/mediawiki/skins/${k} + '') cfg.skins)} + + ${concatStringsSep "\n" (mapAttrsToList (k: v: '' + ln -s ${v} $out/share/mediawiki/extensions/${k} + '') cfg.extensions)} + ''; + }; + + mediawikiScripts = pkgs.runCommand "mediawiki-scripts" { + buildInputs = [ pkgs.makeWrapper ]; + preferLocalBuild = true; + } '' + mkdir -p $out/bin + for i in changePassword.php createAndPromote.php userOptions.php edit.php nukePage.php update.php; do + makeWrapper ${pkgs.php}/bin/php $out/bin/mediawiki-$(basename $i .php) \ + --set MEDIAWIKI_CONFIG ${mediawikiConfig} \ + --add-flags ${pkg}/share/mediawiki/maintenance/$i + done + ''; + + mediawikiConfig = pkgs.writeText "LocalSettings.php" '' + <?php + # Protect against web entry + if ( !defined( 'MEDIAWIKI' ) ) { + exit; + } + + $wgSitename = "${cfg.name}"; + $wgMetaNamespace = false; + + ## The URL base path to the directory containing the wiki; + ## defaults for all runtime URL paths are based off of this. + ## For more information on customizing the URLs + ## (like /w/index.php/Page_title to /wiki/Page_title) please see: + ## https://www.mediawiki.org/wiki/Manual:Short_URL + $wgScriptPath = ""; + + ## The protocol and server name to use in fully-qualified URLs + $wgServer = "${if cfg.virtualHost.enableSSL then "https" else "http"}://${cfg.virtualHost.hostName}"; + + ## The URL path to static resources (images, scripts, etc.) + $wgResourceBasePath = $wgScriptPath; + + ## The URL path to the logo. Make sure you change this from the default, + ## or else you'll overwrite your logo when you upgrade! + $wgLogo = "$wgResourceBasePath/resources/assets/wiki.png"; + + ## UPO means: this is also a user preference option + + $wgEnableEmail = true; + $wgEnableUserEmail = true; # UPO + + $wgEmergencyContact = "${if cfg.virtualHost.adminAddr != null then cfg.virtualHost.adminAddr else config.services.httpd.adminAddr}"; + $wgPasswordSender = $wgEmergencyContact; + + $wgEnotifUserTalk = false; # UPO + $wgEnotifWatchlist = false; # UPO + $wgEmailAuthentication = true; + + ## Database settings + $wgDBtype = "${cfg.database.type}"; + $wgDBserver = "${cfg.database.host}:${if cfg.database.socket != null then cfg.database.socket else toString cfg.database.port}"; + $wgDBname = "${cfg.database.name}"; + $wgDBuser = "${cfg.database.user}"; + ${optionalString (cfg.database.passwordFile != null) "$wgDBpassword = file_get_contents(\"${cfg.database.passwordFile}\");"} + + ${optionalString (cfg.database.type == "mysql" && cfg.database.tablePrefix != null) '' + # MySQL specific settings + $wgDBprefix = "${cfg.database.tablePrefix}"; + ''} + + ${optionalString (cfg.database.type == "mysql") '' + # MySQL table options to use during installation or update + $wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary"; + ''} + + ## Shared memory settings + $wgMainCacheType = CACHE_NONE; + $wgMemCachedServers = []; + + ${optionalString (cfg.uploadsDir != null) '' + $wgEnableUploads = true; + $wgUploadDirectory = "${cfg.uploadsDir}"; + ''} + + $wgUseImageMagick = true; + $wgImageMagickConvertCommand = "${pkgs.imagemagick}/bin/convert"; + + # InstantCommons allows wiki to use images from https://commons.wikimedia.org + $wgUseInstantCommons = false; + + # Periodically send a pingback to https://www.mediawiki.org/ with basic data + # about this MediaWiki instance. The Wikimedia Foundation shares this data + # with MediaWiki developers to help guide future development efforts. + $wgPingback = true; + + ## If you use ImageMagick (or any other shell command) on a + ## Linux server, this will need to be set to the name of an + ## available UTF-8 locale + $wgShellLocale = "C.UTF-8"; + + ## Set $wgCacheDirectory to a writable directory on the web server + ## to make your wiki go slightly faster. The directory should not + ## be publically accessible from the web. + $wgCacheDirectory = "${cacheDir}"; + + # Site language code, should be one of the list in ./languages/data/Names.php + $wgLanguageCode = "en"; + + $wgSecretKey = file_get_contents("${stateDir}/secret.key"); + + # Changing this will log out all existing sessions. + $wgAuthenticationTokenVersion = ""; + + ## For attaching licensing metadata to pages, and displaying an + ## appropriate copyright notice / icon. GNU Free Documentation + ## License and Creative Commons licenses are supported so far. + $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright + $wgRightsUrl = ""; + $wgRightsText = ""; + $wgRightsIcon = ""; + + # Path to the GNU diff3 utility. Used for conflict resolution. + $wgDiff = "${pkgs.diffutils}/bin/diff"; + $wgDiff3 = "${pkgs.diffutils}/bin/diff3"; + + # Enabled skins. + ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadSkin('${k}');") cfg.skins)} + + # Enabled extensions. + ${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadExtension('${k}');") cfg.extensions)} + + + # End of automatically generated settings. + # Add more configuration options below. + + ${cfg.extraConfig} + ''; + +in +{ + # interface + options = { + services.mediawiki = { + + enable = mkEnableOption "MediaWiki"; + + package = mkOption { + type = types.package; + default = pkgs.mediawiki; + description = "Which MediaWiki package to use."; + }; + + name = mkOption { + default = "MediaWiki"; + example = "Foobar Wiki"; + description = "Name of the wiki."; + }; + + uploadsDir = mkOption { + type = types.nullOr types.path; + default = "${stateDir}/uploads"; + description = '' + This directory is used for uploads of pictures. The directory passed here is automatically + created and permissions adjusted as required. + ''; + }; + + passwordFile = mkOption { + type = types.path; + description = "A file containing the initial password for the admin user."; + example = "/run/keys/mediawiki-password"; + }; + + skins = mkOption { + default = {}; + type = types.attrsOf types.path; + description = '' + List of paths whose content is copied to the 'skins' + subdirectory of the MediaWiki installation. + ''; + }; + + extensions = mkOption { + default = {}; + type = types.attrsOf types.path; + description = '' + List of paths whose content is copied to the 'extensions' + subdirectory of the MediaWiki installation. + ''; + }; + + database = { + type = mkOption { + type = types.enum [ "mysql" "postgres" "sqlite" "mssql" "oracle" ]; + default = "mysql"; + description = "Database engine to use. MySQL/MariaDB is the database of choice by MediaWiki developers."; + }; + + host = mkOption { + type = types.str; + default = "localhost"; + description = "Database host address."; + }; + + port = mkOption { + type = types.port; + default = 3306; + description = "Database host port."; + }; + + name = mkOption { + type = types.str; + default = "mediawiki"; + description = "Database name."; + }; + + user = mkOption { + type = types.str; + default = "mediawiki"; + description = "Database user."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/mediawiki-dbpassword"; + description = '' + A file containing the password corresponding to + <option>database.user</option>. + ''; + }; + + tablePrefix = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + If you only have access to a single database and wish to install more than + one version of MediaWiki, or have other applications that also use the + database, you can give the table names a unique prefix to stop any naming + conflicts or confusion. + See <link xlink:href='https://www.mediawiki.org/wiki/Manual:$wgDBprefix'/>. + ''; + }; + + socket = mkOption { + type = types.nullOr types.path; + default = if cfg.database.createLocally then "/run/mysqld/mysqld.sock" else null; + defaultText = "/run/mysqld/mysqld.sock"; + description = "Path to the unix socket file to use for authentication."; + }; + + createLocally = mkOption { + type = types.bool; + default = cfg.database.type == "mysql"; + defaultText = "true"; + description = '' + Create the database and database user locally. + This currently only applies if database type "mysql" is selected. + ''; + }; + }; + + virtualHost = mkOption { + type = types.submodule ({ + options = import ../web-servers/apache-httpd/per-server-options.nix { + inherit lib; + forMainServer = false; + }; + }); + example = literalExample '' + { + hostName = "mediawiki.example.org"; + enableSSL = true; + adminAddr = "webmaster@example.org"; + sslServerCert = "/var/lib/acme/mediawiki.example.org/full.pem"; + sslServerKey = "/var/lib/acme/mediawiki.example.org/key.pem"; + } + ''; + description = '' + Apache configuration can be done by adapting <option>services.httpd.virtualHosts</option>. + See <xref linkend="opt-services.httpd.virtualHosts"/> for further information. + ''; + }; + + poolConfig = mkOption { + type = types.lines; + default = '' + pm = dynamic + pm.max_children = 32 + pm.start_servers = 2 + pm.min_spare_servers = 2 + pm.max_spare_servers = 4 + pm.max_requests = 500 + ''; + description = '' + Options for MediaWiki's PHP pool. See the documentation on <literal>php-fpm.conf</literal> + for details on configuration directives. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + description = '' + Any additional text to be appended to MediaWiki's + LocalSettings.php configuration file. For configuration + settings, see <link xlink:href="https://www.mediawiki.org/wiki/Manual:Configuration_settings"/>. + ''; + default = ""; + example = '' + $wgEnableEmail = false; + ''; + }; + + }; + }; + + # implementation + config = mkIf cfg.enable { + + assertions = [ + { assertion = cfg.database.createLocally -> cfg.database.type == "mysql"; + message = "services.mediawiki.createLocally is currently only supported for database type 'mysql'"; + } + { assertion = cfg.database.createLocally -> cfg.database.user == user; + message = "services.mediawiki.database.user must be set to ${user} if services.mediawiki.database.createLocally is set true"; + } + { assertion = cfg.database.createLocally -> cfg.database.socket != null; + message = "services.mediawiki.database.socket must be set if services.mediawiki.database.createLocally is set to true"; + } + { assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; + message = "a password cannot be specified if services.mediawiki.database.createLocally is set to true"; + } + ]; + + services.mediawiki.skins = { + MonoBook = "${cfg.package}/share/mediawiki/skins/MonoBook"; + Timeless = "${cfg.package}/share/mediawiki/skins/Timeless"; + Vector = "${cfg.package}/share/mediawiki/skins/Vector"; + }; + + services.mysql = mkIf cfg.database.createLocally { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.database.user; + ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }; + } + ]; + }; + + services.phpfpm.pools.mediawiki = { + listen = "/run/phpfpm/mediawiki.sock"; + extraConfig = '' + listen.owner = ${config.services.httpd.user} + listen.group = ${config.services.httpd.group} + user = ${user} + group = ${group} + + env[MEDIAWIKI_CONFIG] = ${mediawikiConfig} + + ${cfg.poolConfig} + ''; + }; + + services.httpd = { + enable = true; + adminAddr = mkDefault cfg.virtualHost.adminAddr; + extraModules = [ "proxy_fcgi" ]; + virtualHosts = [ (mkMerge [ + cfg.virtualHost { + documentRoot = mkForce "${pkg}/share/mediawiki"; + extraConfig = '' + <Directory "${pkg}/share/mediawiki"> + <FilesMatch "\.php$"> + <If "-f %{REQUEST_FILENAME}"> + SetHandler "proxy:unix:${fpm.listen}|fcgi://localhost/" + </If> + </FilesMatch> + + Require all granted + DirectoryIndex index.php + AllowOverride All + </Directory> + '' + optionalString (cfg.uploadsDir != null) '' + Alias "/images" "${cfg.uploadsDir}" + <Directory "${cfg.uploadsDir}"> + Require all granted + </Directory> + ''; + } + ]) ]; + }; + + systemd.tmpfiles.rules = [ + "d '${stateDir}' 0750 ${user} ${group} - -" + "d '${cacheDir}' 0750 ${user} ${group} - -" + ] ++ optionals (cfg.uploadsDir != null) [ + "d '${cfg.uploadsDir}' 0750 ${user} ${group} - -" + "Z '${cfg.uploadsDir}' 0750 ${user} ${group} - -" + ]; + + systemd.services.mediawiki-init = { + wantedBy = [ "multi-user.target" ]; + before = [ "phpfpm-mediawiki.service" ]; + after = optional cfg.database.createLocally "mysql.service"; + script = '' + if ! test -e "${stateDir}/secret.key"; then + tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c 64 > ${stateDir}/secret.key + fi + + echo "exit( wfGetDB( DB_MASTER )->tableExists( 'user' ) ? 1 : 0 );" | \ + ${pkgs.php}/bin/php ${pkg}/share/mediawiki/maintenance/eval.php --conf ${mediawikiConfig} && \ + ${pkgs.php}/bin/php ${pkg}/share/mediawiki/maintenance/install.php \ + --confpath /tmp \ + --scriptpath / \ + --dbserver ${cfg.database.host}${optionalString (cfg.database.socket != null) ":${cfg.database.socket}"} \ + --dbport ${toString cfg.database.port} \ + --dbname ${cfg.database.name} \ + ${optionalString (cfg.database.tablePrefix != null) "--dbprefix ${cfg.database.tablePrefix}"} \ + --dbuser ${cfg.database.user} \ + ${optionalString (cfg.database.passwordFile != null) "--dbpassfile ${cfg.database.passwordFile}"} \ + --passfile ${cfg.passwordFile} \ + ${cfg.name} \ + admin + + ${pkgs.php}/bin/php ${pkg}/share/mediawiki/maintenance/update.php --conf ${mediawikiConfig} --quick + ''; + + serviceConfig = { + Type = "oneshot"; + User = user; + Group = group; + PrivateTmp = true; + }; + }; + + systemd.services.httpd.after = optional (cfg.database.createLocally && cfg.database.type == "mysql") "mysql.service"; + + users.users.${user}.group = group; + + environment.systemPackages = [ mediawikiScripts ]; + }; +} diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix index fa9a36d11892..a0214a75d93e 100644 --- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix @@ -297,8 +297,23 @@ in { systemd.services = { "nextcloud-setup" = let + c = cfg.config; + writePhpArrary = a: "[${concatMapStringsSep "," (val: ''"${toString val}"'') a}]"; overrideConfig = pkgs.writeText "nextcloud-config.php" '' <?php + ${optionalString (c.dbpassFile != null) '' + function nix_read_pwd() { + $file = "${c.dbpassFile}"; + if (!file_exists($file)) { + throw new \RuntimeException(sprintf( + "Cannot start Nextcloud, dbpass file %s set by NixOS doesn't exist!", + $file + )); + } + + return trim(file_get_contents($file)); + } + ''} $CONFIG = [ 'apps_paths' => [ [ 'path' => '${cfg.home}/apps', 'url' => '/apps', 'writable' => false ], @@ -309,19 +324,27 @@ in { ${optionalString cfg.caching.apcu "'memcache.local' => '\\OC\\Memcache\\APCu',"} 'log_type' => 'syslog', 'log_level' => '${builtins.toString cfg.logLevel}', - ${optionalString (cfg.config.overwriteProtocol != null) "'overwriteprotocol' => '${cfg.config.overwriteProtocol}',"} + ${optionalString (c.overwriteProtocol != null) "'overwriteprotocol' => '${c.overwriteProtocol}',"} + ${optionalString (c.dbname != null) "'dbname' => '${c.dbname}',"} + ${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"} + ${optionalString (c.dbport != null) "'dbport' => '${toString c.dbport}',"} + ${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"} + ${optionalString (c.dbtableprefix != null) "'dbtableprefix' => '${toString c.dbtableprefix}',"} + ${optionalString (c.dbpass != null) "'dbpassword' => '${c.dbpass}',"} + ${optionalString (c.dbpassFile != null) "'dbpassword' => nix_read_pwd(),"} + 'dbtype' => '${c.dbtype}', + 'trusted_domains' => ${writePhpArrary ([ cfg.hostName ] ++ c.extraTrustedDomains)}, ]; ''; occInstallCmd = let - c = cfg.config; - adminpass = if c.adminpassFile != null - then ''"$(<"${toString c.adminpassFile}")"'' - else ''"${toString c.adminpass}"''; dbpass = if c.dbpassFile != null then ''"$(<"${toString c.dbpassFile}")"'' else if c.dbpass != null then ''"${toString c.dbpass}"'' else null; + adminpass = if c.adminpassFile != null + then ''"$(<"${toString c.adminpassFile}")"'' + else ''"${toString c.adminpass}"''; installFlags = concatStringsSep " \\\n " (mapAttrsToList (k: v: "${k} ${toString v}") { "--database" = ''"${c.dbtype}"''; diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.xml b/nixpkgs/nixos/modules/services/web-apps/nextcloud.xml index d78d866086a6..d66e0f0c2997 100644 --- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.xml +++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.xml @@ -42,10 +42,12 @@ services.postgresql = { <link linkend="opt-services.postgresql.enable">enable</link> = true; - <link linkend="opt-services.postgresql.initialScript">initialScript</link> = pkgs.writeText "psql-init" '' - CREATE ROLE nextcloud WITH LOGIN; - CREATE DATABASE nextcloud WITH OWNER nextcloud; - ''; + <link linkend="opt-services.postgresql.ensureDatabases">ensureDatabases</link> = [ "nextcloud" ]; + <link linkend="opt-services.postgresql.ensureUsers">ensureUsers</link> = [ + { name = "nextcloud"; + ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; + } + ]; }; # ensure that postgres is running *before* running the setup @@ -63,17 +65,22 @@ are used internally to configure an HTTP server using <literal><link xlink:href="https://php-fpm.org/">PHP-FPM</link></literal> and <literal>nginx</literal>. The <literal>config</literal> attribute set is - used for the <literal>config.php</literal> which is used for the - application's configuration. <emphasis>Beware: this isn't entirely pure - since the config is modified by the application's runtime!</emphasis> + used by the imperative installer and all values are written to an additional file + to ensure that changes can be applied by changing the module's options. </para> <para> - In case the application serves multiple hosts (those are checked with + In case the application serves multiple domains (those are checked with <literal><link xlink:href="http://php.net/manual/en/reserved.variables.server.php">$_SERVER['HTTP_HOST']</link></literal>) - those can be added using + it's needed to add them to <literal><link linkend="opt-services.nextcloud.config.extraTrustedDomains">services.nextcloud.config.extraTrustedDomains</link></literal>. </para> + + <para> + Auto updates for Nextcloud apps can be enabled using + <literal><link linkend="opt-services.nextcloud.autoUpdateApps.enable">services.nextcloud.autoUpdateApps</link></literal>. +</para> + </section> <section xml:id="module-services-nextcloud-pitfalls-during-upgrade"> <title>Pitfalls</title> @@ -87,35 +94,24 @@ </para> <para> - Right now changes to the <literal>services.nextcloud.config</literal> - attribute set won't take effect after the first install (except - <literal><link linkend="opt-services.nextcloud.config.extraTrustedDomains">services.nextcloud.config.extraTrustedDomains</link></literal>) - since the actual configuration file is generated by the NextCloud installer - which also sets up critical parts such as the database structure. + All configuration parameters are also stored in + <literal>/var/lib/nextcloud/config/override.config.php</literal> which is generated by + the module and linked from the store to ensure that all values from <literal>config.php</literal> + can be modified by the module. + However <literal>config.php</literal> manages the application's state and shouldn't be touched + manually because of that. </para> - <para> - <emphasis>Warning: don't delete <literal>config.php</literal>! This file + <warning> + <para>Don't delete <literal>config.php</literal>! This file tracks the application's state and a deletion can cause unwanted - side-effects!</emphasis> - </para> + side-effects!</para> + </warning> - <para> - <emphasis>Warning: don't rerun <literal>nextcloud-occ + <warning> + <para>Don't rerun <literal>nextcloud-occ maintenance:install</literal>! This command tries to install the application - and can cause unwanted side-effects!</emphasis> - </para> - - <para> - The issues are known and reported in - <link xlink:href="https://github.com/NixOS/nixpkgs/issues/49783">#49783</link>, - for now it's unfortunately necessary to manually work around these issues. - </para> - - <para> - Right now app installation and configuration is done imperatively in the nextcloud web ui or via the <literal>nextcloud-occ</literal> command line utility. - You can activate auto updates for your apps via - <literal><link linkend="opt-services.nextcloud.autoUpdateApps.enable">services.nextcloud.autoUpdateApps</link></literal>. - </para> + and can cause unwanted side-effects!</para> + </warning> </section> </chapter> diff --git a/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix b/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix index b882f6c2ae7e..1bd9de93735d 100644 --- a/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix +++ b/nixpkgs/nixos/modules/services/web-apps/tt-rss.nix @@ -16,6 +16,9 @@ let poolName = "tt-rss"; + mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql"; + pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql"; + tt-rss-config = pkgs.writeText "config.php" '' <?php @@ -200,6 +203,12 @@ let and 3306 for pgsql and mysql respectively). ''; }; + + createLocally = mkOption { + type = types.bool; + default = true; + description = "Create the database and database user locally."; + }; }; auth = { @@ -551,9 +560,13 @@ let }; }; - systemd.services.tt-rss = let - dbService = if cfg.database.type == "pgsql" then "postgresql.service" else "mysql.service"; - in { + systemd.tmpfiles.rules = [ + "d '${cfg.root}' 0755 ${cfg.user} tt_rss - -" + "Z '${cfg.root}' 0755 ${cfg.user} tt_rss - -" + ]; + + systemd.services.tt-rss = + { description = "Tiny Tiny RSS feeds update daemon"; @@ -562,14 +575,14 @@ let if cfg.database.type == "pgsql" then '' ${optionalString (cfg.database.password != null) "PGPASSWORD=${cfg.database.password}"} \ ${optionalString (cfg.database.passwordFile != null) "PGPASSWORD=$(cat ${cfg.database.passwordFile})"} \ - ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${config.services.postgresql.package}/bin/psql \ + ${config.services.postgresql.package}/bin/psql \ -U ${cfg.database.user} \ ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} --port ${toString dbPort}"} \ -c '${e}' \ ${cfg.database.name}'' else if cfg.database.type == "mysql" then '' - echo '${e}' | ${pkgs.sudo}/bin/sudo -u ${cfg.user} ${config.services.mysql.package}/bin/mysql \ + echo '${e}' | ${config.services.mysql.package}/bin/mysql \ -u ${cfg.database.user} \ ${optionalString (cfg.database.password != null) "-p${cfg.database.password}"} \ ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} -P ${toString dbPort}"} \ @@ -579,7 +592,6 @@ let in '' rm -rf "${cfg.root}/*" - mkdir -m 755 -p "${cfg.root}" cp -r "${pkgs.tt-rss}/"* "${cfg.root}" ${optionalString (cfg.pluginPackages != []) '' for plugin in ${concatStringsSep " " cfg.pluginPackages}; do @@ -592,19 +604,10 @@ let done ''} ln -sf "${tt-rss-config}" "${cfg.root}/config.php" - chown -R "${cfg.user}" "${cfg.root}" chmod -R 755 "${cfg.root}" '' + (optionalString (cfg.database.type == "pgsql") '' - ${optionalString (cfg.database.host == null && cfg.database.password == null) '' - if ! [ -e ${cfg.root}/.db-created ]; then - ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createuser ${cfg.database.user} - ${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -O ${cfg.database.user} ${cfg.database.name} - touch ${cfg.root}/.db-created - fi - ''} - exists=$(${callSql "select count(*) > 0 from pg_tables where tableowner = user"} \ | tail -n+3 | head -n-2 | sed -e 's/[ \n\t]*//') @@ -628,18 +631,18 @@ let serviceConfig = { User = "${cfg.user}"; + Group = "tt_rss"; ExecStart = "${pkgs.php}/bin/php ${cfg.root}/update.php --daemon"; StandardOutput = "syslog"; StandardError = "syslog"; - PermissionsStartOnly = true; }; wantedBy = [ "multi-user.target" ]; - requires = ["${dbService}"]; - after = ["network.target" "${dbService}"]; + requires = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; + after = [ "network.target" ] ++ optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; }; - services.mysql = optionalAttrs (cfg.database.type == "mysql") { + services.mysql = mkIf mysqlLocal { enable = true; package = mkDefault pkgs.mysql; ensureDatabases = [ cfg.database.name ]; @@ -653,17 +656,22 @@ let ]; }; - services.postgresql = optionalAttrs (cfg.database.type == "pgsql") { + services.postgresql = mkIf pgsqlLocal { enable = mkDefault true; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { name = cfg.user; + ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; }; + } + ]; }; - users = optionalAttrs (cfg.user == "tt_rss") { - users.tt_rss = { - description = "tt-rss service user"; - isSystemUser = true; - group = "tt_rss"; - }; - groups.tt_rss = {}; + users.users.tt_rss = optionalAttrs (cfg.user == "tt_rss") { + description = "tt-rss service user"; + isSystemUser = true; + group = "tt_rss"; }; + + users.groups.tt_rss = {}; }; } diff --git a/nixpkgs/nixos/modules/services/web-apps/zabbix.nix b/nixpkgs/nixos/modules/services/web-apps/zabbix.nix new file mode 100644 index 000000000000..4b5334579a99 --- /dev/null +++ b/nixpkgs/nixos/modules/services/web-apps/zabbix.nix @@ -0,0 +1,225 @@ +{ config, lib, pkgs, ... }: + +let + + inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types; + inherit (lib) literalExample mapAttrs optionalString; + + cfg = config.services.zabbixWeb; + fpm = config.services.phpfpm.pools.zabbix; + + user = "zabbix"; + group = "zabbix"; + stateDir = "/var/lib/zabbix"; + + zabbixConfig = pkgs.writeText "zabbix.conf.php" '' + <?php + // Zabbix GUI configuration file. + global $DB; + $DB['TYPE'] = '${ { "mysql" = "MYSQL"; "pgsql" = "POSTGRESQL"; "oracle" = "ORACLE"; }.${cfg.database.type} }'; + $DB['SERVER'] = '${cfg.database.host}'; + $DB['PORT'] = '${toString cfg.database.port}'; + $DB['DATABASE'] = '${cfg.database.name}'; + $DB['USER'] = '${cfg.database.user}'; + $DB['PASSWORD'] = ${if cfg.database.passwordFile != null then "file_get_contents('${cfg.database.passwordFile}')" else "''"}; + // Schema name. Used for IBM DB2 and PostgreSQL. + $DB['SCHEMA'] = '''; + $ZBX_SERVER = '${cfg.server.address}'; + $ZBX_SERVER_PORT = '${toString cfg.server.port}'; + $ZBX_SERVER_NAME = '''; + $IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG; + ''; + +in +{ + # interface + + options.services = { + zabbixWeb = { + enable = mkEnableOption "the Zabbix web interface"; + + package = mkOption { + type = types.package; + default = pkgs.zabbix.web; + defaultText = "zabbix.web"; + description = "Which Zabbix package to use."; + }; + + server = { + port = mkOption { + type = types.int; + description = "The port of the Zabbix server to connect to."; + default = 10051; + }; + + address = mkOption { + type = types.str; + description = "The IP address or hostname of the Zabbix server to connect to."; + default = "localhost"; + }; + }; + + database = { + type = mkOption { + type = types.enum [ "mysql" "pgsql" "oracle" ]; + example = "mysql"; + default = "pgsql"; + description = "Database engine to use."; + }; + + host = mkOption { + type = types.str; + default = ""; + description = "Database host address."; + }; + + port = mkOption { + type = types.int; + default = + if cfg.database.type == "mysql" then config.services.mysql.port + else if cfg.database.type == "pgsql" then config.services.postgresql.port + else 1521; + description = "Database host port."; + }; + + name = mkOption { + type = types.str; + default = "zabbix"; + description = "Database name."; + }; + + user = mkOption { + type = types.str; + default = "zabbix"; + description = "Database user."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/zabbix-dbpassword"; + description = '' + A file containing the password corresponding to + <option>database.user</option>. + ''; + }; + + socket = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/postgresql"; + description = "Path to the unix socket file to use for authentication."; + }; + }; + + virtualHost = mkOption { + type = types.submodule ({ + options = import ../web-servers/apache-httpd/per-server-options.nix { + inherit lib; + forMainServer = false; + }; + }); + example = { + hostName = "zabbix.example.org"; + enableSSL = true; + adminAddr = "webmaster@example.org"; + sslServerCert = "/var/lib/acme/zabbix.example.org/full.pem"; + sslServerKey = "/var/lib/acme/zabbix.example.org/key.pem"; + }; + description = '' + Apache configuration can be done by adapting <literal>services.httpd.virtualHosts.<name></literal>. + See <xref linkend="opt-services.httpd.virtualHosts"/> for further information. + ''; + }; + + poolConfig = mkOption { + type = types.lines; + default = '' + pm = dynamic + pm.max_children = 32 + pm.start_servers = 2 + pm.min_spare_servers = 2 + pm.max_spare_servers = 4 + pm.max_requests = 500 + ''; + description = '' + Options for the Zabbix PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives. + ''; + }; + + }; + }; + + # implementation + + config = mkIf cfg.enable { + + systemd.tmpfiles.rules = [ + "d '${stateDir}' 0750 ${user} ${group} - -" + "d '${stateDir}/session' 0750 ${user} ${config.services.httpd.group} - -" + ]; + + services.phpfpm.pools.zabbix = { + phpOptions = '' + # https://www.zabbix.com/documentation/current/manual/installation/install + memory_limit = 128M + post_max_size = 16M + upload_max_filesize = 2M + max_execution_time = 300 + max_input_time = 300 + session.auto_start = 0 + mbstring.func_overload = 0 + always_populate_raw_post_data = -1 + # https://bbs.archlinux.org/viewtopic.php?pid=1745214#p1745214 + session.save_path = ${stateDir}/session + '' + optionalString (config.time.timeZone != null) '' + date.timezone = "${config.time.timeZone}" + '' + optionalString (cfg.database.type == "oracle") '' + extension=${pkgs.phpPackages.oci8}/lib/php/extensions/oci8.so + ''; + listen = "/run/phpfpm/zabbix.sock"; + extraConfig = '' + listen.owner = ${config.services.httpd.user}; + listen.group = ${config.services.httpd.group}; + user = ${user}; + group = ${config.services.httpd.group}; + env[ZABBIX_CONFIG] = ${zabbixConfig} + ${cfg.poolConfig} + ''; + }; + + services.httpd = { + enable = true; + adminAddr = mkDefault cfg.virtualHost.adminAddr; + extraModules = [ "proxy_fcgi" ]; + virtualHosts = [ (mkMerge [ + cfg.virtualHost { + documentRoot = mkForce "${cfg.package}/share/zabbix"; + extraConfig = '' + <Directory "${cfg.package}/share/zabbix"> + <FilesMatch "\.php$"> + <If "-f %{REQUEST_FILENAME}"> + SetHandler "proxy:unix:${fpm.listen}|fcgi://localhost/" + </If> + </FilesMatch> + AllowOverride all + Options -Indexes + DirectoryIndex index.php + </Directory> + ''; + } + ]) ]; + }; + + users.users.${user} = mapAttrs (name: mkDefault) { + description = "Zabbix daemon user"; + uid = config.ids.uids.zabbix; + inherit group; + }; + + users.groups.${group} = mapAttrs (name: mkDefault) { + gid = config.ids.gids.zabbix; + }; + + }; +} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix index bf99f6c132af..ea9476a7c915 100644 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -21,10 +21,9 @@ let else [{ip = "*"; port = 80;}]; getListen = cfg: - let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen; - in if list == [] - then defaultListen cfg - else list; + if cfg.listen == [] + then defaultListen cfg + else cfg.listen; listenToString = l: "${l.ip}:${toString l.port}"; @@ -638,7 +637,7 @@ in message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; } ]; - warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts); + warnings = map (cfg: "apache-httpd's extraSubservices option is deprecated. Most existing subservices have been ported to the NixOS module system. Please update your configuration accordingly.") (lib.filter (cfg: cfg.extraSubservices != []) allHosts); users.users = optionalAttrs (mainCfg.user == "wwwrun") (singleton { name = "wwwrun"; @@ -672,7 +671,7 @@ in wantedBy = [ "multi-user.target" ]; wants = [ "keys.target" ]; - after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ]; + after = [ "network.target" "fs.target" "keys.target" ]; path = [ httpd pkgs.coreutils pkgs.gnugrep ] diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/foswiki.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/foswiki.nix deleted file mode 100644 index 8c1ac8935a47..000000000000 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/foswiki.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ config, pkgs, lib, serverInfo, ... }: -let - inherit (pkgs) foswiki; - inherit (serverInfo.serverConfig) user group; - inherit (config) vardir; -in -{ - options.vardir = lib.mkOption { - type = lib.types.path; - default = "/var/www/foswiki"; - description = "The directory where variable foswiki data will be stored and served from."; - }; - - # TODO: this will probably need to be better customizable - extraConfig = - let httpd-conf = pkgs.runCommand "foswiki-httpd.conf" - { preferLocalBuild = true; } - '' - substitute '${foswiki}/foswiki_httpd_conf.txt' "$out" \ - --replace /var/www/foswiki/ "${vardir}/" - ''; - in - '' - RewriteEngine on - RewriteRule /foswiki/(.*) ${vardir}/$1 - - <Directory "${vardir}"> - Require all granted - </Directory> - - Include ${httpd-conf} - <Directory "${vardir}/pub"> - Options FollowSymlinks - </Directory> - ''; - - /** This handles initial setup and updates. - It will probably need some tweaking, maybe per-site. */ - startupScript = pkgs.writeScript "foswiki_startup.sh" ( - let storeLink = "${vardir}/package"; in - '' - [ -e '${storeLink}' ] || needs_setup=1 - mkdir -p '${vardir}' - cd '${vardir}' - ln -sf -T '${foswiki}' '${storeLink}' - - if [ -n "$needs_setup" ]; then # do initial setup - mkdir -p bin lib - # setup most of data/ as copies only - cp -r '${foswiki}'/data '${vardir}/' - rm -r '${vardir}'/data/{System,mime.types} - ln -sr -t '${vardir}/data/' '${storeLink}'/data/{System,mime.types} - - ln -sr '${storeLink}/locale' . - - mkdir pub - ln -sr '${storeLink}/pub/System' pub/ - - mkdir templates - ln -sr '${storeLink}'/templates/* templates/ - - ln -sr '${storeLink}/tools' . - - mkdir -p '${vardir}'/working/{logs,tmp} - ln -sr '${storeLink}/working/README' working/ # used to check dir validity - - chown -R '${user}:${group}' . - chmod +w -R . - fi - - # bin/* and lib/* shall always be overwritten, in case files are added - ln -srf '${storeLink}'/bin/* '${vardir}/bin/' - ln -srf '${storeLink}'/lib/* '${vardir}/lib/' - '' - /* Symlinking bin/ one-by-one ensures that ${vardir}/lib/LocalSite.cfg - is used instead of ${foswiki}/... */ - ); -} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix deleted file mode 100644 index 6234478014ce..000000000000 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix +++ /dev/null @@ -1,349 +0,0 @@ -{ config, lib, pkgs, serverInfo, php, ... }: - -with lib; - -let - - httpd = serverInfo.serverConfig.package; - - version24 = !versionOlder httpd.version "2.4"; - - allGranted = if version24 then '' - Require all granted - '' else '' - Order allow,deny - Allow from all - ''; - - mediawikiConfig = pkgs.writeText "LocalSettings.php" - '' - <?php - # Copied verbatim from the default (generated) LocalSettings.php. - if( defined( 'MW_INSTALL_PATH' ) ) { - $IP = MW_INSTALL_PATH; - } else { - $IP = dirname( __FILE__ ); - } - - $path = array( $IP, "$IP/includes", "$IP/languages" ); - set_include_path( implode( PATH_SEPARATOR, $path ) . PATH_SEPARATOR . get_include_path() ); - - require_once( "$IP/includes/DefaultSettings.php" ); - - if ( $wgCommandLineMode ) { - if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) { - die( "This script must be run from the command line\n" ); - } - } - - $wgScriptPath = "${config.urlPrefix}"; - - # We probably need to set $wgSecretKey and $wgCacheEpoch. - - # Paths to external programs. - $wgDiff3 = "${pkgs.diffutils}/bin/diff3"; - $wgDiff = "${pkgs.diffutils}/bin/diff"; - $wgImageMagickConvertCommand = "${pkgs.imagemagick.out}/bin/convert"; - - #$wgDebugLogFile = "/tmp/mediawiki_debug_log.txt"; - - # Database configuration. - $wgDBtype = "${config.dbType}"; - $wgDBserver = "${config.dbServer}"; - $wgDBuser = "${config.dbUser}"; - $wgDBpassword = "${config.dbPassword}"; - $wgDBname = "${config.dbName}"; - - # E-mail. - $wgEmergencyContact = "${config.emergencyContact}"; - $wgPasswordSender = "${config.passwordSender}"; - - $wgSitename = "${config.siteName}"; - - ${optionalString (config.logo != "") '' - $wgLogo = "${config.logo}"; - ''} - - ${optionalString (config.articleUrlPrefix != "") '' - $wgArticlePath = "${config.articleUrlPrefix}/$1"; - ''} - - ${optionalString config.enableUploads '' - $wgEnableUploads = true; - $wgUploadDirectory = "${config.uploadDir}"; - ''} - - ${optionalString (config.defaultSkin != "") '' - $wgDefaultSkin = "${config.defaultSkin}"; - ''} - - ${config.extraConfig} - ?> - ''; - - # Unpack Mediawiki and put the config file in its root directory. - mediawikiRoot = pkgs.stdenv.mkDerivation rec { - name= "mediawiki-1.31.1"; - - src = pkgs.fetchurl { - url = "https://releases.wikimedia.org/mediawiki/1.31/${name}.tar.gz"; - sha256 = "13x48clij21cmysjkpnx68vggchrdasqp7b290j87xlfgjhdhnnf"; - }; - - skins = config.skins; - extensions = config.extensions; - - buildPhase = - '' - for skin in $skins; do - cp -prvd $skin/* skins/ - done - for extension in $extensions; do - cp -prvd $extension/* extensions/ - done - ''; # */ - - installPhase = - '' - mkdir -p $out - cp -r * $out - cp ${mediawikiConfig} $out/LocalSettings.php - sed -i \ - -e 's|/bin/bash|${pkgs.bash}/bin/bash|g' \ - -e 's|/usr/bin/timeout|${pkgs.coreutils}/bin/timeout|g' \ - $out/includes/shell/limit.sh \ - $out/includes/GlobalFunctions.php - ''; - }; - - mediawikiScripts = pkgs.runCommand "mediawiki-${config.id}-scripts" { - buildInputs = [ pkgs.makeWrapper ]; - preferLocalBuild = true; - } '' - mkdir -p $out/bin - for i in changePassword.php createAndPromote.php userOptions.php edit.php nukePage.php update.php; do - makeWrapper ${php}/bin/php $out/bin/mediawiki-${config.id}-$(basename $i .php) \ - --add-flags ${mediawikiRoot}/maintenance/$i - done - ''; - -in - -{ - - extraConfig = - '' - ${optionalString config.enableUploads '' - Alias ${config.urlPrefix}/images ${config.uploadDir} - - <Directory ${config.uploadDir}> - ${allGranted} - Options -Indexes - </Directory> - ''} - - ${if config.urlPrefix != "" then "Alias ${config.urlPrefix} ${mediawikiRoot}" else '' - RewriteEngine On - RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f - RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d - ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedDirs} - ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedFiles} - RewriteRule ${if config.enableUploads - then "!^/images" - else "^.*\$" - } %{DOCUMENT_ROOT}/${if config.articleUrlPrefix == "" - then "" - else "${config.articleUrlPrefix}/" - }index.php [L] - ''} - - <Directory ${mediawikiRoot}> - ${allGranted} - DirectoryIndex index.php - </Directory> - - ${optionalString (config.articleUrlPrefix != "") '' - Alias ${config.articleUrlPrefix} ${mediawikiRoot}/index.php - ''} - ''; - - documentRoot = if config.urlPrefix == "" then mediawikiRoot else null; - - enablePHP = true; - - options = { - - id = mkOption { - default = "main"; - description = '' - A unique identifier necessary to keep multiple MediaWiki server - instances on the same machine apart. This is used to - disambiguate the administrative scripts, which get names like - mediawiki-$id-change-password. - ''; - }; - - dbType = mkOption { - default = "postgres"; - example = "mysql"; - description = "Database type."; - }; - - dbName = mkOption { - default = "mediawiki"; - description = "Name of the database that holds the MediaWiki data."; - }; - - dbServer = mkOption { - default = ""; # use a Unix domain socket - example = "10.0.2.2"; - description = '' - The location of the database server. Leave empty to use a - database server running on the same machine through a Unix - domain socket. - ''; - }; - - dbUser = mkOption { - default = "mediawiki"; - description = "The user name for accessing the database."; - }; - - dbPassword = mkOption { - default = ""; - example = "foobar"; - description = '' - The password of the database user. Warning: this is stored in - cleartext in the Nix store! - ''; - }; - - emergencyContact = mkOption { - default = serverInfo.serverConfig.adminAddr; - example = "admin@example.com"; - description = '' - Emergency contact e-mail address. Defaults to the Apache - admin address. - ''; - }; - - passwordSender = mkOption { - default = serverInfo.serverConfig.adminAddr; - example = "password@example.com"; - description = '' - E-mail address from which password confirmations originate. - Defaults to the Apache admin address. - ''; - }; - - siteName = mkOption { - default = "MediaWiki"; - example = "Foobar Wiki"; - description = "Name of the wiki"; - }; - - logo = mkOption { - default = ""; - example = "/images/logo.png"; - description = "The URL of the site's logo (which should be a 135x135px image)."; - }; - - urlPrefix = mkOption { - default = "/w"; - description = '' - The URL prefix under which the Mediawiki service appears. - ''; - }; - - articleUrlPrefix = mkOption { - default = "/wiki"; - example = ""; - description = '' - The URL prefix under which article pages appear, - e.g. http://server/wiki/Page. Leave empty to use the main URL - prefix, e.g. http://server/w/index.php?title=Page. - ''; - }; - - enableUploads = mkOption { - default = false; - description = "Whether to enable file uploads."; - }; - - uploadDir = mkOption { - default = throw "You must specify `uploadDir'."; - example = "/data/mediawiki-upload"; - description = "The directory that stores uploaded files."; - }; - - defaultSkin = mkOption { - default = ""; - example = "nostalgia"; - description = "Set this value to change the default skin used by MediaWiki."; - }; - - skins = mkOption { - default = []; - type = types.listOf types.path; - description = - '' - List of paths whose content is copied to the ‘skins’ - subdirectory of the MediaWiki installation. - ''; - }; - - extensions = mkOption { - default = []; - type = types.listOf types.path; - description = - '' - List of paths whose content is copied to the 'extensions' - subdirectory of the MediaWiki installation. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - example = - '' - $wgEnableEmail = false; - ''; - description = '' - Any additional text to be appended to MediaWiki's - configuration file. This is a PHP script. For configuration - settings, see <link xlink:href='https://www.mediawiki.org/wiki/Manual:Configuration_settings'/>. - ''; - }; - - }; - - extraPath = [ mediawikiScripts ]; - - # !!! Need to specify that Apache has a dependency on PostgreSQL! - - startupScript = pkgs.writeScript "mediawiki_startup.sh" - # Initialise the database automagically if we're using a Postgres - # server on localhost. - (optionalString (config.dbType == "postgres" && config.dbServer == "") '' - if ! ${pkgs.postgresql}/bin/psql -l | grep -q ' ${config.dbName} ' ; then - ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole "${config.dbUser}" || true - ${pkgs.postgresql}/bin/createdb "${config.dbName}" -O "${config.dbUser}" - ( echo 'CREATE LANGUAGE plpgsql;' - cat ${mediawikiRoot}/maintenance/postgres/tables.sql - echo 'CREATE TEXT SEARCH CONFIGURATION public.default ( COPY = pg_catalog.english );' - echo COMMIT - ) | ${pkgs.postgresql}/bin/psql -U "${config.dbUser}" "${config.dbName}" - fi - ${php}/bin/php ${mediawikiRoot}/maintenance/update.php - ''); - - robotsEntries = optionalString (config.articleUrlPrefix != "") - '' - User-agent: * - Disallow: ${config.urlPrefix}/ - Disallow: ${config.articleUrlPrefix}/Special:Search - Disallow: ${config.articleUrlPrefix}/Special:Random - ''; - -} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix index 4bbd041b6e04..536e707137c6 100644 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix +++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix @@ -24,14 +24,6 @@ with lib; ''; }; - port = mkOption { - type = types.int; - default = 0; - description = '' - Port for the server. Option will be removed, use <option>listen</option> instead. - ''; - }; - listen = mkOption { type = types.listOf (types.submodule ( { diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix deleted file mode 100644 index a883bb2b3433..000000000000 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix +++ /dev/null @@ -1,103 +0,0 @@ -{ config, pkgs, serverInfo, lib, ... }: - -let - extraWorkersProperties = lib.optionalString (config ? extraWorkersProperties) config.extraWorkersProperties; - - workersProperties = pkgs.writeText "workers.properties" '' -# Define list of workers that will be used -# for mapping requests -# The configuration directives are valid -# for the mod_jk version 1.2.18 and later -# -worker.list=loadbalancer,status - -# Define Node1 -# modify the host as your host IP or DNS name. -worker.node1.port=8009 -worker.node1.host=localhost -worker.node1.type=ajp13 -worker.node1.lbfactor=1 - -# Load-balancing behaviour -worker.loadbalancer.type=lb -worker.loadbalancer.balance_workers=node1 - -# Status worker for managing load balancer -worker.status.type=status - -${extraWorkersProperties} - ''; -in -{ - - options = { - extraWorkersProperties = lib.mkOption { - default = ""; - description = "Additional configuration for the workers.properties file."; - }; - }; - - extraModules = [ - { name = "jk"; path = "${pkgs.tomcat_connectors}/modules/mod_jk.so"; } - ]; - - extraConfig = '' -# Where to find workers.properties -JkWorkersFile ${workersProperties} - -# Where to put jk logs -JkLogFile ${serverInfo.serverConfig.logDir}/mod_jk.log - -# Set the jk log level [debug/error/info] -JkLogLevel info - -# Select the log format -JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" - -# JkOptions indicates to send SSK KEY SIZE -# Note: Changed from +ForwardURICompat. -# See http://tomcat.apache.org/security-jk.html -JkOptions +ForwardKeySize +ForwardURICompatUnparsed -ForwardDirectories - -# JkRequestLogFormat -JkRequestLogFormat "%w %V %T" - -# Mount your applications -JkMount /__application__/* loadbalancer - -# You can use external file for mount points. -# It will be checked for updates each 60 seconds. -# The format of the file is: /url=worker -# /examples/*=loadbalancer -#JkMountFile uriworkermap.properties - -# Add shared memory. -# This directive is present with 1.2.10 and -# later versions of mod_jk, and is needed for -# for load balancing to work properly -# Note: Replaced JkShmFile logs/jk.shm due to SELinux issues. Refer to -# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=225452 -JkShmFile ${serverInfo.serverConfig.stateDir}/jk.shm - -# Static files in all Tomcat webapp context directories are served by apache -JkAutoAlias /var/tomcat/webapps - -# All requests go to worker by default -JkMount /* loadbalancer -# Serve some static files using httpd -#JkUnMount /*.html loadbalancer -#JkUnMount /*.jpg loadbalancer -#JkUnMount /*.gif loadbalancer -#JkUnMount /*.css loadbalancer -#JkUnMount /*.png loadbalancer -#JkUnMount /*.js loadbalancer - -# Add jkstatus for managing runtime data -<Location /jkstatus/> -JkMount status -Order deny,allow -Deny from all -Allow from 127.0.0.1 -</Location> - ''; -} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/trac.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/trac.nix deleted file mode 100644 index 28b411a64b6f..000000000000 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/trac.nix +++ /dev/null @@ -1,121 +0,0 @@ -{ config, lib, pkgs, serverInfo, ... }: - -with lib; - -let - - # Build a Subversion instance with Apache modules and Swig/Python bindings. - subversion = pkgs.subversion.override { - bdbSupport = true; - httpServer = true; - pythonBindings = true; - apacheHttpd = httpd; - }; - - httpd = serverInfo.serverConfig.package; - - versionPre24 = versionOlder httpd.version "2.4"; - -in - -{ - - options = { - - projectsLocation = mkOption { - description = "URL path in which Trac projects can be accessed"; - default = "/projects"; - }; - - projects = mkOption { - description = "List of projects that should be provided by Trac. If they are not defined yet empty projects are created."; - default = []; - example = - [ { identifier = "myproject"; - name = "My Project"; - databaseURL="postgres://root:password@/tracdb"; - subversionRepository="/data/subversion/myproject"; - } - ]; - }; - - user = mkOption { - default = "wwwrun"; - description = "User account under which Trac runs."; - }; - - group = mkOption { - default = "wwwrun"; - description = "Group under which Trac runs."; - }; - - ldapAuthentication = { - enable = mkOption { - default = false; - description = "Enable the ldap authentication in trac"; - }; - - url = mkOption { - default = "ldap://127.0.0.1/dc=example,dc=co,dc=ke?uid?sub?(objectClass=inetOrgPerson)"; - description = "URL of the LDAP authentication"; - }; - - name = mkOption { - default = "Trac server"; - description = "AuthName"; - }; - }; - - }; - - extraModules = singleton - { name = "python"; path = "${pkgs.mod_python}/modules/mod_python.so"; }; - - extraConfig = '' - <Location ${config.projectsLocation}> - SetHandler mod_python - PythonHandler trac.web.modpython_frontend - PythonOption TracEnvParentDir /var/trac/projects - PythonOption TracUriRoot ${config.projectsLocation} - PythonOption PYTHON_EGG_CACHE /var/trac/egg-cache - </Location> - ${if config.ldapAuthentication.enable then '' - <LocationMatch "^${config.projectsLocation}[^/]+/login$"> - AuthType Basic - AuthName "${config.ldapAuthentication.name}" - AuthBasicProvider "ldap" - AuthLDAPURL "${config.ldapAuthentication.url}" - ${if versionPre24 then "authzldapauthoritative Off" else ""} - require valid-user - </LocationMatch> - '' else ""} - ''; - - globalEnvVars = singleton - { name = "PYTHONPATH"; - value = - makeSearchPathOutput "lib" "lib/${pkgs.python.libPrefix}/site-packages" - [ pkgs.mod_python - pkgs.pythonPackages.trac - pkgs.pythonPackages.setuptools - pkgs.pythonPackages.genshi - pkgs.pythonPackages.psycopg2 - subversion - ]; - }; - - startupScript = pkgs.writeScript "activateTrac" '' - mkdir -p /var/trac - chown ${config.user}:${config.group} /var/trac - - ${concatMapStrings (project: - '' - if [ ! -d /var/trac/${project.identifier} ] - then - export PYTHONPATH=${pkgs.pythonPackages.psycopg2}/lib/${pkgs.python.libPrefix}/site-packages - ${pkgs.pythonPackages.trac}/bin/trac-admin /var/trac/${project.identifier} initenv "${project.name}" "${project.databaseURL}" svn "${project.subversionRepository}" - fi - '' ) (config.projects)} - ''; - -} diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/zabbix.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/zabbix.nix deleted file mode 100644 index cab16593bcbc..000000000000 --- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/zabbix.nix +++ /dev/null @@ -1,84 +0,0 @@ -{ config, lib, pkgs, serverInfo, ... }: - -with lib; - -let - - # The Zabbix PHP frontend needs to be able to write its - # configuration settings (the connection info to the database) to - # the "conf" subdirectory. So symlink $out/conf to some directory - # outside of the Nix store where we want to keep this stateful info. - # Note that different instances of the frontend will therefore end - # up with their own copies of the PHP sources. !!! Alternatively, - # we could generate zabbix.conf.php declaratively. - zabbixPHP = pkgs.runCommand "${pkgs.zabbix.server.name}-php" {} - '' - cp -rs ${pkgs.zabbix.server}/share/zabbix/php "$out" - chmod -R u+w $out - ln -s "${if config.configFile == null - then "${config.stateDir}/zabbix.conf.php" - else config.configFile}" "$out/conf/zabbix.conf.php" - ''; - -in - -{ - - enablePHP = true; - - phpOptions = - '' - post_max_size = 32M - max_execution_time = 300 - max_input_time = 300 - ''; - - extraConfig = '' - Alias ${config.urlPrefix}/ ${zabbixPHP}/ - - <Directory ${zabbixPHP}> - DirectoryIndex index.php - Order deny,allow - Allow from * - </Directory> - ''; - - startupScript = pkgs.writeScript "zabbix-startup-hook" '' - mkdir -p ${config.stateDir} - chown -R ${serverInfo.serverConfig.user} ${config.stateDir} - ''; - - # The frontend needs "ps" to find out whether zabbix_server is running. - extraServerPath = [ pkgs.procps ]; - - options = { - - urlPrefix = mkOption { - default = "/zabbix"; - description = " - The URL prefix under which the Zabbix service appears. - Use the empty string to have it appear in the server root. - "; - }; - - configFile = mkOption { - default = null; - type = types.nullOr types.path; - description = '' - The configuration file (zabbix.conf.php) which contains the database - connection settings. If not set, the configuration settings will created - by the web installer. - ''; - }; - - stateDir = mkOption { - default = "/var/lib/zabbix/frontend"; - description = " - Directory where the dynamically generated configuration data - of the PHP frontend will be stored. - "; - }; - - }; - -} diff --git a/nixpkgs/nixos/modules/services/x11/clight.nix b/nixpkgs/nixos/modules/services/x11/clight.nix new file mode 100644 index 000000000000..6ec395bb05ec --- /dev/null +++ b/nixpkgs/nixos/modules/services/x11/clight.nix @@ -0,0 +1,115 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.clight; + + toConf = v: + if builtins.isFloat v then toString v + else if isInt v then toString v + else if isBool v then boolToString v + else if isString v then ''"${escape [''"''] v}"'' + else if isList v then "[ " + concatMapStringsSep ", " toConf v + " ]" + else abort "clight.toConf: unexpected type (v = ${v})"; + + clightConf = pkgs.writeText "clight.conf" + (concatStringsSep "\n" (mapAttrsToList + (name: value: "${toString name} = ${toConf value};") + (filterAttrs + (_: value: value != null) + cfg.settings))); +in { + options.services.clight = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable clight or not. + ''; + }; + + temperature = { + day = mkOption { + type = types.int; + default = 5500; + description = '' + Colour temperature to use during the day, between + <literal>1000</literal> and <literal>25000</literal> K. + ''; + }; + night = mkOption { + type = types.int; + default = 3700; + description = '' + Colour temperature to use at night, between + <literal>1000</literal> and <literal>25000</literal> K. + ''; + }; + }; + + settings = let + validConfigTypes = with types; either int (either str (either bool float)); + in mkOption { + type = with types; attrsOf (nullOr (either validConfigTypes (listOf validConfigTypes))); + default = {}; + example = { captures = 20; gamma_long_transition = true; ac_capture_timeouts = [ 120 300 60 ]; }; + description = '' + Additional configuration to extend clight.conf. See + <link xlink:href="https://github.com/FedeDP/Clight/blob/master/Extra/clight.conf"/> for a + sample configuration file. + ''; + }; + }; + + config = mkIf cfg.enable { + boot.kernelModules = [ "i2c_dev" ]; + environment.systemPackages = with pkgs; [ clight clightd ]; + services.dbus.packages = with pkgs; [ clight clightd ]; + services.upower.enable = true; + + services.clight.settings = { + gamma_temp = with cfg.temperature; mkDefault [ day night ]; + } // (optionalAttrs (config.location.provider == "manual") { + latitude = mkDefault config.location.latitude; + longitude = mkDefault config.location.longitude; + }); + + services.geoclue2.appConfig."clightc" = { + isAllowed = true; + isSystem = true; + }; + + systemd.services.clightd = { + requires = [ "polkit.service" ]; + wantedBy = [ "multi-user.target" ]; + + description = "Bus service to manage various screen related properties (gamma, dpms, backlight)"; + serviceConfig = { + Type = "dbus"; + BusName = "org.clightd.clightd"; + Restart = "on-failure"; + RestartSec = 5; + ExecStart = '' + ${pkgs.clightd}/bin/clightd + ''; + }; + }; + + systemd.user.services.clight = { + after = [ "upower.service" "clightd.service" ]; + wants = [ "upower.service" "clightd.service" ]; + partOf = [ "graphical-session.target" ]; + wantedBy = [ "graphical-session.target" ]; + + description = "C daemon to adjust screen brightness to match ambient brightness, as computed capturing frames from webcam"; + serviceConfig = { + Restart = "on-failure"; + RestartSec = 5; + ExecStart = '' + ${pkgs.clight}/bin/clight --conf-file ${clightConf} + ''; + }; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/x11/compton.nix b/nixpkgs/nixos/modules/services/x11/compton.nix index d4357324c870..c02c9bfd94e8 100644 --- a/nixpkgs/nixos/modules/services/x11/compton.nix +++ b/nixpkgs/nixos/modules/services/x11/compton.nix @@ -7,57 +7,35 @@ let cfg = config.services.compton; - literalAttrs = v: - if isString v then toString v - else if isAttrs v then "{\n" - + concatStringsSep "\n" (mapAttrsToList - (name: value: "${literalAttrs name} = ${literalAttrs value};") - v) - + "\n}" - else generators.toPretty {} v; + pairOf = x: with types; addCheck (listOf x) (y: length y == 2); floatBetween = a: b: with lib; with types; addCheck str (x: versionAtLeast x a && versionOlder x b); - pairOf = x: with types; addCheck (listOf x) (y: length y == 2); - - opacityRules = optionalString (length cfg.opacityRules != 0) - (concatMapStringsSep ",\n" (rule: ''"${rule}"'') cfg.opacityRules); - - configFile = pkgs.writeText "compton.conf" - (optionalString cfg.fade '' - # fading - fading = true; - fade-delta = ${toString cfg.fadeDelta}; - fade-in-step = ${elemAt cfg.fadeSteps 0}; - fade-out-step = ${elemAt cfg.fadeSteps 1}; - fade-exclude = ${toJSON cfg.fadeExclude}; - '' + optionalString cfg.shadow '' - - # shadows - shadow = true; - shadow-offset-x = ${toString (elemAt cfg.shadowOffsets 0)}; - shadow-offset-y = ${toString (elemAt cfg.shadowOffsets 1)}; - shadow-opacity = ${cfg.shadowOpacity}; - shadow-exclude = ${toJSON cfg.shadowExclude}; - '' + '' - - # opacity - active-opacity = ${cfg.activeOpacity}; - inactive-opacity = ${cfg.inactiveOpacity}; - - wintypes: - ${literalAttrs cfg.wintypes}; - - opacity-rule = [ - ${opacityRules} - ]; - - # other options - backend = ${toJSON cfg.backend}; - vsync = ${boolToString cfg.vSync}; - refresh-rate = ${toString cfg.refreshRate}; - '' + cfg.extraOptions); + toConf = attrs: concatStringsSep "\n" + (mapAttrsToList + (k: v: let + sep = if isAttrs v then ":" else "="; + # Basically a tinkered lib.generators.mkKeyValueDefault + mkValueString = v: + if isBool v then boolToString v + else if isInt v then toString v + else if isFloat v then toString v + else if isString v then ''"${escape [ ''"'' ] v}"'' + else if isList v then "[ " + + concatMapStringsSep " , " mkValueString v + + " ]" + else if isAttrs v then "{ " + + concatStringsSep " " + (mapAttrsToList + (key: value: "${toString key}=${mkValueString value};") + v) + + " }" + else abort "compton.mkValueString: unexpected type (v = ${v})"; + in "${escape [ sep ] k}${sep}${mkValueString v};") + attrs); + + configFile = pkgs.writeText "compton.conf" (toConf cfg.settings); in { @@ -236,23 +214,13 @@ in { ''; }; - package = mkOption { - type = types.package; - default = pkgs.compton; - defaultText = "pkgs.compton"; - example = literalExample "pkgs.compton"; - description = '' - Compton derivation to use. - ''; - }; - - extraOptions = mkOption { - type = types.lines; - default = ""; - example = '' - unredir-if-possible = true; - dbe = true; - ''; + settings = let + configTypes = with types; either bool (either int (either float str)); + # types.loaOf converts lists to sets + loaOf = t: with types; either (listOf t) (attrsOf t); + in mkOption { + type = loaOf (types.either configTypes (loaOf (types.either configTypes (loaOf configTypes)))); + default = {}; description = '' Additional Compton configuration. ''; @@ -260,6 +228,42 @@ in { }; config = mkIf cfg.enable { + services.compton.settings = let + # Hard conversion to float, literally lib.toInt but toFloat + toFloat = str: let + may_be_float = builtins.fromJSON str; + in if builtins.isFloat may_be_float + then may_be_float + else throw "Could not convert ${str} to float."; + in { + # fading + fading = mkDefault cfg.fade; + fade-delta = mkDefault cfg.fadeDelta; + fade-in-step = mkDefault (toFloat (elemAt cfg.fadeSteps 0)); + fade-out-step = mkDefault (toFloat (elemAt cfg.fadeSteps 1)); + fade-exclude = mkDefault cfg.fadeExclude; + + # shadows + shadow = mkDefault cfg.shadow; + shadow-offset-x = mkDefault (elemAt cfg.shadowOffsets 0); + shadow-offset-y = mkDefault (elemAt cfg.shadowOffsets 1); + shadow-opacity = mkDefault (toFloat cfg.shadowOpacity); + shadow-exclude = mkDefault cfg.shadowExclude; + + # opacity + active-opacity = mkDefault (toFloat cfg.activeOpacity); + inactive-opacity = mkDefault (toFloat cfg.inactiveOpacity); + + wintypes = mkDefault cfg.wintypes; + + opacity-rule = mkDefault cfg.opacityRules; + + # other options + backend = mkDefault cfg.backend; + vsync = mkDefault cfg.vSync; + refresh-rate = mkDefault cfg.refreshRate; + }; + systemd.user.services.compton = { description = "Compton composite manager"; wantedBy = [ "graphical-session.target" ]; @@ -271,13 +275,13 @@ in { }; serviceConfig = { - ExecStart = "${cfg.package}/bin/compton --config ${configFile}"; + ExecStart = "${pkgs.compton}/bin/compton --config ${configFile}"; RestartSec = 3; Restart = "always"; }; }; - environment.systemPackages = [ cfg.package ]; + environment.systemPackages = [ pkgs.compton ]; }; } diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/default.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/default.nix index 2b1e9169e5f6..671a959cdde1 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/default.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/default.nix @@ -20,7 +20,7 @@ in imports = [ ./none.nix ./xterm.nix ./xfce.nix ./plasma5.nix ./lumina.nix ./lxqt.nix ./enlightenment.nix ./gnome3.nix ./kodi.nix ./maxx.nix - ./mate.nix ./pantheon.nix + ./mate.nix ./pantheon.nix ./surf-display.nix ]; options = { diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix index ef6820d33260..5e1e652a5089 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -123,12 +123,8 @@ in { services.dleyna-renderer.enable = mkDefault true; services.dleyna-server.enable = mkDefault true; services.gnome3.at-spi2-core.enable = true; - services.gnome3.evince.enable = mkDefault true; services.gnome3.evolution-data-server.enable = true; - services.gnome3.file-roller.enable = mkDefault true; services.gnome3.glib-networking.enable = true; - services.gnome3.gnome-disks.enable = mkDefault true; - services.gnome3.gnome-documents.enable = mkDefault true; services.gnome3.gnome-keyring.enable = true; services.gnome3.gnome-online-accounts.enable = mkDefault true; services.gnome3.gnome-remote-desktop.enable = mkDefault true; @@ -154,7 +150,14 @@ in { services.hardware.bolt.enable = mkDefault true; services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center systemd.packages = [ pkgs.gnome3.vino ]; - services.flatpak.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + xdg.portal.enable = true; + xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + + # Enable default programs + programs.evince.enable = mkDefault true; + programs.file-roller.enable = mkDefault true; + programs.gnome-disks.enable = mkDefault true; + programs.gnome-documents.enable = mkDefault true; # If gnome3 is installed, build vim for gtk3 too. nixpkgs.config.vim.gui = "gtk3"; @@ -229,7 +232,7 @@ in { # Use the correct gnome3 packageSet networking.networkmanager.basePackages = - { inherit (pkgs) networkmanager modemmanager wpa_supplicant; + { inherit (pkgs) networkmanager modemmanager wpa_supplicant crda; inherit (pkgs.gnome3) networkmanager-openvpn networkmanager-vpnc networkmanager-openconnect networkmanager-fortisslvpn networkmanager-iodine networkmanager-l2tp; }; diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix index 41903b33fae9..8e1272f3c92b 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix @@ -102,6 +102,10 @@ in # Makes qt applications look less alien export QT_QPA_PLATFORMTHEME=gtk3 export QT_STYLE_OVERRIDE=adwaita + + # Settings from elementary-default-settings + export GTK_CSD=1 + export GTK_MODULES=$GTK_MODULES:pantheon-filechooser-module fi ''; @@ -147,7 +151,7 @@ in networking.networkmanager.enable = mkDefault true; networking.networkmanager.basePackages = - { inherit (pkgs) networkmanager modemmanager wpa_supplicant; + { inherit (pkgs) networkmanager modemmanager wpa_supplicant crda; inherit (pkgs.gnome3) networkmanager-openvpn networkmanager-vpnc networkmanager-openconnect networkmanager-fortisslvpn networkmanager-iodine networkmanager-l2tp; }; diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix index dc8bfc7dc172..94a307ae1007 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -21,6 +21,13 @@ in description = "Enable the Plasma 5 (KDE 5) desktop environment."; }; + phononBackend = mkOption { + type = types.enum [ "gstreamer" "vlc" ]; + default = "gstreamer"; + example = "vlc"; + description = "Phonon audio backend to install."; + }; + enableQt4Support = mkOption { type = types.bool; default = true; @@ -64,8 +71,8 @@ in }; security.wrappers = { - kcheckpass.source = "${lib.getBin plasma5.kscreenlocker}/lib/libexec/kcheckpass"; - "start_kdeinit".source = "${lib.getBin pkgs.kinit}/lib/libexec/kf5/start_kdeinit"; + kcheckpass.source = "${lib.getBin plasma5.kscreenlocker}/libexec/kcheckpass"; + "start_kdeinit".source = "${lib.getBin pkgs.kinit}/libexec/kf5/start_kdeinit"; kwin_wayland = { source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland"; capabilities = "cap_sys_nice+ep"; @@ -161,15 +168,17 @@ in qtvirtualkeyboard - libsForQt5.phonon-backend-gstreamer - xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/ ] - ++ lib.optionals cfg.enableQt4Support [ pkgs.phonon-backend-gstreamer ] + # Phonon audio backend + ++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer + ++ lib.optional (cfg.phononBackend == "gstreamer" && cfg.enableQt4Support) pkgs.phonon-backend-gstreamer + ++ lib.optional (cfg.phononBackend == "vlc") libsForQt5.phonon-backend-vlc + ++ lib.optional (cfg.phononBackend == "vlc" && cfg.enableQt4Support) pkgs.phonon-backend-vlc # Optional hardware support features - ++ lib.optional config.hardware.bluetooth.enable bluedevil + ++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt ] ++ lib.optional config.networking.networkmanager.enable plasma-nm ++ lib.optional config.hardware.pulseaudio.enable plasma-pa ++ lib.optional config.powerManagement.enable powerdevil @@ -224,6 +233,9 @@ in security.pam.services.sddm.enableKwallet = true; security.pam.services.slim.enableKwallet = true; + xdg.portal.enable = true; + xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-kde ]; + # Update the start menu for each user that is currently logged in system.userActivationScripts.plasmaSetup = '' # The KDE icon cache is supposed to update itself diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/surf-display.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/surf-display.nix new file mode 100644 index 000000000000..232bbf5c55d4 --- /dev/null +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/surf-display.nix @@ -0,0 +1,127 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.desktopManager.surf-display; + + surfDisplayConf = '' + # Surf Kiosk Display: Wrap around surf browser and turn your + # system into a browser screen in KIOSK-mode. + + # default download URI for all display screens if not configured individually + DEFAULT_WWW_URI="${cfg.defaultWwwUri}" + + # Enforce fixed resolution for all displays (default: not set): + #DEFAULT_RESOLUTION="1920x1080" + + # HTTP proxy URL, if needed (default: not set). + #HTTP_PROXY_URL="http://webcache:3128" + + # Setting for internal inactivity timer to restart surf-display + # if the user goes inactive/idle. + INACTIVITY_INTERVAL="${builtins.toString cfg.inactivityInterval}" + + # log to syslog instead of .xsession-errors + LOG_TO_SYSLOG="yes" + + # Launch pulseaudio daemon if not already running. + WITH_PULSEAUDIO="yes" + + # screensaver settings, see "man 1 xset" for possible options + SCREENSAVER_SETTINGS="${cfg.screensaverSettings}" + + # disable right and middle pointer device click in browser sessions while keeping + # scrolling wheels' functionality intact... (consider "pointer" subcommand on + # xmodmap man page for details). + POINTER_BUTTON_MAP="${cfg.pointerButtonMap}" + + # Hide idle mouse pointer. + HIDE_IDLE_POINTER="${cfg.hideIdlePointer}" + + ${cfg.extraConfig} + ''; + +in { + options = { + services.xserver.desktopManager.surf-display = { + enable = mkEnableOption "surf-display as a kiosk browser session"; + + defaultWwwUri = mkOption { + type = types.string; + default = "${pkgs.surf-display}/share/surf-display/empty-page.html"; + example = "https://www.example.com/"; + description = "Default URI to display."; + }; + + inactivityInterval = mkOption { + type = types.int; + default = 300; + example = "0"; + description = '' + Setting for internal inactivity timer to restart surf-display if the + user goes inactive/idle to get a fresh session for the next user of + the kiosk. + + If this value is set to zero, the whole feature of restarting due to + inactivity is disabled. + ''; + }; + + screensaverSettings = mkOption { + type = types.string; + default = ""; + description = '' + Screensaver settings, see <literal>man 1 xset</literal> for possible options. + ''; + }; + + pointerButtonMap = mkOption { + type = types.string; + default = "1 0 0 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + description = '' + Disable right and middle pointer device click in browser sessions + while keeping scrolling wheels' functionality intact. See pointer + subcommand on <literal>man xmodmap</literal> for details. + ''; + }; + + hideIdlePointer = mkOption { + type = types.string; + default = "yes"; + example = "no"; + description = "Hide idle mouse pointer."; + }; + + extraConfig = mkOption { + type = types.string; + default = ""; + example = '' + # Enforce fixed resolution for all displays (default: not set): + DEFAULT_RESOLUTION="1920x1080" + + # HTTP proxy URL, if needed (default: not set). + HTTP_PROXY_URL="http://webcache:3128" + + # Configure individual display screens with host specific parameters: + DISPLAYS['display-host-0']="www_uri=https://www.displayserver.comany.net/display-1/index.html" + DISPLAYS['display-host-1']="www_uri=https://www.displayserver.comany.net/display-2/index.html" + DISPLAYS['display-host-2']="www_uri=https://www.displayserver.comany.net/display-3/index.html|res=1920x1280" + DISPLAYS['display-host-3']="www_uri=https://www.displayserver.comany.net/display-4/index.html"|res=1280x1024" + DISPLAYS['display-host-local-file']="www_uri=file:///usr/share/doc/surf-display/empty-page.html" + ''; + description = '' + Extra configuration options to append to <literal>/etc/default/surf-display</literal>. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + services.xserver.displayManager.extraSessionFilePackages = [ + pkgs.surf-display + ]; + + environment.etc."default/surf-display".text = surfDisplayConf; + }; +} diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix index ff4b91923e02..3f1669d08516 100644 --- a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix @@ -96,6 +96,14 @@ in type = types.bool; }; + autoSuspend = mkOption { + default = true; + description = '' + Suspend the machine after inactivity. + ''; + type = types.bool; + }; + }; }; @@ -176,10 +184,40 @@ in systemd.user.services.dbus.wantedBy = [ "default.target" ]; - programs.dconf.profiles.gdm = pkgs.writeText "dconf-gdm-profile" '' - system-db:local - ${gdm}/share/dconf/profile/gdm - ''; + programs.dconf.profiles.gdm = + let + customDconf = pkgs.writeTextFile { + name = "gdm-dconf"; + destination = "/dconf/gdm-custom"; + text = '' + ${optionalString (!cfg.gdm.autoSuspend) '' + [org/gnome/settings-daemon/plugins/power] + sleep-inactive-ac-type='nothing' + sleep-inactive-battery-type='nothing' + sleep-inactive-ac-timeout=0 + sleep-inactive-battery-timeout=0 + ''} + ''; + }; + + customDconfDb = pkgs.stdenv.mkDerivation { + name = "gdm-dconf-db"; + buildCommand = '' + ${pkgs.gnome3.dconf}/bin/dconf compile $out ${customDconf}/dconf + ''; + }; + in pkgs.stdenv.mkDerivation { + name = "dconf-gdm-profile"; + buildCommand = '' + # Check that the GDM profile starts with what we expect. + if [ $(head -n 1 ${gdm}/share/dconf/profile/gdm) != "user-db:user" ]; then + echo "GDM dconf profile changed, please update gdm.nix" + exit 1 + fi + # Insert our custom DB behind it. + sed '2ifile-db:${customDconfDb}' ${gdm}/share/dconf/profile/gdm > $out + ''; + }; # Use AutomaticLogin if delay is zero, because it's immediate. # Otherwise with TimedLogin with zero seconds the prompt is still diff --git a/nixpkgs/nixos/modules/services/x11/extra-layouts.nix b/nixpkgs/nixos/modules/services/x11/extra-layouts.nix new file mode 100644 index 000000000000..5523dd2bf023 --- /dev/null +++ b/nixpkgs/nixos/modules/services/x11/extra-layouts.nix @@ -0,0 +1,165 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + layouts = config.services.xserver.extraLayouts; + + layoutOpts = { + options = { + description = mkOption { + type = types.str; + description = "A short description of the layout."; + }; + + languages = mkOption { + type = types.listOf types.str; + description = + '' + A list of languages provided by the layout. + (Use ISO 639-2 codes, for example: "eng" for english) + ''; + }; + + compatFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + The path to the xkb compat file. + This file sets the compatibility state, used to preserve + compatibility with xkb-unaware programs. + It must contain a <literal>xkb_compat "name" { ... }</literal> block. + ''; + }; + + geometryFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + The path to the xkb geometry file. + This (completely optional) file describes the physical layout of + keyboard, which maybe be used by programs to depict it. + It must contain a <literal>xkb_geometry "name" { ... }</literal> block. + ''; + }; + + keycodesFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + The path to the xkb keycodes file. + This file specifies the range and the interpretation of the raw + keycodes sent by the keyboard. + It must contain a <literal>xkb_keycodes "name" { ... }</literal> block. + ''; + }; + + symbolsFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + The path to the xkb symbols file. + This is the most important file: it defines which symbol or action + maps to each key and must contain a + <literal>xkb_symbols "name" { ... }</literal> block. + ''; + }; + + typesFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + The path to the xkb types file. + This file specifies the key types that can be associated with + the various keyboard keys. + It must contain a <literal>xkb_types "name" { ... }</literal> block. + ''; + }; + + }; + }; + +in + +{ + + ###### interface + + options.services.xserver = { + extraLayouts = mkOption { + type = types.attrsOf (types.submodule layoutOpts); + default = {}; + example = literalExample + '' + { + mine = { + description = "My custom xkb layout."; + languages = [ "eng" ]; + symbolsFile = /path/to/my/layout; + }; + } + ''; + description = '' + Extra custom layouts that will be included in the xkb configuration. + Information on how to create a new layout can be found here: + <link xlink:href="https://www.x.org/releases/current/doc/xorg-docs/input/XKB-Enhancing.html#Defining_New_Layouts"></link>. + For more examples see + <link xlink:href="https://wiki.archlinux.org/index.php/X_KeyBoard_extension#Basic_examples"></link> + ''; + }; + + }; + + ###### implementation + + config = mkIf (layouts != { }) { + + # We don't override xkeyboard_config directly to + # reduce the amount of packages to be recompiled. + # Only the following packages are necessary to set + # a custom layout anyway: + nixpkgs.overlays = lib.singleton (self: super: { + + xkb_patched = self.xorg.xkeyboardconfig_custom { + layouts = config.services.xserver.extraLayouts; + }; + + xorg = super.xorg // { + xorgserver = super.xorg.xorgserver.overrideAttrs (old: { + configureFlags = old.configureFlags ++ [ + "--with-xkb-bin-directory=${self.xorg.xkbcomp}/bin" + "--with-xkb-path=${self.xkb_patched}/share/X11/xkb" + ]; + }); + + setxkbmap = super.xorg.setxkbmap.overrideAttrs (old: { + postInstall = + '' + mkdir -p $out/share + ln -sfn ${self.xkb_patched}/etc/X11 $out/share/X11 + ''; + }); + + xkbcomp = super.xorg.xkbcomp.overrideAttrs (old: { + configureFlags = "--with-xkb-config-root=${self.xkb_patched}/share/X11/xkb"; + }); + + }; + + ckbcomp = super.ckbcomp.override { + xkeyboard_config = self.xkb_patched; + }; + + xkbvalidate = super.xkbvalidate.override { + libxkbcommon = self.libxkbcommon.override { + xkeyboard_config = self.xkb_patched; + }; + }; + + }); + + services.xserver.xkbDir = "${pkgs.xkb_patched}/etc/X11/xkb"; + + }; + +} diff --git a/nixpkgs/nixos/modules/services/x11/gdk-pixbuf.nix b/nixpkgs/nixos/modules/services/x11/gdk-pixbuf.nix index 2dc8eabd95a7..9ad926369ec7 100644 --- a/nixpkgs/nixos/modules/services/x11/gdk-pixbuf.nix +++ b/nixpkgs/nixos/modules/services/x11/gdk-pixbuf.nix @@ -5,21 +5,21 @@ with lib; let cfg = config.services.xserver.gdk-pixbuf; - # Get packages to generate the cache for. We always include gdk_pixbuf. - effectivePackages = unique ([pkgs.gdk_pixbuf] ++ cfg.modulePackages); + # Get packages to generate the cache for. We always include gdk-pixbuf. + effectivePackages = unique ([pkgs.gdk-pixbuf] ++ cfg.modulePackages); # Generate the cache file by running gdk-pixbuf-query-loaders for each # package and concatenating the results. loadersCache = pkgs.runCommand "gdk-pixbuf-loaders.cache" { preferLocalBuild = true; } '' ( for package in ${concatStringsSep " " effectivePackages}; do - module_dir="$package/${pkgs.gdk_pixbuf.moduleDir}" + module_dir="$package/${pkgs.gdk-pixbuf.moduleDir}" if [[ ! -d $module_dir ]]; then echo "Warning (services.xserver.gdk-pixbuf): missing module directory $module_dir" 1>&2 continue fi GDK_PIXBUF_MODULEDIR="$module_dir" \ - ${pkgs.gdk_pixbuf.dev}/bin/gdk-pixbuf-query-loaders + ${pkgs.gdk-pixbuf.dev}/bin/gdk-pixbuf-query-loaders done ) > "$out" ''; diff --git a/nixpkgs/nixos/modules/services/x11/redshift.nix b/nixpkgs/nixos/modules/services/x11/redshift.nix index 4345a3348081..55f8f75021bc 100644 --- a/nixpkgs/nixos/modules/services/x11/redshift.nix +++ b/nixpkgs/nixos/modules/services/x11/redshift.nix @@ -5,6 +5,7 @@ with lib; let cfg = config.services.redshift; + lcfg = config.location; in { @@ -18,35 +19,6 @@ in { ''; }; - latitude = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Your current latitude, between - <literal>-90.0</literal> and <literal>90.0</literal>. Must be provided - along with longitude. - ''; - }; - - longitude = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Your current longitude, between - between <literal>-180.0</literal> and <literal>180.0</literal>. Must be - provided along with latitude. - ''; - }; - - provider = mkOption { - type = types.enum [ "manual" "geoclue2" ]; - default = "manual"; - description = '' - The location provider to use for determining your location. If set to - <literal>manual</literal> you must also provide latitude/longitude. - ''; - }; - temperature = { day = mkOption { type = types.int; @@ -106,33 +78,19 @@ in { }; config = mkIf cfg.enable { - assertions = [ - { - assertion = - if cfg.provider == "manual" - then (cfg.latitude != null && cfg.longitude != null) - else (cfg.latitude == null && cfg.longitude == null); - message = "Latitude and longitude must be provided together, and with provider set to null."; - } - ]; - # needed so that .desktop files are installed, which geoclue cares about environment.systemPackages = [ cfg.package ]; - services.geoclue2 = mkIf (cfg.provider == "geoclue2") { - enable = true; - appConfig."redshift" = { - isAllowed = true; - isSystem = true; - }; + services.geoclue2.appConfig."redshift" = { + isAllowed = true; + isSystem = true; }; - systemd.user.services.redshift = + systemd.user.services.redshift = let - providerString = - if cfg.provider == "manual" - then "${cfg.latitude}:${cfg.longitude}" - else cfg.provider; + providerString = if lcfg.provider == "manual" + then "${toString lcfg.latitude}:${toString lcfg.longitude}" + else lcfg.provider; in { description = "Redshift colour temperature adjuster"; diff --git a/nixpkgs/nixos/modules/services/x11/xserver.nix b/nixpkgs/nixos/modules/services/x11/xserver.nix index a1ed2fd1e97b..b1a316706976 100644 --- a/nixpkgs/nixos/modules/services/x11/xserver.nix +++ b/nixpkgs/nixos/modules/services/x11/xserver.nix @@ -14,6 +14,9 @@ let # Alias so people can keep using "virtualbox" instead of "vboxvideo". virtualbox = { modules = [ xorg.xf86videovboxvideo ]; driverName = "vboxvideo"; }; + # Alias so that "radeon" uses the xf86-video-ati driver. + radeon = { modules = [ xorg.xf86videoati ]; driverName = "ati"; }; + # modesetting does not have a xf86videomodesetting package as it is included in xorgserver modesetting = {}; }; @@ -241,7 +244,7 @@ in videoDrivers = mkOption { type = types.listOf types.str; # !!! We'd like "nv" here, but it segfaults the X server. - default = [ "ati" "cirrus" "vesa" "vmware" "modesetting" ]; + default = [ "radeon" "cirrus" "vesa" "vmware" "modesetting" ]; example = [ "ati_unfree" "amdgpu" "amdgpu-pro" "nv" "nvidia" "nvidiaLegacy390" "nvidiaLegacy340" "nvidiaLegacy304" @@ -662,10 +665,9 @@ in restartIfChanged = false; environment = - { - LD_LIBRARY_PATH = concatStringsSep ":" ([ "/run/opengl-driver/lib" ] - ++ concatLists (catAttrs "libPath" cfg.drivers)); - } // cfg.displayManager.job.environment; + optionalAttrs config.hardware.opengl.setLdLibraryPath + { LD_LIBRARY_PATH = pkgs.addOpenGLRunpath.driverLink; } + // cfg.displayManager.job.environment; preStart = '' diff --git a/nixpkgs/nixos/modules/system/boot/binfmt.nix b/nixpkgs/nixos/modules/system/boot/binfmt.nix index d6c0f0504868..a550ffd6320f 100644 --- a/nixpkgs/nixos/modules/system/boot/binfmt.nix +++ b/nixpkgs/nixos/modules/system/boot/binfmt.nix @@ -115,6 +115,14 @@ let magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00''; mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff''; }; + wasm32-wasi = { + magicOrExtension = ''\x00asm''; + mask = ''\xff\xff\xff\xff''; + }; + wasm64-wasi = { + magicOrExtension = ''\x00asm''; + mask = ''\xff\xff\xff\xff''; + }; x86_64-windows = { magicOrExtension = ".exe"; recognitionType = "extension"; @@ -226,6 +234,7 @@ in { emulatedSystems = mkOption { default = []; + example = [ "wasm32-wasi" "x86_64-windows" "aarch64-linux" ]; description = '' List of systems to emulate. Will also configure Nix to support your new systems. diff --git a/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl index a36b3c180eb4..a09c5dc47618 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -407,6 +407,29 @@ addEntry("NixOS - Default", $defaultConfig); $conf .= "$extraEntries\n" unless $extraEntriesBeforeNixOS; +# Find all the children of the current default configuration +# Do not search for grand children +my @links = sort (glob "$defaultConfig/fine-tune/*"); +foreach my $link (@links) { + + my $entryName = ""; + + my $cfgName = readFile("$link/configuration-name"); + + my $date = strftime("%F", localtime(lstat($link)->mtime)); + my $version = + -e "$link/nixos-version" + ? readFile("$link/nixos-version") + : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]); + + if ($cfgName) { + $entryName = $cfgName; + } else { + $entryName = "($date - $version)"; + } + addEntry("NixOS - $entryName", $link); +} + my $grubBootPath = $grubBoot->path; # extraEntries could refer to @bootRoot@, which we have to substitute $conf =~ s/\@bootRoot\@/$grubBootPath/g; diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix index 910a602c61de..22d459ceb04f 100644 --- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix +++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix @@ -22,7 +22,9 @@ let editor = if cfg.editor then "True" else "False"; - inherit (cfg) consoleMode configurationLimit; + configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit; + + inherit (cfg) consoleMode; inherit (efi) efiSysMountPoint canTouchEfiVariables; @@ -58,12 +60,15 @@ in { }; configurationLimit = mkOption { - default = 100; + default = null; example = 120; - type = types.int; + type = types.nullOr types.int; description = '' - Maximum of configurations in boot menu. Otherwise boot partition could - run out of disk space. + Maximum number of latest generations in the boot menu. + Useful to prevent boot partition running out of disk space. + + <literal>null</literal> means no limit i.e. all generations + that were not garbage collected yet. ''; }; diff --git a/nixpkgs/nixos/modules/system/boot/resolved.nix b/nixpkgs/nixos/modules/system/boot/resolved.nix index 5c66cf4a6e6e..3ea96f8e4645 100644 --- a/nixpkgs/nixos/modules/system/boot/resolved.nix +++ b/nixpkgs/nixos/modules/system/boot/resolved.nix @@ -3,6 +3,10 @@ with lib; let cfg = config.services.resolved; + + dnsmasqResolve = config.services.dnsmasq.enable && + config.services.dnsmasq.resolveLocalQueries; + in { @@ -126,6 +130,12 @@ in config = mkIf cfg.enable { + assertions = [ + { assertion = !config.networking.useHostResolvConf; + message = "Using host resolv.conf is not supported with systemd-resolved"; + } + ]; + systemd.additionalUpstreamSystemUnits = [ "systemd-resolved.service" ]; @@ -135,21 +145,30 @@ in restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ]; }; - environment.etc."systemd/resolved.conf".text = '' - [Resolve] - ${optionalString (config.networking.nameservers != []) - "DNS=${concatStringsSep " " config.networking.nameservers}"} - ${optionalString (cfg.fallbackDns != []) - "FallbackDNS=${concatStringsSep " " cfg.fallbackDns}"} - ${optionalString (cfg.domains != []) - "Domains=${concatStringsSep " " cfg.domains}"} - LLMNR=${cfg.llmnr} - DNSSEC=${cfg.dnssec} - ${config.services.resolved.extraConfig} - ''; + environment.etc = { + "systemd/resolved.conf".text = '' + [Resolve] + ${optionalString (config.networking.nameservers != []) + "DNS=${concatStringsSep " " config.networking.nameservers}"} + ${optionalString (cfg.fallbackDns != []) + "FallbackDNS=${concatStringsSep " " cfg.fallbackDns}"} + ${optionalString (cfg.domains != []) + "Domains=${concatStringsSep " " cfg.domains}"} + LLMNR=${cfg.llmnr} + DNSSEC=${cfg.dnssec} + ${config.services.resolved.extraConfig} + ''; + + # symlink the dynamic stub resolver of resolv.conf as recommended by upstream: + # https://www.freedesktop.org/software/systemd/man/systemd-resolved.html#/etc/resolv.conf + "resolv.conf".source = "/run/systemd/resolve/stub-resolv.conf"; + } // optionalAttrs dnsmasqResolve { + "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf"; + }; # If networkmanager is enabled, ask it to interface with resolved. networking.networkmanager.dns = "systemd-resolved"; + }; } diff --git a/nixpkgs/nixos/modules/system/boot/stage-2.nix b/nixpkgs/nixos/modules/system/boot/stage-2.nix index 55e6b19c67fd..6b0b47227301 100644 --- a/nixpkgs/nixos/modules/system/boot/stage-2.nix +++ b/nixpkgs/nixos/modules/system/boot/stage-2.nix @@ -4,19 +4,20 @@ with lib; let + useHostResolvConf = config.networking.resolvconf.enable && config.networking.useHostResolvConf; + bootStage2 = pkgs.substituteAll { src = ./stage-2-init.sh; shellDebug = "${pkgs.bashInteractive}/bin/bash"; shell = "${pkgs.bash}/bin/bash"; isExecutable = true; inherit (config.nix) readOnlyStore; - inherit (config.networking) useHostResolvConf; + inherit useHostResolvConf; inherit (config.system.build) earlyMountScript; - path = lib.makeBinPath [ + path = lib.makeBinPath ([ pkgs.coreutils pkgs.utillinux - pkgs.openresolv - ]; + ] ++ lib.optional useHostResolvConf pkgs.openresolv); fsPackagesPath = lib.makeBinPath config.system.fsPackages; postBootCommands = pkgs.writeText "local-cmds" '' diff --git a/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix b/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix index 63f974b704f3..ee4ae845a7d5 100644 --- a/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixpkgs/nixos/modules/system/boot/systemd-unit-options.nix @@ -6,7 +6,7 @@ with import ./systemd-lib.nix { inherit config lib pkgs; }; let checkService = checkUnitConfig "Service" [ (assertValueOneOf "Type" [ - "simple" "forking" "oneshot" "dbus" "notify" "idle" + "exec" "simple" "forking" "oneshot" "dbus" "notify" "idle" ]) (assertValueOneOf "Restart" [ "no" "on-success" "on-failure" "on-abnormal" "on-abort" "always" diff --git a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix index 91f4ae79ee91..18753ae0c1ae 100644 --- a/nixpkgs/nixos/modules/tasks/auto-upgrade.nix +++ b/nixpkgs/nixos/modules/tasks/auto-upgrade.nix @@ -53,6 +53,16 @@ let cfg = config.system.autoUpgrade; in ''; }; + allowReboot = mkOption { + default = false; + type = types.bool; + description = '' + Reboot the system into the new generation instead of a switch + if the new generation uses a different kernel, kernel modules + or initrd than the booted system. + ''; + }; + }; }; @@ -78,11 +88,23 @@ let cfg = config.system.autoUpgrade; in HOME = "/root"; } // config.networking.proxy.envVars; - 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} - ''; + path = [ pkgs.coreutils pkgs.gnutar pkgs.xz.bin pkgs.gitMinimal config.nix.package.out ]; + + script = let + nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild"; + in + if cfg.allowReboot then '' + ${nixos-rebuild} boot ${toString cfg.flags} + booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})" + built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})" + if [ "$booted" = "$built" ]; then + ${nixos-rebuild} switch ${toString cfg.flags} + else + /run/current-system/sw/bin/shutdown -r +1 + fi + '' else '' + ${nixos-rebuild} switch ${toString cfg.flags} + ''; startAt = cfg.dates; }; diff --git a/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix index c6a90bcf1a51..98038701ca58 100644 --- a/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix +++ b/nixpkgs/nixos/modules/tasks/filesystems/xfs.nix @@ -18,6 +18,7 @@ in boot.initrd.extraUtilsCommands = mkIf inInitrd '' copy_bin_and_libs ${pkgs.xfsprogs.bin}/bin/fsck.xfs + copy_bin_and_libs ${pkgs.xfsprogs.bin}/bin/xfs_repair ''; # Trick just to set 'sh' after the extraUtils nuke-refs. diff --git a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix index f7f07bad9522..ac06b6caee30 100644 --- a/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixpkgs/nixos/modules/tasks/filesystems/zfs.nix @@ -1,8 +1,6 @@ { config, lib, pkgs, utils, ... }: # -# todo: -# - crontab for scrubs, etc -# - zfs tunables +# TODO: zfs tunables with utils; with lib; @@ -13,6 +11,7 @@ let cfgSnapshots = config.services.zfs.autoSnapshot; cfgSnapFlags = cfgSnapshots.flags; cfgScrub = config.services.zfs.autoScrub; + cfgTrim = config.services.zfs.trim; inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems; inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems; @@ -268,14 +267,26 @@ in }; }; - services.zfs.autoScrub = { - enable = mkOption { - default = false; - type = types.bool; + services.zfs.trim = { + enable = mkEnableOption "Enables periodic TRIM on all ZFS pools."; + + interval = mkOption { + default = "weekly"; + type = types.str; + example = "daily"; description = '' - Enables periodic scrubbing of ZFS pools. + How often we run trim. For most desktop and server systems + a sufficient trimming frequency is once a week. + + The format is described in + <citerefentry><refentrytitle>systemd.time</refentrytitle> + <manvolnum>7</manvolnum></citerefentry>. ''; }; + }; + + services.zfs.autoScrub = { + enable = mkEnableOption "Enables periodic scrubbing of ZFS pools."; interval = mkOption { default = "Sun, 02:00"; @@ -535,5 +546,17 @@ in }; }; }) + + (mkIf cfgTrim.enable { + systemd.services.zpool-trim = { + description = "ZFS pools trim"; + after = [ "zfs-import.target" ]; + path = [ packages.zfsUser ]; + startAt = cfgTrim.interval; + script = '' + zpool list -H -o name | xargs -n1 zpool trim + ''; + }; + }) ]; } diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix b/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix index c12ada7a030a..2b8a7944dc36 100644 --- a/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixpkgs/nixos/modules/tasks/network-interfaces-scripted.nix @@ -103,7 +103,7 @@ let script = '' - ${optionalString (!config.environment.etc?"resolv.conf") '' + ${optionalString config.networking.resolvconf.enable '' # Set the static DNS configuration, if given. ${pkgs.openresolv}/sbin/resolvconf -m 1 -a static <<EOF ${optionalString (cfg.nameservers != [] && cfg.domain != null) '' diff --git a/nixpkgs/nixos/modules/tasks/network-interfaces.nix b/nixpkgs/nixos/modules/tasks/network-interfaces.nix index f9b0eb330bf8..c75d7cbc408b 100644 --- a/nixpkgs/nixos/modules/tasks/network-interfaces.nix +++ b/nixpkgs/nixos/modules/tasks/network-interfaces.nix @@ -1017,7 +1017,6 @@ in pkgs.iproute pkgs.iputils pkgs.nettools - pkgs.openresolv ] ++ optionals config.networking.wireless.enable [ pkgs.wirelesstools # FIXME: obsolete? @@ -1087,7 +1086,24 @@ in virtualisation.vswitch = mkIf (cfg.vswitches != { }) { enable = true; }; - services.udev.packages = mkIf (cfg.wlanInterfaces != {}) [ + services.udev.packages = [ + (pkgs.writeTextFile rec { + name = "ipv6-privacy-extensions.rules"; + destination = "/etc/udev/rules.d/98-${name}"; + text = '' + # enable and prefer IPv6 privacy addresses by default + ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.%k.use_tempaddr=2" + ''; + }) + (pkgs.writeTextFile rec { + name = "ipv6-privacy-extensions.rules"; + destination = "/etc/udev/rules.d/99-${name}"; + text = concatMapStrings (i: '' + # enable IPv6 privacy addresses but prefer EUI-64 addresses for ${i.name} + ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${i.name}.use_tempaddr=1" + '') (filter (i: !i.preferTempAddress) interfaces); + }) + ] ++ lib.optional (cfg.wlanInterfaces != {}) (pkgs.writeTextFile { name = "99-zzz-40-wlanInterfaces.rules"; destination = "/etc/udev/rules.d/99-zzz-40-wlanInterfaces.rules"; @@ -1161,8 +1177,7 @@ in # Generate the same systemd events for both 'add' and 'move' udev events. ACTION=="move", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName} ''); - }) ]; - + }); }; } diff --git a/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix b/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix index 4e0f2cae299e..828419fb4b9d 100644 --- a/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix +++ b/nixpkgs/nixos/modules/virtualisation/parallels-guest.nix @@ -47,7 +47,7 @@ in config = mkIf config.hardware.parallels.enable { services.xserver = { drivers = singleton - { name = "prlvideo"; modules = [ prl-tools ]; libPath = [ prl-tools ]; }; + { name = "prlvideo"; modules = [ prl-tools ]; }; screenSection = '' Option "NoMTRR" @@ -65,6 +65,7 @@ in hardware.opengl.package = prl-tools; hardware.opengl.package32 = pkgs.pkgsi686Linux.linuxPackages.prl-tools.override { libsOnly = true; kernel = null; }; + hardware.opengl.setLdLibraryPath = true; services.udev.packages = [ prl-tools ]; diff --git a/nixpkgs/nixos/release-combined.nix b/nixpkgs/nixos/release-combined.nix index b9a9515f94ef..7146aebf54be 100644 --- a/nixpkgs/nixos/release-combined.nix +++ b/nixpkgs/nixos/release-combined.nix @@ -68,8 +68,9 @@ in rec { nixos.tests.chromium.x86_64-linux or [] (all nixos.tests.firefox) (all nixos.tests.firewall) - (except ["aarch64-linux"] nixos.tests.gnome3) - (except ["aarch64-linux"] nixos.tests.pantheon) + (all nixos.tests.gnome3-xorg) + (all nixos.tests.gnome3) + (all nixos.tests.pantheon) nixos.tests.installer.zfsroot.x86_64-linux or [] # ZFS is 64bit only (except ["aarch64-linux"] nixos.tests.installer.lvm) (except ["aarch64-linux"] nixos.tests.installer.luksroot) @@ -103,7 +104,7 @@ in rec { #(all nixos.tests.keymap.neo) #(all nixos.tests.keymap.qwertz) (all nixos.tests.plasma5) - #(all nixos.tests.lightdm) + (all nixos.tests.lightdm) (all nixos.tests.login) (all nixos.tests.misc) (all nixos.tests.mutableUsers) diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix index 665a75e47dad..c24c8ae61a58 100644 --- a/nixpkgs/nixos/tests/all-tests.nix +++ b/nixpkgs/nixos/tests/all-tests.nix @@ -56,7 +56,7 @@ in containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {}; containers-restart_networking = handleTest ./containers-restart_networking.nix {}; containers-tmpfs = handleTest ./containers-tmpfs.nix {}; - #couchdb = handleTest ./couchdb.nix {}; # spidermonkey-1.8.5 is marked as broken + couchdb = handleTest ./couchdb.nix {}; deluge = handleTest ./deluge.nix {}; dhparams = handleTest ./dhparams.nix {}; dnscrypt-proxy = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy.nix {}; @@ -85,6 +85,7 @@ in flannel = handleTestOn ["x86_64-linux"] ./flannel.nix {}; flatpak = handleTest ./flatpak.nix {}; flatpak-builder = handleTest ./flatpak-builder.nix {}; + fluentd = handleTest ./fluentd.nix {}; fsck = handleTest ./fsck.nix {}; fwupd = handleTestOn ["x86_64-linux"] ./fwupd.nix {}; # libsmbios is unsupported on aarch64 gdk-pixbuf = handleTest ./gdk-pixbuf.nix {}; @@ -92,14 +93,15 @@ in gitlab = handleTest ./gitlab.nix {}; gitolite = handleTest ./gitolite.nix {}; gjs = handleTest ./gjs.nix {}; - gnome3 = handleTestOn ["x86_64-linux"] ./gnome3.nix {}; # libsmbios is unsupported on aarch64 - gnome3-gdm = handleTestOn ["x86_64-linux"] ./gnome3-gdm.nix {}; # libsmbios is unsupported on aarch64 + gnome3-xorg = handleTest ./gnome3-xorg.nix {}; + gnome3 = handleTest ./gnome3.nix {}; gocd-agent = handleTest ./gocd-agent.nix {}; gocd-server = handleTest ./gocd-server.nix {}; google-oslogin = handleTest ./google-oslogin {}; graphene = handleTest ./graphene.nix {}; grafana = handleTest ./grafana.nix {}; graphite = handleTest ./graphite.nix {}; + graylog = handleTest ./graylog.nix {}; hadoop.hdfs = handleTestOn [ "x86_64-linux" ] ./hadoop/hdfs.nix {}; hadoop.yarn = handleTestOn [ "x86_64-linux" ] ./hadoop/yarn.nix {}; handbrake = handleTestOn ["x86_64-linux"] ./handbrake.nix {}; @@ -137,7 +139,7 @@ in ldap = handleTest ./ldap.nix {}; leaps = handleTest ./leaps.nix {}; lidarr = handleTest ./lidarr.nix {}; - #lightdm = handleTest ./lightdm.nix {}; + lightdm = handleTest ./lightdm.nix {}; limesurvey = handleTest ./limesurvey.nix {}; login = handleTest ./login.nix {}; loki = handleTest ./loki.nix {}; @@ -145,6 +147,7 @@ in mailcatcher = handleTest ./mailcatcher.nix {}; mathics = handleTest ./mathics.nix {}; matrix-synapse = handleTest ./matrix-synapse.nix {}; + mediawiki = handleTest ./mediawiki.nix {}; memcached = handleTest ./memcached.nix {}; mesos = handleTest ./mesos.nix {}; miniflux = handleTest ./miniflux.nix {}; @@ -180,6 +183,7 @@ in nginx = handleTest ./nginx.nix {}; nginx-sso = handleTest ./nginx-sso.nix {}; nix-ssh-serve = handleTest ./nix-ssh-serve.nix {}; + nixos-generate-config = handleTest ./nixos-generate-config.nix {}; novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {}; nsd = handleTest ./nsd.nix {}; nzbget = handleTest ./nzbget.nix {}; @@ -206,6 +210,7 @@ in plotinus = handleTest ./plotinus.nix {}; postgis = handleTest ./postgis.nix {}; postgresql = handleTest ./postgresql.nix {}; + postgresql-wal-receiver = handleTest ./postgresql-wal-receiver.nix {}; powerdns = handleTest ./powerdns.nix {}; predictable-interface-names = handleTest ./predictable-interface-names.nix {}; printing = handleTest ./printing.nix {}; @@ -247,8 +252,8 @@ in pdns-recursor = handleTest ./pdns-recursor.nix {}; taskserver = handleTest ./taskserver.nix {}; telegraf = handleTest ./telegraf.nix {}; + tiddlywiki = handleTest ./tiddlywiki.nix {}; tinydns = handleTest ./tinydns.nix {}; - tomcat = handleTest ./tomcat.nix {}; tor = handleTest ./tor.nix {}; transmission = handleTest ./transmission.nix {}; udisks2 = handleTest ./udisks2.nix {}; diff --git a/nixpkgs/nixos/tests/boot.nix b/nixpkgs/nixos/tests/boot.nix index c9bb1e77c6d0..57d8006d7ac3 100644 --- a/nixpkgs/nixos/tests/boot.nix +++ b/nixpkgs/nixos/tests/boot.nix @@ -17,46 +17,33 @@ let ]; }).config.system.build.isoImage; - makeBootTest = name: machineConfig: - makeTest { - inherit iso; - name = "boot-" + name; - nodes = { }; - testScript = - '' - my $machine = createMachine({ ${machineConfig}, qemuFlags => '-m 768' }); - $machine->start; - $machine->waitForUnit("multi-user.target"); - $machine->succeed("nix verify -r --no-trust /run/current-system"); + perlAttrs = params: "{ ${concatStringsSep ", " (mapAttrsToList (name: param: "${name} => ${builtins.toJSON param}") params)} }"; - # Test whether the channel got installed correctly. - $machine->succeed("nix-instantiate --dry-run '<nixpkgs>' -A hello"); - $machine->succeed("nix-env --dry-run -iA nixos.procps"); - - $machine->shutdown; - ''; - }; -in { - - biosCdrom = makeBootTest "bios-cdrom" '' - cdrom => glob("${iso}/iso/*.iso") - ''; - - biosUsb = makeBootTest "bios-usb" '' - usb => glob("${iso}/iso/*.iso") - ''; + makeBootTest = name: extraConfig: + let + machineConfig = perlAttrs ({ qemuFlags = "-m 768"; } // extraConfig); + in + makeTest { + inherit iso; + name = "boot-" + name; + nodes = { }; + testScript = + '' + my $machine = createMachine(${machineConfig}); + $machine->start; + $machine->waitForUnit("multi-user.target"); + $machine->succeed("nix verify -r --no-trust /run/current-system"); - uefiCdrom = makeBootTest "uefi-cdrom" '' - cdrom => glob("${iso}/iso/*.iso"), - bios => '${pkgs.OVMF.fd}/FV/OVMF.fd' - ''; + # Test whether the channel got installed correctly. + $machine->succeed("nix-instantiate --dry-run '<nixpkgs>' -A hello"); + $machine->succeed("nix-env --dry-run -iA nixos.procps"); - uefiUsb = makeBootTest "uefi-usb" '' - usb => glob("${iso}/iso/*.iso"), - bios => '${pkgs.OVMF.fd}/FV/OVMF.fd' - ''; + $machine->shutdown; + ''; + }; - netboot = let + makeNetbootTest = name: extraConfig: + let config = (import ../lib/eval-config.nix { inherit system; modules = @@ -65,35 +52,55 @@ in { { key = "serial"; } ]; }).config; - ipxeScriptDir = pkgs.writeTextFile { - name = "ipxeScriptDir"; - text = '' - #!ipxe - dhcp - kernel bzImage init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} console=ttyS0 - initrd initrd - boot - ''; - destination = "/boot.ipxe"; - }; ipxeBootDir = pkgs.symlinkJoin { name = "ipxeBootDir"; paths = [ config.system.build.netbootRamdisk config.system.build.kernel - ipxeScriptDir + config.system.build.netbootIpxeScript ]; }; + machineConfig = perlAttrs ({ + qemuFlags = "-boot order=n -m 2000"; + netBackendArgs = "tftp=${ipxeBootDir},bootfile=netboot.ipxe"; + } // extraConfig); in makeTest { - name = "boot-netboot"; + name = "boot-netboot-" + name; nodes = { }; testScript = '' - my $machine = createMachine({ qemuFlags => '-boot order=n -net nic,model=e1000 -net user,tftp=${ipxeBootDir}/,bootfile=boot.ipxe -m 2000M' }); + my $machine = createMachine(${machineConfig}); $machine->start; $machine->waitForUnit("multi-user.target"); $machine->shutdown; ''; }; +in { + + biosCdrom = makeBootTest "bios-cdrom" { + cdrom = "${iso}/iso/${iso.isoName}"; + }; + + biosUsb = makeBootTest "bios-usb" { + usb = "${iso}/iso/${iso.isoName}"; + }; + + uefiCdrom = makeBootTest "uefi-cdrom" { + cdrom = "${iso}/iso/${iso.isoName}"; + bios = "${pkgs.OVMF.fd}/FV/OVMF.fd"; + }; + + uefiUsb = makeBootTest "uefi-usb" { + usb = "${iso}/iso/${iso.isoName}"; + bios = "${pkgs.OVMF.fd}/FV/OVMF.fd"; + }; + + biosNetboot = makeNetbootTest "bios" {}; + + uefiNetboot = makeNetbootTest "uefi" { + bios = "${pkgs.OVMF.fd}/FV/OVMF.fd"; + # Custom ROM is needed for EFI PXE boot. I failed to understand exactly why, because QEMU should still use iPXE for EFI. + netFrontendArgs = "romfile=${pkgs.ipxe}/ipxe.efirom"; + }; } diff --git a/nixpkgs/nixos/tests/cassandra.nix b/nixpkgs/nixos/tests/cassandra.nix index aea4fa4d1c95..c55733c9be7b 100644 --- a/nixpkgs/nixos/tests/cassandra.nix +++ b/nixpkgs/nixos/tests/cassandra.nix @@ -8,11 +8,12 @@ let jmxRoles = [{ username = "me"; password = "password"; }]; jmxRolesFile = ./cassandra-jmx-roles; jmxAuthArgs = "-u ${(builtins.elemAt jmxRoles 0).username} -pw ${(builtins.elemAt jmxRoles 0).password}"; + jmxPort = 7200; # Non-standard port so it doesn't accidentally work # Would usually be assigned to 512M numMaxHeapSize = "400"; getHeapLimitCommand = '' - nodetool info | grep "^Heap Memory" | awk \'{print $NF}\' + nodetool info -p ${toString jmxPort} | grep "^Heap Memory" | awk \'{print $NF}\' ''; checkHeapLimitCommand = '' [ 1 -eq "$(echo "$(${getHeapLimitCommand}) < ${numMaxHeapSize}" | ${pkgs.bc}/bin/bc)" ] @@ -27,19 +28,20 @@ let package = testPackage; maxHeapSize = "${numMaxHeapSize}M"; heapNewSize = "100M"; + inherit jmxPort; }; - nodeCfg = ipAddress: extra: {pkgs, config, ...}: - { environment.systemPackages = [ testPackage ]; - networking = { - firewall.allowedTCPPorts = [ 7000 7199 9042 ]; - useDHCP = false; - interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [ - { address = ipAddress; prefixLength = 24; } - ]; - }; - services.cassandra = cassandraCfg ipAddress // extra; - virtualisation.memorySize = 1024; + nodeCfg = ipAddress: extra: {pkgs, config, ...}: rec { + environment.systemPackages = [ testPackage ]; + networking = { + firewall.allowedTCPPorts = [ 7000 9042 services.cassandra.jmxPort ]; + useDHCP = false; + interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [ + { address = ipAddress; prefixLength = 24; } + ]; }; + services.cassandra = cassandraCfg ipAddress // extra; + virtualisation.memorySize = 1024; + }; in { name = "cassandra-ci"; @@ -50,7 +52,9 @@ in cass2 = nodeCfg "192.168.1.3" { jvmOpts = [ "-Dcassandra.replace_address=cass1" ]; }; }; - testScript = '' + testScript = let + jmxPortS = toString jmxPort; + in '' # Check configuration subtest "Timers exist", sub { $cass0->succeed("systemctl list-timers | grep cassandra-full-repair.timer"); @@ -63,51 +67,51 @@ in }; subtest "Nodetool is operational", sub { $cass0->waitForUnit("cassandra.service"); - $cass0->waitUntilSucceeds("nc -z localhost 7199"); - $cass0->succeed("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass0'"); + $cass0->waitUntilSucceeds("nc -z localhost ${jmxPortS}"); + $cass0->succeed("nodetool status -p ${jmxPortS} --resolve-ip | egrep '^UN[[:space:]]+cass0'"); }; subtest "Cluster name was set", sub { $cass0->waitForUnit("cassandra.service"); - $cass0->waitUntilSucceeds("nc -z localhost 7199"); - $cass0->waitUntilSucceeds("nodetool describecluster | grep 'Name: ${clusterName}'"); + $cass0->waitUntilSucceeds("nc -z localhost ${jmxPortS}"); + $cass0->waitUntilSucceeds("nodetool describecluster -p ${jmxPortS} | grep 'Name: ${clusterName}'"); }; subtest "Heap limit set correctly", sub { # Nodetool takes a while until it can display info - $cass0->waitUntilSucceeds('nodetool info'); + $cass0->waitUntilSucceeds('nodetool info -p ${jmxPortS}'); $cass0->succeed('${checkHeapLimitCommand}'); }; # Check cluster interaction subtest "Bring up cluster", sub { $cass1->waitForUnit("cassandra.service"); - $cass1->waitUntilSucceeds("nodetool ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"); - $cass0->succeed("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass1'"); + $cass1->waitUntilSucceeds("nodetool -p ${jmxPortS} ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"); + $cass0->succeed("nodetool status -p ${jmxPortS} --resolve-ip | egrep '^UN[[:space:]]+cass1'"); }; '' + lib.optionalString testRemoteAuth '' subtest "Remote authenticated jmx", sub { # Doesn't work if not enabled - $cass0->waitUntilSucceeds("nc -z localhost 7199"); - $cass1->fail("nc -z 192.168.1.1 7199"); - $cass1->fail("nodetool -h 192.168.1.1 status"); + $cass0->waitUntilSucceeds("nc -z localhost ${jmxPortS}"); + $cass1->fail("nc -z 192.168.1.1 ${toString jmxPort}"); + $cass1->fail("nodetool -p ${jmxPortS} -h 192.168.1.1 status"); # Works if enabled - $cass1->waitUntilSucceeds("nc -z localhost 7199"); - $cass0->succeed("nodetool -h 192.168.1.2 ${jmxAuthArgs} status"); + $cass1->waitUntilSucceeds("nc -z localhost ${toString jmxPort}"); + $cass0->succeed("nodetool -p ${jmxPortS} -h 192.168.1.2 ${jmxAuthArgs} status"); }; '' + '' subtest "Break and fix node", sub { $cass1->block; - $cass0->waitUntilSucceeds("nodetool status --resolve-ip | egrep -c '^DN[[:space:]]+cass1'"); - $cass0->succeed("nodetool status | egrep -c '^UN' | grep 1"); + $cass0->waitUntilSucceeds("nodetool status -p ${jmxPortS} --resolve-ip | egrep -c '^DN[[:space:]]+cass1'"); + $cass0->succeed("nodetool status -p ${jmxPortS} | egrep -c '^UN' | grep 1"); $cass1->unblock; - $cass1->waitUntilSucceeds("nodetool ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"); - $cass0->succeed("nodetool status | egrep -c '^UN' | grep 2"); + $cass1->waitUntilSucceeds("nodetool -p ${jmxPortS} ${jmxAuthArgs} status | egrep -c '^UN' | grep 2"); + $cass0->succeed("nodetool status -p ${jmxPortS} | egrep -c '^UN' | grep 2"); }; subtest "Replace crashed node", sub { $cass1->crash; $cass2->waitForUnit("cassandra.service"); - $cass0->waitUntilFails("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass1'"); - $cass0->waitUntilSucceeds("nodetool status --resolve-ip | egrep '^UN[[:space:]]+cass2'"); + $cass0->waitUntilFails("nodetool status -p ${jmxPortS} --resolve-ip | egrep '^UN[[:space:]]+cass1'"); + $cass0->waitUntilSucceeds("nodetool status -p ${jmxPortS} --resolve-ip | egrep '^UN[[:space:]]+cass2'"); }; ''; }) diff --git a/nixpkgs/nixos/tests/deluge.nix b/nixpkgs/nixos/tests/deluge.nix index 22ad84e7bff1..b58030409b5c 100644 --- a/nixpkgs/nixos/tests/deluge.nix +++ b/nixpkgs/nixos/tests/deluge.nix @@ -8,9 +8,11 @@ import ./make-test.nix ({ pkgs, ...} : { simple = { services.deluge = { enable = true; - web.enable = true; + web = { + enable = true; + openFirewall = true; + }; }; - networking.firewall.allowedTCPPorts = [ 8112 ]; }; declarative = diff --git a/nixpkgs/nixos/tests/flatpak-builder.nix b/nixpkgs/nixos/tests/flatpak-builder.nix index 2100631ec7f4..49b97e8ca99e 100644 --- a/nixpkgs/nixos/tests/flatpak-builder.nix +++ b/nixpkgs/nixos/tests/flatpak-builder.nix @@ -9,6 +9,7 @@ import ./make-test.nix ({ pkgs, ... }: machine = { pkgs, ... }: { services.flatpak.enable = true; + xdg.portal.enable = true; environment.systemPackages = with pkgs; [ gnome-desktop-testing flatpak-builder ] ++ flatpak-builder.installedTestsDependencies; virtualisation.diskSize = 2048; }; diff --git a/nixpkgs/nixos/tests/fluentd.nix b/nixpkgs/nixos/tests/fluentd.nix new file mode 100644 index 000000000000..e5c4c3d21631 --- /dev/null +++ b/nixpkgs/nixos/tests/fluentd.nix @@ -0,0 +1,46 @@ +import ./make-test.nix ({ pkgs, lib, ... }: { + name = "fluentd"; + + machine = { pkgs, ... }: { + services.fluentd = { + enable = true; + config = '' + <source> + @type http + port 9880 + </source> + + <match **> + type copy + <store> + @type file + format json + path /tmp/fluentd + symlink_path /tmp/current-log + </store> + <store> + @type stdout + </store> + </match> + ''; + }; + }; + + testScript = let + testMessage = "an example log message"; + + payload = pkgs.writeText "test-message.json" (builtins.toJSON { + inherit testMessage; + }); + in '' + $machine->start; + $machine->waitForUnit('fluentd.service'); + $machine->waitForOpenPort(9880); + + $machine->succeed("curl -fsSL -X POST -H 'Content-type: application/json' -d @${payload} http://localhost:9880/test.tag"); + + $machine->succeed("systemctl stop fluentd"); # blocking flush + + $machine->succeed("grep '${testMessage}' /tmp/current-log"); + ''; +}) diff --git a/nixpkgs/nixos/tests/gdk-pixbuf.nix b/nixpkgs/nixos/tests/gdk-pixbuf.nix index 005c5111da2b..9a62b593f46d 100644 --- a/nixpkgs/nixos/tests/gdk-pixbuf.nix +++ b/nixpkgs/nixos/tests/gdk-pixbuf.nix @@ -3,12 +3,12 @@ import ./make-test.nix ({ pkgs, ... }: { name = "gdk-pixbuf"; meta = { - maintainers = pkgs.gdk_pixbuf.meta.maintainers; + maintainers = pkgs.gdk-pixbuf.meta.maintainers; }; machine = { pkgs, ... }: { environment.systemPackages = with pkgs; [ gnome-desktop-testing ]; - environment.variables.XDG_DATA_DIRS = [ "${pkgs.gdk_pixbuf.installedTests}/share" ]; + environment.variables.XDG_DATA_DIRS = [ "${pkgs.gdk-pixbuf.installedTests}/share" ]; # Tests allocate a lot of memory trying to exploit a CVE # but qemu-system-i386 has a 2047M memory limit diff --git a/nixpkgs/nixos/tests/gnome3-gdm.nix b/nixpkgs/nixos/tests/gnome3-gdm.nix deleted file mode 100644 index c2808d87d99d..000000000000 --- a/nixpkgs/nixos/tests/gnome3-gdm.nix +++ /dev/null @@ -1,63 +0,0 @@ -import ./make-test.nix ({ pkgs, ...} : { - name = "gnome3-gdm"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ lethalman ]; - }; - - machine = - { ... }: - - { imports = [ ./common/user-account.nix ]; - - services.xserver.enable = true; - - services.xserver.displayManager.gdm = { - enable = true; - autoLogin = { - enable = true; - user = "alice"; - }; - }; - services.xserver.desktopManager.gnome3.enable = true; - - virtualisation.memorySize = 1024; - }; - - testScript = let - # Keep line widths somewhat managable - bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"; - gdbus = "${bus} gdbus"; - # Call javascript in gnome shell, returns a tuple (success, output), where - # `success` is true if the dbus call was successful and output is what the - # javascript evaluates to. - eval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval"; - # False when startup is done - startingUp = "${gdbus} ${eval} Main.layoutManager._startingUp"; - # Hopefully gnome-terminal's wm class - wmClass = "${gdbus} ${eval} global.display.focus_window.wm_class"; - in '' - # wait for gdm to start - $machine->waitForUnit("display-manager.service"); - - # wait for alice to be logged in - $machine->waitForUnit("default.target","alice"); - - # Check that logging in has given the user ownership of devices. - $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); - - # Wait for the wayland server - $machine->waitForFile("/run/user/1000/wayland-0"); - - # Wait for gnome shell, correct output should be "(true, 'false')" - $machine->waitUntilSucceeds("su - alice -c '${startingUp} | grep -q true,..false'"); - - # open a terminal - $machine->succeed("su - alice -c '${bus} gnome-terminal'"); - # and check it's there - $machine->waitUntilSucceeds("su - alice -c '${wmClass} | grep -q gnome-terminal-server'"); - - # wait to get a nice screenshot - $machine->sleep(20); - $machine->screenshot("screen"); - ''; -}) diff --git a/nixpkgs/nixos/tests/gnome3-xorg.nix b/nixpkgs/nixos/tests/gnome3-xorg.nix new file mode 100644 index 000000000000..f12361da0372 --- /dev/null +++ b/nixpkgs/nixos/tests/gnome3-xorg.nix @@ -0,0 +1,41 @@ +import ./make-test.nix ({ pkgs, ...} : { + name = "gnome3-xorg"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = pkgs.gnome3.maintainers; + }; + + machine = + { ... }: + + { imports = [ ./common/user-account.nix ]; + + services.xserver.enable = true; + + services.xserver.displayManager.gdm.enable = false; + services.xserver.displayManager.lightdm.enable = true; + services.xserver.displayManager.lightdm.autoLogin.enable = true; + services.xserver.displayManager.lightdm.autoLogin.user = "alice"; + services.xserver.desktopManager.gnome3.enable = true; + services.xserver.desktopManager.default = "gnome-xorg"; + + virtualisation.memorySize = 1024; + }; + + testScript = + '' + $machine->waitForX; + + # wait for alice to be logged in + $machine->waitForUnit("default.target","alice"); + + # Check that logging in has given the user ownership of devices. + $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); + + $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'"); + $machine->succeed("xauth merge ~alice/.Xauthority"); + $machine->waitForWindow(qr/alice.*machine/); + $machine->succeed("timeout 900 bash -c 'while read msg; do if [[ \$msg =~ \"GNOME Shell started\" ]]; then break; fi; done < <(journalctl -f)'"); + $machine->sleep(10); + $machine->screenshot("screen"); + ''; +}) diff --git a/nixpkgs/nixos/tests/gnome3.nix b/nixpkgs/nixos/tests/gnome3.nix index b58c9e5a0e32..b6fe602a7327 100644 --- a/nixpkgs/nixos/tests/gnome3.nix +++ b/nixpkgs/nixos/tests/gnome3.nix @@ -1,7 +1,7 @@ import ./make-test.nix ({ pkgs, ...} : { name = "gnome3"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ domenkozar eelco lethalman ]; + maintainers = pkgs.gnome3.maintainers; }; machine = @@ -11,19 +11,34 @@ import ./make-test.nix ({ pkgs, ...} : { services.xserver.enable = true; - services.xserver.displayManager.gdm.enable = false; - services.xserver.displayManager.lightdm.enable = true; - services.xserver.displayManager.lightdm.autoLogin.enable = true; - services.xserver.displayManager.lightdm.autoLogin.user = "alice"; + services.xserver.displayManager.gdm = { + enable = true; + autoLogin = { + enable = true; + user = "alice"; + }; + }; + services.xserver.desktopManager.gnome3.enable = true; - services.xserver.desktopManager.default = "gnome-xorg"; virtualisation.memorySize = 1024; }; - testScript = - '' - $machine->waitForX; + testScript = let + # Keep line widths somewhat managable + bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"; + gdbus = "${bus} gdbus"; + # Call javascript in gnome shell, returns a tuple (success, output), where + # `success` is true if the dbus call was successful and output is what the + # javascript evaluates to. + eval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval"; + # False when startup is done + startingUp = "${gdbus} ${eval} Main.layoutManager._startingUp"; + # Hopefully gnome-terminal's wm class + wmClass = "${gdbus} ${eval} global.display.focus_window.wm_class"; + in '' + # wait for gdm to start + $machine->waitForUnit("display-manager.service"); # wait for alice to be logged in $machine->waitForUnit("default.target","alice"); @@ -31,11 +46,19 @@ import ./make-test.nix ({ pkgs, ...} : { # Check that logging in has given the user ownership of devices. $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); - $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'"); - $machine->succeed("xauth merge ~alice/.Xauthority"); - $machine->waitForWindow(qr/alice.*machine/); - $machine->succeed("timeout 900 bash -c 'while read msg; do if [[ \$msg =~ \"GNOME Shell started\" ]]; then break; fi; done < <(journalctl -f)'"); - $machine->sleep(10); + # Wait for the wayland server + $machine->waitForFile("/run/user/1000/wayland-0"); + + # Wait for gnome shell, correct output should be "(true, 'false')" + $machine->waitUntilSucceeds("su - alice -c '${startingUp} | grep -q true,..false'"); + + # open a terminal + $machine->succeed("su - alice -c '${bus} gnome-terminal'"); + # and check it's there + $machine->waitUntilSucceeds("su - alice -c '${wmClass} | grep -q gnome-terminal-server'"); + + # wait to get a nice screenshot + $machine->sleep(20); $machine->screenshot("screen"); ''; }) diff --git a/nixpkgs/nixos/tests/grafana.nix b/nixpkgs/nixos/tests/grafana.nix index 9dc765a879bc..7a1b4c8ffbbc 100644 --- a/nixpkgs/nixos/tests/grafana.nix +++ b/nixpkgs/nixos/tests/grafana.nix @@ -1,25 +1,91 @@ -import ./make-test.nix ({ lib, ... }: -{ - name = "grafana"; +import ./make-test.nix ({ lib, pkgs, ... }: - meta = with lib.maintainers; { - maintainers = [ willibutz ]; - }; +let + inherit (lib) mkMerge nameValuePair maintainers; - machine = { ... }: { + baseGrafanaConf = { services.grafana = { enable = true; addr = "localhost"; analytics.reporting.enable = false; domain = "localhost"; - security.adminUser = "testusername"; + security = { + adminUser = "testadmin"; + adminPassword = "snakeoilpwd"; + }; }; }; + extraNodeConfs = { + postgresql = { + services.grafana.database = { + host = "127.0.0.1:5432"; + user = "grafana"; + }; + services.postgresql = { + enable = true; + ensureDatabases = [ "grafana" ]; + ensureUsers = [{ + name = "grafana"; + ensurePermissions."DATABASE grafana" = "ALL PRIVILEGES"; + }]; + }; + systemd.services.grafana.after = [ "postgresql.service" ]; + }; + + mysql = { + services.grafana.database.user = "grafana"; + services.mysql = { + enable = true; + ensureDatabases = [ "grafana" ]; + ensureUsers = [{ + name = "grafana"; + ensurePermissions."grafana.*" = "ALL PRIVILEGES"; + }]; + package = pkgs.mariadb; + }; + systemd.services.grafana.after = [ "mysql.service" ]; + }; + }; + + nodes = builtins.listToAttrs (map (dbName: + nameValuePair dbName (mkMerge [ + baseGrafanaConf + (extraNodeConfs.${dbName} or {}) + ])) [ "sqlite" "postgresql" "mysql" ]); + +in { + name = "grafana"; + + meta = with maintainers; { + maintainers = [ willibutz ]; + }; + + inherit nodes; + testScript = '' - $machine->start; - $machine->waitForUnit("grafana.service"); - $machine->waitForOpenPort(3000); - $machine->succeed("curl -sSfL http://127.0.0.1:3000/"); + startAll(); + + subtest "Grafana sqlite", sub { + $sqlite->waitForUnit("grafana.service"); + $sqlite->waitForOpenPort(3000); + $sqlite->succeed("curl -sSfN -u testadmin:snakeoilpwd http://127.0.0.1:3000/api/org/users | grep -q testadmin\@localhost"); + }; + + subtest "Grafana postgresql", sub { + $postgresql->waitForUnit("grafana.service"); + $postgresql->waitForUnit("postgresql.service"); + $postgresql->waitForOpenPort(3000); + $postgresql->waitForOpenPort(5432); + $postgresql->succeed("curl -sSfN -u testadmin:snakeoilpwd http://127.0.0.1:3000/api/org/users | grep -q testadmin\@localhost"); + }; + + subtest "Grafana mysql", sub { + $mysql->waitForUnit("grafana.service"); + $mysql->waitForUnit("mysql.service"); + $mysql->waitForOpenPort(3000); + $mysql->waitForOpenPort(3306); + $mysql->succeed("curl -sSfN -u testadmin:snakeoilpwd http://127.0.0.1:3000/api/org/users | grep -q testadmin\@localhost"); + }; ''; }) diff --git a/nixpkgs/nixos/tests/graylog.nix b/nixpkgs/nixos/tests/graylog.nix new file mode 100644 index 000000000000..dc54afd1d26d --- /dev/null +++ b/nixpkgs/nixos/tests/graylog.nix @@ -0,0 +1,111 @@ +import ./make-test.nix ({ pkgs, lib, ... }: { + name = "graylog"; + meta.maintainers = with lib.maintainers; [ ma27 ]; + + machine = { pkgs, ... }: { + virtualisation.memorySize = 4096; + virtualisation.diskSize = 4096; + + services.mongodb.enable = true; + services.elasticsearch.enable = true; + services.elasticsearch.package = pkgs.elasticsearch-oss; + services.elasticsearch.extraConf = '' + network.publish_host: 127.0.0.1 + network.bind_host: 127.0.0.1 + ''; + + services.graylog = { + enable = true; + passwordSecret = "YGhZ59wXMrYOojx5xdgEpBpDw2N6FbhM4lTtaJ1KPxxmKrUvSlDbtWArwAWMQ5LKx1ojHEVrQrBMVRdXbRyZLqffoUzHfssc"; + elasticsearchHosts = [ "http://localhost:9200" ]; + + # `echo -n "nixos" | shasum -a 256` + rootPasswordSha2 = "6ed332bcfa615381511d4d5ba44a293bb476f368f7e9e304f0dff50230d1a85b"; + }; + + environment.systemPackages = [ pkgs.jq ]; + + systemd.services.graylog.path = [ pkgs.netcat ]; + systemd.services.graylog.preStart = '' + until nc -z localhost 9200; do + sleep 2 + done + ''; + }; + + testScript = let + payloads.login = pkgs.writeText "login.json" (builtins.toJSON { + host = "127.0.0.1:9000"; + username = "admin"; + password = "nixos"; + }); + + payloads.input = pkgs.writeText "input.json" (builtins.toJSON { + title = "Demo"; + global = false; + type = "org.graylog2.inputs.gelf.udp.GELFUDPInput"; + node = "@node@"; + configuration = { + bind_address = "0.0.0.0"; + decompress_size_limit = 8388608; + number_worker_threads = 1; + override_source = null; + port = 12201; + recv_buffer_size = 262144; + }; + }); + + payloads.gelf_message = pkgs.writeText "gelf.json" (builtins.toJSON { + host = "example.org"; + short_message = "A short message"; + full_message = "A long message"; + version = "1.1"; + level = 5; + facility = "Test"; + }); + in '' + $machine->start; + $machine->waitForUnit("graylog.service"); + $machine->waitForOpenPort(9000); + $machine->succeed("curl -sSfL http://127.0.0.1:9000/"); + + my $session = $machine->succeed("curl -X POST " + . "-sSfL http://127.0.0.1:9000/api/system/sessions " + . "-d \$(cat ${payloads.login}) " + . "-H 'Content-Type: application/json' " + . "-H 'Accept: application/json' " + . "-H 'x-requested-by: cli' " + . "| jq .session_id | xargs echo" + ); + + chomp($session); + + $machine->succeed("curl -X POST " + . "-sSfL http://127.0.0.1:9000/api/system/inputs -u $session:session " + . "-d \$(cat ${payloads.input} | sed -e \"s,\@node\@,\$(cat /var/lib/graylog/server/node-id),\") " + . "-H 'Accept: application/json' " + . "-H 'Content-Type: application/json' " + . "-H 'x-requested-by: cli' " + ); + + $machine->waitUntilSucceeds("test \"\$(curl -sSfL 'http://127.0.0.1:9000/api/cluster/inputstates' " + . "-u $session:session " + . "-H 'Accept: application/json' " + . "-H 'Content-Type: application/json' " + . "-H 'x-requested-by: cli'" + . "| jq 'to_entries[]|.value|.[0]|.state' | xargs echo" + . ")\" = \"RUNNING\"" + ); + + $machine->succeed("echo -n \$(cat ${payloads.gelf_message}) | nc -w10 -u 127.0.0.1 12201"); + + $machine->succeed("test \"\$(curl -X GET " + . "-sSfL 'http://127.0.0.1:9000/api/search/universal/relative?query=*' " + . "-u $session:session " + . "-H 'Accept: application/json' " + . "-H 'Content-Type: application/json' " + . "-H 'x-requested-by: cli'" + . " | jq '.total_results' | xargs echo)\" = \"1\"" + ); + ''; +}) diff --git a/nixpkgs/nixos/tests/initdb.nix b/nixpkgs/nixos/tests/initdb.nix new file mode 100644 index 000000000000..749d7857a134 --- /dev/null +++ b/nixpkgs/nixos/tests/initdb.nix @@ -0,0 +1,26 @@ +let + pkgs = import <nixpkgs> { }; +in +with import <nixpkgs/nixos/lib/testing.nix> { inherit pkgs; system = builtins.currentSystem; }; +with pkgs.lib; + +makeTest { + name = "pg-initdb"; + + machine = {...}: + { + documentation.enable = false; + services.postgresql.enable = true; + services.postgresql.package = pkgs.postgresql_9_6; + environment.pathsToLink = [ + "/share/postgresql" + ]; + }; + + testScript = '' + $machine->start; + $machine->succeed("sudo -u postgres initdb -D /tmp/testpostgres2"); + $machine->shutdown; + ''; + + } \ No newline at end of file diff --git a/nixpkgs/nixos/tests/installer.nix b/nixpkgs/nixos/tests/installer.nix index 07659b60b3b8..a136678c6eff 100644 --- a/nixpkgs/nixos/tests/installer.nix +++ b/nixpkgs/nixos/tests/installer.nix @@ -67,6 +67,7 @@ let # partitions and filesystems. testScriptFun = { bootLoader, createPartitions, grubVersion, grubDevice, grubUseEfi , grubIdentifier, preBootCommands, extraConfig + , testCloneConfig }: let iface = if grubVersion == 1 then "ide" else "virtio"; @@ -85,6 +86,7 @@ let in if !isEfi && !(pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then throw "Non-EFI boot methods are only supported on i686 / x86_64" else '' + $machine->start; # Make sure that we get a login prompt etc. @@ -185,6 +187,43 @@ let ${preBootCommands} $machine->waitForUnit("network.target"); $machine->shutdown; + + # Tests for validating clone configuration entries in grub menu + ${optionalString testCloneConfig '' + # Reboot Machine + $machine = createMachine({ ${hdFlags} qemuFlags => "${qemuFlags}", name => "clone-default-config" }); + ${preBootCommands} + $machine->waitForUnit("multi-user.target"); + + # Booted configuration name should be Home + # This is not the name that shows in the grub menu. + # The default configuration is always shown as "Default" + $machine->succeed("cat /run/booted-system/configuration-name >&2"); + $machine->succeed("cat /run/booted-system/configuration-name | grep Home"); + + # We should find **not** a file named /etc/gitconfig + $machine->fail("test -e /etc/gitconfig"); + + # Set grub to boot the second configuration + $machine->succeed("grub-reboot 1"); + + $machine->shutdown; + + # Reboot Machine + $machine = createMachine({ ${hdFlags} qemuFlags => "${qemuFlags}", name => "clone-alternate-config" }); + ${preBootCommands} + + $machine->waitForUnit("multi-user.target"); + # Booted configuration name should be Work + $machine->succeed("cat /run/booted-system/configuration-name >&2"); + $machine->succeed("cat /run/booted-system/configuration-name | grep Work"); + + # We should find a file named /etc/gitconfig + $machine->succeed("test -e /etc/gitconfig"); + + $machine->shutdown; + ''} + ''; @@ -194,6 +233,7 @@ let , bootLoader ? "grub" # either "grub" or "systemd-boot" , grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid", grubUseEfi ? false , enableOCR ? false, meta ? {} + , testCloneConfig ? false }: makeTest { inherit enableOCR; @@ -269,7 +309,8 @@ let testScript = testScriptFun { inherit bootLoader createPartitions preBootCommands - grubVersion grubDevice grubIdentifier grubUseEfi extraConfig; + grubVersion grubDevice grubIdentifier grubUseEfi extraConfig + testCloneConfig; }; }; @@ -304,32 +345,24 @@ let ''; }; - -in { - - # !!! `parted mkpart' seems to silently create overlapping partitions. - - # The (almost) simplest partitioning scheme: a swap partition and # one big filesystem partition. - simple = makeInstallerTest "simple" - { createPartitions = - '' - $machine->succeed( - "flock /dev/vda parted --script /dev/vda -- mklabel msdos" - . " mkpart primary linux-swap 1M 1024M" - . " mkpart primary ext2 1024M -1s", - "udevadm settle", - "mkswap /dev/vda1 -L swap", - "swapon -L swap", - "mkfs.ext3 -L nixos /dev/vda2", - "mount LABEL=nixos /mnt", - ); - ''; - }; - - # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem - simpleUefiSystemdBoot = makeInstallerTest "simpleUefiSystemdBoot" + simple-test-config = { createPartitions = + '' + $machine->succeed( + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary linux-swap 1M 1024M" + . " mkpart primary ext2 1024M -1s", + "udevadm settle", + "mkswap /dev/vda1 -L swap", + "swapon -L swap", + "mkfs.ext3 -L nixos /dev/vda2", + "mount LABEL=nixos /mnt", + ); + ''; + }; + + simple-uefi-grub-config = { createPartitions = '' $machine->succeed( @@ -348,10 +381,45 @@ in { "mount LABEL=BOOT /mnt/boot", ); ''; - bootLoader = "systemd-boot"; + bootLoader = "grub"; + grubUseEfi = true; }; - simpleUefiGrub = makeInstallerTest "simpleUefiGrub" + clone-test-extraconfig = { extraConfig = + '' + environment.systemPackages = [ pkgs.grub2 ]; + boot.loader.grub.configurationName = "Home"; + nesting.clone = [ + { + boot.loader.grub.configurationName = lib.mkForce "Work"; + + environment.etc = { + "gitconfig".text = " + [core] + gitproxy = none for work.com + "; + }; + } + ]; + ''; + testCloneConfig = true; + }; + + +in { + + # !!! `parted mkpart' seems to silently create overlapping partitions. + + + # The (almost) simplest partitioning scheme: a swap partition and + # one big filesystem partition. + simple = makeInstallerTest "simple" simple-test-config; + + # Test cloned configurations with the simple grub configuration + simpleClone = makeInstallerTest "simpleClone" (simple-test-config // clone-test-extraconfig); + + # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem + simpleUefiSystemdBoot = makeInstallerTest "simpleUefiSystemdBoot" { createPartitions = '' $machine->succeed( @@ -370,10 +438,14 @@ in { "mount LABEL=BOOT /mnt/boot", ); ''; - bootLoader = "grub"; - grubUseEfi = true; + bootLoader = "systemd-boot"; }; + simpleUefiGrub = makeInstallerTest "simpleUefiGrub" simple-uefi-grub-config; + + # Test cloned configurations with the uefi grub configuration + simpleUefiGrubClone = makeInstallerTest "simpleUefiGrubClone" (simple-uefi-grub-config // clone-test-extraconfig); + # Same as the previous, but now with a separate /boot partition. separateBoot = makeInstallerTest "separateBoot" { createPartitions = diff --git a/nixpkgs/nixos/tests/ipv6.nix b/nixpkgs/nixos/tests/ipv6.nix index 14f24c29cfe2..d11eba764da3 100644 --- a/nixpkgs/nixos/tests/ipv6.nix +++ b/nixpkgs/nixos/tests/ipv6.nix @@ -1,14 +1,16 @@ # Test of IPv6 functionality in NixOS, including whether router # solicication/advertisement using radvd works. -import ./make-test.nix ({ pkgs, ...} : { +import ./make-test.nix ({ pkgs, lib, ...} : { name = "ipv6"; meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ eelco ]; }; nodes = - { client = { ... }: { }; + # Remove the interface configuration provided by makeTest so that the + # interfaces are all configured implicitly + { client = { ... }: { networking.interfaces = lib.mkForce {}; }; server = { ... }: @@ -73,6 +75,11 @@ import ./make-test.nix ({ pkgs, ...} : { $client->succeed("curl --fail -g http://[$serverIp]"); $client->fail("curl --fail -g http://[$clientIp]"); }; + subtest "privacy extensions", sub { + my $ip = waitForAddress $client, "eth1", "global temporary"; + # Default route should have "src <temporary address>" in it + $client->succeed("ip r g ::2 | grep $ip"); + }; # TODO: test reachability of a machine on another network. ''; diff --git a/nixpkgs/nixos/tests/lightdm.nix b/nixpkgs/nixos/tests/lightdm.nix index 8a9a7408d292..c805f1ed9f3c 100644 --- a/nixpkgs/nixos/tests/lightdm.nix +++ b/nixpkgs/nixos/tests/lightdm.nix @@ -1,7 +1,7 @@ import ./make-test.nix ({ pkgs, ...} : { name = "lightdm"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ aszlig ]; + maintainers = [ aszlig worldofpeace ]; }; machine = { ... }: { diff --git a/nixpkgs/nixos/tests/mediawiki.nix b/nixpkgs/nixos/tests/mediawiki.nix new file mode 100644 index 000000000000..6293e8a2f465 --- /dev/null +++ b/nixpkgs/nixos/tests/mediawiki.nix @@ -0,0 +1,19 @@ +import ./make-test.nix ({ pkgs, lib, ... }: { + name = "mediawiki"; + meta.maintainers = [ lib.maintainers.aanderse ]; + + machine = + { ... }: + { services.mediawiki.enable = true; + services.mediawiki.virtualHost.hostName = "localhost"; + services.mediawiki.virtualHost.adminAddr = "root@example.com"; + services.mediawiki.passwordFile = pkgs.writeText "password" "correcthorsebatterystaple"; + }; + + testScript = '' + startAll; + + $machine->waitForUnit('phpfpm-mediawiki.service'); + $machine->succeed('curl -L http://localhost/') =~ /MediaWiki has been installed/ or die; + ''; +}) diff --git a/nixpkgs/nixos/tests/mysql.nix b/nixpkgs/nixos/tests/mysql.nix index abf9606aa366..05bd968de02d 100644 --- a/nixpkgs/nixos/tests/mysql.nix +++ b/nixpkgs/nixos/tests/mysql.nix @@ -19,7 +19,7 @@ import ./make-test.nix ({ pkgs, ...} : { services.mysql.initialScript = pkgs.writeText "mysql-init.sql" '' CREATE USER 'passworduser'@'localhost' IDENTIFIED BY 'password123'; ''; - services.mysql.package = pkgs.mysql; + services.mysql.package = pkgs.mysql57; }; mariadb = diff --git a/nixpkgs/nixos/tests/networking.nix b/nixpkgs/nixos/tests/networking.nix index ed9f287d5582..949d946bdc4c 100644 --- a/nixpkgs/nixos/tests/networking.nix +++ b/nixpkgs/nixos/tests/networking.nix @@ -510,7 +510,7 @@ let ''; }; }; - nodes.client = { pkgs, ... }: with pkgs.lib; { + nodes.clientWithPrivacy = { pkgs, ... }: with pkgs.lib; { virtualisation.vlans = [ 1 ]; networking = { useNetworkd = networkd; @@ -522,21 +522,39 @@ let }; }; }; + nodes.client = { pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 ]; + networking = { + useNetworkd = networkd; + useDHCP = true; + interfaces.eth1 = { + preferTempAddress = false; + ipv4.addresses = mkOverride 0 [ ]; + ipv6.addresses = mkOverride 0 [ ]; + }; + }; + }; testScript = { ... }: '' startAll; $client->waitForUnit("network.target"); + $clientWithPrivacy->waitForUnit("network.target"); $router->waitForUnit("network-online.target"); # Wait until we have an ip address + $clientWithPrivacy->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'"); $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'"); # Test vlan 1 + $clientWithPrivacy->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1"); $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1"); # Test address used is temporary - $client->waitUntilSucceeds("! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'"); + $clientWithPrivacy->waitUntilSucceeds("! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'"); + + # Test address used is EUI-64 + $client->waitUntilSucceeds("ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'"); ''; }; routes = { diff --git a/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix b/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix index 0351d4db69ac..8a840a608753 100644 --- a/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix +++ b/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix @@ -27,10 +27,7 @@ in { dbtype = "pgsql"; dbname = "nextcloud"; dbuser = "nextcloud"; - dbhost = "localhost"; - dbpassFile = toString (pkgs.writeText "db-pass-file" '' - hunter2 - ''); + dbhost = "/run/postgresql"; inherit adminuser; adminpassFile = toString (pkgs.writeText "admin-pass-file" '' ${adminpass} @@ -84,10 +81,12 @@ in { services.postgresql = { enable = true; - initialScript = pkgs.writeText "psql-init" '' - create role nextcloud with login password 'hunter2'; - create database nextcloud with owner nextcloud; - ''; + ensureDatabases = [ "nextcloud" ]; + ensureUsers = [ + { name = "nextcloud"; + ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; + } + ]; }; }; }; diff --git a/nixpkgs/nixos/tests/nixos-generate-config.nix b/nixpkgs/nixos/tests/nixos-generate-config.nix new file mode 100644 index 000000000000..15a173e024b4 --- /dev/null +++ b/nixpkgs/nixos/tests/nixos-generate-config.nix @@ -0,0 +1,24 @@ +import ./make-test.nix ({ lib, ... } : { + name = "nixos-generate-config"; + meta.maintainers = with lib.maintainers; [ basvandijk ]; + machine = { + system.nixos-generate-config.configuration = '' + # OVERRIDDEN + { config, pkgs, ... }: { + imports = [ ./hardware-configuration.nix ]; + $bootLoaderConfig + } + ''; + }; + testScript = '' + startAll; + $machine->waitForUnit("multi-user.target"); + $machine->succeed("nixos-generate-config"); + + # Test if the configuration really is overridden + $machine->succeed("grep 'OVERRIDDEN' /etc/nixos/configuration.nix"); + + # Test of if the Perl variable $bootLoaderConfig is spliced correctly: + $machine->succeed("grep 'boot\\.loader\\.grub\\.enable = true;' /etc/nixos/configuration.nix"); + ''; +}) diff --git a/nixpkgs/nixos/tests/ostree.nix b/nixpkgs/nixos/tests/ostree.nix index 8b19004874e7..d7ad84a1a5f0 100644 --- a/nixpkgs/nixos/tests/ostree.nix +++ b/nixpkgs/nixos/tests/ostree.nix @@ -12,7 +12,7 @@ import ./make-test.nix ({ pkgs, lib, ... }: { gnome-desktop-testing ostree gnupg (python3.withPackages (p: with p; [ pyyaml ])) ]; - environment.variables.GI_TYPELIB_PATH = lib.makeSearchPath "lib/girepository-1.0" (with pkgs; [ gtk3 pango.out ostree gdk_pixbuf atk ]); # for GJS tests + environment.variables.GI_TYPELIB_PATH = lib.makeSearchPath "lib/girepository-1.0" (with pkgs; [ gtk3 pango.out ostree gdk-pixbuf atk ]); # for GJS tests }; testScript = '' diff --git a/nixpkgs/nixos/tests/postgresql-wal-receiver.nix b/nixpkgs/nixos/tests/postgresql-wal-receiver.nix new file mode 100644 index 000000000000..791b041ba95b --- /dev/null +++ b/nixpkgs/nixos/tests/postgresql-wal-receiver.nix @@ -0,0 +1,86 @@ +{ system ? builtins.currentSystem +, config ? { } +, pkgs ? import ../.. { inherit system config; } }: + +with import ../lib/testing.nix { inherit system pkgs; }; +with pkgs.lib; + +let + postgresqlDataDir = "/var/db/postgresql/test"; + replicationUser = "wal_receiver_user"; + replicationSlot = "wal_receiver_slot"; + replicationConn = "postgresql://${replicationUser}@localhost"; + baseBackupDir = "/tmp/pg_basebackup"; + walBackupDir = "/tmp/pg_wal"; + recoveryConf = pkgs.writeText "recovery.conf" '' + restore_command = 'cp ${walBackupDir}/%f %p' + ''; + + makePostgresqlWalReceiverTest = subTestName: postgresqlPackage: makeTest { + name = "postgresql-wal-receiver-${subTestName}"; + meta.maintainers = with maintainers; [ pacien ]; + + machine = { ... }: { + services.postgresql = { + package = postgresqlPackage; + enable = true; + dataDir = postgresqlDataDir; + extraConfig = '' + wal_level = archive # alias for replica on pg >= 9.6 + max_wal_senders = 10 + max_replication_slots = 10 + ''; + authentication = '' + host replication ${replicationUser} all trust + ''; + initialScript = pkgs.writeText "init.sql" '' + create user ${replicationUser} replication; + select * from pg_create_physical_replication_slot('${replicationSlot}'); + ''; + }; + + services.postgresqlWalReceiver.receivers.main = { + inherit postgresqlPackage; + connection = replicationConn; + slot = replicationSlot; + directory = walBackupDir; + }; + }; + + testScript = '' + # make an initial base backup + $machine->waitForUnit('postgresql'); + $machine->waitForUnit('postgresql-wal-receiver-main'); + # WAL receiver healthchecks PG every 5 seconds, so let's be sure they have connected each other + # required only for 9.4 + $machine->sleep(5); + $machine->succeed('${postgresqlPackage}/bin/pg_basebackup --dbname=${replicationConn} --pgdata=${baseBackupDir}'); + + # create a dummy table with 100 records + $machine->succeed('sudo -u postgres psql --command="create table dummy as select * from generate_series(1, 100) as val;"'); + + # stop postgres and destroy data + $machine->systemctl('stop postgresql'); + $machine->systemctl('stop postgresql-wal-receiver-main'); + $machine->succeed('rm -r ${postgresqlDataDir}/{base,global,pg_*}'); + + # restore the base backup + $machine->succeed('cp -r ${baseBackupDir}/* ${postgresqlDataDir} && chown postgres:postgres -R ${postgresqlDataDir}'); + + # prepare WAL and recovery + $machine->succeed('chmod a+rX -R ${walBackupDir}'); + $machine->execute('for part in ${walBackupDir}/*.partial; do mv $part ''${part%%.*}; done'); # make use of partial segments too + $machine->succeed('cp ${recoveryConf} ${postgresqlDataDir}/recovery.conf && chmod 666 ${postgresqlDataDir}/recovery.conf'); + + # replay WAL + $machine->systemctl('start postgresql'); + $machine->waitForFile('${postgresqlDataDir}/recovery.done'); + $machine->systemctl('restart postgresql'); + $machine->waitForUnit('postgresql'); + + # check that our records have been restored + $machine->succeed('test $(sudo -u postgres psql --pset="pager=off" --tuples-only --command="select count(distinct val) from dummy;") -eq 100'); + ''; + }; + +in mapAttrs makePostgresqlWalReceiverTest (import ../../pkgs/servers/sql/postgresql pkgs) diff --git a/nixpkgs/nixos/tests/prometheus-2.nix b/nixpkgs/nixos/tests/prometheus-2.nix index d7035d49ad4d..219c47c73d95 100644 --- a/nixpkgs/nixos/tests/prometheus-2.nix +++ b/nixpkgs/nixos/tests/prometheus-2.nix @@ -1,9 +1,44 @@ -import ./make-test.nix { +let + grpcPort = 19090; + queryPort = 9090; + minioPort = 9000; + pushgwPort = 9091; + + s3 = { + accessKey = "BKIKJAA5BMMU2RHO6IBB"; + secretKey = "V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12"; + }; + + objstore.config = { + type = "S3"; + config = { + bucket = "thanos-bucket"; + endpoint = "s3:${toString minioPort}"; + region = "us-east-1"; + access_key = s3.accessKey; + secret_key = s3.secretKey; + insecure = true; + signature_version2 = false; + encrypt_sse = false; + put_user_metadata = {}; + http_config = { + idle_conn_timeout = "0s"; + insecure_skip_verify = false; + }; + trace = { + enable = false; + }; + }; + }; + +in import ./make-test.nix { name = "prometheus-2"; nodes = { - one = { pkgs, ... }: { + prometheus = { pkgs, ... }: { + virtualisation.diskSize = 2 * 1024; environment.systemPackages = [ pkgs.jq ]; + networking.firewall.allowedTCPPorts = [ grpcPort ]; services.prometheus2 = { enable = true; scrapeConfigs = [ @@ -11,7 +46,7 @@ import ./make-test.nix { job_name = "prometheus"; static_configs = [ { - targets = [ "127.0.0.1:9090" ]; + targets = [ "127.0.0.1:${toString queryPort}" ]; labels = { instance = "localhost"; }; } ]; @@ -21,7 +56,7 @@ import ./make-test.nix { scrape_interval = "1s"; static_configs = [ { - targets = [ "127.0.0.1:9091" ]; + targets = [ "127.0.0.1:${toString pushgwPort}" ]; } ]; } @@ -35,33 +70,170 @@ import ./make-test.nix { expr: count(up{job="prometheus"}) '' ]; + globalConfig = { + external_labels = { + some_label = "required by thanos"; + }; + }; + extraFlags = [ + # Required by thanos + "--storage.tsdb.min-block-duration=5s" + "--storage.tsdb.max-block-duration=5s" + ]; }; services.prometheus.pushgateway = { enable = true; + web.listen-address = ":${toString pushgwPort}"; persistMetrics = true; persistence.interval = "1s"; stateDir = "prometheus-pushgateway"; }; + services.thanos = { + sidecar = { + enable = true; + grpc-address = "0.0.0.0:${toString grpcPort}"; + inherit objstore; + }; + + # TODO: Add some tests for these services: + #rule = { + # enable = true; + # http-address = "0.0.0.0:19194"; + # grpc-address = "0.0.0.0:19193"; + # query.addresses = [ + # "localhost:19191" + # ]; + # labels = { + # just = "some"; + # nice = "labels"; + # }; + #}; + # + #receive = { + # http-address = "0.0.0.0:19195"; + # enable = true; + # labels = { + # just = "some"; + # nice = "labels"; + # }; + #}; + }; + }; + + query = { pkgs, ... }: { + environment.systemPackages = [ pkgs.jq ]; + services.thanos.query = { + enable = true; + http-address = "0.0.0.0:${toString queryPort}"; + store.addresses = [ + "prometheus:${toString grpcPort}" + ]; + }; + }; + + store = { pkgs, ... }: { + virtualisation.diskSize = 2 * 1024; + environment.systemPackages = with pkgs; [ jq thanos ]; + services.thanos.store = { + enable = true; + http-address = "0.0.0.0:10902"; + grpc-address = "0.0.0.0:${toString grpcPort}"; + inherit objstore; + sync-block-duration = "1s"; + }; + services.thanos.compact = { + enable = true; + http-address = "0.0.0.0:10903"; + inherit objstore; + consistency-delay = "5s"; + }; + services.thanos.query = { + enable = true; + http-address = "0.0.0.0:${toString queryPort}"; + store.addresses = [ + "localhost:${toString grpcPort}" + ]; + }; + }; + + s3 = { pkgs, ... } : { + # Minio requires at least 1GiB of free disk space to run. + virtualisation.diskSize = 2 * 1024; + networking.firewall.allowedTCPPorts = [ minioPort ]; + + services.minio = { + enable = true; + inherit (s3) accessKey secretKey; + }; + + environment.systemPackages = [ pkgs.minio-client ]; }; }; - testScript = '' - startAll; - $one->waitForUnit("prometheus2.service"); - $one->waitForOpenPort(9090); - $one->succeed("curl -s http://127.0.0.1:9090/metrics"); + testScript = { nodes, ... } : '' + # Before starting the other machines we first make sure that our S3 service is online + # and has a bucket added for thanos: + $s3->start; + $s3->waitForUnit("minio.service"); + $s3->waitForOpenPort(${toString minioPort}); + $s3->succeed( + "mc config host add minio " . + "http://localhost:${toString minioPort} ${s3.accessKey} ${s3.secretKey} S3v4"); + $s3->succeed("mc mb minio/thanos-bucket"); + + # Now that s3 has started we can start the other machines: + $prometheus->start; + $query->start; + $store->start; - # Let's test if pushing a metric to the pushgateway succeeds - # and whether that metric gets ingested by prometheus. - $one->waitForUnit("pushgateway.service"); - $one->succeed( + # Check if prometheus responds to requests: + $prometheus->waitForUnit("prometheus2.service"); + $prometheus->waitForOpenPort(${toString queryPort}); + $prometheus->succeed("curl -s http://127.0.0.1:${toString queryPort}/metrics"); + + # Let's test if pushing a metric to the pushgateway succeeds: + $prometheus->waitForUnit("pushgateway.service"); + $prometheus->succeed( "echo 'some_metric 3.14' | " . - "curl --data-binary \@- http://127.0.0.1:9091/metrics/job/some_job"); - $one->waitUntilSucceeds( - "curl -sf 'http://127.0.0.1:9090/api/v1/query?query=some_metric' " . - "| jq '.data.result[0].value[1]' | grep '\"3.14\"'"); + "curl --data-binary \@- http://127.0.0.1:${toString pushgwPort}/metrics/job/some_job"); + + # Now check whether that metric gets ingested by prometheus. + # Since we'll check for the metric several times on different machines + # we abstract the test using the following function: + + # Function to check if the metric "some_metric" has been received and returns the correct value. + local *Machine::waitForMetric = sub { + my ($self) = @_; + $self->waitUntilSucceeds( + "curl -sf 'http://127.0.0.1:${toString queryPort}/api/v1/query?query=some_metric' " . + "| jq '.data.result[0].value[1]' | grep '\"3.14\"'"); + }; + + $prometheus->waitForMetric; # Let's test if the pushgateway persists metrics to the configured location. - $one->waitUntilSucceeds("test -e /var/lib/prometheus-pushgateway/metrics"); + $prometheus->waitUntilSucceeds("test -e /var/lib/prometheus-pushgateway/metrics"); + + # Test thanos + $prometheus->waitForUnit("thanos-sidecar.service"); + + # Test if the Thanos query service can correctly retrieve the metric that was send above. + $query->waitForUnit("thanos-query.service"); + $query->waitForMetric; + + # Test if the Thanos sidecar has correctly uploaded its TSDB to S3, if the + # Thanos storage service has correctly downloaded it from S3 and if the Thanos + # query service running on $store can correctly retrieve the metric: + $store->waitForUnit("thanos-store.service"); + $store->waitForMetric; + + $store->waitForUnit("thanos-compact.service"); + + # Test if the Thanos bucket command is able to retrieve blocks from the S3 bucket + # and check if the blocks have the correct labels: + $store->succeed( + "thanos bucket ls" . + " --objstore.config-file=${nodes.store.config.services.thanos.store.objstore.config-file}" . + " --output=json | jq .thanos.labels.some_label | grep 'required by thanos'"); ''; } diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix index 90c7c9701f60..02d83f82f338 100644 --- a/nixpkgs/nixos/tests/prometheus-exporters.nix +++ b/nixpkgs/nixos/tests/prometheus-exporters.nix @@ -3,10 +3,11 @@ , pkgs ? import ../.. { inherit system config; } }: -with pkgs.lib; -with import ../lib/testing.nix { inherit system pkgs; }; - let + inherit (import ../lib/testing.nix { inherit system pkgs; }) makeTest; + inherit (pkgs.lib) concatStringsSep maintainers mapAttrs mkMerge + removeSuffix replaceChars singleton splitString; + escape' = str: replaceChars [''"'' "$" "\n"] [''\\\"'' "\\$" ""] str; /* @@ -73,7 +74,7 @@ let exporterTest = '' waitForUnit("prometheus-bind-exporter.service"); waitForOpenPort(9119); - succeed("curl -sSf http://localhost:9119/metrics" | grep -q 'bind_query_recursions_total 0'); + succeed("curl -sSf http://localhost:9119/metrics | grep -q 'bind_query_recursions_total 0'"); ''; }; @@ -187,6 +188,47 @@ let ''; }; + mail = { + exporterConfig = { + enable = true; + configuration = { + monitoringInterval = "2s"; + mailCheckTimeout = "10s"; + servers = [ { + name = "testserver"; + server = "localhost"; + port = 25; + from = "mail-exporter@localhost"; + to = "mail-exporter@localhost"; + detectionDir = "/var/spool/mail/mail-exporter/new"; + } ]; + }; + }; + metricProvider = { + services.postfix.enable = true; + systemd.services.prometheus-mail-exporter = { + after = [ "postfix.service" ]; + requires = [ "postfix.service" ]; + preStart = '' + mkdir -p 0600 mail-exporter/new + ''; + serviceConfig = { + ProtectHome = true; + ReadOnlyPaths = "/"; + ReadWritePaths = "/var/spool/mail"; + WorkingDirectory = "/var/spool/mail"; + }; + }; + users.users.mailexporter.isSystemUser = true; + }; + exporterTest = '' + waitForUnit("postfix.service") + waitForUnit("prometheus-mail-exporter.service") + waitForOpenPort(9225) + waitUntilSucceeds("curl -sSf http://localhost:9225/metrics | grep -q 'mail_deliver_success{configname=\"testserver\"} 1'") + ''; + }; + nginx = { exporterConfig = { enable = true; @@ -231,6 +273,30 @@ let ''; }; + postgres = { + exporterConfig = { + enable = true; + runAsLocalSuperUser = true; + }; + metricProvider = { + services.postgresql.enable = true; + }; + exporterTest = '' + waitForUnit("prometheus-postgres-exporter.service"); + waitForOpenPort(9187); + waitForUnit("postgresql.service"); + succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_exporter_last_scrape_error 0'"); + succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_up 1'"); + systemctl("stop postgresql.service"); + succeed("curl -sSf http://localhost:9187/metrics | grep -qv 'pg_exporter_last_scrape_error 0'"); + succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_up 0'"); + systemctl("start postgresql.service"); + waitForUnit("postgresql.service"); + succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_exporter_last_scrape_error 0'"); + succeed("curl -sSf http://localhost:9187/metrics | grep -q 'pg_up 1'"); + ''; + }; + snmp = { exporterConfig = { enable = true; @@ -311,6 +377,7 @@ let }; exporterTest = '' waitForUnit("prometheus-varnish-exporter.service"); + waitForOpenPort(6081); waitForOpenPort(9131); succeed("curl -sSf http://localhost:9131/metrics | grep -q 'varnish_up 1'"); ''; @@ -331,11 +398,12 @@ let inherit (snakeoil.peer1) publicKey; }; }; + systemd.services.prometheus-wireguard-exporter.after = [ "wireguard-wg0.service" ]; }; exporterTest = '' waitForUnit("prometheus-wireguard-exporter.service"); waitForOpenPort(9586); - succeed("curl -sSf http://localhost:9586/metrics | grep '${snakeoil.peer1.publicKey}'"); + waitUntilSucceeds("curl -sSf http://localhost:9586/metrics | grep '${snakeoil.peer1.publicKey}'"); ''; }; }; diff --git a/nixpkgs/nixos/tests/redmine.nix b/nixpkgs/nixos/tests/redmine.nix index cbdb5c8d2954..2d4df288b055 100644 --- a/nixpkgs/nixos/tests/redmine.nix +++ b/nixpkgs/nixos/tests/redmine.nix @@ -10,19 +10,9 @@ let mysqlTest = 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.enable = true; services.redmine.package = package; services.redmine.database.type = "mysql2"; - 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; @@ -48,19 +38,9 @@ let pgsqlTest = package: makeTest { machine = { config, pkgs, ... }: - { services.postgresql.enable = true; - services.postgresql.ensureDatabases = [ "redmine" ]; - services.postgresql.ensureUsers = [ - { name = "redmine"; - ensurePermissions = { "DATABASE redmine" = "ALL PRIVILEGES"; }; - } - ]; - - services.redmine.enable = true; + { services.redmine.enable = true; services.redmine.package = package; services.redmine.database.type = "postgresql"; - services.redmine.database.host = ""; - services.redmine.database.port = 5432; services.redmine.plugins = { redmine_env_auth = pkgs.fetchurl { url = https://github.com/Intera/redmine_env_auth/archive/0.7.zip; diff --git a/nixpkgs/nixos/tests/syncthing-init.nix b/nixpkgs/nixos/tests/syncthing-init.nix index 811a466ff941..0de76b688bdc 100644 --- a/nixpkgs/nixos/tests/syncthing-init.nix +++ b/nixpkgs/nixos/tests/syncthing-init.nix @@ -22,9 +22,13 @@ in { }; testScript = '' + my $config; + $machine->waitForUnit("syncthing-init.service"); - $machine->succeed("cat /var/lib/syncthing/config.xml") =~ /${testId}/ or die; - $machine->succeed("cat /var/lib/syncthing/config.xml") =~ /testFolder/ or die; + $config = $machine->succeed("cat /var/lib/syncthing/.config/syncthing/config.xml"); + + $config =~ /${testId}/ or die; + $config =~ /testFolder/ or die; ''; }) diff --git a/nixpkgs/nixos/tests/tiddlywiki.nix b/nixpkgs/nixos/tests/tiddlywiki.nix new file mode 100644 index 000000000000..4a2014a4ec91 --- /dev/null +++ b/nixpkgs/nixos/tests/tiddlywiki.nix @@ -0,0 +1,67 @@ +import ./make-test.nix ({ ... }: { + name = "tiddlywiki"; + nodes = { + default = { + services.tiddlywiki.enable = true; + }; + configured = { + boot.postBootCommands = '' + echo "username,password + somelogin,somesecret" > /var/lib/wikiusers.csv + ''; + services.tiddlywiki = { + enable = true; + listenOptions = { + port = 3000; + credentials="../wikiusers.csv"; + readers="(authenticated)"; + }; + }; + }; + }; + + testScript = '' + startAll; + + subtest "by default works without configuration", sub { + $default->waitForUnit("tiddlywiki.service"); + }; + + subtest "by default available on port 8080 without auth", sub { + $default->waitForUnit("tiddlywiki.service"); + $default->waitForOpenPort(8080); + $default->succeed("curl --fail 127.0.0.1:8080"); + }; + + subtest "by default creates empty wiki", sub { + $default->succeed("test -f /var/lib/tiddlywiki/tiddlywiki.info"); + }; + + subtest "configured on port 3000 with basic auth", sub { + $configured->waitForUnit("tiddlywiki.service"); + $configured->waitForOpenPort(3000); + $configured->fail("curl --fail 127.0.0.1:3000"); + $configured->succeed("curl --fail 127.0.0.1:3000 --user somelogin:somesecret"); + }; + + subtest "configured with different wikifolder", sub { + $configured->succeed("test -f /var/lib/tiddlywiki/tiddlywiki.info"); + }; + + subtest "restart preserves changes", sub { + # given running wiki + $default->waitForUnit("tiddlywiki.service"); + # with some changes + $default->succeed("curl --fail --request PUT --header 'X-Requested-With:TiddlyWiki' --data '{ \"title\": \"title\", \"text\": \"content\" }' --url 127.0.0.1:8080/recipes/default/tiddlers/somepage "); + $default->succeed("sleep 2"); # server syncs to filesystem on timer + + # when wiki is cycled + $default->systemctl("restart tiddlywiki.service"); + $default->waitForUnit("tiddlywiki.service"); + $default->waitForOpenPort(8080); + + # the change is preserved + $default->succeed("curl --fail 127.0.0.1:8080/recipes/default/tiddlers/somepage"); + }; + ''; +}) diff --git a/nixpkgs/nixos/tests/tomcat.nix b/nixpkgs/nixos/tests/tomcat.nix deleted file mode 100644 index 8e7b886dd302..000000000000 --- a/nixpkgs/nixos/tests/tomcat.nix +++ /dev/null @@ -1,30 +0,0 @@ -import ./make-test.nix ({ pkgs, ...} : { - name = "tomcat"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ eelco ]; - }; - - nodes = { - server = - { ... }: - - { services.tomcat.enable = true; - services.httpd.enable = true; - services.httpd.adminAddr = "foo@bar.com"; - services.httpd.extraSubservices = - [ { serviceType = "tomcat-connector"; } ]; - networking.firewall.allowedTCPPorts = [ 80 ]; - }; - - client = { }; - }; - - testScript = '' - startAll; - - $server->waitForUnit("tomcat"); - $client->waitForUnit("network.target"); - $client->waitUntilSucceeds("curl --fail http://server/examples/servlets/servlet/HelloWorldExample"); - $client->waitUntilSucceeds("curl --fail http://server/examples/jsp/jsp2/simpletag/hello.jsp"); - ''; -}) diff --git a/nixpkgs/nixos/tests/trac.nix b/nixpkgs/nixos/tests/trac.nix deleted file mode 100644 index 8ec11ebda2cf..000000000000 --- a/nixpkgs/nixos/tests/trac.nix +++ /dev/null @@ -1,74 +0,0 @@ -import ./make-test.nix ({ pkgs, ... }: { - name = "trac"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ eelco ]; - }; - - nodes = { - storage = - { ... }: - { services.nfs.server.enable = true; - services.nfs.server.exports = '' - /repos 192.168.1.0/255.255.255.0(rw,no_root_squash) - ''; - services.nfs.server.createMountPoints = true; - }; - - postgresql = - { pkgs, ... }: - { services.postgresql.enable = true; - services.postgresql.package = pkgs.postgresql; - services.postgresql.enableTCPIP = true; - services.postgresql.authentication = '' - # Generated file; do not edit! - local all all trust - host all all 127.0.0.1/32 trust - host all all ::1/128 trust - host all all 192.168.1.0/24 trust - ''; - }; - - webserver = - { pkgs, ... }: - { fileSystems = pkgs.lib.mkVMOverride - [ { mountPoint = "/repos"; - device = "storage:/repos"; - fsType = "nfs"; - } - ]; - services.httpd.enable = true; - services.httpd.adminAddr = "root@localhost"; - services.httpd.extraSubservices = [ { serviceType = "trac"; } ]; - environment.systemPackages = [ pkgs.pythonPackages.trac pkgs.subversion ]; - }; - - client = - { ... }: - { imports = [ ./common/x11.nix ]; - services.xserver.desktopManager.plasma5.enable = true; - }; - }; - - testScript = - '' - startAll; - - $postgresql->waitForUnit("postgresql"); - $postgresql->succeed("createdb trac"); - - $webserver->succeed("mkdir -p /repos/trac"); - $webserver->succeed("svnadmin create /repos/trac"); - - $webserver->waitForUnit("httpd"); - $webserver->waitForFile("/var/trac"); - $webserver->succeed("mkdir -p /var/trac/projects/test"); - $webserver->succeed("PYTHONPATH=${pkgs.pythonPackages.psycopg2}/lib/${pkgs.python.libPrefix}/site-packages trac-admin /var/trac/projects/test initenv Test postgres://root\@postgresql/trac svn /repos/trac"); - - $client->waitForX; - $client->execute("konqueror http://webserver/projects/test &"); - $client->waitForWindow(qr/Test.*Konqueror/); - $client->sleep(30); # loading takes a long time - - $client->screenshot("screen"); - ''; -}) |