diff options
Diffstat (limited to 'nixos')
128 files changed, 3066 insertions, 2216 deletions
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 3b01f4fed35a8..ac22712baf87a 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -124,11 +124,12 @@ let manualXsltprocOptions = toString [ "--param section.autolabel 1" "--param section.label.includes.component.label 1" - "--stringparam html.stylesheet style.css" + "--stringparam html.stylesheet 'style.css overrides.css highlightjs/mono-blue.css'" + "--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'" "--param xref.with.number.and.title 1" "--param toc.section.depth 3" "--stringparam admon.style ''" - "--stringparam callout.graphics.extension .gif" + "--stringparam callout.graphics.extension .svg" "--stringparam current.docid manual" "--param chunk.section.depth 0" "--param chunk.first.sections 1" @@ -139,7 +140,7 @@ let manual-combined = runCommand "nixos-manual-combined" { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2 buildPackages.libxslt ]; + nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; meta.description = "The NixOS manual as plain docbook XML"; } '' @@ -194,7 +195,7 @@ let olinkDB = runCommand "manual-olinkdb" { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2 buildPackages.libxslt ]; + nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; } '' xsltproc \ @@ -244,7 +245,7 @@ in rec { # Generate the NixOS manual. manual = runCommand "nixos-manual" { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2 buildPackages.libxslt ]; + nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; meta.description = "The NixOS manual in HTML format"; allowedReferences = ["out"]; } @@ -260,9 +261,11 @@ in rec { ${manual-combined}/manual-combined.xml mkdir -p $dst/images/callouts - cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/ + cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/ - cp ${./style.css} $dst/style.css + cp ${../../../doc/style.css} $dst/style.css + cp ${../../../doc/overrides.css} $dst/overrides.css + cp -r ${pkgs.documentation-highlighter} $dst/highlightjs mkdir -p $out/nix-support echo "nix-build out $out" >> $out/nix-support/hydra-build-products @@ -272,7 +275,7 @@ in rec { manualEpub = runCommand "nixos-manual-epub" { inherit sources; - buildInputs = [ libxml2 libxslt zip ]; + buildInputs = [ libxml2.bin libxslt.bin zip ]; } '' # Generate the epub manual. @@ -286,7 +289,7 @@ in rec { ${manual-combined}/manual-combined.xml mkdir -p $dst/epub/OEBPS/images/callouts - cp -r ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/epub/OEBPS/images/callouts # */ + cp -r ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */ echo "application/epub+zip" > mimetype manual="$dst/nixos-manual.epub" zip -0Xq "$manual" mimetype @@ -302,7 +305,7 @@ in rec { # Generate the NixOS manpages. manpages = runCommand "nixos-manpages" { inherit sources; - nativeBuildInputs = [ buildPackages.libxml2 buildPackages.libxslt ]; + nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; allowedReferences = ["out"]; } '' diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml index ec940d5d2b865..13fa8d1e114cc 100644 --- a/nixos/doc/manual/development/option-types.xml +++ b/nixos/doc/manual/development/option-types.xml @@ -282,8 +282,8 @@ options.mod = mkOption { option set (<xref linkend='ex-submodule-listof-definition' />).</para> -<example xml:id='ex-submodule-listof-declaration'><title>Declaration of a list - nof submodules</title> +<example xml:id='ex-submodule-listof-declaration'><title>Declaration of a list + of submodules</title> <screen> options.mod = mkOption { description = "submodule example"; diff --git a/nixos/doc/manual/release-notes/rl-1803.xml b/nixos/doc/manual/release-notes/rl-1803.xml index b755245a69fbb..9221c2951ed25 100644 --- a/nixos/doc/manual/release-notes/rl-1803.xml +++ b/nixos/doc/manual/release-notes/rl-1803.xml @@ -4,7 +4,7 @@ version="5.0" xml:id="sec-release-18.03"> -<title>Release 18.03 (“Impala”, 2018/03/??)</title> +<title>Release 18.03 (“Impala”, 2018/04/04)</title> <section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -18,6 +18,20 @@ has the following highlights: </para> <itemizedlist> + + <listitem> + <para> + End of support is planned for end of October 2018, handing over to 18.09. + </para> + </listitem> + + <listitem> + <para> + Platform support: x86_64-linux and x86_64-darwin since release time (the latter isn't NixOS, really). + Binaries for aarch64-linux are available, but no channel exists yet, as it's waiting for some test fixes, etc. + </para> + </listitem> + <listitem> <para> Nix now defaults to 2.0; see its @@ -27,13 +41,13 @@ has the following highlights: </para> <listitem> <para> - Linux kernel defaults to the 4.14 branch (it was 4.9). + Core version changes: linux: 4.9 -> 4.14, glibc: 2.25 -> 2.26, gcc: 6 -> 7, systemd: 234 -> 237. </para> </listitem> <listitem> <para> - GCC defaults to 7.x (it was 6.x). + Desktop version changes: gnome: 3.24 -> 3.26, (KDE) plasma-desktop: 5.10 -> 5.12. </para> </listitem> @@ -59,13 +73,7 @@ has the following highlights: </para> </listitem> <listitem> - <para> - The GNOME version is now 3.26. - </para> - </listitem> - - <listitem> - <para>PHP now defaults to PHP 7.2</para> + <para>PHP now defaults to PHP 7.2, updated from 7.1.</para> </listitem> </itemizedlist> @@ -81,9 +89,66 @@ has the following highlights: </para> <para>The following new services were added since the last release:</para> <itemizedlist> - <listitem> - <para></para> - </listitem> + <listitem><para><literal>./config/krb5/default.nix</literal></para></listitem> + <listitem><para><literal>./hardware/digitalbitbox.nix</literal></para></listitem> + <listitem><para><literal>./misc/label.nix</literal></para></listitem> + <listitem><para><literal>./programs/ccache.nix</literal></para></listitem> + <listitem><para><literal>./programs/criu.nix</literal></para></listitem> + <listitem><para><literal>./programs/digitalbitbox/default.nix</literal></para></listitem> + <listitem><para><literal>./programs/less.nix</literal></para></listitem> + <listitem><para><literal>./programs/npm.nix</literal></para></listitem> + <listitem><para><literal>./programs/plotinus.nix</literal></para></listitem> + <listitem><para><literal>./programs/rootston.nix</literal></para></listitem> + <listitem><para><literal>./programs/systemtap.nix</literal></para></listitem> + <listitem><para><literal>./programs/sway.nix</literal></para></listitem> + <listitem><para><literal>./programs/udevil.nix</literal></para></listitem> + <listitem><para><literal>./programs/way-cooler.nix</literal></para></listitem> + <listitem><para><literal>./programs/yabar.nix</literal></para></listitem> + <listitem><para><literal>./programs/zsh/zsh-autoenv.nix</literal></para></listitem> + <listitem><para><literal>./services/backup/borgbackup.nix</literal></para></listitem> + <listitem><para><literal>./services/backup/crashplan-small-business.nix</literal></para></listitem> + <listitem><para><literal>./services/desktops/dleyna-renderer.nix</literal></para></listitem> + <listitem><para><literal>./services/desktops/dleyna-server.nix</literal></para></listitem> + <listitem><para><literal>./services/desktops/pipewire.nix</literal></para></listitem> + <listitem><para><literal>./services/desktops/gnome3/chrome-gnome-shell.nix</literal></para></listitem> + <listitem><para><literal>./services/desktops/gnome3/tracker-miners.nix</literal></para></listitem> + <listitem><para><literal>./services/hardware/fwupd.nix</literal></para></listitem> + <listitem><para><literal>./services/hardware/interception-tools.nix</literal></para></listitem> + <listitem><para><literal>./services/hardware/u2f.nix</literal></para></listitem> + <listitem><para><literal>./services/hardware/usbmuxd.nix</literal></para></listitem> + <listitem><para><literal>./services/mail/clamsmtp.nix</literal></para></listitem> + <listitem><para><literal>./services/mail/dkimproxy-out.nix</literal></para></listitem> + <listitem><para><literal>./services/mail/pfix-srsd.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/gitea.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/home-assistant.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/ihaskell.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/logkeys.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/novacomd.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/osrm.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/plexpy.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/pykms.nix</literal></para></listitem> + <listitem><para><literal>./services/misc/tzupdate.nix</literal></para></listitem> + <listitem><para><literal>./services/monitoring/fusion-inventory.nix</literal></para></listitem> + <listitem><para><literal>./services/monitoring/prometheus/exporters.nix</literal></para></listitem> + <listitem><para><literal>./services/network-filesystems/beegfs.nix</literal></para></listitem> + <listitem><para><literal>./services/network-filesystems/davfs2.nix</literal></para></listitem> + <listitem><para><literal>./services/network-filesystems/openafs/client.nix</literal></para></listitem> + <listitem><para><literal>./services/network-filesystems/openafs/server.nix</literal></para></listitem> + <listitem><para><literal>./services/network-filesystems/ceph.nix</literal></para></listitem> + <listitem><para><literal>./services/networking/aria2.nix</literal></para></listitem> + <listitem><para><literal>./services/networking/monero.nix</literal></para></listitem> + <listitem><para><literal>./services/networking/nghttpx/default.nix</literal></para></listitem> + <listitem><para><literal>./services/networking/nixops-dns.nix</literal></para></listitem> + <listitem><para><literal>./services/networking/rxe.nix</literal></para></listitem> + <listitem><para><literal>./services/networking/stunnel.nix</literal></para></listitem> + <listitem><para><literal>./services/web-apps/matomo.nix</literal></para></listitem> + <listitem><para><literal>./services/web-apps/restya-board.nix</literal></para></listitem> + <listitem><para><literal>./services/web-servers/mighttpd2.nix</literal></para></listitem> + <listitem><para><literal>./services/x11/fractalart.nix</literal></para></listitem> + <listitem><para><literal>./system/boot/binfmt.nix</literal></para></listitem> + <listitem><para><literal>./system/boot/grow-partition.nix</literal></para></listitem> + <listitem><para><literal>./tasks/filesystems/ecryptfs.nix</literal></para></listitem> + <listitem><para><literal>./virtualisation/hyperv-guest.nix</literal></para></listitem> </itemizedlist> </section> @@ -174,7 +239,7 @@ following incompatible changes:</para> the <literal>openssh_with_kerberos</literal> package is now a deprecated alias. If you do not want Kerberos support, - you can do <literal>openssh.override { withKerboros = false; }</literal>. + you can do <literal>openssh.override { withKerberos = false; }</literal>. Note, this also applies to the <literal>openssh_hpn</literal> package. </para> </listitem> @@ -322,6 +387,43 @@ following incompatible changes:</para> <link xlink:href="https://github.com/rvl/pump.io-nixos">external module</link>. </para> </listitem> + <listitem> + <para> + The Prosody XMPP server has received a major update. The following modules were renamed: + <itemizedlist> + <listitem> + <para> + <option>services.prosody.modules.httpserver</option> is now <option>services.prosody.modules.http_files</option> + </para> + </listitem> + <listitem> + <para> + <option>services.prosody.modules.console</option> is now <option>services.prosody.modules.admin_telnet</option> + </para> + </listitem> + </itemizedlist> + </para> + + <para> + Many new modules are now core modules, most notably <option>services.prosody.modules.carbons</option> + and <option>services.prosody.modules.mam</option>. + </para> + + <para> + The better-performing <literal>libevent</literal> backend is now enabled by default. + </para> + + <para> + <literal>withCommunityModules</literal> now passes through the modules to <option>services.prosody.extraModules</option>. + Use <literal>withOnlyInstalledCommunityModules</literal> for modules that should not be enabled directly, e.g <literal>lib_ldap</literal>. + </para> + </listitem> + <listitem> + <para> + All prometheus exporter modules are now defined as submodules. + The exporters are configured using <literal>services.prometheus.exporters</literal>. + </para> + </listitem> </itemizedlist> </section> @@ -383,15 +485,6 @@ following incompatible changes:</para> </listitem> <listitem> <para> - The option <option>services.xserver.desktopManager.default</option> is now - <literal>none</literal> by default. An assertion failure is thrown if WM's - and DM's default are <literal>none</literal>. - To explicitly run a plain X session without and DM or WM, the newly - introduced option <option>services.xserver.plainX</option> must be set to true. - </para> - </listitem> - <listitem> - <para> The option <option>services.logstash.listenAddress</option> is now <literal>127.0.0.1</literal> by default. Previously the default behaviour was to listen on all interfaces. </para> diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml index 959bd86759b1e..61f9ec8ba9950 100644 --- a/nixos/doc/manual/release-notes/rl-1809.xml +++ b/nixos/doc/manual/release-notes/rl-1809.xml @@ -58,6 +58,9 @@ following incompatible changes:</para> <itemizedlist> <listitem> <para> + The <literal>clementine</literal> package points now to the free derivation. + <literal>clementineFree</literal> is removed now and <literal>clementineUnfree</literal> + points to the package which is bundled with the unfree <literal>libspotify</literal> package. </para> </listitem> </itemizedlist> diff --git a/nixos/doc/manual/style.css b/nixos/doc/manual/style.css deleted file mode 100644 index 3118b37ead1f2..0000000000000 --- a/nixos/doc/manual/style.css +++ /dev/null @@ -1,267 +0,0 @@ -/* Copied from http://bakefile.sourceforge.net/, which appears - licensed under the GNU GPL. */ - - -/*************************************************************************** - Basic headers and text: - ***************************************************************************/ - -body -{ - font-family: "Nimbus Sans L", sans-serif; - background: white; - margin: 2em 1em 2em 1em; -} - -h1, h2, h3, h4 -{ - color: #005aa0; -} - -h1 /* title */ -{ - font-size: 200%; -} - -h2 /* chapters, appendices, subtitle */ -{ - font-size: 180%; -} - -/* Extra space between chapters, appendices. */ -div.chapter > div.titlepage h2, div.appendix > div.titlepage h2 -{ - margin-top: 1.5em; -} - -div.section > div.titlepage h2 /* sections */ -{ - font-size: 150%; - margin-top: 1.5em; -} - -h3 /* subsections */ -{ - font-size: 125%; -} - -div.simplesect h2 -{ - font-size: 110%; -} - -div.appendix h3 -{ - font-size: 150%; - margin-top: 1.5em; -} - -div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */ -{ - margin-top: 1.4em; - font-size: 125%; -} - -div.refsection h3 -{ - font-size: 110%; -} - - -/*************************************************************************** - Examples: - ***************************************************************************/ - -div.example -{ - border: 1px solid #b0b0b0; - padding: 6px 6px; - margin-left: 1.5em; - margin-right: 1.5em; - background: #f4f4f8; - border-radius: 0.4em; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -div.example p.title -{ - margin-top: 0em; -} - -div.example pre -{ - box-shadow: none; -} - - -/*************************************************************************** - Screen dumps: - ***************************************************************************/ - -pre.screen, pre.programlisting -{ - border: 1px solid #b0b0b0; - padding: 3px 3px; - margin-left: 1.5em; - margin-right: 1.5em; - color: #600000; - background: #f4f4f8; - font-family: monospace; - border-radius: 0.4em; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -div.example pre.programlisting -{ - border: 0px; - padding: 0 0; - margin: 0 0 0 0; -} - - -/*************************************************************************** - Notes, warnings etc: - ***************************************************************************/ - -.note, .warning -{ - border: 1px solid #b0b0b0; - padding: 3px 3px; - margin-left: 1.5em; - margin-right: 1.5em; - margin-bottom: 1em; - padding: 0.3em 0.3em 0.3em 0.3em; - background: #fffff5; - border-radius: 0.4em; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -div.note, div.warning -{ - font-style: italic; -} - -div.note h3, div.warning h3 -{ - color: red; - font-size: 100%; - padding-right: 0.5em; - display: inline; -} - -div.note p, div.warning p -{ - margin-bottom: 0em; -} - -div.note h3 + p, div.warning h3 + p -{ - display: inline; -} - -div.note h3 -{ - color: blue; - font-size: 100%; -} - -div.navfooter * -{ - font-size: 90%; -} - - -/*************************************************************************** - Links colors and highlighting: - ***************************************************************************/ - -a { text-decoration: none; } -a:hover { text-decoration: underline; } -a:link { color: #0048b3; } -a:visited { color: #002a6a; } - - -/*************************************************************************** - Table of contents: - ***************************************************************************/ - -div.toc -{ - font-size: 90%; -} - -div.toc dl -{ - margin-top: 0em; - margin-bottom: 0em; -} - - -/*************************************************************************** - Special elements: - ***************************************************************************/ - -tt, code -{ - color: #400000; -} - -.term -{ - font-weight: bold; - -} - -div.variablelist dd p, div.glosslist dd p -{ - margin-top: 0em; -} - -div.variablelist dd, div.glosslist dd -{ - margin-left: 1.5em; -} - -div.glosslist dt -{ - font-style: italic; -} - -.varname -{ - color: #400000; -} - -span.command strong -{ - font-weight: normal; - color: #400000; -} - -div.calloutlist table -{ - box-shadow: none; -} - -table -{ - border-collapse: collapse; - box-shadow: 0.4em 0.4em 0.5em #e0e0e0; -} - -table.simplelist -{ - text-align: left; - color: #005aa0; - border: 0; - padding: 5px; - background: #fffff5; - font-weight: normal; - font-style: italic; - box-shadow: none; - margin-bottom: 1em; -} - -div.navheader table, div.navfooter table { - box-shadow: none; -} diff --git a/nixos/lib/make-system-tarball.nix b/nixos/lib/make-system-tarball.nix index a2a0340a6bd3d..92539235be754 100644 --- a/nixos/lib/make-system-tarball.nix +++ b/nixos/lib/make-system-tarball.nix @@ -1,4 +1,4 @@ -{ stdenv, perl, xz, pathsFromGraph +{ stdenv, perl, pixz, pathsFromGraph , # The file name of the resulting tarball fileName ? "nixos-system-${stdenv.system}" @@ -21,14 +21,20 @@ # Extra tar arguments , extraArgs ? "" + # Command used for compression +, compressCommand ? "pixz" + # Extension for the compressed tarball +, compressionExtension ? ".xz" + # extra inputs, like the compressor to use +, extraInputs ? [ pixz ] }: stdenv.mkDerivation { name = "tarball"; builder = ./make-system-tarball.sh; - buildInputs = [perl xz]; + buildInputs = [ perl ] ++ extraInputs; - inherit fileName pathsFromGraph extraArgs extraCommands; + inherit fileName pathsFromGraph extraArgs extraCommands compressCommand; # !!! should use XML. sources = map (x: x.source) contents; @@ -41,4 +47,6 @@ stdenv.mkDerivation { # For obtaining the closure of `storeContents'. exportReferencesGraph = map (x: [("closure-" + baseNameOf x.object) x.object]) storeContents; + + extension = compressionExtension; } diff --git a/nixos/lib/make-system-tarball.sh b/nixos/lib/make-system-tarball.sh index 73a009d8488a7..1a52a284a2573 100644 --- a/nixos/lib/make-system-tarball.sh +++ b/nixos/lib/make-system-tarball.sh @@ -1,5 +1,4 @@ source $stdenv/setup -set -x sources_=($sources) targets_=($targets) @@ -54,8 +53,8 @@ mkdir -p $out/tarball rm env-vars -tar --sort=name --mtime='@1' --owner=0 --group=0 --numeric-owner -cvJf $out/tarball/$fileName.tar.xz * $extraArgs +time tar --sort=name --mtime='@1' --owner=0 --group=0 --numeric-owner -c * $extraArgs | $compressCommand > $out/tarball/$fileName.tar${extension} mkdir -p $out/nix-support echo $system > $out/nix-support/system -echo "file system-tarball $out/tarball/$fileName.tar.xz" > $out/nix-support/hydra-build-products +echo "file system-tarball $out/tarball/$fileName.tar${extension}" > $out/nix-support/hydra-build-products diff --git a/nixos/maintainers/option-usages.nix b/nixos/maintainers/option-usages.nix index 7be0255b35acb..371ee7d91808d 100644 --- a/nixos/maintainers/option-usages.nix +++ b/nixos/maintainers/option-usages.nix @@ -15,7 +15,7 @@ # # $ nix-build ./option-usage.nix --argstr testOption service.xserver.enable -A txt -o service.xserver.enable._txt # -# otther target exists such as, `dotContent`, `dot`, and `pdf`. If you are +# Other targets exists such as `dotContent`, `dot`, and `pdf`. If you are # looking for the option usage of multiple options, you can provide a list # as argument. # @@ -35,7 +35,7 @@ # value is replaced by a `throw` statement which is caught by the `tryEval` # evaluation of each option value. # -# We then compare the result of the evluation of the original module, with +# We then compare the result of the evaluation of the original module, with # the result of the second evaluation, and consider that the new failures are # caused by our mutation of the `config` argument. # @@ -62,7 +62,7 @@ let "_module.args" # For some reasons which we yet have to investigate, some options cannot - # be replaced by a throw without cuasing a non-catchable failure. + # be replaced by a throw without causing a non-catchable failure. "networking.bonds" "networking.bridges" "networking.interfaces" diff --git a/nixos/maintainers/scripts/gce/create-gce.sh b/nixos/maintainers/scripts/gce/create-gce.sh index ef1801fe54beb..0fd26d34d07f9 100755 --- a/nixos/maintainers/scripts/gce/create-gce.sh +++ b/nixos/maintainers/scripts/gce/create-gce.sh @@ -3,7 +3,7 @@ set -euo pipefail -BUCKET_NAME="${BUCKET_NAME:-nixos-images}" +BUCKET_NAME="${BUCKET_NAME:-nixos-cloud-images}" TIMESTAMP="$(date +%Y%m%d%H%M)" export TIMESTAMP @@ -19,5 +19,5 @@ img_name=$(basename "$img_path") img_id=$(echo "$img_name" | sed 's|.raw.tar.gz$||;s|\.|-|g;s|_|-|g') if ! gsutil ls "gs://${BUCKET_NAME}/$img_name"; then gsutil cp "$img_path" "gs://${BUCKET_NAME}/$img_name" + gsutil acl ch -u AllUsers:R "gs://${BUCKET_NAME}/$img_name" fi -gcloud compute images create "$img_id" --source-uri "gs://${BUCKET_NAME}/$img_name" diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix index b9d5b2b903e79..a20910353f347 100644 --- a/nixos/modules/config/no-x-libs.nix +++ b/nixos/modules/config/no-x-libs.nix @@ -32,7 +32,6 @@ with lib; networkmanager-l2tp = pkgs.networkmanager-l2tp.override { withGnome = false; }; networkmanager-openconnect = pkgs.networkmanager-openconnect.override { withGnome = false; }; networkmanager-openvpn = pkgs.networkmanager-openvpn.override { withGnome = false; }; - networkmanager-pptp = pkgs.networkmanager-pptp.override { withGnome = false; }; networkmanager-vpnc = pkgs.networkmanager-vpnc.override { withGnome = false; }; networkmanager-iodine = pkgs.networkmanager-iodine.override { withGnome = false; }; pinentry = pkgs.pinentry_ncurses; diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix index 7b36d4f1cbdf6..c595c69329469 100644 --- a/nixos/modules/config/nsswitch.nix +++ b/nixos/modules/config/nsswitch.nix @@ -17,23 +17,23 @@ let resolved = canLoadExternalModules && config.services.resolved.enable; hostArray = [ "files" ] - ++ optionals mymachines [ "mymachines" ] - ++ optionals nssmdns [ "mdns_minimal [NOTFOUND=return]" ] - ++ optionals nsswins [ "wins" ] - ++ optionals resolved ["resolve [!UNAVAIL=return]"] + ++ optional mymachines "mymachines" + ++ optional nssmdns "mdns_minimal [NOTFOUND=return]" + ++ optional nsswins "wins" + ++ optional resolved "resolve [!UNAVAIL=return]" ++ [ "dns" ] - ++ optionals nssmdns [ "mdns" ] - ++ optionals myhostname ["myhostname" ]; + ++ optional nssmdns "mdns" + ++ optional myhostname "myhostname"; passwdArray = [ "files" ] ++ optional sssd "sss" - ++ optionals ldap [ "ldap" ] - ++ optionals mymachines [ "mymachines" ] + ++ optional ldap "ldap" + ++ optional mymachines "mymachines" ++ [ "systemd" ]; shadowArray = [ "files" ] ++ optional sssd "sss" - ++ optionals ldap [ "ldap" ]; + ++ optional ldap "ldap"; servicesArray = [ "files" ] ++ optional sssd "sss"; diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index d3212d9316051..3611516650181 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -109,7 +109,6 @@ in "/sbin" "/share/applications" "/share/desktop-directories" - "/share/doc" "/share/emacs" "/share/icons" "/share/menus" diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 11e969b760e03..42d5d233f1c11 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -35,6 +35,7 @@ let name = mkOption { type = types.str; + apply = x: assert (builtins.stringLength x < 32 || abort "Username '${x}' is longer than 31 characters which is not allowed!"); x; description = '' The name of the user account. If undefined, the name of the attribute set will be used. @@ -91,6 +92,7 @@ let group = mkOption { type = types.str; + apply = x: assert (builtins.stringLength x < 17 || abort "Group name '${x}' is longer than 16 characters which is not allowed!"); x; default = "nogroup"; description = "The user's primary group."; }; @@ -502,9 +504,6 @@ in { }; }; - # Install all the user shells - environment.systemPackages = systemShells; - users.groups = { root.gid = ids.gids.root; wheel.gid = ids.gids.wheel; @@ -541,14 +540,29 @@ in { # for backwards compatibility system.activationScripts.groups = stringAfter [ "users" ] ""; - environment.etc."subuid" = { - text = subuidFile; - mode = "0644"; - }; - environment.etc."subgid" = { - text = subgidFile; - mode = "0644"; - }; + # Install all the user shells + environment.systemPackages = systemShells; + + environment.etc = { + "subuid" = { + text = subuidFile; + mode = "0644"; + }; + "subgid" = { + text = subgidFile; + mode = "0644"; + }; + } // (mapAttrs' (name: { packages, ... }: { + name = "profiles/per-user/${name}"; + value.source = pkgs.buildEnv { + name = "user-environment"; + paths = packages; + inherit (config.environment) pathsToLink extraOutputsToInstall; + inherit (config.system.path) ignoreCollisions postBuild; + }; + }) (filterAttrs (_: u: u.packages != []) cfg.users)); + + environment.profiles = [ "/etc/profiles/per-user/$USER" ]; assertions = [ { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique); @@ -579,22 +593,4 @@ in { }; - imports = - [ (mkAliasOptionModule [ "users" "extraUsers" ] [ "users" "users" ]) - (mkAliasOptionModule [ "users" "extraGroups" ] [ "users" "groups" ]) - { - environment = { - etc = mapAttrs' (name: { packages, ... }: { - name = "profiles/per-user/${name}"; - value.source = pkgs.buildEnv { - name = "user-environment"; - paths = packages; - inherit (config.environment) pathsToLink extraOutputsToInstall; - inherit (config.system.path) ignoreCollisions postBuild; - }; - }) (filterAttrs (_: { packages, ... }: packages != []) cfg.users); - profiles = ["/etc/profiles/per-user/$USER"]; - }; - } - ]; } diff --git a/nixos/modules/hardware/video/amdgpu-pro.nix b/nixos/modules/hardware/video/amdgpu-pro.nix index 5cc96d8bd0746..50af022b93c86 100644 --- a/nixos/modules/hardware/video/amdgpu-pro.nix +++ b/nixos/modules/hardware/video/amdgpu-pro.nix @@ -15,13 +15,19 @@ let opengl = config.hardware.opengl; + kernel = pkgs.linux_4_9.override { + extraConfig = '' + KALLSYMS_ALL y + ''; + }; + in { config = mkIf enabled { - nixpkgs.config.xorg.abiCompat = "1.18"; + nixpkgs.config.xorg.abiCompat = "1.19"; services.xserver.drivers = singleton { name = "amdgpu"; modules = [ package ]; libPath = [ package ]; }; @@ -31,6 +37,9 @@ in boot.extraModulePackages = [ package ]; + boot.kernelPackages = + pkgs.recurseIntoAttrs (pkgs.linuxPackagesFor kernel); + boot.blacklistedKernelModules = [ "radeon" ]; hardware.firmware = [ package ]; @@ -38,10 +47,15 @@ in system.activationScripts.setup-amdgpu-pro = '' mkdir -p /run/lib ln -sfn ${package}/lib ${package.libCompatDir} + ln -sfn ${package} /run/amdgpu-pro '' + optionalString opengl.driSupport32Bit '' ln -sfn ${package32}/lib ${package32.libCompatDir} ''; + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isYes "KALLSYMS_ALL") + ]; + environment.etc = { "amd/amdrc".source = package + "/etc/amd/amdrc"; "amd/amdapfxx.blb".source = package + "/etc/amd/amdapfxx.blb"; diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index eafc9869315a7..a1f1cef07adae 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -16,8 +16,6 @@ let kernelPackages.nvidia_x11 else if elem "nvidiaBeta" drivers then kernelPackages.nvidia_x11_beta - else if elem "nvidiaLegacy173" drivers then - kernelPackages.nvidia_x11_legacy173 else if elem "nvidiaLegacy304" drivers then kernelPackages.nvidia_x11_legacy304 else if elem "nvidiaLegacy340" drivers then diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix index 3306846b7fa7c..ddf91a5656c7c 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix @@ -21,9 +21,6 @@ in "it cannot be cross compiled"; }; - # Needed by RPi firmware - nixpkgs.config.allowUnfree = true; - boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix index 08903ba397a19..891923234dda9 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -21,9 +21,6 @@ in "it cannot be cross compiled"; }; - # Needed by RPi firmware - nixpkgs.config.allowUnfree = true; - boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix index 2833b75b84d87..212013b5e2896 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix @@ -21,9 +21,6 @@ in "it cannot be cross compiled"; }; - # Needed by RPi firmware - nixpkgs.config.allowUnfree = true; - boot.loader.grub.enable = false; boot.loader.generic-extlinux-compatible.enable = true; diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 23312c073d568..c091923de60f7 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -20,6 +20,20 @@ let in { options.sdImage = { + imageName = mkOption { + default = "${config.sdImage.imageBaseName}-${config.system.nixos.label}-${pkgs.stdenv.system}.img"; + description = '' + Name of the generated image file. + ''; + }; + + imageBaseName = mkOption { + default = "nixos-sd-image"; + description = '' + Prefix of the name of the generated image file. + ''; + }; + storePaths = mkOption { type = with types; listOf package; example = literalExample "[ pkgs.stdenv ]"; @@ -61,19 +75,25 @@ in sdImage.storePaths = [ config.system.build.toplevel ]; system.build.sdImage = pkgs.stdenv.mkDerivation { - name = "sd-image-${pkgs.stdenv.system}.img"; + name = config.sdImage.imageName; buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ]; buildCommand = '' + mkdir -p $out/nix-support $out/sd-image + export img=$out/sd-image/${config.sdImage.imageName} + + echo "${pkgs.stdenv.system}" > $out/nix-support/system + echo "file sd-image $img" >> $out/nix-support/hydra-build-products + # Create the image file sized to fit /boot and /, plus 20M of slack rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }') bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512)) imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 20 * 1024 * 1024)) - truncate -s $imageSize $out + truncate -s $imageSize $img # type=b is 'W95 FAT32', type=83 is 'Linux'. - sfdisk $out <<EOF + sfdisk $img <<EOF label: dos label-id: 0x2178694e @@ -82,11 +102,11 @@ in EOF # Copy the rootfs into the SD image - eval $(partx $out -o START,SECTORS --nr 2 --pairs) - dd conv=notrunc if=${rootfsImage} of=$out seek=$START count=$SECTORS + eval $(partx $img -o START,SECTORS --nr 2 --pairs) + dd conv=notrunc if=${rootfsImage} of=$img seek=$START count=$SECTORS # Create a FAT32 /boot partition of suitable size into bootpart.img - eval $(partx $out -o START,SECTORS --nr 1 --pairs) + eval $(partx $img -o START,SECTORS --nr 1 --pairs) truncate -s $((SECTORS * 512)) bootpart.img faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n NIXOS_BOOT bootpart.img @@ -96,7 +116,7 @@ in # Copy the populated /boot into the SD image (cd boot; mcopy -bpsvm -i ../bootpart.img ./* ::) - dd conv=notrunc if=bootpart.img of=$out seek=$START count=$SECTORS + dd conv=notrunc if=bootpart.img of=$img seek=$START count=$SECTORS ''; }; diff --git a/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix b/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix index ba84cd51098fe..6d4ba96dba0c1 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball-fuloong2f.nix @@ -54,7 +54,7 @@ in environment.systemPackages = [ pkgs.w3m # needed for the manual anyway pkgs.testdisk # useful for repairing boot problems - pkgs.mssys # for writing Microsoft boot sectors / MBRs + pkgs.ms-sys # for writing Microsoft boot sectors / MBRs pkgs.parted pkgs.ddrescue pkgs.ccrypt diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix new file mode 100644 index 0000000000000..cea8981370bb3 --- /dev/null +++ b/nixos/modules/misc/documentation.nix @@ -0,0 +1,77 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.documentation; in + +{ + + options = { + + documentation = { + + enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to install documentation of packages from + <option>environment.systemPackages</option> into the generated system path. + ''; + }; + + man.enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to install manual pages and the <command>man</command> command. + This also includes "man" outputs. + ''; + }; + + doc.enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to install documentation distributed in packages' <literal>/share/doc</literal>. + Usually plain text and/or HTML. + This also includes "doc" outputs. + ''; + }; + + info.enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to install info pages and the <command>info</command> command. + This also includes "info" outputs. + ''; + }; + + }; + + }; + + config = mkIf cfg.enable (mkMerge [ + + (mkIf cfg.man.enable { + environment.systemPackages = [ pkgs.man-db ]; + environment.pathsToLink = [ "/share/man" ]; + environment.extraOutputsToInstall = [ "man" ]; + }) + + (mkIf cfg.doc.enable { + # TODO(@oxij): put it here and remove from profiles? + # environment.systemPackages = [ pkgs.w3m ]; # w3m-nox? + environment.pathsToLink = [ "/share/doc" ]; + environment.extraOutputsToInstall = [ "doc" ]; + }) + + (mkIf cfg.info.enable { + environment.systemPackages = [ pkgs.texinfoInteractive ]; + environment.pathsToLink = [ "/share/info" ]; + environment.extraOutputsToInstall = [ "info" ]; + }) + + ]); + +} diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 39a24cfecc537..3594f57595c74 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -106,7 +106,7 @@ freenet = 79; ircd = 80; bacula = 81; - almir = 82; + #almir = 82; # removed 2018-03-25, the almir package was removed in 30291227f2411abaca097773eedb49b8f259e297 during 2017-08 deluge = 83; mysql = 84; rabbitmq = 85; @@ -305,6 +305,7 @@ hass = 286; monero = 287; ceph = 288; + duplicati = 289; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -393,7 +394,7 @@ freenet = 79; ircd = 80; bacula = 81; - almir = 82; + #almir = 82; # removed 2018-03-25, the almir package was removed in 30291227f2411abaca097773eedb49b8f259e297 during 2017-08 deluge = 83; mysql = 84; rabbitmq = 85; @@ -578,6 +579,7 @@ hass = 286; monero = 287; ceph = 288; + duplicati = 289; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix index b8f0a223c910a..7519d9176982b 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -16,6 +16,21 @@ in options.system = { + # XXX: Reintroduce old options to make nixops before 1.6 able to evaluate configurations + # XXX: Remove after nixops has been bumped to a compatible version + nixosVersion = mkOption { + readOnly = true; + internal = true; + type = types.str; + default = config.system.nixos.version; + }; + nixosVersionSuffix = mkOption { + readOnly = true; + internal = true; + type = types.str; + default = config.system.nixos.versionSuffix; + }; + nixos.version = mkOption { internal = true; type = types.str; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 64a109f50e379..63e463370d1fc 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -59,6 +59,7 @@ ./installer/tools/tools.nix ./misc/assertions.nix ./misc/crashdump.nix + ./misc/documentation.nix ./misc/extra-arguments.nix ./misc/ids.nix ./misc/lib.nix @@ -86,12 +87,11 @@ ./programs/freetds.nix ./programs/gnupg.nix ./programs/gphoto2.nix - ./programs/info.nix + ./programs/iftop.nix ./programs/java.nix ./programs/kbdlight.nix ./programs/less.nix ./programs/light.nix - ./programs/man.nix ./programs/mosh.nix ./programs/mtr.nix ./programs/nano.nix @@ -159,8 +159,9 @@ ./services/audio/slimserver.nix ./services/audio/squeezelite.nix ./services/audio/ympd.nix - ./services/backup/almir.nix ./services/backup/bacula.nix + ./services/backup/borgbackup.nix + ./services/backup/duplicati.nix ./services/backup/crashplan.nix ./services/backup/crashplan-small-business.nix ./services/backup/mysql-backup.nix @@ -324,8 +325,9 @@ ./services/misc/geoip-updater.nix ./services/misc/gitea.nix #./services/misc/gitit.nix - ./services/misc/gitlab.nix + #./services/misc/gitlab.nix ./services/misc/gitolite.nix + ./services/misc/gitweb.nix ./services/misc/gogs.nix ./services/misc/gollum.nix ./services/misc/gpsd.nix @@ -363,6 +365,7 @@ ./services/misc/rippled.nix ./services/misc/ripple-data-api.nix ./services/misc/rogue.nix + ./services/misc/serviio.nix ./services/misc/siproxd.nix ./services/misc/snapper.nix ./services/misc/sonarr.nix @@ -398,16 +401,7 @@ ./services/monitoring/osquery.nix ./services/monitoring/prometheus/default.nix ./services/monitoring/prometheus/alertmanager.nix - ./services/monitoring/prometheus/blackbox-exporter.nix - ./services/monitoring/prometheus/collectd-exporter.nix - ./services/monitoring/prometheus/fritzbox-exporter.nix - ./services/monitoring/prometheus/json-exporter.nix - ./services/monitoring/prometheus/minio-exporter.nix - ./services/monitoring/prometheus/nginx-exporter.nix - ./services/monitoring/prometheus/node-exporter.nix - ./services/monitoring/prometheus/snmp-exporter.nix - ./services/monitoring/prometheus/unifi-exporter.nix - ./services/monitoring/prometheus/varnish-exporter.nix + ./services/monitoring/prometheus/exporters.nix ./services/monitoring/riemann.nix ./services/monitoring/riemann-dash.nix ./services/monitoring/riemann-tools.nix @@ -640,7 +634,6 @@ ./services/web-apps/atlassian/jira.nix ./services/web-apps/frab.nix ./services/web-apps/mattermost.nix - ./services/web-apps/nixbot.nix ./services/web-apps/nexus.nix ./services/web-apps/pgpkeyserver-lite.nix ./services/web-apps/matomo.nix @@ -660,6 +653,7 @@ ./services/web-servers/mighttpd2.nix ./services/web-servers/minio.nix ./services/web-servers/nginx/default.nix + ./services/web-servers/nginx/gitweb.nix ./services/web-servers/phpfpm/default.nix ./services/web-servers/shellinabox.nix ./services/web-servers/tomcat.nix diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 39b8553976ebd..3bf06a951193f 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -9,7 +9,7 @@ environment.systemPackages = [ pkgs.w3m-nox # needed for the manual anyway pkgs.testdisk # useful for repairing boot problems - pkgs.mssys # for writing Microsoft boot sectors / MBRs + pkgs.ms-sys # for writing Microsoft boot sectors / MBRs pkgs.efibootmgr pkgs.efivar pkgs.parted diff --git a/nixos/modules/profiles/docker-container.nix b/nixos/modules/profiles/docker-container.nix index 433492b96137e..7031d7d1d5931 100644 --- a/nixos/modules/profiles/docker-container.nix +++ b/nixos/modules/profiles/docker-container.nix @@ -14,9 +14,7 @@ in { ]; # Create the tarball - system.build.tarball = import ../../lib/make-system-tarball.nix { - inherit (pkgs) stdenv perl xz pathsFromGraph; - + system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix { contents = []; extraArgs = "--owner=0"; diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix index e2497d04252e0..40df7063a9bf3 100644 --- a/nixos/modules/profiles/minimal.nix +++ b/nixos/modules/profiles/minimal.nix @@ -10,10 +10,9 @@ with lib; # This isn't perfect, but let's expect the user specifies an UTF-8 defaultLocale i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ]; - services.nixosManual.enable = mkDefault false; - programs.man.enable = mkDefault false; - programs.info.enable = mkDefault false; + documentation.enable = mkDefault false; + services.nixosManual.enable = mkDefault false; sound.enable = mkDefault false; } diff --git a/nixos/modules/programs/iftop.nix b/nixos/modules/programs/iftop.nix new file mode 100644 index 0000000000000..a98a9a8187d4b --- /dev/null +++ b/nixos/modules/programs/iftop.nix @@ -0,0 +1,18 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.iftop; +in { + options = { + programs.iftop.enable = mkEnableOption "iftop + setcap wrapper"; + }; + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.iftop ]; + security.wrappers.iftop = { + source = "${pkgs.iftop}/bin/iftop"; + capabilities = "cap_net_raw+p"; + }; + }; +} diff --git a/nixos/modules/programs/info.nix b/nixos/modules/programs/info.nix deleted file mode 100644 index be6439dca5adc..0000000000000 --- a/nixos/modules/programs/info.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ - - options = { - - programs.info.enable = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable info pages and the <command>info</command> command. - ''; - }; - - }; - - - config = mkIf config.programs.info.enable { - - environment.systemPackages = [ pkgs.texinfoInteractive ]; - - environment.pathsToLink = [ "/info" "/share/info" ]; - - environment.extraOutputsToInstall = [ "info" ]; - - }; - -} diff --git a/nixos/modules/programs/less.nix b/nixos/modules/programs/less.nix index c0283c9e68626..d39103a58057d 100644 --- a/nixos/modules/programs/less.nix +++ b/nixos/modules/programs/less.nix @@ -6,7 +6,7 @@ let cfg = config.programs.less; - configFile = '' + configText = if (cfg.configFile != null) then (builtins.readFile cfg.configFile) else '' #command ${concatStringsSep "\n" (mapAttrsToList (command: action: "${command} ${action}") cfg.commands) @@ -25,7 +25,7 @@ let ''; lessKey = pkgs.runCommand "lesskey" - { src = pkgs.writeText "lessconfig" configFile; } + { src = pkgs.writeText "lessconfig" configText; } "${pkgs.less}/bin/lesskey -o $out $src"; in @@ -37,6 +37,19 @@ in enable = mkEnableOption "less"; + configFile = mkOption { + type = types.nullOr types.path; + default = null; + example = literalExample "$${pkgs.my-configs}/lesskey"; + description = '' + Path to lesskey configuration file. + + <option>configFile</option> takes precedence over <option>commands</option>, + <option>clearDefaultCommands</option>, <option>lineEditingKeys</option>, and + <option>envVariables</option>. + ''; + }; + commands = mkOption { type = types.attrsOf types.str; default = {}; diff --git a/nixos/modules/programs/man.nix b/nixos/modules/programs/man.nix deleted file mode 100644 index 5b20a38d88565..0000000000000 --- a/nixos/modules/programs/man.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ - - options = { - - programs.man.enable = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable manual pages and the <command>man</command> command. - This also includes "man" outputs of all <literal>systemPackages</literal>. - ''; - }; - - }; - - - config = mkIf config.programs.man.enable { - - environment.systemPackages = [ pkgs.man-db ]; - - environment.pathsToLink = [ "/share/man" ]; - - environment.extraOutputsToInstall = [ "man" ]; - - }; - -} diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 489d7d8b9b50e..0c3ac054292d3 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -4,6 +4,7 @@ with lib; { imports = [ + (mkRenamedOptionModule [ "dysnomia" ] [ "services" "dysnomia" ]) (mkRenamedOptionModule [ "environment" "x11Packages" ] [ "environment" "systemPackages" ]) (mkRenamedOptionModule [ "environment" "enableBashCompletion" ] [ "programs" "bash" "enableCompletion" ]) (mkRenamedOptionModule [ "environment" "nix" ] [ "nix" "package" ]) @@ -196,13 +197,17 @@ with lib; (mkRenamedOptionModule [ "virtualization" "growPartition" ] [ "boot" "growPartition" ]) # misc/version.nix - (mkRenamedOptionModule [ "config" "system" "nixosVersion" ] [ "config" "system" "nixos" "version" ]) + #(mkRenamedOptionModule [ "config" "system" "nixosVersion" ] [ "config" "system" "nixos" "version" ]) (mkRenamedOptionModule [ "config" "system" "nixosRelease" ] [ "config" "system" "nixos" "release" ]) - (mkRenamedOptionModule [ "config" "system" "nixosVersionSuffix" ] [ "config" "system" "nixos" "versionSuffix" ]) + #(mkRenamedOptionModule [ "config" "system" "nixosVersionSuffix" ] [ "config" "system" "nixos" "versionSuffix" ]) (mkRenamedOptionModule [ "config" "system" "nixosRevision" ] [ "config" "system" "nixos" "revision" ]) (mkRenamedOptionModule [ "config" "system" "nixosCodeName" ] [ "config" "system" "nixos" "codeName" ]) (mkRenamedOptionModule [ "config" "system" "nixosLabel" ] [ "config" "system" "nixos" "label" ]) + # Users + (mkAliasOptionModule [ "users" "extraUsers" ] [ "users" "users" ]) + (mkAliasOptionModule [ "users" "extraGroups" ] [ "users" "groups" ]) + # Options that are obsolete and have no replacement. (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "") (mkRemovedOptionModule [ "programs" "bash" "enable" ] "") @@ -240,5 +245,15 @@ with lib; # Xen (mkRenamedOptionModule [ "virtualisation" "xen" "qemu-package" ] [ "virtualisation" "xen" "package-qemu" ]) - ]; + + (mkRenamedOptionModule [ "programs" "info" "enable" ] [ "documentation" "info" "enable" ]) + (mkRenamedOptionModule [ "programs" "man" "enable" ] [ "documentation" "man" "enable" ]) + + ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter" + "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" + "snmpExporter" "unifiExporter" "varnishExporter" ] + (opt: mkRemovedOptionModule [ "services" "prometheus" "${opt}" ] '' + The prometheus exporters are now configured using `services.prometheus.exporters'. + See the 18.03 release notes for more information. + '' )); } diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 0736239ed2cfb..e9676d9dfb154 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -140,14 +140,6 @@ in ''; }; - tosHash = mkOption { - type = types.string; - default = "cc88d8d9517f490191401e7b54e9ffd12a2b9082ec7a1d4cec6101f9f1647e7b"; - description = '' - SHA256 of the Terms of Services document. This changes once in a while. - ''; - }; - production = mkOption { type = types.bool; default = true; @@ -196,7 +188,7 @@ in let cpath = "${cfg.directory}/${cert}"; rights = if data.allowKeysForGroup then "750" else "700"; - cmdline = [ "-v" "-d" data.domain "--default_root" data.webroot "--valid_min" cfg.validMin "--tos_sha256" cfg.tosHash ] + cmdline = [ "-v" "-d" data.domain "--default_root" data.webroot "--valid_min" cfg.validMin ] ++ optionals (data.email != null) [ "--email" data.email ] ++ concatMap (p: [ "-f" p ]) data.plugins ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains) diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix index 9ca818e86ffa1..df6108dede7c4 100644 --- a/nixos/modules/security/duosec.nix +++ b/nixos/modules/security/duosec.nix @@ -25,14 +25,14 @@ let loginCfgFile = optional cfg.ssh.enable { source = pkgs.writeText "login_duo.conf" configFile; mode = "0600"; - uid = config.ids.uids.sshd; + user = "sshd"; target = "duo/login_duo.conf"; }; pamCfgFile = optional cfg.pam.enable { source = pkgs.writeText "pam_duo.conf" configFile; mode = "0600"; - uid = config.ids.uids.sshd; + user = "sshd"; target = "duo/pam_duo.conf"; }; in diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index e1cad03e66e22..f2bdfcf885eea 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -386,7 +386,7 @@ let ${optionalString (cfg.enableGnomeKeyring) "session optional ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start"} ${optionalString (config.virtualisation.lxc.lxcfs.enable) - "session optional ${pkgs.lxcfs}/lib/security/pam_cgfs.so -c freezer,memory,name=systemd,unified,cpuset"} + "session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all"} ''); }; diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index e0ec77a295947..24283e1d6165c 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -47,8 +47,8 @@ in default = true; description = '' - Whether users of the <code>wheel</code> group can execute - commands as super user without entering a password. + Whether users of the <code>wheel</code> group must + provide a password to run commands as super user via <command>sudo</command>. ''; }; diff --git a/nixos/modules/services/backup/almir.nix b/nixos/modules/services/backup/almir.nix deleted file mode 100644 index fbb4ff4034f14..0000000000000 --- a/nixos/modules/services/backup/almir.nix +++ /dev/null @@ -1,173 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.almir; - - bconsoleconf = pkgs.writeText "bconsole.conf" - '' - Director { - Name = ${cfg.director_name} - DIRport = ${toString cfg.director_port} - address = ${cfg.director_address} - Password = "${cfg.director_password}" - } - ''; - - productionini = pkgs.writeText "production.ini" - '' -[app:main] -use = egg:almir - -pyramid.reload_templates = false -pyramid.debug_authorization = false -pyramid.debug_notfound = false -pyramid.debug_routematch = false -pyramid.debug_templates = false -pyramid.default_locale_name = en -pyramid.includes = - pyramid_exclog -exclog.extra_info = true - -sqlalchemy.url = ${cfg.sqlalchemy_engine_url} -timezone = ${cfg.timezone} -bconsole_config = ${bconsoleconf} - -[server:main] -use = egg:waitress#main -host = 127.0.0.1 -port = ${toString cfg.port} - - -# Begin logging configuration - -[loggers] -keys = root, almir, sqlalchemy, exc_logger - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console - -[logger_almir] -level = WARN -handlers = -qualname = almir - -[logger_exc_logger] -level = ERROR -handlers = -qualname = exc_logger - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine -# "level = INFO" logs SQL queries. -# "level = DEBUG" logs SQL queries and results. -# "level = WARN" logs neither. (Recommended for production systems.) - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s - ''; -in { - options = { - services.almir = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable Almir web server. Also configures postgresql database and installs bacula. - ''; - }; - - port = mkOption { - default = 35000; - type = types.int; - description = '' - Port for Almir web server to listen on. - ''; - }; - - timezone = mkOption { - description = '' - Timezone as specified in https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - ''; - example = "Europe/Ljubljana"; - }; - - sqlalchemy_engine_url = mkOption { - default = "postgresql:///bacula"; - example = '' - postgresql://bacula:bacula@localhost:5432/bacula - mysql+mysqlconnector://<user>:<password>@<hostname>/<database>' - sqlite:////var/lib/bacula/bacula.db' - ''; - description = '' - Define SQL database connection to bacula catalog as specified in http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls - ''; - }; - - director_name = mkOption { - description = '' - Name of the Director to connect with bconsole. - ''; - }; - - director_password = mkOption { - description = '' - Password for Director to connect with bconsole. - ''; - }; - - director_port = mkOption { - default = 9101; - type = types.int; - description = '' - Port for Director to connect with bconsole. - ''; - }; - - director_address = mkOption { - default = "127.0.0.1"; - description = '' - IP/Hostname for Director to connect with bconsole. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - systemd.services.almir = { - after = [ "network.target" "postgresql.service" ]; - description = "Almir web app"; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.pythonPackages.almir ]; - environment.PYTHONPATH = "${pkgs.pythonPackages.almir}/lib/${pkgs.pythonPackages.python.libPrefix}/site-packages"; - serviceConfig.ExecStart = "${pkgs.pythonPackages.pyramid}/bin/pserve ${productionini}"; - }; - - environment.systemPackages = [ pkgs.pythonPackages.almir ]; - - users.extraUsers.almir = { - group = "almir"; - uid = config.ids.uids.almir; - createHome = true; - shell = "${pkgs.bash}/bin/bash"; - }; - - users.extraGroups.almir.gid = config.ids.gids.almir; - }; -} diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix new file mode 100644 index 0000000000000..1b730e0c2b76d --- /dev/null +++ b/nixos/modules/services/backup/borgbackup.nix @@ -0,0 +1,580 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + isLocalPath = x: + builtins.substring 0 1 x == "/" # absolute path + || builtins.substring 0 1 x == "." # relative path + || builtins.match "[.*:.*]" == null; # not machine:path + + mkExcludeFile = cfg: + # Write each exclude pattern to a new line + pkgs.writeText "excludefile" (concatStringsSep "\n" cfg.exclude); + + mkKeepArgs = cfg: + # If cfg.prune.keep e.g. has a yearly attribute, + # its content is passed on as --keep-yearly + concatStringsSep " " + (mapAttrsToList (x: y: "--keep-${x}=${toString y}") cfg.prune.keep); + + mkBackupScript = cfg: '' + on_exit() + { + exitStatus=$? + # Reset the EXIT handler, or else we're called again on 'exit' below + trap - EXIT + ${cfg.postHook} + exit $exitStatus + } + trap 'on_exit' INT TERM QUIT EXIT + + archiveName="${cfg.archiveBaseName}-$(date ${cfg.dateFormat})" + archiveSuffix="${optionalString cfg.appendFailedSuffix ".failed"}" + ${cfg.preHook} + '' + optionalString cfg.doInit '' + # Run borg init if the repo doesn't exist yet + if ! borg list > /dev/null; then + borg init \ + --encryption ${cfg.encryption.mode} \ + $extraInitArgs + ${cfg.postInit} + fi + '' + '' + borg create \ + --compression ${cfg.compression} \ + --exclude-from ${mkExcludeFile cfg} \ + $extraCreateArgs \ + "::$archiveName$archiveSuffix" \ + ${escapeShellArgs cfg.paths} + '' + optionalString cfg.appendFailedSuffix '' + borg rename "::$archiveName$archiveSuffix" "$archiveName" + '' + '' + ${cfg.postCreate} + '' + optionalString (cfg.prune.keep != { }) '' + borg prune \ + ${mkKeepArgs cfg} \ + --prefix ${escapeShellArg cfg.prune.prefix} \ + $extraPruneArgs + ${cfg.postPrune} + ''; + + mkPassEnv = cfg: with cfg.encryption; + if passCommand != null then + { BORG_PASSCOMMAND = passCommand; } + else if passphrase != null then + { BORG_PASSPHRASE = passphrase; } + else { }; + + mkBackupService = name: cfg: + let + userHome = config.users.users.${cfg.user}.home; + in nameValuePair "borgbackup-job-${name}" { + description = "BorgBackup job ${name}"; + path = with pkgs; [ + borgbackup openssh + ]; + script = mkBackupScript cfg; + serviceConfig = { + User = cfg.user; + Group = cfg.group; + # Only run when no other process is using CPU or disk + CPUSchedulingPolicy = "idle"; + IOSchedulingClass = "idle"; + ProtectSystem = "strict"; + ReadWritePaths = + [ "${userHome}/.config/borg" "${userHome}/.cache/borg" ] + # Borg needs write access to repo if it is not remote + ++ optional (isLocalPath cfg.repo) cfg.repo; + PrivateTmp = true; + }; + environment = { + BORG_REPO = cfg.repo; + inherit (cfg) extraInitArgs extraCreateArgs extraPruneArgs; + } // (mkPassEnv cfg) // cfg.environment; + inherit (cfg) startAt; + }; + + # Paths listed in ReadWritePaths must exist before service is started + mkActivationScript = name: cfg: + let + install = "install -o ${cfg.user} -g ${cfg.group}"; + in + nameValuePair "borgbackup-job-${name}" (stringAfter [ "users" ] ('' + # Eensure that the home directory already exists + # We can't assert createHome == true because that's not the case for root + cd "${config.users.users.${cfg.user}.home}" + ${install} -d .config/borg + ${install} -d .cache/borg + '' + optionalString (isLocalPath cfg.repo) '' + ${install} -d ${escapeShellArg cfg.repo} + '')); + + mkPassAssertion = name: cfg: { + assertion = with cfg.encryption; + mode != "none" -> passCommand != null || passphrase != null; + message = + "passCommand or passphrase has to be specified because" + + '' borgbackup.jobs.${name}.encryption != "none"''; + }; + + mkRepoService = name: cfg: + nameValuePair "borgbackup-repo-${name}" { + description = "Create BorgBackup repository ${name} directory"; + script = '' + mkdir -p ${escapeShellArg cfg.path} + chown ${cfg.user}:${cfg.group} ${escapeShellArg cfg.path} + ''; + serviceConfig = { + # The service's only task is to ensure that the specified path exists + Type = "oneshot"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + mkAuthorizedKey = cfg: appendOnly: key: + let + # Because of the following line, clients do not need to specify an absolute repo path + cdCommand = "cd ${escapeShellArg cfg.path}"; + restrictedArg = "--restrict-to-${if cfg.allowSubRepos then "path" else "repository"} ."; + appendOnlyArg = optionalString appendOnly "--append-only"; + quotaArg = optionalString (cfg.quota != null) "--storage-quota ${cfg.quota}"; + serveCommand = "borg serve ${restrictedArg} ${appendOnlyArg} ${quotaArg}"; + in + ''command="${cdCommand} && ${serveCommand}",restrict ${key}''; + + mkUsersConfig = name: cfg: { + users.${cfg.user} = { + openssh.authorizedKeys.keys = + (map (mkAuthorizedKey cfg false) cfg.authorizedKeys + ++ map (mkAuthorizedKey cfg true) cfg.authorizedKeysAppendOnly); + useDefaultShell = true; + }; + groups.${cfg.group} = { }; + }; + + mkKeysAssertion = name: cfg: { + assertion = cfg.authorizedKeys != [ ] || cfg.authorizedKeysAppendOnly != [ ]; + message = + "borgbackup.repos.${name} does not make sense" + + " without at least one public key"; + }; + +in { + meta.maintainers = with maintainers; [ dotlambda ]; + + ###### interface + + options.services.borgbackup.jobs = mkOption { + description = "Deduplicating backups using BorgBackup."; + default = { }; + example = literalExample '' + { + rootBackup = { + paths = "/"; + exclude = [ "/nix" ]; + repo = "/path/to/local/repo"; + encryption = { + mode = "repokey"; + passphrase = "secret"; + }; + compression = "auto,lzma"; + startAt = "weekly"; + }; + } + ''; + type = types.attrsOf (types.submodule (let globalConfig = config; in + { name, config, ... }: { + options = { + + paths = mkOption { + type = with types; either path (nonEmptyListOf path); + description = "Path(s) to back up."; + example = "/home/user"; + apply = x: if isList x then x else [ x ]; + }; + + repo = mkOption { + type = types.str; + description = "Remote or local repository to back up to."; + example = "user@machine:/path/to/repo"; + }; + + archiveBaseName = mkOption { + type = types.strMatching "[^/{}]+"; + default = "${globalConfig.networking.hostName}-${name}"; + defaultText = "\${config.networking.hostName}-<name>"; + description = '' + How to name the created archives. A timestamp, whose format is + determined by <option>dateFormat</option>, will be appended. The full + name can be modified at runtime (<literal>$archiveName</literal>). + Placeholders like <literal>{hostname}</literal> must not be used. + ''; + }; + + dateFormat = mkOption { + type = types.str; + description = '' + Arguments passed to <command>date</command> + to create a timestamp suffix for the archive name. + ''; + default = "+%Y-%m-%dT%H:%M:%S"; + example = "-u +%s"; + }; + + startAt = mkOption { + type = with types; either str (listOf str); + default = "daily"; + description = '' + When or how often the backup should run. + Must be in the format described in + <citerefentry><refentrytitle>systemd.time</refentrytitle> + <manvolnum>7</manvolnum></citerefentry>. + If you do not want the backup to start + automatically, use <literal>[ ]</literal>. + ''; + }; + + user = mkOption { + type = types.str; + description = '' + The user <command>borg</command> is run as. + User or group need read permission + for the specified <option>paths</option>. + ''; + default = "root"; + }; + + group = mkOption { + type = types.str; + description = '' + The group borg is run as. User or group needs read permission + for the specified <option>paths</option>. + ''; + default = "root"; + }; + + encryption.mode = mkOption { + type = types.enum [ + "repokey" "keyfile" + "repokey-blake2" "keyfile-blake2" + "authenticated" "authenticated-blake2" + "none" + ]; + description = '' + Encryption mode to use. Setting a mode + other than <literal>"none"</literal> requires + you to specify a <option>passCommand</option> + or a <option>passphrase</option>. + ''; + }; + + encryption.passCommand = mkOption { + type = with types; nullOr str; + description = '' + A command which prints the passphrase to stdout. + Mutually exclusive with <option>passphrase</option>. + ''; + default = null; + example = "cat /path/to/passphrase_file"; + }; + + encryption.passphrase = mkOption { + type = with types; nullOr str; + description = '' + The passphrase the backups are encrypted with. + Mutually exclusive with <option>passCommand</option>. + If you do not want the passphrase to be stored in the + world-readable Nix store, use <option>passCommand</option>. + ''; + default = null; + }; + + compression = mkOption { + # "auto" is optional, + # compression mode must be given, + # compression level is optional + type = types.strMatching "none|(auto,)?(lz4|zstd|zlib|lzma)(,[[:digit:]]{1,2})?"; + description = '' + Compression method to use. Refer to + <command>borg help compression</command> + for all available options. + ''; + default = "lz4"; + example = "auto,lzma"; + }; + + exclude = mkOption { + type = with types; listOf str; + description = '' + Exclude paths matching any of the given patterns. See + <command>borg help patterns</command> for pattern syntax. + ''; + default = [ ]; + example = [ + "/home/*/.cache" + "/nix" + ]; + }; + + doInit = mkOption { + type = types.bool; + description = '' + Run <command>borg init</command> if the + specified <option>repo</option> does not exist. + You should set this to <literal>false</literal> + if the repository is located on an external drive + that might not always be mounted. + ''; + default = true; + }; + + appendFailedSuffix = mkOption { + type = types.bool; + description = '' + Append a <literal>.failed</literal> suffix + to the archive name, which is only removed if + <command>borg create</command> has a zero exit status. + ''; + default = true; + }; + + prune.keep = mkOption { + # Specifying e.g. `prune.keep.yearly = -1` + # means there is no limit of yearly archives to keep + # The regex is for use with e.g. --keep-within 1y + type = with types; attrsOf (either int (strMatching "[[:digit:]]+[Hdwmy]")); + description = '' + Prune a repository by deleting all archives not matching any of the + specified retention options. See <command>borg help prune</command> + for the available options. + ''; + default = { }; + example = literalExample '' + { + within = "1d"; # Keep all archives from the last day + daily = 7; + weekly = 4; + monthly = -1; # Keep at least one archive for each month + } + ''; + }; + + prune.prefix = mkOption { + type = types.str; + description = '' + Only consider archive names starting with this prefix for pruning. + By default, only archives created by this job are considered. + Use <literal>""</literal> to consider all archives. + ''; + default = config.archiveBaseName; + defaultText = "\${archiveBaseName}"; + }; + + environment = mkOption { + type = with types; attrsOf str; + description = '' + Environment variables passed to the backup script. + You can for example specify which SSH key to use. + ''; + default = { }; + example = { BORG_RSH = "ssh -i /path/to/key"; }; + }; + + preHook = mkOption { + type = types.lines; + description = '' + Shell commands to run before the backup. + This can for example be used to mount file systems. + ''; + default = ""; + example = '' + # To add excluded paths at runtime + extraCreateArgs="$extraCreateArgs --exclude /some/path" + ''; + }; + + postInit = mkOption { + type = types.lines; + description = '' + Shell commands to run after <command>borg init</command>. + ''; + default = ""; + }; + + postCreate = mkOption { + type = types.lines; + description = '' + Shell commands to run after <command>borg create</command>. The name + of the created archive is stored in <literal>$archiveName</literal>. + ''; + default = ""; + }; + + postPrune = mkOption { + type = types.lines; + description = '' + Shell commands to run after <command>borg prune</command>. + ''; + default = ""; + }; + + postHook = mkOption { + type = types.lines; + description = '' + Shell commands to run just before exit. They are executed + even if a previous command exits with a non-zero exit code. + The latter is available as <literal>$exitStatus</literal>. + ''; + default = ""; + }; + + extraInitArgs = mkOption { + type = types.str; + description = '' + Additional arguments for <command>borg init</command>. + Can also be set at runtime using <literal>$extraInitArgs</literal>. + ''; + default = ""; + example = "--append-only"; + }; + + extraCreateArgs = mkOption { + type = types.str; + description = '' + Additional arguments for <command>borg create</command>. + Can also be set at runtime using <literal>$extraCreateArgs</literal>. + ''; + default = ""; + example = "--stats --checkpoint-interval 600"; + }; + + extraPruneArgs = mkOption { + type = types.str; + description = '' + Additional arguments for <command>borg prune</command>. + Can also be set at runtime using <literal>$extraPruneArgs</literal>. + ''; + default = ""; + example = "--save-space"; + }; + + }; + } + )); + }; + + options.services.borgbackup.repos = mkOption { + description = '' + Serve BorgBackup repositories to given public SSH keys, + restricting their access to the repository only. + Also, clients do not need to specify the absolute path when accessing the repository, + i.e. <literal>user@machine:.</literal> is enough. (Note colon and dot.) + ''; + default = { }; + type = types.attrsOf (types.submodule ( + { name, config, ... }: { + options = { + + path = mkOption { + type = types.path; + description = '' + Where to store the backups. Note that the directory + is created automatically, with correct permissions. + ''; + default = "/var/lib/borgbackup"; + }; + + user = mkOption { + type = types.str; + description = '' + The user <command>borg serve</command> is run as. + User or group needs write permission + for the specified <option>path</option>. + ''; + default = "borg"; + }; + + group = mkOption { + type = types.str; + description = '' + The group <command>borg serve</command> is run as. + User or group needs write permission + for the specified <option>path</option>. + ''; + default = "borg"; + }; + + authorizedKeys = mkOption { + type = with types; listOf str; + description = '' + Public SSH keys that are given full write access to this repository. + You should use a different SSH key for each repository you write to, because + the specified keys are restricted to running <command>borg serve</command> + and can only access this single repository. + ''; + default = [ ]; + }; + + authorizedKeysAppendOnly = mkOption { + type = with types; listOf str; + description = '' + Public SSH keys that can only be used to append new data (archives) to the repository. + Note that archives can still be marked as deleted and are subsequently removed from disk + upon accessing the repo with full write access, e.g. when pruning. + ''; + default = [ ]; + }; + + allowSubRepos = mkOption { + type = types.bool; + description = '' + Allow clients to create repositories in subdirectories of the + specified <option>path</option>. These can be accessed using + <literal>user@machine:path/to/subrepo</literal>. Note that a + <option>quota</option> applies to repositories independently. + Therefore, if this is enabled, clients can create multiple + repositories and upload an arbitrary amount of data. + ''; + default = false; + }; + + quota = mkOption { + # See the definition of parse_file_size() in src/borg/helpers/parseformat.py + type = with types; nullOr (strMatching "[[:digit:].]+[KMGTP]?"); + description = '' + Storage quota for the repository. This quota is ensured for all + sub-repositories if <option>allowSubRepos</option> is enabled + but not for the overall storage space used. + ''; + default = null; + example = "100G"; + }; + + }; + } + )); + }; + + ###### implementation + + config = mkIf (with config.services.borgbackup; jobs != { } || repos != { }) + (with config.services.borgbackup; { + assertions = + mapAttrsToList mkPassAssertion jobs + ++ mapAttrsToList mkKeysAssertion repos; + + system.activationScripts = mapAttrs' mkActivationScript jobs; + + systemd.services = + # A job named "foo" is mapped to systemd.services.borgbackup-job-foo + mapAttrs' mkBackupService jobs + # A repo named "foo" is mapped to systemd.services.borgbackup-repo-foo + // mapAttrs' mkRepoService repos; + + users = mkMerge (mapAttrsToList mkUsersConfig repos); + + environment.systemPackages = with pkgs; [ borgbackup ]; + }); +} diff --git a/nixos/modules/services/backup/duplicati.nix b/nixos/modules/services/backup/duplicati.nix new file mode 100644 index 0000000000000..9772ca4d20a79 --- /dev/null +++ b/nixos/modules/services/backup/duplicati.nix @@ -0,0 +1,40 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.duplicati; +in +{ + options = { + services.duplicati = { + enable = mkEnableOption "Duplicati"; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.duplicati ]; + + systemd.services.duplicati = { + description = "Duplicati backup"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "duplicati"; + Group = "duplicati"; + ExecStart = "${pkgs.duplicati}/bin/duplicati-server --webservice-interface=any --webservice-port=8200 --server-datafolder=/var/lib/duplicati"; + Restart = "on-failure"; + }; + }; + + users.extraUsers.duplicati = { + uid = config.ids.uids.duplicati; + home = "/var/lib/duplicati"; + createHome = true; + group = "duplicati"; + }; + users.extraGroups.duplicati.gid = config.ids.gids.duplicati; + + }; +} + diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix index 59e9d122fb50f..4fc7c24813a55 100644 --- a/nixos/modules/services/backup/tarsnap.nix +++ b/nixos/modules/services/backup/tarsnap.nix @@ -238,6 +238,20 @@ in Whether to produce verbose logging output. ''; }; + explicitSymlinks = mkOption { + type = types.bool; + default = false; + description = '' + Whether to follow symlinks specified as archives. + ''; + }; + followSymlinks = mkOption { + type = types.bool; + default = false; + description = '' + Whether to follow all symlinks in archive trees. + ''; + }; }; } )); @@ -285,12 +299,12 @@ in }) gcfg.archives); systemd.services = - mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" { + (mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" { description = "Tarsnap archive '${name}'"; requires = [ "network-online.target" ]; after = [ "network-online.target" ]; - path = [ pkgs.iputils pkgs.tarsnap pkgs.utillinux ]; + path = with pkgs; [ iputils tarsnap utillinux ]; # In order for the persistent tarsnap timer to work reliably, we have to # make sure that the tarsnap server is reachable after systemd starts up @@ -300,10 +314,12 @@ in while ! ping -q -c 1 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done ''; - script = - let run = ''tarsnap --configfile "/etc/tarsnap/${name}.conf" \ - -c -f "${name}-$(date +"%Y%m%d%H%M%S")" \ + script = let + tarsnap = ''tarsnap --configfile "/etc/tarsnap/${name}.conf"''; + run = ''${tarsnap} -c -f "${name}-$(date +"%Y%m%d%H%M%S")" \ ${optionalString cfg.verbose "-v"} \ + ${optionalString cfg.explicitSymlinks "-H"} \ + ${optionalString cfg.followSymlinks "-L"} \ ${concatStringsSep " " cfg.directories}''; in if (cfg.cachedir != null) then '' mkdir -p ${cfg.cachedir} @@ -313,7 +329,7 @@ in if [ ! -e ${cfg.cachedir}/firstrun ]; then ( flock 10 flock -u 9 - tarsnap --configfile "/etc/tarsnap/${name}.conf" --fsck + ${tarsnap} --fsck flock 9 ) 10>${cfg.cachedir}/firstrun fi @@ -329,7 +345,44 @@ in CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ]; PermissionsStartOnly = "true"; }; - }) gcfg.archives; + }) gcfg.archives) // + + (mapAttrs' (name: cfg: nameValuePair "tarsnap-restore-${name}"{ + description = "Tarsnap restore '${name}'"; + requires = [ "network-online.target" ]; + + path = with pkgs; [ iputils tarsnap utillinux ]; + + script = let + tarsnap = ''tarsnap --configfile "/etc/tarsnap/${name}.conf"''; + lastArchive = ''$(${tarsnap} --list-archives | sort | tail -1)''; + run = ''${tarsnap} -x -f "${lastArchive}" ${optionalString cfg.verbose "-v"}''; + + in if (cfg.cachedir != null) then '' + mkdir -p ${cfg.cachedir} + chmod 0700 ${cfg.cachedir} + + ( flock 9 + if [ ! -e ${cfg.cachedir}/firstrun ]; then + ( flock 10 + flock -u 9 + ${tarsnap} --fsck + flock 9 + ) 10>${cfg.cachedir}/firstrun + fi + ) 9>${cfg.cachedir}/lockf + + exec flock ${cfg.cachedir}/firstrun ${run} + '' else "exec ${run}"; + + serviceConfig = { + Type = "oneshot"; + IOSchedulingClass = "idle"; + NoNewPrivileges = "true"; + CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ]; + PermissionsStartOnly = "true"; + }; + }) gcfg.archives); # Note: the timer must be Persistent=true, so that systemd will start it even # if e.g. your laptop was asleep while the latest interval occurred. diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix index 762bb4b38675c..3d133f82d2048 100644 --- a/nixos/modules/services/backup/znapzend.nix +++ b/nixos/modules/services/backup/znapzend.nix @@ -386,7 +386,7 @@ in echo Resetting znapzend zetups ${pkgs.znapzend}/bin/znapzendzetup list \ | grep -oP '(?<=\*\*\* backup plan: ).*(?= \*\*\*)' \ - | xargs ${pkgs.znapzend}/bin/znapzendzetup delete + | xargs -I{} ${pkgs.znapzend}/bin/znapzendzetup delete "{}" '' + concatStringsSep "\n" (mapAttrsToList (dataset: config: '' echo Importing znapzend zetup ${config} for dataset ${dataset} ${pkgs.znapzend}/bin/znapzendzetup import --write ${dataset} ${config} diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix index 4a2c6f0833ebc..aeb0a0d2432d7 100644 --- a/nixos/modules/services/cluster/kubernetes/default.nix +++ b/nixos/modules/services/cluster/kubernetes/default.nix @@ -279,7 +279,7 @@ in { tokenAuthFile = mkOption { description = '' Kubernetes apiserver token authentication file. See - <link xlink:href="http://kubernetes.io/docs/admin/authentication.html"/> + <link xlink:href="https://kubernetes.io/docs/admin/authentication.html"/> ''; default = null; type = types.nullOr types.path; @@ -288,7 +288,7 @@ in { basicAuthFile = mkOption { description = '' Kubernetes apiserver basic authentication file. See - <link xlink:href="http://kubernetes.io/docs/admin/authentication.html"/> + <link xlink:href="https://kubernetes.io/docs/admin/authentication.html"/> ''; default = pkgs.writeText "users" '' kubernetes,admin,0 @@ -299,7 +299,7 @@ in { authorizationMode = mkOption { description = '' Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC/RBAC). See - <link xlink:href="http://kubernetes.io/docs/admin/authorization.html"/> + <link xlink:href="https://kubernetes.io/docs/admin/authorization.html"/> ''; default = ["RBAC" "Node"]; type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "RBAC" "Node"]); @@ -308,7 +308,7 @@ in { authorizationPolicy = mkOption { description = '' Kubernetes apiserver authorization policy file. See - <link xlink:href="http://kubernetes.io/docs/admin/authorization.html"/> + <link xlink:href="https://kubernetes.io/docs/admin/authorization.html"/> ''; default = []; type = types.listOf types.attrs; @@ -332,7 +332,7 @@ in { runtimeConfig = mkOption { description = '' Api runtime configuration. See - <link xlink:href="http://kubernetes.io/docs/admin/cluster-management.html"/> + <link xlink:href="https://kubernetes.io/docs/admin/cluster-management.html"/> ''; default = "authentication.k8s.io/v1beta1=true"; example = "api/all=false,api/v1=true"; @@ -342,7 +342,7 @@ in { admissionControl = mkOption { description = '' Kubernetes admission control plugins to use. See - <link xlink:href="http://kubernetes.io/docs/admin/admission-controllers/"/> + <link xlink:href="https://kubernetes.io/docs/admin/admission-controllers/"/> ''; default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota" "DefaultStorageClass" "DefaultTolerationSeconds" "NodeRestriction"]; example = [ @@ -766,7 +766,7 @@ in { rm /opt/cni/bin/* || true ${concatMapStrings (package: '' echo "Linking cni package: ${package}" - ln -fs ${package.plugins}/* /opt/cni/bin + ln -fs ${package}/bin/* /opt/cni/bin '') cfg.kubelet.cni.packages} ''; serviceConfig = { @@ -828,7 +828,7 @@ in { }; # Allways include cni plugins - services.kubernetes.kubelet.cni.packages = [pkgs.cni]; + services.kubernetes.kubelet.cni.packages = [pkgs.cni-plugins]; boot.kernelModules = ["br_netfilter"]; diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index 54047a50caa6c..c2f4e9c0c5a73 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -145,6 +145,11 @@ in { }; config = mkIf cfg.enable { + # server references the dejavu fonts + environment.systemPackages = [ + pkgs.dejavu_fonts + ]; + users.extraGroups = optional (cfg.group == "jenkins") { name = "jenkins"; gid = config.ids.gids.jenkins; @@ -200,10 +205,12 @@ in { ${replacePlugins} ''; + # For reference: https://wiki.jenkins.io/display/JENKINS/JenkinsLinuxStartupScript script = '' ${pkgs.jdk}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \ --httpPort=${toString cfg.port} \ --prefix=${cfg.prefix} \ + -Djava.awt.headless=true \ ${concatStringsSep " " cfg.extraOptions} ''; diff --git a/nixos/modules/services/logging/graylog.nix b/nixos/modules/services/logging/graylog.nix index a0dc0d6d089de..95f31829882ff 100644 --- a/nixos/modules/services/logging/graylog.nix +++ b/nixos/modules/services/logging/graylog.nix @@ -141,7 +141,7 @@ in JAVA_HOME = jre; GRAYLOG_CONF = "${confFile}"; }; - path = [ pkgs.openjdk8 pkgs.which pkgs.procps ]; + path = [ pkgs.jre_headless pkgs.which pkgs.procps ]; preStart = '' mkdir -p /var/lib/graylog -m 755 diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index b42c73b866687..543e732127a53 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -30,6 +30,7 @@ let '' default_internal_user = ${cfg.user} + default_internal_group = ${cfg.group} ${optionalString (cfg.mailUser != null) "mail_uid = ${cfg.mailUser}"} ${optionalString (cfg.mailGroup != null) "mail_gid = ${cfg.mailGroup}"} diff --git a/nixos/modules/services/misc/defaultUnicornConfig.rb b/nixos/modules/services/misc/defaultUnicornConfig.rb index 84622622db70b..0b58c59c7a513 100644 --- a/nixos/modules/services/misc/defaultUnicornConfig.rb +++ b/nixos/modules/services/misc/defaultUnicornConfig.rb @@ -1,205 +1,69 @@ -# The following was taken from github.com/crohr/syslogger and is BSD -# licensed. -require 'syslog' -require 'logger' -require 'thread' +worker_processes 3 -class Syslogger - - VERSION = "1.6.0" - - attr_reader :level, :ident, :options, :facility, :max_octets - attr_accessor :formatter - - MAPPING = { - Logger::DEBUG => Syslog::LOG_DEBUG, - Logger::INFO => Syslog::LOG_INFO, - Logger::WARN => Syslog::LOG_WARNING, - Logger::ERROR => Syslog::LOG_ERR, - Logger::FATAL => Syslog::LOG_CRIT, - Logger::UNKNOWN => Syslog::LOG_ALERT - } - - # - # Initializes default options for the logger - # <tt>ident</tt>:: the name of your program [default=$0]. - # <tt>options</tt>:: syslog options [default=<tt>Syslog::LOG_PID | Syslog::LOG_CONS</tt>]. - # Correct values are: - # LOG_CONS : writes the message on the console if an error occurs when sending the message; - # LOG_NDELAY : no delay before sending the message; - # LOG_PERROR : messages will also be written on STDERR; - # LOG_PID : adds the process number to the message (just after the program name) - # <tt>facility</tt>:: the syslog facility [default=nil] Correct values include: - # Syslog::LOG_DAEMON - # Syslog::LOG_USER - # Syslog::LOG_SYSLOG - # Syslog::LOG_LOCAL2 - # Syslog::LOG_NEWS - # etc. - # - # Usage: - # logger = Syslogger.new("my_app", Syslog::LOG_PID | Syslog::LOG_CONS, Syslog::LOG_LOCAL0) - # logger.level = Logger::INFO # use Logger levels - # logger.warn "warning message" - # logger.debug "debug message" - # - def initialize(ident = $0, options = Syslog::LOG_PID | Syslog::LOG_CONS, facility = nil) - @ident = ident - @options = options || (Syslog::LOG_PID | Syslog::LOG_CONS) - @facility = facility - @level = Logger::INFO - @mutex = Mutex.new - @formatter = Logger::Formatter.new - end - - %w{debug info warn error fatal unknown}.each do |logger_method| - # Accepting *args as message could be nil. - # Default params not supported in ruby 1.8.7 - define_method logger_method.to_sym do |*args, &block| - return true if @level > Logger.const_get(logger_method.upcase) - message = args.first || block && block.call - add(Logger.const_get(logger_method.upcase), message) - end - - unless logger_method == 'unknown' - define_method "#{logger_method}?".to_sym do - @level <= Logger.const_get(logger_method.upcase) - end - end - end - - # Log a message at the Logger::INFO level. Useful for use with Rack::CommonLogger - def write(msg) - add(Logger::INFO, msg) - end - - # Logs a message at the Logger::INFO level. - def <<(msg) - add(Logger::INFO, msg) - end - - # Low level method to add a message. - # +severity+:: the level of the message. One of Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR, Logger::FATAL, Logger::UNKNOWN - # +message+:: the message string. - # If nil, the method will call the block and use the result as the message string. - # If both are nil or no block is given, it will use the progname as per the behaviour of both the standard Ruby logger, and the Rails BufferedLogger. - # +progname+:: optionally, overwrite the program name that appears in the log message. - def add(severity, message = nil, progname = nil, &block) - if message.nil? && block.nil? && !progname.nil? - message, progname = progname, nil - end - progname ||= @ident - - @mutex.synchronize do - Syslog.open(progname, @options, @facility) do |s| - s.mask = Syslog::LOG_UPTO(MAPPING[@level]) - communication = clean(message || block && block.call) - if self.max_octets - buffer = "#{tags_text}" - communication.bytes do |byte| - buffer.concat(byte) - # if the last byte we added is potentially part of an escape, we'll go ahead and add another byte - if buffer.bytesize >= self.max_octets && !['%'.ord,'\\'.ord].include?(byte) - s.log(MAPPING[severity],buffer) - buffer = "" - end - end - s.log(MAPPING[severity],buffer) unless buffer.empty? - else - s.log(MAPPING[severity],"#{tags_text}#{communication}") - end - end - end - end - - # Set the max octets of the messages written to the log - def max_octets=(max_octets) - @max_octets = max_octets - end - - # Sets the minimum level for messages to be written in the log. - # +level+:: one of <tt>Logger::DEBUG</tt>, <tt>Logger::INFO</tt>, <tt>Logger::WARN</tt>, <tt>Logger::ERROR</tt>, <tt>Logger::FATAL</tt>, <tt>Logger::UNKNOWN</tt> - def level=(level) - level = Logger.const_get(level.to_s.upcase) if level.is_a?(Symbol) - - unless level.is_a?(Fixnum) - raise ArgumentError.new("Invalid logger level `#{level.inspect}`") - end - - @level = level - end - - # Sets the ident string passed along to Syslog - def ident=(ident) - @ident = ident - end - - # Tagging code borrowed from ActiveSupport gem - def tagged(*tags) - new_tags = push_tags(*tags) - yield self - ensure - pop_tags(new_tags.size) - end - - def push_tags(*tags) - tags.flatten.reject{ |i| i.respond_to?(:empty?) ? i.empty? : !i }.tap do |new_tags| - current_tags.concat new_tags - end - end - - def pop_tags(size = 1) - current_tags.pop size - end - - def clear_tags! - current_tags.clear - end - - protected - - # Borrowed from SyslogLogger. - def clean(message) - message = message.to_s.dup - message.strip! # remove whitespace - message.gsub!(/\n/, '\\n') # escape newlines - message.gsub!(/%/, '%%') # syslog(3) freaks on % (printf) - message.gsub!(/\e\[[^m]*m/, '') # remove useless ansi color codes - message - end - - private - - def tags_text - tags = current_tags - if tags.any? - tags.collect { |tag| "[#{tag}] " }.join - end - end - - def current_tags - Thread.current[:syslogger_tagged_logging_tags] ||= [] - end -end +listen ENV["UNICORN_PATH"] + "/tmp/sockets/gitlab.socket", :backlog => 1024 +listen "/run/gitlab/gitlab.socket", :backlog => 1024 -worker_processes 2 working_directory ENV["GITLAB_PATH"] -pid ENV["UNICORN_PATH"] + "/tmp/pids/unicorn.pid" -listen ENV["UNICORN_PATH"] + "/tmp/sockets/gitlab.socket", :backlog => 1024 +pid ENV["UNICORN_PATH"] + "/tmp/pids/unicorn.pid" timeout 60 -logger Syslogger.new - +# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings +# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow preload_app true - GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true check_client_connection false +before_fork do |server, worker| + # the following is highly recommended for Rails + "preload_app true" + # as there's no need for the master process to hold a connection + defined?(ActiveRecord::Base) and + ActiveRecord::Base.connection.disconnect! + + # The following is only recommended for memory/DB-constrained + # installations. It is not needed if your system can house + # twice as many worker_processes as you have configured. + # + # This allows a new master process to incrementally + # phase out the old master process with SIGTTOU to avoid a + # thundering herd (especially in the "preload_app false" case) + # when doing a transparent upgrade. The last worker spawned + # will then kill off the old master process with a SIGQUIT. + old_pid = "#{server.config[:pid]}.oldbin" + if old_pid != server.pid + begin + sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU + Process.kill(sig, File.read(old_pid).to_i) + rescue Errno::ENOENT, Errno::ESRCH + end + end + + # Throttle the master from forking too quickly by sleeping. Due + # to the implementation of standard Unix signal handlers, this + # helps (but does not completely) prevent identical, repeated signals + # from being lost when the receiving process is busy. + # sleep 1 +end + after_fork do |server, worker| + # per-process listener ports for debugging/admin/migrations + # addr = "127.0.0.1:#{9293 + worker.nr}" + # server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true) + + # the following is *required* for Rails + "preload_app true", defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection + + # reset prometheus client, this will cause any opened metrics files to be closed + defined?(::Prometheus::Client.reinitialize_on_pid_change) && + Prometheus::Client.reinitialize_on_pid_change + + # if preload_app is true, then you may also want to check and + # restart any other shared sockets/descriptors such as Memcached, + # and Redis. TokyoCabinet file handles are safe to reuse + # between any number of forked children (assuming your kernel + # correctly implements pread()/pwrite() system calls) end diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix index 39d23610b0644..e4517c636e880 100644 --- a/nixos/modules/services/misc/disnix.nix +++ b/nixos/modules/services/misc/disnix.nix @@ -57,7 +57,7 @@ in ###### implementation config = mkIf cfg.enable { - dysnomia.enable = true; + services.dysnomia.enable = true; environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService; diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix index c5c41ad296dab..25cd0038e36d3 100644 --- a/nixos/modules/services/misc/dysnomia.nix +++ b/nixos/modules/services/misc/dysnomia.nix @@ -3,8 +3,8 @@ with lib; let - cfg = config.dysnomia; - + cfg = config.services.dysnomia; + printProperties = properties: concatMapStrings (propertyName: let @@ -13,7 +13,7 @@ let if isList property then "${propertyName}=(${lib.concatMapStrings (elem: "\"${toString elem}\" ") (properties."${propertyName}")})\n" else "${propertyName}=\"${toString property}\"\n" ) (builtins.attrNames properties); - + properties = pkgs.stdenv.mkDerivation { name = "dysnomia-properties"; buildCommand = '' @@ -22,13 +22,13 @@ let EOF ''; }; - + containersDir = pkgs.stdenv.mkDerivation { name = "dysnomia-containers"; buildCommand = '' mkdir -p $out cd $out - + ${concatMapStrings (containerName: let containerProperties = cfg.containers."${containerName}"; @@ -42,11 +42,11 @@ let ) (builtins.attrNames cfg.containers)} ''; }; - + linkMutableComponents = {containerName}: '' mkdir ${containerName} - + ${concatMapStrings (componentName: let component = cfg.components."${containerName}"."${componentName}"; @@ -54,13 +54,13 @@ let "ln -s ${component} ${containerName}/${componentName}\n" ) (builtins.attrNames (cfg.components."${containerName}" or {}))} ''; - + componentsDir = pkgs.stdenv.mkDerivation { name = "dysnomia-components"; buildCommand = '' mkdir -p $out cd $out - + ${concatMapStrings (containerName: let components = cfg.components."${containerName}"; @@ -72,59 +72,59 @@ let in { options = { - dysnomia = { - + services.dysnomia = { + enable = mkOption { type = types.bool; default = false; description = "Whether to enable Dysnomia"; }; - + enableAuthentication = mkOption { type = types.bool; default = false; description = "Whether to publish privacy-sensitive authentication credentials"; }; - + package = mkOption { type = types.path; description = "The Dysnomia package"; }; - + properties = mkOption { description = "An attribute set in which each attribute represents a machine property. Optionally, these values can be shell substitutions."; default = {}; }; - + containers = mkOption { description = "An attribute set in which each key represents a container and each value an attribute set providing its configuration properties"; default = {}; }; - + components = mkOption { description = "An atttribute set in which each key represents a container and each value an attribute set in which each key represents a component and each value a derivation constructing its initial state"; default = {}; }; - + extraContainerProperties = mkOption { description = "An attribute set providing additional container settings in addition to the default properties"; default = {}; }; - + extraContainerPaths = mkOption { description = "A list of paths containing additional container configurations that are added to the search folders"; default = []; }; - + extraModulePaths = mkOption { description = "A list of paths containing additional modules that are added to the search folders"; default = []; }; }; }; - + config = mkIf cfg.enable { - + environment.etc = { "dysnomia/containers" = { source = containersDir; @@ -136,16 +136,16 @@ in source = properties; }; }; - + environment.variables = { DYSNOMIA_STATEDIR = "/var/state/dysnomia-nixos"; DYSNOMIA_CONTAINERS_PATH = "${lib.concatMapStrings (containerPath: "${containerPath}:") cfg.extraContainerPaths}/etc/dysnomia/containers"; DYSNOMIA_MODULES_PATH = "${lib.concatMapStrings (modulePath: "${modulePath}:") cfg.extraModulePaths}/etc/dysnomia/modules"; }; - + environment.systemPackages = [ cfg.package ]; - - dysnomia.package = pkgs.dysnomia.override (origArgs: { + + services.dysnomia.package = pkgs.dysnomia.override (origArgs: { enableApacheWebApplication = config.services.httpd.enable; enableAxis2WebService = config.services.tomcat.axis2.enable; enableEjabberdDump = config.services.ejabberd.enable; @@ -155,8 +155,8 @@ in enableTomcatWebApplication = config.services.tomcat.enable; enableMongoDatabase = config.services.mongodb.enable; }); - - dysnomia.properties = { + + services.dysnomia.properties = { hostname = config.networking.hostName; system = if config.nixpkgs.system == "" then builtins.currentSystem else config.nixpkgs.system; @@ -173,8 +173,8 @@ in ''; }}"); }; - - dysnomia.containers = lib.recursiveUpdate ({ + + services.dysnomia.containers = lib.recursiveUpdate ({ process = {}; wrapper = {}; } diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix index 458d0087dbda7..63e976ae566ca 100644 --- a/nixos/modules/services/misc/gitea.nix +++ b/nixos/modules/services/misc/gitea.nix @@ -40,6 +40,10 @@ let SECRET_KEY = #secretkey# INSTALL_LOCK = true + [log] + ROOT_PATH = ${cfg.log.rootPath} + LEVEL = ${cfg.log.level} + ${cfg.extraConfig} ''; in @@ -65,6 +69,19 @@ in description = "gitea data directory."; }; + log = { + rootPath = mkOption { + default = "${cfg.stateDir}/log"; + type = types.str; + description = "Root path for log files."; + }; + level = mkOption { + default = "Trace"; + type = types.enum [ "Trace" "Debug" "Info" "Warn" "Error" "Critical" ]; + description = "General log level."; + }; + }; + user = mkOption { type = types.str; default = "gitea"; @@ -287,6 +304,7 @@ in description = "Gitea Service"; home = cfg.stateDir; createHome = true; + useDefaultShell = true; }; }; diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 9ed5875a0191d..20d7ec90dcc95 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -143,6 +143,7 @@ let 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_LOG_PATH = "${cfg.statePath}/log"; GITLAB_SHELL_PATH = "${cfg.packages.gitlab-shell}"; GITLAB_SHELL_CONFIG_PATH = "${cfg.statePath}/shell/config.yml"; @@ -500,7 +501,7 @@ in { Type = "simple"; User = cfg.user; Group = cfg.group; - TimeoutSec = "300"; + TimeoutSec = "infinity"; Restart = "on-failure"; WorkingDirectory = gitlabEnv.HOME; ExecStart = "${cfg.packages.gitaly}/bin/gitaly ${gitalyToml}"; @@ -566,6 +567,7 @@ in { mkdir -p ${cfg.statePath}/tmp/pids mkdir -p ${cfg.statePath}/tmp/sockets mkdir -p ${cfg.statePath}/shell + mkdir -p ${cfg.statePath}/db rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks mkdir -p ${cfg.statePath}/config @@ -580,6 +582,7 @@ in { ln -sf ${cfg.statePath}/log /run/gitlab/log ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp + ln -sf $GITLAB_SHELL_CONFIG_PATH /run/gitlab/shell-config.yml chown -R ${cfg.user}:${cfg.group} /run/gitlab # Prepare home directory @@ -587,6 +590,7 @@ in { touch ${gitlabEnv.HOME}/.ssh/authorized_keys chown -R ${cfg.user}:${cfg.group} ${gitlabEnv.HOME}/ + cp -rf ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config ${optionalString cfg.smtp.enable '' ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb diff --git a/nixos/modules/services/misc/gitweb.nix b/nixos/modules/services/misc/gitweb.nix new file mode 100644 index 0000000000000..b0e34a690ca50 --- /dev/null +++ b/nixos/modules/services/misc/gitweb.nix @@ -0,0 +1,51 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.gitweb; + +in +{ + + options.services.gitweb = { + + projectroot = mkOption { + default = "/srv/git"; + type = types.path; + description = '' + Path to git projects (bare repositories) that should be served by + gitweb. Must not end with a slash. + ''; + }; + + extraConfig = mkOption { + default = ""; + type = types.lines; + description = '' + Verbatim configuration text appended to the generated gitweb.conf file. + ''; + example = '' + $feature{'highlight'}{'default'} = [1]; + $feature{'ctags'}{'default'} = [1]; + $feature{'avatar'}{'default'} = ['gravatar']; + ''; + }; + + gitwebConfigFile = mkOption { + default = pkgs.writeText "gitweb.conf" '' + # path to git projects (<project>.git) + $projectroot = "${cfg.projectroot}"; + $highlight_bin = "${pkgs.highlight}/bin/highlight"; + ${cfg.extraConfig} + ''; + type = types.path; + readOnly = true; + internal = true; + }; + + }; + + meta.maintainers = with maintainers; [ gnidorah ]; + +} diff --git a/nixos/modules/services/misc/gogs.nix b/nixos/modules/services/misc/gogs.nix index f6d326e43d948..ba744d37e71c5 100644 --- a/nixos/modules/services/misc/gogs.nix +++ b/nixos/modules/services/misc/gogs.nix @@ -35,6 +35,9 @@ let SECRET_KEY = #secretkey# INSTALL_LOCK = true + [log] + ROOT_PATH = ${cfg.stateDir}/log + ${cfg.extraConfig} ''; in diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index cc60a143fa6c3..ac37c11106efc 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -104,7 +104,6 @@ in { config = mkIf cfg.enable { systemd.services.home-assistant = { description = "Home Assistant"; - wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; preStart = lib.optionalString (cfg.config != null) '' rm -f ${cfg.configDir}/configuration.yaml @@ -121,6 +120,16 @@ in { ReadWritePaths = "${cfg.configDir}"; PrivateTmp = true; }; + path = [ + "/run/wrappers" # needed for ping + ]; + }; + + systemd.targets.home-assistant = rec { + description = "Home Assistant"; + wantedBy = [ "multi-user.target" ]; + wants = [ "home-assistant.service" ]; + after = wants; }; users.extraUsers.hass = { diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index 484079ed62dfc..f2d34560a718d 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -439,19 +439,18 @@ in services.xserver.displayManager.hiddenUsers = map ({ name, ... }: name) nixbldUsers; + # FIXME: use systemd-tmpfiles to create Nix directories. system.activationScripts.nix = stringAfter [ "etc" "users" ] '' # Nix initialisation. - mkdir -m 0755 -p \ + install -m 0755 -d \ /nix/var/nix/gcroots \ /nix/var/nix/temproots \ - /nix/var/nix/manifests \ /nix/var/nix/userpool \ /nix/var/nix/profiles \ /nix/var/nix/db \ - /nix/var/log/nix/drvs \ - /nix/var/nix/channel-cache - mkdir -m 1777 -p \ + /nix/var/log/nix/drvs + install -m 1777 -d \ /nix/var/nix/gcroots/per-user \ /nix/var/nix/profiles/per-user \ /nix/var/nix/gcroots/tmp diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index b8253956d54f3..abf506ea7c673 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -112,10 +112,10 @@ in system.build.manual = manual; - environment.systemPackages = - [ manual.manual helpScript ] - ++ optionals config.services.xserver.enable [desktopItem pkgs.nixos-icons] - ++ optional config.programs.man.enable manual.manpages; + environment.systemPackages = [] + ++ optionals config.services.xserver.enable [ desktopItem pkgs.nixos-icons ] + ++ optional config.documentation.man.enable manual.manpages + ++ optionals config.documentation.doc.enable [ manual.manual helpScript ]; boot.extraTTYs = mkIf cfg.showManual ["tty${toString cfg.ttyNumber}"]; diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix index ae3f84333d2d7..c757093e5c1b2 100644 --- a/nixos/modules/services/misc/parsoid.nix +++ b/nixos/modules/services/misc/parsoid.nix @@ -6,6 +6,8 @@ let cfg = config.services.parsoid; + parsoid = pkgs.nodePackages."parsoid-git://github.com/abbradar/parsoid#stable"; + confTree = { worker_heartbeat_timeout = 300000; logging = { level = "info"; }; @@ -93,7 +95,7 @@ in after = [ "network.target" ]; serviceConfig = { User = "nobody"; - ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/bin/server.js -c ${confFile} -n ${toString cfg.workers}"; + ExecStart = "${parsoid}/lib/node_modules/parsoid/bin/server.js -c ${confFile} -n ${toString cfg.workers}"; }; }; diff --git a/nixos/modules/services/misc/serviio.nix b/nixos/modules/services/misc/serviio.nix new file mode 100644 index 0000000000000..a6612e9c6adb3 --- /dev/null +++ b/nixos/modules/services/misc/serviio.nix @@ -0,0 +1,92 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.serviio; + + serviioStart = pkgs.writeScript "serviio.sh" '' + #!${pkgs.bash}/bin/sh + + SERVIIO_HOME=${pkgs.serviio} + + # Setup the classpath + SERVIIO_CLASS_PATH="$SERVIIO_HOME/lib/*:$SERVIIO_HOME/config" + + # Setup Serviio specific properties + JAVA_OPTS="-Djava.net.preferIPv4Stack=true -Djava.awt.headless=true -Dorg.restlet.engine.loggerFacadeClass=org.restlet.ext.slf4j.Slf4jLoggerFacade + -Dderby.system.home=${cfg.dataDir}/library -Dserviio.home=${cfg.dataDir} -Dffmpeg.location=${pkgs.ffmpeg}/bin/ffmpeg -Ddcraw.location=${pkgs.dcraw}/bin/dcraw" + + # Execute the JVM in the foreground + exec ${pkgs.jre}/bin/java -Xmx512M -Xms20M -XX:+UseG1GC -XX:GCTimeRatio=1 -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 $JAVA_OPTS -classpath "$SERVIIO_CLASS_PATH" org.serviio.MediaServer "$@" + ''; + +in { + + ###### interface + options = { + services.serviio = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the Serviio Media Server. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/serviio"; + description = '' + The directory where serviio stores its state, data, etc. + ''; + }; + + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.serviio = { + description = "Serviio Media Server"; + after = [ "local-fs.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.serviio ]; + serviceConfig = { + User = "serviio"; + Group = "serviio"; + ExecStart = "${serviioStart}"; + ExecStop = "${serviioStart} -stop"; + }; + }; + + users.extraUsers = [ + { + name = "serviio"; + group = "serviio"; + home = cfg.dataDir; + description = "Serviio Media Server User"; + createHome = true; + isSystemUser = true; + } + ]; + + users.extraGroups = [ + { name = "serviio";} + ]; + + networking.firewall = { + allowedTCPPorts = [ + 8895 # serve UPnP responses + 23423 # console + 23424 # mediabrowser + ]; + allowedUDPPorts = [ + 1900 # UPnP service discovey + ]; + }; + }; +} diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 921be23f3681d..a5b6dbab1577b 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -25,6 +25,7 @@ let DATABASE_USER = cfg.database.user; DATABASE_PASSWORD = cfg.database.password; DATABASE_PATH = cfg.database.path; + DATABASE_CONN_MAX_LIFETIME = cfg.database.connMaxLifetime; SECURITY_ADMIN_USER = cfg.security.adminUser; SECURITY_ADMIN_PASSWORD = cfg.security.adminPassword; @@ -143,6 +144,15 @@ in { default = "${cfg.dataDir}/data/grafana.db"; type = types.path; }; + + connMaxLifetime = mkOption { + description = '' + Sets the maximum amount of time (in seconds) a connection may be reused. + For MySQL this setting should be shorter than the `wait_timeout' variable. + ''; + default = 14400; + type = types.int; + }; }; security = { @@ -241,7 +251,9 @@ in { description = "Grafana Service Daemon"; wantedBy = ["multi-user.target"]; after = ["networking.target"]; - environment = mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions; + environment = { + QT_QPA_PLATFORM = "offscreen"; + } // mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions; serviceConfig = { ExecStart = "${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir}"; WorkingDirectory = cfg.dataDir; diff --git a/nixos/modules/services/monitoring/monit.nix b/nixos/modules/services/monitoring/monit.nix index 71f50cc0f19df..d48e5c550abbf 100644 --- a/nixos/modules/services/monitoring/monit.nix +++ b/nixos/modules/services/monitoring/monit.nix @@ -26,16 +26,10 @@ in environment.systemPackages = [ pkgs.monit ]; - environment.etc = [ - { - source = pkgs.writeTextFile { - name = "monitrc"; - text = config.services.monit.config; - }; - target = "monitrc"; - mode = "0400"; - } - ]; + environment.etc."monitrc" = { + text = config.services.monit.config; + mode = "0400"; + }; systemd.services.monit = { description = "Pro-active monitoring utility for unix systems"; @@ -48,6 +42,8 @@ in KillMode = "process"; Restart = "always"; }; + restartTriggers = [ config.environment.etc."monitrc".source ]; }; + }; } diff --git a/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix b/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix deleted file mode 100644 index ce2e1cf2d74b6..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix +++ /dev/null @@ -1,68 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.blackboxExporter; -in { - options = { - services.prometheus.blackboxExporter = { - enable = mkEnableOption "prometheus blackbox exporter"; - - configFile = mkOption { - type = types.path; - description = '' - Path to configuration file. - ''; - }; - - port = mkOption { - type = types.int; - default = 9115; - description = '' - Port to listen on. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the blackbox exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-blackbox-exporter = { - description = "Prometheus exporter for blackbox probes"; - unitConfig.Documentation = "https://github.com/prometheus/blackbox_exporter"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - AmbientCapabilities = [ "CAP_NET_RAW" ]; # for ping probes - ExecStart = '' - ${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \ - --web.listen-address :${toString cfg.port} \ - --config.file ${cfg.configFile} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/collectd-exporter.nix b/nixos/modules/services/monitoring/prometheus/collectd-exporter.nix deleted file mode 100644 index f8a5b9576a116..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/collectd-exporter.nix +++ /dev/null @@ -1,128 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.collectdExporter; - - collectSettingsArgs = if (cfg.collectdBinary.enable) then '' - -collectd.listen-address ${optionalString (cfg.collectdBinary.listenAddress != null) cfg.collectdBinary.listenAddress}:${toString cfg.collectdBinary.port} \ - -collectd.security-level ${cfg.collectdBinary.securityLevel} \ - '' else ""; - -in { - options = { - services.prometheus.collectdExporter = { - enable = mkEnableOption "prometheus collectd exporter"; - - port = mkOption { - type = types.int; - default = 9103; - description = '' - Port to listen on. - This is used for scraping as well as the to receive collectd data via the write_http plugin. - ''; - }; - - listenAddress = mkOption { - type = types.nullOr types.str; - default = null; - example = "0.0.0.0"; - description = '' - Address to listen on for web interface, telemetry and collectd JSON data. - ''; - }; - - collectdBinary = { - enable = mkEnableOption "collectd binary protocol receiver"; - - authFile = mkOption { - default = null; - type = types.nullOr types.path; - description = "File mapping user names to pre-shared keys (passwords)."; - }; - - port = mkOption { - type = types.int; - default = 25826; - description = ''Network address on which to accept collectd binary network packets.''; - }; - - listenAddress = mkOption { - type = types.nullOr types.str; - default = null; - example = "0.0.0.0"; - description = '' - Address to listen on for binary network packets. - ''; - }; - - securityLevel = mkOption { - type = types.enum ["None" "Sign" "Encrypt"]; - default = "None"; - description = '' - Minimum required security level for accepted packets. - ''; - }; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the collectd exporter. - ''; - }; - - logFormat = mkOption { - type = types.str; - default = "logger:stderr"; - example = "logger:syslog?appname=bob&local=7 or logger:stdout?json=true"; - description = '' - Set the log target and format. - ''; - }; - - logLevel = mkOption { - type = types.enum ["debug" "info" "warn" "error" "fatal"]; - default = "info"; - description = '' - Only log messages with the given severity or above. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = (optional cfg.openFirewall cfg.port) ++ - (optional (cfg.openFirewall && cfg.collectdBinary.enable) cfg.collectdBinary.port); - - systemd.services.prometheus-collectd-exporter = { - description = "Prometheus exporter for Collectd metrics"; - unitConfig.Documentation = "https://github.com/prometheus/collectd_exporter"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - DynamicUser = true; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecStart = '' - ${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \ - -log.format ${cfg.logFormat} \ - -log.level ${cfg.logLevel} \ - -web.listen-address ${optionalString (cfg.listenAddress != null) cfg.listenAddress}:${toString cfg.port} \ - ${collectSettingsArgs} \ - ${concatStringsSep " " cfg.extraFlags} - ''; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix new file mode 100644 index 0000000000000..8d6ca1e40a19b --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -0,0 +1,172 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.prometheus.exporters; + + # each attribute in `exporterOpts` is expected to have specified: + # - port (types.int): port on which the exporter listens + # - serviceOpts (types.attrs): config that is merged with the + # default definition of the exporter's + # systemd service + # - extraOpts (types.attrs): extra configuration options to + # configure the exporter with, which + # are appended to the default options + # + # 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; }; + 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; }; + unifi = import ./exporters/unifi.nix { inherit config lib pkgs; }; + varnish = import ./exporters/varnish.nix { inherit config lib pkgs; }; + }; + + mkExporterOpts = ({ name, port }: { + enable = mkEnableOption "the prometheus ${name} exporter"; + port = mkOption { + type = types.int; + default = port; + description = '' + Port to listen on. + ''; + }; + listenAddress = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + Address to listen on. + ''; + }; + extraFlags = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra commandline options to pass to the ${name} exporter. + ''; + }; + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open port in firewall for incoming connections. + ''; + }; + firewallFilter = mkOption { + type = types.str; + default = "-p tcp -m tcp --dport ${toString port}"; + example = literalExample '' + "-i eth0 -p tcp -m tcp --dport ${toString port}" + ''; + description = '' + Specify a filter for iptables to use when + <option>services.prometheus.exporters.${name}.openFirewall</option> + is true. It is used as `ip46tables -I INPUT <option>firewallFilter</option> -j ACCEPT`. + ''; + }; + user = mkOption { + type = types.str; + default = "nobody"; + 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. + ''; + }; + group = mkOption { + type = types.str; + default = "nobody"; + 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. + ''; + }; + }); + + mkSubModule = { name, port, extraOpts, serviceOpts }: { + ${name} = mkOption { + type = types.submodule { + options = (mkExporterOpts { + inherit name port; + } // extraOpts); + }; + internal = true; + default = {}; + }; + }; + + mkSubModules = (foldl' (a: b: a//b) {} + (mapAttrsToList (name: opts: mkSubModule { + inherit name; + inherit (opts) port serviceOpts; + extraOpts = opts.extraOpts or {}; + }) exporterOpts) + ); + + mkExporterConf = { name, conf, serviceOpts }: + mkIf conf.enable { + networking.firewall.extraCommands = mkIf conf.openFirewall '' + ip46tables -I INPUT ${conf.firewallFilter} -j ACCEPT + ''; + systemd.services."prometheus-${name}-exporter" = mkMerge ([{ + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Restart = mkDefault "always"; + PrivateTmp = mkDefault true; + WorkingDirectory = mkDefault /tmp; + } // mkIf (!(serviceOpts.serviceConfig.DynamicUser or false)) { + User = conf.user; + Group = conf.group; + }; + } serviceOpts ]); + }; +in +{ + options.services.prometheus.exporters = mkOption { + type = types.submodule { + options = (mkSubModules); + }; + description = "Prometheus exporter configuration"; + default = {}; + example = literalExample '' + { + node = { + enable = true; + enabledCollectors = [ "systemd" ]; + }; + varnish.enable = true; + } + ''; + }; + + config = mkMerge ([{ + 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! + ''; + }]; + }] ++ [(mkIf config.services.minio.enable { + services.prometheus.exporters.minio.minioAddress = mkDefault "http://localhost:9000"; + services.prometheus.exporters.minio.minioAccessKey = mkDefault config.services.minio.accessKey; + services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey; + })] ++ (mapAttrsToList (name: conf: + mkExporterConf { + inherit name; + inherit (conf) serviceOpts; + conf = cfg.${name}; + }) exporterOpts) + ); + + meta.doc = ./exporters.xml; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters.xml b/nixos/modules/services/monitoring/prometheus/exporters.xml new file mode 100644 index 0000000000000..4f0bcb2981067 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters.xml @@ -0,0 +1,135 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-prometheus-exporters"> + +<title>Prometheus exporters</title> + +<para>Prometheus exporters provide metrics for the <link xlink:href="https://prometheus.io">prometheus monitoring system</link>.</para> + +<section><title>Configuration</title> + <para>One of the most common exporters is the <link xlink:href="https://github.com/prometheus/node_exporter">node 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 = { + enable = true; + enabledCollectors = [ + "logind" + "systemd" + ]; + disabledCollectors = [ + "textfile" + ]; + openFirewall = true; + firewallFilter = "-i br0 -p tcp -m tcp --dport 9100"; + }; +</programlisting> +It should now serve all metrics from the collectors +that are explicitly enabled and the ones that are +<link xlink:href="https://github.com/prometheus/node_exporter#enabled-by-default">enabled by default</link>, via http under <literal>/metrics</literal>. In this example the firewall should just +allow incoming connections to the exporter's port on the bridge interface <literal>br0</literal> +(this would have to be configured seperately of course). +For more information about configuration see <literal>man configuration.nix</literal> or +search through the <link xlink:href="https://nixos.org/nixos/options.html#prometheus.exporters">available options</link>. +</para> +</section> +<section><title>Adding a new exporter</title> + <para>To add a new exporter, it has to be packaged first (see <literal>nixpkgs/pkgs/servers/monitoring/prometheus/</literal> for examples), then a module can be added. The postfix exporter is used in this example:</para> +<itemizedlist> + <listitem> + <para> + Some default options for all exporters are provided by + <literal>nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix</literal>: + </para> + </listitem> + <listitem override='none'> + <itemizedlist> + <listitem><para><literal>enable</literal></para></listitem> + <listitem><para><literal>port</literal></para></listitem> + <listitem><para><literal>listenAddress</literal></para></listitem> + <listitem><para><literal>extraFlags</literal></para></listitem> + <listitem><para><literal>openFirewall</literal></para></listitem> + <listitem><para><literal>firewallFilter</literal></para></listitem> + <listitem><para><literal>user</literal></para></listitem> + <listitem><para><literal>group</literal></para></listitem> + </itemizedlist> + </listitem> + <listitem> + <para>As there is already a package available, the module can now be added. + This is accomplished by adding a new file to the + <literal>nixos/modules/services/monitoring/prometheus/exporters/</literal> directory, + which will be called postfix.nix and contains all exporter specific options + and configuration: + <programlisting> + # nixpgs/nixos/modules/services/prometheus/exporters/postfix.nix + { config, lib, pkgs }: + + with lib; + + let + # for convenience we define cfg here + cfg = config.services.prometheus.exporters.postfix; + in + { + port = 9154; # The postfix exporter listens on this port by default + + # `extraOpts` is an attribute set which contains additional options + # (and optional overrides for default options). + # Note that this attribute is optional. + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = '' + Path under which to expose metrics. + ''; + }; + logfilePath = mkOption { + type = types.path; + default = /var/log/postfix_exporter_input.log; + example = /var/log/mail.log; + description = '' + Path where Postfix writes log entries. + This file will be truncated by this exporter! + ''; + }; + showqPath = mkOption { + type = types.path; + default = /var/spool/postfix/public/showq; + example = /var/lib/postfix/queue/public/showq; + description = '' + Path at which Postfix places its showq socket. + ''; + }; + }; + + # `serviceOpts` is an attribute set which contains configuration + # for the exporter's systemd service. One of + # `serviceOpts.script` and `serviceOpts.serviceConfig.ExecStart` + # has to be specified here. This will be merged with the default + # service confiuration. + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; + } + </programlisting> + </para> + </listitem> + <listitem> + <para> + This should already be enough for the postfix exporter. Additionally one could + now add assertions and conditional default values. This can be done in the + 'meta-module' that combines all exporter definitions and generates the submodules: + <literal>nixpkgs/nixos/modules/services/prometheus/exporters.nix</literal> + </para> + </listitem> +</itemizedlist> +</section> +</chapter> diff --git a/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix b/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix new file mode 100644 index 0000000000000..d09d1c4f36631 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.blackbox; +in +{ + port = 9115; + extraOpts = { + configFile = mkOption { + type = types.path; + description = '' + Path to configuration file. + ''; + }; + }; + 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} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix b/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix new file mode 100644 index 0000000000000..0eba3527162d0 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.collectd; +in +{ + port = 9103; + extraOpts = { + collectdBinary = { + enable = mkEnableOption "collectd binary protocol receiver"; + + authFile = mkOption { + default = null; + type = types.nullOr types.path; + description = "File mapping user names to pre-shared keys (passwords)."; + }; + + port = mkOption { + type = types.int; + default = 25826; + description = ''Network address on which to accept collectd binary network packets.''; + }; + + listenAddress = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + Address to listen on for binary network packets. + ''; + }; + + securityLevel = mkOption { + type = types.enum ["None" "Sign" "Encrypt"]; + default = "None"; + description = '' + Minimum required security level for accepted packets. + ''; + }; + }; + + logFormat = mkOption { + type = types.str; + default = "logger:stderr"; + example = "logger:syslog?appname=bob&local=7 or logger:stdout?json=true"; + description = '' + Set the log target and format. + ''; + }; + + logLevel = mkOption { + type = types.enum ["debug" "info" "warn" "error" "fatal"]; + default = "info"; + description = '' + Only log messages with the given severity or above. + ''; + }; + }; + serviceOpts = let + collectSettingsArgs = if (cfg.collectdBinary.enable) then '' + -collectd.listen-address ${cfg.collectdBinary.listenAddress}:${toString cfg.collectdBinary.port} \ + -collectd.security-level ${cfg.collectdBinary.securityLevel} \ + '' else ""; + in { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \ + -log.format ${cfg.logFormat} \ + -log.level ${cfg.logLevel} \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${collectSettingsArgs} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix b/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix new file mode 100644 index 0000000000000..a3f1d9d313232 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/fritzbox.nix @@ -0,0 +1,39 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.fritzbox; +in +{ + port = 9133; + extraOpts = { + gatewayAddress = mkOption { + type = types.str; + default = "fritz.box"; + description = '' + The hostname or IP of the FRITZ!Box. + ''; + }; + + gatewayPort = mkOption { + type = types.int; + default = 49000; + description = '' + The port of the FRITZ!Box UPnP service. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-fritzbox-exporter}/bin/fritzbox_exporter \ + -listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -gateway-address ${cfg.gatewayAddress} \ + -gateway-port ${toString cfg.gatewayPort} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/json.nix b/nixos/modules/services/monitoring/prometheus/exporters/json.nix new file mode 100644 index 0000000000000..a5494e85e016d --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/json.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.json; +in +{ + port = 7979; + extraOpts = { + url = mkOption { + type = types.str; + description = '' + URL to scrape JSON from. + ''; + }; + configFile = mkOption { + type = types.path; + description = '' + Path to configuration file. + ''; + }; + listenAddress = {}; # not used + }; + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \ + --port ${toString cfg.port} \ + ${cfg.url} ${cfg.configFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/minio.nix b/nixos/modules/services/monitoring/prometheus/exporters/minio.nix new file mode 100644 index 0000000000000..3cc4ffdbc8fd9 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/minio.nix @@ -0,0 +1,65 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.minio; +in +{ + port = 9290; + extraOpts = { + minioAddress = mkOption { + type = types.str; + example = "https://10.0.0.1:9000"; + description = '' + The URL of the minio server. + Use HTTPS if Minio accepts secure connections only. + By default this connects to the local minio server if enabled. + ''; + }; + + minioAccessKey = mkOption { + type = types.str; + example = "yourMinioAccessKey"; + description = '' + The value of the Minio access key. + It is required in order to connect to the server. + By default this uses the one from the local minio server if enabled + and <literal>config.services.minio.accessKey</literal>. + ''; + }; + + minioAccessSecret = mkOption { + type = types.str; + description = '' + The value of the Minio access secret. + It is required in order to connect to the server. + By default this uses the one from the local minio server if enabled + and <literal>config.services.minio.secretKey</literal>. + ''; + }; + + minioBucketStats = mkOption { + type = types.bool; + default = false; + description = '' + Collect statistics about the buckets and files in buckets. + It requires more computation, use it carefully in case of large buckets.. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -minio.server ${cfg.minioAddress} \ + -minio.access-key ${cfg.minioAccessKey} \ + -minio.access-secret ${cfg.minioAccessSecret} \ + ${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix b/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix new file mode 100644 index 0000000000000..6a3ba2d0457c5 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.nginx; +in +{ + port = 9113; + extraOpts = { + scrapeUri = mkOption { + type = types.string; + default = "http://localhost/nginx_status"; + description = '' + Address to access the nginx status page. + Can be enabled with services.nginx.statusPage = true. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-nginx-exporter}/bin/nginx_exporter \ + -nginx.scrape_uri '${cfg.scrapeUri}' \ + -telemetry.address ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/node.nix b/nixos/modules/services/monitoring/prometheus/exporters/node.nix new file mode 100644 index 0000000000000..c85f5f9cfb2d7 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/node.nix @@ -0,0 +1,39 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.node; +in +{ + port = 9100; + extraOpts = { + enabledCollectors = mkOption { + type = types.listOf types.string; + default = []; + example = ''[ "systemd" ]''; + description = '' + Collectors to enable. The collectors listed here are enabled in addition to the default ones. + ''; + }; + disabledCollectors = mkOption { + type = types.listOf types.str; + default = []; + example = ''[ "timex" ]''; + description = '' + Collectors to disable which are enabled by default. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-node-exporter}/bin/node_exporter \ + ${concatMapStringsSep " " (x: "--collector." + x) cfg.enabledCollectors} \ + ${concatMapStringsSep " " (x: "--no-collector." + x) cfg.disabledCollectors} \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix b/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix new file mode 100644 index 0000000000000..1e909aa27d833 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.postfix; +in +{ + port = 9154; + extraOpts = { + telemetryPath = mkOption { + type = types.str; + default = "/metrics"; + description = '' + Path under which to expose metrics. + ''; + }; + logfilePath = mkOption { + type = types.path; + default = "/var/log/postfix_exporter_input.log"; + example = "/var/log/mail.log"; + description = '' + Path where Postfix writes log entries. + This file will be truncated by this exporter! + ''; + }; + showqPath = mkOption { + type = types.path; + default = "/var/spool/postfix/public/showq"; + example = "/var/lib/postfix/queue/public/showq"; + description = '' + Path where Postfix places it's showq socket. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --web.telemetry-path ${cfg.telemetryPath} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix new file mode 100644 index 0000000000000..404cd0a1896b8 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix @@ -0,0 +1,71 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.snmp; +in +{ + port = 9116; + extraOpts = { + configurationPath = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to a snmp exporter configuration file. Mutually exclusive with 'configuration' option. + ''; + example = "./snmp.yml"; + }; + + configuration = mkOption { + type = types.nullOr types.attrs; + default = {}; + description = '' + Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option. + ''; + example = '' + { + "default" = { + "version" = 2; + "auth" = { + "community" = "public"; + }; + }; + }; + ''; + }; + + logFormat = mkOption { + type = types.str; + default = "logger:stderr"; + description = '' + Set the log target and format. + ''; + }; + + logLevel = mkOption { + type = types.enum ["debug" "info" "warn" "error" "fatal"]; + default = "info"; + description = '' + Only log messages with the given severity or above. + ''; + }; + }; + serviceOpts = let + configFile = if cfg.configurationPath != null + then cfg.configurationPath + 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} \ + -log.format ${cfg.logFormat} \ + -log.level ${cfg.logLevel} \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix b/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix new file mode 100644 index 0000000000000..011dcbe208e4e --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix @@ -0,0 +1,67 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.unifi; +in +{ + port = 9130; + extraOpts = { + unifiAddress = mkOption { + type = types.str; + example = "https://10.0.0.1:8443"; + description = '' + URL of the UniFi Controller API. + ''; + }; + + unifiInsecure = mkOption { + type = types.bool; + default = false; + description = '' + If enabled skip the verification of the TLS certificate of the UniFi Controller API. + Use with caution. + ''; + }; + + unifiUsername = mkOption { + type = types.str; + example = "ReadOnlyUser"; + description = '' + username for authentication against UniFi Controller API. + ''; + }; + + unifiPassword = mkOption { + type = types.str; + description = '' + Password for authentication against UniFi Controller API. + ''; + }; + + unifiTimeout = mkOption { + type = types.str; + default = "5s"; + example = "2m"; + description = '' + Timeout including unit for UniFi Controller API requests. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \ + -telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \ + -unifi.addr ${cfg.unifiAddress} \ + -unifi.username ${cfg.unifiUsername} \ + -unifi.password ${cfg.unifiPassword} \ + -unifi.timeout ${cfg.unifiTimeout} \ + ${optionalString cfg.unifiInsecure "-unifi.insecure" } \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix b/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix new file mode 100644 index 0000000000000..b439a83e7aa2f --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix @@ -0,0 +1,21 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.varnish; +in +{ + port = 9131; + serviceOpts = { + path = [ pkgs.varnish ]; + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/fritzbox-exporter.nix b/nixos/modules/services/monitoring/prometheus/fritzbox-exporter.nix deleted file mode 100644 index 6da39b6519cb2..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/fritzbox-exporter.nix +++ /dev/null @@ -1,76 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.fritzboxExporter; -in { - options = { - services.prometheus.fritzboxExporter = { - enable = mkEnableOption "prometheus fritzbox exporter"; - - port = mkOption { - type = types.int; - default = 9133; - description = '' - Port to listen on. - ''; - }; - - gatewayAddress = mkOption { - type = types.str; - default = "fritz.box"; - description = '' - The hostname or IP of the FRITZ!Box. - ''; - }; - - gatewayPort = mkOption { - type = types.int; - default = 49000; - description = '' - The port of the FRITZ!Box UPnP service. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the fritzbox exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-fritzbox-exporter = { - description = "Prometheus exporter for FRITZ!Box via UPnP"; - unitConfig.Documentation = "https://github.com/ndecker/fritzbox_exporter"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecStart = '' - ${pkgs.prometheus-fritzbox-exporter}/bin/fritzbox_exporter \ - -listen-address :${toString cfg.port} \ - -gateway-address ${cfg.gatewayAddress} \ - -gateway-port ${toString cfg.gatewayPort} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/json-exporter.nix b/nixos/modules/services/monitoring/prometheus/json-exporter.nix deleted file mode 100644 index 6bc56df9834b0..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/json-exporter.nix +++ /dev/null @@ -1,74 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.jsonExporter; -in { - options = { - services.prometheus.jsonExporter = { - enable = mkEnableOption "prometheus JSON exporter"; - - url = mkOption { - type = types.str; - description = '' - URL to scrape JSON from. - ''; - }; - - configFile = mkOption { - type = types.path; - description = '' - Path to configuration file. - ''; - }; - - port = mkOption { - type = types.int; - default = 7979; - description = '' - Port to listen on. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the JSON exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-json-exporter = { - description = "Prometheus exporter for JSON over HTTP"; - unitConfig.Documentation = "https://github.com/kawamuray/prometheus-json-exporter"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecStart = '' - ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \ - --port ${toString cfg.port} \ - ${cfg.url} ${cfg.configFile} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/minio-exporter.nix b/nixos/modules/services/monitoring/prometheus/minio-exporter.nix deleted file mode 100644 index 4314671523cf1..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/minio-exporter.nix +++ /dev/null @@ -1,117 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.minioExporter; -in { - options = { - services.prometheus.minioExporter = { - enable = mkEnableOption "prometheus minio exporter"; - - port = mkOption { - type = types.int; - default = 9290; - description = '' - Port to listen on. - ''; - }; - - listenAddress = mkOption { - type = types.nullOr types.str; - default = null; - example = "0.0.0.0"; - description = '' - Address to listen on for web interface and telemetry. - ''; - }; - - minioAddress = mkOption { - type = types.str; - example = "https://10.0.0.1:9000"; - default = if config.services.minio.enable then "http://localhost:9000" else null; - description = '' - The URL of the minio server. - Use HTTPS if Minio accepts secure connections only. - By default this connects to the local minio server if enabled. - ''; - }; - - minioAccessKey = mkOption ({ - type = types.str; - example = "BKIKJAA5BMMU2RHO6IBB"; - description = '' - The value of the Minio access key. - It is required in order to connect to the server. - By default this uses the one from the local minio server if enabled - and <literal>config.services.minio.accessKey</literal>. - ''; - } // optionalAttrs (config.services.minio.enable && config.services.minio.accessKey != "") { - default = config.services.minio.accessKey; - }); - - minioAccessSecret = mkOption ({ - type = types.str; - description = '' - The calue of the Minio access secret. - It is required in order to connect to the server. - By default this uses the one from the local minio server if enabled - and <literal>config.services.minio.secretKey</literal>. - ''; - } // optionalAttrs (config.services.minio.enable && config.services.minio.secretKey != "") { - default = config.services.minio.secretKey; - }); - - minioBucketStats = mkOption { - type = types.bool; - default = false; - description = '' - Collect statistics about the buckets and files in buckets. - It requires more computation, use it carefully in case of large buckets.. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the minio exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-minio-exporter = { - description = "Prometheus exporter for Minio server metrics"; - unitConfig.Documentation = "https://github.com/joe-pll/minio-exporter"; - wantedBy = [ "multi-user.target" ]; - after = optional config.services.minio.enable "minio.service"; - serviceConfig = { - DynamicUser = true; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecStart = '' - ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \ - -web.listen-address ${optionalString (cfg.listenAddress != null) cfg.listenAddress}:${toString cfg.port} \ - -minio.server ${cfg.minioAddress} \ - -minio.access-key ${cfg.minioAccessKey} \ - -minio.access-secret ${cfg.minioAccessSecret} \ - ${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix b/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix deleted file mode 100644 index 1ccafee3b18b9..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.nginxExporter; -in { - options = { - services.prometheus.nginxExporter = { - enable = mkEnableOption "prometheus nginx exporter"; - - port = mkOption { - type = types.int; - default = 9113; - description = '' - Port to listen on. - ''; - }; - - listenAddress = mkOption { - type = types.string; - default = "0.0.0.0"; - description = '' - Address to listen on. - ''; - }; - - scrapeUri = mkOption { - type = types.string; - default = "http://localhost/nginx_status"; - description = '' - Address to access the nginx status page. - Can be enabled with services.nginx.statusPage = true. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the nginx exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-nginx-exporter = { - after = [ "network.target" "nginx.service" ]; - description = "Prometheus exporter for nginx metrics"; - unitConfig.Documentation = "https://github.com/discordianfish/nginx_exporter"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecStart = '' - ${pkgs.prometheus-nginx-exporter}/bin/nginx_exporter \ - -nginx.scrape_uri '${cfg.scrapeUri}' \ - -telemetry.address ${cfg.listenAddress}:${toString cfg.port} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/node-exporter.nix b/nixos/modules/services/monitoring/prometheus/node-exporter.nix deleted file mode 100644 index bad4389ce7993..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/node-exporter.nix +++ /dev/null @@ -1,87 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.nodeExporter; -in { - options = { - services.prometheus.nodeExporter = { - enable = mkEnableOption "prometheus node exporter"; - - port = mkOption { - type = types.int; - default = 9100; - description = '' - Port to listen on. - ''; - }; - - listenAddress = mkOption { - type = types.string; - default = "0.0.0.0"; - description = '' - Address to listen on. - ''; - }; - - enabledCollectors = mkOption { - type = types.listOf types.string; - default = []; - example = ''[ "systemd" ]''; - description = '' - Collectors to enable. The collectors listed here are enabled in addition to the default ones. - ''; - }; - - disabledCollectors = mkOption { - type = types.listOf types.str; - default = []; - example = ''[ "timex" ]''; - description = '' - Collectors to disable which are enabled by default. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the node exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-node-exporter = { - description = "Prometheus exporter for machine metrics"; - unitConfig.Documentation = "https://github.com/prometheus/node_exporter"; - wantedBy = [ "multi-user.target" ]; - script = '' - exec ${pkgs.prometheus-node-exporter}/bin/node_exporter \ - ${concatMapStringsSep " " (x: "--collector." + x) cfg.enabledCollectors} \ - ${concatMapStringsSep " " (x: "--no-collector." + x) cfg.disabledCollectors} \ - --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix b/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix deleted file mode 100644 index fe33f8c1f04dd..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix +++ /dev/null @@ -1,127 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.snmpExporter; - mkConfigFile = pkgs.writeText "snmp.yml" (if cfg.configurationPath == null then builtins.toJSON cfg.configuration else builtins.readFile cfg.configurationPath); -in { - options = { - services.prometheus.snmpExporter = { - enable = mkEnableOption "Prometheus snmp exporter"; - - user = mkOption { - type = types.str; - default = "nobody"; - description = '' - User name under which snmp exporter shall be run. - ''; - }; - - group = mkOption { - type = types.str; - default = "nogroup"; - description = '' - Group under which snmp exporter shall be run. - ''; - }; - - port = mkOption { - type = types.int; - default = 9116; - description = '' - Port to listen on. - ''; - }; - - listenAddress = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Address to listen on for web interface and telemetry. - ''; - }; - - configurationPath = mkOption { - type = types.nullOr types.path; - default = null; - description = '' - Path to a snmp exporter configuration file. Mutually exclusive with 'configuration' option. - ''; - example = "./snmp.yml"; - }; - - configuration = mkOption { - type = types.nullOr types.attrs; - default = {}; - description = '' - Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option. - ''; - example = '' - { - "default" = { - "version" = 2; - "auth" = { - "community" = "public"; - }; - }; - }; - ''; - }; - - logFormat = mkOption { - type = types.str; - default = "logger:stderr"; - description = '' - Set the log target and format. - ''; - }; - - logLevel = mkOption { - type = types.enum ["debug" "info" "warn" "error" "fatal"]; - default = "info"; - description = '' - Only log messages with the given severity or above. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - assertions = singleton - { - assertion = (cfg.configurationPath == null) != (cfg.configuration == null); - message = "Please ensure you have either 'configuration' or 'configurationPath' set!"; - }; - - systemd.services.prometheus-snmp-exporter = { - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - script = '' - ${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \ - -config.file ${mkConfigFile} \ - -log.format ${cfg.logFormat} \ - -log.level ${cfg.logLevel} \ - -web.listen-address ${optionalString (cfg.listenAddress != null) cfg.listenAddress}:${toString cfg.port} - ''; - - serviceConfig = { - User = cfg.user; - Group = cfg.group; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = "/tmp"; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/unifi-exporter.nix b/nixos/modules/services/monitoring/prometheus/unifi-exporter.nix deleted file mode 100644 index 0a56d6ae95a59..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/unifi-exporter.nix +++ /dev/null @@ -1,105 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.services.prometheus.unifiExporter; -in { - options = { - services.prometheus.unifiExporter = { - enable = mkEnableOption "prometheus unifi exporter"; - - port = mkOption { - type = types.int; - default = 9130; - description = '' - Port to listen on. - ''; - }; - - unifiAddress = mkOption { - type = types.str; - example = "https://10.0.0.1:8443"; - description = '' - URL of the UniFi Controller API. - ''; - }; - - unifiInsecure = mkOption { - type = types.bool; - default = false; - description = '' - If enabled skip the verification of the TLS certificate of the UniFi Controller API. - Use with caution. - ''; - }; - - unifiUsername = mkOption { - type = types.str; - example = "ReadOnlyUser"; - description = '' - username for authentication against UniFi Controller API. - ''; - }; - - unifiPassword = mkOption { - type = types.str; - description = '' - Password for authentication against UniFi Controller API. - ''; - }; - - unifiTimeout = mkOption { - type = types.str; - default = "5s"; - example = "2m"; - description = '' - Timeout including unit for UniFi Controller API requests. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the unifi exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-unifi-exporter = { - description = "Prometheus exporter for UniFi Controller metrics"; - unitConfig.Documentation = "https://github.com/mdlayher/unifi_exporter"; - wantedBy = [ "multi-user.target" ]; - after = optional config.services.unifi.enable "unifi.service"; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecStart = '' - ${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \ - -telemetry.addr :${toString cfg.port} \ - -unifi.addr ${cfg.unifiAddress} \ - -unifi.username ${cfg.unifiUsername} \ - -unifi.password ${cfg.unifiPassword} \ - -unifi.timeout ${cfg.unifiTimeout} \ - ${optionalString cfg.unifiInsecure "-unifi.insecure" } \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - }; - }; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix b/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix deleted file mode 100644 index 143ebb62aeac5..0000000000000 --- a/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix +++ /dev/null @@ -1,61 +0,0 @@ -{ config, pkgs, lib, ... }: - -# Shamelessly cribbed from nginx-exporter.nix. ~ C. -with lib; - -let - cfg = config.services.prometheus.varnishExporter; -in { - options = { - services.prometheus.varnishExporter = { - enable = mkEnableOption "prometheus Varnish exporter"; - - port = mkOption { - type = types.int; - default = 9131; - description = '' - Port to listen on. - ''; - }; - - extraFlags = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra commandline options when launching the Varnish exporter. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Open port in firewall for incoming connections. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port; - - systemd.services.prometheus-varnish-exporter = { - description = "Prometheus exporter for Varnish metrics"; - unitConfig.Documentation = "https://github.com/jonnenauha/prometheus_varnish_exporter"; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.varnish ]; - script = '' - exec ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \ - -web.listen-address :${toString cfg.port} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - serviceConfig = { - User = "nobody"; - Restart = "always"; - PrivateTmp = true; - WorkingDirectory = /tmp; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - }; - }; - }; -} diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix index 2eac6dfec5b7b..fd7e317eee955 100644 --- a/nixos/modules/services/networking/dhcpd.nix +++ b/nixos/modules/services/networking/dhcpd.nix @@ -36,6 +36,7 @@ let preStart = '' mkdir -m 755 -p ${cfg.stateDir} + chown dhcpd:nogroup ${cfg.stateDir} touch ${cfg.stateDir}/dhcpd.leases ''; diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index f83fb7a6d5dcf..10e96eb403623 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -135,8 +135,7 @@ in { default = { inherit networkmanager modemmanager wpa_supplicant networkmanager-openvpn networkmanager-vpnc networkmanager-openconnect networkmanager-fortisslvpn - networkmanager-pptp networkmanager-l2tp - networkmanager-iodine; }; + networkmanager-l2tp networkmanager-iodine; }; internal = true; }; @@ -267,8 +266,6 @@ in { message = "You can not use networking.networkmanager with networking.wireless"; }]; - boot.kernelModules = [ "ppp_mppe" ]; # Needed for most (all?) PPTP VPN connections. - environment.etc = with cfg.basePackages; [ { source = configFile; target = "NetworkManager/NetworkManager.conf"; @@ -285,9 +282,6 @@ in { { source = "${networkmanager-fortisslvpn}/etc/NetworkManager/VPN/nm-fortisslvpn-service.name"; target = "NetworkManager/VPN/nm-fortisslvpn-service.name"; } - { source = "${networkmanager-pptp}/etc/NetworkManager/VPN/nm-pptp-service.name"; - target = "NetworkManager/VPN/nm-pptp-service.name"; - } { source = "${networkmanager-l2tp}/etc/NetworkManager/VPN/nm-l2tp-service.name"; target = "NetworkManager/VPN/nm-l2tp-service.name"; } diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix index 9d7e6d6018af4..d57ebb61f6361 100644 --- a/nixos/modules/services/networking/prosody.nix +++ b/nixos/modules/services/networking/prosody.nix @@ -15,6 +15,7 @@ let description = "Path to the key file."; }; + # TODO: rename to certificate to match the prosody config cert = mkOption { type = types.path; description = "Path to the certificate file."; @@ -30,7 +31,7 @@ let }; moduleOpts = { - + # Generally required roster = mkOption { type = types.bool; default = true; @@ -61,12 +62,38 @@ let description = "Service discovery"; }; - legacyauth = mkOption { + # Not essential, but recommended + carbons = mkOption { type = types.bool; default = true; - description = "Legacy authentication. Only used by some old clients and bots"; + description = "Keep multiple clients in sync"; + }; + + pep = mkOption { + type = types.bool; + default = true; + description = "Enables users to publish their mood, activity, playing music and more"; + }; + + private = mkOption { + type = types.bool; + default = true; + description = "Private XML storage (for room bookmarks, etc.)"; + }; + + blocklist = mkOption { + type = types.bool; + default = true; + description = "Allow users to block communications with other users"; }; + vcard = mkOption { + type = types.bool; + default = true; + description = "Allow users to set vCards"; + }; + + # Nice to have version = mkOption { type = types.bool; default = true; @@ -91,36 +118,112 @@ let description = "Replies to XMPP pings with pongs"; }; - console = mkOption { + register = mkOption { + type = types.bool; + default = true; + description = "Allow users to register on this server using a client and change passwords"; + }; + + mam = mkOption { type = types.bool; default = false; - description = "telnet to port 5582"; + description = "Store messages in an archive and allow users to access it"; }; + # Admin interfaces + admin_adhoc = mkOption { + type = types.bool; + default = true; + description = "Allows administration via an XMPP client that supports ad-hoc commands"; + }; + + admin_telnet = mkOption { + type = types.bool; + default = false; + description = "Opens telnet console interface on localhost port 5582"; + }; + + # HTTP modules bosh = mkOption { type = types.bool; default = false; description = "Enable BOSH clients, aka 'Jabber over HTTP'"; }; - httpserver = mkOption { + websocket = mkOption { + type = types.bool; + default = false; + description = "Enable WebSocket support"; + }; + + http_files = mkOption { type = types.bool; default = false; description = "Serve static files from a directory over HTTP"; }; - websocket = mkOption { + # Other specific functionality + limits = mkOption { type = types.bool; default = false; - description = "Enable WebSocket support"; + description = "Enable bandwidth limiting for XMPP connections"; + }; + + groups = mkOption { + type = types.bool; + default = false; + description = "Shared roster support"; + }; + + server_contact_info = mkOption { + type = types.bool; + default = false; + description = "Publish contact information for this service"; + }; + + announce = mkOption { + type = types.bool; + default = false; + description = "Send announcement to all online users"; + }; + + welcome = mkOption { + type = types.bool; + default = false; + description = "Welcome users who register accounts"; + }; + + watchregistrations = mkOption { + type = types.bool; + default = false; + description = "Alert admins of registrations"; + }; + + motd = mkOption { + type = types.bool; + default = false; + description = "Send a message to users when they log in"; + }; + + legacyauth = mkOption { + type = types.bool; + default = false; + description = "Legacy authentication. Only used by some old clients and bots"; + }; + + proxy65 = mkOption { + type = types.bool; + default = false; + description = "Enables a file transfer proxy service which clients behind NAT can use"; }; }; toLua = x: if builtins.isString x then ''"${x}"'' - else if builtins.isBool x then toString x + else if builtins.isBool x then (if x == true then "true" else "false") else if builtins.isInt x then toString x + else if builtins.isList x then ''{ ${lib.concatStringsSep ", " (map (n: toLua n) x) } }'' else throw "Invalid Lua value"; createSSLOptsStr = o: '' @@ -198,6 +301,59 @@ in description = "Allow account creation"; }; + c2sRequireEncryption = mkOption { + type = types.bool; + default = true; + description = '' + Force clients to use encrypted connections? This option will + prevent clients from authenticating unless they are using encryption. + ''; + }; + + s2sRequireEncryption = mkOption { + type = types.bool; + default = true; + description = '' + Force servers to use encrypted connections? This option will + prevent servers from authenticating unless they are using encryption. + Note that this is different from authentication. + ''; + }; + + s2sSecureAuth = mkOption { + type = types.bool; + default = false; + description = '' + Force certificate authentication for server-to-server connections? + This provides ideal security, but requires servers you communicate + with to support encryption AND present valid, trusted certificates. + For more information see https://prosody.im/doc/s2s#security + ''; + }; + + s2sInsecureDomains = mkOption { + type = types.listOf types.str; + default = []; + example = [ "insecure.example.com" ]; + description = '' + Some servers have invalid or self-signed certificates. You can list + remote domains here that will not be required to authenticate using + certificates. They will be authenticated using DNS instead, even + when s2s_secure_auth is enabled. + ''; + }; + + s2sSecureDomains = mkOption { + type = types.listOf types.str; + default = []; + example = [ "jabber.org" ]; + description = '' + Even if you leave s2s_secure_auth disabled, you can still require valid + certificates for some domains by specifying a list here. + ''; + }; + + modules = moduleOpts; extraModules = mkOption { @@ -206,6 +362,12 @@ in description = "Enable custom modules"; }; + extraPluginPaths = mkOption { + type = types.listOf types.path; + default = []; + description = "Addtional path in which to look find plugins/modules"; + }; + virtualHosts = mkOption { description = "Define the virtual hosts"; @@ -255,37 +417,47 @@ in config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.prosody ]; + environment.systemPackages = [ cfg.package ]; environment.etc."prosody/prosody.cfg.lua".text = '' pidfile = "/var/lib/prosody/prosody.pid" - log = "*syslog" data_path = "/var/lib/prosody" - - allow_registration = ${boolToString cfg.allowRegistration}; - - ${ optionalString cfg.modules.console "console_enabled = true;" } + plugin_paths = { + ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.extraPluginPaths) } + } ${ optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl) } - admins = { ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.admins) } }; + admins = ${toLua cfg.admins} + + -- we already build with libevent, so we can just enable it for a more performant server + use_libevent = true modules_enabled = { ${ lib.concatStringsSep "\n\ \ " (lib.mapAttrsToList - (name: val: optionalString val ''"${name}";'') + (name: val: optionalString val "${toLua name};") cfg.modules) } + ${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.package.communityModules)} + ${ lib.concatStringsSep "\n" (map (x: "${toLua x};") cfg.extraModules)} + }; - ${ optionalString cfg.allowRegistration "\"register\"\;" } + allow_registration = ${toLua cfg.allowRegistration} - ${ lib.concatStringsSep "\n" (map (x: "\"${x}\";") cfg.extraModules)} + c2s_require_encryption = ${toLua cfg.c2sRequireEncryption} + + s2s_require_encryption = ${toLua cfg.s2sRequireEncryption} + + s2s_secure_auth = ${toLua cfg.s2sSecureAuth} + + s2s_insecure_domains = ${toLua cfg.s2sInsecureDomains} + + s2s_secure_domains = ${toLua cfg.s2sSecureDomains} - "posix"; - }; ${ cfg.extraConfig } diff --git a/nixos/modules/services/networking/tcpcrypt.nix b/nixos/modules/services/networking/tcpcrypt.nix index 2f304165eb4bd..ee005e11aa326 100644 --- a/nixos/modules/services/networking/tcpcrypt.nix +++ b/nixos/modules/services/networking/tcpcrypt.nix @@ -44,9 +44,9 @@ in path = [ pkgs.iptables pkgs.tcpcrypt pkgs.procps ]; preStart = '' - mkdir -p /var/run/tcpcryptd - chown tcpcryptd /var/run/tcpcryptd - sysctl -n net.ipv4.tcp_ecn >/run/pre-tcpcrypt-ecn-state + mkdir -p /run/tcpcryptd + chown tcpcryptd /run/tcpcryptd + sysctl -n net.ipv4.tcp_ecn > /run/tcpcryptd/pre-tcpcrypt-ecn-state sysctl -w net.ipv4.tcp_ecn=0 iptables -t raw -N nixos-tcpcrypt @@ -61,8 +61,8 @@ in script = "tcpcryptd -x 0x10"; postStop = '' - if [ -f /run/pre-tcpcrypt-ecn-state ]; then - sysctl -w net.ipv4.tcp_ecn=$(cat /run/pre-tcpcrypt-ecn-state) + if [ -f /run/tcpcryptd/pre-tcpcrypt-ecn-state ]; then + sysctl -w net.ipv4.tcp_ecn=$(cat /run/tcpcryptd/pre-tcpcrypt-ecn-state) fi iptables -t mangle -D POSTROUTING -j nixos-tcpcrypt || true diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix index 545ee327d5964..f069a9883a7f5 100644 --- a/nixos/modules/services/networking/unbound.nix +++ b/nixos/modules/services/networking/unbound.nix @@ -112,7 +112,7 @@ in mkdir -m 0755 -p ${stateDir}/dev/ cp ${confFile} ${stateDir}/unbound.conf ${optionalString cfg.enableRootTrustAnchor '' - ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} + ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!" chown unbound ${stateDir} ${rootTrustAnchorFile} ''} touch ${stateDir}/dev/random diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix index 86e0204ec2f72..cd1617b8e2bac 100644 --- a/nixos/modules/services/networking/zerotierone.nix +++ b/nixos/modules/services/networking/zerotierone.nix @@ -7,6 +7,16 @@ let in { options.services.zerotierone.enable = mkEnableOption "ZeroTierOne"; + + options.services.zerotierone.joinNetworks = mkOption { + default = []; + example = [ "a8a2c3c10c1a68de" ]; + type = types.listOf types.str; + description = '' + List of ZeroTier Network IDs to join on startup + ''; + }; + options.services.zerotierone.package = mkOption { default = pkgs.zerotierone; defaultText = "pkgs.zerotierone"; @@ -22,12 +32,13 @@ in path = [ cfg.package ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = - '' - mkdir -p /var/lib/zerotier-one + preStart = '' + mkdir -p /var/lib/zerotier-one/networks.d chmod 700 /var/lib/zerotier-one chown -R root:root /var/lib/zerotier-one - ''; + '' + (concatMapStrings (netId: '' + touch "/var/lib/zerotier-one/networks.d/${netId}.conf" + '') cfg.joinNetworks); serviceConfig = { ExecStart = "${cfg.package}/bin/zerotier-one"; Restart = "always"; @@ -38,6 +49,9 @@ in # ZeroTier does not issue DHCP leases, but some strangers might... networking.dhcpcd.denyInterfaces = [ "zt0" ]; + # ZeroTier receives UDP transmissions on port 9993 by default + networking.firewall.allowedUDPPorts = [ 9993 ]; + environment.systemPackages = [ cfg.package ]; }; } diff --git a/nixos/modules/services/security/hologram-server.nix b/nixos/modules/services/security/hologram-server.nix index e267fed27955e..bad02c7440bac 100644 --- a/nixos/modules/services/security/hologram-server.nix +++ b/nixos/modules/services/security/hologram-server.nix @@ -12,16 +12,20 @@ let dn = cfg.ldapBindDN; password = cfg.ldapBindPassword; }; - insecureldap = cfg.ldapInsecure; - userattr = cfg.ldapUserAttr; - baseDN = cfg.ldapBaseDN; + insecureldap = cfg.ldapInsecure; + userattr = cfg.ldapUserAttr; + baseDN = cfg.ldapBaseDN; + enableldapRoles = cfg.enableLdapRoles; + roleAttr = cfg.roleAttr; + groupClassAttr = cfg.groupClassAttr; }; aws = { account = cfg.awsAccount; defaultrole = cfg.awsDefaultRole; }; - stats = cfg.statsAddress; - listen = cfg.listenAddress; + stats = cfg.statsAddress; + listen = cfg.listenAddress; + cachetimeout = cfg.cacheTimeoutSeconds; }); in { options = { @@ -70,6 +74,24 @@ in { description = "Password of account to use to query the LDAP server"; }; + enableLdapRoles = mkOption { + type = types.bool; + default = false; + description = "Whether to assign user roles based on the user's LDAP group memberships"; + }; + + groupClassAttr = mkOption { + type = types.str; + default = "groupOfNames"; + description = "The objectclass attribute to search for groups when enableLdapRoles is true"; + }; + + roleAttr = mkOption { + type = types.str; + default = "businessCategory"; + description = "Which LDAP group attribute to search for authorized role ARNs"; + }; + awsAccount = mkOption { type = types.str; description = "AWS account number"; @@ -85,6 +107,12 @@ in { default = ""; description = "Address of statsd server"; }; + + cacheTimeoutSeconds = mkOption { + type = types.int; + default = 3600; + description = "How often (in seconds) to refresh the LDAP cache"; + }; }; }; diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index fed91756e7696..2c727de210270 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -5,6 +5,7 @@ with lib; let cfg = config.services.tor; torDirectory = "/var/lib/tor"; + torRunDirectory = "/run/tor"; opt = name: value: optionalString (value != null) "${name} ${value}"; optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}"; @@ -38,6 +39,7 @@ let ''} ${optint "ControlPort" cfg.controlPort} + ${optionalString cfg.controlSocket.enable "ControlSocket ${torRunDirectory}/control GroupWritable RelaxDirModeCheck"} '' # Client connection config + optionalString cfg.client.enable '' @@ -140,6 +142,17 @@ in ''; }; + controlSocket = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Wheter to enable Tor control socket. Control socket is created + in <literal>${torRunDirectory}/control</literal> + ''; + }; + }; + client = { enable = mkOption { type = types.bool; @@ -692,7 +705,7 @@ in # Translated from the upstream contrib/dist/tor.service.in preStart = '' - install -o tor -g tor -d ${torDirectory}/onion + install -o tor -g tor -d ${torDirectory}/onion ${torRunDirectory} ${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config ''; @@ -716,7 +729,7 @@ in DevicePolicy = "closed"; InaccessibleDirectories = "/home"; ReadOnlyDirectories = "/"; - ReadWriteDirectories = torDirectory; + ReadWriteDirectories = [torDirectory torRunDirectory]; NoNewPrivileges = "yes"; }; }; diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index 4911a64c95d04..0998d5a7107a7 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -21,6 +21,19 @@ let # for users in group "transmission" to have access to torrents fullSettings = { umask = 2; download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings; + + # Directories transmission expects to exist and be ug+rwx. + directoriesToManage = [ homeDir settingsDir fullSettings.download-dir fullSettings.incomplete-dir ]; + + preStart = pkgs.writeScript "transmission-pre-start" '' + #!${pkgs.runtimeShell} + set -ex + for DIR in ${escapeShellArgs directoriesToManage}; do + mkdir -p "$DIR" + chmod 770 "$DIR" + done + cp -f ${settingsFile} ${settingsDir}/settings.json + ''; in { options = { @@ -59,8 +72,8 @@ in time the service starts). String values must be quoted, integer and boolean values must not. - See https://trac.transmissionbt.com/wiki/EditConfigFiles for - documentation. + See https://github.com/transmission/transmission/wiki/Editing-Configuration-Files + for documentation. ''; }; @@ -89,9 +102,7 @@ in # 1) Only the "transmission" user and group have access to torrents. # 2) Optionally update/force specific fields into the configuration file. - serviceConfig.ExecStartPre = '' - ${pkgs.runtimeShell} -c "mkdir -p ${homeDir} ${settingsDir} ${fullSettings.download-dir} ${fullSettings.incomplete-dir} && chmod 770 ${homeDir} ${settingsDir} ${fullSettings.download-dir} ${fullSettings.incomplete-dir} && rm -f ${settingsDir}/settings.json && cp -f ${settingsFile} ${settingsDir}/settings.json" - ''; + serviceConfig.ExecStartPre = preStart; serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port}"; serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; serviceConfig.User = "transmission"; diff --git a/nixos/modules/services/web-apps/nixbot.nix b/nixos/modules/services/web-apps/nixbot.nix deleted file mode 100644 index 0592d01bf3692..0000000000000 --- a/nixos/modules/services/web-apps/nixbot.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.nixbot; - pyramidIni = '' - ### - # app configuration - # http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html - ### - - [app:main] - use = egg:nixbot - - nixbot.github_token = ${cfg.githubToken} - nixbot.bot_name = ${cfg.botName} - nixbot.repo = ${cfg.repo} - nixbot.pr_repo = ${cfg.prRepo} - nixbot.hydra_jobsets_repo = ${cfg.hydraJobsetsRepo} - nixbot.github_secret = justnotsorandom - nixbot.public_url = ${cfg.publicUrl} - nixbot.repo_dir = ${cfg.repoDir} - - pyramid.reload_templates = false - pyramid.debug_authorization = false - pyramid.debug_notfound = false - pyramid.debug_routematch = false - pyramid.default_locale_name = en - - # By default, the toolbar only appears for clients from IP addresses - # '127.0.0.1' and '::1'. - # debugtoolbar.hosts = 127.0.0.1 ::1 - - ### - # wsgi server configuration - ### - - [server:main] - use = egg:waitress#main - host = 0.0.0.0 - port = 6543 - - ### - # logging configuration - # http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html - ### - - [loggers] - keys = root, nixbot - - [handlers] - keys = console - - [formatters] - keys = generic - - [logger_root] - level = INFO - handlers = console - - [logger_nixbot] - level = INFO - handlers = - qualname = nixbot - - [handler_console] - class = StreamHandler - args = (sys.stderr,) - level = NOTSET - formatter = generic - - [formatter_generic] - format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s - ''; -in { - options = { - services.nixbot = { - enable = mkEnableOption "nixbot"; - - botName = mkOption { - type = types.str; - description = "The bot's github user account name."; - default = "nixbot"; - }; - - githubToken = mkOption { - type = types.str; - description = "The bot's github user account token."; - example = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - }; - - repo = mkOption { - type = types.str; - description = "The github repository to check for PRs."; - example = "nixos/nixpkgs"; - }; - - prRepo = mkOption { - type = types.str; - description = "The github repository to push the testing branches to."; - example = "nixos/nixpkgs-pr"; - }; - - hydraJobsetsRepo = mkOption { - type = types.str; - description = "The github repository to push the hydra jobset definitions to."; - example = "nixos/hydra-jobsets"; - }; - - publicUrl = mkOption { - type = types.str; - description = "The public URL the bot is reachable at (Github hook endpoint)."; - example = "https://nixbot.nixos.org"; - }; - - repoDir = mkOption { - type = types.path; - description = "The directory the repositories are stored in."; - default = "/var/lib/nixbot"; - }; - }; - }; - - config = mkIf cfg.enable { - users.extraUsers.nixbot = { - createHome = true; - home = cfg.repoDir; - }; - - systemd.services.nixbot = let - env = pkgs.python3.buildEnv.override { - extraLibs = [ pkgs.nixbot ]; - }; - in { - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - script = '' - ${env}/bin/pserve ${pkgs.writeText "production.ini" pyramidIni} - ''; - - serviceConfig = { - User = "nixbot"; - Group = "nogroup"; - PermissionsStartOnly = true; - }; - }; - }; -} diff --git a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix index 1d53ce6590056..4bbd041b6e042 100644 --- a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix +++ b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix @@ -118,7 +118,7 @@ with lib; default = []; example = [ { urlPath = "/foo/bar.png"; - files = "/home/eelco/some-file.png"; + file = "/home/eelco/some-file.png"; } ]; description = '' diff --git a/nixos/modules/services/web-servers/lighttpd/gitweb.nix b/nixos/modules/services/web-servers/lighttpd/gitweb.nix index c8d9836b0b689..37128d90401d7 100644 --- a/nixos/modules/services/web-servers/lighttpd/gitweb.nix +++ b/nixos/modules/services/web-servers/lighttpd/gitweb.nix @@ -3,12 +3,7 @@ with lib; let - cfg = config.services.lighttpd.gitweb; - gitwebConfigFile = pkgs.writeText "gitweb.conf" '' - # path to git projects (<project>.git) - $projectroot = "${cfg.projectroot}"; - ${cfg.extraConfig} - ''; + cfg = config.services.gitweb; in { @@ -23,26 +18,9 @@ in ''; }; - projectroot = mkOption { - default = "/srv/git"; - type = types.path; - description = '' - Path to git projects (bare repositories) that should be served by - gitweb. Must not end with a slash. - ''; - }; - - extraConfig = mkOption { - default = ""; - type = types.lines; - description = '' - Verbatim configuration text appended to the generated gitweb.conf file. - ''; - }; - }; - config = mkIf cfg.enable { + config = mkIf config.services.lighttpd.gitweb.enable { # declare module dependencies services.lighttpd.enableModules = [ "mod_cgi" "mod_redirect" "mod_alias" "mod_setenv" ]; @@ -60,7 +38,7 @@ in "/gitweb/" => "${pkgs.git}/share/gitweb/gitweb.cgi" ) setenv.add-environment = ( - "GITWEB_CONFIG" => "${gitwebConfigFile}", + "GITWEB_CONFIG" => "${cfg.gitwebConfigFile}", "HOME" => "${cfg.projectroot}" ) } diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index dee877f1c1143..938a8a1fe334b 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -9,15 +9,16 @@ let serverName = if vhostConfig.serverName != null then vhostConfig.serverName else vhostName; + acmeDirectory = config.security.acme.directory; in vhostConfig // { inherit serverName; } // (optionalAttrs vhostConfig.enableACME { - sslCertificate = "/var/lib/acme/${serverName}/fullchain.pem"; - sslCertificateKey = "/var/lib/acme/${serverName}/key.pem"; + sslCertificate = "${acmeDirectory}/${serverName}/fullchain.pem"; + sslCertificateKey = "${acmeDirectory}/${serverName}/key.pem"; }) // (optionalAttrs (vhostConfig.useACMEHost != null) { - sslCertificate = "/var/lib/acme/${vhostConfig.useACMEHost}/fullchain.pem"; - sslCertificateKey = "/var/lib/acme/${vhostConfig.useACMEHost}/key.pem"; + sslCertificate = "${acmeDirectory}/${vhostConfig.useACMEHost}/fullchain.pem"; + sslCertificateKey = "${acmeDirectory}/${vhostConfig.useACMEHost}/key.pem"; }) ) cfg.virtualHosts; enableIPv6 = config.networking.enableIPv6; diff --git a/nixos/modules/services/web-servers/nginx/gitweb.nix b/nixos/modules/services/web-servers/nginx/gitweb.nix new file mode 100644 index 0000000000000..3dc3ebc7e4c2b --- /dev/null +++ b/nixos/modules/services/web-servers/nginx/gitweb.nix @@ -0,0 +1,59 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.gitweb; + +in +{ + + options.services.nginx.gitweb = { + + enable = mkOption { + default = false; + type = types.bool; + description = '' + If true, enable gitweb in nginx. Access it at http://yourserver/gitweb + ''; + }; + + }; + + config = mkIf config.services.nginx.gitweb.enable { + + systemd.services.gitweb = { + description = "GitWeb service"; + script = "${pkgs.git}/share/gitweb/gitweb.cgi --fastcgi --nproc=1"; + environment = { + FCGI_SOCKET_PATH = "/run/gitweb/gitweb.sock"; + }; + serviceConfig = { + User = "nginx"; + Group = "nginx"; + RuntimeDirectory = [ "gitweb" ]; + }; + wantedBy = [ "multi-user.target" ]; + }; + + services.nginx = { + virtualHosts.default = { + locations."/gitweb/" = { + root = "${pkgs.git}/share"; + tryFiles = "$uri @gitweb"; + }; + locations."@gitweb" = { + extraConfig = '' + include ${pkgs.nginx}/conf/fastcgi_params; + fastcgi_param GITWEB_CONFIG ${cfg.gitwebConfigFile}; + fastcgi_pass unix:/run/gitweb/gitweb.sock; + ''; + }; + }; + }; + + }; + + meta.maintainers = with maintainers; [ gnidorah ]; + +} diff --git a/nixos/modules/services/web-servers/varnish/default.nix b/nixos/modules/services/web-servers/varnish/default.nix index d63fb954ef966..bc74d62b116a1 100644 --- a/nixos/modules/services/web-servers/varnish/default.nix +++ b/nixos/modules/services/web-servers/varnish/default.nix @@ -6,13 +6,22 @@ let cfg = config.services.varnish; commandLine = "-f ${pkgs.writeText "default.vcl" cfg.config}" + - optionalString (cfg.extraModules != []) " -p vmod_path='${makeSearchPathOutput "lib" "lib/varnish/vmods" ([pkgs.varnish] ++ cfg.extraModules)}' -r vmod_path"; + optionalString (cfg.extraModules != []) " -p vmod_path='${makeSearchPathOutput "lib" "lib/varnish/vmods" ([cfg.package] ++ cfg.extraModules)}' -r vmod_path"; in { options = { services.varnish = { enable = mkEnableOption "Varnish Server"; + package = mkOption { + type = types.package; + default = pkgs.varnish5; + defaultText = "pkgs.varnish5"; + description = '' + The package to use + ''; + }; + http_address = mkOption { type = types.str; default = "*:6081"; @@ -39,7 +48,7 @@ in extraModules = mkOption { type = types.listOf types.package; default = []; - example = literalExample "[ pkgs.varnish-geoip ]"; + example = literalExample "[ pkgs.varnish5Packages.geoip ]"; description = " Varnish modules (except 'std'). "; @@ -73,7 +82,7 @@ in serviceConfig = { Type = "simple"; PermissionsStartOnly = true; - ExecStart = "${pkgs.varnish}/sbin/varnishd -a ${cfg.http_address} -n ${cfg.stateDir} -F ${cfg.extraCommandLine} ${commandLine}"; + ExecStart = "${cfg.package}/sbin/varnishd -a ${cfg.http_address} -n ${cfg.stateDir} -F ${cfg.extraCommandLine} ${commandLine}"; Restart = "always"; RestartSec = "5s"; User = "varnish"; @@ -84,13 +93,13 @@ in }; }; - environment.systemPackages = [ pkgs.varnish ]; + environment.systemPackages = [ cfg.package ]; # check .vcl syntax at compile time (e.g. before nixops deployment) system.extraDependencies = [ (pkgs.stdenv.mkDerivation { name = "check-varnish-syntax"; - buildCommand = "${pkgs.varnish}/sbin/varnishd -C ${commandLine} 2> $out"; + buildCommand = "${cfg.package}/sbin/varnishd -C ${commandLine} 2> $out || (cat $out; exit 1)"; }) ]; diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix index 4622c7b760f01..f435e85f6b835 100644 --- a/nixos/modules/services/x11/desktop-managers/default.nix +++ b/nixos/modules/services/x11/desktop-managers/default.nix @@ -87,11 +87,11 @@ in default = mkOption { type = types.str; - default = "none"; - example = "plasma5"; + default = ""; + example = "none"; description = "Default desktop manager loaded if none have been chosen."; apply = defaultDM: - if defaultDM == "none" && cfg.session.list != [] then + if defaultDM == "" && cfg.session.list != [] then (head cfg.session.list).name else if any (w: w.name == defaultDM) cfg.session.list then defaultDM diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 7256013d5d8bc..10e8ef0ed3817 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -182,8 +182,7 @@ in { { inherit (pkgs) networkmanager modemmanager wpa_supplicant; inherit (pkgs.gnome3) networkmanager-openvpn networkmanager-vpnc networkmanager-openconnect networkmanager-fortisslvpn - networkmanager-pptp networkmanager-iodine - networkmanager-l2tp; }; + networkmanager-iodine networkmanager-l2tp; }; # Needed for themes and backgrounds environment.pathsToLink = [ "/share" ]; diff --git a/nixos/modules/services/x11/desktop-managers/lxqt.nix b/nixos/modules/services/x11/desktop-managers/lxqt.nix index fb907618d35b7..2596ec4ad85cb 100644 --- a/nixos/modules/services/x11/desktop-managers/lxqt.nix +++ b/nixos/modules/services/x11/desktop-managers/lxqt.nix @@ -61,6 +61,8 @@ in environment.variables.GIO_EXTRA_MODULES = [ "${pkgs.gvfs}/lib/gio/modules" ]; + services.upower.enable = config.powerManagement.enable; }; + } diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix index 0117dc9d132be..db83aaf3c19f3 100644 --- a/nixos/modules/services/x11/desktop-managers/mate.nix +++ b/nixos/modules/services/x11/desktop-managers/mate.nix @@ -108,6 +108,8 @@ in services.gnome3.gnome-keyring.enable = true; services.upower.enable = config.powerManagement.enable; + security.pam.services."mate-screensaver".unixAuth = true; + environment.pathsToLink = [ "/share" ]; }; diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index 25ba95fccd756..e617e55a7a57a 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -12,6 +12,7 @@ in ./afterstep.nix ./bspwm.nix ./dwm.nix + ./evilwm.nix ./exwm.nix ./fluxbox.nix ./fvwm.nix @@ -61,9 +62,7 @@ in example = "wmii"; description = "Default window manager loaded if none have been chosen."; apply = defaultWM: - if defaultWM == "none" && cfg.session != [] then - (head cfg.session).name - else if any (w: w.name == defaultWM) cfg.session then + if any (w: w.name == defaultWM) cfg.session then defaultWM else throw "Default window manager (${defaultWM}) not found."; diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index f96d3c5afbac4..e7918cf9d315f 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -161,15 +161,6 @@ in ''; }; - plainX = mkOption { - type = types.bool; - default = false; - description = '' - Whether the X11 session can be plain (without DM/WM) and - the Xsession script will be used as fallback or not. - ''; - }; - autorun = mkOption { type = types.bool; default = true; @@ -561,11 +552,6 @@ in + "${toString (length primaryHeads)} heads set to primary: " + concatMapStringsSep ", " (x: x.output) primaryHeads; }) - { assertion = cfg.desktopManager.default == "none" && cfg.windowManager.default == "none" -> cfg.plainX; - message = "Either the desktop manager or the window manager shouldn't be `none`! " - + "To explicitly allow this, you can also set `services.xserver.plainX` to `true`. " - + "The `default` value looks for enabled WMs/DMs and select the first one."; - } ]; environment.etc = diff --git a/nixos/modules/system/boot/kexec.nix b/nixos/modules/system/boot/kexec.nix index 14ebe66e63204..3fc1af28f628e 100644 --- a/nixos/modules/system/boot/kexec.nix +++ b/nixos/modules/system/boot/kexec.nix @@ -1,7 +1,7 @@ { config, pkgs, lib, ... }: { - config = lib.mkIf (pkgs.kexectools != null) { + config = lib.mkIf (pkgs.kexectools.meta.available) { environment.systemPackages = [ pkgs.kexectools ]; systemd.services."prepare-kexec" = diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index 9d2c580d62a7d..b83012dfda7ef 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -43,7 +43,7 @@ if [ ! -e /proc/1 ]; then local options="$3" local fsType="$4" - mkdir -m 0755 -p "$mountPoint" + install -m 0755 -d "$mountPoint" mount -n -t "$fsType" -o "$options" "$device" "$mountPoint" } source @earlyMountScript@ @@ -71,7 +71,7 @@ fi # Provide a /etc/mtab. -mkdir -m 0755 -p /etc +install -m 0755 -d /etc test -e /etc/fstab || touch /etc/fstab # to shut up mount rm -f /etc/mtab* # not that we care about stale locks ln -s /proc/mounts /etc/mtab @@ -79,8 +79,8 @@ ln -s /proc/mounts /etc/mtab # More special file systems, initialise required directories. [ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default -mkdir -m 01777 -p /tmp -mkdir -m 0755 -p /var/{log,lib,db} /nix/var /etc/nixos/ \ +install -m 01777 -d /tmp +install -m 0755 -d /var/{log,lib,db} /nix/var /etc/nixos/ \ /run/lock /home /bin # for the /bin/sh symlink diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 92c9ee0c4691b..b8a2d42e0fbc2 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -524,6 +524,14 @@ in ''; }; + systemd.enableCgroupAccounting = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable cgroup accounting. + ''; + }; + systemd.extraConfig = mkOption { default = ""; type = types.lines; @@ -725,6 +733,13 @@ in "systemd/system.conf".text = '' [Manager] + ${optionalString config.systemd.enableCgroupAccounting '' + DefaultCPUAccounting=yes + DefaultIOAccounting=yes + DefaultBlockIOAccounting=yes + DefaultMemoryAccounting=yes + DefaultTasksAccounting=yes + ''} ${config.systemd.extraConfig} ''; diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 630fe6d114ce8..e754a1e8718d5 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -68,8 +68,7 @@ let (hasAttr dev cfg.macvlans) || (hasAttr dev cfg.sits) || (hasAttr dev cfg.vlans) || - (hasAttr dev cfg.vswitches) || - (hasAttr dev cfg.wlanInterfaces) + (hasAttr dev cfg.vswitches) then [ "${dev}-netdev.service" ] else optional (dev != null && dev != "lo" && !config.boot.isContainer) (subsystemDevice dev); @@ -192,7 +191,7 @@ let if out=$(ip addr add "${cidr}" dev "${i.name}" 2>&1); then echo "done" elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then - echo "failed" + echo "'ip addr add "${cidr}" dev "${i.name}"' failed: $out" exit 1 fi '' @@ -213,7 +212,7 @@ let if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" 2>&1); then echo "done" elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then - echo "failed" + echo "'ip route add "${cidr}" ${options} ${via} dev "${i.name}"' failed: $out" exit 1 fi '' diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 4039e4e516321..14f9b95675151 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -62,35 +62,6 @@ let then mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n==device) interfaces) ++ mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n!=device) interfaces) else mapAttrsToList (n: v: v // {_iName = n;}) interfaces; - # udev script that configures a physical wlan device and adds virtual interfaces - wlanDeviceUdevScript = device: interfaceList: pkgs.writeScript "wlan-${device}-udev-script" '' - #!${pkgs.runtimeShell} - - # Change the wireless phy device to a predictable name. - if [ -e "/sys/class/net/${device}/phy80211/name" ]; then - ${pkgs.iw}/bin/iw phy `${pkgs.coreutils}/bin/cat /sys/class/net/${device}/phy80211/name` set name ${device} || true - fi - - # Crate new, virtual interfaces and configure them at the same time - ${flip concatMapStrings (drop 1 interfaceList) (i: '' - ${pkgs.iw}/bin/iw dev ${device} interface add ${i._iName} type ${i.type} \ - ${optionalString (i.type == "mesh" && i.meshID != null) "mesh_id ${i.meshID}"} \ - ${optionalString (i.type == "monitor" && i.flags != null) "flags ${i.flags}"} \ - ${optionalString (i.type == "managed" && i.fourAddr != null) "4addr ${if i.fourAddr then "on" else "off"}"} \ - ${optionalString (i.mac != null) "addr ${i.mac}"} - '')} - - # Reconfigure and rename the default interface that already exists - ${flip concatMapStrings (take 1 interfaceList) (i: '' - ${pkgs.iw}/bin/iw dev ${device} set type ${i.type} - ${optionalString (i.type == "mesh" && i.meshID != null) "${pkgs.iw}/bin/iw dev ${device} set meshid ${i.meshID}"} - ${optionalString (i.type == "monitor" && i.flags != null) "${pkgs.iw}/bin/iw dev ${device} set monitor ${i.flags}"} - ${optionalString (i.type == "managed" && i.fourAddr != null) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if i.fourAddr then "on" else "off"}"} - ${optionalString (i.mac != null) "${pkgs.iproute}/bin/ip link set dev ${device} address ${i.mac}"} - ${optionalString (device != i._iName) "${pkgs.iproute}/bin/ip link set dev ${device} name ${i._iName}"} - '')} - ''; - # We must escape interfaces due to the systemd interpretation subsystemDevice = interface: "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; @@ -489,7 +460,7 @@ in networking.interfaces = mkOption { default = {}; example = - { eth0.ipv4 = [ { + { eth0.ipv4.addresses = [ { address = "131.211.84.78"; prefixLength = 25; } ]; diff --git a/nixos/modules/virtualisation/ec2-amis.nix b/nixos/modules/virtualisation/ec2-amis.nix index 01512911a057e..baffad79b0019 100644 --- a/nixos/modules/virtualisation/ec2-amis.nix +++ b/nixos/modules/virtualisation/ec2-amis.nix @@ -240,5 +240,22 @@ let self = { "17.09".sa-east-1.hvm-ebs = "ami-4762202b"; "17.09".ap-south-1.hvm-ebs = "ami-4e376021"; - latest = self."17.09"; + # 18.03.131792.becbe4dbe16 + "18.03".eu-west-1.hvm-ebs = "ami-cda4fab4"; + "18.03".eu-west-2.hvm-ebs = "ami-d96786be"; + "18.03".eu-west-3.hvm-ebs = "ami-6b0cba16"; + "18.03".eu-central-1.hvm-ebs = "ami-5e2b75b5"; + "18.03".us-east-1.hvm-ebs = "ami-d464cba9"; + "18.03".us-east-2.hvm-ebs = "ami-fd221298"; + "18.03".us-west-1.hvm-ebs = "ami-ff0d1d9f"; + "18.03".us-west-2.hvm-ebs = "ami-c05c3bb8"; + "18.03".ca-central-1.hvm-ebs = "ami-cc72f4a8"; + "18.03".ap-southeast-1.hvm-ebs = "ami-b61633ca"; + "18.03".ap-southeast-2.hvm-ebs = "ami-530fc131"; + "18.03".ap-northeast-1.hvm-ebs = "ami-90d6c0ec"; + "18.03".ap-northeast-2.hvm-ebs = "ami-a1248bcf"; + "18.03".sa-east-1.hvm-ebs = "ami-b090c6dc"; + "18.03".ap-south-1.hvm-ebs = "ami-32c9ec5d"; + + latest = self."18.03"; }; in self diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 155a33b3bb373..0b6bec786da4c 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -2,7 +2,7 @@ with lib; let - diskSize = 1024; # MB + diskSize = 1536; # MB gce = pkgs.google-compute-engine; in { @@ -57,6 +57,12 @@ in # Always include cryptsetup so that NixOps can use it. environment.systemPackages = [ pkgs.cryptsetup ]; + # Make sure GCE image does not replace host key that NixOps sets + environment.etc."default/instance_configs.cfg".text = lib.mkDefault '' + [InstanceSetup] + set_host_keys = false + ''; + # Rely on GCP's firewall instead networking.firewall.enable = mkDefault false; @@ -69,6 +75,9 @@ in networking.usePredictableInterfaceNames = false; + # GC has 1460 MTU + networking.interfaces.eth0.mtu = 1460; + # allow the google-accounts-daemon to manage users users.mutableUsers = true; # and allow users to sudo without password diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index a369b7ddbe1d8..024db7f87c2e8 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -119,18 +119,10 @@ in { after = [ "systemd-udev-settle.service" ] ++ optional vswitch.enable "vswitchd.service"; - environment = { - LIBVIRTD_ARGS = ''--config "${configFile}" ${concatStringsSep " " cfg.extraOptions}''; - }; + environment.LIBVIRTD_ARGS = ''--config "${configFile}" ${concatStringsSep " " cfg.extraOptions}''; - path = with pkgs; [ - bridge-utils - dmidecode - dnsmasq - ebtables - cfg.qemuPackage # libvirtd requires qemu-img to manage disk images - ] - ++ optional vswitch.enable vswitch.package; + path = [ cfg.qemuPackage ] # libvirtd requires qemu-img to manage disk images + ++ optional vswitch.enable vswitch.package; preStart = '' mkdir -p /var/log/libvirt/qemu -m 755 diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index 674f230c81045..ee327ed805b27 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -320,7 +320,7 @@ in mkOption { default = [ "-net nic,netdev=user.0,model=virtio" - "-netdev user,id=user.0,\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}" + "-netdev user,id=user.0\${QEMU_NET_OPTS:+,$QEMU_NET_OPTS}" ]; type = types.listOf types.str; description = '' diff --git a/nixos/release.nix b/nixos/release.nix index 6a3fcea176834..4fd77e6471cff 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -17,14 +17,14 @@ let } // args); # Note: only supportedSystems are considered. - callTestOnTheseSystems = systems: fn: args: - forTheseSystems + callTestOnMatchingSystems = systems: fn: args: + forMatchingSystems (intersectLists supportedSystems systems) (system: hydraJob (importTest fn args system)); - callTest = callTestOnTheseSystems supportedSystems; + callTest = callTestOnMatchingSystems supportedSystems; - callSubTests = callSubTestsOnTheseSystems supportedSystems; - callSubTestsOnTheseSystems = systems: fn: args: let + callSubTests = callSubTestsOnMatchingSystems supportedSystems; + callSubTestsOnMatchingSystems = systems: fn: args: let discover = attrs: let subTests = filterAttrs (const (hasAttr "test")) attrs; in mapAttrs (const (t: hydraJob t.test)) subTests; @@ -55,6 +55,17 @@ let }).config.system.build.isoImage); + makeSdImage = + { module, maintainers ? ["dezgeg"], system }: + + with import nixpkgs { inherit system; }; + + hydraJob ((import lib/eval-config.nix { + inherit system; + modules = [ module versionModule ]; + }).config.system.build.sdImage); + + makeSystemTarball = { module, maintainers ? ["viric"], system }: @@ -127,7 +138,7 @@ in rec { # Build the initial ramdisk so Hydra can keep track of its size over time. initialRamdisk = buildFromConfig ({ pkgs, ... }: { }) (config: config.system.build.initialRamdisk); - netboot = forTheseSystems [ "x86_64-linux" "aarch64-linux" ] (system: makeNetboot { + netboot = forMatchingSystems [ "x86_64-linux" "aarch64-linux" ] (system: makeNetboot { inherit system; modules = [ ./modules/installer/netboot/netboot-minimal.nix @@ -141,7 +152,7 @@ in rec { inherit system; }); - iso_graphical = forTheseSystems [ "x86_64-linux" ] (system: makeIso { + iso_graphical = forMatchingSystems [ "x86_64-linux" ] (system: makeIso { module = ./modules/installer/cd-dvd/installation-cd-graphical-kde.nix; type = "graphical"; inherit system; @@ -149,15 +160,19 @@ in rec { # A variant with a more recent (but possibly less stable) kernel # that might support more hardware. - iso_minimal_new_kernel = forTheseSystems [ "x86_64-linux" ] (system: makeIso { + iso_minimal_new_kernel = forMatchingSystems [ "x86_64-linux" ] (system: makeIso { module = ./modules/installer/cd-dvd/installation-cd-minimal-new-kernel.nix; type = "minimal-new-kernel"; inherit system; }); + sd_image = forMatchingSystems [ "aarch64-linux" ] (system: makeSdImage { + module = ./modules/installer/cd-dvd/sd-image-aarch64.nix; + inherit system; + }); # A bootable VirtualBox virtual appliance as an OVA file (i.e. packaged OVF). - ova = forTheseSystems [ "x86_64-linux" ] (system: + ova = forMatchingSystems [ "x86_64-linux" ] (system: with import nixpkgs { inherit system; }; @@ -233,9 +248,9 @@ in rec { tests.boot-stage1 = callTest tests/boot-stage1.nix {}; tests.borgbackup = callTest tests/borgbackup.nix {}; tests.buildbot = callTest tests/buildbot.nix {}; - tests.cadvisor = callTestOnTheseSystems ["x86_64-linux"] tests/cadvisor.nix {}; - tests.ceph = callTestOnTheseSystems ["x86_64-linux"] tests/ceph.nix {}; - tests.chromium = (callSubTestsOnTheseSystems ["x86_64-linux"] tests/chromium.nix {}).stable or {}; + tests.cadvisor = callTestOnMatchingSystems ["x86_64-linux"] tests/cadvisor.nix {}; + tests.ceph = callTestOnMatchingSystems ["x86_64-linux"] tests/ceph.nix {}; + tests.chromium = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/chromium.nix {}).stable or {}; tests.cjdns = callTest tests/cjdns.nix {}; tests.cloud-init = callTest tests/cloud-init.nix {}; tests.containers-ipv4 = callTest tests/containers-ipv4.nix {}; @@ -249,21 +264,21 @@ in rec { tests.containers-hosts = callTest tests/containers-hosts.nix {}; tests.containers-macvlans = callTest tests/containers-macvlans.nix {}; tests.couchdb = callTest tests/couchdb.nix {}; - tests.docker = callTestOnTheseSystems ["x86_64-linux"] tests/docker.nix {}; - tests.docker-tools = callTestOnTheseSystems ["x86_64-linux"] tests/docker-tools.nix {}; - tests.docker-edge = callTestOnTheseSystems ["x86_64-linux"] tests/docker-edge.nix {}; + tests.docker = callTestOnMatchingSystems ["x86_64-linux"] tests/docker.nix {}; + tests.docker-tools = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-tools.nix {}; + tests.docker-edge = callTestOnMatchingSystems ["x86_64-linux"] tests/docker-edge.nix {}; tests.dovecot = callTest tests/dovecot.nix {}; - tests.dnscrypt-proxy = callTestOnTheseSystems ["x86_64-linux"] tests/dnscrypt-proxy.nix {}; + tests.dnscrypt-proxy = callTestOnMatchingSystems ["x86_64-linux"] tests/dnscrypt-proxy.nix {}; tests.ecryptfs = callTest tests/ecryptfs.nix {}; - tests.etcd = callTestOnTheseSystems ["x86_64-linux"] tests/etcd.nix {}; - tests.ec2-nixops = (callSubTestsOnTheseSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-nixops or {}; - tests.ec2-config = (callSubTestsOnTheseSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-config or {}; - tests.elk = callSubTestsOnTheseSystems ["x86_64-linux"] tests/elk.nix {}; + tests.etcd = callTestOnMatchingSystems ["x86_64-linux"] tests/etcd.nix {}; + tests.ec2-nixops = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-nixops or {}; + tests.ec2-config = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-config or {}; + tests.elk = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/elk.nix {}; tests.env = callTest tests/env.nix {}; tests.ferm = callTest tests/ferm.nix {}; tests.firefox = callTest tests/firefox.nix {}; tests.firewall = callTest tests/firewall.nix {}; - tests.fleet = callTestOnTheseSystems ["x86_64-linux"] tests/fleet.nix {}; + tests.fleet = callTestOnMatchingSystems ["x86_64-linux"] tests/fleet.nix {}; tests.fwupd = callTest tests/fwupd.nix {}; #tests.gitlab = callTest tests/gitlab.nix {}; tests.gitolite = callTest tests/gitolite.nix {}; @@ -280,6 +295,7 @@ in rec { tests.hound = callTest tests/hound.nix {}; tests.hocker-fetchdocker = callTest tests/hocker-fetchdocker {}; tests.i3wm = callTest tests/i3wm.nix {}; + tests.iftop = callTest tests/iftop.nix {}; tests.initrd-network-ssh = callTest tests/initrd-network-ssh {}; tests.installer = callSubTests tests/installer.nix {}; tests.influxdb = callTest tests/influxdb.nix {}; @@ -296,7 +312,10 @@ in rec { tests.kernel-copperhead = callTest tests/kernel-copperhead.nix {}; tests.kernel-latest = callTest tests/kernel-latest.nix {}; tests.kernel-lts = callTest tests/kernel-lts.nix {}; - tests.kubernetes = callSubTestsOnTheseSystems ["x86_64-linux"] tests/kubernetes/default.nix {}; + tests.kubernetes.dns = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/dns.nix {}; + ## kubernetes.e2e should eventually replace kubernetes.rbac when it works + #tests.kubernetes.e2e = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/e2e.nix {}; + tests.kubernetes.rbac = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/rbac.nix {}; tests.latestKernel.login = callTest tests/login.nix { latestKernel = true; }; tests.ldap = callTest tests/ldap.nix {}; #tests.lightdm = callTest tests/lightdm.nix {}; @@ -326,14 +345,14 @@ in rec { tests.nginx = callTest tests/nginx.nix { }; tests.nghttpx = callTest tests/nghttpx.nix { }; tests.nix-ssh-serve = callTest tests/nix-ssh-serve.nix { }; - tests.novacomd = callTestOnTheseSystems ["x86_64-linux"] tests/novacomd.nix { }; + tests.novacomd = callTestOnMatchingSystems ["x86_64-linux"] tests/novacomd.nix { }; tests.leaps = callTest tests/leaps.nix { }; tests.nsd = callTest tests/nsd.nix {}; tests.openssh = callTest tests/openssh.nix {}; tests.openldap = callTest tests/openldap.nix {}; tests.owncloud = callTest tests/owncloud.nix {}; tests.pam-oath-login = callTest tests/pam-oath-login.nix {}; - #tests.panamax = callTestOnTheseSystems ["x86_64-linux"] tests/panamax.nix {}; + #tests.panamax = callTestOnMatchingSystems ["x86_64-linux"] tests/panamax.nix {}; tests.peerflix = callTest tests/peerflix.nix {}; tests.php-pcre = callTest tests/php-pcre.nix {}; tests.postgresql = callSubTests tests/postgresql.nix {}; @@ -344,6 +363,7 @@ in rec { tests.predictable-interface-names = callSubTests tests/predictable-interface-names.nix {}; tests.printing = callTest tests/printing.nix {}; tests.prometheus = callTest tests/prometheus.nix {}; + tests.prosody = callTest tests/prosody.nix {}; tests.proxy = callTest tests/proxy.nix {}; # tests.quagga = callTest tests/quagga.nix {}; tests.quake3 = callTest tests/quake3.nix {}; @@ -364,9 +384,10 @@ in rec { tests.switchTest = callTest tests/switch-test.nix {}; tests.taskserver = callTest tests/taskserver.nix {}; tests.tomcat = callTest tests/tomcat.nix {}; + tests.transmission = callTest tests/transmission.nix {}; tests.udisks2 = callTest tests/udisks2.nix {}; tests.vault = callTest tests/vault.nix {}; - tests.virtualbox = callSubTestsOnTheseSystems ["x86_64-linux"] tests/virtualbox.nix {}; + tests.virtualbox = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/virtualbox.nix {}; tests.wordpress = callTest tests/wordpress.nix {}; tests.xautolock = callTest tests/xautolock.nix {}; tests.xfce = callTest tests/xfce.nix {}; diff --git a/nixos/tests/atd.nix b/nixos/tests/atd.nix index c2c0a716e0de5..5260c8ddfb827 100644 --- a/nixos/tests/atd.nix +++ b/nixos/tests/atd.nix @@ -17,20 +17,14 @@ import ./make-test.nix ({ pkgs, lib, ... }: startAll; $machine->fail("test -f ~root/at-1"); - $machine->fail("test -f ~root/batch-1"); $machine->fail("test -f ~alice/at-1"); - $machine->fail("test -f ~alice/batch-1"); $machine->succeed("echo 'touch ~root/at-1' | at now+1min"); - $machine->succeed("echo 'touch ~root/batch-1' | batch"); $machine->succeed("su - alice -c \"echo 'touch at-1' | at now+1min\""); - $machine->succeed("su - alice -c \"echo 'touch batch-1' | batch\""); $machine->succeed("sleep 1.5m"); $machine->succeed("test -f ~root/at-1"); - $machine->succeed("test -f ~root/batch-1"); $machine->succeed("test -f ~alice/at-1"); - $machine->succeed("test -f ~alice/batch-1"); ''; }) diff --git a/nixos/tests/borgbackup.nix b/nixos/tests/borgbackup.nix index 123b02be72511..36731773de27e 100644 --- a/nixos/tests/borgbackup.nix +++ b/nixos/tests/borgbackup.nix @@ -1,21 +1,162 @@ -import ./make-test.nix ({ pkgs, ...}: { +import ./make-test.nix ({ pkgs, ... }: + +let + passphrase = "supersecret"; + dataDir = "/ran:dom/data"; + excludeFile = "not_this_file"; + keepFile = "important_file"; + keepFileData = "important_data"; + localRepo = "/root/back:up"; + archiveName = "my_archive"; + remoteRepo = "borg@server:."; # No need to specify path + privateKey = pkgs.writeText "id_ed25519" '' + -----BEGIN OPENSSH PRIVATE KEY----- + b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW + QyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrwAAAJB+cF5HfnBe + RwAAAAtzc2gtZWQyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrw + AAAEBN75NsJZSpt63faCuaD75Unko0JjlSDxMhYHAPJk2/xXHxQHThDpD9/AMWNqQer3Tg + 9gXMb2lTZMn0pelo8xyvAAAADXJzY2h1ZXR6QGt1cnQ= + -----END OPENSSH PRIVATE KEY----- + ''; + publicKey = '' + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHHxQHThDpD9/AMWNqQer3Tg9gXMb2lTZMn0pelo8xyv root@client + ''; + privateKeyAppendOnly = pkgs.writeText "id_ed25519" '' + -----BEGIN OPENSSH PRIVATE KEY----- + b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW + QyNTUxOQAAACBacZuz1ELGQdhI7PF6dGFafCDlvh8pSEc4cHjkW0QjLwAAAJC9YTxxvWE8 + cQAAAAtzc2gtZWQyNTUxOQAAACBacZuz1ELGQdhI7PF6dGFafCDlvh8pSEc4cHjkW0QjLw + AAAEAAhV7wTl5dL/lz+PF/d4PnZXuG1Id6L/mFEiGT1tZsuFpxm7PUQsZB2Ejs8Xp0YVp8 + IOW+HylIRzhweORbRCMvAAAADXJzY2h1ZXR6QGt1cnQ= + -----END OPENSSH PRIVATE KEY----- + ''; + publicKeyAppendOnly = '' + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpxm7PUQsZB2Ejs8Xp0YVp8IOW+HylIRzhweORbRCMv root@client + ''; + +in { name = "borgbackup"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ mic92 ]; + meta = with pkgs.stdenv.lib; { + maintainers = with maintainers; [ dotlambda ]; }; nodes = { - machine = { config, pkgs, ... }: { - environment.systemPackages = [ pkgs.borgbackup ]; + client = { config, pkgs, ... }: { + services.borgbackup.jobs = { + + local = rec { + paths = dataDir; + repo = localRepo; + preHook = '' + # Don't append a timestamp + archiveName="${archiveName}" + ''; + encryption = { + mode = "repokey"; + inherit passphrase; + }; + compression = "auto,zlib,9"; + prune.keep = { + within = "1y"; + yearly = 5; + }; + exclude = [ "*/${excludeFile}" ]; + postHook = "echo post"; + startAt = [ ]; # Do not run automatically + }; + + remote = { + paths = dataDir; + repo = remoteRepo; + encryption.mode = "none"; + startAt = [ ]; + environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519"; + }; + + remoteAppendOnly = { + paths = dataDir; + repo = remoteRepo; + encryption.mode = "none"; + startAt = [ ]; + environment.BORG_RSH = "ssh -oStrictHostKeyChecking=no -i /root/id_ed25519.appendOnly"; + }; + + }; + }; + + server = { config, pkgs, ... }: { + services.openssh = { + enable = true; + passwordAuthentication = false; + challengeResponseAuthentication = false; + }; + + services.borgbackup.repos.repo1 = { + authorizedKeys = [ publicKey ]; + path = "/data/borgbackup"; + }; + + # Second repo to make sure the authorizedKeys options are merged correctly + services.borgbackup.repos.repo2 = { + authorizedKeysAppendOnly = [ publicKeyAppendOnly ]; + path = "/data/borgbackup"; + quota = ".5G"; + }; }; }; testScript = '' - my $borg = "BORG_PASSPHRASE=supersecret borg"; - $machine->succeed("$borg init --encryption=repokey /tmp/backup"); - $machine->succeed("mkdir /tmp/data/ && echo 'data' >/tmp/data/file"); - $machine->succeed("$borg create --stats /tmp/backup::test /tmp/data"); - $machine->succeed("$borg extract /tmp/backup::test"); - $machine->succeed('c=$(cat data/file) && echo "c = $c" >&2 && [[ "$c" == "data" ]]'); + startAll; + + $client->fail('test -d "${remoteRepo}"'); + + $client->succeed("cp ${privateKey} /root/id_ed25519"); + $client->succeed("chmod 0600 /root/id_ed25519"); + $client->succeed("cp ${privateKeyAppendOnly} /root/id_ed25519.appendOnly"); + $client->succeed("chmod 0600 /root/id_ed25519.appendOnly"); + + $client->succeed("mkdir -p ${dataDir}"); + $client->succeed("touch ${dataDir}/${excludeFile}"); + $client->succeed("echo '${keepFileData}' > ${dataDir}/${keepFile}"); + + subtest "local", sub { + my $borg = "BORG_PASSPHRASE='${passphrase}' borg"; + $client->systemctl("start --wait borgbackup-job-local"); + $client->fail("systemctl is-failed borgbackup-job-local"); + # Make sure exactly one archive has been created + $client->succeed("c=\$($borg list '${localRepo}' | wc -l) && [[ \$c == '1' ]]"); + # Make sure excludeFile has been excluded + $client->fail("$borg list '${localRepo}::${archiveName}' | grep -qF '${excludeFile}'"); + # Make sure keepFile has the correct content + $client->succeed("$borg extract '${localRepo}::${archiveName}'"); + $client->succeed('c=$(cat ${dataDir}/${keepFile}) && [[ "$c" == "${keepFileData}" ]]'); + }; + + subtest "remote", sub { + my $borg = "BORG_RSH='ssh -oStrictHostKeyChecking=no -i /root/id_ed25519' borg"; + $server->waitForUnit("sshd.service"); + $client->waitForUnit("network.target"); + $client->systemctl("start --wait borgbackup-job-remote"); + $client->fail("systemctl is-failed borgbackup-job-remote"); + + # Make sure we can't access repos other than the specified one + $client->fail("$borg list borg\@server:wrong"); + + #TODO: Make sure that data is actually deleted + }; + + subtest "remoteAppendOnly", sub { + my $borg = "BORG_RSH='ssh -oStrictHostKeyChecking=no -i /root/id_ed25519.appendOnly' borg"; + $server->waitForUnit("sshd.service"); + $client->waitForUnit("network.target"); + $client->systemctl("start --wait borgbackup-job-remoteAppendOnly"); + $client->fail("systemctl is-failed borgbackup-job-remoteAppendOnly"); + + # Make sure we can't access repos other than the specified one + $client->fail("$borg list borg\@server:wrong"); + + #TODO: Make sure that data is not actually deleted + }; + ''; }) diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix index 3a2c651647667..65c314e22e1d2 100644 --- a/nixos/tests/chromium.nix +++ b/nixos/tests/chromium.nix @@ -151,11 +151,11 @@ mapAttrs (channel: chromiumPkg: makeTest rec { $machine->screenshot("sandbox_info"); - $machine->succeed(ru "${xdo "submit-url" '' + $machine->succeed(ru "${xdo "find-window" '' search --sync --onlyvisible --name "sandbox status" windowfocus --sync ''}"); - $machine->succeed(ru "${xdo "submit-url" '' + $machine->succeed(ru "${xdo "copy-sandbox-info" '' key --delay 1000 Ctrl+a Ctrl+c ''}"); @@ -166,6 +166,26 @@ mapAttrs (channel: chromiumPkg: makeTest rec { && $clipboard =~ /network namespaces.*yes/mi && $clipboard =~ /seccomp.*sandbox.*yes/mi && $clipboard =~ /you are adequately sandboxed/mi; + + $machine->sleep(1); + $machine->succeed(ru "${xdo "find-window-after-copy" '' + search --onlyvisible --name "sandbox status" + ''}"); + + my $clipboard = $machine->succeed(ru "echo void | ${pkgs.xclip}/bin/xclip -i"); + $machine->succeed(ru "${xdo "copy-sandbox-info" '' + key --delay 1000 Ctrl+a Ctrl+c + ''}"); + + my $clipboard = $machine->succeed(ru "${pkgs.xclip}/bin/xclip -o"); + die "copying twice in a row does not work properly: $clipboard" + unless $clipboard =~ /namespace sandbox.*yes/mi + && $clipboard =~ /pid namespaces.*yes/mi + && $clipboard =~ /network namespaces.*yes/mi + && $clipboard =~ /seccomp.*sandbox.*yes/mi + && $clipboard =~ /you are adequately sandboxed/mi; + + $machine->screenshot("afer_copy_from_chromium"); }; $machine->shutdown; diff --git a/nixos/tests/containers-imperative.nix b/nixos/tests/containers-imperative.nix index 7e2a54976387d..20902913e9a7b 100644 --- a/nixos/tests/containers-imperative.nix +++ b/nixos/tests/containers-imperative.nix @@ -20,7 +20,7 @@ import ./make-test.nix ({ pkgs, ...} : { containers.foo.config = {}; }; }; - in [ pkgs.stdenv emptyContainer.config.containers.foo.path ]; + in [ pkgs.stdenv emptyContainer.config.containers.foo.path pkgs.libxslt ]; }; testScript = diff --git a/nixos/tests/containers-physical_interfaces.nix b/nixos/tests/containers-physical_interfaces.nix index bd1228b8e37dc..bde8e175f9532 100644 --- a/nixos/tests/containers-physical_interfaces.nix +++ b/nixos/tests/containers-physical_interfaces.nix @@ -52,7 +52,7 @@ import ./make-test.nix ({ pkgs, ...} : { config = { networking.bonds.bond0 = { interfaces = [ "eth1" ]; - mode = "active-backup"; + driverOptions.mode = "active-backup"; }; networking.interfaces.bond0.ipv4.addresses = [ { address = "10.10.0.3"; prefixLength = 24; } @@ -73,7 +73,7 @@ import ./make-test.nix ({ pkgs, ...} : { config = { networking.bonds.bond0 = { interfaces = [ "eth1" ]; - mode = "active-backup"; + driverOptions.mode = "active-backup"; }; networking.bridges.br0.interfaces = [ "bond0" ]; networking.interfaces.br0.ipv4.addresses = [ diff --git a/nixos/tests/iftop.nix b/nixos/tests/iftop.nix new file mode 100644 index 0000000000000..21ff3cafed7ce --- /dev/null +++ b/nixos/tests/iftop.nix @@ -0,0 +1,30 @@ +import ./make-test.nix ({ pkgs, lib, ... }: + +with lib; + +{ + name = "iftop"; + meta.maintainers = with pkgs.stdenv.lib.maintainers; [ ma27 ]; + + nodes = { + withIftop = { + imports = [ ./common/user-account.nix ]; + + programs.iftop.enable = true; + }; + withoutIftop = { + imports = [ ./common/user-account.nix ]; + }; + }; + + testScript = '' + subtest "machine with iftop enabled", sub { + $withIftop->start; + $withIftop->succeed("su -l alice -c 'iftop -t -s 1'"); + }; + subtest "machine without iftop", sub { + $withoutIftop->start; + $withoutIftop->mustFail("su -l alice -c 'iftop -t -s 1'"); + }; + ''; +}) diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index c12919540a30c..acf248d0a5a66 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -69,13 +69,20 @@ let let iface = if grubVersion == 1 then "ide" else "virtio"; isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi); + + # FIXME don't duplicate the -enable-kvm etc. flags here yet again! qemuFlags = (if system == "x86_64-linux" then "-m 768 " else "-m 512 ") + - (optionalString (system == "x86_64-linux") "-cpu kvm64 "); + (optionalString (system == "x86_64-linux") "-cpu kvm64 ") + + (optionalString (system == "aarch64-linux") "-enable-kvm -machine virt,gic-version=host -cpu host "); + hdFlags = ''hda => "vm-state-machine/machine.qcow2", hdaInterface => "${iface}", '' - + optionalString isEfi ''bios => "${pkgs.OVMF.fd}/FV/OVMF.fd", ''; - in - '' + + optionalString isEfi (if pkgs.stdenv.isAarch64 + then ''bios => "${pkgs.OVMF.fd}/FV/QEMU_EFI.fd", '' + else ''bios => "${pkgs.OVMF.fd}/FV/OVMF.fd", ''); + 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. diff --git a/nixos/tests/kubernetes/certs.nix b/nixos/tests/kubernetes/certs.nix index d3eff910c467f..520c728b65ee2 100644 --- a/nixos/tests/kubernetes/certs.nix +++ b/nixos/tests/kubernetes/certs.nix @@ -6,29 +6,62 @@ kubelets }: let - runWithCFSSL = name: cmd: - builtins.fromJSON (builtins.readFile ( - pkgs.runCommand "${name}-cfss.json" { - buildInputs = [ pkgs.cfssl ]; - } "cfssl ${cmd} > $out" - )); - - writeCFSSL = content: - pkgs.runCommand content.name { - buildInputs = [ pkgs.cfssl ]; - } '' - mkdir -p $out - cd $out - cat ${writeFile content} | cfssljson -bare ${content.name} - ''; + runWithCFSSL = name: cmd: + let secrets = pkgs.runCommand "${name}-cfss.json" { + buildInputs = [ pkgs.cfssl pkgs.jq ]; + outputs = [ "out" "cert" "key" "csr" ]; + } + '' + ( + echo "${cmd}" + cfssl ${cmd} > tmp + cat tmp | jq -r .key > $key + cat tmp | jq -r .cert > $cert + cat tmp | jq -r .csr > $csr + + touch $out + ) 2>&1 | fold -w 80 -s + ''; + in { + key = secrets.key; + cert = secrets.cert; + csr = secrets.csr; + }; + + writeCFSSL = content: + pkgs.runCommand content.name { + buildInputs = [ pkgs.cfssl pkgs.jq ]; + } '' + mkdir -p $out + cd $out + + json=${pkgs.lib.escapeShellArg (builtins.toJSON content)} + + # for a given $field in the $json, treat the associated value as a + # file path and substitute the contents thereof into the $json + # object. + expandFileField() { + local field=$1 + if jq -e --arg field "$field" 'has($field)'; then + local path="$(echo "$json" | jq -r ".$field")" + json="$(echo "$json" | jq --arg val "$(cat "$path")" ".$field = \$val")" + fi + } + + expandFileField key + expandFileField ca + expandFileField cert + + echo "$json" | cfssljson -bare ${content.name} + ''; noCSR = content: pkgs.lib.filterAttrs (n: v: n != "csr") content; noKey = content: pkgs.lib.filterAttrs (n: v: n != "key") content; - writeFile = content: pkgs.writeText "content" ( - if pkgs.lib.isAttrs content then builtins.toJSON content - else toString content - ); + writeFile = content: + if pkgs.lib.isDerivation content + then content + else pkgs.writeText "content" (builtins.toJSON content); createServingCertKey = { ca, cn, hosts? [], size ? 2048, name ? cn }: noCSR ( diff --git a/nixos/tests/kubernetes/e2e.nix b/nixos/tests/kubernetes/e2e.nix index d9d7ba9bb2cc5..175d8413045ed 100644 --- a/nixos/tests/kubernetes/e2e.nix +++ b/nixos/tests/kubernetes/e2e.nix @@ -2,7 +2,7 @@ with import ./base.nix { inherit system; }; let domain = "my.zyx"; - certs = import ./certs.nix { externalDomain = domain; }; + certs = import ./certs.nix { externalDomain = domain; kubelets = ["machine1" "machine2"]; }; kubeconfig = pkgs.writeText "kubeconfig.json" (builtins.toJSON { apiVersion = "v1"; kind = "Config"; diff --git a/nixos/tests/kubernetes/rbac.nix b/nixos/tests/kubernetes/rbac.nix index 1966fed3a5fb9..226808c4b2632 100644 --- a/nixos/tests/kubernetes/rbac.nix +++ b/nixos/tests/kubernetes/rbac.nix @@ -12,7 +12,7 @@ let }); roRoleBinding = pkgs.writeText "ro-role-binding.json" (builtins.toJSON { - apiVersion = "rbac.authorization.k8s.io/v1beta1"; + apiVersion = "rbac.authorization.k8s.io/v1"; kind = "RoleBinding"; metadata = { name = "read-pods"; @@ -31,7 +31,7 @@ let }); roRole = pkgs.writeText "ro-role.json" (builtins.toJSON { - apiVersion = "rbac.authorization.k8s.io/v1beta1"; + apiVersion = "rbac.authorization.k8s.io/v1"; kind = "Role"; metadata = { name = "pod-reader"; diff --git a/nixos/tests/misc.nix b/nixos/tests/misc.nix index 4fd9466dc5027..179c95e764366 100644 --- a/nixos/tests/misc.nix +++ b/nixos/tests/misc.nix @@ -96,7 +96,7 @@ import ./make-test.nix ({ pkgs, ...} : rec { $machine->succeed("systemctl start systemd-udev-settle.service"); subtest "udev-auto-load", sub { $machine->waitForUnit('systemd-udev-settle.service'); - $machine->succeed('lsmod | grep psmouse'); + $machine->succeed('lsmod | grep mousedev'); }; # Test whether systemd-tmpfiles-clean works. diff --git a/nixos/tests/openldap.nix b/nixos/tests/openldap.nix index 1178701c609e9..1eaf87a8eaa85 100644 --- a/nixos/tests/openldap.nix +++ b/nixos/tests/openldap.nix @@ -1,5 +1,5 @@ import ./make-test.nix { - name = "dovecot"; + name = "openldap"; machine = { pkgs, ... }: { services.openldap = { @@ -28,8 +28,8 @@ import ./make-test.nix { }; testScript = '' - $machine->succeed('systemctl status openldap.service'); $machine->waitForUnit('openldap.service'); + $machine->succeed('systemctl status openldap.service'); $machine->succeed('ldapsearch -LLL -D "cn=root,dc=example" -w notapassword -b "dc=example"'); ''; } diff --git a/nixos/tests/prosody.nix b/nixos/tests/prosody.nix new file mode 100644 index 0000000000000..fcebfaf74e126 --- /dev/null +++ b/nixos/tests/prosody.nix @@ -0,0 +1,75 @@ +import ./make-test.nix { + name = "prosody"; + + machine = { config, pkgs, ... }: { + services.prosody = { + enable = true; + # TODO: use a self-signed certificate + c2sRequireEncryption = false; + }; + environment.systemPackages = let + sendMessage = pkgs.writeScriptBin "send-message" '' + #!/usr/bin/env python3 + # Based on the sleekxmpp send_client example, look there for more details: + # https://github.com/fritzy/SleekXMPP/blob/develop/examples/send_client.py + import sleekxmpp + + class SendMsgBot(sleekxmpp.ClientXMPP): + """ + A basic SleekXMPP bot that will log in, send a message, + and then log out. + """ + def __init__(self, jid, password, recipient, message): + sleekxmpp.ClientXMPP.__init__(self, jid, password) + + self.recipient = recipient + self.msg = message + + self.add_event_handler("session_start", self.start, threaded=True) + + def start(self, event): + self.send_presence() + self.get_roster() + + self.send_message(mto=self.recipient, + mbody=self.msg, + mtype='chat') + + self.disconnect(wait=True) + + + if __name__ == '__main__': + xmpp = SendMsgBot("test1@localhost", "test1", "test2@localhost", "Hello World!") + xmpp.register_plugin('xep_0030') # Service Discovery + xmpp.register_plugin('xep_0199') # XMPP Ping + + # TODO: verify certificate + # If you want to verify the SSL certificates offered by a server: + # xmpp.ca_certs = "path/to/ca/cert" + + if xmpp.connect(('localhost', 5222)): + xmpp.process(block=True) + else: + print("Unable to connect.") + sys.exit(1) + ''; + in [ (pkgs.python3.withPackages (ps: [ ps.sleekxmpp ])) sendMessage ]; + }; + + testScript = '' + $machine->waitForUnit('prosody.service'); + $machine->succeed('prosodyctl status') =~ /Prosody is running/; + + # set password to 'test' (it's asked twice) + $machine->succeed('yes test1 | prosodyctl adduser test1@localhost'); + # set password to 'y' + $machine->succeed('yes | prosodyctl adduser test2@localhost'); + # correct password to 'test2' + $machine->succeed('yes test2 | prosodyctl passwd test2@localhost'); + + $machine->succeed("send-message"); + + $machine->succeed('prosodyctl deluser test1@localhost'); + $machine->succeed('prosodyctl deluser test2@localhost'); + ''; +} diff --git a/nixos/tests/transmission.nix b/nixos/tests/transmission.nix new file mode 100644 index 0000000000000..34c49bd7f15b8 --- /dev/null +++ b/nixos/tests/transmission.nix @@ -0,0 +1,21 @@ +import ./make-test.nix ({ pkgs, ...} : { + name = "transmission"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ coconnor ]; + }; + + machine = { config, pkgs, ... }: { + imports = [ ../modules/profiles/minimal.nix ]; + + networking.firewall.allowedTCPPorts = [ 9091 ]; + + services.transmission.enable = true; + }; + + testScript = + '' + startAll; + $machine->waitForUnit("transmission"); + $machine->shutdown; + ''; +}) diff --git a/nixos/tests/vault.nix b/nixos/tests/vault.nix index 2c08d06f286bd..515d5c8bac251 100644 --- a/nixos/tests/vault.nix +++ b/nixos/tests/vault.nix @@ -17,7 +17,7 @@ import ./make-test.nix ({ pkgs, ... }: $machine->waitForUnit('multi-user.target'); $machine->waitForUnit('vault.service'); $machine->waitForOpenPort(8200); - $machine->succeed('vault init'); - $machine->succeed('vault status | grep "Sealed: true"'); + $machine->succeed('vault operator init'); + $machine->succeed('vault status | grep Sealed | grep true'); ''; }) |