diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2311.section.md | 8 | ||||
-rw-r--r-- | nixos/lib/testing/driver.nix | 7 | ||||
-rw-r--r-- | nixos/modules/security/sudo.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/matrix/mautrix-telegram.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/misc/atuin.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/misc/gitlab.nix | 7 | ||||
-rw-r--r-- | nixos/modules/services/monitoring/mimir.nix | 14 | ||||
-rw-r--r-- | nixos/modules/services/networking/dae.nix | 170 | ||||
-rw-r--r-- | nixos/modules/services/networking/jool.nix | 313 | ||||
-rw-r--r-- | nixos/modules/services/networking/nftables.nix | 22 | ||||
-rw-r--r-- | nixos/modules/virtualisation/anbox.nix | 59 | ||||
-rw-r--r-- | nixos/modules/virtualisation/lxd.nix | 127 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 6 | ||||
-rw-r--r-- | nixos/tests/anbox.nix | 40 | ||||
-rw-r--r-- | nixos/tests/dae.nix | 29 | ||||
-rw-r--r-- | nixos/tests/jool.nix | 106 | ||||
-rw-r--r-- | nixos/tests/lxd/container.nix | 3 | ||||
-rw-r--r-- | nixos/tests/lxd/default.nix | 4 | ||||
-rw-r--r-- | nixos/tests/lxd/preseed.nix | 71 |
19 files changed, 726 insertions, 267 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index aa6197039244..8f02975d5382 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -38,7 +38,7 @@ - [stalwart-mail](https://stalw.art), an all-in-one email server (SMTP, IMAP, JMAP). Available as [services.stalwart-mail](#opt-services.stalwart-mail.enable). -- [Jool](https://nicmx.github.io/Jool/en/index.html), an Open Source implementation of IPv4/IPv6 translation on Linux. Available as [networking.jool.enable](#opt-networking.jool.enable). +- [Jool](https://nicmx.github.io/Jool/en/index.html), a kernelspace NAT64 and SIIT implementation, providing translation between IPv4 and IPv6. Available as [networking.jool.enable](#opt-networking.jool.enable). - [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services. @@ -94,6 +94,8 @@ - `etcd` has been updated to 3.5, you will want to read the [3.3 to 3.4](https://etcd.io/docs/v3.5/upgrades/upgrade_3_4/) and [3.4 to 3.5](https://etcd.io/docs/v3.5/upgrades/upgrade_3_5/) upgrade guides +- `gitlab` installations created or updated between versions \[15.11.0, 15.11.2] have an incorrect database schema. This will become a problem when upgrading to `gitlab` >=16.2.0. A workaround for affected users can be found in the [GitLab docs](https://docs.gitlab.com/ee/update/versions/gitlab_16_changes.html#undefined-column-error-upgrading-to-162-or-later). + - `consul` has been updated to `1.16.0`. See the [release note](https://github.com/hashicorp/consul/releases/tag/v1.16.0) for more details. Once a new Consul version has started and upgraded its data directory, it generally cannot be downgraded to the previous version. - `himalaya` has been updated to `0.8.0`, which drops the native TLS support (in favor of Rustls) and add OAuth 2.0 support. See the [release note](https://github.com/soywod/himalaya/releases/tag/v0.8.0) for more details. @@ -175,6 +177,8 @@ - The `html-proofer` package has been updated from major version 3 to major version 5, which includes [breaking changes](https://github.com/gjtorikian/html-proofer/blob/v5.0.8/UPGRADING.md). +- `kratos` has been updated from 0.10.1 to the first stable version 1.0.0, please read the [0.10.1 to 0.11.0](https://github.com/ory/kratos/releases/tag/v0.11.0), [0.11.0 to 0.11.1](https://github.com/ory/kratos/releases/tag/v0.11.1), [0.11.1 to 0.13.0](https://github.com/ory/kratos/releases/tag/v0.13.0) and [0.13.0 to 1.0.0](https://github.com/ory/kratos/releases/tag/v1.0.0) upgrade guides. The most notable breaking change is the introduction of one-time passwords (`code`) and update of the default recovery strategy from `link` to `code`. + ## Other Notable Changes {#sec-release-23.11-notable-changes} - The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration. @@ -243,6 +247,8 @@ The module update takes care of the new config syntax and the data itself (user - `networking.nftables` is no longer flushing all rulesets on every reload. Use `networking.nftables.flushRuleset = true;` to get back the old behaviour. +- The `cawbird` package is dropped from nixpkgs, as it got broken by the Twitter API closing down and has been abandoned upstream. + ## Nixpkgs internals {#sec-release-23.11-nixpkgs-internals} - The use of `sourceRoot = "source";`, `sourceRoot = "source/subdir";`, and similar lines in package derivations using the default `unpackPhase` is deprecated as it requires `unpackPhase` to always produce a directory named "source". Use `sourceRoot = src.name`, `sourceRoot = "${src.name}/subdir";`, or `setSourceRoot = "sourceRoot=$(echo */subdir)";` or similar instead. diff --git a/nixos/lib/testing/driver.nix b/nixos/lib/testing/driver.nix index 23574698c062..cc97ca72083f 100644 --- a/nixos/lib/testing/driver.nix +++ b/nixos/lib/testing/driver.nix @@ -175,7 +175,12 @@ in }; config = { - _module.args.hostPkgs = config.hostPkgs; + _module.args = { + hostPkgs = + # Comment is in nixos/modules/misc/nixpkgs.nix + lib.mkOverride lib.modules.defaultOverridePriority + config.hostPkgs.__splicedPackages; + }; driver = withChecks driver; diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index 9ac91bd0d368..d225442773c6 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -192,6 +192,10 @@ in ###### implementation config = mkIf cfg.enable { + assertions = [ + { assertion = cfg.package.pname != "sudo-rs"; + message = "The NixOS `sudo` module does not work with `sudo-rs` yet."; } + ]; # We `mkOrder 600` so that the default rule shows up first, but there is # still enough room for a user to `mkBefore` it. diff --git a/nixos/modules/services/matrix/mautrix-telegram.nix b/nixos/modules/services/matrix/mautrix-telegram.nix index 17032ed808e9..97a6ba858e00 100644 --- a/nixos/modules/services/matrix/mautrix-telegram.nix +++ b/nixos/modules/services/matrix/mautrix-telegram.nix @@ -159,7 +159,6 @@ in { if [ ! -f '${registrationFile}' ]; then ${pkgs.mautrix-telegram}/bin/mautrix-telegram \ --generate-registration \ - --base-config='${pkgs.mautrix-telegram}/${pkgs.mautrix-telegram.pythonModule.sitePackages}/mautrix_telegram/example-config.yaml' \ --config='${settingsFile}' \ --registration='${registrationFile}' fi diff --git a/nixos/modules/services/misc/atuin.nix b/nixos/modules/services/misc/atuin.nix index 57ff02df7d68..8d2c1b5242ff 100644 --- a/nixos/modules/services/misc/atuin.nix +++ b/nixos/modules/services/misc/atuin.nix @@ -6,7 +6,7 @@ in { options = { services.atuin = { - enable = lib.mkEnableOption (mdDoc "Enable server for shell history sync with atuin"); + enable = lib.mkEnableOption (mdDoc "Atuin server for shell history sync"); openRegistration = mkOption { type = types.bool; diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index c5e38b498829..b399ccc38f58 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -1088,6 +1088,11 @@ in { ''Support for container registries other than gitlab-container-registry has ended since GitLab 16.0.0 and is scheduled for removal in a future release. Please back up your data and migrate to the gitlab-container-registry package.'' ) + (mkIf + (versionAtLeast (getVersion cfg.packages.gitlab) "16.2.0" && versionOlder (getVersion cfg.packages.gitlab) "16.5.0") + ''GitLab instances created or updated between versions [15.11.0, 15.11.2] have an incorrect database schema. + Check the upstream documentation for a workaround: https://docs.gitlab.com/ee/update/versions/gitlab_16_changes.html#undefined-column-error-upgrading-to-162-or-later'' + ) ]; assertions = [ @@ -1655,7 +1660,7 @@ in { Restart = "on-failure"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; ExecStart = concatStringsSep " " [ - "${cfg.packages.gitlab.rubyEnv}/bin/puma" + "${cfg.packages.gitlab.rubyEnv}/bin/bundle" "exec" "puma" "-e production" "-C ${cfg.statePath}/config/puma.rb" "-w ${cfg.puma.workers}" diff --git a/nixos/modules/services/monitoring/mimir.nix b/nixos/modules/services/monitoring/mimir.nix index edca9b7be4ff..6ed139b22974 100644 --- a/nixos/modules/services/monitoring/mimir.nix +++ b/nixos/modules/services/monitoring/mimir.nix @@ -32,11 +32,21 @@ in { type = types.package; description = lib.mdDoc ''Mimir package to use.''; }; + + extraFlags = mkOption { + type = types.listOf types.str; + default = []; + example = [ "--config.expand-env=true" ]; + description = lib.mdDoc '' + Specify a list of additional command line flags, + which get escaped and are then passed to Mimir. + ''; + }; }; config = mkIf cfg.enable { # for mimirtool - environment.systemPackages = [ pkgs.mimir ]; + environment.systemPackages = [ cfg.package ]; assertions = [{ assertion = ( @@ -60,7 +70,7 @@ in { else cfg.configFile; in { - ExecStart = "${cfg.package}/bin/mimir --config.file=${conf}"; + ExecStart = "${cfg.package}/bin/mimir --config.file=${conf} ${escapeShellArgs cfg.extraFlags}"; DynamicUser = true; Restart = "always"; ProtectSystem = "full"; diff --git a/nixos/modules/services/networking/dae.nix b/nixos/modules/services/networking/dae.nix index 231c555b3303..42ed3c7f8d4a 100644 --- a/nixos/modules/services/networking/dae.nix +++ b/nixos/modules/services/networking/dae.nix @@ -1,41 +1,161 @@ -{ config, pkgs, lib, ... }: +{ config, lib, pkgs, ... }: + let cfg = config.services.dae; + assets = cfg.assets; + genAssetsDrv = paths: pkgs.symlinkJoin { + name = "dae-assets"; + inherit paths; + }; in { - meta.maintainers = with lib.maintainers; [ pokon548 ]; + meta.maintainers = with lib.maintainers; [ pokon548 oluceps ]; options = { - services.dae = { - enable = lib.options.mkEnableOption (lib.mdDoc "the dae service"); - package = lib.mkPackageOptionMD pkgs "dae" { }; + services.dae = with lib;{ + enable = mkEnableOption + (mdDoc "A Linux high-performance transparent proxy solution based on eBPF"); + + package = mkPackageOptionMD pkgs "dae" { }; + + assets = mkOption { + type = with types;(listOf path); + default = with pkgs; [ v2ray-geoip v2ray-domain-list-community ]; + defaultText = literalExpression "with pkgs; [ v2ray-geoip v2ray-domain-list-community ]"; + description = mdDoc '' + Assets required to run dae. + ''; + }; + + assetsPath = mkOption { + type = types.str; + default = "${genAssetsDrv assets}/share/v2ray"; + defaultText = literalExpression '' + (symlinkJoin { + name = "dae-assets"; + paths = assets; + })/share/v2ray + ''; + description = mdDoc '' + The path which contains geolocation database. + This option will override `assets`. + ''; + }; + + openFirewall = mkOption { + type = with types; submodule { + options = { + enable = mkEnableOption "enable"; + port = mkOption { + type = types.int; + description = '' + Port to be opened. Consist with field `tproxy_port` in config file. + ''; + }; + }; + }; + default = { + enable = true; + port = 12345; + }; + defaultText = literalExpression '' + { + enable = true; + port = 12345; + } + ''; + description = mdDoc '' + Open the firewall port. + ''; + }; + + configFile = mkOption { + type = types.path; + default = "/etc/dae/config.dae"; + example = "/path/to/your/config.dae"; + description = mdDoc '' + The path of dae config file, end with `.dae`. + ''; + }; + + config = mkOption { + type = types.str; + default = '' + global{} + routing{} + ''; + description = mdDoc '' + Config text for dae. + + See <https://github.com/daeuniverse/dae/blob/main/example.dae>. + ''; + }; + + disableTxChecksumIpGeneric = + mkEnableOption (mdDoc "See <https://github.com/daeuniverse/dae/issues/43>"); + }; }; - config = lib.mkIf config.services.dae.enable { - networking.firewall.allowedTCPPorts = [ 12345 ]; - networking.firewall.allowedUDPPorts = [ 12345 ]; + config = lib.mkIf cfg.enable + + { + environment.systemPackages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; - systemd.services.dae = { - unitConfig = { - Description = "dae Service"; - Documentation = "https://github.com/daeuniverse/dae"; - After = [ "network-online.target" "systemd-sysctl.service" ]; - Wants = [ "network-online.target" ]; + environment.etc."dae/config.dae" = { + mode = "0400"; + source = pkgs.writeText "config.dae" cfg.config; }; - serviceConfig = { - User = "root"; - ExecStartPre = "${lib.getExe cfg.package} validate -c /etc/dae/config.dae"; - ExecStart = "${lib.getExe cfg.package} run --disable-timestamp -c /etc/dae/config.dae"; - ExecReload = "${lib.getExe cfg.package} reload $MAINPID"; - LimitNPROC = 512; - LimitNOFILE = 1048576; - Restart = "on-abnormal"; - Type = "notify"; + networking = lib.mkIf cfg.openFirewall.enable { + firewall = + let portToOpen = cfg.openFirewall.port; + in + { + allowedTCPPorts = [ portToOpen ]; + allowedUDPPorts = [ portToOpen ]; + }; }; - wantedBy = [ "multi-user.target" ]; + systemd.services.dae = + let + daeBin = lib.getExe cfg.package; + TxChecksumIpGenericWorkaround = with lib;(getExe pkgs.writeShellApplication { + name = "disable-tx-checksum-ip-generic"; + text = with pkgs; '' + iface=$(${iproute2}/bin/ip route | ${lib.getExe gawk} '/default/ {print $5}') + ${lib.getExe ethtool} -K "$iface" tx-checksum-ip-generic off + ''; + }); + in + { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStartPre = [ "" "${daeBin} validate -c ${cfg.configFile}" ] + ++ (with lib; optional cfg.disableTxChecksumIpGeneric TxChecksumIpGenericWorkaround); + ExecStart = [ "" "${daeBin} run --disable-timestamp -c ${cfg.configFile}" ]; + Environment = "DAE_LOCATION_ASSET=${cfg.assetsPath}"; + }; + }; + + assertions = [ + { + assertion = lib.pathExists (toString (genAssetsDrv cfg.assets) + "/share/v2ray"); + message = '' + Packages in `assets` has no preset paths included. + Please set `assetsPath` instead. + ''; + } + + { + assertion = !((config.services.dae.config != "global{}\nrouting{}\n") + && (config.services.dae.configFile != "/etc/dae/config.dae")); + message = '' + Option `config` and `configFile` could not be set + at the same time. + ''; + } + ]; }; - }; } diff --git a/nixos/modules/services/networking/jool.nix b/nixos/modules/services/networking/jool.nix index 3aafbe40967c..d2d2b0956e8a 100644 --- a/nixos/modules/services/networking/jool.nix +++ b/nixos/modules/services/networking/jool.nix @@ -16,7 +16,7 @@ let TemporaryFileSystem = [ "/" ]; BindReadOnlyPaths = [ builtins.storeDir - "/run/current-system/kernel-modules" + "/run/booted-system/kernel-modules" ]; # Give capabilities to load the module and configure it @@ -31,26 +31,96 @@ let configFormat = pkgs.formats.json {}; - mkDefaultAttrs = lib.mapAttrs (n: v: lib.mkDefault v); + # Generate the config file of instance `name` + nat64Conf = name: + configFormat.generate "jool-nat64-${name}.conf" + (cfg.nat64.${name} // { instance = name; }); + siitConf = name: + configFormat.generate "jool-siit-${name}.conf" + (cfg.siit.${name} // { instance = name; }); + + # NAT64 config type + nat64Options = lib.types.submodule { + # The format is plain JSON + freeformType = configFormat.type; + # Some options with a default value + options.framework = lib.mkOption { + type = lib.types.enum [ "netfilter" "iptables" ]; + default = "netfilter"; + description = lib.mdDoc '' + The framework to use for attaching Jool's translation to the exist + kernel packet processing rules. See the + [documentation](https://nicmx.github.io/Jool/en/intro-jool.html#design) + for the differences between the two options. + ''; + }; + options.global.pool6 = lib.mkOption { + type = lib.types.strMatching "[[:xdigit:]:]+/[[:digit:]]+" + // { description = "Network prefix in CIDR notation"; }; + default = "64:ff9b::/96"; + description = lib.mdDoc '' + The prefix used for embedding IPv4 into IPv6 addresses. + Defaults to the well-known NAT64 prefix, defined by + [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). + ''; + }; + }; - defaultNat64 = { - instance = "default"; - framework = "netfilter"; - global.pool6 = "64:ff9b::/96"; + # SIIT config type + siitOptions = lib.types.submodule { + # The format is, again, plain JSON + freeformType = configFormat.type; + # Some options with a default value + options = { inherit (nat64Options.getSubOptions []) framework; }; + }; + + makeNat64Unit = name: opts: { + "jool-nat64-${name}" = { + description = "Jool, NAT64 setup of instance ${name}"; + documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStartPre = "${pkgs.kmod}/bin/modprobe jool"; + ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf name}"; + ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf name} instance remove"; + } // hardening; + }; }; - defaultSiit = { - instance = "default"; - framework = "netfilter"; + + makeSiitUnit = name: opts: { + "jool-siit-${name}" = { + description = "Jool, SIIT setup of instance ${name}"; + documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit"; + ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf name}"; + ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf name} instance remove"; + } // hardening; + }; }; - nat64Conf = configFormat.generate "jool-nat64.conf" cfg.nat64.config; - siitConf = configFormat.generate "jool-siit.conf" cfg.siit.config; + checkNat64 = name: _: '' + printf 'Validating Jool configuration for NAT64 instance "${name}"... ' + jool file check ${nat64Conf name} + printf 'Ok.\n'; touch "$out" + ''; + + checkSiit = name: _: '' + printf 'Validating Jool configuration for SIIT instance "${name}"... ' + jool_siit file check ${siitConf name} + printf 'Ok.\n'; touch "$out" + ''; in { - ###### interface - options = { networking.jool.enable = lib.mkOption { type = lib.types.bool; @@ -64,157 +134,146 @@ in NAT64, analogous to the IPv4 NAPT. Refer to the upstream [documentation](https://nicmx.github.io/Jool/en/intro-xlat.html) for the supported modes of translation and how to configure them. + + Enabling this option will install the Jool kernel module and the + command line tools for controlling it. ''; }; - networking.jool.nat64.enable = lib.mkEnableOption (lib.mdDoc "a NAT64 instance of Jool."); - networking.jool.nat64.config = lib.mkOption { - type = configFormat.type; - default = defaultNat64; + networking.jool.nat64 = lib.mkOption { + type = lib.types.attrsOf nat64Options; + default = { }; example = lib.literalExpression '' { - # custom NAT64 prefix - global.pool6 = "2001:db8:64::/96"; - - # Port forwarding - bib = [ - { # SSH 192.0.2.16 → 2001:db8:a::1 - "protocol" = "TCP"; - "ipv4 address" = "192.0.2.16#22"; - "ipv6 address" = "2001:db8:a::1#22"; - } - { # DNS (TCP) 192.0.2.16 → 2001:db8:a::2 - "protocol" = "TCP"; - "ipv4 address" = "192.0.2.16#53"; - "ipv6 address" = "2001:db8:a::2#53"; - } - { # DNS (UDP) 192.0.2.16 → 2001:db8:a::2 - "protocol" = "UDP"; - "ipv4 address" = "192.0.2.16#53"; - "ipv6 address" = "2001:db8:a::2#53"; - } - ]; - - pool4 = [ - # Ports for dynamic translation - { protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; } - { protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; } - { protocol = "ICMP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; } - - # Ports for static BIB entries - { protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "22"; } - { protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "53"; } - ]; + default = { + # custom NAT64 prefix + global.pool6 = "2001:db8:64::/96"; + + # Port forwarding + bib = [ + { # SSH 192.0.2.16 → 2001:db8:a::1 + "protocol" = "TCP"; + "ipv4 address" = "192.0.2.16#22"; + "ipv6 address" = "2001:db8:a::1#22"; + } + { # DNS (TCP) 192.0.2.16 → 2001:db8:a::2 + "protocol" = "TCP"; + "ipv4 address" = "192.0.2.16#53"; + "ipv6 address" = "2001:db8:a::2#53"; + } + { # DNS (UDP) 192.0.2.16 → 2001:db8:a::2 + "protocol" = "UDP"; + "ipv4 address" = "192.0.2.16#53"; + "ipv6 address" = "2001:db8:a::2#53"; + } + ]; + + pool4 = [ + # Port ranges for dynamic translation + { protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; } + { protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; } + { protocol = "ICMP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; } + + # Ports for static BIB entries + { protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "22"; } + { protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "53"; } + ]; + }; } ''; description = lib.mdDoc '' - The configuration of a stateful NAT64 instance of Jool managed through - NixOS. See https://nicmx.github.io/Jool/en/config-atomic.html for the - available options. + Definitions of NAT64 instances of Jool. + See the + [documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for + the available options. Also check out the + [tutorial](https://nicmx.github.io/Jool/en/run-nat64.html) for an + introduction to NAT64 and how to troubleshoot the setup. + + The attribute name defines the name of the instance, with the main one + being `default`: this can be accessed from the command line without + specifying the name with `-i`. ::: {.note} - Existing or more instances created manually will not interfere with the - NixOS instance, provided the respective `pool4` addresses and port - ranges are not overlapping. + Instances created imperatively from the command line will not interfere + with the NixOS instances, provided the respective `pool4` addresses and + port ranges are not overlapping. ::: ::: {.warning} - Changes to the NixOS instance performed via `jool instance nixos-nat64` - are applied correctly but will be lost after restarting - `jool-nat64.service`. + Changes to an instance performed via `jool -i <name>` are applied + correctly but will be lost after restarting the respective + `jool-nat64-<name>.service`. ::: ''; }; - networking.jool.siit.enable = lib.mkEnableOption (lib.mdDoc "a SIIT instance of Jool."); - networking.jool.siit.config = lib.mkOption { - type = configFormat.type; - default = defaultSiit; + networking.jool.siit = lib.mkOption { + type = lib.types.attrsOf siitOptions; + default = { }; example = lib.literalExpression '' { - # Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v. - pool6 = "2001:db8::/96"; - - # Explicit address mappings - eamt = [ - # 2001:db8:1:: ←→ 192.0.2.0 - { "ipv6 prefix": "2001:db8:1::/128", "ipv4 prefix": "192.0.2.0" } - # 2001:db8:1::x ←→ 198.51.100.x - { "ipv6 prefix": "2001:db8:2::/120", "ipv4 prefix": "198.51.100.0/24" } - ] + default = { + # Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v. + global.pool6 = "2001:db8::/96"; + + # Explicit address mappings + eamt = [ + # 2001:db8:1:: ←→ 192.0.2.0 + { "ipv6 prefix" = "2001:db8:1::/128"; "ipv4 prefix" = "192.0.2.0"; } + # 2001:db8:1::x ←→ 198.51.100.x + { "ipv6 prefix" = "2001:db8:2::/120"; "ipv4 prefix" = "198.51.100.0/24"; } + ]; + }; } ''; description = lib.mdDoc '' - The configuration of a SIIT instance of Jool managed through - NixOS. See https://nicmx.github.io/Jool/en/config-atomic.html for the - available options. + Definitions of SIIT instances of Jool. + See the + [documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for + the available options. Also check out the + [tutorial](https://nicmx.github.io/Jool/en/run-vanilla.html) for an + introduction to SIIT and how to troubleshoot the setup. + + The attribute name defines the name of the instance, with the main one + being `default`: this can be accessed from the command line without + specifying the name with `-i`. ::: {.note} - Existing or more instances created manually will not interfere with the - NixOS instance, provided the respective `EAMT` address mappings are not - overlapping. + Instances created imperatively from the command line will not interfere + with the NixOS instances, provided the respective EAMT addresses and + port ranges are not overlapping. ::: ::: {.warning} - Changes to the NixOS instance performed via `jool instance nixos-siit` - are applied correctly but will be lost after restarting - `jool-siit.service`. + Changes to an instance performed via `jool -i <name>` are applied + correctly but will be lost after restarting the respective + `jool-siit-<name>.service`. ::: ''; }; }; - ###### implementation - config = lib.mkIf cfg.enable { - environment.systemPackages = [ jool-cli ]; + # Install kernel module and cli tools boot.extraModulePackages = [ jool ]; + environment.systemPackages = [ jool-cli ]; - systemd.services.jool-nat64 = lib.mkIf cfg.nat64.enable { - description = "Jool, NAT64 setup"; - documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - reloadIfChanged = true; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStartPre = "${pkgs.kmod}/bin/modprobe jool"; - ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf}"; - ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf} instance remove"; - } // hardening; - }; - - systemd.services.jool-siit = lib.mkIf cfg.siit.enable { - description = "Jool, SIIT setup"; - documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - reloadIfChanged = true; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit"; - ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf}"; - ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf} instance remove"; - } // hardening; - }; - - system.checks = lib.singleton (pkgs.runCommand "jool-validated" { - nativeBuildInputs = [ pkgs.buildPackages.jool-cli ]; - preferLocalBuild = true; - } '' - printf 'Validating Jool configuration... ' - ${lib.optionalString cfg.siit.enable "jool_siit file check ${siitConf}"} - ${lib.optionalString cfg.nat64.enable "jool file check ${nat64Conf}"} - printf 'ok\n' - touch "$out" - ''); - - networking.jool.nat64.config = mkDefaultAttrs defaultNat64; - networking.jool.siit.config = mkDefaultAttrs defaultSiit; + # Install services for each instance + systemd.services = lib.mkMerge + (lib.mapAttrsToList makeNat64Unit cfg.nat64 ++ + lib.mapAttrsToList makeSiitUnit cfg.siit); + # Check the configuration of each instance + system.checks = lib.optional (cfg.nat64 != {} || cfg.siit != {}) + (pkgs.runCommand "jool-validated" + { + nativeBuildInputs = with pkgs.buildPackages; [ jool-cli ]; + preferLocalBuild = true; + } + (lib.concatStrings + (lib.mapAttrsToList checkNat64 cfg.nat64 ++ + lib.mapAttrsToList checkSiit cfg.siit))); }; meta.maintainers = with lib.maintainers; [ rnhmjoj ]; diff --git a/nixos/modules/services/networking/nftables.nix b/nixos/modules/services/networking/nftables.nix index 0e4cd6fa1503..47159ade328c 100644 --- a/nixos/modules/services/networking/nftables.nix +++ b/nixos/modules/services/networking/nftables.nix @@ -70,6 +70,26 @@ in ''; }; + networking.nftables.checkRulesetRedirects = mkOption { + type = types.addCheck (types.attrsOf types.path) (attrs: all types.path.check (attrNames attrs)); + default = { + "/etc/hosts" = config.environment.etc.hosts.source; + "/etc/protocols" = config.environment.etc.protocols.source; + "/etc/services" = config.environment.etc.services.source; + }; + defaultText = literalExpression '' + { + "/etc/hosts" = config.environment.etc.hosts.source; + "/etc/protocols" = config.environment.etc.protocols.source; + "/etc/services" = config.environment.etc.services.source; + } + ''; + description = mdDoc '' + Set of paths that should be intercepted and rewritten while checking the ruleset + using `pkgs.buildPackages.libredirect`. + ''; + }; + networking.nftables.preCheckRuleset = mkOption { type = types.lines; default = ""; @@ -282,7 +302,7 @@ in cp $out ruleset.conf sed 's|include "${deletionsScriptVar}"||' -i ruleset.conf ${cfg.preCheckRuleset} - export NIX_REDIRECTS=/etc/protocols=${pkgs.buildPackages.iana-etc}/etc/protocols:/etc/services=${pkgs.buildPackages.iana-etc}/etc/services + export NIX_REDIRECTS=${escapeShellArg (concatStringsSep ":" (mapAttrsToList (n: v: "${n}=${v}") cfg.checkRulesetRedirects))} LD_PRELOAD="${pkgs.buildPackages.libredirect}/lib/libredirect.so ${pkgs.buildPackages.lklWithFirewall.lib}/lib/liblkl-hijack.so" \ ${pkgs.buildPackages.nftables}/bin/nft --check --file ruleset.conf ''; diff --git a/nixos/modules/virtualisation/anbox.nix b/nixos/modules/virtualisation/anbox.nix index c7e9e23c4c92..523d9a9576ef 100644 --- a/nixos/modules/virtualisation/anbox.nix +++ b/nixos/modules/virtualisation/anbox.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.virtualisation.anbox; - kernelPackages = config.boot.kernelPackages; + addrOpts = v: addr: pref: name: { address = mkOption { default = addr; @@ -25,6 +25,28 @@ let }; }; + finalImage = if cfg.imageModifications == "" then cfg.image else ( pkgs.callPackage ( + { runCommandNoCC, squashfsTools }: + + runCommandNoCC "${cfg.image.name}-modified.img" { + nativeBuildInputs = [ + squashfsTools + ]; + } '' + echo "-> Extracting Anbox root image..." + unsquashfs -dest rootfs ${cfg.image} + + echo "-> Modifying Anbox root image..." + ( + cd rootfs + ${cfg.imageModifications} + ) + + echo "-> Packing modified Anbox root image..." + mksquashfs rootfs $out -comp xz -no-xattrs -all-root + '' + ) { }); + in { @@ -42,6 +64,18 @@ in ''; }; + imageModifications = mkOption { + default = ""; + type = types.lines; + description = lib.mdDoc '' + Commands to edit the image filesystem. + + This can be used to e.g. bundle a privileged F-Droid. + + Commands are ran with PWD being at the root of the filesystem. + ''; + }; + extraInit = mkOption { type = types.lines; default = ""; @@ -67,16 +101,19 @@ in config = mkIf cfg.enable { assertions = singleton { - assertion = versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.18"; - message = "Anbox needs user namespace support to work properly"; + assertion = with config.boot.kernelPackages; kernelAtLeast "5.5" && kernelOlder "5.18"; + message = "Anbox needs a kernel with binder and ashmem support"; }; environment.systemPackages = with pkgs; [ anbox ]; - services.udev.extraRules = '' - KERNEL=="ashmem", NAME="%k", MODE="0666" - KERNEL=="binder*", NAME="%k", MODE="0666" - ''; + systemd.mounts = singleton { + requiredBy = [ "anbox-container-manager.service" ]; + description = "Anbox Binder File System"; + what = "binder"; + where = "/dev/binderfs"; + type = "binder"; + }; virtualisation.lxc.enable = true; networking.bridges.anbox0.interfaces = []; @@ -87,6 +124,9 @@ in internalInterfaces = [ "anbox0" ]; }; + # Ensures NetworkManager doesn't touch anbox0 + networking.networkmanager.unmanaged = [ "anbox0" ]; + systemd.services.anbox-container-manager = let anboxloc = "/var/lib/anbox"; in { @@ -121,12 +161,13 @@ in ExecStart = '' ${pkgs.anbox}/bin/anbox container-manager \ --data-path=${anboxloc} \ - --android-image=${cfg.image} \ + --android-image=${finalImage} \ --container-network-address=${cfg.ipv4.container.address} \ --container-network-gateway=${cfg.ipv4.gateway.address} \ --container-network-dns-servers=${cfg.ipv4.dns} \ --use-rootfs-overlay \ - --privileged + --privileged \ + --daemon ''; }; }; diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix index 07c5e550ec58..e30fbebb662c 100644 --- a/nixos/modules/virtualisation/lxd.nix +++ b/nixos/modules/virtualisation/lxd.nix @@ -2,21 +2,20 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.virtualisation.lxd; + preseedFormat = pkgs.formats.yaml {}; in { imports = [ - (mkRemovedOptionModule [ "virtualisation" "lxd" "zfsPackage" ] "Override zfs in an overlay instead to override it globally") + (lib.mkRemovedOptionModule [ "virtualisation" "lxd" "zfsPackage" ] "Override zfs in an overlay instead to override it globally") ]; ###### interface options = { virtualisation.lxd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = lib.mdDoc '' This option enables lxd, a daemon that manages @@ -32,28 +31,28 @@ in { ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = pkgs.lxd; - defaultText = literalExpression "pkgs.lxd"; + defaultText = lib.literalExpression "pkgs.lxd"; description = lib.mdDoc '' The LXD package to use. ''; }; - lxcPackage = mkOption { - type = types.package; + lxcPackage = lib.mkOption { + type = lib.types.package; default = pkgs.lxc; - defaultText = literalExpression "pkgs.lxc"; + defaultText = lib.literalExpression "pkgs.lxc"; description = lib.mdDoc '' The LXC package to use with LXD (required for AppArmor profiles). ''; }; - zfsSupport = mkOption { - type = types.bool; + zfsSupport = lib.mkOption { + type = lib.types.bool; default = config.boot.zfs.enabled; - defaultText = literalExpression "config.boot.zfs.enabled"; + defaultText = lib.literalExpression "config.boot.zfs.enabled"; description = lib.mdDoc '' Enables lxd to use zfs as a storage for containers. @@ -62,8 +61,8 @@ in { ''; }; - recommendedSysctlSettings = mkOption { - type = types.bool; + recommendedSysctlSettings = lib.mkOption { + type = lib.types.bool; default = false; description = lib.mdDoc '' Enables various settings to avoid common pitfalls when @@ -75,8 +74,67 @@ in { ''; }; - startTimeout = mkOption { - type = types.int; + preseed = lib.mkOption { + type = lib.types.nullOr (lib.types.submodule { + freeformType = preseedFormat.type; + }); + + default = null; + + description = lib.mdDoc '' + Configuration for LXD preseed, see + <https://documentation.ubuntu.com/lxd/en/latest/howto/initialize/#initialize-preseed> + for supported values. + + Changes to this will be re-applied to LXD which will overwrite existing entities or create missing ones, + but entities will *not* be removed by preseed. + ''; + + example = lib.literalExpression '' + { + networks = [ + { + name = "lxdbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "default"; + devices = { + eth0 = { + name = "eth0"; + network = "lxdbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "default"; + driver = "dir"; + config = { + source = "/var/lib/lxd/storage-pools/default"; + }; + } + ]; + } + ''; + }; + + startTimeout = lib.mkOption { + type = lib.types.int; default = 600; apply = toString; description = lib.mdDoc '' @@ -91,13 +149,13 @@ in { Enables the (experimental) LXD UI. ''); - package = mkPackageOption pkgs.lxd-unwrapped "ui" { }; + package = lib.mkPackageOption pkgs.lxd-unwrapped "ui" { }; }; }; }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; # Note: the following options are also declared in virtualisation.lxc, but @@ -139,19 +197,19 @@ in { wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" - (mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service") + (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service") ]; requires = [ "network-online.target" "lxd.socket" - (mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service") + (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service") ]; documentation = [ "man:lxd(1)" ]; path = [ pkgs.util-linux ] - ++ optional cfg.zfsSupport config.boot.zfs.package; + ++ lib.optional cfg.zfsSupport config.boot.zfs.package; - environment = mkIf (cfg.ui.enable) { + environment = lib.mkIf (cfg.ui.enable) { "LXD_UI" = cfg.ui.package; }; @@ -173,11 +231,26 @@ in { # By default, `lxd` loads configuration files from hard-coded # `/usr/share/lxc/config` - since this is a no-go for us, we have to # explicitly tell it where the actual configuration files are - Environment = mkIf (config.virtualisation.lxc.lxcfs.enable) + Environment = lib.mkIf (config.virtualisation.lxc.lxcfs.enable) "LXD_LXC_TEMPLATE_CONFIG=${pkgs.lxcfs}/share/lxc/config"; }; }; + systemd.services.lxd-preseed = lib.mkIf (cfg.preseed != null) { + description = "LXD initialization with preseed file"; + wantedBy = ["multi-user.target"]; + requires = ["lxd.service"]; + after = ["lxd.service"]; + + script = '' + ${pkgs.coreutils}/bin/cat ${preseedFormat.generate "lxd-preseed.yaml" cfg.preseed} | ${cfg.package}/bin/lxd init --preseed + ''; + + serviceConfig = { + Type = "oneshot"; + }; + }; + users.groups.lxd = {}; users.users.root = { @@ -185,7 +258,7 @@ in { subGidRanges = [ { startGid = 1000000; count = 65536; } ]; }; - boot.kernel.sysctl = mkIf cfg.recommendedSysctlSettings { + boot.kernel.sysctl = lib.mkIf cfg.recommendedSysctlSettings { "fs.inotify.max_queued_events" = 1048576; "fs.inotify.max_user_instances" = 1048576; "fs.inotify.max_user_watches" = 1048576; @@ -197,6 +270,6 @@ in { }; boot.kernelModules = [ "veth" "xt_comment" "xt_CHECKSUM" "xt_MASQUERADE" "vhost_vsock" ] - ++ optionals (!config.networking.nftables.enable) [ "iptable_mangle" ]; + ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ]; }; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 681f2430c12d..e5affdab8890 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 {}; + anbox = runTest ./anbox.nix; anuko-time-tracker = handleTest ./anuko-time-tracker.nix {}; apcupsd = handleTest ./apcupsd.nix {}; apfs = runTest ./apfs.nix; @@ -210,6 +211,7 @@ in { custom-ca = handleTest ./custom-ca.nix {}; croc = handleTest ./croc.nix {}; darling = handleTest ./darling.nix {}; + dae = handleTest ./dae.nix {}; dconf = handleTest ./dconf.nix {}; deepin = handleTest ./deepin.nix {}; deluge = handleTest ./deluge.nix {}; @@ -395,7 +397,7 @@ in { jibri = handleTest ./jibri.nix {}; jirafeau = handleTest ./jirafeau.nix {}; jitsi-meet = handleTest ./jitsi-meet.nix {}; - jool = handleTest ./jool.nix {}; + jool = import ./jool.nix { inherit pkgs runTest; }; k3s = handleTest ./k3s {}; kafka = handleTest ./kafka.nix {}; kanidm = handleTest ./kanidm.nix {}; @@ -446,7 +448,7 @@ in { loki = handleTest ./loki.nix {}; luks = handleTest ./luks.nix {}; lvm2 = handleTest ./lvm2 {}; - lxd = pkgs.recurseIntoAttrs (handleTest ./lxd {}); + lxd = pkgs.recurseIntoAttrs (handleTest ./lxd { inherit handleTestOn; }); lxd-image-server = handleTest ./lxd-image-server.nix {}; #logstash = handleTest ./logstash.nix {}; lorri = handleTest ./lorri/default.nix {}; diff --git a/nixos/tests/anbox.nix b/nixos/tests/anbox.nix new file mode 100644 index 000000000000..d78f63ec761f --- /dev/null +++ b/nixos/tests/anbox.nix @@ -0,0 +1,40 @@ +{ lib, pkgs, ... }: + +{ + name = "anbox"; + meta.maintainers = with lib.maintainers; [ mvnetbiz ]; + + nodes.machine = { pkgs, config, ... }: { + imports = [ + ./common/user-account.nix + ./common/x11.nix + ]; + + environment.systemPackages = with pkgs; [ android-tools ]; + + test-support.displayManager.auto.user = "alice"; + + virtualisation.anbox.enable = true; + boot.kernelPackages = pkgs.linuxPackages_5_15; + + # The AArch64 anbox image will not start. + # Meanwhile the postmarketOS images work just fine. + virtualisation.anbox.image = pkgs.anbox.postmarketos-image; + virtualisation.memorySize = 2500; + }; + + testScript = { nodes, ... }: let + user = nodes.machine.users.users.alice; + bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus"; + in '' + machine.wait_for_x() + + machine.wait_until_succeeds( + "sudo -iu alice ${bus} anbox wait-ready" + ) + + machine.wait_until_succeeds("adb shell true") + + print(machine.succeed("adb devices")) + ''; +} diff --git a/nixos/tests/dae.nix b/nixos/tests/dae.nix new file mode 100644 index 000000000000..b8c8ebce7457 --- /dev/null +++ b/nixos/tests/dae.nix @@ -0,0 +1,29 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: { + + name = "dae"; + + meta = { + maintainers = with lib.maintainers; [ oluceps ]; + }; + + nodes.machine = { pkgs, ... }: { + environment.systemPackages = [ pkgs.curl ]; + services.nginx = { + enable = true; + statusPage = true; + }; + services.dae = { + enable = true; + }; + }; + + testScript = '' + machine.wait_for_unit("nginx.service") + machine.wait_for_unit("dae.service") + + machine.wait_for_open_port(80) + + machine.succeed("curl --fail --max-time 10 http://localhost") + ''; + +}) diff --git a/nixos/tests/jool.nix b/nixos/tests/jool.nix index 6d5ded9b18e0..93575f07b1c8 100644 --- a/nixos/tests/jool.nix +++ b/nixos/tests/jool.nix @@ -1,9 +1,4 @@ -{ system ? builtins.currentSystem, - config ? {}, - pkgs ? import ../.. { inherit system config; } -}: - -with import ../lib/testing-python.nix { inherit system pkgs; }; +{ pkgs, runTest }: let inherit (pkgs) lib; @@ -23,7 +18,6 @@ let description = "Mock webserver"; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - serviceConfig.Restart = "always"; script = '' while true; do { @@ -40,7 +34,7 @@ let in { - siit = makeTest { + siit = runTest { # This test simulates the setup described in [1] with two IPv6 and # IPv4-only devices on different subnets communicating through a border # relay running Jool in SIIT mode. @@ -49,8 +43,7 @@ in meta.maintainers = with lib.maintainers; [ rnhmjoj ]; # Border relay - nodes.relay = { ... }: { - imports = [ ../modules/profiles/minimal.nix ]; + nodes.relay = { virtualisation.vlans = [ 1 2 ]; # Enable packet routing @@ -65,20 +58,13 @@ in eth2.ipv4.addresses = [ { address = "192.0.2.1"; prefixLength = 24; } ]; }; - networking.jool = { - enable = true; - siit.enable = true; - siit.config.global.pool6 = "fd::/96"; - }; + networking.jool.enable = true; + networking.jool.siit.default.global.pool6 = "fd::/96"; }; # IPv6 only node - nodes.alice = { ... }: { - imports = [ - ../modules/profiles/minimal.nix - ipv6Only - (webserver 6 "Hello, Bob!") - ]; + nodes.alice = { + imports = [ ipv6Only (webserver 6 "Hello, Bob!") ]; virtualisation.vlans = [ 1 ]; networking.interfaces.eth1.ipv6 = { @@ -89,12 +75,8 @@ in }; # IPv4 only node - nodes.bob = { ... }: { - imports = [ - ../modules/profiles/minimal.nix - ipv4Only - (webserver 4 "Hello, Alice!") - ]; + nodes.bob = { + imports = [ ipv4Only (webserver 4 "Hello, Alice!") ]; virtualisation.vlans = [ 2 ]; networking.interfaces.eth1.ipv4 = { @@ -107,17 +89,17 @@ in testScript = '' start_all() - relay.wait_for_unit("jool-siit.service") + relay.wait_for_unit("jool-siit-default.service") alice.wait_for_unit("network-addresses-eth1.service") bob.wait_for_unit("network-addresses-eth1.service") with subtest("Alice and Bob can't ping each other"): - relay.systemctl("stop jool-siit.service") + relay.systemctl("stop jool-siit-default.service") alice.fail("ping -c1 fd::192.0.2.16") bob.fail("ping -c1 198.51.100.8") with subtest("Alice and Bob can ping using the relay"): - relay.systemctl("start jool-siit.service") + relay.systemctl("start jool-siit-default.service") alice.wait_until_succeeds("ping -c1 fd::192.0.2.16") bob.wait_until_succeeds("ping -c1 198.51.100.8") @@ -132,7 +114,7 @@ in ''; }; - nat64 = makeTest { + nat64 = runTest { # This test simulates the setup described in [1] with two IPv6-only nodes # (a client and a homeserver) on the LAN subnet and an IPv4 node on the WAN. # The router runs Jool in stateful NAT64 mode, masquarading the LAN and @@ -142,8 +124,7 @@ in meta.maintainers = with lib.maintainers; [ rnhmjoj ]; # Router - nodes.router = { ... }: { - imports = [ ../modules/profiles/minimal.nix ]; + nodes.router = { virtualisation.vlans = [ 1 2 ]; # Enable packet routing @@ -158,32 +139,29 @@ in eth2.ipv4.addresses = [ { address = "203.0.113.1"; prefixLength = 24; } ]; }; - networking.jool = { - enable = true; - nat64.enable = true; - nat64.config = { - bib = [ - { # forward HTTP 203.0.113.1 (router) → 2001:db8::9 (homeserver) - "protocol" = "TCP"; - "ipv4 address" = "203.0.113.1#80"; - "ipv6 address" = "2001:db8::9#80"; - } - ]; - pool4 = [ - # Ports for dynamic translation - { protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; } - { protocol = "UDP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; } - { protocol = "ICMP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; } - # Ports for static BIB entries - { protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "80"; } - ]; - }; + networking.jool.enable = true; + networking.jool.nat64.default = { + bib = [ + { # forward HTTP 203.0.113.1 (router) → 2001:db8::9 (homeserver) + "protocol" = "TCP"; + "ipv4 address" = "203.0.113.1#80"; + "ipv6 address" = "2001:db8::9#80"; + } + ]; + pool4 = [ + # Ports for dynamic translation + { protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; } + { protocol = "UDP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; } + { protocol = "ICMP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; } + # Ports for static BIB entries + { protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "80"; } + ]; }; }; # LAN client (IPv6 only) - nodes.client = { ... }: { - imports = [ ../modules/profiles/minimal.nix ipv6Only ]; + nodes.client = { + imports = [ ipv6Only ]; virtualisation.vlans = [ 1 ]; networking.interfaces.eth1.ipv6 = { @@ -194,12 +172,8 @@ in }; # LAN server (IPv6 only) - nodes.homeserver = { ... }: { - imports = [ - ../modules/profiles/minimal.nix - ipv6Only - (webserver 6 "Hello from IPv6!") - ]; + nodes.homeserver = { + imports = [ ipv6Only (webserver 6 "Hello from IPv6!") ]; virtualisation.vlans = [ 1 ]; networking.interfaces.eth1.ipv6 = { @@ -210,12 +184,8 @@ in }; # WAN server (IPv4 only) - nodes.server = { ... }: { - imports = [ - ../modules/profiles/minimal.nix - ipv4Only - (webserver 4 "Hello from IPv4!") - ]; + nodes.server = { + imports = [ ipv4Only (webserver 4 "Hello from IPv4!") ]; virtualisation.vlans = [ 2 ]; networking.interfaces.eth1.ipv4.addresses = @@ -229,7 +199,7 @@ in node.wait_for_unit("network-addresses-eth1.service") with subtest("Client can ping the WAN server"): - router.wait_for_unit("jool-nat64.service") + router.wait_for_unit("jool-nat64-default.service") client.succeed("ping -c1 64:ff9b::203.0.113.16") with subtest("Client can connect to the WAN webserver"): diff --git a/nixos/tests/lxd/container.nix b/nixos/tests/lxd/container.nix index a2b61b78f7d6..bdaaebfc0028 100644 --- a/nixos/tests/lxd/container.nix +++ b/nixos/tests/lxd/container.nix @@ -49,6 +49,9 @@ in { # Wait for lxd to settle machine.succeed("lxd waitready") + # no preseed should mean no service + machine.fail("systemctl status lxd-preseed.service") + machine.succeed("lxd init --minimal") machine.succeed( diff --git a/nixos/tests/lxd/default.nix b/nixos/tests/lxd/default.nix index 8ca591211a06..20afdd5e48bb 100644 --- a/nixos/tests/lxd/default.nix +++ b/nixos/tests/lxd/default.nix @@ -2,9 +2,11 @@ system ? builtins.currentSystem, config ? {}, pkgs ? import ../../.. {inherit system config;}, + handleTestOn, }: { container = import ./container.nix {inherit system pkgs;}; nftables = import ./nftables.nix {inherit system pkgs;}; + preseed = import ./preseed.nix {inherit system pkgs;}; ui = import ./ui.nix {inherit system pkgs;}; - virtual-machine = import ./virtual-machine.nix { inherit system pkgs; }; + virtual-machine = handleTestOn ["x86_64-linux"] ./virtual-machine.nix { inherit system pkgs; }; } diff --git a/nixos/tests/lxd/preseed.nix b/nixos/tests/lxd/preseed.nix new file mode 100644 index 000000000000..7d89b9f56daa --- /dev/null +++ b/nixos/tests/lxd/preseed.nix @@ -0,0 +1,71 @@ +import ../make-test-python.nix ({ pkgs, lib, ... } : + +{ + name = "lxd-preseed"; + + meta = { + maintainers = with lib.maintainers; [ adamcstephens ]; + }; + + nodes.machine = { lib, ... }: { + virtualisation = { + diskSize = 4096; + + lxc.lxcfs.enable = true; + lxd.enable = true; + + lxd.preseed = { + networks = [ + { + name = "nixostestbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "nixostest_default"; + devices = { + eth0 = { + name = "eth0"; + network = "nixostestbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "default"; + size = "35GiB"; + type = "disk"; + }; + }; + } + ]; + storage_pools = [ + { + name = "nixostest_pool"; + driver = "dir"; + } + ]; + }; + }; + }; + + testScript = '' + def wait_for_preseed(_) -> bool: + _, output = machine.systemctl("is-active lxd-preseed.service") + return ("inactive" in output) + + machine.wait_for_unit("sockets.target") + machine.wait_for_unit("lxd.service") + with machine.nested("Waiting for preseed to complete"): + retry(wait_for_preseed) + + with subtest("Verify preseed resources created"): + machine.succeed("lxc profile show nixostest_default") + machine.succeed("lxc network info nixostestbr0") + machine.succeed("lxc storage show nixostest_pool") + ''; +}) |