diff options
Diffstat (limited to 'nixos')
25 files changed, 589 insertions, 256 deletions
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 7fc0ad702f84..f9de2db1a084 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -5,55 +5,6 @@ with pkgs; let lib = pkgs.lib; - # Remove invisible and internal options. - optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options); - - # Replace functions by the string <function> - substFunction = x: - if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x - else if builtins.isList x then map substFunction x - else if lib.isFunction x then "<function>" - else x; - - # Generate DocBook documentation for a list of packages. This is - # what `relatedPackages` option of `mkOption` from - # ../../../lib/options.nix influences. - # - # Each element of `relatedPackages` can be either - # - a string: that will be interpreted as an attribute name from `pkgs`, - # - a list: that will be interpreted as an attribute path from `pkgs`, - # - an attrset: that can specify `name`, `path`, `package`, `comment` - # (either of `name`, `path` is required, the rest are optional). - genRelatedPackages = packages: - let - unpack = p: if lib.isString p then { name = p; } - else if lib.isList p then { path = p; } - else p; - describe = args: - let - title = args.title or null; - name = args.name or (lib.concatStringsSep "." args.path); - path = args.path or [ args.name ]; - package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs); - in "<listitem>" - + "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>" - + lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>" - + ": ${package.meta.description or "???"}.</para>" - + lib.optionalString (args ? comment) "\n<para>${args.comment}</para>" - # Lots of `longDescription's break DocBook, so we just wrap them into <programlisting> - + lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>" - + "</listitem>"; - in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>"; - - optionsListDesc = lib.flip map optionsListVisible (opt: opt // { - # Clean up declaration sites to not refer to the NixOS source tree. - declarations = map stripAnyPrefixes opt.declarations; - } - // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; } - // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; } - // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; } - // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; }); - # We need to strip references to /nix/store/* from options, # including any `extraSources` if some modules came from elsewhere, # or else the build will fail. @@ -63,37 +14,13 @@ let prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources); stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip; - # Custom "less" that pushes up all the things ending in ".enable*" - # and ".package*" - optionLess = a: b: - let - ise = lib.hasPrefix "enable"; - isp = lib.hasPrefix "package"; - cmp = lib.splitByAndCompare ise lib.compare - (lib.splitByAndCompare isp lib.compare lib.compare); - in lib.compareLists cmp a.loc b.loc < 0; - - # Customly sort option list for the man page. - optionsList = lib.sort optionLess optionsListDesc; - - # Convert the list of options into an XML file. - optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList); - - optionsDocBook = runCommand "options-db.xml" {} '' - optionsXML=${optionsXML} - if grep /nixpkgs/nixos/modules $optionsXML; then - echo "The manual appears to depend on the location of Nixpkgs, which is bad" - echo "since this prevents sharing via the NixOS channel. This is typically" - echo "caused by an option default that refers to a relative path (see above" - echo "for hints about the offending path)." - exit 1 - fi - ${buildPackages.libxslt.bin}/bin/xsltproc \ - --stringparam revision '${revision}' \ - -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML - ${buildPackages.libxslt.bin}/bin/xsltproc \ - -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml - ''; + optionsDoc = buildPackages.nixosOptionsDoc { + inherit options revision; + transformOptions = opt: opt // { + # Clean up declaration sites to not refer to the NixOS source tree. + declarations = map stripAnyPrefixes opt.declarations; + }; + }; sources = lib.sourceFilesBySuffices ./. [".xml"]; @@ -108,7 +35,7 @@ let generatedSources = runCommand "generated-docbook" {} '' mkdir $out ln -s ${modulesDoc} $out/modules.xml - ln -s ${optionsDocBook} $out/options-db.xml + ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml printf "%s" "${version}" > $out/version ''; @@ -234,22 +161,7 @@ let in rec { inherit generatedSources; - # The NixOS options in JSON format. - optionsJSON = runCommand "options-json" - { meta.description = "List of NixOS options in JSON format"; - } - '' - # Export list of options in different format. - dst=$out/share/doc/nixos - mkdir -p $dst - - cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON - (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList)))) - } $dst/options.json - - mkdir -p $out/nix-support - echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products - ''; # */ + inherit (optionsDoc) optionsJSON optionsXML optionsDocBook; # Generate the NixOS manual. manualHTML = runCommand "nixos-manual-html" diff --git a/nixos/lib/make-options-doc/default.nix b/nixos/lib/make-options-doc/default.nix new file mode 100644 index 000000000000..c22c7500335d --- /dev/null +++ b/nixos/lib/make-options-doc/default.nix @@ -0,0 +1,125 @@ +/* Generate JSON, XML and DocBook documentation for given NixOS options. + + Minimal example: + + { pkgs, }: + + let + eval = import (pkgs.path + "/nixos/lib/eval-config.nix") { + baseModules = [ + ../module.nix + ]; + modules = []; + }; + in pkgs.nixosOptionsDoc { + options = eval.options; + } + +*/ +{ pkgs +, lib +, options +, transformOptions ? lib.id # function for additional tranformations of the options +, revision ? "" # Specify revision for the options +}: + +let + # Replace functions by the string <function> + substFunction = x: + if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x + else if builtins.isList x then map substFunction x + else if lib.isFunction x then "<function>" + else x; + + optionsListDesc = lib.flip map optionsListVisible + (opt: transformOptions opt + // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; } + // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; } + // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; } + // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; } + ); + + # Generate DocBook documentation for a list of packages. This is + # what `relatedPackages` option of `mkOption` from + # ../../../lib/options.nix influences. + # + # Each element of `relatedPackages` can be either + # - a string: that will be interpreted as an attribute name from `pkgs`, + # - a list: that will be interpreted as an attribute path from `pkgs`, + # - an attrset: that can specify `name`, `path`, `package`, `comment` + # (either of `name`, `path` is required, the rest are optional). + genRelatedPackages = packages: + let + unpack = p: if lib.isString p then { name = p; } + else if lib.isList p then { path = p; } + else p; + describe = args: + let + title = args.title or null; + name = args.name or (lib.concatStringsSep "." args.path); + path = args.path or [ args.name ]; + package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs); + in "<listitem>" + + "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>" + + lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>" + + ": ${package.meta.description or "???"}.</para>" + + lib.optionalString (args ? comment) "\n<para>${args.comment}</para>" + # Lots of `longDescription's break DocBook, so we just wrap them into <programlisting> + + lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>" + + "</listitem>"; + in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>"; + + # Custom "less" that pushes up all the things ending in ".enable*" + # and ".package*" + optionLess = a: b: + let + ise = lib.hasPrefix "enable"; + isp = lib.hasPrefix "package"; + cmp = lib.splitByAndCompare ise lib.compare + (lib.splitByAndCompare isp lib.compare lib.compare); + in lib.compareLists cmp a.loc b.loc < 0; + + # Remove invisible and internal options. + optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options); + + # Customly sort option list for the man page. + optionsList = lib.sort optionLess optionsListDesc; + + # Convert the list of options into an XML file. + optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList); + +in rec { + # The NixOS options in JSON format. + optionsJSON = pkgs.runCommand "options.json" + { meta.description = "List of NixOS options in JSON format"; + } + '' + # Export list of options in different format. + dst=$out/share/doc/nixos + mkdir -p $dst + + cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON + (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList)))) + } $dst/options.json + + mkdir -p $out/nix-support + echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products + ''; # */ + + optionsDocBook = pkgs.runCommand "options-docbook.xml" {} '' + optionsXML=${optionsXML} + if grep /nixpkgs/nixos/modules $optionsXML; then + echo "The manual appears to depend on the location of Nixpkgs, which is bad" + echo "since this prevents sharing via the NixOS channel. This is typically" + echo "caused by an option default that refers to a relative path (see above" + echo "for hints about the offending path)." + exit 1 + fi + + ${pkgs.libxslt.bin}/bin/xsltproc \ + --stringparam revision '${revision}' \ + -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML + ${pkgs.libxslt.bin}/bin/xsltproc \ + -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml + ''; +} diff --git a/nixos/doc/manual/options-to-docbook.xsl b/nixos/lib/make-options-doc/options-to-docbook.xsl index 72ac89d4ff62..72ac89d4ff62 100644 --- a/nixos/doc/manual/options-to-docbook.xsl +++ b/nixos/lib/make-options-doc/options-to-docbook.xsl diff --git a/nixos/doc/manual/postprocess-option-descriptions.xsl b/nixos/lib/make-options-doc/postprocess-option-descriptions.xsl index 1201c7612c2e..1201c7612c2e 100644 --- a/nixos/doc/manual/postprocess-option-descriptions.xsl +++ b/nixos/lib/make-options-doc/postprocess-option-descriptions.xsl diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index e0c192246c0c..afb74581e239 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -19,7 +19,7 @@ let lhs = optCall lhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; }; in - lhs // rhs // + recursiveUpdate lhs rhs // optionalAttrs (lhs ? packageOverrides) { packageOverrides = pkgs: optCall lhs.packageOverrides pkgs // diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index df453aac9fef..c775345ba4c0 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -106,9 +106,14 @@ ./programs/digitalbitbox/default.nix ./programs/dmrconfig.nix ./programs/environment.nix + ./programs/evince.nix + ./programs/file-roller.nix ./programs/firejail.nix ./programs/fish.nix ./programs/freetds.nix + ./programs/gnome-disks.nix + ./programs/gnome-documents.nix + ./programs/gpaste.nix ./programs/gnupg.nix ./programs/gphoto2.nix ./programs/iftop.nix @@ -209,6 +214,7 @@ ./services/backup/duplicity.nix ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix + ./services/backup/postgresql-wal-receiver.nix ./services/backup/restic.nix ./services/backup/restic-rest-server.nix ./services/backup/rsnapshot.nix @@ -280,12 +286,8 @@ ./services/desktops/pipewire.nix ./services/desktops/gnome3/at-spi2-core.nix ./services/desktops/gnome3/chrome-gnome-shell.nix - ./services/desktops/gnome3/evince.nix ./services/desktops/gnome3/evolution-data-server.nix - ./services/desktops/gnome3/file-roller.nix ./services/desktops/gnome3/glib-networking.nix - ./services/desktops/gnome3/gnome-disks.nix - ./services/desktops/gnome3/gnome-documents.nix ./services/desktops/gnome3/gnome-keyring.nix ./services/desktops/gnome3/gnome-online-accounts.nix ./services/desktops/gnome3/gnome-remote-desktop.nix @@ -293,7 +295,6 @@ ./services/desktops/gnome3/gnome-settings-daemon.nix ./services/desktops/gnome3/gnome-terminal-server.nix ./services/desktops/gnome3/gnome-user-share.nix - ./services/desktops/gnome3/gpaste.nix ./services/desktops/gnome3/gvfs.nix ./services/desktops/gnome3/rygel.nix ./services/desktops/gnome3/seahorse.nix diff --git a/nixos/modules/services/desktops/gnome3/evince.nix b/nixos/modules/programs/evince.nix index 5f040a16f067..473fddb09d02 100644 --- a/nixos/modules/services/desktops/gnome3/evince.nix +++ b/nixos/modules/programs/evince.nix @@ -6,14 +6,21 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "evince" "enable" ] + [ "programs" "evince" "enable" ]) + ]; + ###### interface options = { - services.gnome3.evince = { + programs.evince = { enable = mkEnableOption - "systemd and dbus services for Evince, the GNOME document viewer"; + "Evince, the GNOME document viewer"; }; @@ -22,7 +29,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.evince.enable { + config = mkIf config.programs.evince.enable { environment.systemPackages = [ pkgs.evince ]; diff --git a/nixos/modules/services/desktops/gnome3/file-roller.nix b/nixos/modules/programs/file-roller.nix index 7fb558a98953..64f6a94e7641 100644 --- a/nixos/modules/services/desktops/gnome3/file-roller.nix +++ b/nixos/modules/programs/file-roller.nix @@ -6,11 +6,18 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "file-roller" "enable" ] + [ "programs" "file-roller" "enable" ]) + ]; + ###### interface options = { - services.gnome3.file-roller = { + programs.file-roller = { enable = mkEnableOption "File Roller, an archive manager for GNOME"; @@ -21,7 +28,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.file-roller.enable { + config = mkIf config.programs.file-roller.enable { environment.systemPackages = [ pkgs.gnome3.file-roller ]; diff --git a/nixos/modules/services/desktops/gnome3/gnome-disks.nix b/nixos/modules/programs/gnome-disks.nix index 139534cdb892..1cf839a6ddb0 100644 --- a/nixos/modules/services/desktops/gnome3/gnome-disks.nix +++ b/nixos/modules/programs/gnome-disks.nix @@ -1,4 +1,4 @@ -# GNOME Disks daemon. +# GNOME Disks. { config, pkgs, lib, ... }: @@ -6,17 +6,24 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "gnome-disks" "enable" ] + [ "programs" "gnome-disks" "enable" ]) + ]; + ###### interface options = { - services.gnome3.gnome-disks = { + programs.gnome-disks = { enable = mkOption { type = types.bool; default = false; description = '' - Whether to enable GNOME Disks daemon, a service designed to + Whether to enable GNOME Disks daemon, a program designed to be a UDisks2 graphical front-end. ''; }; @@ -28,7 +35,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.gnome-disks.enable { + config = mkIf config.programs.gnome-disks.enable { environment.systemPackages = [ pkgs.gnome3.gnome-disk-utility ]; diff --git a/nixos/modules/services/desktops/gnome3/gnome-documents.nix b/nixos/modules/programs/gnome-documents.nix index f6efb6684240..bfa3d409ee30 100644 --- a/nixos/modules/services/desktops/gnome3/gnome-documents.nix +++ b/nixos/modules/programs/gnome-documents.nix @@ -1,4 +1,4 @@ -# GNOME Documents daemon. +# GNOME Documents. { config, pkgs, lib, ... }: @@ -6,17 +6,24 @@ with lib; { + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "gnome-documents" "enable" ] + [ "programs" "gnome-documents" "enable" ]) + ]; + ###### interface options = { - services.gnome3.gnome-documents = { + programs.gnome-documents = { enable = mkOption { type = types.bool; default = false; description = '' - Whether to enable GNOME Documents services, a document + Whether to enable GNOME Documents, a document manager application for GNOME. ''; }; @@ -28,7 +35,7 @@ with lib; ###### implementation - config = mkIf config.services.gnome3.gnome-documents.enable { + config = mkIf config.programs.gnome-documents.enable { environment.systemPackages = [ pkgs.gnome3.gnome-documents ]; diff --git a/nixos/modules/services/desktops/gnome3/gpaste.nix b/nixos/modules/programs/gpaste.nix index 5a8258775e0a..4f6deb77e5eb 100644 --- a/nixos/modules/services/desktops/gnome3/gpaste.nix +++ b/nixos/modules/programs/gpaste.nix @@ -1,12 +1,20 @@ -# GPaste daemon. +# GPaste. { config, lib, pkgs, ... }: with lib; { + + # Added 2019-08-09 + imports = [ + (mkRenamedOptionModule + [ "services" "gnome3" "gpaste" "enable" ] + [ "programs" "gpaste" "enable" ]) + ]; + ###### interface options = { - services.gnome3.gpaste = { + programs.gpaste = { enable = mkOption { type = types.bool; default = false; @@ -18,10 +26,9 @@ with lib; }; ###### implementation - config = mkIf config.services.gnome3.gpaste.enable { + config = mkIf config.programs.gpaste.enable { environment.systemPackages = [ pkgs.gnome3.gpaste ]; services.dbus.packages = [ pkgs.gnome3.gpaste ]; - services.xserver.desktopManager.gnome3.sessionPath = [ pkgs.gnome3.gpaste ]; systemd.packages = [ pkgs.gnome3.gpaste ]; }; } diff --git a/nixos/modules/programs/nylas-mail.nix b/nixos/modules/programs/nylas-mail.nix deleted file mode 100644 index 08a6cd0a6049..000000000000 --- a/nixos/modules/programs/nylas-mail.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.nylas-mail; -in { - ###### interface - options = { - services.nylas-mail = { - - enable = mkEnableOption '' - nylas-mail - Open-source mail client built on the modern web with Electron, React, and Flux - ''; - - gnome3-keyring = mkOption { - type = types.bool; - default = true; - description = "Enable gnome3 keyring for nylas-mail."; - }; - }; - }; - - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ pkgs.nylas-mail-bin ]; - - services.gnome3.gnome-keyring = mkIf cfg.gnome3-keyring { - enable = true; - }; - - }; -} diff --git a/nixos/modules/services/backup/postgresql-wal-receiver.nix b/nixos/modules/services/backup/postgresql-wal-receiver.nix new file mode 100644 index 000000000000..d9a37037992e --- /dev/null +++ b/nixos/modules/services/backup/postgresql-wal-receiver.nix @@ -0,0 +1,203 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + receiverSubmodule = { + options = { + postgresqlPackage = mkOption { + type = types.package; + example = literalExample "pkgs.postgresql_11"; + description = '' + PostgreSQL package to use. + ''; + }; + + directory = mkOption { + type = types.path; + example = literalExample "/mnt/pg_wal/main/"; + description = '' + Directory to write the output to. + ''; + }; + + statusInterval = mkOption { + type = types.int; + default = 10; + description = '' + Specifies the number of seconds between status packets sent back to the server. + This allows for easier monitoring of the progress from server. + A value of zero disables the periodic status updates completely, + although an update will still be sent when requested by the server, to avoid timeout disconnect. + ''; + }; + + slot = mkOption { + type = types.str; + default = ""; + example = "some_slot_name"; + description = '' + Require <command>pg_receivewal</command> to use an existing replication slot (see + <link xlink:href="https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION-SLOTS">Section 26.2.6 of the PostgreSQL manual</link>). + When this option is used, <command>pg_receivewal</command> will report a flush position to the server, + indicating when each segment has been synchronized to disk so that the server can remove that segment if it is not otherwise needed. + + When the replication client of <command>pg_receivewal</command> is configured on the server as a synchronous standby, + then using a replication slot will report the flush position to the server, but only when a WAL file is closed. + Therefore, that configuration will cause transactions on the primary to wait for a long time and effectively not work satisfactorily. + The option <option>synchronous</option> must be specified in addition to make this work correctly. + ''; + }; + + synchronous = mkOption { + type = types.bool; + default = false; + description = '' + Flush the WAL data to disk immediately after it has been received. + Also send a status packet back to the server immediately after flushing, regardless of <option>statusInterval</option>. + + This option should be specified if the replication client of <command>pg_receivewal</command> is configured on the server as a synchronous standby, + to ensure that timely feedback is sent to the server. + ''; + }; + + compress = mkOption { + type = types.ints.between 0 9; + default = 0; + description = '' + Enables gzip compression of write-ahead logs, and specifies the compression level + (<literal>0</literal> through <literal>9</literal>, <literal>0</literal> being no compression and <literal>9</literal> being best compression). + The suffix <literal>.gz</literal> will automatically be added to all filenames. + + This option requires PostgreSQL >= 10. + ''; + }; + + connection = mkOption { + type = types.str; + example = "postgresql://user@somehost"; + description = '' + Specifies parameters used to connect to the server, as a connection string. + See <link xlink:href="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING">Section 34.1.1 of the PostgreSQL manual</link> for more information. + + Because <command>pg_receivewal</command> doesn't connect to any particular database in the cluster, + database name in the connection string will be ignored. + ''; + }; + + extraArgs = mkOption { + type = with types; listOf str; + default = [ ]; + example = literalExample '' + [ + "--no-sync" + ] + ''; + description = '' + A list of extra arguments to pass to the <command>pg_receivewal</command> command. + ''; + }; + + environment = mkOption { + type = with types; attrsOf str; + default = { }; + example = literalExample '' + { + PGPASSFILE = "/private/passfile"; + PGSSLMODE = "require"; + } + ''; + description = '' + Environment variables passed to the service. + Usable parameters are listed in <link xlink:href="https://www.postgresql.org/docs/current/libpq-envars.html">Section 34.14 of the PostgreSQL manual</link>. + ''; + }; + }; + }; + +in { + options = { + services.postgresqlWalReceiver = { + receivers = mkOption { + type = with types; attrsOf (submodule receiverSubmodule); + default = { }; + example = literalExample '' + { + main = { + postgresqlPackage = pkgs.postgresql_11; + directory = /mnt/pg_wal/main/; + slot = "main_wal_receiver"; + connection = "postgresql://user@somehost"; + }; + } + ''; + description = '' + PostgreSQL WAL receivers. + Stream write-ahead logs from a PostgreSQL server using <command>pg_receivewal</command> (formerly <command>pg_receivexlog</command>). + See <link xlink:href="https://www.postgresql.org/docs/current/app-pgreceivewal.html">the man page</link> for more information. + ''; + }; + }; + }; + + config = let + receivers = config.services.postgresqlWalReceiver.receivers; + in mkIf (receivers != { }) { + users = { + users.postgres = { + uid = config.ids.uids.postgres; + group = "postgres"; + description = "PostgreSQL server user"; + }; + + groups.postgres = { + gid = config.ids.gids.postgres; + }; + }; + + assertions = concatLists (attrsets.mapAttrsToList (name: config: [ + { + assertion = config.compress > 0 -> versionAtLeast config.postgresqlPackage.version "10"; + message = "Invalid configuration for WAL receiver \"${name}\": compress requires PostgreSQL version >= 10."; + } + ]) receivers); + + systemd.tmpfiles.rules = mapAttrsToList (name: config: '' + d ${escapeShellArg config.directory} 0750 postgres postgres - - + '') receivers; + + systemd.services = with attrsets; mapAttrs' (name: config: nameValuePair "postgresql-wal-receiver-${name}" { + description = "PostgreSQL WAL receiver (${name})"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "postgres"; + Group = "postgres"; + KillSignal = "SIGINT"; + Restart = "always"; + RestartSec = 30; + }; + + inherit (config) environment; + + script = let + receiverCommand = postgresqlPackage: + if (versionAtLeast postgresqlPackage.version "10") + then "${postgresqlPackage}/bin/pg_receivewal" + else "${postgresqlPackage}/bin/pg_receivexlog"; + in '' + ${receiverCommand config.postgresqlPackage} \ + --no-password \ + --directory=${escapeShellArg config.directory} \ + --status-interval=${toString config.statusInterval} \ + --dbname=${escapeShellArg config.connection} \ + ${optionalString (config.compress > 0) "--compress=${toString config.compress}"} \ + ${optionalString (config.slot != "") "--slot=${escapeShellArg config.slot}"} \ + ${optionalString config.synchronous "--synchronous"} \ + ${concatStringsSep " " config.extraArgs} + ''; + }) receivers; + }; + + meta.maintainers = with maintainers; [ pacien ]; +} diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix index 5ddf8ba4bfbd..77e404116c8a 100644 --- a/nixos/modules/services/databases/couchdb.nix +++ b/nixos/modules/services/databases/couchdb.nix @@ -160,7 +160,7 @@ in { systemd.tmpfiles.rules = [ "d '${dirOf cfg.uriFile}' - ${cfg.user} ${cfg.group} - -" - "d '${dirOf cfg.logFile}' - ${cfg.user} ${cfg.group} - -" + "f '${cfg.logFile}' - ${cfg.user} ${cfg.group} - -" "d '${cfg.databaseDir}' - ${cfg.user} ${cfg.group} - -" "d '${cfg.viewIndexDir}' - ${cfg.user} ${cfg.group} - -" ]; @@ -169,11 +169,9 @@ in { description = "CouchDB Server"; wantedBy = [ "multi-user.target" ]; - preStart = - '' + preStart = '' touch ${cfg.configFile} - touch -a ${cfg.logFile} - ''; + ''; environment = mkIf useVersion2 { # we are actually specifying 4 configuration files: diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index 7ff899970ccd..10250bb5193a 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -330,13 +330,13 @@ in fi '' + optionalString (cfg.ensureDatabases != []) '' ${concatMapStrings (database: '' - $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc "CREATE DATABASE ${database}" + $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${database}"' '') cfg.ensureDatabases} '' + '' ${concatMapStrings (user: '' $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc "CREATE USER ${user.name}" ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' - $PSQL -tAc "GRANT ${permission} ON ${database} TO ${user.name}" + $PSQL -tAc 'GRANT ${permission} ON ${database} TO ${user.name}' '') user.ensurePermissions)} '') cfg.ensureUsers} ''; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index c2f6b585d493..bf1084eecc3a 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -503,12 +503,12 @@ in { message = "Cannot set both adminPassword and adminPasswordFile"; } { - assertion = cfg.security.secretKeyFile != opt.security.secretKeyFile.default -> cfg.security.secretKeyFile == null; + assertion = cfg.security.secretKey != opt.security.secretKey.default -> cfg.security.secretKeyFile == null; message = "Cannot set both secretKey and secretKeyFile"; } { assertion = cfg.smtp.password != opt.smtp.password.default -> cfg.smtp.passwordFile == null; - message = "Cannot set both password and secretKeyFile"; + message = "Cannot set both password and passwordFile"; } ]; diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index cd7502421255..5e1e652a5089 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -123,12 +123,8 @@ in { services.dleyna-renderer.enable = mkDefault true; services.dleyna-server.enable = mkDefault true; services.gnome3.at-spi2-core.enable = true; - services.gnome3.evince.enable = mkDefault true; services.gnome3.evolution-data-server.enable = true; - services.gnome3.file-roller.enable = mkDefault true; services.gnome3.glib-networking.enable = true; - services.gnome3.gnome-disks.enable = mkDefault true; - services.gnome3.gnome-documents.enable = mkDefault true; services.gnome3.gnome-keyring.enable = true; services.gnome3.gnome-online-accounts.enable = mkDefault true; services.gnome3.gnome-remote-desktop.enable = mkDefault true; @@ -157,6 +153,12 @@ in { xdg.portal.enable = true; xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + # Enable default programs + programs.evince.enable = mkDefault true; + programs.file-roller.enable = mkDefault true; + programs.gnome-disks.enable = mkDefault true; + programs.gnome-documents.enable = mkDefault true; + # If gnome3 is installed, build vim for gtk3 too. nixpkgs.config.vim.gui = "gtk3"; diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index b9a9515f94ef..7146aebf54be 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -68,8 +68,9 @@ in rec { nixos.tests.chromium.x86_64-linux or [] (all nixos.tests.firefox) (all nixos.tests.firewall) - (except ["aarch64-linux"] nixos.tests.gnome3) - (except ["aarch64-linux"] nixos.tests.pantheon) + (all nixos.tests.gnome3-xorg) + (all nixos.tests.gnome3) + (all nixos.tests.pantheon) nixos.tests.installer.zfsroot.x86_64-linux or [] # ZFS is 64bit only (except ["aarch64-linux"] nixos.tests.installer.lvm) (except ["aarch64-linux"] nixos.tests.installer.luksroot) @@ -103,7 +104,7 @@ in rec { #(all nixos.tests.keymap.neo) #(all nixos.tests.keymap.qwertz) (all nixos.tests.plasma5) - #(all nixos.tests.lightdm) + (all nixos.tests.lightdm) (all nixos.tests.login) (all nixos.tests.misc) (all nixos.tests.mutableUsers) diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 25dd9f3f4283..c24c8ae61a58 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -56,7 +56,7 @@ in containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {}; containers-restart_networking = handleTest ./containers-restart_networking.nix {}; containers-tmpfs = handleTest ./containers-tmpfs.nix {}; - #couchdb = handleTest ./couchdb.nix {}; # spidermonkey-1.8.5 is marked as broken + couchdb = handleTest ./couchdb.nix {}; deluge = handleTest ./deluge.nix {}; dhparams = handleTest ./dhparams.nix {}; dnscrypt-proxy = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy.nix {}; @@ -93,8 +93,8 @@ in gitlab = handleTest ./gitlab.nix {}; gitolite = handleTest ./gitolite.nix {}; gjs = handleTest ./gjs.nix {}; - gnome3 = handleTestOn ["x86_64-linux"] ./gnome3.nix {}; # libsmbios is unsupported on aarch64 - gnome3-gdm = handleTestOn ["x86_64-linux"] ./gnome3-gdm.nix {}; # libsmbios is unsupported on aarch64 + gnome3-xorg = handleTest ./gnome3-xorg.nix {}; + gnome3 = handleTest ./gnome3.nix {}; gocd-agent = handleTest ./gocd-agent.nix {}; gocd-server = handleTest ./gocd-server.nix {}; google-oslogin = handleTest ./google-oslogin {}; @@ -139,7 +139,7 @@ in ldap = handleTest ./ldap.nix {}; leaps = handleTest ./leaps.nix {}; lidarr = handleTest ./lidarr.nix {}; - #lightdm = handleTest ./lightdm.nix {}; + lightdm = handleTest ./lightdm.nix {}; limesurvey = handleTest ./limesurvey.nix {}; login = handleTest ./login.nix {}; loki = handleTest ./loki.nix {}; @@ -210,6 +210,7 @@ in plotinus = handleTest ./plotinus.nix {}; postgis = handleTest ./postgis.nix {}; postgresql = handleTest ./postgresql.nix {}; + postgresql-wal-receiver = handleTest ./postgresql-wal-receiver.nix {}; powerdns = handleTest ./powerdns.nix {}; predictable-interface-names = handleTest ./predictable-interface-names.nix {}; printing = handleTest ./printing.nix {}; diff --git a/nixos/tests/gnome3-gdm.nix b/nixos/tests/gnome3-gdm.nix deleted file mode 100644 index c2808d87d99d..000000000000 --- a/nixos/tests/gnome3-gdm.nix +++ /dev/null @@ -1,63 +0,0 @@ -import ./make-test.nix ({ pkgs, ...} : { - name = "gnome3-gdm"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ lethalman ]; - }; - - machine = - { ... }: - - { imports = [ ./common/user-account.nix ]; - - services.xserver.enable = true; - - services.xserver.displayManager.gdm = { - enable = true; - autoLogin = { - enable = true; - user = "alice"; - }; - }; - services.xserver.desktopManager.gnome3.enable = true; - - virtualisation.memorySize = 1024; - }; - - testScript = let - # Keep line widths somewhat managable - bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"; - gdbus = "${bus} gdbus"; - # Call javascript in gnome shell, returns a tuple (success, output), where - # `success` is true if the dbus call was successful and output is what the - # javascript evaluates to. - eval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval"; - # False when startup is done - startingUp = "${gdbus} ${eval} Main.layoutManager._startingUp"; - # Hopefully gnome-terminal's wm class - wmClass = "${gdbus} ${eval} global.display.focus_window.wm_class"; - in '' - # wait for gdm to start - $machine->waitForUnit("display-manager.service"); - - # wait for alice to be logged in - $machine->waitForUnit("default.target","alice"); - - # Check that logging in has given the user ownership of devices. - $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); - - # Wait for the wayland server - $machine->waitForFile("/run/user/1000/wayland-0"); - - # Wait for gnome shell, correct output should be "(true, 'false')" - $machine->waitUntilSucceeds("su - alice -c '${startingUp} | grep -q true,..false'"); - - # open a terminal - $machine->succeed("su - alice -c '${bus} gnome-terminal'"); - # and check it's there - $machine->waitUntilSucceeds("su - alice -c '${wmClass} | grep -q gnome-terminal-server'"); - - # wait to get a nice screenshot - $machine->sleep(20); - $machine->screenshot("screen"); - ''; -}) diff --git a/nixos/tests/gnome3-xorg.nix b/nixos/tests/gnome3-xorg.nix new file mode 100644 index 000000000000..f12361da0372 --- /dev/null +++ b/nixos/tests/gnome3-xorg.nix @@ -0,0 +1,41 @@ +import ./make-test.nix ({ pkgs, ...} : { + name = "gnome3-xorg"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = pkgs.gnome3.maintainers; + }; + + machine = + { ... }: + + { imports = [ ./common/user-account.nix ]; + + services.xserver.enable = true; + + services.xserver.displayManager.gdm.enable = false; + services.xserver.displayManager.lightdm.enable = true; + services.xserver.displayManager.lightdm.autoLogin.enable = true; + services.xserver.displayManager.lightdm.autoLogin.user = "alice"; + services.xserver.desktopManager.gnome3.enable = true; + services.xserver.desktopManager.default = "gnome-xorg"; + + virtualisation.memorySize = 1024; + }; + + testScript = + '' + $machine->waitForX; + + # wait for alice to be logged in + $machine->waitForUnit("default.target","alice"); + + # Check that logging in has given the user ownership of devices. + $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); + + $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'"); + $machine->succeed("xauth merge ~alice/.Xauthority"); + $machine->waitForWindow(qr/alice.*machine/); + $machine->succeed("timeout 900 bash -c 'while read msg; do if [[ \$msg =~ \"GNOME Shell started\" ]]; then break; fi; done < <(journalctl -f)'"); + $machine->sleep(10); + $machine->screenshot("screen"); + ''; +}) diff --git a/nixos/tests/gnome3.nix b/nixos/tests/gnome3.nix index b58c9e5a0e32..b6fe602a7327 100644 --- a/nixos/tests/gnome3.nix +++ b/nixos/tests/gnome3.nix @@ -1,7 +1,7 @@ import ./make-test.nix ({ pkgs, ...} : { name = "gnome3"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ domenkozar eelco lethalman ]; + maintainers = pkgs.gnome3.maintainers; }; machine = @@ -11,19 +11,34 @@ import ./make-test.nix ({ pkgs, ...} : { services.xserver.enable = true; - services.xserver.displayManager.gdm.enable = false; - services.xserver.displayManager.lightdm.enable = true; - services.xserver.displayManager.lightdm.autoLogin.enable = true; - services.xserver.displayManager.lightdm.autoLogin.user = "alice"; + services.xserver.displayManager.gdm = { + enable = true; + autoLogin = { + enable = true; + user = "alice"; + }; + }; + services.xserver.desktopManager.gnome3.enable = true; - services.xserver.desktopManager.default = "gnome-xorg"; virtualisation.memorySize = 1024; }; - testScript = - '' - $machine->waitForX; + testScript = let + # Keep line widths somewhat managable + bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"; + gdbus = "${bus} gdbus"; + # Call javascript in gnome shell, returns a tuple (success, output), where + # `success` is true if the dbus call was successful and output is what the + # javascript evaluates to. + eval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval"; + # False when startup is done + startingUp = "${gdbus} ${eval} Main.layoutManager._startingUp"; + # Hopefully gnome-terminal's wm class + wmClass = "${gdbus} ${eval} global.display.focus_window.wm_class"; + in '' + # wait for gdm to start + $machine->waitForUnit("display-manager.service"); # wait for alice to be logged in $machine->waitForUnit("default.target","alice"); @@ -31,11 +46,19 @@ import ./make-test.nix ({ pkgs, ...} : { # Check that logging in has given the user ownership of devices. $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); - $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'"); - $machine->succeed("xauth merge ~alice/.Xauthority"); - $machine->waitForWindow(qr/alice.*machine/); - $machine->succeed("timeout 900 bash -c 'while read msg; do if [[ \$msg =~ \"GNOME Shell started\" ]]; then break; fi; done < <(journalctl -f)'"); - $machine->sleep(10); + # Wait for the wayland server + $machine->waitForFile("/run/user/1000/wayland-0"); + + # Wait for gnome shell, correct output should be "(true, 'false')" + $machine->waitUntilSucceeds("su - alice -c '${startingUp} | grep -q true,..false'"); + + # open a terminal + $machine->succeed("su - alice -c '${bus} gnome-terminal'"); + # and check it's there + $machine->waitUntilSucceeds("su - alice -c '${wmClass} | grep -q gnome-terminal-server'"); + + # wait to get a nice screenshot + $machine->sleep(20); $machine->screenshot("screen"); ''; }) diff --git a/nixos/tests/lightdm.nix b/nixos/tests/lightdm.nix index 8a9a7408d292..c805f1ed9f3c 100644 --- a/nixos/tests/lightdm.nix +++ b/nixos/tests/lightdm.nix @@ -1,7 +1,7 @@ import ./make-test.nix ({ pkgs, ...} : { name = "lightdm"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ aszlig ]; + maintainers = [ aszlig worldofpeace ]; }; machine = { ... }: { diff --git a/nixos/tests/postgresql-wal-receiver.nix b/nixos/tests/postgresql-wal-receiver.nix new file mode 100644 index 000000000000..791b041ba95b --- /dev/null +++ b/nixos/tests/postgresql-wal-receiver.nix @@ -0,0 +1,86 @@ +{ system ? builtins.currentSystem +, config ? { } +, pkgs ? import ../.. { inherit system config; } }: + +with import ../lib/testing.nix { inherit system pkgs; }; +with pkgs.lib; + +let + postgresqlDataDir = "/var/db/postgresql/test"; + replicationUser = "wal_receiver_user"; + replicationSlot = "wal_receiver_slot"; + replicationConn = "postgresql://${replicationUser}@localhost"; + baseBackupDir = "/tmp/pg_basebackup"; + walBackupDir = "/tmp/pg_wal"; + recoveryConf = pkgs.writeText "recovery.conf" '' + restore_command = 'cp ${walBackupDir}/%f %p' + ''; + + makePostgresqlWalReceiverTest = subTestName: postgresqlPackage: makeTest { + name = "postgresql-wal-receiver-${subTestName}"; + meta.maintainers = with maintainers; [ pacien ]; + + machine = { ... }: { + services.postgresql = { + package = postgresqlPackage; + enable = true; + dataDir = postgresqlDataDir; + extraConfig = '' + wal_level = archive # alias for replica on pg >= 9.6 + max_wal_senders = 10 + max_replication_slots = 10 + ''; + authentication = '' + host replication ${replicationUser} all trust + ''; + initialScript = pkgs.writeText "init.sql" '' + create user ${replicationUser} replication; + select * from pg_create_physical_replication_slot('${replicationSlot}'); + ''; + }; + + services.postgresqlWalReceiver.receivers.main = { + inherit postgresqlPackage; + connection = replicationConn; + slot = replicationSlot; + directory = walBackupDir; + }; + }; + + testScript = '' + # make an initial base backup + $machine->waitForUnit('postgresql'); + $machine->waitForUnit('postgresql-wal-receiver-main'); + # WAL receiver healthchecks PG every 5 seconds, so let's be sure they have connected each other + # required only for 9.4 + $machine->sleep(5); + $machine->succeed('${postgresqlPackage}/bin/pg_basebackup --dbname=${replicationConn} --pgdata=${baseBackupDir}'); + + # create a dummy table with 100 records + $machine->succeed('sudo -u postgres psql --command="create table dummy as select * from generate_series(1, 100) as val;"'); + + # stop postgres and destroy data + $machine->systemctl('stop postgresql'); + $machine->systemctl('stop postgresql-wal-receiver-main'); + $machine->succeed('rm -r ${postgresqlDataDir}/{base,global,pg_*}'); + + # restore the base backup + $machine->succeed('cp -r ${baseBackupDir}/* ${postgresqlDataDir} && chown postgres:postgres -R ${postgresqlDataDir}'); + + # prepare WAL and recovery + $machine->succeed('chmod a+rX -R ${walBackupDir}'); + $machine->execute('for part in ${walBackupDir}/*.partial; do mv $part ''${part%%.*}; done'); # make use of partial segments too + $machine->succeed('cp ${recoveryConf} ${postgresqlDataDir}/recovery.conf && chmod 666 ${postgresqlDataDir}/recovery.conf'); + + # replay WAL + $machine->systemctl('start postgresql'); + $machine->waitForFile('${postgresqlDataDir}/recovery.done'); + $machine->systemctl('restart postgresql'); + $machine->waitForUnit('postgresql'); + + # check that our records have been restored + $machine->succeed('test $(sudo -u postgres psql --pset="pager=off" --tuples-only --command="select count(distinct val) from dummy;") -eq 100'); + ''; + }; + +in mapAttrs makePostgresqlWalReceiverTest (import ../../pkgs/servers/sql/postgresql pkgs) diff --git a/nixos/tests/syncthing-init.nix b/nixos/tests/syncthing-init.nix index 811a466ff941..0de76b688bdc 100644 --- a/nixos/tests/syncthing-init.nix +++ b/nixos/tests/syncthing-init.nix @@ -22,9 +22,13 @@ in { }; testScript = '' + my $config; + $machine->waitForUnit("syncthing-init.service"); - $machine->succeed("cat /var/lib/syncthing/config.xml") =~ /${testId}/ or die; - $machine->succeed("cat /var/lib/syncthing/config.xml") =~ /testFolder/ or die; + $config = $machine->succeed("cat /var/lib/syncthing/.config/syncthing/config.xml"); + + $config =~ /${testId}/ or die; + $config =~ /testFolder/ or die; ''; }) |