diff options
Diffstat (limited to 'nixos')
22 files changed, 853 insertions, 102 deletions
diff --git a/nixos/doc/manual/README b/nixos/doc/manual/README deleted file mode 100644 index 120c127d7af..00000000000 --- a/nixos/doc/manual/README +++ /dev/null @@ -1,3 +0,0 @@ -Moved to: ./contributing-to-this-manual.xml. Link: - -https://nixos.org/manual/nixos/unstable/#chap-contributing diff --git a/nixos/doc/manual/README.md b/nixos/doc/manual/README.md new file mode 100644 index 00000000000..bc649761df6 --- /dev/null +++ b/nixos/doc/manual/README.md @@ -0,0 +1,3 @@ +[Moved to ./contributing-to-this-manual.chapter.md](./contributing-to-this-manual.chapter.md). Link: + +https://nixos.org/manual/nixos/unstable/#chap-contributing diff --git a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml index 91acaf728e2..7ebf6c0187a 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml @@ -85,6 +85,13 @@ <link linkend="opt-services.vikunja.enable">services.vikunja</link>. </para> </listitem> + <listitem> + <para> + <link xlink:href="https://www.snapraid.it/">snapraid</link>, a + backup program for disk arrays. Available as + <link linkend="opt-snapraid.enable">snapraid</link>. + </para> + </listitem> </itemizedlist> </section> <section xml:id="sec-release-21.11-incompatibilities"> @@ -486,7 +493,7 @@ </itemizedlist> </listitem> </itemizedlist> - <itemizedlist spacing="compact"> + <itemizedlist> <listitem> <para> <literal>yggdrasil</literal> was upgraded to a new major @@ -495,6 +502,14 @@ changelog</link>. </para> </listitem> + <listitem> + <para> + <literal>icingaweb2</literal> was upgraded to a new release + which requires a manual database upgrade, see + <link xlink:href="https://github.com/Icinga/icingaweb2/releases/tag/v2.9.0">upstream + changelog</link>. + </para> + </listitem> </itemizedlist> </section> <section xml:id="sec-release-21.11-notable-changes"> @@ -538,6 +553,22 @@ <literal>claws-mail-gtk2</literal> package. </para> </listitem> + <listitem> + <para> + The wordpress module provides a new interface which allows to + use different webservers with the new option + <link xlink:href="options.html#opt-services.wordpress.webserver"><literal>services.wordpress.webserver</literal></link>. + Currently <literal>httpd</literal> and + <literal>nginx</literal> are supported. The definitions of + wordpress sites should now be set in + <link xlink:href="options.html#opt-services.wordpress.sites"><literal>services.wordpress.sites</literal></link>. + </para> + <para> + Sites definitions that use the old interface are automatically + migrated in the new option. This backward compatibility will + be removed in 22.05. + </para> + </listitem> </itemizedlist> </section> </section> diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md index 1cef74510db..a0ca0ca3d0e 100644 --- a/nixos/doc/manual/release-notes/rl-2111.section.md +++ b/nixos/doc/manual/release-notes/rl-2111.section.md @@ -25,6 +25,10 @@ In addition to numerous new and upgraded packages, this release has the followin - [vikunja](https://vikunja.io), a to-do list app. Available as [services.vikunja](#opt-services.vikunja.enable). +- [snapraid](https://www.snapraid.it/), a backup program for disk arrays. + Available as [snapraid](#opt-snapraid.enable). + + ## Backward Incompatibilities {#sec-release-21.11-incompatibilities} - The `staticjinja` package has been upgraded from 1.0.4 to 3.0.1 @@ -122,6 +126,8 @@ In addition to numerous new and upgraded packages, this release has the followin - `yggdrasil` was upgraded to a new major release with breaking changes, see [upstream changelog](https://github.com/yggdrasil-network/yggdrasil-go/releases/tag/v0.4.0). +- `icingaweb2` was upgraded to a new release which requires a manual database upgrade, see [upstream changelog](https://github.com/Icinga/icingaweb2/releases/tag/v2.9.0). + ## Other Notable Changes {#sec-release-21.11-notable-changes} - The setting [`services.openssh.logLevel`](options.html#opt-services.openssh.logLevel) `"VERBOSE"` `"INFO"`. This brings NixOS in line with upstream and other Linux distributions, and reduces log spam on servers due to bruteforcing botnets. @@ -131,3 +137,7 @@ In addition to numerous new and upgraded packages, this release has the followin - Sway: The terminal emulator `rxvt-unicode` is no longer installed by default via `programs.sway.extraPackages`. The current default configuration uses `alacritty` (and soon `foot`) so this is only an issue when using a customized configuration and not installing `rxvt-unicode` explicitly. - The `claws-mail` package now references the new GTK+ 3 release branch, major version 4. To use the GTK+ 2 releases, one can install the `claws-mail-gtk2` package. + +- The wordpress module provides a new interface which allows to use different webservers with the new option [`services.wordpress.webserver`](options.html#opt-services.wordpress.webserver). Currently `httpd` and `nginx` are supported. The definitions of wordpress sites should now be set in [`services.wordpress.sites`](options.html#opt-services.wordpress.sites). + + Sites definitions that use the old interface are automatically migrated in the new option. This backward compatibility will be removed in 22.05. diff --git a/nixos/lib/test-driver/test-driver.py b/nixos/lib/test-driver/test-driver.py index 7f4dd5963c9..15eaba88476 100644 --- a/nixos/lib/test-driver/test-driver.py +++ b/nixos/lib/test-driver/test-driver.py @@ -292,7 +292,12 @@ class Machine: net_frontend += "," + args["netFrontendArgs"] start_command = ( - "qemu-kvm -m 384 " + net_backend + " " + net_frontend + " $QEMU_OPTS " + args.get("qemuBinary", "qemu-kvm") + + " -m 384 " + + net_backend + + " " + + net_frontend + + " $QEMU_OPTS " ) if "hda" in args: diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 28f36ca82b9..ad1bccd5428 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -849,6 +849,7 @@ ./services/networking/ucarp.nix ./services/networking/unbound.nix ./services/networking/unifi.nix + ./services/video/unifi-video.nix ./services/networking/v2ray.nix ./services/networking/vsftpd.nix ./services/networking/wakeonlan.nix @@ -1104,6 +1105,7 @@ ./tasks/network-interfaces-systemd.nix ./tasks/network-interfaces-scripted.nix ./tasks/scsi-link-power-management.nix + ./tasks/snapraid.nix ./tasks/swraid.nix ./tasks/trackpoint.nix ./tasks/powertop.nix diff --git a/nixos/modules/programs/xwayland.nix b/nixos/modules/programs/xwayland.nix index 7e9a424a715..cb3c9c5b156 100644 --- a/nixos/modules/programs/xwayland.nix +++ b/nixos/modules/programs/xwayland.nix @@ -10,14 +10,16 @@ in { options.programs.xwayland = { - enable = mkEnableOption '' - Xwayland X server allows running X programs on a Wayland compositor. - ''; + enable = mkEnableOption "Xwayland (an X server for interfacing X11 apps with the Wayland protocol)"; defaultFontPath = mkOption { type = types.str; default = optionalString config.fonts.fontDir.enable "/run/current-system/sw/share/X11/fonts"; + defaultText = literalExample '' + optionalString config.fonts.fontDir.enable + "/run/current-system/sw/share/X11/fonts"; + ''; description = '' Default font path. Setting this option causes Xwayland to be rebuilt. ''; @@ -25,7 +27,15 @@ in package = mkOption { type = types.path; - description = "The Xwayland package"; + default = pkgs.xwayland.override (oldArgs: { + inherit (cfg) defaultFontPath; + }); + defaultText = literalExample '' + pkgs.xwayland.override (oldArgs: { + inherit (config.programs.xwayland) defaultFontPath; + }); + ''; + description = "The Xwayland package to use."; }; }; @@ -37,9 +47,5 @@ in environment.systemPackages = [ cfg.package ]; - programs.xwayland.package = pkgs.xwayland.override (oldArgs: { - inherit (cfg) defaultFontPath; - }); - }; } diff --git a/nixos/modules/services/cluster/k3s/default.nix b/nixos/modules/services/cluster/k3s/default.nix index 300c182406c..d0fb8cc5098 100644 --- a/nixos/modules/services/cluster/k3s/default.nix +++ b/nixos/modules/services/cluster/k3s/default.nix @@ -35,10 +35,20 @@ in token = mkOption { type = types.str; - description = "The k3s token to use when connecting to the server. This option only makes sense for an agent."; + description = '' + The k3s token to use when connecting to the server. This option only makes sense for an agent. + WARNING: This option will expose store your token unencrypted world-readable in the nix store. + If this is undesired use the tokenFile option instead. + ''; default = ""; }; + tokenFile = mkOption { + type = types.nullOr types.path; + description = "File path containing k3s token to use when connecting to the server. This option only makes sense for an agent."; + default = null; + }; + docker = mkOption { type = types.bool; default = false; @@ -68,8 +78,8 @@ in message = "serverAddr should be set if role is 'agent'"; } { - assertion = cfg.role == "agent" -> cfg.token != ""; - message = "token should be set if role is 'agent'"; + assertion = cfg.role == "agent" -> cfg.token != "" || cfg.tokenFile != null; + message = "token or tokenFile should be set if role is 'agent'"; } ]; @@ -105,7 +115,12 @@ in "${cfg.package}/bin/k3s ${cfg.role}" ] ++ (optional cfg.docker "--docker") ++ (optional cfg.disableAgent "--disable-agent") - ++ (optional (cfg.role == "agent") "--server ${cfg.serverAddr} --token ${cfg.token}") + ++ (optional (cfg.role == "agent") "--server ${cfg.serverAddr} ${ + if cfg.tokenFile != null then + "--token-file ${cfg.tokenFile}" + else + "--token ${cfg.token}" + }") ++ [ cfg.extraFlags ] ); }; diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix index 33da4071638..480d5a184f2 100644 --- a/nixos/modules/services/networking/bind.nix +++ b/nixos/modules/services/networking/bind.nix @@ -61,7 +61,7 @@ let blackhole { badnetworks; }; forward first; forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} }; - directory "/run/named"; + directory "${cfg.directory}"; pid-file "/run/named/named.pid"; ${cfg.extraOptions} }; @@ -166,6 +166,12 @@ in "; }; + directory = mkOption { + type = types.str; + default = "/run/named"; + description = "Working directory of BIND."; + }; + zones = mkOption { default = [ ]; type = with types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (types.submodule bindZoneOptions)); @@ -240,6 +246,9 @@ in ${pkgs.coreutils}/bin/mkdir -p /run/named chown ${bindUser} /run/named + + ${pkgs.coreutils}/bin/mkdir -p ${cfg.directory} + chown ${bindUser} ${cfg.directory} ''; serviceConfig = { diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index 053efe71270..7820eedd932 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -18,6 +18,7 @@ let ${lib.optionalString (cfg.zone != "") "zone=${cfg.zone}"} ssl=${boolToStr cfg.ssl} wildcard=YES + ipv6=${boolToStr cfg.ipv6} quiet=${boolToStr cfg.quiet} verbose=${boolToStr cfg.verbose} ${cfg.extraConfig} @@ -116,7 +117,15 @@ with lib; default = true; type = bool; description = '' - Whether to use to use SSL/TLS to connect to dynamic DNS provider. + Whether to use SSL/TLS to connect to dynamic DNS provider. + ''; + }; + + ipv6 = mkOption { + default = false; + type = bool; + description = '' + Whether to use IPv6. ''; }; diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index 940ac7832da..d28ea61e66a 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -26,12 +26,12 @@ let if value != null then [ (nameValuePair (nameToEnvVar name) (if isBool value then boolToString value else toString value)) ] else [] ) cfg.config)); in { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") { - WEB_VAULT_FOLDER = "${pkgs.vaultwarden-vault}/share/vaultwarden/vault"; + WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault"; } // configEnv; configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv)); - vaultwarden = pkgs.vaultwarden.override { inherit (cfg) dbBackend; }; + vaultwarden = cfg.package.override { inherit (cfg) dbBackend; }; in { imports = [ @@ -102,6 +102,20 @@ in { <literal>vaultwarden</literal> is running. ''; }; + + package = mkOption { + type = package; + default = pkgs.vaultwarden; + defaultText = "pkgs.vaultwarden"; + description = "Vaultwarden package to use."; + }; + + webVaultPackage = mkOption { + type = package; + default = pkgs.vaultwarden-vault; + defaultText = "pkgs.vaultwarden-vault"; + description = "Web vault package to use."; + }; }; config = mkIf cfg.enable { diff --git a/nixos/modules/services/video/unifi-video.nix b/nixos/modules/services/video/unifi-video.nix new file mode 100644 index 00000000000..d4c0268ed66 --- /dev/null +++ b/nixos/modules/services/video/unifi-video.nix @@ -0,0 +1,265 @@ +{ config, lib, pkgs, utils, ... }: +with lib; +let + cfg = config.services.unifi-video; + mainClass = "com.ubnt.airvision.Main"; + cmd = '' + ${pkgs.jsvc}/bin/jsvc \ + -cwd ${stateDir} \ + -debug \ + -verbose:class \ + -nodetach \ + -user unifi-video \ + -home ${cfg.jrePackage}/lib/openjdk \ + -cp ${pkgs.commonsDaemon}/share/java/commons-daemon-1.2.4.jar:${stateDir}/lib/airvision.jar \ + -pidfile ${cfg.pidFile} \ + -procname unifi-video \ + -Djava.security.egd=file:/dev/./urandom \ + -Xmx${cfg.maximumJavaHeapSize}M \ + -Xss512K \ + -XX:+UseG1GC \ + -XX:+UseStringDeduplication \ + -XX:MaxMetaspaceSize=768M \ + -Djava.library.path=${stateDir}/lib \ + -Djava.awt.headless=true \ + -Djavax.net.ssl.trustStore=${stateDir}/etc/ufv-truststore \ + -Dfile.encoding=UTF-8 \ + -Dav.tempdir=/var/cache/unifi-video + ''; + + mongoConf = pkgs.writeTextFile { + name = "mongo.conf"; + executable = false; + text = '' + # for documentation of all options, see http://docs.mongodb.org/manual/reference/configuration-options/ + + storage: + dbPath: ${cfg.dataDir}/db + journal: + enabled: true + syncPeriodSecs: 60 + + systemLog: + destination: file + logAppend: true + path: ${stateDir}/logs/mongod.log + + net: + port: 7441 + bindIp: 127.0.0.1 + http: + enabled: false + + operationProfiling: + slowOpThresholdMs: 500 + mode: off + ''; + }; + + + mongoWtConf = pkgs.writeTextFile { + name = "mongowt.conf"; + executable = false; + text = '' + # for documentation of all options, see: + # http://docs.mongodb.org/manual/reference/configuration-options/ + + storage: + dbPath: ${cfg.dataDir}/db-wt + journal: + enabled: true + wiredTiger: + engineConfig: + cacheSizeGB: 1 + + systemLog: + destination: file + logAppend: true + path: logs/mongod.log + + net: + port: 7441 + bindIp: 127.0.0.1 + + operationProfiling: + slowOpThresholdMs: 500 + mode: off + ''; + }; + + stateDir = "/var/lib/unifi-video"; + +in + { + + options.services.unifi-video = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not to enable the unifi-video service. + ''; + }; + + jrePackage = mkOption { + type = types.package; + default = pkgs.jre8; + defaultText = "pkgs.jre8"; + description = '' + The JRE package to use. Check the release notes to ensure it is supported. + ''; + }; + + unifiVideoPackage = mkOption { + type = types.package; + default = pkgs.unifi-video; + defaultText = "pkgs.unifi-video"; + description = '' + The unifi-video package to use. + ''; + }; + + mongodbPackage = mkOption { + type = types.package; + default = pkgs.mongodb-4_0; + defaultText = "pkgs.mongodb"; + description = '' + The mongodb package to use. + ''; + }; + + logDir = mkOption { + type = types.str; + default = "${stateDir}/logs"; + description = '' + Where to store the logs. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "${stateDir}/data"; + description = '' + Where to store the database and other data. + ''; + }; + + openPorts = mkOption { + type = types.bool; + default = true; + description = '' + Whether or not to open the required ports on the firewall. + ''; + }; + + maximumJavaHeapSize = mkOption { + type = types.nullOr types.int; + default = 1024; + example = 4096; + description = '' + Set the maximimum heap size for the JVM in MB. + ''; + }; + + pidFile = mkOption { + type = types.path; + default = "${cfg.dataDir}/unifi-video.pid"; + description = "Location of unifi-video pid file."; + }; + +}; + +config = mkIf cfg.enable { + users = { + users.unifi-video = { + description = "UniFi Video controller daemon user"; + home = stateDir; + group = "unifi-video"; + isSystemUser = true; + }; + groups.unifi-video = {}; + }; + + networking.firewall = mkIf cfg.openPorts { + # https://help.ui.com/hc/en-us/articles/217875218-UniFi-Video-Ports-Used + allowedTCPPorts = [ + 7080 # HTTP portal + 7443 # HTTPS portal + 7445 # Video over HTTP (mobile app) + 7446 # Video over HTTPS (mobile app) + 7447 # RTSP via the controller + 7442 # Camera management from cameras to NVR over WAN + ]; + allowedUDPPorts = [ + 6666 # Inbound camera streams sent over WAN + ]; + }; + + systemd.tmpfiles.rules = [ + "d '${stateDir}' 0700 unifi-video unifi-video - -" + "d '/var/cache/unifi-video' 0700 unifi-video unifi-video - -" + + "d '${stateDir}/logs' 0700 unifi-video unifi-video - -" + "C '${stateDir}/etc' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/etc" + "C '${stateDir}/webapps' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/webapps" + "C '${stateDir}/email' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/email" + "C '${stateDir}/fw' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/fw" + "C '${stateDir}/lib' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/lib" + + "d '${stateDir}/data' 0700 unifi-video unifi-video - -" + "d '${stateDir}/data/db' 0700 unifi-video unifi-video - -" + "C '${stateDir}/data/system.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/etc/system.properties" + + "d '${stateDir}/bin' 0700 unifi-video unifi-video - -" + "f '${stateDir}/bin/evostreamms' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/evostreamms" + "f '${stateDir}/bin/libavcodec.so.54' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavcodec.so.54" + "f '${stateDir}/bin/libavformat.so.54' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavformat.so.54" + "f '${stateDir}/bin/libavutil.so.52' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavutil.so.52" + "f '${stateDir}/bin/ubnt.avtool' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/ubnt.avtool" + "f '${stateDir}/bin/ubnt.updater' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/ubnt.updater" + "C '${stateDir}/bin/mongo' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongo" + "C '${stateDir}/bin/mongod' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongod" + "C '${stateDir}/bin/mongoperf' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongoperf" + "C '${stateDir}/bin/mongos' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongos" + + "d '${stateDir}/conf' 0700 unifi-video unifi-video - -" + "C '${stateDir}/conf/evostream' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/evostream" + "Z '${stateDir}/conf/evostream' 0700 unifi-video unifi-video - -" + "L+ '${stateDir}/conf/mongodv3.0+.conf' 0700 unifi-video unifi-video - ${mongoConf}" + "L+ '${stateDir}/conf/mongodv3.6+.conf' 0700 unifi-video unifi-video - ${mongoConf}" + "L+ '${stateDir}/conf/mongod-wt.conf' 0700 unifi-video unifi-video - ${mongoWtConf}" + "L+ '${stateDir}/conf/catalina.policy' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/catalina.policy" + "L+ '${stateDir}/conf/catalina.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/catalina.properties" + "L+ '${stateDir}/conf/context.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/context.xml" + "L+ '${stateDir}/conf/logging.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/logging.properties" + "L+ '${stateDir}/conf/server.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/server.xml" + "L+ '${stateDir}/conf/tomcat-users.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/tomcat-users.xml" + "L+ '${stateDir}/conf/web.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/web.xml" + + ]; + + systemd.services.unifi-video = { + description = "UniFi Video NVR daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ] ; + unitConfig.RequiresMountsFor = stateDir; + # Make sure package upgrades trigger a service restart + restartTriggers = [ cfg.unifiVideoPackage cfg.mongodbPackage ]; + path = with pkgs; [ gawk coreutils busybox which jre8 lsb-release libcap util-linux ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${(removeSuffix "\n" cmd)} ${mainClass} start"; + ExecStop = "${(removeSuffix "\n" cmd)} stop ${mainClass} stop"; + Restart = "on-failure"; + UMask = "0077"; + User = "unifi-video"; + WorkingDirectory = "${stateDir}"; + }; + }; + + }; + + meta = { + maintainers = with lib.maintainers; [ rsynnest ]; + }; +} diff --git a/nixos/modules/services/web-apps/discourse.nix b/nixos/modules/services/web-apps/discourse.nix index d3ae072f86a..8d5302ba267 100644 --- a/nixos/modules/services/web-apps/discourse.nix +++ b/nixos/modules/services/web-apps/discourse.nix @@ -475,21 +475,16 @@ in plugins = lib.mkOption { type = lib.types.listOf lib.types.package; default = []; - example = '' - [ - (pkgs.fetchFromGitHub { - owner = "discourse"; - repo = "discourse-spoiler-alert"; - rev = "e200cfa571d252cab63f3d30d619b370986e4cee"; - sha256 = "0ya69ix5g77wz4c9x9gmng6l25ghb5xxlx3icr6jam16q14dzc33"; - }) + example = lib.literalExample '' + with config.services.discourse.package.plugins; [ + discourse-canned-replies + discourse-github ]; ''; description = '' - <productname>Discourse</productname> plugins to install as a - list of derivations. As long as a plugin supports the - standard install method, packaging it should only require - fetching its source with an appropriate fetcher. + Plugins to install as part of + <productname>Discourse</productname>, expressed as a list of + derivations. ''; }; diff --git a/nixos/modules/services/web-apps/discourse.xml b/nixos/modules/services/web-apps/discourse.xml index bae56242321..1d6866e7b35 100644 --- a/nixos/modules/services/web-apps/discourse.xml +++ b/nixos/modules/services/web-apps/discourse.xml @@ -262,9 +262,31 @@ services.discourse = { <para> You can install <productname>Discourse</productname> plugins using the <xref linkend="opt-services.discourse.plugins" /> - option. As long as a plugin supports the standard install - method, packaging it should only require fetching its source - with an appropriate fetcher. + option. Pre-packaged plugins are provided in + <literal><your_discourse_package_here>.plugins</literal>. If + you want the full suite of plugins provided through + <literal>nixpkgs</literal>, you can also set the <xref + linkend="opt-services.discourse.package" /> option to + <literal>pkgs.discourseAllPlugins</literal>. + </para> + + <para> + Plugins can be built with the + <literal><your_discourse_package_here>.mkDiscoursePlugin</literal> + function. Normally, it should suffice to provide a + <literal>name</literal> and <literal>src</literal> attribute. If + the plugin has Ruby dependencies, however, they need to be + packaged in accordance with the <link + xlink:href="https://nixos.org/manual/nixpkgs/stable/#developing-with-ruby">Developing + with Ruby</link> section of the Nixpkgs manual and the + appropriate gem options set in <literal>bundlerEnvArgs</literal> + (normally <literal>gemdir</literal> is sufficient). A plugin's + Ruby dependencies are listed in its + <filename>plugin.rb</filename> file as function calls to + <literal>gem</literal>. To construct the corresponding + <filename>Gemfile</filename>, run <command>bundle + init</command>, then add the <literal>gem</literal> lines to it + verbatim. </para> <para> @@ -280,7 +302,10 @@ services.discourse = { <para> For example, to add the <link xlink:href="https://github.com/discourse/discourse-spoiler-alert">discourse-spoiler-alert</link> - plugin and disable it by default: + and <link + xlink:href="https://github.com/discourse/discourse-solved">discourse-solved</link> + plugins, and disable <literal>discourse-spoiler-alert</literal> + by default: <programlisting> services.discourse = { @@ -301,13 +326,9 @@ services.discourse = { <link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file"; }; <link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true; - <link linkend="opt-services.discourse.mail.incoming.enable">plugins</link> = [ - (pkgs.fetchFromGitHub { - owner = "discourse"; - repo = "discourse-spoiler-alert"; - rev = "e200cfa571d252cab63f3d30d619b370986e4cee"; - sha256 = "0ya69ix5g77wz4c9x9gmng6l25ghb5xxlx3icr6jam16q14dzc33"; - }) + <link linkend="opt-services.discourse.mail.incoming.enable">plugins</link> = with config.services.discourse.package.plugins; [ + discourse-spoiler-alert + discourse-solved ]; <link linkend="opt-services.discourse.siteSettings">siteSettings</link> = { plugins = { diff --git a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix index eea49bda283..f8f0854f1bc 100644 --- a/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix +++ b/nixos/modules/services/web-apps/icingaweb2/icingaweb2.nix @@ -23,6 +23,16 @@ in { ''; }; + libraryPaths = mkOption { + type = attrsOf package; + default = { }; + description = '' + Libraries to add to the Icingaweb2 library path. + The name of the attribute is the name of the library, the value + is the package to add. + ''; + }; + virtualHost = mkOption { type = nullOr str; default = "icingaweb2"; @@ -167,6 +177,9 @@ in { services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") { ${poolName} = { user = "icingaweb2"; + phpEnv = { + ICINGAWEB_LIBDIR = toString (pkgs.linkFarm "icingaweb2-libdir" (mapAttrsToList (name: path: { inherit name path; }) cfg.libraryPaths)); + }; phpPackage = pkgs.php.withExtensions ({ enabled, all }: [ all.imagick ] ++ enabled); phpOptions = '' date.timezone = "${cfg.timezone}" @@ -184,6 +197,11 @@ in { }; }; + services.icingaweb2.libraryPaths = { + ipl = pkgs.icingaweb2-ipl; + thirdparty = pkgs.icingaweb2-thirdparty; + }; + systemd.services."phpfpm-${poolName}".serviceConfig.ReadWritePaths = [ "/etc/icingaweb2" ]; services.nginx = { diff --git a/nixos/modules/services/web-apps/wordpress.nix b/nixos/modules/services/web-apps/wordpress.nix index 775ecb3acaf..6f1ef815bc4 100644 --- a/nixos/modules/services/web-apps/wordpress.nix +++ b/nixos/modules/services/web-apps/wordpress.nix @@ -3,13 +3,18 @@ let inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types; inherit (lib) any attrValues concatMapStringsSep flatten literalExample; - inherit (lib) mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString; + inherit (lib) filterAttrs mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString; - eachSite = config.services.wordpress; + cfg = migrateOldAttrs config.services.wordpress; + eachSite = cfg.sites; user = "wordpress"; - group = config.services.httpd.group; + webserver = config.services.${cfg.webserver}; stateDir = hostName: "/var/lib/wordpress/${hostName}"; + # Migrate config.services.wordpress.<hostName> to config.services.wordpress.sites.<hostName> + oldSites = filterAttrs (o: _: o != "sites" && o != "webserver"); + migrateOldAttrs = cfg: cfg // { sites = cfg.sites // oldSites cfg; }; + pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec { pname = "wordpress-${hostName}"; version = src.version; @@ -261,21 +266,48 @@ in # interface options = { services.wordpress = mkOption { - type = types.attrsOf (types.submodule siteOpts); + type = types.submodule { + # Used to support old interface + freeformType = types.attrsOf (types.submodule siteOpts); + + # New interface + options.sites = mkOption { + type = types.attrsOf (types.submodule siteOpts); + default = {}; + description = "Specification of one or more WordPress sites to serve"; + }; + + options.webserver = mkOption { + type = types.enum [ "httpd" "nginx" ]; + default = "httpd"; + description = '' + Whether to use apache2 or nginx for virtual host management. + + Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>. + See <xref linkend="opt-services.nginx.virtualHosts"/> for further information. + + Further apache2 configuration can be done by adapting <literal>services.httpd.virtualHosts.<name></literal>. + See <xref linkend="opt-services.httpd.virtualHosts"/> for further information. + ''; + }; + }; default = {}; - description = "Specification of one or more WordPress sites to serve via Apache."; + description = "Wordpress configuration"; }; + }; # implementation - config = mkIf (eachSite != {}) { + config = mkIf (eachSite != {}) (mkMerge [{ assertions = mapAttrsToList (hostName: cfg: { assertion = cfg.database.createLocally -> cfg.database.user == user; - message = "services.wordpress.${hostName}.database.user must be ${user} if the database is to be automatically provisioned"; + message = ''services.wordpress.sites."${hostName}".database.user must be ${user} if the database is to be automatically provisioned''; } ) eachSite; + warnings = mapAttrsToList (hostName: _: ''services.wordpress."${hostName}" is deprecated use services.wordpress.sites."${hostName}"'') (oldSites cfg); + services.mysql = mkIf (any (v: v.database.createLocally) (attrValues eachSite)) { enable = true; package = mkDefault pkgs.mariadb; @@ -289,14 +321,18 @@ in services.phpfpm.pools = mapAttrs' (hostName: cfg: ( nameValuePair "wordpress-${hostName}" { - inherit user group; + inherit user; + group = webserver.group; settings = { - "listen.owner" = config.services.httpd.user; - "listen.group" = config.services.httpd.group; + "listen.owner" = webserver.user; + "listen.group" = webserver.group; } // cfg.poolConfig; } )) eachSite; + } + + (mkIf (cfg.webserver == "httpd") { services.httpd = { enable = true; extraModules = [ "proxy_fcgi" ]; @@ -332,11 +368,13 @@ in ''; } ]) eachSite; }; + }) + { systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [ - "d '${stateDir hostName}' 0750 ${user} ${group} - -" - "d '${cfg.uploadsDir}' 0750 ${user} ${group} - -" - "Z '${cfg.uploadsDir}' 0750 ${user} ${group} - -" + "d '${stateDir hostName}' 0750 ${user} ${webserver.group} - -" + "d '${cfg.uploadsDir}' 0750 ${user} ${webserver.group} - -" + "Z '${cfg.uploadsDir}' 0750 ${user} ${webserver.group} - -" ]) eachSite); systemd.services = mkMerge [ @@ -350,7 +388,7 @@ in serviceConfig = { Type = "oneshot"; User = user; - Group = group; + Group = webserver.group; }; })) eachSite) @@ -360,9 +398,65 @@ in ]; users.users.${user} = { - group = group; + group = webserver.group; isSystemUser = true; }; + } - }; + (mkIf (cfg.webserver == "nginx") { + services.nginx = { + enable = true; + virtualHosts = mapAttrs (hostName: cfg: { + serverName = mkDefault hostName; + root = "${pkg hostName cfg}/share/wordpress"; + extraConfig = '' + index index.php; + ''; + locations = { + "/" = { + priority = 200; + extraConfig = '' + try_files $uri $uri/ /index.php$is_args$args; + ''; + }; + "~ \\.php$" = { + priority = 500; + extraConfig = '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools."wordpress-${hostName}".socket}; + fastcgi_index index.php; + include "${config.services.nginx.package}/conf/fastcgi.conf"; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; + # Mitigate https://httpoxy.org/ vulnerabilities + fastcgi_param HTTP_PROXY ""; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + fastcgi_connect_timeout 300; + fastcgi_send_timeout 300; + fastcgi_read_timeout 300; + ''; + }; + "~ /\\." = { + priority = 800; + extraConfig = "deny all;"; + }; + "~* /(?:uploads|files)/.*\\.php$" = { + priority = 900; + extraConfig = "deny all;"; + }; + "~* \\.(js|css|png|jpg|jpeg|gif|ico)$" = { + priority = 1000; + extraConfig = '' + expires max; + log_not_found off; + ''; + }; + }; + }) eachSite; + }; + }) + + ]); } diff --git a/nixos/modules/tasks/snapraid.nix b/nixos/modules/tasks/snapraid.nix new file mode 100644 index 00000000000..4529009930f --- /dev/null +++ b/nixos/modules/tasks/snapraid.nix @@ -0,0 +1,230 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.snapraid; +in +{ + options.snapraid = with types; { + enable = mkEnableOption "SnapRAID"; + dataDisks = mkOption { + default = { }; + example = { + d1 = "/mnt/disk1/"; + d2 = "/mnt/disk2/"; + d3 = "/mnt/disk3/"; + }; + description = "SnapRAID data disks."; + type = attrsOf str; + }; + parityFiles = mkOption { + default = [ ]; + example = [ + "/mnt/diskp/snapraid.parity" + "/mnt/diskq/snapraid.2-parity" + "/mnt/diskr/snapraid.3-parity" + "/mnt/disks/snapraid.4-parity" + "/mnt/diskt/snapraid.5-parity" + "/mnt/disku/snapraid.6-parity" + ]; + description = "SnapRAID parity files."; + type = listOf str; + }; + contentFiles = mkOption { + default = [ ]; + example = [ + "/var/snapraid.content" + "/mnt/disk1/snapraid.content" + "/mnt/disk2/snapraid.content" + ]; + description = "SnapRAID content list files."; + type = listOf str; + }; + exclude = mkOption { + default = [ ]; + example = [ "*.unrecoverable" "/tmp/" "/lost+found/" ]; + description = "SnapRAID exclude directives."; + type = listOf str; + }; + touchBeforeSync = mkOption { + default = true; + example = false; + description = + "Whether <command>snapraid touch</command> should be run before <command>snapraid sync</command>."; + type = bool; + }; + sync.interval = mkOption { + default = "01:00"; + example = "daily"; + description = "How often to run <command>snapraid sync</command>."; + type = str; + }; + scrub = { + interval = mkOption { + default = "Mon *-*-* 02:00:00"; + example = "weekly"; + description = "How often to run <command>snapraid scrub</command>."; + type = str; + }; + plan = mkOption { + default = 8; + example = 5; + description = + "Percent of the array that should be checked by <command>snapraid scrub</command>."; + type = int; + }; + olderThan = mkOption { + default = 10; + example = 20; + description = + "Number of days since data was last scrubbed before it can be scrubbed again."; + type = int; + }; + }; + extraConfig = mkOption { + default = ""; + example = '' + nohidden + blocksize 256 + hashsize 16 + autosave 500 + pool /pool + ''; + description = "Extra config options for SnapRAID."; + type = lines; + }; + }; + + config = + let + nParity = builtins.length cfg.parityFiles; + mkPrepend = pre: s: pre + s; + in + mkIf cfg.enable { + assertions = [ + { + assertion = nParity <= 6; + message = "You can have no more than six SnapRAID parity files."; + } + { + assertion = builtins.length cfg.contentFiles >= nParity + 1; + message = + "There must be at least one SnapRAID content file for each SnapRAID parity file plus one."; + } + ]; + + environment = { + systemPackages = with pkgs; [ snapraid ]; + + etc."snapraid.conf" = { + text = with cfg; + let + prependData = mkPrepend "data "; + prependContent = mkPrepend "content "; + prependExclude = mkPrepend "exclude "; + in + concatStringsSep "\n" + (map prependData + ((mapAttrsToList (name: value: name + " " + value)) dataDisks) + ++ zipListsWith (a: b: a + b) + ([ "parity " ] ++ map (i: toString i + "-parity ") (range 2 6)) + parityFiles ++ map prependContent contentFiles + ++ map prependExclude exclude) + "\n" + extraConfig; + }; + }; + + systemd.services = with cfg; { + snapraid-scrub = { + description = "Scrub the SnapRAID array"; + startAt = scrub.interval; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.snapraid}/bin/snapraid scrub -p ${ + toString scrub.plan + } -o ${toString scrub.olderThan}"; + Nice = 19; + IOSchedulingPriority = 7; + CPUSchedulingPolicy = "batch"; + + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "none"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + SystemCallErrorNumber = "EPERM"; + CapabilityBoundingSet = "CAP_DAC_OVERRIDE"; + + ProtectSystem = "strict"; + ProtectHome = "read-only"; + ReadWritePaths = + # scrub requires access to directories containing content files + # to remove them if they are stale + let + contentDirs = map dirOf contentFiles; + in + unique ( + attrValues dataDisks ++ contentDirs + ); + }; + unitConfig.After = "snapraid-sync.service"; + }; + snapraid-sync = { + description = "Synchronize the state of the SnapRAID array"; + startAt = sync.interval; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.snapraid}/bin/snapraid sync"; + Nice = 19; + IOSchedulingPriority = 7; + CPUSchedulingPolicy = "batch"; + + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "none"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + SystemCallErrorNumber = "EPERM"; + CapabilityBoundingSet = "CAP_DAC_OVERRIDE"; + + ProtectSystem = "strict"; + ProtectHome = "read-only"; + ReadWritePaths = + # sync requires access to directories containing content files + # to remove them if they are stale + let + contentDirs = map dirOf contentFiles; + in + unique ( + attrValues dataDisks ++ parityFiles ++ contentDirs + ); + } // optionalAttrs touchBeforeSync { + ExecStartPre = "${pkgs.snapraid}/bin/snapraid touch"; + }; + }; + }; + }; +} diff --git a/nixos/modules/virtualisation/vmware-guest.nix b/nixos/modules/virtualisation/vmware-guest.nix index 962a9059ea4..9465a8d6800 100644 --- a/nixos/modules/virtualisation/vmware-guest.nix +++ b/nixos/modules/virtualisation/vmware-guest.nix @@ -56,5 +56,7 @@ in ${open-vm-tools}/bin/vmware-user-suid-wrapper ''; }; + + services.udev.packages = [ open-vm-tools ]; }; } diff --git a/nixos/tests/agda.nix b/nixos/tests/agda.nix index f282788519c..ec61af2afe7 100644 --- a/nixos/tests/agda.nix +++ b/nixos/tests/agda.nix @@ -2,6 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: let hello-world = pkgs.writeText "hello-world" '' + {-# OPTIONS --guardedness #-} open import IO open import Level @@ -35,10 +36,6 @@ in machine.succeed("touch TestEmpty.agda") machine.succeed("agda TestEmpty.agda") - # Minimal script that actually uses the standard library - machine.succeed('echo "import IO" > TestIO.agda') - machine.succeed("agda -l standard-library -i . TestIO.agda") - # Hello world machine.succeed( "cp ${hello-world} HelloWorld.agda" diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index e364bbe1bfa..ef721dabb58 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -43,7 +43,7 @@ in bitcoind = handleTest ./bitcoind.nix {}; bittorrent = handleTest ./bittorrent.nix {}; blockbook-frontend = handleTest ./blockbook-frontend.nix {}; - boot = handleTestOn ["x86_64-linux"] ./boot.nix {}; # syslinux is unsupported on aarch64 + boot = handleTestOn ["x86_64-linux" "aarch64-linux"] ./boot.nix {}; boot-stage1 = handleTest ./boot-stage1.nix {}; borgbackup = handleTest ./borgbackup.nix {}; botamusique = handleTest ./botamusique.nix {}; diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix index c5040f3b31f..bdae6341ec9 100644 --- a/nixos/tests/boot.nix +++ b/nixos/tests/boot.nix @@ -4,6 +4,7 @@ }: with import ../lib/testing-python.nix { inherit system pkgs; }; +with import ../lib/qemu-flags.nix { inherit pkgs; }; with pkgs.lib; let @@ -21,7 +22,10 @@ let makeBootTest = name: extraConfig: let - machineConfig = pythonDict ({ qemuFlags = "-m 768"; } // extraConfig); + machineConfig = pythonDict ({ + qemuBinary = qemuBinary pkgs.qemu_test; + qemuFlags = "-m 768"; + } // extraConfig); in makeTest { inherit iso; @@ -61,6 +65,7 @@ let ]; }; machineConfig = pythonDict ({ + qemuBinary = qemuBinary pkgs.qemu_test; qemuFlags = "-boot order=n -m 2000"; netBackendArgs = "tftp=${ipxeBootDir},bootfile=netboot.ipxe"; } // extraConfig); @@ -75,31 +80,34 @@ let machine.shutdown() ''; }; + uefiBinary = { + x86_64-linux = "${pkgs.OVMF.fd}/FV/OVMF.fd"; + aarch64-linux = "${pkgs.OVMF.fd}/FV/QEMU_EFI.fd"; + }.${pkgs.stdenv.hostPlatform.system}; in { - - biosCdrom = makeBootTest "bios-cdrom" { + uefiCdrom = makeBootTest "uefi-cdrom" { cdrom = "${iso}/iso/${iso.isoName}"; + bios = uefiBinary; }; - biosUsb = makeBootTest "bios-usb" { + uefiUsb = makeBootTest "uefi-usb" { usb = "${iso}/iso/${iso.isoName}"; + bios = uefiBinary; }; - uefiCdrom = makeBootTest "uefi-cdrom" { + uefiNetboot = makeNetbootTest "uefi" { + bios = uefiBinary; + # Custom ROM is needed for EFI PXE boot. I failed to understand exactly why, because QEMU should still use iPXE for EFI. + netFrontendArgs = "romfile=${pkgs.ipxe}/ipxe.efirom"; + }; +} // optionalAttrs (pkgs.stdenv.hostPlatform.system == "x86_64-linux") { + biosCdrom = makeBootTest "bios-cdrom" { cdrom = "${iso}/iso/${iso.isoName}"; - bios = "${pkgs.OVMF.fd}/FV/OVMF.fd"; }; - uefiUsb = makeBootTest "uefi-usb" { + biosUsb = makeBootTest "bios-usb" { usb = "${iso}/iso/${iso.isoName}"; - bios = "${pkgs.OVMF.fd}/FV/OVMF.fd"; }; biosNetboot = makeNetbootTest "bios" {}; - - uefiNetboot = makeNetbootTest "uefi" { - bios = "${pkgs.OVMF.fd}/FV/OVMF.fd"; - # Custom ROM is needed for EFI PXE boot. I failed to understand exactly why, because QEMU should still use iPXE for EFI. - netFrontendArgs = "romfile=${pkgs.ipxe}/ipxe.efirom"; - }; } diff --git a/nixos/tests/wordpress.nix b/nixos/tests/wordpress.nix index a5c10c2de74..45c58b5b65c 100644 --- a/nixos/tests/wordpress.nix +++ b/nixos/tests/wordpress.nix @@ -10,48 +10,68 @@ import ./make-test-python.nix ({ pkgs, ... }: ]; }; - machine = - { ... }: - { services.httpd.adminAddr = "webmaster@site.local"; + nodes = { + wp_httpd = { ... }: { + services.httpd.adminAddr = "webmaster@site.local"; services.httpd.logPerVirtualHost = true; - services.wordpress."site1.local" = { - database.tablePrefix = "site1_"; + services.wordpress = { + # Test support for old interface + "site1.local" = { + database.tablePrefix = "site1_"; + }; + sites = { + "site2.local" = { + database.tablePrefix = "site2_"; + }; + }; }; - services.wordpress."site2.local" = { - database.tablePrefix = "site2_"; + networking.firewall.allowedTCPPorts = [ 80 ]; + networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ]; + }; + + wp_nginx = { ... }: { + services.wordpress.webserver = "nginx"; + services.wordpress.sites = { + "site1.local" = { + database.tablePrefix = "site1_"; + }; + "site2.local" = { + database.tablePrefix = "site2_"; + }; }; + networking.firewall.allowedTCPPorts = [ 80 ]; networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ]; }; + }; testScript = '' import re start_all() - machine.wait_for_unit("httpd") - - machine.wait_for_unit("phpfpm-wordpress-site1.local") - machine.wait_for_unit("phpfpm-wordpress-site2.local") + wp_httpd.wait_for_unit("httpd") + wp_nginx.wait_for_unit("nginx") site_names = ["site1.local", "site2.local"] - with subtest("website returns welcome screen"): + for machine in (wp_httpd, wp_nginx): for site_name in site_names: - assert "Welcome to the famous" in machine.succeed(f"curl -fL {site_name}") + machine.wait_for_unit(f"phpfpm-wordpress-{site_name}") - with subtest("wordpress-init went through"): - for site_name in site_names: - info = machine.get_unit_info(f"wordpress-init-{site_name}") - assert info["Result"] == "success" + with subtest("website returns welcome screen"): + assert "Welcome to the famous" in machine.succeed(f"curl -L {site_name}") - with subtest("secret keys are set"): - pattern = re.compile(r"^define.*NONCE_SALT.{64,};$", re.MULTILINE) - for site_name in site_names: - assert pattern.search( - machine.succeed(f"cat /var/lib/wordpress/{site_name}/secret-keys.php") - ) + with subtest("wordpress-init went through"): + info = machine.get_unit_info(f"wordpress-init-{site_name}") + assert info["Result"] == "success" + + with subtest("secret keys are set"): + pattern = re.compile(r"^define.*NONCE_SALT.{64,};$", re.MULTILINE) + assert pattern.search( + machine.succeed(f"cat /var/lib/wordpress/{site_name}/secret-keys.php") + ) ''; }) |