diff options
Diffstat (limited to 'nixos')
30 files changed, 652 insertions, 452 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2003.xml b/nixos/doc/manual/release-notes/rl-2003.xml index b8af15f59c9..886b16ef965 100644 --- a/nixos/doc/manual/release-notes/rl-2003.xml +++ b/nixos/doc/manual/release-notes/rl-2003.xml @@ -208,7 +208,7 @@ <listitem> <para> The packages <literal>openobex</literal> and <literal>obexftp</literal> - are no loger installed when enabling bluetooth via + are no longer installed when enabling Bluetooth via <option>hardware.bluetooth.enable</option>. </para> </listitem> @@ -220,6 +220,11 @@ in conjunction with an external webserver to replace this functionality. </para> </listitem> + <listitem> + <para> + The fourStore and fourStoreEndpoint modules have been removed. + </para> + </listitem> </itemizedlist> </section> diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix index a89667ea221..3560e579e47 100644 --- a/nixos/modules/config/networking.nix +++ b/nixos/modules/config/networking.nix @@ -41,19 +41,6 @@ in ''; }; - networking.hostConf = lib.mkOption { - type = types.lines; - default = "multi on"; - example = '' - multi on - reorder on - trim lan - ''; - description = '' - The contents of <filename>/etc/host.conf</filename>. See also <citerefentry><refentrytitle>host.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. - ''; - }; - networking.timeServers = mkOption { default = [ "0.nixos.pool.ntp.org" @@ -186,7 +173,9 @@ in ''; # /etc/host.conf: resolver configuration file - "host.conf".text = cfg.hostConf; + "host.conf".text = '' + multi on + ''; } // optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") { # /etc/rpc: RPC program numbers. diff --git a/nixos/modules/i18n/input-method/ibus.nix b/nixos/modules/i18n/input-method/ibus.nix index 956c521dde0..d7857976fcc 100644 --- a/nixos/modules/i18n/input-method/ibus.nix +++ b/nixos/modules/i18n/input-method/ibus.nix @@ -53,9 +53,15 @@ in config = mkIf (config.i18n.inputMethod.enabled == "ibus") { i18n.inputMethod.package = ibusPackage; + environment.systemPackages = [ + ibusAutostart + ]; + # Without dconf enabled it is impossible to use IBus - environment.systemPackages = with pkgs; [ - dconf ibusAutostart + programs.dconf.enable = true; + + services.dbus.packages = [ + ibusAutostart ]; environment.variables = { diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index f8b188e7b1c..bedd87a368e 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -80,8 +80,8 @@ in #kdm = 39; # dropped in 17.03 #ghostone = 40; # dropped in 18.03 git = 41; - fourstore = 42; - fourstorehttp = 43; + #fourstore = 42; # dropped in 20.03 + #fourstorehttp = 43; # dropped in 20.03 virtuoso = 44; rtkit = 45; dovecot2 = 46; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 8e373550bb3..bb217d873bb 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -254,8 +254,6 @@ ./services/continuous-integration/jenkins/default.nix ./services/continuous-integration/jenkins/job-builder.nix ./services/continuous-integration/jenkins/slave.nix - ./services/databases/4store-endpoint.nix - ./services/databases/4store.nix ./services/databases/aerospike.nix ./services/databases/cassandra.nix ./services/databases/clickhouse.nix diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index e392fef54dd..83b29613d9c 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -239,6 +239,7 @@ with lib; (mkRemovedOptionModule [ "systemd" "generator-packages" ] "Use systemd.packages instead.") (mkRemovedOptionModule [ "fonts" "enableCoreFonts" ] "Use fonts.fonts = [ pkgs.corefonts ]; instead.") (mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.") + (mkRemovedOptionModule [ "networking" "hostConf" ] "Use environment.etc.\"host.conf\" instead.") # ZSH (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) diff --git a/nixos/modules/services/databases/4store-endpoint.nix b/nixos/modules/services/databases/4store-endpoint.nix deleted file mode 100644 index 59ed0e5f0af..00000000000 --- a/nixos/modules/services/databases/4store-endpoint.nix +++ /dev/null @@ -1,74 +0,0 @@ -{ config, lib, pkgs, ... }: -let - cfg = config.services.fourStoreEndpoint; - endpointUser = "fourstorehttp"; - run = "${pkgs.su}/bin/su -s ${pkgs.runtimeShell} ${endpointUser} -c"; -in -with lib; -{ - - ###### interface - - options = { - - services.fourStoreEndpoint = { - - enable = mkOption { - default = false; - description = "Whether to enable 4Store SPARQL endpoint."; - }; - - database = mkOption { - default = config.services.fourStore.database; - description = "RDF database name to expose via the endpoint. Defaults to local 4Store database name."; - }; - - listenAddress = mkOption { - default = null; - description = "IP address to listen on."; - }; - - port = mkOption { - default = 8080; - description = "port to listen on."; - }; - - options = mkOption { - default = ""; - description = "Extra CLI options to pass to 4Store's 4s-httpd process."; - }; - - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - - assertions = singleton - { assertion = cfg.enable -> cfg.database != ""; - message = "Must specify 4Store database name"; - }; - - users.users = singleton - { name = endpointUser; - uid = config.ids.uids.fourstorehttp; - description = "4Store SPARQL endpoint user"; - }; - - services.avahi.enable = true; - - systemd.services."4store-endpoint" = { - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - script = '' - ${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}' - ''; - }; - - }; - -} diff --git a/nixos/modules/services/databases/4store.nix b/nixos/modules/services/databases/4store.nix deleted file mode 100644 index be4351c1c38..00000000000 --- a/nixos/modules/services/databases/4store.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ config, lib, pkgs, ... }: -let - cfg = config.services.fourStore; - stateDir = "/var/lib/4store"; - fourStoreUser = "fourstore"; - run = "${pkgs.su}/bin/su -s ${pkgs.runtimeShell} ${fourStoreUser}"; -in -with lib; -{ - - ###### interface - - options = { - - services.fourStore = { - - enable = mkOption { - default = false; - description = "Whether to enable 4Store RDF database server."; - }; - - database = mkOption { - default = ""; - description = "RDF database name. If it doesn't exist, it will be created. Databases are stored in ${stateDir}."; - }; - - options = mkOption { - default = ""; - description = "Extra CLI options to pass to 4Store."; - }; - - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - - assertions = singleton - { assertion = cfg.enable -> cfg.database != ""; - message = "Must specify 4Store database name."; - }; - - users.users = singleton - { name = fourStoreUser; - uid = config.ids.uids.fourstore; - description = "4Store database user"; - home = stateDir; - }; - - services.avahi.enable = true; - - systemd.services."4store" = { - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - preStart = '' - mkdir -p ${stateDir}/ - chown ${fourStoreUser} ${stateDir} - if ! test -e "${stateDir}/${cfg.database}"; then - ${run} -c '${pkgs.rdf4store}/bin/4s-backend-setup ${cfg.database}' - fi - ''; - - script = '' - ${run} -c '${pkgs.rdf4store}/bin/4s-backend -D ${cfg.options} ${cfg.database}' - ''; - }; - }; -} diff --git a/nixos/modules/services/misc/apache-kafka.nix b/nixos/modules/services/misc/apache-kafka.nix index 798e902ccae..46308f74dc9 100644 --- a/nixos/modules/services/misc/apache-kafka.nix +++ b/nixos/modules/services/misc/apache-kafka.nix @@ -131,7 +131,7 @@ in { home = head cfg.logDirs; }; - systemd.tmpfiles.rules = map (logDir: "d '${logDir} 0700 apache-kafka - - -") cfg.logDirs; + systemd.tmpfiles.rules = map (logDir: "d '${logDir}' 0700 apache-kafka - - -") cfg.logDirs; systemd.services.apache-kafka = { description = "Apache Kafka Daemon"; diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix index b6f4d88adbe..258476dd9fe 100644 --- a/nixos/modules/services/misc/gitea.nix +++ b/nixos/modules/services/misc/gitea.nix @@ -396,9 +396,7 @@ in Restart = "always"; # Filesystem - ProtectSystem = "strict"; ProtectHome = true; - PrivateTmp = true; PrivateDevices = true; ProtectKernelTunables = true; ProtectKernelModules = true; @@ -413,7 +411,7 @@ in PrivateMounts = true; PrivateUsers = true; MemoryDenyWriteExecute = true; - SystemCallFilter = "~@chown @clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @privileged @raw-io @reboot @resources @setuid @swap"; + SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @raw-io @reboot @resources @setuid @swap"; SystemCallArchitectures = "native"; RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; }; @@ -475,4 +473,5 @@ in timerConfig.OnCalendar = cfg.dump.interval; }; }; + meta.maintainers = with lib.maintainers; [ srhb ]; } diff --git a/nixos/modules/services/networking/yggdrasil.nix b/nixos/modules/services/networking/yggdrasil.nix index 5d65f8e3413..9e675ecd6f4 100644 --- a/nixos/modules/services/networking/yggdrasil.nix +++ b/nixos/modules/services/networking/yggdrasil.nix @@ -12,11 +12,11 @@ let configFileProvided = (cfg.configFile != null); generateConfig = ( if configProvided && configFileProvided then - "${pkgs.jq}/bin/jq -s add /run/yggdrasil/configFile.json ${configAsFile}" + "${pkgs.jq}/bin/jq -s add ${configAsFile} ${cfg.configFile}" else if configProvided then "cat ${configAsFile}" else if configFileProvided then - "cat /run/yggdrasil/configFile.json" + "cat ${cfg.configFile}" else "${cfg.package}/bin/yggdrasil -genconf" ); @@ -147,7 +147,7 @@ in { RuntimeDirectory = "yggdrasil"; RuntimeDirectoryMode = "0700"; BindReadOnlyPaths = mkIf configFileProvided - [ "${cfg.configFile}:/run/yggdrasil/configFile.json" ]; + [ "${cfg.configFile}" ]; # TODO: as of yggdrasil 0.3.8 and systemd 243, yggdrasil fails # to set up the network adapter when DynamicUser is set. See diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index 7409eb8cdcb..412f9180375 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -7,6 +7,7 @@ let apparmor = config.security.apparmor.enable; homeDir = cfg.home; + downloadDirPermissions = cfg.downloadDirPermissions; downloadDir = "${homeDir}/Downloads"; incompleteDir = "${homeDir}/.incomplete"; @@ -16,16 +17,14 @@ 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 + for DIR in "${homeDir}" "${settingsDir}" "${fullSettings.download-dir}" "${fullSettings.incomplete-dir}"; do mkdir -p "$DIR" - chmod 770 "$DIR" done + chmod 700 "${homeDir}" "${settingsDir}" + chmod ${downloadDirPermissions} "${fullSettings.download-dir}" "${fullSettings.incomplete-dir}" cp -f ${settingsFile} ${settingsDir}/settings.json ''; in @@ -71,6 +70,16 @@ in ''; }; + downloadDirPermissions = mkOption { + type = types.string; + default = "770"; + example = "775"; + description = '' + The permissions to set for download-dir and incomplete-dir. + They will be applied on every service start. + ''; + }; + port = mkOption { type = types.int; default = 9091; diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index b67f0880878..e3a2db398e6 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -31,8 +31,12 @@ let occ = pkgs.writeScriptBin "nextcloud-occ" '' #! ${pkgs.stdenv.shell} cd ${pkgs.nextcloud} - exec /run/wrappers/bin/sudo -u nextcloud \ - NEXTCLOUD_CONFIG_DIR="${cfg.home}/config" \ + sudo=exec + if [[ "$USER" != nextcloud ]]; then + sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR' + fi + export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config" + $sudo \ ${phpPackage}/bin/php \ -c ${pkgs.writeText "php.ini" phpOptionsStr}\ occ $* @@ -420,6 +424,7 @@ in { nextcloud-update-plugins = mkIf cfg.autoUpdateApps.enable { serviceConfig.Type = "oneshot"; serviceConfig.ExecStart = "${occ}/bin/nextcloud-occ app:update --all"; + serviceConfig.User = "nextcloud"; startAt = cfg.autoUpdateApps.startAt; }; }; diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index f5a6051b4b5..850d3052533 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -367,7 +367,7 @@ in type = types.lines; default = ""; description = '' - Cnfiguration lines appended to the generated Apache + Configuration lines appended to the generated Apache configuration file. Note that this mechanism may not work when <option>configFile</option> is overridden. ''; diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix index 25ef1cbfc67..99db5b17b64 100644 --- a/nixos/modules/services/x11/desktop-managers/pantheon.nix +++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix @@ -163,7 +163,7 @@ in # Settings from elementary-default-settings environment.sessionVariables.GTK_CSD = "1"; - environment.sessionVariables.GTK_MODULES = "pantheon-filechooser-module"; + environment.sessionVariables.GTK3_MODULES = [ "pantheon-filechooser-module" ]; environment.etc."gtk-3.0/settings.ini".source = "${pkgs.pantheon.elementary-default-settings}/etc/gtk-3.0/settings.ini"; environment.pathsToLink = [ diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 226769f1059..58d914d0810 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -11,7 +11,7 @@ let checkLink = checkUnitConfig "Link" [ (assertOnlyFields [ "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name" "OriginalName" - "MTUBytes" "BitsPerSecond" "Duplex" "AutoNegotiation" "WakeOnLan" "Port" + "MTUBytes" "BitsPerSecond" "Duplex" "AutoNegotiation" "WakeOnLan" "Port" "Advertise" "TCPSegmentationOffload" "TCP6SegmentationOffload" "GenericSegmentationOffload" "GenericReceiveOffload" "LargeReceiveOffload" "RxChannels" "TxChannels" "OtherChannels" "CombinedChannels" @@ -276,7 +276,7 @@ let (assertValueOneOf "ARP" boolValues) (assertValueOneOf "Multicast" boolValues) (assertValueOneOf "Unmanaged" boolValues) - (assertValueOneOf "RequiredForOnline" boolValues) + (assertValueOneOf "RequiredForOnline" (boolValues ++ ["off" "no-carrier" "dormant" "degraded-carrier" "carrier" "degraded" "enslaved" "routable"])) ]; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index fbc8b511f3b..23ad22ee5a1 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -48,6 +48,7 @@ in clickhouse = handleTest ./clickhouse.nix {}; cloud-init = handleTest ./cloud-init.nix {}; codimd = handleTest ./codimd.nix {}; + consul = handleTest ./consul.nix {}; containers-bridge = handleTest ./containers-bridge.nix {}; containers-ephemeral = handleTest ./containers-ephemeral.nix {}; containers-extra_veth = handleTest ./containers-extra_veth.nix {}; @@ -93,6 +94,7 @@ in gitea = handleTest ./gitea.nix {}; gitlab = handleTest ./gitlab.nix {}; gitolite = handleTest ./gitolite.nix {}; + gitolite-fcgiwrap = handleTest ./gitolite-fcgiwrap.nix {}; glusterfs = handleTest ./glusterfs.nix {}; gnome3-xorg = handleTest ./gnome3-xorg.nix {}; gnome3 = handleTest ./gnome3.nix {}; @@ -267,6 +269,7 @@ in taskserver = handleTest ./taskserver.nix {}; telegraf = handleTest ./telegraf.nix {}; tiddlywiki = handleTest ./tiddlywiki.nix {}; + timezone = handleTest ./timezone.nix {}; tinydns = handleTest ./tinydns.nix {}; tor = handleTest ./tor.nix {}; transmission = handleTest ./transmission.nix {}; diff --git a/nixos/tests/consul.nix b/nixos/tests/consul.nix new file mode 100644 index 00000000000..6600dae4770 --- /dev/null +++ b/nixos/tests/consul.nix @@ -0,0 +1,143 @@ +import ./make-test-python.nix ({pkgs, lib, ...}: + +let + # Settings for both servers and agents + webUi = true; + retry_interval = "1s"; + raft_multiplier = 1; + + defaultExtraConfig = { + inherit retry_interval; + performance = { + inherit raft_multiplier; + }; + }; + + allConsensusServerHosts = [ + "192.168.1.1" + "192.168.1.2" + "192.168.1.3" + ]; + + allConsensusClientHosts = [ + "192.168.2.1" + "192.168.2.2" + ]; + + firewallSettings = { + # See https://www.consul.io/docs/install/ports.html + allowedTCPPorts = [ 8301 8302 8600 8500 8300 ]; + allowedUDPPorts = [ 8301 8302 8600 ]; + }; + + client = index: { pkgs, ... }: + let + ip = builtins.elemAt allConsensusClientHosts index; + in + { + environment.systemPackages = [ pkgs.consul ]; + + networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [ + { address = ip; prefixLength = 16; } + ]; + networking.firewall = firewallSettings; + + services.consul = { + enable = true; + inherit webUi; + extraConfig = defaultExtraConfig // { + server = false; + retry_join = allConsensusServerHosts; + bind_addr = ip; + }; + }; + }; + + server = index: { pkgs, ... }: + let + ip = builtins.elemAt allConsensusServerHosts index; + in + { + networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [ + { address = builtins.elemAt allConsensusServerHosts index; prefixLength = 16; } + ]; + networking.firewall = firewallSettings; + + services.consul = + let + thisConsensusServerHost = builtins.elemAt allConsensusServerHosts index; + in + assert builtins.elem thisConsensusServerHost allConsensusServerHosts; + { + enable = true; + inherit webUi; + extraConfig = defaultExtraConfig // { + server = true; + bootstrap_expect = builtins.length allConsensusServerHosts; + retry_join = + # If there's only 1 node in the network, we allow self-join; + # otherwise, the node must not try to join itself, and join only the other servers. + # See https://github.com/hashicorp/consul/issues/2868 + if builtins.length allConsensusServerHosts == 1 + then allConsensusServerHosts + else builtins.filter (h: h != thisConsensusServerHost) allConsensusServerHosts; + bind_addr = ip; + }; + }; + }; +in { + name = "consul"; + + nodes = { + server1 = server 0; + server2 = server 1; + server3 = server 2; + + client1 = client 0; + client2 = client 1; + }; + + testScript = '' + servers = [server1, server2, server3] + machines = [server1, server2, server3, client1, client2] + + for m in machines: + m.wait_for_unit("consul.service") + + for m in machines: + m.wait_until_succeeds("[ $(consul members | grep -o alive | wc -l) == 5 ]") + + client1.succeed("consul kv put testkey 42") + client2.succeed("[ $(consul kv get testkey) == 42 ]") + + # Test that the cluster can tolearate failures of any single server: + for server in servers: + server.crash() + + # For each client, wait until they have connection again + # using `kv get -recurse` before issuing commands. + client1.wait_until_succeeds("consul kv get -recurse") + client2.wait_until_succeeds("consul kv get -recurse") + + # Do some consul actions while one server is down. + client1.succeed("consul kv put testkey 43") + client2.succeed("[ $(consul kv get testkey) == 43 ]") + client2.succeed("consul kv delete testkey") + + # Restart crashed machine. + server.start() + + # Wait for recovery. + for m in machines: + m.wait_until_succeeds("[ $(consul members | grep -o alive | wc -l) == 5 ]") + + # Wait for client connections. + client1.wait_until_succeeds("consul kv get -recurse") + client2.wait_until_succeeds("consul kv get -recurse") + + # Do some consul actions with server back up. + client1.succeed("consul kv put testkey 44") + client2.succeed("[ $(consul kv get testkey) == 44 ]") + client2.succeed("consul kv delete testkey") + ''; +}) diff --git a/nixos/tests/dhparams.nix b/nixos/tests/dhparams.nix index d11dfeec5d0..a0de2911777 100644 --- a/nixos/tests/dhparams.nix +++ b/nixos/tests/dhparams.nix @@ -4,7 +4,7 @@ let environment.systemPackages = [ pkgs.openssl ]; }; -in import ./make-test.nix { +in import ./make-test-python.nix { name = "dhparams"; nodes.generation1 = { pkgs, config, ... }: { @@ -66,79 +66,77 @@ in import ./make-test.nix { node = "generation${toString gen}"; in nodes.${node}.config.security.dhparams.params.${name}.path; - assertParamBits = gen: name: bits: let - path = getParamPath gen name; - in '' - $machine->nest('check bit size of ${path}', sub { - my $out = $machine->succeed('openssl dhparam -in ${path} -text'); - $out =~ /^\s*DH Parameters:\s+\((\d+)\s+bit\)\s*$/m; - die "bit size should be ${toString bits} but it is $1 instead." - if $1 != ${toString bits}; - }); - ''; - switchToGeneration = gen: let node = "generation${toString gen}"; inherit (nodes.${node}.config.system.build) toplevel; switchCmd = "${toplevel}/bin/switch-to-configuration test"; in '' - $machine->nest('switch to generation ${toString gen}', sub { - $machine->succeed('${switchCmd}'); - $main::machine = ''$${node}; - }); + with machine.nested("switch to generation ${toString gen}"): + machine.succeed( + "${switchCmd}" + ) + machine = ${node} ''; in '' - my $machine = $generation1; + import re - $machine->waitForUnit('multi-user.target'); - subtest "verify startup order", sub { - $machine->succeed('systemctl is-active foo.service'); - }; + def assert_param_bits(path, bits): + with machine.nested(f"check bit size of {path}"): + output = machine.succeed(f"openssl dhparam -in {path} -text") + pattern = re.compile(r"^\s*DH Parameters:\s+\((\d+)\s+bit\)\s*$", re.M) + match = pattern.match(output) + if match is None: + raise Exception("bla") + if match[1] != str(bits): + raise Exception(f"bit size should be {bits} but it is {match[1]} instead.") - subtest "check bit sizes of dhparam files", sub { - ${assertParamBits 1 "foo" 16} - ${assertParamBits 1 "bar" 17} - }; + + machine = generation1 + + machine.wait_for_unit("multi-user.target") + + with subtest("verify startup order"): + machine.succeed("systemctl is-active foo.service") + + with subtest("check bit sizes of dhparam files"): + assert_param_bits("${getParamPath 1 "foo"}", 16) + assert_param_bits("${getParamPath 1 "bar"}", 17) ${switchToGeneration 2} - subtest "check whether bit size has changed", sub { - ${assertParamBits 2 "foo" 18} - }; + with subtest("check whether bit size has changed"): + assert_param_bits("${getParamPath 2 "foo"}", 18) - subtest "ensure that dhparams file for 'bar' was deleted", sub { - $machine->fail('test -e ${getParamPath 1 "bar"}'); - }; + with subtest("ensure that dhparams file for 'bar' was deleted"): + machine.fail("test -e ${getParamPath 1 "bar"}") ${switchToGeneration 3} - subtest "ensure that 'security.dhparams.path' has been deleted", sub { - $machine->fail( - 'test -e ${nodes.generation3.config.security.dhparams.path}' - ); - }; + with subtest("ensure that 'security.dhparams.path' has been deleted"): + machine.fail("test -e ${nodes.generation3.config.security.dhparams.path}") ${switchToGeneration 4} - subtest "check bit sizes dhparam files", sub { - ${assertParamBits 4 "foo2" 18} - ${assertParamBits 4 "bar2" 19} - }; + with subtest("check bit sizes dhparam files"): + assert_param_bits( + "${getParamPath 4 "foo2"}", 18 + ) + assert_param_bits( + "${getParamPath 4 "bar2"}", 19 + ) - subtest "check whether dhparam files are in the Nix store", sub { - $machine->succeed( - 'expr match ${getParamPath 4 "foo2"} ${builtins.storeDir}', - 'expr match ${getParamPath 4 "bar2"} ${builtins.storeDir}', - ); - }; + with subtest("check whether dhparam files are in the Nix store"): + machine.succeed( + "expr match ${getParamPath 4 "foo2"} ${builtins.storeDir}", + "expr match ${getParamPath 4 "bar2"} ${builtins.storeDir}", + ) ${switchToGeneration 5} - subtest "check whether defaultBitSize works as intended", sub { - ${assertParamBits 5 "foo3" 30} - ${assertParamBits 5 "bar3" 30} - }; + with subtest("check whether defaultBitSize works as intended"): + assert_param_bits("${getParamPath 5 "foo3"}", 30) + assert_param_bits("${getParamPath 5 "bar3"}", 30) ''; } diff --git a/nixos/tests/docker-tools-overlay.nix b/nixos/tests/docker-tools-overlay.nix index 637957bd3e8..1a0e0ea6775 100644 --- a/nixos/tests/docker-tools-overlay.nix +++ b/nixos/tests/docker-tools-overlay.nix @@ -1,6 +1,6 @@ # this test creates a simple GNU image with docker tools and sees if it executes -import ./make-test.nix ({ pkgs, ... }: +import ./make-test-python.nix ({ pkgs, ... }: { name = "docker-tools-overlay"; meta = with pkgs.stdenv.lib.maintainers; { @@ -16,17 +16,18 @@ import ./make-test.nix ({ pkgs, ... }: }; }; - testScript = - '' - $docker->waitForUnit("sockets.target"); + testScript = '' + docker.wait_for_unit("sockets.target") - $docker->succeed("docker load --input='${pkgs.dockerTools.examples.bash}'"); - $docker->succeed("docker run --rm ${pkgs.dockerTools.examples.bash.imageName} bash --version"); + docker.succeed( + "docker load --input='${pkgs.dockerTools.examples.bash}'", + "docker run --rm ${pkgs.dockerTools.examples.bash.imageName} bash --version", + ) # Check if the nix store has correct user permissions depending on what # storage driver is used, incorrectly built images can show up as readonly. # drw------- 3 0 0 3 Apr 14 11:36 /nix # drw------- 99 0 0 100 Apr 14 11:36 /nix/store - $docker->succeed("docker run --rm -u 1000:1000 ${pkgs.dockerTools.examples.bash.imageName} bash --version"); + docker.succeed("docker run --rm -u 1000:1000 ${pkgs.dockerTools.examples.bash.imageName} bash --version") ''; }) diff --git a/nixos/tests/ecryptfs.nix b/nixos/tests/ecryptfs.nix index 3f02cecb866..ef7bd13eb92 100644 --- a/nixos/tests/ecryptfs.nix +++ b/nixos/tests/ecryptfs.nix @@ -1,4 +1,4 @@ -import ./make-test.nix ({ ... }: +import ./make-test-python.nix ({ ... }: { name = "ecryptfs"; @@ -10,75 +10,76 @@ import ./make-test.nix ({ ... }: }; testScript = '' - $machine->waitForUnit("default.target"); + def login_as_alice(): + machine.wait_until_tty_matches(1, "login: ") + machine.send_chars("alice\n") + machine.wait_until_tty_matches(1, "Password: ") + machine.send_chars("foobar\n") + machine.wait_until_tty_matches(1, "alice\@machine") - # Set alice up with a password and a home - $machine->succeed("(echo foobar; echo foobar) | passwd alice"); - $machine->succeed("chown -R alice.users ~alice"); - # Migrate alice's home - my $out = $machine->succeed("echo foobar | ecryptfs-migrate-home -u alice"); - $machine->log("ecryptfs-migrate-home said: $out"); + def logout(): + machine.send_chars("logout\n") + machine.wait_until_tty_matches(1, "login: ") - # Log alice in (ecryptfs passwhrase is wrapped during first login) - $machine->waitUntilTTYMatches(1, "login: "); - $machine->sendChars("alice\n"); - $machine->waitUntilTTYMatches(1, "Password: "); - $machine->sendChars("foobar\n"); - $machine->waitUntilTTYMatches(1, "alice\@machine"); - $machine->sendChars("logout\n"); - $machine->waitUntilTTYMatches(1, "login: "); + + machine.wait_for_unit("default.target") + + with subtest("Set alice up with a password and a home"): + machine.succeed("(echo foobar; echo foobar) | passwd alice") + machine.succeed("chown -R alice.users ~alice") + + with subtest("Migrate alice's home"): + out = machine.succeed("echo foobar | ecryptfs-migrate-home -u alice") + machine.log(f"ecryptfs-migrate-home said: {out}") + + with subtest("Log alice in (ecryptfs passwhrase is wrapped during first login)"): + login_as_alice() + machine.send_chars("logout\n") + machine.wait_until_tty_matches(1, "login: ") # Why do I need to do this?? - $machine->succeed("su alice -c ecryptfs-umount-private || true"); - $machine->sleep(1); - $machine->fail("mount | grep ecryptfs"); # check that encrypted home is not mounted + machine.succeed("su alice -c ecryptfs-umount-private || true") + machine.sleep(1) + + with subtest("check that encrypted home is not mounted"): + machine.fail("mount | grep ecryptfs") - # Show contents of the user keyring - my $out = $machine->succeed("su - alice -c 'keyctl list \@u'"); - $machine->log("keyctl unlink said: " . $out); + with subtest("Show contents of the user keyring"): + out = machine.succeed("su - alice -c 'keyctl list \@u'") + machine.log(f"keyctl unlink said: {out}") - # Log alice again - $machine->waitUntilTTYMatches(1, "login: "); - $machine->sendChars("alice\n"); - $machine->waitUntilTTYMatches(1, "Password: "); - $machine->sendChars("foobar\n"); - $machine->waitUntilTTYMatches(1, "alice\@machine"); + with subtest("Log alice again"): + login_as_alice() - # Create some files in encrypted home - $machine->succeed("su alice -c 'touch ~alice/a'"); - $machine->succeed("su alice -c 'echo c > ~alice/b'"); + with subtest("Create some files in encrypted home"): + machine.succeed("su alice -c 'touch ~alice/a'") + machine.succeed("su alice -c 'echo c > ~alice/b'") - # Logout - $machine->sendChars("logout\n"); - $machine->waitUntilTTYMatches(1, "login: "); + with subtest("Logout"): + logout() # Why do I need to do this?? - $machine->succeed("su alice -c ecryptfs-umount-private || true"); - $machine->sleep(1); - - # Check that the filesystem is not accessible - $machine->fail("mount | grep ecryptfs"); - $machine->succeed("su alice -c 'test \! -f ~alice/a'"); - $machine->succeed("su alice -c 'test \! -f ~alice/b'"); - - # Log alice once more - $machine->waitUntilTTYMatches(1, "login: "); - $machine->sendChars("alice\n"); - $machine->waitUntilTTYMatches(1, "Password: "); - $machine->sendChars("foobar\n"); - $machine->waitUntilTTYMatches(1, "alice\@machine"); - - # Check that the files are there - $machine->sleep(1); - $machine->succeed("su alice -c 'test -f ~alice/a'"); - $machine->succeed("su alice -c 'test -f ~alice/b'"); - $machine->succeed(qq%test "\$(cat ~alice/b)" = "c"%); - - # Catch https://github.com/NixOS/nixpkgs/issues/16766 - $machine->succeed("su alice -c 'ls -lh ~alice/'"); - - $machine->sendChars("logout\n"); - $machine->waitUntilTTYMatches(1, "login: "); + machine.succeed("su alice -c ecryptfs-umount-private || true") + machine.sleep(1) + + with subtest("Check that the filesystem is not accessible"): + machine.fail("mount | grep ecryptfs") + machine.succeed("su alice -c 'test \! -f ~alice/a'") + machine.succeed("su alice -c 'test \! -f ~alice/b'") + + with subtest("Log alice once more"): + login_as_alice() + + with subtest("Check that the files are there"): + machine.sleep(1) + machine.succeed("su alice -c 'test -f ~alice/a'") + machine.succeed("su alice -c 'test -f ~alice/b'") + machine.succeed('test "$(cat ~alice/b)" = "c"') + + with subtest("Catch https://github.com/NixOS/nixpkgs/issues/16766"): + machine.succeed("su alice -c 'ls -lh ~alice/'") + + logout() ''; }) diff --git a/nixos/tests/env.nix b/nixos/tests/env.nix index 6c681905b19..e603338e489 100644 --- a/nixos/tests/env.nix +++ b/nixos/tests/env.nix @@ -1,4 +1,4 @@ -import ./make-test.nix ({ pkgs, ...} : { +import ./make-test-python.nix ({ pkgs, ...} : { name = "environment"; meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ nequissimus ]; @@ -20,16 +20,17 @@ import ./make-test.nix ({ pkgs, ...} : { }; }; - testScript = - '' - $machine->succeed('[ -L "/etc/plainFile" ]'); - $machine->succeed('cat "/etc/plainFile" | grep "Hello World"'); - $machine->succeed('[ -d "/etc/folder" ]'); - $machine->succeed('[ -d "/etc/folder/with" ]'); - $machine->succeed('[ -L "/etc/folder/with/file" ]'); - $machine->succeed('cat "/etc/plainFile" | grep "Hello World"'); + testScript = '' + machine.succeed('[ -L "/etc/plainFile" ]') + assert "Hello World" in machine.succeed('cat "/etc/plainFile"') + machine.succeed('[ -d "/etc/folder" ]') + machine.succeed('[ -d "/etc/folder/with" ]') + machine.succeed('[ -L "/etc/folder/with/file" ]') + assert "Hello World" in machine.succeed('cat "/etc/plainFile"') - $machine->succeed('echo ''${TERMINFO_DIRS} | grep "/run/current-system/sw/share/terminfo"'); - $machine->succeed('echo ''${NIXCON} | grep "awesome"'); - ''; + assert "/run/current-system/sw/share/terminfo" in machine.succeed( + "echo ''${TERMINFO_DIRS}" + ) + assert "awesome" in machine.succeed("echo ''${NIXCON}") + ''; }) diff --git a/nixos/tests/gitolite-fcgiwrap.nix b/nixos/tests/gitolite-fcgiwrap.nix new file mode 100644 index 00000000000..414b7d6fe7e --- /dev/null +++ b/nixos/tests/gitolite-fcgiwrap.nix @@ -0,0 +1,93 @@ +import ./make-test-python.nix ( + { pkgs, ... }: + + let + user = "gitolite-admin"; + password = "some_password"; + + # not used but needed to setup gitolite + adminPublicKey = '' + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO7urFhAA90BTpGuEHeWWTY3W/g9PBxXNxfWhfbrm4Le root@client + ''; + in + { + name = "gitolite-fcgiwrap"; + + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ bbigras ]; + }; + + nodes = { + + server = + { ... }: + { + networking.firewall.allowedTCPPorts = [ 80 ]; + + services.fcgiwrap.enable = true; + services.gitolite = { + enable = true; + adminPubkey = adminPublicKey; + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts."server".locations."/git".extraConfig = '' + # turn off gzip as git objects are already well compressed + gzip off; + + # use file based basic authentication + auth_basic "Git Repository Authentication"; + auth_basic_user_file /etc/gitolite/htpasswd; + + # common FastCGI parameters are required + include ${pkgs.nginx}/conf/fastcgi_params; + + # strip the CGI program prefix + fastcgi_split_path_info ^(/git)(.*)$; + fastcgi_param PATH_INFO $fastcgi_path_info; + + # pass authenticated user login(mandatory) to Gitolite + fastcgi_param REMOTE_USER $remote_user; + + # pass git repository root directory and hosting user directory + # these env variables can be set in a wrapper script + fastcgi_param GIT_HTTP_EXPORT_ALL ""; + fastcgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories; + fastcgi_param GITOLITE_HTTP_HOME /var/lib/gitolite; + fastcgi_param SCRIPT_FILENAME ${pkgs.gitolite}/bin/gitolite-shell; + + # use Unix domain socket or inet socket + fastcgi_pass unix:/run/fcgiwrap.sock; + ''; + }; + + # WARNING: DON'T DO THIS IN PRODUCTION! + # This puts unhashed secrets directly into the Nix store for ease of testing. + environment.etc."gitolite/htpasswd".source = pkgs.runCommand "htpasswd" {} '' + ${pkgs.apacheHttpd}/bin/htpasswd -bc "$out" ${user} ${password} + ''; + }; + + client = + { pkgs, ... }: + { + environment.systemPackages = [ pkgs.git ]; + }; + }; + + testScript = '' + start_all() + + server.wait_for_unit("gitolite-init.service") + server.wait_for_unit("nginx.service") + server.wait_for_file("/run/fcgiwrap.sock") + + client.wait_for_unit("multi-user.target") + client.succeed( + "git clone http://${user}:${password}@server/git/gitolite-admin.git" + ) + ''; + } +) diff --git a/nixos/tests/installed-tests/default.nix b/nixos/tests/installed-tests/default.nix index f4780bdcfc9..8e997ee4aeb 100644 --- a/nixos/tests/installed-tests/default.nix +++ b/nixos/tests/installed-tests/default.nix @@ -29,36 +29,51 @@ let # Extra flags to pass to gnome-desktop-testing-runner. , testRunnerFlags ? "" - }: - makeTest rec { - name = tested.name; - - meta = { - maintainers = tested.meta.maintainers; - }; - - machine = { ... }: { - imports = [ - testConfig - ] ++ optional withX11 ../common/x11.nix; - - environment.systemPackages = with pkgs; [ gnome-desktop-testing ]; - - }; - - testScript = - optionalString withX11 '' - machine.wait_for_x() - '' + - optionalString (preTestScript != "") '' - ${preTestScript} - '' + - '' - machine.succeed( - "gnome-desktop-testing-runner ${testRunnerFlags} -d '${tested.installedTests}/share'" - ) - ''; - }; + + # Extra attributes to pass to makeTest. + # They will be recursively merged into the attrset created by this function. + , ... + }@args: + makeTest + (recursiveUpdate + rec { + name = tested.name; + + meta = { + maintainers = tested.meta.maintainers; + }; + + machine = { ... }: { + imports = [ + testConfig + ] ++ optional withX11 ../common/x11.nix; + + environment.systemPackages = with pkgs; [ gnome-desktop-testing ]; + + }; + + testScript = + optionalString withX11 '' + machine.wait_for_x() + '' + + optionalString (preTestScript != "") '' + ${preTestScript} + '' + + '' + machine.succeed( + "gnome-desktop-testing-runner ${testRunnerFlags} -d '${tested.installedTests}/share'" + ) + ''; + } + + (removeAttrs args [ + "tested" + "testConfig" + "preTestScript" + "withX11" + "testRunnerFlags" + ]) + ); in @@ -73,6 +88,7 @@ in glib-networking = callInstalledTest ./glib-networking.nix {}; gnome-photos = callInstalledTest ./gnome-photos.nix {}; graphene = callInstalledTest ./graphene.nix {}; + ibus = callInstalledTest ./ibus.nix {}; libgdata = callInstalledTest ./libgdata.nix {}; libxmlb = callInstalledTest ./libxmlb.nix {}; ostree = callInstalledTest ./ostree.nix {}; diff --git a/nixos/tests/installed-tests/ibus.nix b/nixos/tests/installed-tests/ibus.nix new file mode 100644 index 00000000000..af54b612b50 --- /dev/null +++ b/nixos/tests/installed-tests/ibus.nix @@ -0,0 +1,20 @@ +{ pkgs, makeInstalledTest, ... }: + +makeInstalledTest { + tested = pkgs.ibus; + + testConfig = { + i18n.inputMethod.enabled = "ibus"; + }; + + preTestScript = '' + # ibus has ibus-desktop-testing-runner but it tries to manage desktop session so we just spawn ibus-daemon ourselves + machine.succeed("ibus-daemon --daemonize --verbose") + ''; + + withX11 = true; + + # TODO: ibus-daemon is currently crashing or something + # maybe make ibus systemd service that auto-restarts? + meta.broken = true; +} diff --git a/nixos/tests/ipv6.nix b/nixos/tests/ipv6.nix index d11eba764da..ba464b57447 100644 --- a/nixos/tests/ipv6.nix +++ b/nixos/tests/ipv6.nix @@ -1,7 +1,7 @@ # Test of IPv6 functionality in NixOS, including whether router # solicication/advertisement using radvd works. -import ./make-test.nix ({ pkgs, lib, ...} : { +import ./make-test-python.nix ({ pkgs, lib, ...} : { name = "ipv6"; meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ eelco ]; @@ -35,51 +35,56 @@ import ./make-test.nix ({ pkgs, lib, ...} : { testScript = '' + import re + # Start the router first so that it respond to router solicitations. - $router->waitForUnit("radvd"); + router.wait_for_unit("radvd") - startAll; + start_all() - $client->waitForUnit("network.target"); - $server->waitForUnit("network.target"); - $server->waitForUnit("httpd.service"); + client.wait_for_unit("network.target") + server.wait_for_unit("network.target") + server.wait_for_unit("httpd.service") # Wait until the given interface has a non-tentative address of # the desired scope (i.e. has completed Duplicate Address # Detection). - sub waitForAddress { - my ($machine, $iface, $scope) = @_; - $machine->waitUntilSucceeds("[ `ip -o -6 addr show dev $iface scope $scope | grep -v tentative | wc -l` -ge 1 ]"); - my $ip = (split /[ \/]+/, $machine->succeed("ip -o -6 addr show dev $iface scope $scope"))[3]; - $machine->log("$scope address on $iface is $ip"); - return $ip; - } - - subtest "loopback address", sub { - $client->succeed("ping -c 1 ::1 >&2"); - $client->fail("ping -c 1 ::2 >&2"); - }; - - subtest "local link addressing", sub { - my $clientIp = waitForAddress $client, "eth1", "link"; - my $serverIp = waitForAddress $server, "eth1", "link"; - $client->succeed("ping -c 1 $clientIp%eth1 >&2"); - $client->succeed("ping -c 1 $serverIp%eth1 >&2"); - }; - - subtest "global addressing", sub { - my $clientIp = waitForAddress $client, "eth1", "global"; - my $serverIp = waitForAddress $server, "eth1", "global"; - $client->succeed("ping -c 1 $clientIp >&2"); - $client->succeed("ping -c 1 $serverIp >&2"); - $client->succeed("curl --fail -g http://[$serverIp]"); - $client->fail("curl --fail -g http://[$clientIp]"); - }; - subtest "privacy extensions", sub { - my $ip = waitForAddress $client, "eth1", "global temporary"; + def wait_for_address(machine, iface, scope, temporary=False): + temporary_flag = "temporary" if temporary else "-temporary" + cmd = f"ip -o -6 addr show dev {iface} scope {scope} -tentative {temporary_flag}" + + machine.wait_until_succeeds(f"[ `{cmd} | wc -l` -eq 1 ]") + output = machine.succeed(cmd) + ip = re.search(r"inet6 ([0-9a-f:]{2,})/", output).group(1) + + if temporary: + scope = scope + " temporary" + machine.log(f"{scope} address on {iface} is {ip}") + return ip + + + with subtest("Loopback address can be pinged"): + client.succeed("ping -c 1 ::1 >&2") + client.fail("ping -c 1 ::2 >&2") + + with subtest("Local link addresses can be obtained and pinged"): + client_ip = wait_for_address(client, "eth1", "link") + server_ip = wait_for_address(server, "eth1", "link") + client.succeed(f"ping -c 1 {client_ip}%eth1 >&2") + client.succeed(f"ping -c 1 {server_ip}%eth1 >&2") + + with subtest("Global addresses can be obtained, pinged, and reached via http"): + client_ip = wait_for_address(client, "eth1", "global") + server_ip = wait_for_address(server, "eth1", "global") + client.succeed(f"ping -c 1 {client_ip} >&2") + client.succeed(f"ping -c 1 {server_ip} >&2") + client.succeed(f"curl --fail -g http://[{server_ip}]") + client.fail(f"curl --fail -g http://[{client_ip}]") + + with subtest("Privacy extensions: Global temporary address can be obtained and pinged"): + ip = wait_for_address(client, "eth1", "global", temporary=True) # Default route should have "src <temporary address>" in it - $client->succeed("ip r g ::2 | grep $ip"); - }; + client.succeed(f"ip r g ::2 | grep {ip}") # TODO: test reachability of a machine on another network. ''; diff --git a/nixos/tests/munin.nix b/nixos/tests/munin.nix index 31374aaf77e..7b674db7768 100644 --- a/nixos/tests/munin.nix +++ b/nixos/tests/munin.nix @@ -1,7 +1,7 @@ # This test runs basic munin setup with node and cron job running on the same # machine. -import ./make-test.nix ({ pkgs, ...} : { +import ./make-test-python.nix ({ pkgs, ...} : { name = "munin"; meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ domenkozar eelco ]; @@ -12,33 +12,33 @@ import ./make-test.nix ({ pkgs, ...} : { { config, ... }: { services = { - munin-node = { + munin-node = { + enable = true; + # disable a failing plugin to prevent irrelevant error message, see #23049 + disabledPlugins = [ "apc_nis" ]; + }; + munin-cron = { enable = true; - # disable a failing plugin to prevent irrelevant error message, see #23049 - disabledPlugins = [ "apc_nis" ]; - }; - munin-cron = { - enable = true; - hosts = '' - [${config.networking.hostName}] - address localhost - ''; - }; + hosts = '' + [${config.networking.hostName}] + address localhost + ''; + }; }; - # long timeout to prevent hydra failure on high load - systemd.services.munin-node.serviceConfig.TimeoutStartSec = "10min"; + + # increase the systemd timer interval so it fires more often + systemd.timers.munin-cron.timerConfig.OnCalendar = pkgs.stdenv.lib.mkForce "*:*:0/10"; }; }; testScript = '' - startAll; + start_all() - $one->waitForUnit("munin-node.service"); - # make sure the node is actually listening - $one->waitForOpenPort(4949); - $one->succeed('systemctl start munin-cron'); - # wait for munin-cron output - $one->waitForFile("/var/lib/munin/one/one-uptime-uptime-g.rrd"); - $one->waitForFile("/var/www/munin/one/index.html"); + with subtest("ensure munin-node starts and listens on 4949"): + one.wait_for_unit("munin-node.service") + one.wait_for_open_port(4949) + with subtest("ensure munin-cron output is correct"): + one.wait_for_file("/var/lib/munin/one/one-uptime-uptime-g.rrd") + one.wait_for_file("/var/www/munin/one/index.html") ''; }) diff --git a/nixos/tests/pam-u2f.nix b/nixos/tests/pam-u2f.nix index 1052a2f3b91..f492baa9e13 100644 --- a/nixos/tests/pam-u2f.nix +++ b/nixos/tests/pam-u2f.nix @@ -1,4 +1,4 @@ -import ./make-test.nix ({ ... }: +import ./make-test-python.nix ({ ... }: { name = "pam-u2f"; @@ -17,7 +17,9 @@ import ./make-test.nix ({ ... }: testScript = '' - $machine->waitForUnit('multi-user.target'); - $machine->succeed('egrep "auth required .*/lib/security/pam_u2f.so.*debug.*interactive.*cue" /etc/pam.d/ -R'); + machine.wait_for_unit("multi-user.target") + machine.succeed( + 'egrep "auth required .*/lib/security/pam_u2f.so.*debug.*interactive.*cue" /etc/pam.d/ -R' + ) ''; }) diff --git a/nixos/tests/resolv.nix b/nixos/tests/resolv.nix new file mode 100644 index 00000000000..b506f87451e --- /dev/null +++ b/nixos/tests/resolv.nix @@ -0,0 +1,46 @@ +# Test whether DNS resolving returns multiple records and all address families. +import ./make-test-python.nix ({ pkgs, ... } : { + name = "resolv"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ ckauhaus ]; + }; + + nodes.resolv = { ... }: { + networking.extraHosts = '' + # IPv4 only + 192.0.2.1 host-ipv4.example.net + 192.0.2.2 host-ipv4.example.net + # IP6 only + 2001:db8::2:1 host-ipv6.example.net + 2001:db8::2:2 host-ipv6.example.net + # dual stack + 192.0.2.1 host-dual.example.net + 192.0.2.2 host-dual.example.net + 2001:db8::2:1 host-dual.example.net + 2001:db8::2:2 host-dual.example.net + ''; + }; + + testScript = '' + def addrs_in(hostname, addrs): + res = resolv.succeed("getent ahosts {}".format(hostname)) + for addr in addrs: + assert addr in res, "Expected output '{}' not found in\n{}".format(addr, res) + + + start_all() + resolv.wait_for_unit("nscd") + + ipv4 = ["192.0.2.1", "192.0.2.2"] + ipv6 = ["2001:db8::2:1", "2001:db8::2:2"] + + with subtest("IPv4 resolves"): + addrs_in("host-ipv4.example.net", ipv4) + + with subtest("IPv6 resolves"): + addrs_in("host-ipv6.example.net", ipv6) + + with subtest("Dual stack resolves"): + addrs_in("host-dual.example.net", ipv4 + ipv6) + ''; +}) diff --git a/nixos/tests/timezone.nix b/nixos/tests/timezone.nix index 2204649a3fc..7fc9a5058ee 100644 --- a/nixos/tests/timezone.nix +++ b/nixos/tests/timezone.nix @@ -1,45 +1,50 @@ -{ - timezone-static = import ./make-test.nix ({ pkgs, ... }: { - name = "timezone-static"; - meta.maintainers = with pkgs.lib.maintainers; [ lheckemann ]; - - machine.time.timeZone = "Europe/Amsterdam"; - - testScript = '' - $machine->waitForUnit("dbus.socket"); - $machine->fail("timedatectl set-timezone Asia/Tokyo"); - my @dateResult = $machine->execute('date -d @0 "+%Y-%m-%d %H:%M:%S"'); - $dateResult[1] eq "1970-01-01 01:00:00\n" or die "Timezone seems to be wrong"; - ''; - }); - - timezone-imperative = import ./make-test.nix ({ pkgs, ... }: { - name = "timezone-imperative"; - meta.maintainers = with pkgs.lib.maintainers; [ lheckemann ]; - - machine.time.timeZone = null; - - testScript = '' - $machine->waitForUnit("dbus.socket"); - - # Should default to UTC - my @dateResult = $machine->execute('date -d @0 "+%Y-%m-%d %H:%M:%S"'); - print $dateResult[1]; - $dateResult[1] eq "1970-01-01 00:00:00\n" or die "Timezone seems to be wrong"; - - $machine->succeed("timedatectl set-timezone Asia/Tokyo"); - - # Adjustment should be taken into account - my @dateResult = $machine->execute('date -d @0 "+%Y-%m-%d %H:%M:%S"'); - print $dateResult[1]; - $dateResult[1] eq "1970-01-01 09:00:00\n" or die "Timezone was not adjusted"; - - # Adjustment should persist across a reboot - $machine->shutdown; - $machine->waitForUnit("dbus.socket"); - my @dateResult = $machine->execute('date -d @0 "+%Y-%m-%d %H:%M:%S"'); - print $dateResult[1]; - $dateResult[1] eq "1970-01-01 09:00:00\n" or die "Timezone adjustment was not persisted"; - ''; - }); -} +import ./make-test-python.nix ({ pkgs, ...} : { + name = "timezone"; + meta.maintainers = with pkgs.lib.maintainers; [ lheckemann ]; + + nodes = { + node_eutz = { pkgs, ... }: { + time.timeZone = "Europe/Amsterdam"; + }; + + node_nulltz = { pkgs, ... }: { + time.timeZone = null; + }; + }; + + testScript = { nodes, ... }: '' + node_eutz.wait_for_unit("dbus.socket") + + with subtest("static - Ensure timezone change gives the correct result"): + node_eutz.fail("timedatectl set-timezone Asia/Tokyo") + date_result = node_eutz.succeed('date -d @0 "+%Y-%m-%d %H:%M:%S"') + assert date_result == "1970-01-01 01:00:00\n", "Timezone seems to be wrong" + + node_nulltz.wait_for_unit("dbus.socket") + + with subtest("imperative - Ensure timezone defaults to UTC"): + date_result = node_nulltz.succeed('date -d @0 "+%Y-%m-%d %H:%M:%S"') + print(date_result) + assert ( + date_result == "1970-01-01 00:00:00\n" + ), "Timezone seems to be wrong (not UTC)" + + with subtest("imperative - Ensure timezone adjustment produces expected result"): + node_nulltz.succeed("timedatectl set-timezone Asia/Tokyo") + + # Adjustment should be taken into account + date_result = node_nulltz.succeed('date -d @0 "+%Y-%m-%d %H:%M:%S"') + print(date_result) + assert date_result == "1970-01-01 09:00:00\n", "Timezone was not adjusted" + + with subtest("imperative - Ensure timezone adjustment persists across reboot"): + # Adjustment should persist across a reboot + node_nulltz.shutdown() + node_nulltz.wait_for_unit("dbus.socket") + date_result = node_nulltz.succeed('date -d @0 "+%Y-%m-%d %H:%M:%S"') + print(date_result) + assert ( + date_result == "1970-01-01 09:00:00\n" + ), "Timezone adjustment was not persisted" + ''; +}) |