diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2311.section.md | 2 | ||||
-rw-r--r-- | nixos/modules/hardware/cpu/amd-sev.nix | 89 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/games/xonotic.nix | 198 | ||||
-rw-r--r-- | nixos/modules/services/monitoring/prometheus/exporters.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix | 47 | ||||
-rw-r--r-- | nixos/modules/tasks/network-interfaces-systemd.nix | 64 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 3 | ||||
-rw-r--r-- | nixos/tests/amd-sev.nix | 56 | ||||
-rw-r--r-- | nixos/tests/prometheus-exporters.nix | 38 | ||||
-rw-r--r-- | nixos/tests/systemd-initrd-bridge.nix | 63 | ||||
-rw-r--r-- | nixos/tests/systemd-initrd-vlan.nix | 59 | ||||
-rw-r--r-- | nixos/tests/tinywl.nix | 2 |
13 files changed, 567 insertions, 56 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index af5147e0128..18f44320f07 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -347,4 +347,6 @@ The module update takes care of the new config syntax and the data itself (user can automatically format the root device by setting `virtualisation.fileSystems."/".autoFormat = true;`. +- `python3.pkgs.flitBuildHook` has been removed. Use `flit-core` and `format = "pyproject"` instead. + - The `electron` packages now places its application files in `$out/libexec/electron` instead of `$out/lib/electron`. Packages using electron-builder will fail to build and need to be adjusted by changing `lib` to `libexec`. diff --git a/nixos/modules/hardware/cpu/amd-sev.nix b/nixos/modules/hardware/cpu/amd-sev.nix index 28ee07f005b..08e1de49638 100644 --- a/nixos/modules/hardware/cpu/amd-sev.nix +++ b/nixos/modules/hardware/cpu/amd-sev.nix @@ -1,37 +1,43 @@ -{ config, lib, ... }: +{ config, options, lib, ... }: with lib; let - cfg = config.hardware.cpu.amd.sev; - defaultGroup = "sev"; -in - with lib; { - options.hardware.cpu.amd.sev = { - enable = mkEnableOption (lib.mdDoc "access to the AMD SEV device"); - user = mkOption { - description = lib.mdDoc "Owner to assign to the SEV device."; - type = types.str; - default = "root"; - }; - group = mkOption { - description = lib.mdDoc "Group to assign to the SEV device."; - type = types.str; - default = defaultGroup; - }; - mode = mkOption { - description = lib.mdDoc "Mode to set for the SEV device."; - type = types.str; - default = "0660"; - }; + cfgSev = config.hardware.cpu.amd.sev; + cfgSevGuest = config.hardware.cpu.amd.sevGuest; + + optionsFor = device: group: { + enable = mkEnableOption (lib.mdDoc "access to the AMD ${device} device"); + user = mkOption { + description = lib.mdDoc "Owner to assign to the ${device} device."; + type = types.str; + default = "root"; + }; + group = mkOption { + description = lib.mdDoc "Group to assign to the ${device} device."; + type = types.str; + default = group; }; + mode = mkOption { + description = lib.mdDoc "Mode to set for the ${device} device."; + type = types.str; + default = "0660"; + }; + }; +in +with lib; { + options.hardware.cpu.amd.sev = optionsFor "SEV" "sev"; + + options.hardware.cpu.amd.sevGuest = optionsFor "SEV guest" "sev-guest"; - config = mkIf cfg.enable { + config = mkMerge [ + # /dev/sev + (mkIf cfgSev.enable { assertions = [ { - assertion = hasAttr cfg.user config.users.users; + assertion = hasAttr cfgSev.user config.users.users; message = "Given user does not exist"; } { - assertion = (cfg.group == defaultGroup) || (hasAttr cfg.group config.users.groups); + assertion = (cfgSev.group == options.hardware.cpu.amd.sev.group.default) || (hasAttr cfgSev.group config.users.groups); message = "Given group does not exist"; } ]; @@ -40,12 +46,35 @@ in options kvm_amd sev=1 ''; - users.groups = optionalAttrs (cfg.group == defaultGroup) { - "${cfg.group}" = {}; + users.groups = optionalAttrs (cfgSev.group == options.hardware.cpu.amd.sev.group.default) { + "${cfgSev.group}" = { }; }; - services.udev.extraRules = with cfg; '' + services.udev.extraRules = with cfgSev; '' KERNEL=="sev", OWNER="${user}", GROUP="${group}", MODE="${mode}" ''; - }; - } + }) + + # /dev/sev-guest + (mkIf cfgSevGuest.enable { + assertions = [ + { + assertion = hasAttr cfgSevGuest.user config.users.users; + message = "Given user does not exist"; + } + { + assertion = (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) || (hasAttr cfgSevGuest.group config.users.groups); + message = "Given group does not exist"; + } + ]; + + users.groups = optionalAttrs (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) { + "${cfgSevGuest.group}" = { }; + }; + + services.udev.extraRules = with cfgSevGuest; '' + KERNEL=="sev-guest", OWNER="${user}", GROUP="${group}", MODE="${mode}" + ''; + }) + ]; +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 7744bbd76e6..206d5eaf75d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -499,6 +499,7 @@ ./services/games/quake3-server.nix ./services/games/teeworlds.nix ./services/games/terraria.nix + ./services/games/xonotic.nix ./services/hardware/acpid.nix ./services/hardware/actkbd.nix ./services/hardware/argonone.nix diff --git a/nixos/modules/services/games/xonotic.nix b/nixos/modules/services/games/xonotic.nix new file mode 100644 index 00000000000..c84347ddc98 --- /dev/null +++ b/nixos/modules/services/games/xonotic.nix @@ -0,0 +1,198 @@ +{ config +, pkgs +, lib +, ... +}: + +let + cfg = config.services.xonotic; + + serverCfg = pkgs.writeText "xonotic-server.cfg" ( + toString cfg.prependConfig + + "\n" + + builtins.concatStringsSep "\n" ( + lib.mapAttrsToList (key: option: + let + escape = s: lib.escape [ "\"" ] s; + quote = s: "\"${s}\""; + + toValue = x: quote (escape (toString x)); + + value = (if lib.isList option then + builtins.concatStringsSep + " " + (builtins.map (x: toValue x) option) + else + toValue option + ); + in + "${key} ${value}" + ) cfg.settings + ) + + "\n" + + toString cfg.appendConfig + ); +in + +{ + options.services.xonotic = { + enable = lib.mkEnableOption (lib.mdDoc "Xonotic dedicated server"); + + package = lib.mkPackageOption pkgs "xonotic-dedicated" {}; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc '' + Open the firewall for TCP and UDP on the specified port. + ''; + }; + + dataDir = lib.mkOption { + type = lib.types.path; + readOnly = true; + default = "/var/lib/xonotic"; + description = lib.mdDoc '' + Data directory. + ''; + }; + + settings = lib.mkOption { + description = lib.mdDoc '' + Generates the `server.cfg` file. Refer to [upstream's example][0] for + details. + + [0]: https://gitlab.com/xonotic/xonotic/-/blob/master/server/server.cfg + ''; + default = {}; + type = lib.types.submodule { + freeformType = with lib.types; let + scalars = oneOf [ singleLineStr int float ]; + in + attrsOf (oneOf [ scalars (nonEmptyListOf scalars) ]); + + options.sv_public = lib.mkOption { + type = lib.types.int; + default = 0; + example = [ (-1) 1 ]; + description = lib.mdDoc '' + Controls whether the server will be publicly listed. + ''; + }; + + options.hostname = lib.mkOption { + type = lib.types.singleLineStr; + default = "Xonotic $g_xonoticversion Server"; + description = lib.mdDoc '' + The name that will appear in the server list. `$g_xonoticversion` + gets replaced with the current version. + ''; + }; + + options.sv_motd = lib.mkOption { + type = lib.types.singleLineStr; + default = ""; + description = lib.mdDoc '' + Text displayed when players join the server. + ''; + }; + + options.sv_termsofservice_url = lib.mkOption { + type = lib.types.singleLineStr; + default = ""; + description = lib.mdDoc '' + URL for the Terms of Service for playing on your server. + ''; + }; + + options.maxplayers = lib.mkOption { + type = lib.types.int; + default = 16; + description = lib.mdDoc '' + Number of player slots on the server, including spectators. + ''; + }; + + options.net_address = lib.mkOption { + type = lib.types.singleLineStr; + default = "0.0.0.0"; + description = lib.mdDoc '' + The address Xonotic will listen on. + ''; + }; + + options.port = lib.mkOption { + type = lib.types.port; + default = 26000; + description = lib.mdDoc '' + The port Xonotic will listen on. + ''; + }; + }; + }; + + # Still useful even though we're using RFC 42 settings because *some* keys + # can be repeated. + appendConfig = lib.mkOption { + type = with lib.types; nullOr lines; + default = null; + description = lib.mdDoc '' + Literal text to insert at the end of `server.cfg`. + ''; + }; + + # Certain changes need to happen at the beginning of the file. + prependConfig = lib.mkOption { + type = with lib.types; nullOr lines; + default = null; + description = lib.mdDoc '' + Literal text to insert at the start of `server.cfg`. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.xonotic = { + description = "Xonotic server"; + wantedBy = [ "multi-user.target" ]; + + environment = { + # Required or else it tries to write the lock file into the nix store + HOME = cfg.dataDir; + }; + + serviceConfig = { + DynamicUser = true; + User = "xonotic"; + StateDirectory = "xonotic"; + ExecStart = "${cfg.package}/bin/xonotic-dedicated"; + + # Symlink the configuration from the nix store to where Xonotic actually + # looks for it + ExecStartPre = [ + "${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/.xonotic/data" + '' + ${pkgs.coreutils}/bin/ln -sf ${serverCfg} \ + ${cfg.dataDir}/.xonotic/data/server.cfg + '' + ]; + + # Cargo-culted from search results about writing Xonotic systemd units + ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; + + Restart = "on-failure"; + RestartSec = 10; + StartLimitBurst = 5; + }; + }; + + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ + cfg.settings.port + ]; + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ + cfg.settings.port + ]; + }; + + meta.maintainers = with lib.maintainers; [ CobaltCause ]; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 66aff30b5ed..1d06893bf1d 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -68,6 +68,7 @@ let "redis" "rspamd" "rtl_433" + "sabnzbd" "scaphandre" "script" "shelly" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix b/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix new file mode 100644 index 00000000000..41127749401 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/sabnzbd.nix @@ -0,0 +1,47 @@ +{ config, lib, pkgs, options }: + +let + inherit (lib) mkOption types; + cfg = config.services.prometheus.exporters.sabnzbd; +in +{ + port = 9387; + + extraOpts = { + servers = mkOption { + description = "List of sabnzbd servers to connect to."; + type = types.listOf (types.submodule { + options = { + baseUrl = mkOption { + type = types.str; + description = "Base URL of the sabnzbd server."; + example = "http://localhost:8080/sabnzbd"; + }; + apiKeyFile = mkOption { + type = types.str; + description = "File containing the API key."; + example = "/run/secrets/sabnzbd_apikey"; + }; + }; + }); + }; + }; + + serviceOpts = + let + servers = lib.zipAttrs cfg.servers; + apiKeys = lib.concatStringsSep "," (builtins.map (file: "$(cat ${file})") servers.apiKeyFile); + in + { + environment = { + METRICS_PORT = toString cfg.port; + METRICS_ADDR = cfg.listenAddress; + SABNZBD_BASEURLS = lib.concatStringsSep "," servers.baseUrl; + }; + + script = '' + export SABNZBD_APIKEYS="${apiKeys}" + exec ${lib.getExe pkgs.prometheus-sabnzbd-exporter} + ''; + }; +} diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index dfa883a2c33..679567cbb73 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -173,6 +173,33 @@ let }]; })); + bridgeNetworks = mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "bridge"; + }; + }; + networks = listToAttrs (forEach bridge.interfaces (bi: + nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { + DHCP = mkOverride 0 (dhcpStr false); + networkConfig.Bridge = name; + } ]))); + })); + + vlanNetworks = mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { + netdevs."40-${name}" = { + netdevConfig = { + Name = name; + Kind = "vlan"; + }; + vlanConfig.Id = vlan.id; + }; + networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { + vlan = [ name ]; + } ]); + })); + in { @@ -182,7 +209,15 @@ in # Note this is if initrd.network.enable, not if # initrd.systemd.network.enable. By setting the latter and not the # former, the user retains full control over the configuration. - boot.initrd.systemd.network = mkMerge [(genericDhcpNetworks true) interfaceNetworks]; + boot.initrd.systemd.network = mkMerge [ + (genericDhcpNetworks true) + interfaceNetworks + bridgeNetworks + vlanNetworks + ]; + boot.initrd.availableKernelModules = + optional (cfg.bridges != {}) "bridge" ++ + optional (cfg.vlans != {}) "8021q"; }) (mkIf cfg.useNetworkd { @@ -212,19 +247,7 @@ in } (genericDhcpNetworks false) interfaceNetworks - (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { - netdevs."40-${name}" = { - netdevConfig = { - Name = name; - Kind = "bridge"; - }; - }; - networks = listToAttrs (forEach bridge.interfaces (bi: - nameValuePair "40-${bi}" (mkMerge [ (genericNetwork (mkOverride 999)) { - DHCP = mkOverride 0 (dhcpStr false); - networkConfig.Bridge = name; - } ]))); - }))) + bridgeNetworks (mkMerge (flip mapAttrsToList cfg.bonds (name: bond: { netdevs."40-${name}" = { netdevConfig = { @@ -377,18 +400,7 @@ in } ]); }; }))) - (mkMerge (flip mapAttrsToList cfg.vlans (name: vlan: { - netdevs."40-${name}" = { - netdevConfig = { - Name = name; - Kind = "vlan"; - }; - vlanConfig.Id = vlan.id; - }; - networks."40-${vlan.interface}" = (mkMerge [ (genericNetwork (mkOverride 999)) { - vlan = [ name ]; - } ]); - }))) + vlanNetworks ]; # We need to prefill the slaved devices with networking options diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index a9bac3346b9..a3e85c337aa 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -109,6 +109,7 @@ in { allTerminfo = handleTest ./all-terminfo.nix {}; alps = handleTest ./alps.nix {}; amazon-init-shell = handleTest ./amazon-init-shell.nix {}; + amd-sev = runTest ./amd-sev.nix; anbox = runTest ./anbox.nix; anuko-time-tracker = handleTest ./anuko-time-tracker.nix {}; apcupsd = handleTest ./apcupsd.nix {}; @@ -764,6 +765,7 @@ in { systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {}; systemd-credentials-tpm2 = handleTest ./systemd-credentials-tpm2.nix {}; systemd-escaping = handleTest ./systemd-escaping.nix {}; + systemd-initrd-bridge = handleTest ./systemd-initrd-bridge.nix {}; systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {}; systemd-initrd-luks-fido2 = handleTest ./systemd-initrd-luks-fido2.nix {}; systemd-initrd-luks-keyfile = handleTest ./systemd-initrd-luks-keyfile.nix {}; @@ -778,6 +780,7 @@ in { systemd-initrd-networkd = handleTest ./systemd-initrd-networkd.nix {}; systemd-initrd-networkd-ssh = handleTest ./systemd-initrd-networkd-ssh.nix {}; systemd-initrd-networkd-openvpn = handleTest ./initrd-network-openvpn { systemdStage1 = true; }; + systemd-initrd-vlan = handleTest ./systemd-initrd-vlan.nix {}; systemd-journal = handleTest ./systemd-journal.nix {}; systemd-machinectl = handleTest ./systemd-machinectl.nix {}; systemd-networkd = handleTest ./systemd-networkd.nix {}; diff --git a/nixos/tests/amd-sev.nix b/nixos/tests/amd-sev.nix new file mode 100644 index 00000000000..bf9a50c10d0 --- /dev/null +++ b/nixos/tests/amd-sev.nix @@ -0,0 +1,56 @@ +{ lib, ... }: { + name = "amd-sev"; + meta = { + maintainers = with lib.maintainers; [ trundle veehaitch ]; + }; + + nodes.machine = { lib, ... }: { + hardware.cpu.amd.sev.enable = true; + hardware.cpu.amd.sevGuest.enable = true; + + specialisation.sevCustomUserGroup.configuration = { + users.groups.sevtest = { }; + + hardware.cpu.amd.sev = { + enable = true; + group = "root"; + mode = "0600"; + }; + hardware.cpu.amd.sevGuest = { + enable = true; + group = "sevtest"; + }; + }; + }; + + testScript = { nodes, ... }: + let + specialisations = "${nodes.machine.system.build.toplevel}/specialisation"; + in + '' + machine.wait_for_unit("multi-user.target") + + with subtest("Check default settings"): + out = machine.succeed("cat /etc/udev/rules.d/99-local.rules") + assert 'KERNEL=="sev", OWNER="root", GROUP="sev", MODE="0660"' in out + assert 'KERNEL=="sev-guest", OWNER="root", GROUP="sev-guest", MODE="0660"' in out + + out = machine.succeed("cat /etc/group") + assert "sev:" in out + assert "sev-guest:" in out + assert "sevtest:" not in out + + with subtest("Activate configuration with custom user/group"): + machine.succeed('${specialisations}/sevCustomUserGroup/bin/switch-to-configuration test') + + with subtest("Check custom user and group"): + out = machine.succeed("cat /etc/udev/rules.d/99-local.rules") + assert 'KERNEL=="sev", OWNER="root", GROUP="root", MODE="0600"' in out + assert 'KERNEL=="sev-guest", OWNER="root", GROUP="sevtest", MODE="0660"' in out + + out = machine.succeed("cat /etc/group") + assert "sev:" not in out + assert "sev-guest:" not in out + assert "sevtest:" in out + ''; +} diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index 306c5e071e7..7db7fdf13eb 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -1178,6 +1178,44 @@ let ''; }; + sabnzbd = { + exporterConfig = { + enable = true; + servers = [{ + baseUrl = "http://localhost:8080"; + apiKeyFile = "/var/sabnzbd-apikey"; + }]; + }; + + metricProvider = { + services.sabnzbd.enable = true; + + # unrar is required for sabnzbd + nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (pkgs.lib.getName pkg) [ "unrar" ]; + + # extract the generated api key before starting + systemd.services.sabnzbd-apikey = { + requires = [ "sabnzbd.service" ]; + after = [ "sabnzbd.service" ]; + requiredBy = [ "prometheus-sabnzbd-exporter.service" ]; + before = [ "prometheus-sabnzbd-exporter.service" ]; + script = '' + grep -Po '^api_key = \K.+' /var/lib/sabnzbd/sabnzbd.ini > /var/sabnzbd-apikey + ''; + }; + }; + + exporterTest = '' + wait_for_unit("sabnzbd.service") + wait_for_unit("prometheus-sabnzbd-exporter.service") + wait_for_open_port(8080) + wait_for_open_port(9387) + wait_until_succeeds( + "curl -sSf 'localhost:9387/metrics' | grep 'sabnzbd_queue_size{sabnzbd_instance=\"http://localhost:8080\"} 0.0'" + ) + ''; + }; + scaphandre = { exporterConfig = { enable = true; diff --git a/nixos/tests/systemd-initrd-bridge.nix b/nixos/tests/systemd-initrd-bridge.nix new file mode 100644 index 00000000000..f48a46ff2b9 --- /dev/null +++ b/nixos/tests/systemd-initrd-bridge.nix @@ -0,0 +1,63 @@ +import ./make-test-python.nix ({ lib, ... }: { + name = "systemd-initrd-bridge"; + meta.maintainers = [ lib.maintainers.majiir ]; + + # Tests bridge interface configuration in systemd-initrd. + # + # The 'a' and 'b' nodes are connected to a 'bridge' node through different + # links. The 'bridge' node configures a bridge across them. It waits forever + # in initrd (stage 1) with networking enabled. 'a' and 'b' ping 'bridge' to + # test connectivity with the bridge interface. Then, 'a' pings 'b' to test + # the bridge itself. + + nodes = { + bridge = { config, lib, ... }: { + boot.initrd.systemd.enable = true; + boot.initrd.network.enable = true; + boot.initrd.systemd.services.boot-blocker = { + before = [ "initrd.target" ]; + wantedBy = [ "initrd.target" ]; + script = "sleep infinity"; + serviceConfig.Type = "oneshot"; + }; + + networking.primaryIPAddress = "192.168.1.${toString config.virtualisation.test.nodeNumber}"; + + virtualisation.vlans = [ 1 2 ]; + networking.bridges.br0.interfaces = [ "eth1" "eth2" ]; + + networking.interfaces = { + eth1.ipv4.addresses = lib.mkForce []; + eth2.ipv4.addresses = lib.mkForce []; + br0.ipv4.addresses = [{ + address = config.networking.primaryIPAddress; + prefixLength = 24; + }]; + }; + }; + + a = { + virtualisation.vlans = [ 1 ]; + }; + + b = { config, ... }: { + virtualisation.vlans = [ 2 ]; + networking.primaryIPAddress = lib.mkForce "192.168.1.${toString config.virtualisation.test.nodeNumber}"; + networking.interfaces.eth1.ipv4.addresses = lib.mkForce [{ + address = config.networking.primaryIPAddress; + prefixLength = 24; + }]; + }; + }; + + testScript = '' + start_all() + a.wait_for_unit("network.target") + b.wait_for_unit("network.target") + + a.succeed("ping -n -w 10 -c 1 bridge >&2") + b.succeed("ping -n -w 10 -c 1 bridge >&2") + + a.succeed("ping -n -w 10 -c 1 b >&2") + ''; +}) diff --git a/nixos/tests/systemd-initrd-vlan.nix b/nixos/tests/systemd-initrd-vlan.nix new file mode 100644 index 00000000000..5060163a047 --- /dev/null +++ b/nixos/tests/systemd-initrd-vlan.nix @@ -0,0 +1,59 @@ +import ./make-test-python.nix ({ lib, ... }: { + name = "systemd-initrd-vlan"; + meta.maintainers = [ lib.maintainers.majiir ]; + + # Tests VLAN interface configuration in systemd-initrd. + # + # Two nodes are configured for a tagged VLAN. (Note that they also still have + # their ordinary eth0 and eth1 interfaces, which are not VLAN-tagged.) + # + # The 'server' node waits forever in initrd (stage 1) with networking + # enabled. The 'client' node pings it to test network connectivity. + + nodes = let + network = id: { + networking = { + vlans."eth1.10" = { + id = 10; + interface = "eth1"; + }; + interfaces."eth1.10" = { + ipv4.addresses = [{ + address = "192.168.10.${id}"; + prefixLength = 24; + }]; + }; + }; + }; + in { + # Node that will use initrd networking. + server = network "1" // { + boot.initrd.systemd.enable = true; + boot.initrd.network.enable = true; + boot.initrd.systemd.services.boot-blocker = { + before = [ "initrd.target" ]; + wantedBy = [ "initrd.target" ]; + script = "sleep infinity"; + serviceConfig.Type = "oneshot"; + }; + }; + + # Node that will ping the server. + client = network "2"; + }; + + testScript = '' + start_all() + client.wait_for_unit("network.target") + + # Wait for the regular (untagged) interface to be up. + def server_is_up(_) -> bool: + status, _ = client.execute("ping -n -c 1 server >&2") + return status == 0 + with client.nested("waiting for server to come up"): + retry(server_is_up) + + # Try to ping the (tagged) VLAN interface. + client.succeed("ping -n -w 10 -c 1 192.168.10.1 >&2") + ''; +}) diff --git a/nixos/tests/tinywl.nix b/nixos/tests/tinywl.nix index 411cdb1f641..9199866b57a 100644 --- a/nixos/tests/tinywl.nix +++ b/nixos/tests/tinywl.nix @@ -16,6 +16,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: systemPackages = with pkgs; [ tinywl foot wayland-utils ]; }; + hardware.opengl.enable = true; + # Automatically start TinyWL when logging in on tty1: programs.bash.loginShellInit = '' if [ "$(tty)" = "/dev/tty1" ]; then |