diff options
Diffstat (limited to 'nixos/modules')
21 files changed, 1410 insertions, 877 deletions
diff --git a/nixos/modules/hardware/logitech.nix b/nixos/modules/hardware/logitech.nix index d6f43bdddcc..3ebe6aacf5d 100644 --- a/nixos/modules/hardware/logitech.nix +++ b/nixos/modules/hardware/logitech.nix @@ -5,24 +5,92 @@ with lib; let cfg = config.hardware.logitech; -in { + vendor = "046d"; + + daemon = "g15daemon"; + +in +{ + imports = [ + (mkRenamedOptionModule [ "hardware" "logitech" "enable" ] [ "hardware" "logitech" "wireless" "enable" ]) + (mkRenamedOptionModule [ "hardware" "logitech" "enableGraphical" ] [ "hardware" "logitech" "wireless" "enableGraphical" ]) + ]; + options.hardware.logitech = { - enable = mkEnableOption "Logitech Devices"; - enableGraphical = mkOption { - type = types.bool; - default = false; - description = "Enable graphical support applications."; + lcd = { + enable = mkEnableOption "Logitech LCD Devices"; + + startWhenNeeded = mkOption { + type = types.bool; + default = true; + description = '' + Only run the service when an actual supported device is plugged. + ''; + }; + + devices = mkOption { + type = types.listOf types.str; + default = [ "0a07" "c222" "c225" "c227" "c251" ]; + description = '' + List of USB device ids supported by g15daemon. + </para> + <para> + You most likely do not need to change this. + ''; + }; + }; + + wireless = { + enable = mkEnableOption "Logitech Wireless Devices"; + + enableGraphical = mkOption { + type = types.bool; + default = false; + description = "Enable graphical support applications."; + }; }; }; - config = lib.mkIf cfg.enable { - environment.systemPackages = [ - pkgs.ltunify - ] ++ lib.optional cfg.enableGraphical pkgs.solaar; + config = lib.mkIf (cfg.wireless.enable || cfg.lcd.enable) { + environment.systemPackages = [] + ++ lib.optional cfg.wireless.enable pkgs.ltunify + ++ lib.optional cfg.wireless.enableGraphical pkgs.solaar; + + services.udev = { + # ltunifi and solaar both provide udev rules but the most up-to-date have been split + # out into a dedicated derivation - # ltunifi and solaar both provide udev rules but the most up-to-date have been split - # out into a dedicated derivation - services.udev.packages = with pkgs; [ logitech-udev-rules ]; + packages = [] + ++ lib.optional cfg.wireless.enable pkgs.logitech-udev-rules + ++ lib.optional cfg.lcd.enable pkgs.g15daemon; + + extraRules = '' + # nixos: hardware.logitech.lcd + '' + lib.concatMapStringsSep "\n" ( + dev: + ''ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="${vendor}", ATTRS{idProduct}=="${dev}", TAG+="systemd", ENV{SYSTEMD_WANTS}+="${daemon}.service"'' + ) cfg.lcd.devices; + }; + + systemd.services."${daemon}" = lib.mkIf cfg.lcd.enable { + description = "Logitech LCD Support Daemon"; + documentation = [ "man:g15daemon(1)" ]; + wantedBy = lib.mkIf (! cfg.lcd.startWhenNeeded) "multi-user.target"; + + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.g15daemon}/bin/g15daemon"; + # we patch it to write to /run/g15daemon/g15daemon.pid instead of + # /run/g15daemon.pid so systemd will do the cleanup for us. + PIDFile = "/run/${daemon}/g15daemon.pid"; + PrivateTmp = true; + PrivateNetwork = true; + ProtectHome = "tmpfs"; + ProtectSystem = "full"; # strict doesn't work + RuntimeDirectory = daemon; + Restart = "on-failure"; + }; + }; }; } diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 1cd2252ecf2..405fbfa10db 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -417,6 +417,14 @@ in ''; }; + isoImage.squashfsCompression = mkOption { + default = "xz -Xdict-size 100%"; + description = '' + Compression settings to use for the squashfs nix store. + ''; + example = "zstd -Xcompression-level 6"; + }; + isoImage.edition = mkOption { default = ""; description = '' @@ -614,6 +622,7 @@ in # Create the squashfs image that contains the Nix store. system.build.squashfsStore = pkgs.callPackage ../../../lib/make-squashfs.nix { storeContents = config.isoImage.storeContents; + comp = config.isoImage.squashfsCompression; }; # Individual files to be included on the CD, outside of the Nix diff --git a/nixos/modules/services/backup/zfs-replication.nix b/nixos/modules/services/backup/zfs-replication.nix index 5a64304275d..6d75774c78f 100644 --- a/nixos/modules/services/backup/zfs-replication.nix +++ b/nixos/modules/services/backup/zfs-replication.nix @@ -18,7 +18,7 @@ in { }; host = mkOption { - description = "Remote host where snapshots should be sent."; + description = "Remote host where snapshots should be sent. <literal>lz4</literal> is expected to be installed on this host."; example = "example.com"; type = types.str; }; diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index 579b6a4d9c6..3e16b5907dd 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -21,7 +21,7 @@ let listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}' port = ${toString cfg.port} ${cfg.extraConfig} - ''; + ''; groupAccessAvailable = versionAtLeast postgresql.version "11.0"; @@ -55,9 +55,13 @@ in dataDir = mkOption { type = types.path; + defaultText = "/var/lib/postgresql/\${config.services.postgresql.package.psqlSchema}"; example = "/var/lib/postgresql/11"; description = '' - Data directory for PostgreSQL. + The data directory for PostgreSQL. If left as the default value + this directory will automatically be created before the PostgreSQL server starts, otherwise + the sysadmin is responsible for ensuring the directory exists with appropriate ownership + and permissions. ''; }; @@ -249,10 +253,7 @@ in else if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql_9_5 else throw "postgresql_9_4 was removed, please upgrade your postgresql version."); - services.postgresql.dataDir = - mkDefault (if versionAtLeast config.system.stateVersion "17.09" - then "/var/lib/postgresql/${cfg.package.psqlSchema}" - else "/var/db/postgresql"); + services.postgresql.dataDir = mkDefault "/var/lib/postgresql/${cfg.package.psqlSchema}"; services.postgresql.authentication = mkAfter '' @@ -291,40 +292,28 @@ in preStart = '' - # Create data directory. if ! test -e ${cfg.dataDir}/PG_VERSION; then - mkdir -m 0700 -p ${cfg.dataDir} + # Cleanup the data directory. rm -f ${cfg.dataDir}/*.conf - chown -R postgres:postgres ${cfg.dataDir} - fi - ''; # */ - script = - '' - # Initialise the database. - if ! test -e ${cfg.dataDir}/PG_VERSION; then + # Initialise the database. initdb -U ${cfg.superUser} ${concatStringsSep " " cfg.initdbArgs} + # See postStart! touch "${cfg.dataDir}/.first_startup" fi + ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf" ${optionalString (cfg.recoveryConfig != null) '' ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \ "${cfg.dataDir}/recovery.conf" ''} - ${optionalString (!groupAccessAvailable) '' - # postgresql pre 11.0 doesn't start if state directory mode is group accessible - chmod 0700 "${cfg.dataDir}" - ''} - - exec postgres ''; - serviceConfig = + serviceConfig = mkMerge [ { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; User = "postgres"; Group = "postgres"; - PermissionsStartOnly = true; RuntimeDirectory = "postgresql"; Type = if versionAtLeast cfg.package.version "9.6" then "notify" @@ -338,36 +327,48 @@ in # Give Postgres a decent amount of time to clean up after # receiving systemd's SIGINT. TimeoutSec = 120; - }; - # Wait for PostgreSQL to be ready to accept connections. - postStart = - '' - PSQL="${pkgs.utillinux}/bin/runuser -u ${cfg.superUser} -- psql --port=${toString cfg.port}" - - while ! $PSQL -d postgres -c "" 2> /dev/null; do - if ! kill -0 "$MAINPID"; then exit 1; fi - sleep 0.1 - done - - if test -e "${cfg.dataDir}/.first_startup"; then - ${optionalString (cfg.initialScript != null) '' - $PSQL -f "${cfg.initialScript}" -d postgres - ''} - rm -f "${cfg.dataDir}/.first_startup" - fi - '' + optionalString (cfg.ensureDatabases != []) '' - ${concatMapStrings (database: '' - $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${database}"' - '') cfg.ensureDatabases} - '' + '' - ${concatMapStrings (user: '' - $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc 'CREATE USER "${user.name}"' - ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' - $PSQL -tAc 'GRANT ${permission} ON ${database} TO "${user.name}"' - '') user.ensurePermissions)} - '') cfg.ensureUsers} - ''; + ExecStart = "${postgresql}/bin/postgres"; + + # Wait for PostgreSQL to be ready to accept connections. + ExecStartPost = + let + setupScript = pkgs.writeScript "postgresql-setup" ('' + #!${pkgs.runtimeShell} -e + + PSQL="${pkgs.utillinux}/bin/runuser -u ${cfg.superUser} -- psql --port=${toString cfg.port}" + + while ! $PSQL -d postgres -c "" 2> /dev/null; do + if ! kill -0 "$MAINPID"; then exit 1; fi + sleep 0.1 + done + + if test -e "${cfg.dataDir}/.first_startup"; then + ${optionalString (cfg.initialScript != null) '' + $PSQL -f "${cfg.initialScript}" -d postgres + ''} + rm -f "${cfg.dataDir}/.first_startup" + fi + '' + optionalString (cfg.ensureDatabases != []) '' + ${concatMapStrings (database: '' + $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${database}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${database}"' + '') cfg.ensureDatabases} + '' + '' + ${concatMapStrings (user: '' + $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc 'CREATE USER "${user.name}"' + ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' + $PSQL -tAc 'GRANT ${permission} ON ${database} TO "${user.name}"' + '') user.ensurePermissions)} + '') cfg.ensureUsers} + ''); + in + "+${setupScript}"; + } + (mkIf (cfg.dataDir == "/var/lib/postgresql/${cfg.package.psqlSchema}") { + StateDirectory = "postgresql postgresql/${cfg.package.psqlSchema}"; + StateDirectoryMode = if groupAccessAvailable then "0750" else "0700"; + }) + ]; unitConfig.RequiresMountsFor = "${cfg.dataDir}"; }; diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index be59b53e5ce..fa393de3219 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -618,26 +618,38 @@ in { enable = true; ensureUsers = singleton { name = cfg.databaseUsername; }; }; + # The postgresql module doesn't currently support concepts like # objects owners and extensions; for now we tack on what's needed # here. - systemd.services.postgresql.postStart = mkAfter (optionalString databaseActuallyCreateLocally '' - set -eu - - $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${cfg.databaseName}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${cfg.databaseName}" OWNER "${cfg.databaseUsername}"' - current_owner=$($PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.databaseName}'") - if [[ "$current_owner" != "${cfg.databaseUsername}" ]]; then - $PSQL -tAc 'ALTER DATABASE "${cfg.databaseName}" OWNER TO "${cfg.databaseUsername}"' - if [[ -e "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" ]]; then - echo "Reassigning ownership of database ${cfg.databaseName} to user ${cfg.databaseUsername} failed on last boot. Failing..." - exit 1 - fi - touch "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" - $PSQL "${cfg.databaseName}" -tAc "REASSIGN OWNED BY \"$current_owner\" TO \"${cfg.databaseUsername}\"" - rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" - fi - $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm" - ''); + systemd.services.gitlab-postgresql = let pgsql = config.services.postgresql; in mkIf databaseActuallyCreateLocally { + after = [ "postgresql.service" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pgsql.package ]; + script = '' + set -eu + + PSQL="${pkgs.utillinux}/bin/runuser -u ${pgsql.superUser} -- psql --port=${toString pgsql.port}" + + $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${cfg.databaseName}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${cfg.databaseName}" OWNER "${cfg.databaseUsername}"' + current_owner=$($PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.databaseName}'") + if [[ "$current_owner" != "${cfg.databaseUsername}" ]]; then + $PSQL -tAc 'ALTER DATABASE "${cfg.databaseName}" OWNER TO "${cfg.databaseUsername}"' + if [[ -e "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" ]]; then + echo "Reassigning ownership of database ${cfg.databaseName} to user ${cfg.databaseUsername} failed on last boot. Failing..." + exit 1 + fi + touch "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" + $PSQL "${cfg.databaseName}" -tAc "REASSIGN OWNED BY \"$current_owner\" TO \"${cfg.databaseUsername}\"" + rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" + fi + $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm" + ''; + + serviceConfig = { + Type = "oneshot"; + }; + }; # Use postfix to send out mails. services.postfix.enable = mkDefault true; @@ -767,7 +779,7 @@ in { }; systemd.services.gitlab = { - after = [ "gitlab-workhorse.service" "gitaly.service" "network.target" "postgresql.service" "redis.service" ]; + after = [ "gitlab-workhorse.service" "gitaly.service" "network.target" "gitlab-postgresql.service" "redis.service" ]; requires = [ "gitlab-sidekiq.service" ]; wantedBy = [ "multi-user.target" ]; environment = gitlabEnv; diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index c345ec48a01..a3612be3cc2 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -18,7 +18,7 @@ let ${optionalString nm.enable '' { ${pkgs.coreutils}/bin/cat << EOF - From: smartd on ${host} <root> + From: smartd on ${host} <${nm.sender}> To: undisclosed-recipients:; Subject: SMART error on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE @@ -129,6 +129,16 @@ in description = "Whenever to send e-mail notifications."; }; + sender = mkOption { + default = "root"; + example = "example@domain.tld"; + type = types.str; + description = '' + Sender of the notification messages. + Acts as the value of <literal>email</literal> in the emails' <literal>From: ... </literal> field. + ''; + }; + recipient = mkOption { default = "root"; type = types.str; diff --git a/nixos/modules/services/monitoring/zabbix-agent.nix b/nixos/modules/services/monitoring/zabbix-agent.nix index b3383ed628b..73eed7aa66a 100644 --- a/nixos/modules/services/monitoring/zabbix-agent.nix +++ b/nixos/modules/services/monitoring/zabbix-agent.nix @@ -3,8 +3,9 @@ let cfg = config.services.zabbixAgent; - inherit (lib) mkDefault mkEnableOption mkIf mkOption; + inherit (lib) mkDefault mkEnableOption mkIf mkMerge mkOption; inherit (lib) attrValues concatMapStringsSep literalExample optionalString types; + inherit (lib.generators) toKeyValue; user = "zabbix-agent"; group = "zabbix-agent"; @@ -14,19 +15,15 @@ let paths = attrValues cfg.modules; }; - configFile = pkgs.writeText "zabbix_agent.conf" '' - LogType = console - Server = ${cfg.server} - ListenIP = ${cfg.listen.ip} - ListenPort = ${toString cfg.listen.port} - ${optionalString (cfg.modules != {}) "LoadModulePath = ${moduleEnv}/lib"} - ${concatMapStringsSep "\n" (name: "LoadModule = ${name}") (builtins.attrNames cfg.modules)} - ${cfg.extraConfig} - ''; + configFile = pkgs.writeText "zabbix_agent.conf" (toKeyValue { listsAsDuplicateKeys = true; } cfg.settings); in { + imports = [ + (lib.mkRemovedOptionModule [ "services" "zabbixAgent" "extraConfig" ] "Use services.zabbixAgent.settings instead.") + ]; + # interface options = { @@ -105,15 +102,18 @@ in ''; }; - # TODO: for bonus points migrate this to https://github.com/NixOS/rfcs/pull/42 - extraConfig = mkOption { - default = ""; - type = types.lines; + settings = mkOption { + type = with types; attrsOf (oneOf [ int str (listOf str) ]); + default = {}; description = '' - Configuration that is injected verbatim into the configuration file. Refer to + Zabbix Agent configuration. Refer to <link xlink:href="https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_agentd"/> for details on supported values. ''; + example = { + Hostname = "example.org"; + DebugLevel = 4; + }; }; }; @@ -124,6 +124,17 @@ in config = mkIf cfg.enable { + services.zabbixAgent.settings = mkMerge [ + { + LogType = "console"; + Server = cfg.server; + ListenIP = cfg.listen.ip; + ListenPort = cfg.listen.port; + LoadModule = builtins.attrNames cfg.modules; + } + (mkIf (cfg.modules != {}) { LoadModulePath = "${moduleEnv}/lib"; }) + ]; + networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.listen.port ]; }; diff --git a/nixos/modules/services/monitoring/zabbix-proxy.nix b/nixos/modules/services/monitoring/zabbix-proxy.nix index 9d214469c3b..d51507c91a1 100644 --- a/nixos/modules/services/monitoring/zabbix-proxy.nix +++ b/nixos/modules/services/monitoring/zabbix-proxy.nix @@ -5,8 +5,9 @@ let pgsql = config.services.postgresql; mysql = config.services.mysql; - inherit (lib) mkDefault mkEnableOption mkIf mkOption; + inherit (lib) mkDefault mkEnableOption mkIf mkMerge mkOption; inherit (lib) attrValues concatMapStringsSep literalExample optional optionalAttrs optionalString types; + inherit (lib.generators) toKeyValue; user = "zabbix"; group = "zabbix"; @@ -19,24 +20,7 @@ let paths = attrValues cfg.modules; }; - configFile = pkgs.writeText "zabbix_proxy.conf" '' - LogType = console - ListenIP = ${cfg.listen.ip} - ListenPort = ${toString cfg.listen.port} - Server = ${cfg.server} - # TODO: set to cfg.database.socket if database type is pgsql? - DBHost = ${optionalString (cfg.database.createLocally != true) cfg.database.host} - ${optionalString (cfg.database.createLocally != true) "DBPort = ${cfg.database.port}"} - DBName = ${cfg.database.name} - DBUser = ${cfg.database.user} - ${optionalString (cfg.database.passwordFile != null) "Include ${passwordFile}"} - ${optionalString (mysqlLocal && cfg.database.socket != null) "DBSocket = ${cfg.database.socket}"} - SocketDir = ${runtimeDir} - FpingLocation = /run/wrappers/bin/fping - ${optionalString (cfg.modules != {}) "LoadModulePath = ${moduleEnv}/lib"} - ${concatMapStringsSep "\n" (name: "LoadModule = ${name}") (builtins.attrNames cfg.modules)} - ${cfg.extraConfig} - ''; + configFile = pkgs.writeText "zabbix_proxy.conf" (toKeyValue { listsAsDuplicateKeys = true; } cfg.settings); mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql"; pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql"; @@ -44,6 +28,10 @@ let in { + imports = [ + (lib.mkRemovedOptionModule [ "services" "zabbixProxy" "extraConfig" ] "Use services.zabbixProxy.settings instead.") + ]; + # interface options = { @@ -182,15 +170,19 @@ in ''; }; - # TODO: for bonus points migrate this to https://github.com/NixOS/rfcs/pull/42 - extraConfig = mkOption { - default = ""; - type = types.lines; + settings = mkOption { + type = with types; attrsOf (oneOf [ int str (listOf str) ]); + default = {}; description = '' - Configuration that is injected verbatim into the configuration file. Refer to + Zabbix Proxy configuration. Refer to <link xlink:href="https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_proxy"/> for details on supported values. ''; + example = { + CacheSize = "1G"; + SSHKeyLocation = "/var/lib/zabbix/.ssh"; + StartPingers = 32; + }; }; }; @@ -213,6 +205,26 @@ in } ]; + services.zabbixProxy.settings = mkMerge [ + { + LogType = "console"; + ListenIP = cfg.listen.ip; + ListenPort = cfg.listen.port; + Server = cfg.server; + # TODO: set to cfg.database.socket if database type is pgsql? + DBHost = optionalString (cfg.database.createLocally != true) cfg.database.host; + DBName = cfg.database.name; + DBUser = cfg.database.user; + SocketDir = runtimeDir; + FpingLocation = "/run/wrappers/bin/fping"; + LoadModule = builtins.attrNames cfg.modules; + } + (mkIf (cfg.database.createLocally != true) { DBPort = cfg.database.port; }) + (mkIf (cfg.database.passwordFile != null) { Include = [ "${passwordFile}" ]; }) + (mkIf (mysqlLocal && cfg.database.socket != null) { DBSocket = cfg.database.socket; }) + (mkIf (cfg.modules != {}) { LoadModulePath = "${moduleEnv}/lib"; }) + ]; + networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.listen.port ]; }; diff --git a/nixos/modules/services/monitoring/zabbix-server.nix b/nixos/modules/services/monitoring/zabbix-server.nix index b4e4378ce1e..df09488a8cc 100644 --- a/nixos/modules/services/monitoring/zabbix-server.nix +++ b/nixos/modules/services/monitoring/zabbix-server.nix @@ -5,8 +5,9 @@ let pgsql = config.services.postgresql; mysql = config.services.mysql; - inherit (lib) mkDefault mkEnableOption mkIf mkOption; + inherit (lib) mkDefault mkEnableOption mkIf mkMerge mkOption; inherit (lib) attrValues concatMapStringsSep literalExample optional optionalAttrs optionalString types; + inherit (lib.generators) toKeyValue; user = "zabbix"; group = "zabbix"; @@ -19,24 +20,7 @@ let paths = attrValues cfg.modules; }; - configFile = pkgs.writeText "zabbix_server.conf" '' - LogType = console - ListenIP = ${cfg.listen.ip} - ListenPort = ${toString cfg.listen.port} - # TODO: set to cfg.database.socket if database type is pgsql? - DBHost = ${optionalString (cfg.database.createLocally != true) cfg.database.host} - ${optionalString (cfg.database.createLocally != true) "DBPort = ${cfg.database.port}"} - DBName = ${cfg.database.name} - DBUser = ${cfg.database.user} - ${optionalString (cfg.database.passwordFile != null) "Include ${passwordFile}"} - ${optionalString (mysqlLocal && cfg.database.socket != null) "DBSocket = ${cfg.database.socket}"} - PidFile = ${runtimeDir}/zabbix_server.pid - SocketDir = ${runtimeDir} - FpingLocation = /run/wrappers/bin/fping - ${optionalString (cfg.modules != {}) "LoadModulePath = ${moduleEnv}/lib"} - ${concatMapStringsSep "\n" (name: "LoadModule = ${name}") (builtins.attrNames cfg.modules)} - ${cfg.extraConfig} - ''; + configFile = pkgs.writeText "zabbix_server.conf" (toKeyValue { listsAsDuplicateKeys = true; } cfg.settings); mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql"; pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql"; @@ -47,6 +31,7 @@ in imports = [ (lib.mkRenamedOptionModule [ "services" "zabbixServer" "dbServer" ] [ "services" "zabbixServer" "database" "host" ]) (lib.mkRemovedOptionModule [ "services" "zabbixServer" "dbPassword" ] "Use services.zabbixServer.database.passwordFile instead.") + (lib.mkRemovedOptionModule [ "services" "zabbixServer" "extraConfig" ] "Use services.zabbixServer.settings instead.") ]; # interface @@ -176,15 +161,19 @@ in ''; }; - # TODO: for bonus points migrate this to https://github.com/NixOS/rfcs/pull/42 - extraConfig = mkOption { - default = ""; - type = types.lines; + settings = mkOption { + type = with types; attrsOf (oneOf [ int str (listOf str) ]); + default = {}; description = '' - Configuration that is injected verbatim into the configuration file. Refer to + Zabbix Server configuration. Refer to <link xlink:href="https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_server"/> for details on supported values. ''; + example = { + CacheSize = "1G"; + SSHKeyLocation = "/var/lib/zabbix/.ssh"; + StartPingers = 32; + }; }; }; @@ -204,6 +193,26 @@ in } ]; + services.zabbixServer.settings = mkMerge [ + { + LogType = "console"; + ListenIP = cfg.listen.ip; + ListenPort = cfg.listen.port; + # TODO: set to cfg.database.socket if database type is pgsql? + DBHost = optionalString (cfg.database.createLocally != true) cfg.database.host; + DBName = cfg.database.name; + DBUser = cfg.database.user; + PidFile = "${runtimeDir}/zabbix_server.pid"; + SocketDir = runtimeDir; + FpingLocation = "/run/wrappers/bin/fping"; + LoadModule = builtins.attrNames cfg.modules; + } + (mkIf (cfg.database.createLocally != true) { DBPort = cfg.database.port; }) + (mkIf (cfg.database.passwordFile != null) { Include = [ "${passwordFile}" ]; }) + (mkIf (mysqlLocal && cfg.database.socket != null) { DBSocket = cfg.database.socket; }) + (mkIf (cfg.modules != {}) { LoadModulePath = "${moduleEnv}/lib"; }) + ]; + networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.listen.port ]; }; diff --git a/nixos/modules/services/networking/blockbook-frontend.nix b/nixos/modules/services/networking/blockbook-frontend.nix index 61938e51e06..f289683cef0 100644 --- a/nixos/modules/services/networking/blockbook-frontend.nix +++ b/nixos/modules/services/networking/blockbook-frontend.nix @@ -269,4 +269,7 @@ in users.groups = mapAttrs' (instanceName: cfg: ( nameValuePair "${cfg.group}" { })) eachBlockbook; }; + + meta.maintainers = with maintainers; [ maintainers."1000101" ]; + } diff --git a/nixos/modules/services/networking/jicofo.nix b/nixos/modules/services/networking/jicofo.nix index 8c492600944..160a5fea91a 100644 --- a/nixos/modules/services/networking/jicofo.nix +++ b/nixos/modules/services/networking/jicofo.nix @@ -148,5 +148,5 @@ in mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal"; }; - meta.maintainers = with lib.maintainers; [ ]; + meta.maintainers = lib.teams.jitsi.members; } diff --git a/nixos/modules/services/networking/jitsi-videobridge.nix b/nixos/modules/services/networking/jitsi-videobridge.nix index b368ee14903..5482e997a40 100644 --- a/nixos/modules/services/networking/jitsi-videobridge.nix +++ b/nixos/modules/services/networking/jitsi-videobridge.nix @@ -272,5 +272,5 @@ in }]; }; - meta.maintainers = with lib.maintainers; [ ]; + meta.maintainers = lib.teams.jitsi.members; } diff --git a/nixos/modules/services/networking/trickster.nix b/nixos/modules/services/networking/trickster.nix index 8760dd5a938..705204ce49f 100644 --- a/nixos/modules/services/networking/trickster.nix +++ b/nixos/modules/services/networking/trickster.nix @@ -106,7 +106,9 @@ in Restart = "always"; }; }; + }; + + meta.maintainers = with maintainers; [ maintainers."1000101" ]; - }; } diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix index fe6b9210d24..7aaa832a602 100644 --- a/nixos/modules/services/web-apps/dokuwiki.nix +++ b/nixos/modules/services/web-apps/dokuwiki.nix @@ -2,7 +2,7 @@ let - inherit (lib) mkEnableOption mkForce mkIf mkMerge mkOption optionalAttrs recursiveUpdate types; + inherit (lib) mkEnableOption mkForce mkIf mkMerge mkOption optionalAttrs recursiveUpdate types maintainers; inherit (lib) concatMapStringsSep flatten mapAttrs mapAttrs' mapAttrsToList nameValuePair concatMapStringSep; eachSite = config.services.dokuwiki; @@ -95,7 +95,7 @@ let aclFile = mkOption { type = with types; nullOr str; - default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/users.auth.php" else null; + default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null; description = '' Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl Mutually exclusive with services.dokuwiki.acl which is preferred. @@ -249,22 +249,19 @@ let nginx = mkOption { type = types.submodule ( recursiveUpdate - (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) - { - # Enable encryption by default, - options.forceSSL.default = true; - options.enableACME.default = true; - } + (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {} ); - default = {forceSSL = true; enableACME = true;}; + default = {}; example = { serverAliases = [ "wiki.\${config.networking.domain}" ]; - enableACME = false; + # To enable encryption and let let's encrypt take care of certificate + forceSSL = true; + enableACME = true; }; description = '' - With this option, you can customize the nginx virtualHost which already has sensible defaults for DokuWiki. + With this option, you can customize the nginx virtualHost settings. ''; }; }; @@ -276,7 +273,7 @@ in services.dokuwiki = mkOption { type = types.attrsOf (types.submodule siteOpts); default = {}; - description = "Sepcification of one or more dokuwiki sites to service."; + description = "Sepcification of one or more dokuwiki sites to serve."; }; }; @@ -385,4 +382,7 @@ in isSystemUser = true; }; }; + + meta.maintainers = with maintainers; [ maintainers."1000101" ]; + } diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix index 8b601910ba7..3b2b2440491 100644 --- a/nixos/modules/services/web-apps/jitsi-meet.nix +++ b/nixos/modules/services/web-apps/jitsi-meet.nix @@ -329,5 +329,5 @@ in }; }; - meta.maintainers = with lib.maintainers; [ ]; + meta.maintainers = lib.teams.jitsi.members; } diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index 328561dc800..0579e58d1d6 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -45,6 +45,12 @@ let inherit (config.system) stateVersion; in { + + imports = [ + ( mkRemovedOptionModule [ "services" "nextcloud" "nginx" "enable" ] + "The nextcloud module dropped support for other webservers than nginx.") + ]; + options.services.nextcloud = { enable = mkEnableOption "nextcloud"; hostName = mkOption { @@ -91,16 +97,6 @@ in { ''; }; - nginx.enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable nginx virtual host management. - Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>. - See <xref linkend="opt-services.nginx.virtualHosts"/> for further information. - ''; - }; - webfinger = mkOption { type = types.bool; default = false; @@ -468,10 +464,18 @@ in { script = '' chmod og+x ${cfg.home} ln -sf ${cfg.package}/apps ${cfg.home}/ - mkdir -p ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps - ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php - chown -R nextcloud:nginx ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps + # create nextcloud directories. + # if the directories exist already with wrong permissions, we fix that + for dir in ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps; do + if [ ! -e $dir ]; then + install -o nextcloud -g nextcloud -d $dir + elif [ $(stat -c "%G" $dir) != "nextcloud" ]; then + chgrp -R nextcloud $dir + fi + done + + ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php # Do not install if already installed if [[ ! -e ${cfg.home}/config/config.php ]]; then @@ -484,6 +488,7 @@ in { ${occSetTrustedDomainsCmd} ''; serviceConfig.Type = "oneshot"; + serviceConfig.User = "nextcloud"; }; nextcloud-cron = { environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config"; @@ -502,7 +507,7 @@ in { services.phpfpm = { pools.nextcloud = { user = "nextcloud"; - group = "nginx"; + group = "nextcloud"; phpOptions = phpOptionsStr; phpPackage = phpPackage; phpEnv = { @@ -510,99 +515,82 @@ in { PATH = "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin"; }; settings = mapAttrs (name: mkDefault) { - "listen.owner" = "nginx"; - "listen.group" = "nginx"; + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; } // cfg.poolSettings; extraConfig = cfg.poolConfig; }; }; - users.extraUsers.nextcloud = { + users.users.nextcloud = { home = "${cfg.home}"; - group = "nginx"; + group = "nextcloud"; createHome = true; }; + users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ]; environment.systemPackages = [ occ ]; - } - (mkIf cfg.nginx.enable { - services.nginx = { + services.nginx = mkDefault { enable = true; - virtualHosts = { - ${cfg.hostName} = { - root = cfg.package; - locations = { - "= /robots.txt" = { - priority = 100; - extraConfig = '' - allow all; - log_not_found off; - access_log off; - ''; - }; - "/" = { - priority = 200; - extraConfig = "rewrite ^ /index.php;"; - }; - "~ ^/store-apps" = { - priority = 201; - extraConfig = "root ${cfg.home};"; - }; - "= /.well-known/carddav" = { - priority = 210; - extraConfig = "return 301 $scheme://$host/remote.php/dav;"; - }; - "= /.well-known/caldav" = { - priority = 210; - extraConfig = "return 301 $scheme://$host/remote.php/dav;"; - }; - "~ ^\\/(?:build|tests|config|lib|3rdparty|templates|data)\\/" = { - priority = 300; - extraConfig = "deny all;"; - }; - "~ ^\\/(?:\\.|autotest|occ|issue|indie|db_|console)" = { - priority = 300; - extraConfig = "deny all;"; - }; - "~ ^\\/(?:index|remote|public|cron|core/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|ocs-provider\\/.+|ocm-provider\\/.+)\\.php(?:$|\\/)" = { - priority = 500; - extraConfig = '' - include ${config.services.nginx.package}/conf/fastcgi.conf; - fastcgi_split_path_info ^(.+\.php)(\\/.*)$; - try_files $fastcgi_script_name =404; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; - fastcgi_param modHeadersAvailable true; - fastcgi_param front_controller_active true; - fastcgi_pass unix:${fpm.socket}; - fastcgi_intercept_errors on; - fastcgi_request_buffering off; - fastcgi_read_timeout 120s; - ''; - }; - "~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = '' - try_files $uri/ =404; - index index.php; - ''; - "~ \\.(?:css|js|woff2?|svg|gif)$".extraConfig = '' - try_files $uri /index.php$request_uri; - add_header Cache-Control "public, max-age=15778463"; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Download-Options noopen; - add_header X-Permitted-Cross-Domain-Policies none; - add_header X-Frame-Options sameorigin; - add_header Referrer-Policy no-referrer; + virtualHosts.${cfg.hostName} = { + root = cfg.package; + locations = { + "= /robots.txt" = { + priority = 100; + extraConfig = '' + allow all; + log_not_found off; access_log off; ''; - "~ \\.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$".extraConfig = '' - try_files $uri /index.php$request_uri; - access_log off; + }; + "/" = { + priority = 200; + extraConfig = "rewrite ^ /index.php;"; + }; + "~ ^/store-apps" = { + priority = 201; + extraConfig = "root ${cfg.home};"; + }; + "= /.well-known/carddav" = { + priority = 210; + extraConfig = "return 301 $scheme://$host/remote.php/dav;"; + }; + "= /.well-known/caldav" = { + priority = 210; + extraConfig = "return 301 $scheme://$host/remote.php/dav;"; + }; + "~ ^\\/(?:build|tests|config|lib|3rdparty|templates|data)\\/" = { + priority = 300; + extraConfig = "deny all;"; + }; + "~ ^\\/(?:\\.|autotest|occ|issue|indie|db_|console)" = { + priority = 300; + extraConfig = "deny all;"; + }; + "~ ^\\/(?:index|remote|public|cron|core/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|ocs-provider\\/.+|ocm-provider\\/.+)\\.php(?:$|\\/)" = { + priority = 500; + extraConfig = '' + include ${config.services.nginx.package}/conf/fastcgi.conf; + fastcgi_split_path_info ^(.+\.php)(\\/.*)$; + try_files $fastcgi_script_name =404; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; + fastcgi_param modHeadersAvailable true; + fastcgi_param front_controller_active true; + fastcgi_pass unix:${fpm.socket}; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + fastcgi_read_timeout 120s; ''; }; - extraConfig = '' + "~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = '' + try_files $uri/ =404; + index index.php; + ''; + "~ \\.(?:css|js|woff2?|svg|gif)$".extraConfig = '' + try_files $uri /index.php$request_uri; + add_header Cache-Control "public, max-age=15778463"; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header X-Robots-Tag none; @@ -610,28 +598,42 @@ in { add_header X-Permitted-Cross-Domain-Policies none; add_header X-Frame-Options sameorigin; add_header Referrer-Policy no-referrer; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - error_page 403 /core/templates/403.php; - error_page 404 /core/templates/404.php; - client_max_body_size ${cfg.maxUploadSize}; - fastcgi_buffers 64 4K; - fastcgi_hide_header X-Powered-By; - gzip on; - gzip_vary on; - gzip_comp_level 4; - gzip_min_length 256; - gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; - gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; - - ${optionalString cfg.webfinger '' - rewrite ^/.well-known/host-meta /public.php?service=host-meta last; - rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last; - ''} + access_log off; + ''; + "~ \\.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$".extraConfig = '' + try_files $uri /index.php$request_uri; + access_log off; ''; }; + extraConfig = '' + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + add_header X-Frame-Options sameorigin; + add_header Referrer-Policy no-referrer; + add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; + error_page 403 /core/templates/403.php; + error_page 404 /core/templates/404.php; + client_max_body_size ${cfg.maxUploadSize}; + fastcgi_buffers 64 4K; + fastcgi_hide_header X-Powered-By; + gzip on; + gzip_vary on; + gzip_comp_level 4; + gzip_min_length 256; + gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; + gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; + + ${optionalString cfg.webfinger '' + rewrite ^/.well-known/host-meta /public.php?service=host-meta last; + rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last; + ''} + ''; }; }; - }) + } ]); meta.doc = ./nextcloud.xml; diff --git a/nixos/modules/services/web-apps/nextcloud.xml b/nixos/modules/services/web-apps/nextcloud.xml index 332e4d1ff3e..f8b92244c89 100644 --- a/nixos/modules/services/web-apps/nextcloud.xml +++ b/nixos/modules/services/web-apps/nextcloud.xml @@ -29,7 +29,6 @@ services.nextcloud = { <link linkend="opt-services.nextcloud.enable">enable</link> = true; <link linkend="opt-services.nextcloud.hostName">hostName</link> = "nextcloud.tld"; - <link linkend="opt-services.nextcloud.nginx.enable">nginx.enable</link> = true; config = { <link linkend="opt-services.nextcloud.config.dbtype">dbtype</link> = "pgsql"; <link linkend="opt-services.nextcloud.config.dbuser">dbuser</link> = "nextcloud"; @@ -61,9 +60,8 @@ </para> <para> - The options <literal>hostName</literal> and <literal>nginx.enable</literal> - are used internally to configure an HTTP server using - <literal><link xlink:href="https://php-fpm.org/">PHP-FPM</link></literal> + The <literal>hostName</literal> option is used internally to configure an HTTP + server using <literal><link xlink:href="https://php-fpm.org/">PHP-FPM</link></literal> and <literal>nginx</literal>. The <literal>config</literal> attribute set is used by the imperative installer and all values are written to an additional file to ensure that changes can be applied by changing the module's options. diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 721080949e0..47689b2a470 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -8,359 +8,714 @@ let cfg = config.systemd.network; - checkLink = checkUnitConfig "Link" [ - (assertOnlyFields [ - "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name" "OriginalName" - "MTUBytes" "BitsPerSecond" "Duplex" "AutoNegotiation" "WakeOnLan" "Port" "Advertise" - "TCPSegmentationOffload" "TCP6SegmentationOffload" "GenericSegmentationOffload" - "GenericReceiveOffload" "LargeReceiveOffload" "RxChannels" "TxChannels" - "OtherChannels" "CombinedChannels" - ]) - (assertValueOneOf "MACAddressPolicy" ["persistent" "random" "none"]) - (assertMacAddress "MACAddress") - (assertByteFormat "MTUBytes") - (assertByteFormat "BitsPerSecond") - (assertValueOneOf "Duplex" ["half" "full"]) - (assertValueOneOf "AutoNegotiation" boolValues) - (assertValueOneOf "WakeOnLan" ["phy" "unicast" "multicast" "broadcast" "arp" "magic" "secureon" "off"]) - (assertValueOneOf "Port" ["tp" "aui" "bnc" "mii" "fibre"]) - (assertValueOneOf "TCPSegmentationOffload" boolValues) - (assertValueOneOf "TCP6SegmentationOffload" boolValues) - (assertValueOneOf "GenericSegmentationOffload" boolValues) - (assertValueOneOf "UDPSegmentationOffload" boolValues) - (assertValueOneOf "GenericReceiveOffload" boolValues) - (assertValueOneOf "LargeReceiveOffload" boolValues) - (assertInt "RxChannels") - (assertMinimum "RxChannels" 1) - (assertInt "TxChannels") - (assertMinimum "TxChannels" 1) - (assertInt "OtherChannels") - (assertMinimum "OtherChannels" 1) - (assertInt "CombinedChannels") - (assertMinimum "CombinedChannels" 1) - ]; - - checkNetdev = checkUnitConfig "Netdev" [ - (assertOnlyFields [ - "Description" "Name" "Kind" "MTUBytes" "MACAddress" - ]) - (assertHasField "Name") - (assertHasField "Kind") - (assertValueOneOf "Kind" [ - "bond" "bridge" "dummy" "gre" "gretap" "ip6gre" "ip6tnl" "ip6gretap" "ipip" - "ipvlan" "macvlan" "macvtap" "sit" "tap" "tun" "veth" "vlan" "vti" "vti6" - "vxlan" "geneve" "vrf" "vcan" "vxcan" "wireguard" "netdevsim" "xfrm" - ]) - (assertByteFormat "MTUBytes") - (assertMacAddress "MACAddress") - ]; - - checkVRF = checkUnitConfig "VRF" [ - (assertOnlyFields [ "Table" ]) - (assertMinimum "Table" 0) - ]; + check = { + + link = { + + sectionLink = checkUnitConfig "Link" [ + (assertOnlyFields [ + "Description" + "Alias" + "MACAddressPolicy" + "MACAddress" + "NamePolicy" + "Name" + "AlternativeNamesPolicy" + "AlternativeName" + "MTUBytes" + "BitsPerSecond" + "Duplex" + "AutoNegotiation" + "WakeOnLan" + "Port" + "Advertise" + "ReceiveChecksumOffload" + "TransmitChecksumOffload" + "TCPSegmentationOffload" + "TCP6SegmentationOffload" + "GenericSegmentationOffload" + "GenericReceiveOffload" + "LargeReceiveOffload" + "RxChannels" + "TxChannels" + "OtherChannels" + "CombinedChannels" + "RxBufferSize" + "TxBufferSize" + ]) + (assertValueOneOf "MACAddressPolicy" ["persistent" "random" "none"]) + (assertMacAddress "MACAddress") + (assertByteFormat "MTUBytes") + (assertByteFormat "BitsPerSecond") + (assertValueOneOf "Duplex" ["half" "full"]) + (assertValueOneOf "AutoNegotiation" boolValues) + (assertValueOneOf "WakeOnLan" ["phy" "unicast" "multicast" "broadcast" "arp" "magic" "secureon" "off"]) + (assertValueOneOf "Port" ["tp" "aui" "bnc" "mii" "fibre"]) + (assertValueOneOf "ReceiveChecksumOffload" boolValues) + (assertValueOneOf "TransmitChecksumOffload" boolValues) + (assertValueOneOf "TCPSegmentationOffload" boolValues) + (assertValueOneOf "TCP6SegmentationOffload" boolValues) + (assertValueOneOf "GenericSegmentationOffload" boolValues) + (assertValueOneOf "GenericReceiveOffload" boolValues) + (assertValueOneOf "LargeReceiveOffload" boolValues) + (assertInt "RxChannels") + (assertRange "RxChannels" 1 4294967295) + (assertInt "TxChannels") + (assertRange "TxChannels" 1 4294967295) + (assertInt "OtherChannels") + (assertRange "OtherChannels" 1 4294967295) + (assertInt "CombinedChannels") + (assertRange "CombinedChannels" 1 4294967295) + (assertInt "RxBufferSize") + (assertInt "TxBufferSize") + ]; + }; - # NOTE The PrivateKey directive is missing on purpose here, please - # do not add it to this list. The nix store is world-readable let's - # refrain ourselves from providing a footgun. - checkWireGuard = checkUnitConfig "WireGuard" [ - (assertOnlyFields [ - "PrivateKeyFile" "ListenPort" "FwMark" - ]) - # The following check won't work on nix <= 2.2 - # see https://github.com/NixOS/nix/pull/2378 - # - # Add this again when we'll have drop the - # nix < 2.2 support. - # (assertRange "FwMark" 1 4294967295) - ]; + netdev = let + + tunChecks = [ + (assertOnlyFields [ + "MultiQueue" + "PacketInfo" + "VNetHeader" + "User" + "Group" + ]) + (assertValueOneOf "MultiQueue" boolValues) + (assertValueOneOf "PacketInfo" boolValues) + (assertValueOneOf "VNetHeader" boolValues) + ]; + in { + + sectionNetdev = checkUnitConfig "Netdev" [ + (assertOnlyFields [ + "Description" + "Name" + "Kind" + "MTUBytes" + "MACAddress" + ]) + (assertHasField "Name") + (assertHasField "Kind") + (assertValueOneOf "Kind" [ + "bond" + "bridge" + "dummy" + "gre" + "gretap" + "erspan" + "ip6gre" + "ip6tnl" + "ip6gretap" + "ipip" + "ipvlan" + "macvlan" + "macvtap" + "sit" + "tap" + "tun" + "veth" + "vlan" + "vti" + "vti6" + "vxlan" + "geneve" + "l2tp" + "macsec" + "vrf" + "vcan" + "vxcan" + "wireguard" + "netdevsim" + "nlmon" + "fou" + "xfrm" + "ifb" + ]) + (assertByteFormat "MTUBytes") + (assertMacAddress "MACAddress") + ]; - # NOTE The PresharedKey directive is missing on purpose here, please - # do not add it to this list. The nix store is world-readable,let's - # refrain ourselves from providing a footgun. - checkWireGuardPeer = checkUnitConfig "WireGuardPeer" [ - (assertOnlyFields [ - "PublicKey" "PresharedKeyFile" "AllowedIPs" - "Endpoint" "PersistentKeepalive" - ]) - (assertRange "PersistentKeepalive" 1 65535) - ]; + sectionVLAN = checkUnitConfig "VLAN" [ + (assertOnlyFields [ + "Id" + "GVRP" + "MVRP" + "LooseBinding" + "ReorderHeader" + ]) + (assertInt "Id") + (assertRange "Id" 0 4094) + (assertValueOneOf "GVRP" boolValues) + (assertValueOneOf "MVRP" boolValues) + (assertValueOneOf "LooseBinding" boolValues) + (assertValueOneOf "ReorderHeader" boolValues) + ]; - checkVlan = checkUnitConfig "VLAN" [ - (assertOnlyFields ["Id" "GVRP" "MVRP" "LooseBinding" "ReorderHeader"]) - (assertRange "Id" 0 4094) - (assertValueOneOf "GVRP" boolValues) - (assertValueOneOf "MVRP" boolValues) - (assertValueOneOf "LooseBinding" boolValues) - (assertValueOneOf "ReorderHeader" boolValues) - ]; + sectionMACVLAN = checkUnitConfig "MACVLAN" [ + (assertOnlyFields [ + "Mode" + ]) + (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"]) + ]; - checkMacvlan = checkUnitConfig "MACVLAN" [ - (assertOnlyFields ["Mode"]) - (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"]) - ]; + sectionVXLAN = checkUnitConfig "VXLAN" [ + (assertOnlyFields [ + "VNI" + "Remote" + "Local" + "Group" + "TOS" + "TTL" + "MacLearning" + "FDBAgeingSec" + "MaximumFDBEntries" + "ReduceARPProxy" + "L2MissNotification" + "L3MissNotification" + "RouteShortCircuit" + "UDPChecksum" + "UDP6ZeroChecksumTx" + "UDP6ZeroChecksumRx" + "RemoteChecksumTx" + "RemoteChecksumRx" + "GroupPolicyExtension" + "GenericProtocolExtension" + "DestinationPort" + "PortRange" + "FlowLabel" + "IPDoNotFragment" + ]) + (assertInt "VNI") + (assertRange "VNI" 1 16777215) + (assertValueOneOf "MacLearning" boolValues) + (assertInt "MaximumFDBEntries") + (assertValueOneOf "ReduceARPProxy" boolValues) + (assertValueOneOf "L2MissNotification" boolValues) + (assertValueOneOf "L3MissNotification" boolValues) + (assertValueOneOf "RouteShortCircuit" boolValues) + (assertValueOneOf "UDPChecksum" boolValues) + (assertValueOneOf "UDP6ZeroChecksumTx" boolValues) + (assertValueOneOf "UDP6ZeroChecksumRx" boolValues) + (assertValueOneOf "RemoteChecksumTx" boolValues) + (assertValueOneOf "RemoteChecksumRx" boolValues) + (assertValueOneOf "GroupPolicyExtension" boolValues) + (assertValueOneOf "GenericProtocolExtension" boolValues) + (assertInt "FlowLabel") + (assertRange "FlowLabel" 0 1048575) + (assertValueOneOf "IPDoNotFragment" (boolValues + ["inherit"])) + ]; - checkVxlan = checkUnitConfig "VXLAN" [ - (assertOnlyFields [ - "Id" "Remote" "Local" "TOS" "TTL" "MacLearning" "FDBAgeingSec" - "MaximumFDBEntries" "ReduceARPProxy" "L2MissNotification" - "L3MissNotification" "RouteShortCircuit" "UDPChecksum" - "UDP6ZeroChecksumTx" "UDP6ZeroChecksumRx" "RemoteChecksumTx" - "RemoteChecksumRx" "GroupPolicyExtension" "DestinationPort" "PortRange" - "FlowLabel" - ]) - (assertRange "TTL" 0 255) - (assertValueOneOf "MacLearning" boolValues) - (assertValueOneOf "ReduceARPProxy" boolValues) - (assertValueOneOf "L2MissNotification" boolValues) - (assertValueOneOf "L3MissNotification" boolValues) - (assertValueOneOf "RouteShortCircuit" boolValues) - (assertValueOneOf "UDPChecksum" boolValues) - (assertValueOneOf "UDP6ZeroChecksumTx" boolValues) - (assertValueOneOf "UDP6ZeroChecksumRx" boolValues) - (assertValueOneOf "RemoteChecksumTx" boolValues) - (assertValueOneOf "RemoteChecksumRx" boolValues) - (assertValueOneOf "GroupPolicyExtension" boolValues) - (assertRange "FlowLabel" 0 1048575) - ]; + sectionTunnel = checkUnitConfig "Tunnel" [ + (assertOnlyFields [ + "Local" + "Remote" + "TOS" + "TTL" + "DiscoverPathMTU" + "IPv6FlowLabel" + "CopyDSCP" + "EncapsulationLimit" + "Key" + "InputKey" + "OutputKey" + "Mode" + "Independent" + "AssignToLoopback" + "AllowLocalRemote" + "FooOverUDP" + "FOUDestinationPort" + "FOUSourcePort" + "Encapsulation" + "IPv6RapidDeploymentPrefix" + "ISATAP" + "SerializeTunneledPackets" + "ERSPANIndex" + ]) + (assertInt "TTL") + (assertRange "TTL" 0 255) + (assertValueOneOf "DiscoverPathMTU" boolValues) + (assertValueOneOf "CopyDSCP" boolValues) + (assertValueOneOf "Mode" ["ip6ip6" "ipip6" "any"]) + (assertValueOneOf "Independent" boolValues) + (assertValueOneOf "AssignToLoopback" boolValues) + (assertValueOneOf "AllowLocalRemote" boolValues) + (assertValueOneOf "FooOverUDP" boolValues) + (assertPort "FOUDestinationPort") + (assertPort "FOUSourcePort") + (assertValueOneOf "Encapsulation" ["FooOverUDP" "GenericUDPEncapsulation"]) + (assertValueOneOf "ISATAP" boolValues) + (assertValueOneOf "SerializeTunneledPackets" boolValues) + (assertInt "ERSPANIndex") + (assertRange "ERSPANIndex" 1 1048575) + ]; - checkTunnel = checkUnitConfig "Tunnel" [ - (assertOnlyFields [ - "Local" "Remote" "TOS" "TTL" "DiscoverPathMTU" "IPv6FlowLabel" "CopyDSCP" - "EncapsulationLimit" "Key" "InputKey" "OutputKey" "Mode" "Independent" - "AllowLocalRemote" - ]) - (assertRange "TTL" 0 255) - (assertValueOneOf "DiscoverPathMTU" boolValues) - (assertValueOneOf "CopyDSCP" boolValues) - (assertValueOneOf "Mode" ["ip6ip6" "ipip6" "any"]) - (assertValueOneOf "Independent" boolValues) - (assertValueOneOf "AllowLocalRemote" boolValues) - ]; + sectionPeer = checkUnitConfig "Peer" [ + (assertOnlyFields [ + "Name" + "MACAddress" + ]) + (assertMacAddress "MACAddress") + ]; - checkPeer = checkUnitConfig "Peer" [ - (assertOnlyFields ["Name" "MACAddress"]) - (assertMacAddress "MACAddress") - ]; + sectionTun = checkUnitConfig "Tun" tunChecks; + + sectionTap = checkUnitConfig "Tap" tunChecks; + + # NOTE The PrivateKey directive is missing on purpose here, please + # do not add it to this list. The nix store is world-readable let's + # refrain ourselves from providing a footgun. + sectionWireGuard = checkUnitConfig "WireGuard" [ + (assertOnlyFields [ + "PrivateKeyFile" + "ListenPort" + "FirewallMark" + ]) + (assertInt "FirewallMark") + (assertRange "FirewallMark" 1 4294967295) + ]; - tunTapChecks = [ - (assertOnlyFields ["OneQueue" "MultiQueue" "PacketInfo" "VNetHeader" "User" "Group"]) - (assertValueOneOf "OneQueue" boolValues) - (assertValueOneOf "MultiQueue" boolValues) - (assertValueOneOf "PacketInfo" boolValues) - (assertValueOneOf "VNetHeader" boolValues) - ]; + # NOTE The PresharedKey directive is missing on purpose here, please + # do not add it to this list. The nix store is world-readable,let's + # refrain ourselves from providing a footgun. + sectionWireGuardPeer = checkUnitConfig "WireGuardPeer" [ + (assertOnlyFields [ + "PublicKey" + "PresharedKeyFile" + "AllowedIPs" + "Endpoint" + "PersistentKeepalive" + ]) + (assertInt "PersistentKeepalive") + (assertRange "PersistentKeepalive" 0 65535) + ]; - checkTun = checkUnitConfig "Tun" tunTapChecks; - - checkTap = checkUnitConfig "Tap" tunTapChecks; - - checkBond = checkUnitConfig "Bond" [ - (assertOnlyFields [ - "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec" - "UpDelaySec" "DownDelaySec" "LearnPacketIntervalSec" "AdSelect" - "FailOverMACPolicy" "ARPValidate" "ARPIntervalSec" "ARPIPTargets" - "ARPAllTargets" "PrimaryReselectPolicy" "ResendIGMP" "PacketsPerSlave" - "GratuitousARP" "AllSlavesActive" "MinLinks" - ]) - (assertValueOneOf "Mode" [ - "balance-rr" "active-backup" "balance-xor" - "broadcast" "802.3ad" "balance-tlb" "balance-alb" - ]) - (assertValueOneOf "TransmitHashPolicy" [ - "layer2" "layer3+4" "layer2+3" "encap2+3" "encap3+4" - ]) - (assertValueOneOf "LACPTransmitRate" ["slow" "fast"]) - (assertValueOneOf "AdSelect" ["stable" "bandwidth" "count"]) - (assertValueOneOf "FailOverMACPolicy" ["none" "active" "follow"]) - (assertValueOneOf "ARPValidate" ["none" "active" "backup" "all"]) - (assertValueOneOf "ARPAllTargets" ["any" "all"]) - (assertValueOneOf "PrimaryReselectPolicy" ["always" "better" "failure"]) - (assertRange "ResendIGMP" 0 255) - (assertRange "PacketsPerSlave" 0 65535) - (assertRange "GratuitousARP" 0 255) - (assertValueOneOf "AllSlavesActive" boolValues) - ]; + sectionBond = checkUnitConfig "Bond" [ + (assertOnlyFields [ + "Mode" + "TransmitHashPolicy" + "LACPTransmitRate" + "MIIMonitorSec" + "UpDelaySec" + "DownDelaySec" + "LearnPacketIntervalSec" + "AdSelect" + "AdActorSystemPriority" + "AdUserPortKey" + "AdActorSystem" + "FailOverMACPolicy" + "ARPValidate" + "ARPIntervalSec" + "ARPIPTargets" + "ARPAllTargets" + "PrimaryReselectPolicy" + "ResendIGMP" + "PacketsPerSlave" + "GratuitousARP" + "AllSlavesActive" + "DynamicTransmitLoadBalancing" + "MinLinks" + ]) + (assertValueOneOf "Mode" [ + "balance-rr" + "active-backup" + "balance-xor" + "broadcast" + "802.3ad" + "balance-tlb" + "balance-alb" + ]) + (assertValueOneOf "TransmitHashPolicy" [ + "layer2" + "layer3+4" + "layer2+3" + "encap2+3" + "encap3+4" + ]) + (assertValueOneOf "LACPTransmitRate" ["slow" "fast"]) + (assertValueOneOf "AdSelect" ["stable" "bandwidth" "count"]) + (assertInt "AdActorSystemPriority") + (assertRange "AdActorSystemPriority" 1 65535) + (assertInt "AdUserPortKey") + (assertRange "AdUserPortKey" 0 1023) + (assertValueOneOf "FailOverMACPolicy" ["none" "active" "follow"]) + (assertValueOneOf "ARPValidate" ["none" "active" "backup" "all"]) + (assertValueOneOf "ARPAllTargets" ["any" "all"]) + (assertValueOneOf "PrimaryReselectPolicy" ["always" "better" "failure"]) + (assertInt "ResendIGMP") + (assertRange "ResendIGMP" 0 255) + (assertInt "PacketsPerSlave") + (assertRange "PacketsPerSlave" 0 65535) + (assertInt "GratuitousARP") + (assertRange "GratuitousARP" 0 255) + (assertValueOneOf "AllSlavesActive" boolValues) + (assertValueOneOf "DynamicTransmitLoadBalancing" boolValues) + (assertInt "MinLinks") + (assertMinimum "MinLinks" 0) + ]; - checkXfrm = checkUnitConfig "Xfrm" [ - (assertOnlyFields [ - "InterfaceId" "Independent" - ]) - # The following check won't work on nix <= 2.2 - # see https://github.com/NixOS/nix/pull/2378 - # - # Add this again when we'll have drop the - # nix < 2.2 support. - # (assertRange "InterfaceId" 1 4294967295) - (assertValueOneOf "Independent" boolValues) - ]; + sectionXfrm = checkUnitConfig "Xfrm" [ + (assertOnlyFields [ + "InterfaceId" + "Independent" + ]) + (assertInt "InterfaceId") + (assertRange "InterfaceId" 1 4294967295) + (assertValueOneOf "Independent" boolValues) + ]; - checkNetwork = checkUnitConfig "Network" [ - (assertOnlyFields [ - "Description" "DHCP" "DHCPServer" "LinkLocalAddressing" "IPv4LLRoute" - "IPv6Token" "LLMNR" "MulticastDNS" "DNSOverTLS" "DNSSEC" - "DNSSECNegativeTrustAnchors" "LLDP" "EmitLLDP" "BindCarrier" "Address" - "Gateway" "DNS" "Domains" "NTP" "IPForward" "IPMasquerade" - "IPv6PrivacyExtensions" "IPv6AcceptRA" "IPv6DuplicateAddressDetection" - "IPv6HopLimit" "IPv4ProxyARP" "IPv6ProxyNDP" "IPv6ProxyNDPAddress" - "IPv6PrefixDelegation" "IPv6MTUBytes" "Bridge" "Bond" "VRF" "VLAN" - "IPVLAN" "MACVLAN" "VXLAN" "Tunnel" "ActiveSlave" "PrimarySlave" - "ConfigureWithoutCarrier" "Xfrm" "KeepConfiguration" - ]) - # Note: For DHCP the values both, none, v4, v6 are deprecated - (assertValueOneOf "DHCP" ["yes" "no" "ipv4" "ipv6" "both" "none" "v4" "v6"]) - (assertValueOneOf "DHCPServer" boolValues) - (assertValueOneOf "LinkLocalAddressing" ["yes" "no" "ipv4" "ipv6" "ipv4-fallback" "fallback"]) - (assertValueOneOf "IPv4LLRoute" boolValues) - (assertValueOneOf "LLMNR" ["yes" "resolve" "no"]) - (assertValueOneOf "MulticastDNS" ["yes" "resolve" "no"]) - (assertValueOneOf "DNSOverTLS" ["opportunistic" "no"]) - (assertValueOneOf "DNSSEC" ["yes" "allow-downgrade" "no"]) - (assertValueOneOf "LLDP" ["yes" "routers-only" "no"]) - (assertValueOneOf "EmitLLDP" ["yes" "no" "nearest-bridge" "non-tpmr-bridge" "customer-bridge"]) - (assertValueOneOf "IPForward" ["yes" "no" "ipv4" "ipv6"]) - (assertValueOneOf "IPMasquerade" boolValues) - (assertValueOneOf "IPv6PrivacyExtensions" ["yes" "no" "prefer-public" "kernel"]) - (assertValueOneOf "IPv6AcceptRA" boolValues) - (assertValueOneOf "IPv4ProxyARP" boolValues) - (assertValueOneOf "IPv6ProxyNDP" boolValues) - (assertValueOneOf "IPv6PrefixDelegation" (boolValues ++ [ "dhcpv6" "static" ])) - (assertValueOneOf "ActiveSlave" boolValues) - (assertValueOneOf "PrimarySlave" boolValues) - (assertValueOneOf "ConfigureWithoutCarrier" boolValues) - (assertValueOneOf "KeepConfiguration" (boolValues ++ ["static" "dhcp-on-stop" "dhcp"])) - ]; + sectionVRF = checkUnitConfig "VRF" [ + (assertOnlyFields [ + "Table" + ]) + (assertInt "Table") + (assertMinimum "Table" 0) + ]; + }; - checkAddress = checkUnitConfig "Address" [ - (assertOnlyFields [ - "Address" "Peer" "Broadcast" "Label" "PreferredLifetime" "Scope" - "HomeAddress" "DuplicateAddressDetection" "ManageTemporaryAddress" - "PrefixRoute" "AutoJoin" - ]) - (assertHasField "Address") - (assertValueOneOf "PreferredLifetime" ["forever" "infinity" "0" 0]) - (assertValueOneOf "HomeAddress" boolValues) - (assertValueOneOf "DuplicateAddressDetection" boolValues) - (assertValueOneOf "ManageTemporaryAddress" boolValues) - (assertValueOneOf "PrefixRoute" boolValues) - (assertValueOneOf "AutoJoin" boolValues) - ]; + network = { + + sectionLink = checkUnitConfig "Link" [ + (assertOnlyFields [ + "MACAddress" + "MTUBytes" + "ARP" + "Multicast" + "AllMulticast" + "Unmanaged" + "RequiredForOnline" + ]) + (assertMacAddress "MACAddress") + (assertByteFormat "MTUBytes") + (assertValueOneOf "ARP" boolValues) + (assertValueOneOf "Multicast" boolValues) + (assertValueOneOf "AllMulticast" boolValues) + (assertValueOneOf "Unmanaged" boolValues) + (assertValueOneOf "RequiredForOnline" (boolValues ++ [ + "missing" + "off" + "no-carrier" + "dormant" + "degraded-carrier" + "carrier" + "degraded" + "enslaved" + "routable" + ])) + ]; - checkRoutingPolicyRule = checkUnitConfig "RoutingPolicyRule" [ - (assertOnlyFields [ - "TypeOfService" "From" "To" "FirewallMark" "Table" "Priority" - "IncomingInterface" "OutgoingInterface" "SourcePort" "DestinationPort" - "IPProtocol" "InvertRule" "Family" - ]) - (assertRange "TypeOfService" 0 255) - # The following check won't work on nix <= 2.2 - # see https://github.com/NixOS/nix/pull/2378 - # - # Add this again when we'll have drop the - # nix < 2.2 support. - # (assertRange "FirewallMark" 1 4294967295) - (assertInt "Priority") - (assertPort "SourcePort") - (assertPort "DestinationPort") - (assertValueOneOf "InvertRule" boolValues) - (assertValueOneOf "Family" ["ipv4" "ipv6" "both"]) - ]; + sectionNetwork = checkUnitConfig "Network" [ + (assertOnlyFields [ + "Description" + "DHCP" + "DHCPServer" + "LinkLocalAddressing" + "IPv4LLRoute" + "DefaultRouteOnDevice" + "IPv6Token" + "LLMNR" + "MulticastDNS" + "DNSOverTLS" + "DNSSEC" + "DNSSECNegativeTrustAnchors" + "LLDP" + "EmitLLDP" + "BindCarrier" + "Address" + "Gateway" + "DNS" + "Domains" + "DNSDefaultRoute" + "NTP" + "IPForward" + "IPMasquerade" + "IPv6PrivacyExtensions" + "IPv6AcceptRA" + "IPv6DuplicateAddressDetection" + "IPv6HopLimit" + "IPv4ProxyARP" + "IPv6ProxyNDP" + "IPv6ProxyNDPAddress" + "IPv6PrefixDelegation" + "IPv6MTUBytes" + "Bridge" + "Bond" + "VRF" + "VLAN" + "IPVLAN" + "MACVLAN" + "VXLAN" + "Tunnel" + "MACsec" + "ActiveSlave" + "PrimarySlave" + "ConfigureWithoutCarrier" + "IgnoreCarrierLoss" + "Xfrm" + "KeepConfiguration" + ]) + # Note: For DHCP the values both, none, v4, v6 are deprecated + (assertValueOneOf "DHCP" ["yes" "no" "ipv4" "ipv6"]) + (assertValueOneOf "DHCPServer" boolValues) + (assertValueOneOf "LinkLocalAddressing" ["yes" "no" "ipv4" "ipv6" "fallback" "ipv4-fallback"]) + (assertValueOneOf "IPv4LLRoute" boolValues) + (assertValueOneOf "DefaultRouteOnDevice" boolValues) + (assertValueOneOf "LLMNR" (boolValues ++ ["resolve"])) + (assertValueOneOf "MulticastDNS" (boolValues ++ ["resolve"])) + (assertValueOneOf "DNSOverTLS" (boolValues ++ ["opportunistic"])) + (assertValueOneOf "DNSSEC" (boolValues ++ ["allow-downgrade"])) + (assertValueOneOf "LLDP" (boolValues ++ ["routers-only"])) + (assertValueOneOf "EmitLLDP" (boolValues ++ ["nearest-bridge" "non-tpmr-bridge" "customer-bridge"])) + (assertValueOneOf "DNSDefaultRoute" boolValues) + (assertValueOneOf "IPForward" (boolValues ++ ["ipv4" "ipv6"])) + (assertValueOneOf "IPMasquerade" boolValues) + (assertValueOneOf "IPv6PrivacyExtensions" (boolValues ++ ["prefer-public" "kernel"])) + (assertValueOneOf "IPv6AcceptRA" boolValues) + (assertInt "IPv6DuplicateAddressDetection") + (assertMinimum "IPv6DuplicateAddressDetection" 0) + (assertInt "IPv6HopLimit") + (assertMinimum "IPv6HopLimit" 0) + (assertValueOneOf "IPv4ProxyARP" boolValues) + (assertValueOneOf "IPv6ProxyNDP" boolValues) + (assertValueOneOf "IPv6PrefixDelegation" ["static" "dhcpv6" "yes" "false"]) + (assertByteFormat "IPv6MTUBytes") + (assertValueOneOf "ActiveSlave" boolValues) + (assertValueOneOf "PrimarySlave" boolValues) + (assertValueOneOf "ConfigureWithoutCarrier" boolValues) + (assertValueOneOf "IgnoreCarrierLoss" boolValues) + (assertValueOneOf "KeepConfiguration" (boolValues ++ ["static" "dhcp-on-stop" "dhcp"])) + ]; - checkRoute = checkUnitConfig "Route" [ - (assertOnlyFields [ - "Gateway" "GatewayOnLink" "Destination" "Source" "Metric" - "IPv6Preference" "Scope" "PreferredSource" "Table" "Protocol" "Type" - "InitialCongestionWindow" "InitialAdvertisedReceiveWindow" "QuickAck" - "MTUBytes" - ]) - ]; + sectionAddress = checkUnitConfig "Address" [ + (assertOnlyFields [ + "Address" + "Peer" + "Broadcast" + "Label" + "PreferredLifetime" + "Scope" + "HomeAddress" + "DuplicateAddressDetection" + "ManageTemporaryAddress" + "AddPrefixRoute" + "AutoJoin" + ]) + (assertHasField "Address") + (assertValueOneOf "PreferredLifetime" ["forever" "infinity" "0" 0]) + (assertValueOneOf "HomeAddress" boolValues) + (assertValueOneOf "DuplicateAddressDetection" ["ipv4" "ipv6" "both" "none"]) + (assertValueOneOf "ManageTemporaryAddress" boolValues) + (assertValueOneOf "AddPrefixRoute" boolValues) + (assertValueOneOf "AutoJoin" boolValues) + ]; - checkDhcpV4 = checkUnitConfig "DHCPv4" [ - (assertOnlyFields [ - "UseDNS" "RoutesToDNS" "UseNTP" "UseMTU" "Anonymize" "SendHostname" "UseHostname" - "Hostname" "UseDomains" "UseRoutes" "UseTimezone" - "ClientIdentifier" "VendorClassIdentifier" "UserClass" "MaxAttempts" - "DUIDType" "DUIDRawData" "IAID" "RequestBroadcast" "RouteMetric" "RouteTable" - "ListenPort" "SendRelease" - ]) - (assertValueOneOf "UseDNS" boolValues) - (assertValueOneOf "RoutesToDNS" boolValues) - (assertValueOneOf "UseNTP" boolValues) - (assertValueOneOf "UseMTU" boolValues) - (assertValueOneOf "Anonymize" boolValues) - (assertValueOneOf "SendHostname" boolValues) - (assertValueOneOf "UseHostname" boolValues) - (assertValueOneOf "UseDomains" ["yes" "no" "route"]) - (assertValueOneOf "UseRoutes" boolValues) - (assertValueOneOf "UseTimezone" boolValues) - (assertMinimum "MaxAttempts" 0) - (assertValueOneOf "RequestBroadcast" boolValues) - (assertInt "RouteTable") - (assertMinimum "RouteTable" 0) - (assertValueOneOf "SendRelease" boolValues) - ]; + sectionRoutingPolicyRule = checkUnitConfig "RoutingPolicyRule" [ + (assertOnlyFields [ + "TypeOfService" + "From" + "To" + "FirewallMark" + "Table" + "Priority" + "IncomingInterface" + "OutgoingInterface" + "SourcePort" + "DestinationPort" + "IPProtocol" + "InvertRule" + "Family" + "User" + "SuppressPrefixLength" + ]) + (assertInt "TypeOfService") + (assertRange "TypeOfService" 0 255) + (assertInt "FirewallMark") + (assertRange "FirewallMark" 1 4294967295) + (assertInt "Priority") + (assertPort "SourcePort") + (assertPort "DestinationPort") + (assertValueOneOf "InvertRule" boolValues) + (assertValueOneOf "Family" ["ipv4" "ipv6" "both"]) + (assertInt "SuppressPrefixLength") + (assertRange "SuppressPrefixLength" 0 128) + ]; - checkDhcpV6 = checkUnitConfig "DHCPv6" [ - (assertOnlyFields [ - "UseDNS" "UseNTP" "RapidCommit" "ForceDHCPv6PDOtherInformation" - "PrefixDelegationHint" - ]) - (assertValueOneOf "UseDNS" boolValues) - (assertValueOneOf "UseNTP" boolValues) - (assertValueOneOf "RapidCommit" boolValues) - (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues) - ]; + sectionRoute = checkUnitConfig "Route" [ + (assertOnlyFields [ + "Gateway" + "GatewayOnLink" + "Destination" + "Source" + "Metric" + "IPv6Preference" + "Scope" + "PreferredSource" + "Table" + "Protocol" + "Type" + "InitialCongestionWindow" + "InitialAdvertisedReceiveWindow" + "QuickAck" + "FastOpenNoCookie" + "TTLPropagate" + "MTUBytes" + "IPServiceType" + "MultiPathRoute" + ]) + (assertValueOneOf "GatewayOnLink" boolValues) + (assertInt "Metric") + (assertValueOneOf "IPv6Preference" ["low" "medium" "high"]) + (assertValueOneOf "Scope" ["global" "site" "link" "host" "nowhere"]) + (assertValueOneOf "Type" [ + "unicast" + "local" + "broadcast" + "anycast" + "multicast" + "blackhole" + "unreachable" + "prohibit" + "throw" + "nat" + "xresolve" + ]) + (assertValueOneOf "QuickAck" boolValues) + (assertValueOneOf "FastOpenNoCookie" boolValues) + (assertValueOneOf "TTLPropagate" boolValues) + (assertByteFormat "MTUBytes") + (assertValueOneOf "IPServiceType" ["CS6" "CS4"]) + ]; - checkIpv6PrefixDelegation = checkUnitConfig "IPv6PrefixDelegation" [ - (assertOnlyFields [ - "Managed" "OtherInformation" "RouterLifetimeSec" - "RouterPreference" "EmitDNS" "DNS" "EmitDomains" "Domains" - "DNSLifetimeSec" - ]) - (assertValueOneOf "Managed" boolValues) - (assertValueOneOf "OtherInformation" boolValues) - (assertValueOneOf "RouterPreference" ["high" "medium" "low" "normal" "default"]) - (assertValueOneOf "EmitDNS" boolValues) - (assertValueOneOf "EmitDomains" boolValues) - (assertMinimum "DNSLifetimeSec" 0) - ]; + sectionDHCPv4 = checkUnitConfig "DHCPv4" [ + (assertOnlyFields [ + "UseDNS" + "RoutesToDNS" + "UseNTP" + "UseSIP" + "UseMTU" + "Anonymize" + "SendHostname" + "UseHostname" + "Hostname" + "UseDomains" + "UseRoutes" + "UseTimezone" + "ClientIdentifier" + "VendorClassIdentifier" + "UserClass" + "MaxAttempts" + "DUIDType" + "DUIDRawData" + "IAID" + "RequestBroadcast" + "RouteMetric" + "RouteTable" + "RouteMTUBytes" + "ListenPort" + "SendRelease" + "SendDecline" + "BlackList" + "RequestOptions" + "SendOption" + ]) + (assertValueOneOf "UseDNS" boolValues) + (assertValueOneOf "RoutesToDNS" boolValues) + (assertValueOneOf "UseNTP" boolValues) + (assertValueOneOf "UseSIP" boolValues) + (assertValueOneOf "UseMTU" boolValues) + (assertValueOneOf "Anonymize" boolValues) + (assertValueOneOf "SendHostname" boolValues) + (assertValueOneOf "UseHostname" boolValues) + (assertValueOneOf "UseDomains" (boolValues ++ ["route"])) + (assertValueOneOf "UseRoutes" boolValues) + (assertValueOneOf "UseTimezone" boolValues) + (assertValueOneOf "ClientIdentifier" ["mac" "duid" "duid-only"]) + (assertInt "IAID") + (assertValueOneOf "RequestBroadcast" boolValues) + (assertInt "RouteMetric") + (assertInt "RouteTable") + (assertRange "RouteTable" 0 4294967295) + (assertByteFormat "RouteMTUBytes") + (assertPort "ListenPort") + (assertValueOneOf "SendRelease" boolValues) + (assertValueOneOf "SendDecline" boolValues) + ]; - checkIpv6Prefix = checkUnitConfig "IPv6Prefix" [ - (assertOnlyFields [ - "AddressAutoconfiguration" "OnLink" "Prefix" - "PreferredLifetimeSec" "ValidLifetimeSec" - ]) - (assertValueOneOf "AddressAutoconfiguration" boolValues) - (assertValueOneOf "OnLink" boolValues) - (assertMinimum "PreferredLifetimeSec" 0) - (assertMinimum "ValidLifetimeSec" 0) - ]; + sectionDHCPv6 = checkUnitConfig "DHCPv6" [ + (assertOnlyFields [ + "UseDNS" + "UseNTP" + "RapidCommit" + "ForceDHCPv6PDOtherInformation" + "PrefixDelegationHint" + ]) + (assertValueOneOf "UseDNS" boolValues) + (assertValueOneOf "UseNTP" boolValues) + (assertValueOneOf "RapidCommit" boolValues) + (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues) + ]; + sectionDHCPServer = checkUnitConfig "DHCPServer" [ + (assertOnlyFields [ + "PoolOffset" + "PoolSize" + "DefaultLeaseTimeSec" + "MaxLeaseTimeSec" + "EmitDNS" + "DNS" + "EmitNTP" + "NTP" + "EmitSIP" + "SIP" + "EmitRouter" + "EmitTimezone" + "Timezone" + "SendOption" + ]) + (assertInt "PoolOffset") + (assertMinimum "PoolOffset" 0) + (assertInt "PoolSize") + (assertMinimum "PoolSize" 0) + (assertValueOneOf "EmitDNS" boolValues) + (assertValueOneOf "EmitNTP" boolValues) + (assertValueOneOf "EmitSIP" boolValues) + (assertValueOneOf "EmitRouter" boolValues) + (assertValueOneOf "EmitTimezone" boolValues) + ]; - checkDhcpServer = checkUnitConfig "DHCPServer" [ - (assertOnlyFields [ - "PoolOffset" "PoolSize" "DefaultLeaseTimeSec" "MaxLeaseTimeSec" - "EmitDNS" "DNS" "EmitNTP" "NTP" "EmitRouter" "EmitTimezone" "Timezone" - ]) - (assertValueOneOf "EmitDNS" boolValues) - (assertValueOneOf "EmitNTP" boolValues) - (assertValueOneOf "EmitRouter" boolValues) - (assertValueOneOf "EmitTimezone" boolValues) - ]; + sectionIPv6PrefixDelegation = checkUnitConfig "IPv6PrefixDelegation" [ + (assertOnlyFields [ + "Managed" + "OtherInformation" + "RouterLifetimeSec" + "RouterPreference" + "EmitDNS" + "DNS" + "EmitDomains" + "Domains" + "DNSLifetimeSec" + ]) + (assertValueOneOf "Managed" boolValues) + (assertValueOneOf "OtherInformation" boolValues) + (assertValueOneOf "RouterPreference" ["high" "medium" "low" "normal" "default"]) + (assertValueOneOf "EmitDNS" boolValues) + (assertValueOneOf "EmitDomains" boolValues) + ]; - # .network files have a [Link] section with different options than in .netlink files - checkNetworkLink = checkUnitConfig "Link" [ - (assertOnlyFields [ - "MACAddress" "MTUBytes" "ARP" "Multicast" "Unmanaged" "RequiredForOnline" - ]) - (assertMacAddress "MACAddress") - (assertByteFormat "MTUBytes") - (assertValueOneOf "ARP" boolValues) - (assertValueOneOf "Multicast" boolValues) - (assertValueOneOf "Unmanaged" boolValues) - (assertValueOneOf "RequiredForOnline" (boolValues ++ ["off" "no-carrier" "dormant" "degraded-carrier" "carrier" "degraded" "enslaved" "routable"])) - ]; + sectionIPv6Prefix = checkUnitConfig "IPv6Prefix" [ + (assertOnlyFields [ + "AddressAutoconfiguration" + "OnLink" + "Prefix" + "PreferredLifetimeSec" + "ValidLifetimeSec" + ]) + (assertValueOneOf "AddressAutoconfiguration" boolValues) + (assertValueOneOf "OnLink" boolValues) + ]; + }; + }; commonNetworkOptions = { @@ -406,7 +761,7 @@ let linkConfig = mkOption { default = {}; example = { MACAddress = "00:ff:ee:aa:cc:dd"; }; - type = types.addCheck (types.attrsOf unitOption) checkLink; + type = types.addCheck (types.attrsOf unitOption) check.link.sectionLink; description = '' Each attribute in this set specifies an option in the <literal>[Link]</literal> section of the unit. See @@ -417,12 +772,28 @@ let }; + wireguardPeerOptions = { + options = { + wireguardPeerConfig = mkOption { + default = {}; + example = { }; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuardPeer; + description = '' + Each attribute in this set specifies an option in the + <literal>[WireGuardPeer]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + }; + }; + netdevOptions = commonNetworkOptions // { netdevConfig = mkOption { default = {}; example = { Name = "mybridge"; Kind = "bridge"; }; - type = types.addCheck (types.attrsOf unitOption) checkNetdev; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionNetdev; description = '' Each attribute in this set specifies an option in the <literal>[Netdev]</literal> section of the unit. See @@ -431,65 +802,10 @@ let ''; }; - vrfConfig = mkOption { - default = {}; - example = { Table = 2342; }; - type = types.addCheck (types.attrsOf unitOption) checkVRF; - description = '' - Each attribute in this set specifies an option in the - <literal>[VRF]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - A detailed explanation about how VRFs work can be found in the - <link xlink:href="https://www.kernel.org/doc/Documentation/networking/vrf.txt">kernel - docs</link>. - ''; - }; - - wireguardConfig = mkOption { - default = {}; - example = { - PrivateKeyFile = "/etc/wireguard/secret.key"; - ListenPort = 51820; - FwMark = 42; - }; - type = types.addCheck (types.attrsOf unitOption) checkWireGuard; - description = '' - Each attribute in this set specifies an option in the - <literal>[WireGuard]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - Use <literal>PrivateKeyFile</literal> instead of - <literal>PrivateKey</literal>: the nix store is - world-readable. - ''; - }; - - wireguardPeers = mkOption { - default = []; - example = [ { wireguardPeerConfig={ - Endpoint = "192.168.1.1:51820"; - PublicKey = "27s0OvaBBdHoJYkH9osZpjpgSOVNw+RaKfboT/Sfq0g="; - PresharedKeyFile = "/etc/wireguard/psk.key"; - AllowedIPs = [ "10.0.0.1/32" ]; - PersistentKeepalive = 15; - };}]; - type = with types; listOf (submodule wireguardPeerOptions); - description = '' - Each item in this array specifies an option in the - <literal>[WireGuardPeer]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - Use <literal>PresharedKeyFile</literal> instead of - <literal>PresharedKey</literal>: the nix store is - world-readable. - ''; - }; - vlanConfig = mkOption { default = {}; example = { Id = 4; }; - type = types.addCheck (types.attrsOf unitOption) checkVlan; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVLAN; description = '' Each attribute in this set specifies an option in the <literal>[VLAN]</literal> section of the unit. See @@ -501,7 +817,7 @@ let macvlanConfig = mkOption { default = {}; example = { Mode = "private"; }; - type = types.addCheck (types.attrsOf unitOption) checkMacvlan; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionMACVLAN; description = '' Each attribute in this set specifies an option in the <literal>[MACVLAN]</literal> section of the unit. See @@ -513,7 +829,7 @@ let vxlanConfig = mkOption { default = {}; example = { Id = "4"; }; - type = types.addCheck (types.attrsOf unitOption) checkVxlan; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVXLAN; description = '' Each attribute in this set specifies an option in the <literal>[VXLAN]</literal> section of the unit. See @@ -525,7 +841,7 @@ let tunnelConfig = mkOption { default = {}; example = { Remote = "192.168.1.1"; }; - type = types.addCheck (types.attrsOf unitOption) checkTunnel; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionTunnel; description = '' Each attribute in this set specifies an option in the <literal>[Tunnel]</literal> section of the unit. See @@ -537,7 +853,7 @@ let peerConfig = mkOption { default = {}; example = { Name = "veth2"; }; - type = types.addCheck (types.attrsOf unitOption) checkPeer; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionPeer; description = '' Each attribute in this set specifies an option in the <literal>[Peer]</literal> section of the unit. See @@ -549,7 +865,7 @@ let tunConfig = mkOption { default = {}; example = { User = "openvpn"; }; - type = types.addCheck (types.attrsOf unitOption) checkTun; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionTun; description = '' Each attribute in this set specifies an option in the <literal>[Tun]</literal> section of the unit. See @@ -561,7 +877,7 @@ let tapConfig = mkOption { default = {}; example = { User = "openvpn"; }; - type = types.addCheck (types.attrsOf unitOption) checkTap; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionTap; description = '' Each attribute in this set specifies an option in the <literal>[Tap]</literal> section of the unit. See @@ -570,10 +886,50 @@ let ''; }; + wireguardConfig = mkOption { + default = {}; + example = { + PrivateKeyFile = "/etc/wireguard/secret.key"; + ListenPort = 51820; + FwMark = 42; + }; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionWireGuard; + description = '' + Each attribute in this set specifies an option in the + <literal>[WireGuard]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + Use <literal>PrivateKeyFile</literal> instead of + <literal>PrivateKey</literal>: the nix store is + world-readable. + ''; + }; + + wireguardPeers = mkOption { + default = []; + example = [ { wireguardPeerConfig={ + Endpoint = "192.168.1.1:51820"; + PublicKey = "27s0OvaBBdHoJYkH9osZpjpgSOVNw+RaKfboT/Sfq0g="; + PresharedKeyFile = "/etc/wireguard/psk.key"; + AllowedIPs = [ "10.0.0.1/32" ]; + PersistentKeepalive = 15; + };}]; + type = with types; listOf (submodule wireguardPeerOptions); + description = '' + Each item in this array specifies an option in the + <literal>[WireGuardPeer]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + Use <literal>PresharedKeyFile</literal> instead of + <literal>PresharedKey</literal>: the nix store is + world-readable. + ''; + }; + bondConfig = mkOption { default = {}; example = { Mode = "802.3ad"; }; - type = types.addCheck (types.attrsOf unitOption) checkBond; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionBond; description = '' Each attribute in this set specifies an option in the <literal>[Bond]</literal> section of the unit. See @@ -585,7 +941,7 @@ let xfrmConfig = mkOption { default = {}; example = { InterfaceId = 1; }; - type = types.addCheck (types.attrsOf unitOption) checkXfrm; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionXfrm; description = '' Each attribute in this set specifies an option in the <literal>[Xfrm]</literal> section of the unit. See @@ -594,6 +950,21 @@ let ''; }; + vrfConfig = mkOption { + default = {}; + example = { Table = 2342; }; + type = types.addCheck (types.attrsOf unitOption) check.netdev.sectionVRF; + description = '' + Each attribute in this set specifies an option in the + <literal>[VRF]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + A detailed explanation about how VRFs work can be found in the + <link xlink:href="https://www.kernel.org/doc/Documentation/networking/vrf.txt">kernel + docs</link>. + ''; + }; + }; addressOptions = { @@ -601,7 +972,7 @@ let addressConfig = mkOption { default = {}; example = { Address = "192.168.0.100/24"; }; - type = types.addCheck (types.attrsOf unitOption) checkAddress; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionAddress; description = '' Each attribute in this set specifies an option in the <literal>[Address]</literal> section of the unit. See @@ -617,7 +988,7 @@ let routingPolicyRuleConfig = mkOption { default = { }; example = { routingPolicyRuleConfig = { Table = 10; IncomingInterface = "eth1"; Family = "both"; } ;}; - type = types.addCheck (types.attrsOf unitOption) checkRoutingPolicyRule; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoutingPolicyRule; description = '' Each attribute in this set specifies an option in the <literal>[RoutingPolicyRule]</literal> section of the unit. See @@ -633,7 +1004,7 @@ let routeConfig = mkOption { default = {}; example = { Gateway = "192.168.0.1"; }; - type = types.addCheck (types.attrsOf unitOption) checkRoute; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionRoute; description = '' Each attribute in this set specifies an option in the <literal>[Route]</literal> section of the unit. See @@ -644,28 +1015,12 @@ let }; }; - wireguardPeerOptions = { - options = { - wireguardPeerConfig = mkOption { - default = {}; - example = { }; - type = types.addCheck (types.attrsOf unitOption) checkWireGuardPeer; - description = '' - Each attribute in this set specifies an option in the - <literal>[WireGuardPeer]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - }; - }; - ipv6PrefixOptions = { options = { ipv6PrefixConfig = mkOption { default = {}; example = { Prefix = "fd00::/64"; }; - type = types.addCheck (types.attrsOf unitOption) checkIpv6Prefix; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6Prefix; description = '' Each attribute in this set specifies an option in the <literal>[IPv6Prefix]</literal> section of the unit. See @@ -676,13 +1031,24 @@ let }; }; - networkOptions = commonNetworkOptions // { + linkConfig = mkOption { + default = {}; + example = { Unmanaged = true; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionLink; + description = '' + Each attribute in this set specifies an option in the + <literal>[Link]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + networkConfig = mkOption { default = {}; example = { Description = "My Network"; }; - type = types.addCheck (types.attrsOf unitOption) checkNetwork; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionNetwork; description = '' Each attribute in this set specifies an option in the <literal>[Network]</literal> section of the unit. See @@ -701,7 +1067,7 @@ let dhcpV4Config = mkOption { default = {}; example = { UseDNS = true; UseRoutes = true; }; - type = types.addCheck (types.attrsOf unitOption) checkDhcpV4; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv4; description = '' Each attribute in this set specifies an option in the <literal>[DHCPv4]</literal> section of the unit. See @@ -713,7 +1079,7 @@ let dhcpV6Config = mkOption { default = {}; example = { UseDNS = true; UseRoutes = true; }; - type = types.addCheck (types.attrsOf unitOption) checkDhcpV6; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv6; description = '' Each attribute in this set specifies an option in the <literal>[DHCPv6]</literal> section of the unit. See @@ -722,48 +1088,36 @@ let ''; }; - ipv6PrefixDelegationConfig = mkOption { + dhcpServerConfig = mkOption { default = {}; - example = { EmitDNS = true; Managed = true; OtherInformation = true; }; - type = types.addCheck (types.attrsOf unitOption) checkIpv6PrefixDelegation; + example = { PoolOffset = 50; EmitDNS = false; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPServer; description = '' Each attribute in this set specifies an option in the - <literal>[IPv6PrefixDelegation]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - ipv6Prefixes = mkOption { - default = []; - example = { AddressAutoconfiguration = true; OnLink = true; }; - type = with types; listOf (submodule ipv6PrefixOptions); - description = '' - A list of ipv6Prefix sections to be added to the unit. See + <literal>[DHCPServer]</literal> section of the unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> <manvolnum>5</manvolnum></citerefentry> for details. ''; }; - dhcpServerConfig = mkOption { + ipv6PrefixDelegationConfig = mkOption { default = {}; - example = { PoolOffset = 50; EmitDNS = false; }; - type = types.addCheck (types.attrsOf unitOption) checkDhcpServer; + example = { EmitDNS = true; Managed = true; OtherInformation = true; }; + type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6PrefixDelegation; description = '' Each attribute in this set specifies an option in the - <literal>[DHCPServer]</literal> section of the unit. See + <literal>[IPv6PrefixDelegation]</literal> section of the unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> <manvolnum>5</manvolnum></citerefentry> for details. ''; }; - linkConfig = mkOption { - default = {}; - example = { Unmanaged = true; }; - type = types.addCheck (types.attrsOf unitOption) checkNetworkLink; + ipv6Prefixes = mkOption { + default = []; + example = { AddressAutoconfiguration = true; OnLink = true; }; + type = with types; listOf (submodule ipv6PrefixOptions); description = '' - Each attribute in this set specifies an option in the - <literal>[Link]</literal> section of the unit. See + A list of ipv6Prefix sections to be added to the unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> <manvolnum>5</manvolnum></citerefentry> for details. ''; @@ -958,160 +1312,162 @@ let }; }; - commonMatchText = def: optionalString (def.matchConfig != {}) '' + commonMatchText = def: optionalString (def.matchConfig != { }) '' [Match] ${attrsToSection def.matchConfig} ''; linkToUnit = name: def: { inherit (def) enable; - text = commonMatchText def + - '' + text = commonMatchText def + + '' [Link] ${attrsToSection def.linkConfig} - - ${def.extraConfig} - ''; + '' + + def.extraConfig; }; netdevToUnit = name: def: { inherit (def) enable; - text = commonMatchText def + - '' + text = commonMatchText def + + '' [NetDev] ${attrsToSection def.netdevConfig} - - ${optionalString (def.vlanConfig != { }) '' - [VLAN] - ${attrsToSection def.vlanConfig} - - ''} - ${optionalString (def.macvlanConfig != { }) '' - [MACVLAN] - ${attrsToSection def.macvlanConfig} - - ''} - ${optionalString (def.vxlanConfig != { }) '' - [VXLAN] - ${attrsToSection def.vxlanConfig} - - ''} - ${optionalString (def.tunnelConfig != { }) '' - [Tunnel] - ${attrsToSection def.tunnelConfig} - - ''} - ${optionalString (def.peerConfig != { }) '' - [Peer] - ${attrsToSection def.peerConfig} - - ''} - ${optionalString (def.tunConfig != { }) '' - [Tun] - ${attrsToSection def.tunConfig} - - ''} - ${optionalString (def.tapConfig != { }) '' - [Tap] - ${attrsToSection def.tapConfig} - - ''} - ${optionalString (def.bondConfig != { }) '' - [Bond] - ${attrsToSection def.bondConfig} - - ''} - ${optionalString (def.xfrmConfig != { }) '' - [Xfrm] - ${attrsToSection def.xfrmConfig} - - ''} - ${optionalString (def.vrfConfig != { }) '' - [VRF] - ${attrsToSection def.vrfConfig} - - ''} - ${optionalString (def.wireguardConfig != { }) '' - [WireGuard] - ${attrsToSection def.wireguardConfig} - - ''} - ${flip concatMapStrings def.wireguardPeers (x: '' - [WireGuardPeer] - ${attrsToSection x.wireguardPeerConfig} - - '')} - ${def.extraConfig} - ''; + '' + + optionalString (def.vlanConfig != { }) '' + [VLAN] + ${attrsToSection def.vlanConfig} + '' + + optionalString (def.macvlanConfig != { }) '' + [MACVLAN] + ${attrsToSection def.macvlanConfig} + '' + + optionalString (def.vxlanConfig != { }) '' + [VXLAN] + ${attrsToSection def.vxlanConfig} + '' + + optionalString (def.tunnelConfig != { }) '' + [Tunnel] + ${attrsToSection def.tunnelConfig} + '' + + optionalString (def.peerConfig != { }) '' + [Peer] + ${attrsToSection def.peerConfig} + '' + + optionalString (def.tunConfig != { }) '' + [Tun] + ${attrsToSection def.tunConfig} + '' + + optionalString (def.tapConfig != { }) '' + [Tap] + ${attrsToSection def.tapConfig} + '' + + optionalString (def.wireguardConfig != { }) '' + [WireGuard] + ${attrsToSection def.wireguardConfig} + '' + + flip concatMapStrings def.wireguardPeers (x: '' + [WireGuardPeer] + ${attrsToSection x.wireguardPeerConfig} + '') + + optionalString (def.bondConfig != { }) '' + [Bond] + ${attrsToSection def.bondConfig} + '' + + optionalString (def.xfrmConfig != { }) '' + [Xfrm] + ${attrsToSection def.xfrmConfig} + '' + + optionalString (def.vrfConfig != { }) '' + [VRF] + ${attrsToSection def.vrfConfig} + '' + + def.extraConfig; }; networkToUnit = name: def: { inherit (def) enable; - text = commonMatchText def + + text = commonMatchText def + + optionalString (def.linkConfig != { }) '' + [Link] + ${attrsToSection def.linkConfig} '' - ${optionalString (def.linkConfig != { }) '' - [Link] - ${attrsToSection def.linkConfig} - - ''} - + + '' [Network] - ${attrsToSection def.networkConfig} + '' + + attrsToSection def.networkConfig + + optionalString (def.address != [ ]) '' ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)} + '' + + optionalString (def.gateway != [ ]) '' ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)} + '' + + optionalString (def.dns != [ ]) '' ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)} + '' + + optionalString (def.ntp != [ ]) '' ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)} + '' + + optionalString (def.bridge != [ ]) '' ${concatStringsSep "\n" (map (s: "Bridge=${s}") def.bridge)} + '' + + optionalString (def.bond != [ ]) '' ${concatStringsSep "\n" (map (s: "Bond=${s}") def.bond)} + '' + + optionalString (def.vrf != [ ]) '' ${concatStringsSep "\n" (map (s: "VRF=${s}") def.vrf)} + '' + + optionalString (def.vlan != [ ]) '' ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)} + '' + + optionalString (def.macvlan != [ ]) '' ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)} + '' + + optionalString (def.vxlan != [ ]) '' ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)} + '' + + optionalString (def.tunnel != [ ]) '' ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)} + '' + + optionalString (def.xfrm != [ ]) '' ${concatStringsSep "\n" (map (s: "Xfrm=${s}") def.xfrm)} + '' + + '' - ${optionalString (def.dhcpV4Config != { }) '' - [DHCPv4] - ${attrsToSection def.dhcpV4Config} - - ''} - ${optionalString (def.dhcpV6Config != {}) '' - [DHCPv6] - ${attrsToSection def.dhcpV6Config} - - ''} - ${optionalString (def.ipv6PrefixDelegationConfig != {}) '' - [IPv6PrefixDelegation] - ${attrsToSection def.ipv6PrefixDelegationConfig} - - ''} - ${flip concatMapStrings def.ipv6Prefixes (x: '' - [IPv6Prefix] - ${attrsToSection x.ipv6PrefixConfig} - - '')} - ${optionalString (def.dhcpServerConfig != { }) '' - [DHCPServer] - ${attrsToSection def.dhcpServerConfig} - - ''} - ${flip concatMapStrings def.addresses (x: '' - [Address] - ${attrsToSection x.addressConfig} - - '')} - ${flip concatMapStrings def.routes (x: '' - [Route] - ${attrsToSection x.routeConfig} - - '')} - ${flip concatMapStrings def.routingPolicyRules (x: '' - [RoutingPolicyRule] - ${attrsToSection x.routingPolicyRuleConfig} - - '')} - ${def.extraConfig} - ''; + '' + + flip concatMapStrings def.addresses (x: '' + [Address] + ${attrsToSection x.addressConfig} + '') + + flip concatMapStrings def.routingPolicyRules (x: '' + [RoutingPolicyRule] + ${attrsToSection x.routingPolicyRuleConfig} + '') + + flip concatMapStrings def.routes (x: '' + [Route] + ${attrsToSection x.routeConfig} + '') + + optionalString (def.dhcpV4Config != { }) '' + [DHCPv4] + ${attrsToSection def.dhcpV4Config} + '' + + optionalString (def.dhcpV6Config != { }) '' + [DHCPv6] + ${attrsToSection def.dhcpV6Config} + '' + + optionalString (def.dhcpServerConfig != { }) '' + [DHCPServer] + ${attrsToSection def.dhcpServerConfig} + '' + + optionalString (def.ipv6PrefixDelegationConfig != { }) '' + [IPv6PrefixDelegation] + ${attrsToSection def.ipv6PrefixDelegationConfig} + '' + + flip concatMapStrings def.ipv6Prefixes (x: '' + [IPv6Prefix] + ${attrsToSection x.ipv6PrefixConfig} + '') + + def.extraConfig; }; unitFiles = listToAttrs (map (name: { diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 86bd81d781a..a5f368c869a 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -73,7 +73,7 @@ let "systemd-journald.service" "systemd-journal-flush.service" "systemd-journal-catalog-update.service" - "systemd-journald-audit.socket" + ] ++ (optional (!config.boot.isContainer) "systemd-journald-audit.socket") ++ [ "systemd-journald-dev-log.socket" "syslog.socket" @@ -101,7 +101,7 @@ let "dev-hugepages.mount" "dev-mqueue.mount" "sys-fs-fuse-connections.mount" - "sys-kernel-config.mount" + ] ++ (optional (!config.boot.isContainer) "sys-kernel-config.mount") ++ [ "sys-kernel-debug.mount" # Maintaining state across reboots. diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix index e70004e643e..69385e5f2fe 100644 --- a/nixos/modules/tasks/auto-upgrade.nix +++ b/nixos/modules/tasks/auto-upgrade.nix @@ -2,9 +2,9 @@ with lib; -let cfg = config.system.autoUpgrade; in +let cfg = config.system.autoUpgrade; -{ +in { options = { @@ -21,6 +21,16 @@ let cfg = config.system.autoUpgrade; in ''; }; + flake = mkOption { + type = types.nullOr types.str; + default = null; + example = "github:kloenk/nix"; + description = '' + The Flake URI of the NixOS configuration to build. + Disables the option <option>system.autoUpgrade.channel</option>. + ''; + }; + channel = mkOption { type = types.nullOr types.str; default = null; @@ -35,10 +45,20 @@ let cfg = config.system.autoUpgrade; in flags = mkOption { type = types.listOf types.str; - default = []; - example = [ "-I" "stuff=/home/alice/nixos-stuff" "--option" "extra-binary-caches" "http://my-cache.example.org/" ]; + default = [ ]; + example = [ + "-I" + "stuff=/home/alice/nixos-stuff" + "--option" + "extra-binary-caches" + "http://my-cache.example.org/" + ]; description = '' Any additional flags passed to <command>nixos-rebuild</command>. + + If you are using flakes and use a local repo you can add + <command>[ "--update-input" "nixpkgs" "--commit-lock-file" ]</command> + to update nixpkgs. ''; }; @@ -82,11 +102,23 @@ let cfg = config.system.autoUpgrade; in config = lib.mkIf cfg.enable { - system.autoUpgrade.flags = - [ "--no-build-output" ] - ++ (if cfg.channel == null - then [ "--upgrade" ] - else [ "-I" "nixpkgs=${cfg.channel}/nixexprs.tar.xz" ]); + assertions = [{ + assertion = !((cfg.channel != null) && (cfg.flake != null)); + message = '' + The options 'system.autoUpgrade.channels' and 'system.autoUpgrade.flake' cannot both be set. + ''; + }]; + + system.autoUpgrade.flags = [ "--no-build-output" ] + ++ (if cfg.flake == null then + (if cfg.channel == null then + [ "--upgrade" ] + else [ + "-I" + "nixpkgs=${cfg.channel}/nixexprs.tar.xz" + ]) + else + [ "--flake ${cfg.flake}" ]); systemd.services.nixos-upgrade = { description = "NixOS Upgrade"; @@ -96,33 +128,41 @@ let cfg = config.system.autoUpgrade; in serviceConfig.Type = "oneshot"; - environment = config.nix.envVars // - { inherit (config.environment.sessionVariables) NIX_PATH; - HOME = "/root"; - } // config.networking.proxy.envVars; + environment = config.nix.envVars // { + inherit (config.environment.sessionVariables) NIX_PATH; + HOME = "/root"; + } // config.networking.proxy.envVars; - path = with pkgs; [ coreutils gnutar xz.bin gzip gitMinimal config.nix.package.out ]; + path = with pkgs; [ + coreutils + gnutar + xz.bin + gzip + gitMinimal + config.nix.package.out + ]; script = let - nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild"; - in - if cfg.allowReboot then '' - ${nixos-rebuild} boot ${toString cfg.flags} - booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})" - built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})" - if [ "$booted" = "$built" ]; then - ${nixos-rebuild} switch ${toString cfg.flags} - else - /run/current-system/sw/bin/shutdown -r +1 - fi - '' else '' - ${nixos-rebuild} switch ${toString cfg.flags} - ''; + nixos-rebuild = + "${config.system.build.nixos-rebuild}/bin/nixos-rebuild"; + in if cfg.allowReboot then '' + ${nixos-rebuild} boot ${toString cfg.flags} + booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})" + built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})" + if [ "$booted" = "$built" ]; then + ${nixos-rebuild} switch ${toString cfg.flags} + else + /run/current-system/sw/bin/shutdown -r +1 + fi + '' else '' + ${nixos-rebuild} switch ${toString cfg.flags} + ''; startAt = cfg.dates; }; - systemd.timers.nixos-upgrade.timerConfig.RandomizedDelaySec = cfg.randomizedDelaySec; + systemd.timers.nixos-upgrade.timerConfig.RandomizedDelaySec = + cfg.randomizedDelaySec; }; diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 2e87197176b..9ba6ccfbe71 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -253,8 +253,8 @@ let createTunDevice = i: nameValuePair "${i.name}-netdev" { description = "Virtual Network Interface ${i.name}"; - bindsTo = [ "dev-net-tun.device" ]; - after = [ "dev-net-tun.device" "network-pre.target" ]; + bindsTo = optional (!config.boot.isContainer) "dev-net-tun.device"; + after = optional (!config.boot.isContainer) "dev-net-tun.device" ++ [ "network-pre.target" ]; wantedBy = [ "network-setup.service" (subsystemDevice i.name) ]; partOf = [ "network-setup.service" ]; before = [ "network-setup.service" ]; |