diff options
Diffstat (limited to 'nixos')
23 files changed, 746 insertions, 106 deletions
diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml index a499f0080d7..757174c5263 100644 --- a/nixos/doc/manual/configuration/x-windows.xml +++ b/nixos/doc/manual/configuration/x-windows.xml @@ -204,18 +204,18 @@ XKB </link> keyboard layouts using the option - <option> - <link linkend="opt-services.xserver.extraLayouts"> - services.xserver.extraLayouts - </link> - </option>. + <option><link linkend="opt-services.xserver.extraLayouts"> + services.xserver.extraLayouts</link></option>. + </para> + <para> As a first example, we are going to create a layout based on the basic US layout, with an additional layer to type some greek symbols by pressing the right-alt key. </para> <para> - To do this we are going to create a <literal>us-greek</literal> file - with a <literal>xkb_symbols</literal> section. + Create a file called <literal>us-greek</literal> with the following + content (under a directory called <literal>symbols</literal>; it's + an XKB peculiarity that will help with testing): </para> <programlisting> xkb_symbols "us-greek" @@ -231,14 +231,13 @@ xkb_symbols "us-greek" }; </programlisting> <para> - To install the layout, the filepath, a description and the list of - languages must be given: + A minimal layout specification must include the following: </para> <programlisting> <xref linkend="opt-services.xserver.extraLayouts"/>.us-greek = { description = "US layout with alt-gr greek"; languages = [ "eng" ]; - symbolsFile = /path/to/us-greek; + symbolsFile = /yourpath/symbols/us-greek; } </programlisting> <note> @@ -248,9 +247,27 @@ xkb_symbols "us-greek" </para> </note> <para> - The layout should now be installed and ready to use: try it by - running <literal>setxkbmap us-greek</literal> and type - <literal><alt>+a</literal>. To change the default the usual + Applying this customization requires rebuilding several packages, + and a broken XKB file can lead to the X session crashing at login. + Therefore, you're strongly advised to <emphasis role="strong">test + your layout before applying it</emphasis>: +<screen> +<prompt>$ </prompt>nix-shell -p xorg.xkbcomp +<prompt>$ </prompt>setxkbmap -I/yourpath us-greek -print | xkbcomp -I/yourpath - $DISPLAY +</screen> + </para> + <para> + You can inspect the predefined XKB files for examples: +<screen> +<prompt>$ </prompt>echo "$(nix-build --no-out-link '<nixpkgs>' -A xorg.xkeyboardconfig)/etc/X11/xkb/" +</screen> + </para> + <para> + Once the configuration is applied, and you did a logout/login + cycle, the layout should be ready to use. You can try it by e.g. + running <literal>setxkbmap us-greek</literal> and then type + <literal><alt>+a</literal> (it may not get applied in your + terminal straight away). To change the default, the usual <option> <link linkend="opt-services.xserver.layout"> services.xserver.layout diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml index e0552c25a85..5fbef88c4a5 100644 --- a/nixos/doc/manual/release-notes/rl-2105.xml +++ b/nixos/doc/manual/release-notes/rl-2105.xml @@ -680,6 +680,13 @@ environment.systemPackages = [ All CUDA toolkit versions prior to CUDA 10 have been removed. </para> </listitem> + <listitem> + <para> + The <package>babeld</package> service is now being run as an unprivileged user. To achieve that the module configures + <literal>skip-kernel-setup true</literal> and takes care of setting forwarding and rp_filter sysctls by itself as well + as for each interface in <varname>services.babeld.interfaces</varname>. + </para> + </listitem> </itemizedlist> </section> diff --git a/nixos/lib/make-disk-image.nix b/nixos/lib/make-disk-image.nix index d87b3ef8da0..7d40d3b5548 100644 --- a/nixos/lib/make-disk-image.nix +++ b/nixos/lib/make-disk-image.nix @@ -346,6 +346,9 @@ in pkgs.vmTools.runInLinuxVM ( # Some tools assume these exist ln -s vda /dev/xvda ln -s vda /dev/sda + # make systemd-boot find ESP without udev + mkdir /dev/block + ln -s /dev/vda1 /dev/block/254:1 mountPoint=/mnt mkdir $mountPoint diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index 9d49d4055e4..ea9667995e1 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -125,7 +125,7 @@ fi # Resolve the flake. if [[ -n $flake ]]; then - flake=$(nix "${flakeFlags[@]}" flake info --json "${extraBuildFlags[@]}" "${lockFlags[@]}" -- "$flake" | jq -r .url) + flake=$(nix "${flakeFlags[@]}" flake metadata --json "${extraBuildFlags[@]}" "${lockFlags[@]}" -- "$flake" | jq -r .url) fi if [[ ! -e $NIXOS_CONFIG && -z $system && -z $flake ]]; then diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 98ba5ba48b4..3720b24f395 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -530,6 +530,7 @@ ./services/misc/parsoid.nix ./services/misc/plex.nix ./services/misc/plikd.nix + ./services/misc/podgrab.nix ./services/misc/tautulli.nix ./services/misc/pinnwand.nix ./services/misc/pykms.nix @@ -701,6 +702,9 @@ ./services/networking/iodine.nix ./services/networking/iperf3.nix ./services/networking/ircd-hybrid/default.nix + ./services/networking/iscsi/initiator.nix + ./services/networking/iscsi/root-initiator.nix + ./services/networking/iscsi/target.nix ./services/networking/iwd.nix ./services/networking/jicofo.nix ./services/networking/jitsi-videobridge.nix diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix index f3fc4c3cc79..54b6693f85a 100644 --- a/nixos/modules/services/hardware/pcscd.nix +++ b/nixos/modules/services/hardware/pcscd.nix @@ -10,39 +10,37 @@ let paths = map (p: "${p}/pcsc/drivers") config.services.pcscd.plugins; }; -in { +in +{ ###### interface - options = { + options.services.pcscd = { + enable = mkEnableOption "PCSC-Lite daemon"; - services.pcscd = { - enable = mkEnableOption "PCSC-Lite daemon"; - - plugins = mkOption { - type = types.listOf types.package; - default = [ pkgs.ccid ]; - defaultText = "[ pkgs.ccid ]"; - example = literalExample "[ pkgs.pcsc-cyberjack ]"; - description = "Plugin packages to be used for PCSC-Lite."; - }; - - readerConfig = mkOption { - type = types.lines; - default = ""; - example = '' - FRIENDLYNAME "Some serial reader" - DEVICENAME /dev/ttyS0 - LIBPATH /path/to/serial_reader.so - CHANNELID 1 - ''; - description = '' - Configuration for devices that aren't hotpluggable. + plugins = mkOption { + type = types.listOf types.package; + default = [ pkgs.ccid ]; + defaultText = "[ pkgs.ccid ]"; + example = literalExample "[ pkgs.pcsc-cyberjack ]"; + description = "Plugin packages to be used for PCSC-Lite."; + }; - See <citerefentry><refentrytitle>reader.conf</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for valid options. - ''; - }; + readerConfig = mkOption { + type = types.lines; + default = ""; + example = '' + FRIENDLYNAME "Some serial reader" + DEVICENAME /dev/ttyS0 + LIBPATH /path/to/serial_reader.so + CHANNELID 1 + ''; + description = '' + Configuration for devices that aren't hotpluggable. + + See <citerefentry><refentrytitle>reader.conf</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for valid options. + ''; }; }; @@ -50,20 +48,15 @@ in { config = mkIf config.services.pcscd.enable { - systemd.sockets.pcscd = { - description = "PCSC-Lite Socket"; - wantedBy = [ "sockets.target" ]; - before = [ "multi-user.target" ]; - socketConfig.ListenStream = "/run/pcscd/pcscd.comm"; - }; + environment.etc."reader.conf".source = cfgFile; + + systemd.packages = [ (getBin pkgs.pcsclite) ]; + + systemd.sockets.pcscd.wantedBy = [ "sockets.target" ]; systemd.services.pcscd = { - description = "PCSC-Lite daemon"; environment.PCSCLITE_HP_DROPDIR = pluginEnv; - serviceConfig = { - ExecStart = "${getBin pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}"; - ExecReload = "${getBin pkgs.pcsclite}/sbin/pcscd -H"; - }; + restartTriggers = [ "/etc/reader.conf" ]; }; }; } diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix index 892fbd33214..8927d84b478 100644 --- a/nixos/modules/services/mail/exim.nix +++ b/nixos/modules/services/mail/exim.nix @@ -67,6 +67,13 @@ in ''; }; + queueRunnerInterval = mkOption { + type = types.str; + default = "5m"; + description = '' + How often to spawn a new queue runner. + ''; + }; }; }; @@ -104,7 +111,7 @@ in wantedBy = [ "multi-user.target" ]; restartTriggers = [ config.environment.etc."exim.conf".source ]; serviceConfig = { - ExecStart = "${cfg.package}/bin/exim -bdf -q30m"; + ExecStart = "${cfg.package}/bin/exim -bdf -q${cfg.queueRunnerInterval}"; ExecReload = "${coreutils}/bin/kill -HUP $MAINPID"; }; preStart = '' diff --git a/nixos/modules/services/mail/spamassassin.nix b/nixos/modules/services/mail/spamassassin.nix index 4e642542ec6..ac878222b26 100644 --- a/nixos/modules/services/mail/spamassassin.nix +++ b/nixos/modules/services/mail/spamassassin.nix @@ -126,19 +126,36 @@ in }; systemd.services.sa-update = { + # Needs to be able to contact the update server. + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + serviceConfig = { + Type = "oneshot"; + User = "spamd"; + Group = "spamd"; + StateDirectory = "spamassassin"; + ExecStartPost = "+${pkgs.systemd}/bin/systemctl -q --no-block try-reload-or-restart spamd.service"; + }; + script = '' set +e - ${pkgs.su}/bin/su -s "${pkgs.bash}/bin/bash" -c "${pkgs.spamassassin}/bin/sa-update --gpghomedir=/var/lib/spamassassin/sa-update-keys/" spamd - - v=$? + ${pkgs.spamassassin}/bin/sa-update --verbose --gpghomedir=/var/lib/spamassassin/sa-update-keys/ + rc=$? set -e - if [ $v -gt 1 ]; then - echo "sa-update execution error" - exit $v + + if [[ $rc -gt 1 ]]; then + # sa-update failed. + exit $rc fi - if [ $v -eq 0 ]; then - systemctl reload spamd.service + + if [[ $rc -eq 1 ]]; then + # No update was available, exit successfully. + exit 0 fi + + # An update was available and installed. Compile the rules. + ${pkgs.spamassassin}/bin/sa-compile ''; }; @@ -153,32 +170,22 @@ in }; systemd.services.spamd = { - description = "Spam Assassin Server"; + description = "SpamAssassin Server"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + wants = [ "sa-update.service" ]; + after = [ + "network.target" + "sa-update.service" + ]; serviceConfig = { - ExecStart = "${pkgs.spamassassin}/bin/spamd ${optionalString cfg.debug "-D"} --username=spamd --groupname=spamd --virtual-config-dir=/var/lib/spamassassin/user-%u --allow-tell --pidfile=/run/spamd.pid"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + User = "spamd"; + Group = "spamd"; + ExecStart = "+${pkgs.spamassassin}/bin/spamd ${optionalString cfg.debug "-D"} --username=spamd --groupname=spamd --virtual-config-dir=%S/spamassassin/user-%u --allow-tell --pidfile=/run/spamd.pid"; + ExecReload = "+${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + StateDirectory = "spamassassin"; }; - - # 0 and 1 no error, exitcode > 1 means error: - # https://spamassassin.apache.org/full/3.1.x/doc/sa-update.html#exit_codes - preStart = '' - echo "Recreating '/var/lib/spamasassin' with creating '3.004001' (or similar) and 'sa-update-keys'" - mkdir -p /var/lib/spamassassin - chown spamd:spamd /var/lib/spamassassin -R - set +e - ${pkgs.su}/bin/su -s "${pkgs.bash}/bin/bash" -c "${pkgs.spamassassin}/bin/sa-update --gpghomedir=/var/lib/spamassassin/sa-update-keys/" spamd - v=$? - set -e - if [ $v -gt 1 ]; then - echo "sa-update execution error" - exit $v - fi - chown spamd:spamd /var/lib/spamassassin -R - ''; }; }; } diff --git a/nixos/modules/services/misc/podgrab.nix b/nixos/modules/services/misc/podgrab.nix new file mode 100644 index 00000000000..7077408b794 --- /dev/null +++ b/nixos/modules/services/misc/podgrab.nix @@ -0,0 +1,50 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.podgrab; +in +{ + options.services.podgrab = with lib; { + enable = mkEnableOption "Podgrab, a self-hosted podcast manager"; + + passwordFile = mkOption { + type = with types; nullOr str; + default = null; + example = "/run/secrets/password.env"; + description = '' + The path to a file containing the PASSWORD environment variable + definition for Podgrab's authentification. + ''; + }; + + port = mkOption { + type = types.port; + default = 8080; + example = 4242; + description = "The port on which Podgrab will listen for incoming HTTP traffic."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.podgrab = { + description = "Podgrab podcast manager"; + wantedBy = [ "multi-user.target" ]; + environment = { + CONFIG = "/var/lib/podgrab/config"; + DATA = "/var/lib/podgrab/data"; + GIN_MODE = "release"; + PORT = toString cfg.port; + }; + serviceConfig = { + DynamicUser = true; + EnvironmentFile = lib.optional (cfg.passwordFile != null) [ + cfg.passwordFile + ]; + ExecStart = "${pkgs.podgrab}/bin/podgrab"; + WorkingDirectory = "${pkgs.podgrab}/share"; + StateDirectory = [ "podgrab/config" "podgrab/data" ]; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ ambroisie ]; +} diff --git a/nixos/modules/services/networking/babeld.nix b/nixos/modules/services/networking/babeld.nix index e16e56121c4..97dca002a00 100644 --- a/nixos/modules/services/networking/babeld.nix +++ b/nixos/modules/services/networking/babeld.nix @@ -19,7 +19,10 @@ let "interface ${name} ${paramsString interface}\n"; configFile = with cfg; pkgs.writeText "babeld.conf" ( - (optionalString (cfg.interfaceDefaults != null) '' + '' + skip-kernel-setup true + '' + + (optionalString (cfg.interfaceDefaults != null) '' default ${paramsString cfg.interfaceDefaults} '') + (concatMapStrings interfaceConfig (attrNames cfg.interfaces)) @@ -84,13 +87,22 @@ in config = mkIf config.services.babeld.enable { + boot.kernel.sysctl = { + "net.ipv6.conf.all.forwarding" = 1; + "net.ipv6.conf.all.accept_redirects" = 0; + "net.ipv4.conf.all.forwarding" = 1; + "net.ipv4.conf.all.rp_filter" = 0; + } // lib.mapAttrs' (ifname: _: lib.nameValuePair "net.ipv4.conf.${ifname}.rp_filter" (lib.mkDefault 0)) config.services.babeld.interfaces; + systemd.services.babeld = { description = "Babel routing daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile} -I /run/babeld/babeld.pid -S /var/lib/babeld/state"; + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; + DynamicUser = true; IPAddressAllow = [ "fe80::/64" "ff00::/8" "::1/128" "127.0.0.0/8" ]; IPAddressDeny = "any"; LockPersonality = true; @@ -98,7 +110,7 @@ in MemoryDenyWriteExecute = true; ProtectSystem = "strict"; ProtectClock = true; - ProtectKernelTunables = false; # Couldn't write sysctl: Read-only file system + ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; diff --git a/nixos/modules/services/networking/iscsi/initiator.nix b/nixos/modules/services/networking/iscsi/initiator.nix new file mode 100644 index 00000000000..cbc919a2f76 --- /dev/null +++ b/nixos/modules/services/networking/iscsi/initiator.nix @@ -0,0 +1,84 @@ +{ config, lib, pkgs, ... }: with lib; +let + cfg = config.services.openiscsi; +in +{ + options.services.openiscsi = with types; { + enable = mkEnableOption "the openiscsi iscsi daemon"; + enableAutoLoginOut = mkEnableOption '' + automatic login and logout of all automatic targets. + You probably do not want this. + ''; + discoverPortal = mkOption { + type = nullOr str; + default = null; + description = "Portal to discover targets on"; + }; + name = mkOption { + type = str; + description = "Name of this iscsi initiator"; + example = "iqn.2020-08.org.linux-iscsi.initiatorhost:example"; + }; + package = mkOption { + type = package; + description = "openiscsi package to use"; + default = pkgs.openiscsi; + defaultText = "pkgs.openiscsi"; + }; + + extraConfig = mkOption { + type = str; + default = ""; + description = "Lines to append to default iscsid.conf"; + }; + + extraConfigFile = mkOption { + description = '' + Append an additional file's contents to /etc/iscsid.conf. Use a non-store path + and store passwords in this file. + ''; + default = null; + type = nullOr str; + }; + }; + + config = mkIf cfg.enable { + environment.etc."iscsi/iscsid.conf.fragment".source = pkgs.runCommand "iscsid.conf" {} '' + cat "${cfg.package}/etc/iscsi/iscsid.conf" > $out + cat << 'EOF' >> $out + ${cfg.extraConfig} + ${optionalString cfg.enableAutoLoginOut "node.startup = automatic"} + EOF + ''; + environment.etc."iscsi/initiatorname.iscsi".text = "InitiatorName=${cfg.name}"; + + system.activationScripts.iscsid = let + extraCfgDumper = optionalString (cfg.extraConfigFile != null) '' + if [ -f "${cfg.extraConfigFile}" ]; then + printf "\n# The following is from ${cfg.extraConfigFile}:\n" + cat "${cfg.extraConfigFile}" + else + echo "Warning: services.openiscsi.extraConfigFile ${cfg.extraConfigFile} does not exist!" >&2 + fi + ''; + in '' + ( + cat ${config.environment.etc."iscsi/iscsid.conf.fragment".source} + ${extraCfgDumper} + ) > /etc/iscsi/iscsid.conf + ''; + + systemd.packages = [ cfg.package ]; + + systemd.services."iscsid".wantedBy = [ "multi-user.target" ]; + systemd.sockets."iscsid".wantedBy = [ "sockets.target" ]; + + systemd.services."iscsi" = mkIf cfg.enableAutoLoginOut { + wantedBy = [ "remote-fs.target" ]; + serviceConfig.ExecStartPre = mkIf (cfg.discoverPortal != null) "${cfg.package}/bin/iscsiadm --mode discoverydb --type sendtargets --portal ${escapeShellArg cfg.discoverPortal} --discover"; + }; + + environment.systemPackages = [ cfg.package ]; + boot.kernelModules = [ "iscsi_tcp" ]; + }; +} diff --git a/nixos/modules/services/networking/iscsi/root-initiator.nix b/nixos/modules/services/networking/iscsi/root-initiator.nix new file mode 100644 index 00000000000..3274878c4fa --- /dev/null +++ b/nixos/modules/services/networking/iscsi/root-initiator.nix @@ -0,0 +1,181 @@ +{ config, lib, pkgs, ... }: with lib; +let + cfg = config.boot.iscsi-initiator; +in +{ + # If you're booting entirely off another machine you may want to add + # this snippet to always boot the latest "system" version. It is not + # enabled by default in case you have an initrd on a local disk: + # + # boot.initrd.postMountCommands = '' + # ln -sfn /nix/var/nix/profiles/system/init /mnt-root/init + # stage2Init=/init + # ''; + # + # Note: Theoretically you might want to connect to multiple portals and + # log in to multiple targets, however the authors of this module so far + # don't have the need or expertise to reasonably implement it. Also, + # consider carefully before making your boot chain depend on multiple + # machines to be up. + options.boot.iscsi-initiator = with types; { + name = mkOption { + description = '' + Name of the iSCSI initiator to boot from. Note, booting from iscsi + requires networkd based networking. + ''; + default = null; + example = "iqn.2020-08.org.linux-iscsi.initiatorhost:example"; + type = nullOr str; + }; + + discoverPortal = mkOption { + description = '' + iSCSI portal to boot from. + ''; + default = null; + example = "192.168.1.1:3260"; + type = nullOr str; + }; + + target = mkOption { + description = '' + Name of the iSCSI target to boot from. + ''; + default = null; + example = "iqn.2020-08.org.linux-iscsi.targethost:example"; + type = nullOr str; + }; + + logLevel = mkOption { + description = '' + Higher numbers elicits more logs. + ''; + default = 1; + example = 8; + type = int; + }; + + loginAll = mkOption { + description = '' + Do not log into a specific target on the portal, but to all that we discover. + This overrides setting target. + ''; + type = bool; + default = false; + }; + + extraConfig = mkOption { + description = "Extra lines to append to /etc/iscsid.conf"; + default = null; + type = nullOr lines; + }; + + extraConfigFile = mkOption { + description = '' + Append an additional file's contents to `/etc/iscsid.conf`. Use a non-store path + and store passwords in this file. Note: the file specified here must be available + in the initrd, see: `boot.initrd.secrets`. + ''; + default = null; + type = nullOr str; + }; + }; + + config = mkIf (cfg.name != null) { + # The "scripted" networking configuration (ie: non-networkd) + # doesn't properly order the start and stop of the interfaces, and the + # network interfaces are torn down before unmounting disks. Since this + # module is specifically for very-early-boot network mounts, we need + # the network to stay on. + # + # We could probably fix the scripted options to properly order, but I'm + # not inclined to invest that time today. Hopefully this gets users far + # enough along and they can just use networkd. + networking.useNetworkd = true; + networking.useDHCP = false; # Required to set useNetworkd = true + + boot.initrd = { + network.enable = true; + + # By default, the stage-1 disables the network and resets the interfaces + # on startup. Since our startup disks are on the network, we can't let + # the network not work. + network.flushBeforeStage2 = false; + + kernelModules = [ "iscsi_tcp" ]; + + extraUtilsCommands = '' + copy_bin_and_libs ${pkgs.openiscsi}/bin/iscsid + copy_bin_and_libs ${pkgs.openiscsi}/bin/iscsiadm + ${optionalString (!config.boot.initrd.network.ssh.enable) "cp -pv ${pkgs.glibc.out}/lib/libnss_files.so.* $out/lib"} + + mkdir -p $out/etc/iscsi + cp ${config.environment.etc.hosts.source} $out/etc/hosts + cp ${pkgs.openiscsi}/etc/iscsi/iscsid.conf $out/etc/iscsi/iscsid.fragment.conf + chmod +w $out/etc/iscsi/iscsid.fragment.conf + cat << 'EOF' >> $out/etc/iscsi/iscsid.fragment.conf + ${optionalString (cfg.extraConfig != null) cfg.extraConfig} + EOF + ''; + + extraUtilsCommandsTest = '' + $out/bin/iscsiadm --version + ''; + + preLVMCommands = let + extraCfgDumper = optionalString (cfg.extraConfigFile != null) '' + if [ -f "${cfg.extraConfigFile}" ]; then + printf "\n# The following is from ${cfg.extraConfigFile}:\n" + cat "${cfg.extraConfigFile}" + else + echo "Warning: boot.iscsi-initiator.extraConfigFile ${cfg.extraConfigFile} does not exist!" >&2 + fi + ''; + in '' + ${optionalString (!config.boot.initrd.network.ssh.enable) '' + # stolen from initrd-ssh.nix + echo 'root:x:0:0:root:/root:/bin/ash' > /etc/passwd + echo 'passwd: files' > /etc/nsswitch.conf + ''} + + cp -f $extraUtils/etc/hosts /etc/hosts + + mkdir -p /etc/iscsi /run/lock/iscsi + echo "InitiatorName=${cfg.name}" > /etc/iscsi/initiatorname.iscsi + + ( + cat "$extraUtils/etc/iscsi/iscsid.fragment.conf" + printf "\n" + ${optionalString cfg.loginAll ''echo "node.startup = automatic"''} + ${extraCfgDumper} + ) > /etc/iscsi/iscsid.conf + + iscsid --foreground --no-pid-file --debug ${toString cfg.logLevel} & + iscsiadm --mode discoverydb \ + --type sendtargets \ + --discover \ + --portal ${escapeShellArg cfg.discoverPortal} \ + --debug ${toString cfg.logLevel} + + ${if cfg.loginAll then '' + iscsiadm --mode node --loginall all + '' else '' + iscsiadm --mode node --targetname ${escapeShellArg cfg.target} --login + ''} + pkill -9 iscsid + ''; + }; + + services.openiscsi = { + enable = true; + inherit (cfg) name; + }; + + assertions = [ + { + assertion = cfg.loginAll -> cfg.target == null; + message = "iSCSI target name is set while login on all portals is enabled."; + } + ]; + }; +} diff --git a/nixos/modules/services/networking/iscsi/target.nix b/nixos/modules/services/networking/iscsi/target.nix new file mode 100644 index 00000000000..8a10e7d346a --- /dev/null +++ b/nixos/modules/services/networking/iscsi/target.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.target; +in +{ + ###### interface + options = { + services.target = with types; { + enable = mkEnableOption "the kernel's LIO iscsi target"; + + config = mkOption { + type = attrs; + default = {}; + description = '' + Content of /etc/target/saveconfig.json + This file is normally read and written by targetcli + ''; + }; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + environment.etc."target/saveconfig.json" = { + text = builtins.toJSON cfg.config; + mode = "0600"; + }; + + environment.systemPackages = with pkgs; [ targetcli ]; + + boot.kernelModules = [ "configfs" "target_core_mod" "iscsi_target_mod" ]; + + systemd.services.iscsi-target = { + enable = true; + after = [ "network.target" "local-fs.target" ]; + requires = [ "sys-kernel-config.mount" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.python3.pkgs.rtslib}/bin/targetctl restore"; + ExecStop = "${pkgs.python3.pkgs.rtslib}/bin/targetctl clear"; + RemainAfterExit = "yes"; + }; + }; + + systemd.tmpfiles.rules = [ + "d /etc/target 0700 root root - -" + ]; + }; +} diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 51c2f3febdc..18e1263fef5 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -887,6 +887,7 @@ in users.users = optionalAttrs (cfg.user == "nginx") { nginx = { group = cfg.group; + isSystemUser = true; uid = config.ids.uids.nginx; }; }; diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index 2ea191426ce..63e01dd054a 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -236,9 +236,12 @@ def main() -> None: gens += get_generations(profile) remove_old_entries(gens) for gen in gens: - write_entry(*gen, machine_id) - if os.readlink(system_dir(*gen)) == args.default_config: - write_loader_conf(*gen) + try: + write_entry(*gen, machine_id) + if os.readlink(system_dir(*gen)) == args.default_config: + write_loader_conf(*gen) + except OSError as e: + print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr) memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf" if os.path.exists(memtest_entry_file): diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix index f15d5875841..7a1f11ce40d 100644 --- a/nixos/modules/virtualisation/nixos-containers.nix +++ b/nixos/modules/virtualisation/nixos-containers.nix @@ -439,21 +439,16 @@ in default = false; description = '' Whether this NixOS machine is a lightweight container running - in another NixOS system. If set to true, support for nested - containers is disabled by default, but can be reenabled by - setting <option>boot.enableContainers</option> to true. + in another NixOS system. ''; }; boot.enableContainers = mkOption { type = types.bool; - default = !config.boot.isContainer; + default = true; description = '' Whether to enable support for NixOS containers. Defaults to true - (at no cost if containers are not actually used), but only if the - system is not itself a lightweight container of a host. - To enable support for nested containers, this option has to be - explicitly set to true (in the outer container). + (at no cost if containers are not actually used). ''; }; diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index 24df1b6ad7c..fea43727f2f 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -161,9 +161,6 @@ in environment.systemPackages = [ cfg.package ]; - # Make sure Domain 0 gets the required configuration - #boot.kernelPackages = pkgs.boot.kernelPackages.override { features={xen_dom0=true;}; }; - boot.kernelModules = [ "xen-evtchn" "xen-gntdev" "xen-gntalloc" "xen-blkback" "xen-netback" "xen-pciback" "evtchn" "gntdev" "netbk" "blkbk" "xen-scsibk" diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index a6a1c5619b0..3aefa82301c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -75,6 +75,7 @@ in containers-ip = handleTest ./containers-ip.nix {}; containers-macvlans = handleTest ./containers-macvlans.nix {}; containers-names = handleTest ./containers-names.nix {}; + containers-nested = handleTest ./containers-nested.nix {}; containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {}; containers-portforward = handleTest ./containers-portforward.nix {}; containers-reloadable = handleTest ./containers-reloadable.nix {}; @@ -185,6 +186,7 @@ in iodine = handleTest ./iodine.nix {}; ipfs = handleTest ./ipfs.nix {}; ipv6 = handleTest ./ipv6.nix {}; + iscsi-root = handleTest ./iscsi-root.nix {}; jackett = handleTest ./jackett.nix {}; jellyfin = handleTest ./jellyfin.nix {}; jenkins = handleTest ./jenkins.nix {}; @@ -322,6 +324,7 @@ in pleroma = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./pleroma.nix {}; plikd = handleTest ./plikd.nix {}; plotinus = handleTest ./plotinus.nix {}; + podgrab = handleTest ./podgrab.nix {}; podman = handleTestOn ["x86_64-linux"] ./podman.nix {}; pomerium = handleTestOn ["x86_64-linux"] ./pomerium.nix {}; postfix = handleTest ./postfix.nix {}; diff --git a/nixos/tests/babeld.nix b/nixos/tests/babeld.nix index 5817ea4ce14..d4df6f86d08 100644 --- a/nixos/tests/babeld.nix +++ b/nixos/tests/babeld.nix @@ -25,9 +25,6 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : { { virtualisation.vlans = [ 10 20 ]; - boot.kernel.sysctl."net.ipv4.conf.all.forwarding" = 1; - boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; - networking = { useDHCP = false; firewall.enable = false; @@ -74,9 +71,6 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : { { virtualisation.vlans = [ 20 30 ]; - boot.kernel.sysctl."net.ipv4.conf.all.forwarding" = 1; - boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; - networking = { useDHCP = false; firewall.enable = false; diff --git a/nixos/tests/containers-nested.nix b/nixos/tests/containers-nested.nix new file mode 100644 index 00000000000..a653361494f --- /dev/null +++ b/nixos/tests/containers-nested.nix @@ -0,0 +1,30 @@ +# Test for NixOS' container nesting. + +import ./make-test-python.nix ({ pkgs, ... }: { + name = "nested"; + + meta = with pkgs.lib.maintainers; { maintainers = [ sorki ]; }; + + machine = { lib, ... }: + let + makeNested = subConf: { + containers.nested = { + autoStart = true; + privateNetwork = true; + config = subConf; + }; + }; + in makeNested (makeNested { }); + + testScript = '' + machine.start() + machine.wait_for_unit("container@nested.service") + machine.succeed("systemd-run --pty --machine=nested -- machinectl list | grep nested") + print( + machine.succeed( + "systemd-run --pty --machine=nested -- systemd-run --pty --machine=nested -- systemctl status" + ) + ) + ''; +}) + diff --git a/nixos/tests/iscsi-root.nix b/nixos/tests/iscsi-root.nix new file mode 100644 index 00000000000..bda51d2c2e4 --- /dev/null +++ b/nixos/tests/iscsi-root.nix @@ -0,0 +1,161 @@ +import ./make-test-python.nix ( + { pkgs, lib, ... }: + let + initiatorName = "iqn.2020-08.org.linux-iscsi.initiatorhost:example"; + targetName = "iqn.2003-01.org.linux-iscsi.target.x8664:sn.acf8fd9c23af"; + in + { + name = "iscsi"; + meta = { + maintainers = pkgs.lib.teams.deshaw.members + ++ (with pkgs.lib.maintainers; [ ajs124 ]); + }; + + nodes = { + target = { config, pkgs, lib, ... }: { + services.target = { + enable = true; + config = { + fabric_modules = []; + storage_objects = [ + { + dev = "/dev/vdb"; + name = "test"; + plugin = "block"; + write_back = true; + wwn = "92b17c3f-6b40-4168-b082-ceeb7b495522"; + } + ]; + targets = [ + { + fabric = "iscsi"; + tpgs = [ + { + enable = true; + attributes = { + authentication = 0; + generate_node_acls = 1; + }; + luns = [ + { + alias = "94dfe06967"; + alua_tg_pt_gp_name = "default_tg_pt_gp"; + index = 0; + storage_object = "/backstores/block/test"; + } + ]; + node_acls = [ + { + mapped_luns = [ + { + alias = "d42f5bdf8a"; + index = 0; + tpg_lun = 0; + write_protect = false; + } + ]; + node_wwn = initiatorName; + } + ]; + portals = [ + { + ip_address = "0.0.0.0"; + iser = false; + offload = false; + port = 3260; + } + ]; + tag = 1; + } + ]; + wwn = targetName; + } + ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ 3260 ]; + networking.firewall.allowedUDPPorts = [ 3260 ]; + + virtualisation.memorySize = 2048; + virtualisation.emptyDiskImages = [ 2048 ]; + }; + + initiatorAuto = { nodes, config, pkgs, ... }: { + services.openiscsi = { + enable = true; + enableAutoLoginOut = true; + discoverPortal = "target"; + name = initiatorName; + }; + + environment.systemPackages = with pkgs; [ + xfsprogs + ]; + + system.extraDependencies = [ nodes.initiatorRootDisk.config.system.build.toplevel ]; + + nix.binaryCaches = lib.mkForce []; + nix.extraOptions = '' + hashed-mirrors = + connect-timeout = 1 + ''; + }; + + initiatorRootDisk = { config, pkgs, modulesPath, lib, ... }: { + boot.loader.grub.enable = false; + boot.kernelParams = lib.mkOverride 5 ( + [ + "boot.shell_on_fail" + "console=tty1" + "ip=${config.networking.primaryIPAddress}:::255.255.255.0::ens9:none" + ] + ); + + # defaults to true, puts some code in the initrd that tries to mount an overlayfs on /nix/store + virtualisation.writableStore = false; + + fileSystems = lib.mkOverride 5 { + "/" = { + fsType = "xfs"; + device = "/dev/sda"; + options = [ "_netdev" ]; + }; + }; + + boot.iscsi-initiator = { + discoverPortal = "target"; + name = initiatorName; + target = targetName; + }; + }; + }; + + testScript = { nodes, ... }: '' + target.start() + target.wait_for_unit("iscsi-target.service") + + initiatorAuto.start() + + initiatorAuto.wait_for_unit("iscsid.service") + initiatorAuto.wait_for_unit("iscsi.service") + initiatorAuto.get_unit_info("iscsi") + + initiatorAuto.succeed("set -x; while ! test -e /dev/sda; do sleep 1; done") + + initiatorAuto.succeed("mkfs.xfs /dev/sda") + initiatorAuto.succeed("mkdir /mnt && mount /dev/sda /mnt") + initiatorAuto.succeed( + "nixos-install --no-bootloader --no-root-passwd --system ${nodes.initiatorRootDisk.config.system.build.toplevel}" + ) + initiatorAuto.succeed("umount /mnt && rmdir /mnt") + initiatorAuto.shutdown() + + initiatorRootDisk.start() + initiatorRootDisk.wait_for_unit("multi-user.target") + initiatorRootDisk.wait_for_unit("iscsid") + initiatorRootDisk.succeed("touch test") + initiatorRootDisk.shutdown() + ''; + } +) diff --git a/nixos/tests/podgrab.nix b/nixos/tests/podgrab.nix new file mode 100644 index 00000000000..e927e25fea5 --- /dev/null +++ b/nixos/tests/podgrab.nix @@ -0,0 +1,34 @@ +let + defaultPort = 8080; + customPort = 4242; +in +import ./make-test-python.nix ({ pkgs, ... }: { + name = "podgrab"; + + nodes = { + default = { ... }: { + services.podgrab.enable = true; + }; + + customized = { ... }: { + services.podgrab = { + enable = true; + port = customPort; + }; + }; + }; + + testScript = '' + start_all() + + default.wait_for_unit("podgrab") + default.wait_for_open_port("${toString defaultPort}") + default.succeed("curl --fail http://localhost:${toString defaultPort}") + + customized.wait_for_unit("podgrab") + customized.wait_for_open_port("${toString customPort}") + customized.succeed("curl --fail http://localhost:${toString customPort}") + ''; + + meta.maintainers = with pkgs.lib.maintainers; [ ambroisie ]; +}) diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index 62c0080dd51..9aa430c25a4 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -118,6 +118,8 @@ let metricProvider = { services.bird2.enable = true; services.bird2.config = '' + router id 127.0.0.1; + protocol kernel MyObviousTestString { ipv4 { import all; @@ -132,7 +134,9 @@ let exporterTest = '' wait_for_unit("prometheus-bird-exporter.service") wait_for_open_port(9324) - succeed("curl -sSf http://localhost:9324/metrics | grep -q 'MyObviousTestString'") + wait_until_succeeds( + "curl -sSf http://localhost:9324/metrics | grep -q 'MyObviousTestString'" + ) ''; }; |