diff options
Diffstat (limited to 'nixos')
77 files changed, 2567 insertions, 1109 deletions
diff --git a/nixos/doc/manual/development/development.xml b/nixos/doc/manual/development/development.xml index 747159c4427..2983c76c770 100644 --- a/nixos/doc/manual/development/development.xml +++ b/nixos/doc/manual/development/development.xml @@ -15,6 +15,7 @@ NixOS.</para> <xi:include href="writing-modules.xml" /> <xi:include href="building-parts.xml" /> <xi:include href="building-nixos.xml" /> +<xi:include href="nixos-tests.xml" /> <xi:include href="testing-installer.xml" /> </part> diff --git a/nixos/doc/manual/development/nixos-tests.xml b/nixos/doc/manual/development/nixos-tests.xml index a98da993330..c09c41ea3bd 100644 --- a/nixos/doc/manual/development/nixos-tests.xml +++ b/nixos/doc/manual/development/nixos-tests.xml @@ -15,5 +15,6 @@ required for the test.</para> <xi:include href="writing-nixos-tests.xml" /> <xi:include href="running-nixos-tests.xml" /> +<xi:include href="running-nixos-tests-interactively.xml" /> -</chapter> \ No newline at end of file +</chapter> diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.xml b/nixos/doc/manual/development/running-nixos-tests-interactively.xml new file mode 100644 index 00000000000..e4749077781 --- /dev/null +++ b/nixos/doc/manual/development/running-nixos-tests-interactively.xml @@ -0,0 +1,43 @@ +<section xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="sec-running-nixos-tests"> +<title>Running Tests interactively</title> + +<para>The test itself can be run interactively. This is +particularly useful when developing or debugging a test: + +<screen> +$ nix-build nixos/tests/login.nix -A driver +$ ./result/bin/nixos-test-driver +starting VDE switch for network 1 +> +</screen> + +You can then take any Perl statement, e.g. + +<screen> +> startAll +> testScript +> $machine->succeed("touch /tmp/foo") +</screen> + +The function <command>testScript</command> executes the entire test +script and drops you back into the test driver command line upon its +completion. This allows you to inspect the state of the VMs after the +test (e.g. to debug the test script).</para> + +<para>To just start and experiment with the VMs, run: + +<screen> +$ nix-build nixos/tests/login.nix -A driver +$ ./result/bin/nixos-run-vms +</screen> + +The script <command>nixos-run-vms</command> starts the virtual +machines defined by test. The root file system of the VMs is created +on the fly and kept across VM restarts in +<filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>.</para> + +</section> diff --git a/nixos/doc/manual/development/running-nixos-tests.xml b/nixos/doc/manual/development/running-nixos-tests.xml index 156dcd205a5..908c0a66a32 100644 --- a/nixos/doc/manual/development/running-nixos-tests.xml +++ b/nixos/doc/manual/development/running-nixos-tests.xml @@ -2,7 +2,7 @@ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" - xml:id="sec-running-nixos-tests"> + xml:id="sec-running-nixos-tests-interactively"> <title>Running Tests</title> @@ -38,42 +38,4 @@ $ firefox result/log.html </screen> </para> - -<title>Running Tests interactively</title> - -<para>The test itself can be run interactively. This is -particularly useful when developing or debugging a test: - -<screen> -$ nix-build nixos/tests/login.nix -A driver -$ ./result/bin/nixos-test-driver -starting VDE switch for network 1 -> -</screen> - -You can then take any Perl statement, e.g. - -<screen> -> startAll -> testScript -> $machine->succeed("touch /tmp/foo") -</screen> - -The function <command>testScript</command> executes the entire test -script and drops you back into the test driver command line upon its -completion. This allows you to inspect the state of the VMs after the -test (e.g. to debug the test script).</para> - -<para>To just start and experiment with the VMs, run: - -<screen> -$ nix-build nixos/tests/login.nix -A driver -$ ./result/bin/nixos-run-vms -</screen> - -The script <command>nixos-run-vms</command> starts the virtual -machines defined by test. The root file system of the VMs is created -on the fly and kept across VM restarts in -<filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>.</para> - </section> diff --git a/nixos/doc/manual/release-notes/rl-unstable.xml b/nixos/doc/manual/release-notes/rl-unstable.xml index 34ffe1d6d32..cdbd074e782 100644 --- a/nixos/doc/manual/release-notes/rl-unstable.xml +++ b/nixos/doc/manual/release-notes/rl-unstable.xml @@ -35,6 +35,20 @@ and old <literal>steam</literal> package -- to <literal>steamOriginal</literal>. was accordingly renamed to <literal>bomi</literal> </para></listitem> +<listitem> + <para> + The default <literal>NIX_PATH</literal> for NixOS now includes + <literal>/nix/var/nix/profiles/per-user/root/channels</literal>, so it's + easy to add custom channels. + </para> + <para> + Moreover, whenever a <command>nixos-rebuild <action> + --upgrade</command> is issued, every channel that includes a file + called <filename>.update-on-nixos-rebuild</filename> will be upgraded + alongside of the <literal>nixos</literal> channel. + </para> +</listitem> + </itemizedlist> </para> diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix index d3f24e280c7..f2aacf9b292 100644 --- a/nixos/modules/config/i18n.nix +++ b/nixos/modules/config/i18n.nix @@ -74,14 +74,17 @@ in config = { - environment.systemPackages = [ glibcLocales ]; + environment.systemPackages = + optional (config.i18n.supportedLocales != []) glibcLocales; environment.sessionVariables = { LANG = config.i18n.defaultLocale; LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; }; - systemd.globalEnvironment.LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; + systemd.globalEnvironment = mkIf (config.i18n.supportedLocales != []) { + LOCALE_ARCHIVE = "${glibcLocales}/lib/locale/locale-archive"; + }; # ‘/etc/locale.conf’ is used by systemd. environment.etc = singleton diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index f3e86bfd201..d22f9ebd1df 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -23,7 +23,6 @@ let pkgs.cpio pkgs.curl pkgs.diffutils - pkgs.eject # HAL depends on it anyway pkgs.findutils pkgs.gawk pkgs.glibc # for ldd, getent @@ -40,15 +39,12 @@ let pkgs.ncurses pkgs.netcat pkgs.openssh - pkgs.pciutils pkgs.perl pkgs.procps pkgs.rsync pkgs.strace - pkgs.sysvtools pkgs.su pkgs.time - pkgs.usbutils pkgs.utillinux extraManpages ]; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index 4896eee2908..446d79ce220 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -45,12 +45,6 @@ with lib; # Get a console as soon as the initrd loads fbcon on EFI boot. boot.initrd.kernelModules = [ "fbcon" ]; - # Add support for cow filesystems and their utilities - boot.supportedFilesystems = [ "zfs" "btrfs" ]; - - # Configure host id for ZFS to work - networking.hostId = "8425e349"; - # Allow the user to log in as root without a password. users.extraUsers.root.initialHashedPassword = ""; } diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index 14ae3daace0..097631eda9c 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -45,7 +45,9 @@ while [ "$#" -gt 0 ]; do ;; --chroot) runChroot=1 - chrootCommand=("$@") + if [[ "$@" != "" ]]; then + chrootCommand=("$@") + fi break ;; --help) @@ -254,8 +256,14 @@ NIXOS_INSTALL_GRUB=1 chroot $mountPoint \ chroot $mountPoint /nix/var/nix/profiles/system/activate +# Some systems may not be prepared to use NixOS' paths. +export PATH=/run/current-system/sw/bin:/run/current-system/sw/sbin:$PATH +export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixpkgs=/etc/nixos/nixpkgs +export NIX_PATH=$NIX_PATH:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels + + # Ask the user to set a root password. -if [ "$(chroot $mountPoint nix-instantiate --eval '<nixos>' -A config.users.mutableUsers)" = true ] && [ -t 0 ] ; then +if [ "$(chroot $mountPoint nix-instantiate --eval '<nixpkgs/nixos>' -A config.users.mutableUsers)" = true ] && [ -t 1 ] ; then echo "setting root password..." chroot $mountPoint /var/setuid-wrappers/passwd fi diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh index 1d6df8cb3f7..ccafa30856c 100644 --- a/nixos/modules/installer/tools/nixos-rebuild.sh +++ b/nixos/modules/installer/tools/nixos-rebuild.sh @@ -96,6 +96,14 @@ fi # If ‘--upgrade’ is given, run ‘nix-channel --update nixos’. if [ -n "$upgrade" -a -z "$_NIXOS_REBUILD_REEXEC" ]; then nix-channel --update nixos + + # If there are other channels that contain a file called + # ".update-on-nixos-rebuild", update them as well. + for channelpath in /nix/var/nix/profiles/per-user/root/channels/*; do + if [ -e "$channelpath/.update-on-nixos-rebuild" ]; then + nix-channel --update "$(basename "$channelpath")" + fi + done fi # Make sure that we use the Nix package we depend on, not something diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index c2523a3cc32..0319c5688fb 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -203,17 +203,20 @@ sddm = 175; tss = 176; memcached = 177; - nscd = 178; ntp = 179; zabbix = 180; redis = 181; - sshd = 182; unifi = 183; uptimed = 184; zope2 = 185; ripple-data-api = 186; mediatomb = 187; rdnssd = 188; + ihaskell = 189; + i2p = 190; + lambdabot = 191; + asterisk = 192; + plex = 193; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -394,17 +397,20 @@ sddm = 175; tss = 176; #memcached = 177; # unused - #nscd = 178; # unused #ntp = 179; # unused #zabbix = 180; # unused #redis = 181; # unused - #sshd = 182; # unused #unifi = 183; # unused #uptimed = 184; # unused #zope2 = 185; # unused #ripple-data-api = 186; #unused mediatomb = 187; #rdnssd = 188; # unused + ihaskell = 189; + i2p = 190; + lambdabot = 191; + #asterisk = 192; # unused + plex = 193; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 17717c5988d..61cc551f435 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -149,6 +149,7 @@ ./services/games/minecraft-server.nix ./services/games/minetest-server.nix ./services/hardware/acpid.nix + ./services/hardware/actkbd.nix ./services/hardware/amd-hybrid-graphics.nix ./services/hardware/bluetooth.nix ./services/hardware/freefall.nix @@ -193,6 +194,7 @@ ./services/misc/gitlab.nix ./services/misc/gitolite.nix ./services/misc/gpsd.nix + ./services/misc/ihaskell.nix ./services/misc/mediatomb.nix ./services/misc/mesos-master.nix ./services/misc/mesos-slave.nix @@ -202,6 +204,7 @@ ./services/misc/nix-ssh-serve.nix ./services/misc/parsoid.nix ./services/misc/phd.nix + ./services/misc/plex.nix ./services/misc/redmine.nix ./services/misc/rippled.nix ./services/misc/ripple-data-api.nix @@ -241,6 +244,7 @@ ./services/network-filesystems/yandex-disk.nix ./services/networking/aiccu.nix ./services/networking/amuled.nix + ./services/networking/asterisk.nix ./services/networking/atftpd.nix ./services/networking/avahi-daemon.nix ./services/networking/bind.nix @@ -268,10 +272,12 @@ ./services/networking/haproxy.nix ./services/networking/hostapd.nix ./services/networking/i2pd.nix + ./services/networking/i2p.nix ./services/networking/ifplugd.nix ./services/networking/iodined.nix ./services/networking/ircd-hybrid/default.nix ./services/networking/kippo.nix + ./services/networking/lambdabot.nix ./services/networking/mailpile.nix ./services/networking/minidlna.nix ./services/networking/mstpd.nix @@ -336,6 +342,7 @@ ./services/security/fprot.nix ./services/security/frandom.nix ./services/security/haveged.nix + ./services/security/hologram.nix ./services/security/munge.nix ./services/security/torify.nix ./services/security/tor.nix @@ -410,6 +417,9 @@ ./system/boot/stage-1.nix ./system/boot/stage-2.nix ./system/boot/systemd.nix + ./system/boot/networkd.nix + ./system/boot/resolved.nix + ./system/boot/timesyncd.nix ./system/boot/tmp.nix ./system/etc/etc.nix ./system/upstart/upstart.nix @@ -423,6 +433,7 @@ ./tasks/filesystems/f2fs.nix ./tasks/filesystems/jfs.nix ./tasks/filesystems/nfs.nix + ./tasks/filesystems/ntfs.nix ./tasks/filesystems/reiserfs.nix ./tasks/filesystems/unionfs-fuse.nix ./tasks/filesystems/vfat.nix diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 5211b905002..f6676fc3793 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -29,6 +29,8 @@ pkgs.hdparm pkgs.dmraid pkgs.smartmontools # for diagnosing hard disks + pkgs.pciutils + pkgs.usbutils # Tools to create / manipulate filesystems. pkgs.ntfsprogs # for resizing NTFS partitions @@ -50,6 +52,8 @@ ]; # Include support for various filesystems. - boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" ]; + boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "zfs" "ntfs" "cifs" ]; + # Configure host id for ZFS to work + networking.hostId = "8425e349"; } diff --git a/nixos/modules/profiles/container.nix b/nixos/modules/profiles/docker-container.nix index dd2e6579a93..df762b7ac58 100644 --- a/nixos/modules/profiles/container.nix +++ b/nixos/modules/profiles/docker-container.nix @@ -45,10 +45,6 @@ in { ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system ''; - # Disable some features that are not useful in a container. - sound.enable = mkDefault false; - services.udisks2.enable = mkDefault false; - # Install new init script system.activationScripts.installInitScript = '' ln -fs $systemConfig/init /init diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix index 5aab2a2954e..a41d17e5182 100644 --- a/nixos/modules/profiles/installation-device.nix +++ b/nixos/modules/profiles/installation-device.nix @@ -26,15 +26,14 @@ with lib; # Disable some other stuff we don't need. security.sudo.enable = false; - # Include only the en_US locale. This saves 75 MiB or so compared to - # the full glibcLocales package. - i18n.supportedLocales = ["en_US.UTF-8/UTF-8" "en_US/ISO-8859-1"]; + # Automatically log in at the virtual consoles. + services.mingetty.autologinUser = "root"; # Some more help text. services.mingetty.helpLine = '' - Log in as "root" with an empty password. ${ + The "root" account has an empty password. ${ optionalString config.services.xserver.enable "Type `start display-manager' to\nstart the graphical user interface."} ''; diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix index 5067622aaf1..69729923e03 100644 --- a/nixos/modules/profiles/minimal.nix +++ b/nixos/modules/profiles/minimal.nix @@ -3,6 +3,9 @@ { config, lib, pkgs, ... }: +with lib; + { - environment.noXlibs = true; + environment.noXlibs = mkDefault true; + i18n.supportedLocales = [ config.i18n.defaultLocale ]; } diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix index e0379a2c02a..dce757ceb62 100644 --- a/nixos/modules/programs/environment.nix +++ b/nixos/modules/programs/environment.nix @@ -28,6 +28,7 @@ in [ "/nix/var/nix/profiles/per-user/root/channels/nixos" "nixpkgs=/etc/nixos/nixpkgs" "nixos-config=/etc/nixos/configuration.nix" + "/nix/var/nix/profiles/per-user/root/channels" ]; }; diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index 895ecb122cb..566398d839f 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -100,8 +100,10 @@ in chgpasswd = { rootOK = true; }; }; - security.setuidPrograms = [ "passwd" "chfn" "su" "sg" "newgrp" - "newuidmap" "newgidmap" # new in shadow 4.2.x + security.setuidPrograms = [ "su" "chfn" ] + ++ lib.optionals config.users.mutableUsers + [ "passwd" "sg" "newgrp" + "newuidmap" "newgidmap" # new in shadow 4.2.x ]; }; diff --git a/nixos/modules/programs/shell.nix b/nixos/modules/programs/shell.nix index 80d40a7c708..d8845fd8f44 100644 --- a/nixos/modules/programs/shell.nix +++ b/nixos/modules/programs/shell.nix @@ -53,7 +53,7 @@ in # Set up a default Nix expression from which to install stuff. if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then rm -f $HOME/.nix-defexpr - mkdir $HOME/.nix-defexpr + mkdir -p $HOME/.nix-defexpr if [ "$USER" != root ]; then ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root fi diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index d90cffbd967..fc83e7ed590 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -135,7 +135,7 @@ in zipModules ([] ++ obsolete [ "services" "mysql55" ] [ "services" "mysql" ] -++ obsolete [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ] +++ alias [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ] # XBMC ++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ] diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix index 35974f6890e..b116d8bfef2 100644 --- a/nixos/modules/security/grsecurity.nix +++ b/nixos/modules/security/grsecurity.nix @@ -112,9 +112,6 @@ in <literal>kernel.grsecurity.grsec_lock</literal> to non-zero as soon as all sysctl options are set. *THIS IS EXTREMELY IMPORTANT*! - - If disabled, this also turns off the - <literal>systemd-sysctl</literal> service. ''; }; @@ -229,11 +226,8 @@ in kernel 3.19) to continue. ''; } - { assertion = (cfg.stable -> !cfg.testing) || (cfg.testing -> !cfg.stable); - message = '' - You must select either the stable or testing patch, not - both. - ''; + { assertion = !(cfg.stable && cfg.testing); + message = "Select either one of the stable or testing patch"; } { assertion = (cfg.config.restrictProc -> !cfg.config.restrictProcWithGroup) || (cfg.config.restrictProcWithGroup -> !cfg.config.restrictProc); @@ -282,22 +276,21 @@ in # }; # }; - system.activationScripts.grsec = - '' - mkdir -p /etc/grsec - if [ ! -f /etc/grsec/learn_config ]; then - cp ${pkgs.gradm}/etc/grsec/learn_config /etc/grsec - fi - if [ ! -f /etc/grsec/policy ]; then - cp ${pkgs.gradm}/etc/grsec/policy /etc/grsec - fi - chmod -R 0600 /etc/grsec - ''; + system.activationScripts = lib.optionalAttrs (!cfg.config.disableRBAC) { grsec = '' + mkdir -p /etc/grsec + if [ ! -f /etc/grsec/learn_config ]; then + cp ${pkgs.gradm}/etc/grsec/learn_config /etc/grsec + fi + if [ ! -f /etc/grsec/policy ]; then + cp ${pkgs.gradm}/etc/grsec/policy /etc/grsec + fi + chmod -R 0600 /etc/grsec + ''; }; # Enable AppArmor, gradm udev rules, and utilities security.apparmor.enable = true; boot.kernelPackages = customGrsecPkg; - services.udev.packages = [ pkgs.gradm ]; - environment.systemPackages = [ pkgs.gradm pkgs.paxctl pkgs.pax-utils ]; + services.udev.packages = lib.optional (!cfg.config.disableRBAC) pkgs.gradm; + environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils ] ++ lib.optional (!cfg.config.disableRBAC) pkgs.gradm; }; } diff --git a/nixos/modules/services/audio/alsa.nix b/nixos/modules/services/audio/alsa.nix index 653c0ed5d70..c63f4dc8d7f 100644 --- a/nixos/modules/services/audio/alsa.nix +++ b/nixos/modules/services/audio/alsa.nix @@ -33,6 +33,16 @@ in ''; }; + enableMediaKeys = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable volume and capture control with keyboard media keys. + + Enabling this will turn on <option>services.actkbd</option>. + ''; + }; + extraConfig = mkOption { type = types.lines; default = ""; @@ -80,6 +90,23 @@ in }; }; + services.actkbd = mkIf config.sound.enableMediaKeys { + enable = true; + bindings = [ + # "Mute" media key + { keys = [ 113 ]; events = [ "key" ]; command = "${alsaUtils}/bin/amixer -q set Master toggle"; } + + # "Lower Volume" media key + { keys = [ 114 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master 1- unmute"; } + + # "Raise Volume" media key + { keys = [ 115 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master 1+ unmute"; } + + # "Mic Mute" media key + { keys = [ 190 ]; events = [ "key" ]; command = "${alsaUtils}/bin/amixer -q set Capture toggle"; } + ]; + }; + }; } diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix index d9b5bf7b5e6..06ba4b9b5ac 100644 --- a/nixos/modules/services/audio/mpd.nix +++ b/nixos/modules/services/audio/mpd.nix @@ -11,7 +11,7 @@ let mpdConf = pkgs.writeText "mpd.conf" '' music_directory "${cfg.musicDirectory}" playlist_directory "${cfg.dataDir}/playlists" - db_file "${cfg.dataDir}/tag_cache" + db_file "${cfg.dbFile}" state_file "${cfg.dataDir}/state" sticker_file "${cfg.dataDir}/sticker.sql" log_file "syslog" @@ -93,6 +93,14 @@ in { }; }; + + dbFile = mkOption { + type = types.str; + default = "${cfg.dataDir}/tag_cache"; + description = '' + The path to MPD's database. + ''; + }; }; }; diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix index 155161945cd..f8eeb437844 100644 --- a/nixos/modules/services/backup/tarsnap.nix +++ b/nixos/modules/services/backup/tarsnap.nix @@ -5,20 +5,21 @@ with lib; let cfg = config.services.tarsnap; - optionalNullStr = e: v: if e == null then "" else v; - configFile = cfg: '' cachedir ${config.services.tarsnap.cachedir} keyfile ${config.services.tarsnap.keyfile} ${optionalString cfg.nodump "nodump"} ${optionalString cfg.printStats "print-stats"} ${optionalString cfg.printStats "humanize-numbers"} - ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes} + ${optionalString (cfg.checkpointBytes != null) ("checkpoint-bytes "+cfg.checkpointBytes)} ${optionalString cfg.aggressiveNetworking "aggressive-networking"} ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)} ${concatStringsSep "\n" (map (v: "include "+v) cfg.includes)} ${optionalString cfg.lowmem "lowmem"} ${optionalString cfg.verylowmem "verylowmem"} + ${optionalString (cfg.maxbw != null) ("maxbw "+toString cfg.maxbw)} + ${optionalString (cfg.maxbwRateUp != null) ("maxbw-rate-up "+toString cfg.maxbwRateUp)} + ${optionalString (cfg.maxbwRateDown != null) ("maxbw-rate-down "+toString cfg.maxbwRateDown)} ''; in { @@ -166,6 +167,33 @@ in slowing down the archiving process. ''; }; + + maxbw = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Abort archival if upstream bandwidth usage in bytes + exceeds this threshold. + ''; + }; + + maxbwRateUp = mkOption { + type = types.nullOr types.int; + default = null; + example = literalExample "25 * 1000"; + description = '' + Upload bandwidth rate limit in bytes. + ''; + }; + + maxbwRateDown = mkOption { + type = types.nullOr types.int; + default = null; + example = literalExample "50 * 1000"; + description = '' + Download bandwidth rate limit in bytes. + ''; + }; }; } )); diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix index d9ae0454ba5..6a775bb159f 100644 --- a/nixos/modules/services/cluster/kubernetes.nix +++ b/nixos/modules/services/cluster/kubernetes.nix @@ -224,7 +224,7 @@ in { machines = mkOption { description = "Kubernetes controller list of machines to schedule to schedule onto"; - default = []; + default = [config.networking.hostName]; type = types.listOf types.str; }; @@ -310,6 +310,12 @@ in { type = types.str; }; + master = mkOption { + description = "Kubernetes apiserver address"; + default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}"; + type = types.str; + }; + extraOpts = mkOption { description = "Kubernetes proxy extra command line options."; default = ""; @@ -355,6 +361,7 @@ in { --secure_port=${toString cfg.apiserver.securePort} \ --portal_net=${cfg.apiserver.portalNet} \ --logtostderr=true \ + --runtime_config=api/v1beta3 \ ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ ${cfg.apiserver.extraOpts} ''; @@ -416,7 +423,6 @@ in { script = '' export PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH" exec ${cfg.package}/bin/kubelet \ - --etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \ --api_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers} \ --address=${cfg.kubelet.address} \ --port=${toString cfg.kubelet.port} \ @@ -443,7 +449,7 @@ in { after = [ "network-interfaces.target" "etcd.service" ]; serviceConfig = { ExecStart = ''${cfg.package}/bin/kube-proxy \ - --etcd_servers=${concatMapStringsSep "," (s: "http://${s}") cfg.etcdServers} \ + --master=${cfg.proxy.master} \ --bind_address=${cfg.proxy.address} \ --logtostderr=true \ ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ diff --git a/nixos/modules/services/desktops/geoclue2.nix b/nixos/modules/services/desktops/geoclue2.nix index 6bdd5edff1f..0e041fdbfbc 100644 --- a/nixos/modules/services/desktops/geoclue2.nix +++ b/nixos/modules/services/desktops/geoclue2.nix @@ -34,6 +34,8 @@ with lib; services.dbus.packages = [ pkgs.geoclue2 ]; + systemd.packages = [ pkgs.geoclue2 ]; + }; } diff --git a/nixos/modules/services/hardware/actkbd.nix b/nixos/modules/services/hardware/actkbd.nix new file mode 100644 index 00000000000..82de362c371 --- /dev/null +++ b/nixos/modules/services/hardware/actkbd.nix @@ -0,0 +1,130 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.actkbd; + + configFile = pkgs.writeText "actkbd.conf" '' + ${concatMapStringsSep "\n" + ({ keys, events, attributes, command, ... }: + ''${concatMapStringsSep "+" toString keys}:${concatStringsSep "," events}:${concatStringsSep "," attributes}:${command}'' + ) + cfg.bindings} + ${cfg.extraConfig} + ''; + + bindingCfg = { config, ... }: { + options = { + + keys = mkOption { + type = types.listOf types.int; + description = "List of keycodes to match."; + }; + + events = mkOption { + type = types.listOf (types.enum ["key" "rep" "rel"]); + default = [ "key" ]; + description = "List of events to match."; + }; + + attributes = mkOption { + type = types.listOf types.str; + default = [ "exec" ]; + description = "List of attributes."; + }; + + command = mkOption { + type = types.str; + default = ""; + description = "What to run."; + }; + + }; + }; + +in + +{ + + ###### interface + + options = { + + services.actkbd = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the <command>actkbd</command> key mapping daemon. + + Turning this on will start an <command>actkbd</command> + instance for every evdev input that has at least one key + (which is okay even for systems with tiny memory footprint, + since actkbd normally uses <100 bytes of memory per + instance). + + This allows binding keys globally without the need for e.g. + X11. + ''; + }; + + bindings = mkOption { + type = types.listOf (types.submodule bindingCfg); + default = []; + example = lib.literalExample '' + [ { keys = [ 113 ]; events = [ "key" ]; command = "''${pkgs.alsaUtils}/bin/amixer -q set Master toggle"; } + ] + ''; + description = '' + Key bindings for <command>actkbd</command>. + + See <command>actkbd</command> <filename>README</filename> for documentation. + + The example shows a piece of what <option>sound.enableMediaKeys</option> does when enabled. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Literal contents to append to the end of actkbd configuration file. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + services.udev.packages = lib.singleton (pkgs.writeTextFile { + name = "actkbd-udev-rules"; + destination = "/etc/udev/rules.d/61-actkbd.rules"; + text = '' + ACTION=="add", SUBSYSTEM=="input", KERNEL=="event[0-9]*", ENV{ID_INPUT_KEY}=="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="actkbd@$env{DEVNAME}.service" + ''; + }); + + systemd.services."actkbd@" = { + enable = true; + restartIfChanged = true; + unitConfig = { + Description = "actkbd on %I"; + ConditionPathExists = "%I"; + }; + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.actkbd}/bin/actkbd -D -c ${configFile} -d %I"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/logging/fluentd.nix b/nixos/modules/services/logging/fluentd.nix index 61eeec504e0..3aa27a15266 100644 --- a/nixos/modules/services/logging/fluentd.nix +++ b/nixos/modules/services/logging/fluentd.nix @@ -33,6 +33,7 @@ in { wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = "${pkgs.fluentd}/bin/fluentd -c ${pkgs.writeText "fluentd.conf" cfg.config}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; }; }; }; diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix index 284361a04d9..26d2753879d 100644 --- a/nixos/modules/services/misc/etcd.nix +++ b/nixos/modules/services/misc/etcd.nix @@ -11,7 +11,7 @@ in { enable = mkOption { description = "Whether to enable etcd."; default = false; - type = types.uniq types.bool; + type = types.bool; }; name = mkOption { diff --git a/nixos/modules/services/misc/ihaskell.nix b/nixos/modules/services/misc/ihaskell.nix new file mode 100644 index 00000000000..7f7f981de49 --- /dev/null +++ b/nixos/modules/services/misc/ihaskell.nix @@ -0,0 +1,76 @@ +{ pkgs, lib, config, ... }: + +with lib; + +let + + cfg = config.services.ihaskell; + ihaskell = pkgs.ihaskell.override { + inherit (cfg.haskellPackages) ihaskell ghcWithPackages; + packages = self: cfg.extraPackages self; + }; + +in + +{ + options = { + services.ihaskell = { + enable = mkOption { + default = false; + example = true; + description = "Autostart an IHaskell notebook service."; + }; + + haskellPackages = mkOption { + default = pkgs.haskellngPackages; + defaultText = "pkgs.haskellngPackages"; + example = literalExample "pkgs.haskell-ng.packages.ghc784"; + description = '' + haskellPackages used to build IHaskell and other packages. + This can be used to change the GHC version used to build + IHaskell and the packages listed in + <varname>extraPackages</varname>. + ''; + }; + + extraPackages = mkOption { + default = self: []; + example = literalExample '' + haskellPackages: [ + haskellPackages.wreq + haskellPackages.lens + ] + ''; + description = '' + Extra packages available to ghc when running ihaskell. The + value must be a function which receives the attrset defined + in <varname>haskellPackages</varname> as the sole argument. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + users.extraUsers.ihaskell = { + group = config.users.extraGroups.ihaskell.name; + description = "IHaskell user"; + home = "/var/lib/ihaskell"; + createHome = true; + uid = config.ids.uids.ihaskell; + }; + + users.extraGroups.ihaskell.gid = config.ids.gids.ihaskell; + + systemd.services.ihaskell = { + description = "IHaskell notebook instance"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + User = config.users.extraUsers.ihaskell.name; + Group = config.users.extraGroups.ihaskell.name; + ExecStart = "${pkgs.stdenv.shell} -c \"cd $HOME;${ihaskell}/bin/ihaskell-notebook\""; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix new file mode 100644 index 00000000000..f4642b5157e --- /dev/null +++ b/nixos/modules/services/misc/plex.nix @@ -0,0 +1,87 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.plex; + plex = pkgs.plex; +in +{ + options = { + services.plex = { + enable = mkEnableOption "Enable Plex Media Server"; + + # FIXME: In order for this config option to work, symlinks in the Plex + # package in the Nix store have to be changed to point to this directory. + dataDir = mkOption { + type = types.str; + default = "/var/lib/plex"; + description = "The directory where Plex stores its data files."; + }; + + user = mkOption { + type = types.str; + default = "plex"; + description = "User account under which Plex runs."; + }; + + group = mkOption { + type = types.str; + default = "plex"; + description = "Group under which Plex runs."; + }; + }; + }; + + config = mkIf cfg.enable { + # Most of this is just copied from the RPM package's systemd service file. + systemd.services.plex = { + description = "Plex Media Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + preStart = '' + test -d "${cfg.dataDir}" || { + echo "Creating initial Plex data directory in \"${cfg.dataDir}\"." + mkdir -p "${cfg.dataDir}" + chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}" + } + # Copy the database skeleton files to /var/lib/plex/.skeleton + test -d "${cfg.dataDir}/.skeleton" || mkdir "${cfg.dataDir}/.skeleton" + for db in "com.plexapp.plugins.library.db"; do + cp "${plex}/usr/lib/plexmediaserver/Resources/base_$db" "${cfg.dataDir}/.skeleton/$db" + chmod u+w "${cfg.dataDir}/.skeleton/$db" + chown ${cfg.user}:${cfg.group} "${cfg.dataDir}/.skeleton/$db" + done + ''; + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + PermissionsStartOnly = "true"; + ExecStart = "/bin/sh -c '${plex}/usr/lib/plexmediaserver/Plex\\ Media\\ Server'"; + }; + environment = { + PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=cfg.dataDir; + PLEX_MEDIA_SERVER_HOME="${plex}/usr/lib/plexmediaserver"; + PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6"; + PLEX_MEDIA_SERVER_TMPDIR="/tmp"; + LD_LIBRARY_PATH="${plex}/usr/lib/plexmediaserver"; + LC_ALL="en_US.UTF-8"; + LANG="en_US.UTF-8"; + }; + }; + + users.extraUsers = mkIf (cfg.user == "plex") { + plex = { + group = cfg.group; + uid = config.ids.uids.plex; + }; + }; + + users.extraGroups = mkIf (cfg.group == "plex") { + plex = { + gid = config.ids.gids.plex; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/ripple-data-api.nix b/nixos/modules/services/misc/ripple-data-api.nix index 6e5ac7ab00b..3b281449a25 100644 --- a/nixos/modules/services/misc/ripple-data-api.nix +++ b/nixos/modules/services/misc/ripple-data-api.nix @@ -43,6 +43,24 @@ in { type = types.int; }; + importMode = mkOption { + description = "Ripple data api import mode."; + default = "liveOnly"; + type = types.enum ["live" "liveOnly"]; + }; + + minLedger = mkOption { + description = "Ripple data api minimal ledger to fetch."; + default = null; + type = types.nullOr types.int; + }; + + maxLedger = mkOption { + description = "Ripple data api maximal ledger to fetch."; + default = null; + type = types.nullOr types.int; + }; + redis = { enable = mkOption { description = "Whether to enable caching of ripple data to redis."; @@ -129,6 +147,7 @@ in { serviceConfig = { ExecStart = "${pkgs.ripple-data-api}/bin/api"; + Restart = "always"; User = "ripple-data-api"; }; }; @@ -145,8 +164,15 @@ in { LOG_FILE = "/dev/null"; }; - serviceConfig = { - ExecStart = "${pkgs.ripple-data-api}/bin/importer live debug2"; + serviceConfig = let + importMode = + if cfg.minLedger != null && cfg.maxLedger != null then + "${toString cfg.minLedger} ${toString cfg.maxLedger}" + else + cfg.importMode; + in { + ExecStart = "${pkgs.ripple-data-api}/bin/importer ${importMode} debug"; + Restart = "always"; User = "ripple-data-api"; }; diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix index 85a1ed8ae9e..03fcc003a40 100644 --- a/nixos/modules/services/misc/rippled.nix +++ b/nixos/modules/services/misc/rippled.nix @@ -12,7 +12,7 @@ let path=${db.path} ${optionalString (db.compression != null) ("compression=${b2i db.compression}") } ${optionalString (db.onlineDelete != null) ("online_delete=${toString db.onlineDelete}")} - ${optionalString (db.advisoryDelete != null) ("advisory_delete=${toString db.advisoryDelete}")} + ${optionalString (db.advisoryDelete != null) ("advisory_delete=${b2i db.advisoryDelete}")} ${db.extraOpts} ''; @@ -71,6 +71,13 @@ let [sntp_servers] ${concatStringsSep "\n" cfg.sntpServers} + ${optionalString cfg.statsd.enable '' + [insight] + server=statsd + address=${cfg.statsd.address} + prefix=${cfg.statsd.prefix} + ''} + [rpc_startup] { "command": "log_level", "severity": "${cfg.logLevel}" } '' + cfg.extraConfig; @@ -142,7 +149,6 @@ let default = null; type = types.nullOr types.path; }; - }; }; }; @@ -150,7 +156,7 @@ let dbOptions = { type = mkOption { description = "Rippled database type."; - type = types.enum ["rocksdb" "nudb" "sqlite"]; + type = types.enum ["rocksdb" "nudb" "sqlite" "hyperleveldb"]; default = "rocksdb"; }; @@ -317,7 +323,7 @@ in Path to the ripple database. ''; type = types.path; - default = "/var/lib/rippled/db"; + default = "/var/lib/rippled"; }; validationQuorum = mkOption { @@ -366,6 +372,22 @@ in default = "error"; }; + statsd = { + enable = mkEnableOption "Whether enable statsd monitoring for rippled"; + + address = mkOption { + description = "The UDP address and port of the listening StatsD server."; + default = "127.0.0.1:8125"; + type = types.str; + }; + + prefix = mkOption { + description = "A string prepended to each collected metric."; + default = ""; + type = types.str; + }; + }; + extraConfig = mkOption { default = ""; description = '' @@ -400,6 +422,8 @@ in serviceConfig = { ExecStart = "${cfg.package}/bin/rippled --fg --conf ${cfg.config}"; User = "rippled"; + Restart = "on-failure"; + LimitNOFILE=10000; }; }; diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index d6babb8e9a5..8b3741bca0a 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -4,6 +4,10 @@ with lib; let + smbToString = x: if builtins.typeOf x == "bool" + then (if x then "true" else "false") + else toString x; + cfg = config.services.samba; samba = cfg.package; @@ -15,9 +19,9 @@ let shareConfig = name: let share = getAttr name cfg.shares; in - "[${name}]\n " + (toString ( + "[${name}]\n " + (smbToString ( map - (key: "${key} = ${toString (getAttr key share)}\n") + (key: "${key} = ${smbToString (getAttr key share)}\n") (attrNames share) )); @@ -27,12 +31,12 @@ let [ global ] security = ${cfg.securityType} passwd program = /var/setuid-wrappers/passwd %u - pam password change = ${if cfg.syncPasswordsByPam then "yes" else "no"} - invalid users = ${toString cfg.invalidUsers} + pam password change = ${smbToString cfg.syncPasswordsByPam} + invalid users = ${smbToString cfg.invalidUsers} ${cfg.extraConfig} - ${toString (map shareConfig (attrNames cfg.shares))} + ${smbToString (map shareConfig (attrNames cfg.shares))} ''); # This may include nss_ldap, needed for samba if it has to use ldap. @@ -151,7 +155,7 @@ in example = { srv = { path = "/srv"; - "read only" = "yes"; + "read only" = true; comment = "Public samba share."; }; }; @@ -193,7 +197,7 @@ in "samba-setup" = { description = "Samba Setup Task"; script = setupScript; - unitConfig.RequiresMountsFor = "/var/samba /var/log/samba"; + unitConfig.RequiresMountsFor = "/var/lib/samba"; }; }; }; diff --git a/nixos/modules/services/networking/asterisk.nix b/nixos/modules/services/networking/asterisk.nix new file mode 100644 index 00000000000..b079cb22730 --- /dev/null +++ b/nixos/modules/services/networking/asterisk.nix @@ -0,0 +1,223 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.asterisk; + + asteriskUser = "asterisk"; + + varlibdir = "/var/lib/asterisk"; + spooldir = "/var/spool/asterisk"; + logdir = "/var/log/asterisk"; + + asteriskEtc = pkgs.stdenv.mkDerivation + ((mapAttrs' (name: value: nameValuePair + # Fudge the names to make bash happy + ((replaceChars ["."] ["_"] name) + "_") + (value) + ) cfg.confFiles) // + { + confFilesString = concatStringsSep " " ( + attrNames cfg.confFiles + ); + + name = "asterisk.etc"; + + # Default asterisk.conf file + # (Notice that astetcdir will be set to the path of this derivation) + asteriskConf = '' + [directories] + astetcdir => @out@ + astmoddir => ${pkgs.asterisk}/lib/asterisk/modules + astvarlibdir => /var/lib/asterisk + astdbdir => /var/lib/asterisk + astkeydir => /var/lib/asterisk + astdatadir => /var/lib/asterisk + astagidir => /var/lib/asterisk/agi-bin + astspooldir => /var/spool/asterisk + astrundir => /var/run/asterisk + astlogdir => /var/log/asterisk + astsbindir => ${pkgs.asterisk}/sbin + ''; + extraConf = cfg.extraConfig; + + # Loading all modules by default is considered sensible by the authors of + # "Asterisk: The Definitive Guide". Secure sites will likely want to + # specify their own "modules.conf" in the confFiles option. + modulesConf = '' + [modules] + autoload=yes + ''; + + # Use syslog for logging so logs can be viewed with journalctl + loggerConf = '' + [general] + + [logfiles] + syslog.local0 => notice,warning,error + ''; + + buildCommand = '' + mkdir -p "$out" + + # Create asterisk.conf, pointing astetcdir to the path of this derivation + echo "$asteriskConf" | sed "s|@out@|$out|g" > "$out"/asterisk.conf + echo "$extraConf" >> "$out"/asterisk.conf + + echo "$modulesConf" > "$out"/modules.conf + + echo "$loggerConf" > "$out"/logger.conf + + # Config files specified in confFiles option override all other files + for i in $confFilesString; do + conf=$(echo "$i"_ | sed 's/\./_/g') + echo "''${!conf}" > "$out"/"$i" + done + ''; + }); +in + +{ + options = { + services.asterisk = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the Asterisk PBX server. + ''; + }; + + extraConfig = mkOption { + default = ""; + type = types.lines; + example = '' + [options] + verbose=3 + debug=3 + ''; + description = '' + Extra configuration options appended to the default + <literal>asterisk.conf</literal> file. + ''; + }; + + confFiles = mkOption { + default = {}; + type = types.attrsOf types.str; + example = literalExample + '' + { + "extensions.conf" = ''' + [tests] + ; Dial 100 for "hello, world" + exten => 100,1,Answer() + same => n,Wait(1) + same => n,Playback(hello-world) + same => n,Hangup() + + [softphones] + include => tests + + [unauthorized] + '''; + "sip.conf" = ''' + [general] + allowguest=no ; Require authentication + context=unauthorized ; Send unauthorized users to /dev/null + srvlookup=no ; Don't do DNS lookup + udpbindaddr=0.0.0.0 ; Listen on all interfaces + nat=force_rport,comedia ; Assume device is behind NAT + + [softphone](!) + type=friend ; Match on username first, IP second + context=softphones ; Send to softphones context in + ; extensions.conf file + host=dynamic ; Device will register with asterisk + disallow=all ; Manually specify codecs to allow + allow=g722 + allow=ulaw + allow=alaw + + [myphone](softphone) + secret=GhoshevFew ; Change this password! + '''; + "logger.conf" = ''' + [general] + + [logfiles] + ; Add debug output to log + syslog.local0 => notice,warning,error,debug + '''; + } + ''; + description = '' + Sets the content of config files (typically ending with + <literal>.conf</literal>) in the Asterisk configuration directory. + + Note that if you want to change <literal>asterisk.conf</literal>, it + is preferable to use the <option>services.asterisk.extraConfig</option> + option over this option. If <literal>"asterisk.conf"</literal> is + specified with the <option>confFiles</option> option (not recommended), + you must be prepared to set your own <literal>astetcdir</literal> + path. + + See + <link xlink:href="http://www.asterisk.org/community/documentation"/> + for more examples of what is possible here. + ''; + }; + + extraArguments = mkOption { + default = []; + type = types.listOf types.str; + example = + [ "-vvvddd" "-e" "1024" ]; + description = '' + Additional command line arguments to pass to Asterisk. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers = singleton + { name = asteriskUser; + uid = config.ids.uids.asterisk; + description = "Asterisk daemon user"; + home = varlibdir; + }; + + systemd.services.asterisk = { + description = '' + Asterisk PBX server + ''; + + wantedBy = [ "multi-user.target" ]; + + preStart = '' + # Copy skeleton directory tree to /var + for d in '${varlibdir}' '${spooldir}' '${logdir}'; do + # TODO: Make exceptions for /var directories that likely should be updated + if [ ! -e "$d" ]; then + cp --recursive ${pkgs.asterisk}/"$d" "$d" + chown --recursive ${asteriskUser} "$d" + find "$d" -type d | xargs chmod 0755 + fi + done + ''; + + serviceConfig = { + ExecStart = + let + # FIXME: This doesn't account for arguments with spaces + argString = concatStringsSep " " cfg.extraArguments; + in + "${pkgs.asterisk}/bin/asterisk -U ${asteriskUser} -C ${asteriskEtc}/asterisk.conf ${argString} -F"; + Type = "forking"; + PIDFile = "/var/run/asterisk/asterisk.pid"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/btsync.nix b/nixos/modules/services/networking/btsync.nix index 8b90f295ed4..d0123b79e3f 100644 --- a/nixos/modules/services/networking/btsync.nix +++ b/nixos/modules/services/networking/btsync.nix @@ -293,7 +293,7 @@ in systemd.services.btsync = with pkgs; { description = "Bittorrent Sync Service"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + after = [ "network.target" "local-fs.target" ]; serviceConfig = { Restart = "on-abort"; UMask = "0002"; @@ -305,7 +305,7 @@ in systemd.services."btsync@" = with pkgs; { description = "Bittorrent Sync Service for %i"; - after = [ "network.target" ]; + after = [ "network.target" "local-fs.target" ]; serviceConfig = { Restart = "on-abort"; User = "%i"; diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix index be0acb27324..f4063a3406f 100644 --- a/nixos/modules/services/networking/cjdns.nix +++ b/nixos/modules/services/networking/cjdns.nix @@ -44,6 +44,9 @@ let }) else ""; + parseModules = x: + x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; }; + # would be nice to merge 'cfg' with a //, # but the json nesting is wacky. cjdrouteConf = builtins.toJSON ( { @@ -53,8 +56,8 @@ let }; authorizedPasswords = map (p: { password = p; }) cfg.authorizedPasswords; interfaces = { - ETHInterface = if (cfg.ETHInterface.bind != "") then [ cfg.ETHInterface ] else [ ]; - UDPInterface = if (cfg.UDPInterface.bind != "") then [ cfg.UDPInterface ] else [ ]; + ETHInterface = if (cfg.ETHInterface.bind != "") then [ (parseModules cfg.ETHInterface) ] else [ ]; + UDPInterface = if (cfg.UDPInterface.bind != "") then [ (parseModules cfg.UDPInterface) ] else [ ]; }; privateKey = "@CJDNS_PRIVATE_KEY@"; @@ -151,12 +154,14 @@ in ETHInterface = { bind = mkOption { - default = ""; - example = "eth0"; - description = '' - Bind to this device for native ethernet operation. - ''; - }; + default = ""; + example = "eth0"; + description = + '' + Bind to this device for native ethernet operation. + <literal>all</literal> is a pseudo-name which will try to connect to all devices. + ''; + }; beacon = mkOption { type = types.int; diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index f01deb6ee7c..92f6396b358 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -127,8 +127,8 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - # This may change back to forking if too many problems occur: - type = "simple"; + # Uncomment this if too many problems occur: + # Type = "forking"; User = ddclientUser; Group = "nogroup"; #TODO get this to work PermissionsStartOnly = "true"; diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix index 7ddabf73106..18086154b6b 100644 --- a/nixos/modules/services/networking/dnsmasq.nix +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -28,6 +28,7 @@ in services.dnsmasq = { enable = mkOption { + type = types.bool; default = false; description = '' Whether to run dnsmasq. @@ -35,14 +36,16 @@ in }; resolveLocalQueries = mkOption { + type = types.bool; default = true; description = '' Whether dnsmasq should resolve local queries (i.e. add 127.0.0.1 to - /etc/resolv.conf) + /etc/resolv.conf). ''; }; servers = mkOption { + type = types.listOf types.string; default = []; example = [ "8.8.8.8" "8.8.4.4" ]; description = '' @@ -51,11 +54,11 @@ in }; extraConfig = mkOption { - type = types.string; + type = types.lines; default = ""; description = '' Extra configuration directives that should be added to - <literal>dnsmasq.conf</literal> + <literal>dnsmasq.conf</literal>. ''; }; @@ -81,7 +84,7 @@ in }; systemd.services.dnsmasq = { - description = "dnsmasq daemon"; + description = "Dnsmasq Daemon"; after = [ "network.target" "systemd-resolved.service" ]; wantedBy = [ "multi-user.target" ]; path = [ dnsmasq ]; diff --git a/nixos/modules/services/networking/i2p.nix b/nixos/modules/services/networking/i2p.nix new file mode 100644 index 00000000000..bad22c79138 --- /dev/null +++ b/nixos/modules/services/networking/i2p.nix @@ -0,0 +1,42 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.i2p; + homeDir = "/var/lib/i2p"; +in { + ###### interface + options.services.i2p = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enables i2p as a running service upon activation. + ''; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + users.extraUsers.i2p = { + group = "i2p"; + description = "i2p User"; + home = homeDir; + createHome = true; + uid = config.ids.uids.i2p; + }; + users.extraGroups.i2p.gid = config.ids.gids.i2p; + systemd.services.i2p = { + description = "I2P router with administration interface for hidden services"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "i2p"; + WorkingDirectory = homeDir; + Restart = "on-abort"; + ExecStart = "${pkgs.i2p}/bin/i2prouter-plain"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/lambdabot.nix b/nixos/modules/services/networking/lambdabot.nix new file mode 100644 index 00000000000..4ef7c7c9ab6 --- /dev/null +++ b/nixos/modules/services/networking/lambdabot.nix @@ -0,0 +1,81 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.lambdabot; + + rc = builtins.toFile "script.rc" cfg.script; + +in + +{ + + ### configuration + + options = { + + services.lambdabot = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Enable the Lambdabot IRC bot"; + }; + + package = mkOption { + type = types.package; + default = pkgs.lambdabot; + description = "Used lambdabot package"; + }; + + script = mkOption { + type = types.str; + default = ""; + description = "Lambdabot script"; + }; + + }; + + }; + + ### implementation + + config = mkIf cfg.enable { + + systemd.services.lambdabot = { + description = "Lambdabot daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + # Workaround for https://github.com/lambdabot/lambdabot/issues/117 + script = '' + mkdir -p ~/.lambdabot + cd ~/.lambdabot + mkfifo /run/lambdabot/offline + ( + echo 'rc ${rc}' + while true; do + cat /run/lambdabot/offline + done + ) | ${cfg.package}/bin/lambdabot + ''; + serviceConfig = { + User = "lambdabot"; + RuntimeDirectory = [ "lambdabot" ]; + }; + }; + + users.extraUsers.lambdabot = { + group = "lambdabot"; + description = "Lambdabot daemon user"; + home = "/var/lib/lambdabot"; + createHome = true; + uid = config.ids.uids.lambdabot; + }; + + users.extraGroups.lambdabot.gid = config.ids.gids.lambdabot; + + }; + +} diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index f00c5d1f701..60f380f024b 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -98,13 +98,23 @@ in { ''; }; + # Ugly hack for using the correct gnome3 packageSet + basePackages = mkOption { + type = types.attrsOf types.path; + default = { inherit networkmanager modemmanager wpa_supplicant + networkmanager_openvpn networkmanager_vpnc + networkmanager_openconnect + networkmanager_pptp networkmanager_l2tp; }; + internal = true; + }; + packages = mkOption { type = types.listOf types.path; default = [ ]; description = '' Extra packages that provide NetworkManager plugins. ''; - apply = list: [ networkmanager modemmanager wpa_supplicant ] ++ list; + apply = list: (attrValues cfg.basePackages) ++ list; }; appendNameservers = mkOption { @@ -164,7 +174,7 @@ in { boot.kernelModules = [ "ppp_mppe" ]; # Needed for most (all?) PPTP VPN connections. - environment.etc = [ + environment.etc = with cfg.basePackages; [ { source = ipUpScript; target = "NetworkManager/dispatcher.d/01nixos-ip-up"; } @@ -195,14 +205,7 @@ in { target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; }) cfg.dispatcherScripts; - environment.systemPackages = cfg.packages ++ [ - networkmanager_openvpn - networkmanager_vpnc - networkmanager_openconnect - networkmanager_pptp - networkmanager_l2tp - modemmanager - ]; + environment.systemPackages = cfg.packages; users.extraGroups = singleton { name = "networkmanager"; @@ -238,15 +241,7 @@ in { security.polkit.extraConfig = polkitConf; - # openvpn plugin has only dbus interface - services.dbus.packages = cfg.packages ++ [ - networkmanager_openvpn - networkmanager_vpnc - networkmanager_openconnect - networkmanager_pptp - networkmanager_l2tp - modemmanager - ]; + services.dbus.packages = cfg.packages; services.udev.packages = cfg.packages; }; diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index b2740bd33b7..c25532511a0 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -281,10 +281,8 @@ in config = mkIf cfg.enable { - users.extraUsers = singleton - { name = "sshd"; - uid = config.ids.uids.sshd; - description = "SSH privilege separation user"; + users.extraUsers.sshd = + { description = "SSH privilege separation user"; home = "/var/empty"; }; @@ -379,7 +377,7 @@ in Port ${toString port} '') cfg.ports} - ${concatMapStrings ({ port, addr }: '' + ${concatMapStrings ({ port, addr, ... }: '' ListenAddress ${addr}${if port != null then ":" + toString port else ""} '') cfg.listenAddresses} @@ -418,7 +416,7 @@ in (data.publicKey != null && data.publicKeyFile == null); message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; }) - ++ flip map cfg.listenAddresses ({ addr, port }: { + ++ flip map cfg.listenAddresses ({ addr, port, ... }: { assertion = addr != null; message = "addr must be specified in each listenAddresses entry"; }); diff --git a/nixos/modules/services/networking/sslh.nix b/nixos/modules/services/networking/sslh.nix index e251571dca3..c87fe914df8 100644 --- a/nixos/modules/services/networking/sslh.nix +++ b/nixos/modules/services/networking/sslh.nix @@ -81,7 +81,7 @@ in description = "Applicative Protocol Multiplexer (e.g. share SSH and HTTPS on the same port)"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - serviceConfig.ExecStart = "${pkgs.sslh}/bin/sslh -F ${configFile}"; + serviceConfig.ExecStart = "${pkgs.sslh}/bin/sslh -F${configFile}"; serviceConfig.KillMode = "process"; serviceConfig.PIDFile = "${cfg.pidfile}"; }; diff --git a/nixos/modules/services/security/hologram.nix b/nixos/modules/services/security/hologram.nix new file mode 100644 index 00000000000..f9abf38942f --- /dev/null +++ b/nixos/modules/services/security/hologram.nix @@ -0,0 +1,102 @@ +{pkgs, config, lib, ...}: + +with lib; + +let + cfg = config.services.hologram-server; + + cfgFile = pkgs.writeText "hologram-server.json" (builtins.toJSON { + ldap = { + host = cfg.ldapHost; + bind = { + dn = cfg.ldapBindDN; + password = cfg.ldapBindPassword; + }; + insecureldap = cfg.ldapInsecure; + userattr = cfg.ldapUserAttr; + baseDN = cfg.ldapBaseDN; + }; + aws = { + account = cfg.awsAccount; + defaultrole = cfg.awsDefaultRole; + }; + stats = cfg.statsAddress; + listen = cfg.listenAddress; + }); +in { + options = { + services.hologram-server = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the Hologram server for AWS instance credentials"; + }; + + listenAddress = mkOption { + type = types.str; + default = "0.0.0.0:3100"; + description = "Address and port to listen on"; + }; + + ldapHost = mkOption { + type = types.str; + description = "Address of the LDAP server to use"; + }; + + ldapInsecure = mkOption { + type = types.bool; + default = false; + description = "Whether to connect to LDAP over SSL or not"; + }; + + ldapUserAttr = mkOption { + type = types.str; + default = "cn"; + description = "The LDAP attribute for usernames"; + }; + + ldapBaseDN = mkOption { + type = types.str; + description = "The base DN for your Hologram users"; + }; + + ldapBindDN = mkOption { + type = types.str; + description = "DN of account to use to query the LDAP server"; + }; + + ldapBindPassword = mkOption { + type = types.str; + description = "Password of account to use to query the LDAP server"; + }; + + awsAccount = mkOption { + type = types.str; + description = "AWS account number"; + }; + + awsDefaultRole = mkOption { + type = types.str; + description = "AWS default role"; + }; + + statsAddress = mkOption { + type = types.str; + default = ""; + description = "Address of statsd server"; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.hologram-server = { + description = "Provide EC2 instance credentials to machines outside of EC2"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = "${pkgs.goPackages.hologram}/bin/hologram-server --debug --conf ${cfgFile}"; + }; + }; + }; +} diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix index d40f7d6d05d..853b458cf58 100644 --- a/nixos/modules/services/system/dbus.nix +++ b/nixos/modules/services/system/dbus.nix @@ -133,6 +133,8 @@ in # Don't restart dbus-daemon. Bad things tend to happen if we do. systemd.services.dbus.reloadIfChanged = true; + systemd.services.dbus.restartTriggers = [ configDir ]; + environment.pathsToLink = [ "/etc/dbus-1" "/share/dbus-1" ]; }; diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index 0879d9b85bd..caedc2e4217 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -42,11 +42,7 @@ in config = mkIf cfg.enable { - users.extraUsers = singleton - { name = "nscd"; - uid = config.ids.uids.nscd; - description = "Name service cache daemon user"; - }; + users.extraUsers.nscd.description = "Name service cache daemon user"; systemd.services.nscd = { description = "Name Service Cache Daemon"; diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix index 3958be33df2..85ee23c1a3d 100644 --- a/nixos/modules/services/ttys/agetty.nix +++ b/nixos/modules/services/ttys/agetty.nix @@ -10,6 +10,15 @@ with lib; services.mingetty = { + autologinUser = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Username of the account that will be automatically logged in at the console. + If unspecified, a login prompt is shown as usual. + ''; + }; + greetingLine = mkOption { type = types.str; default = ''<<< Welcome to NixOS ${config.system.nixosVersion} (\m) - \l >>>''; @@ -46,28 +55,30 @@ with lib; ###### implementation - config = { - + config = let + autologinArg = optionalString (config.services.mingetty.autologinUser != null) "--autologin ${config.services.mingetty.autologinUser}"; + gettyCmd = extraArgs: "@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login ${autologinArg} ${extraArgs}"; + in { systemd.services."getty@" = - { serviceConfig.ExecStart = "@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login --keep-baud %I 115200,38400,9600 $TERM"; + { serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud %I 115200,38400,9600 $TERM"; restartIfChanged = false; }; systemd.services."serial-getty@" = { serviceConfig.ExecStart = let speeds = concatStringsSep "," (map toString config.services.mingetty.serialSpeed); - in "@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login %I ${speeds} $TERM"; + in gettyCmd "%I ${speeds} $TERM"; restartIfChanged = false; }; systemd.services."container-getty@" = { unitConfig.ConditionPathExists = "/dev/pts/%I"; # Work around being respawned when "machinectl login" exits. - serviceConfig.ExecStart = "@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login --keep-baud pts/%I 115200,38400,9600 $TERM"; + serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud pts/%I 115200,38400,9600 $TERM"; restartIfChanged = false; }; systemd.services."console-getty" = - { serviceConfig.ExecStart = "@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login --keep-baud console 115200,38400,9600 $TERM"; + { serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud console 115200,38400,9600 $TERM"; serviceConfig.Restart = "always"; restartIfChanged = false; enable = mkDefault config.boot.isContainer; diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 2b5cba68d45..2885fd39652 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -231,6 +231,9 @@ let ${if cfg.sslServerCert != null then '' SSLCertificateFile ${cfg.sslServerCert} SSLCertificateKeyFile ${cfg.sslServerKey} + ${if cfg.sslServerChain != null then '' + SSLCertificateChainFile ${cfg.sslServerChain} + '' else ""} '' else ""} ${if cfg.enableSSL then '' diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix index c0ed2041639..52d8c89baff 100644 --- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix +++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix @@ -83,11 +83,11 @@ let # Unpack Mediawiki and put the config file in its root directory. mediawikiRoot = pkgs.stdenv.mkDerivation rec { - name= "mediawiki-1.23.3"; + name= "mediawiki-1.23.9"; src = pkgs.fetchurl { url = "http://download.wikimedia.org/mediawiki/1.23/${name}.tar.gz"; - sha256 = "0l6798jwjwk2khfnm84mgc65ij53a8pnv30wdnn15ys4ivia4bpf"; + sha256 = "1l7k4g0pgz92yvrfr52w26x740s4362v0gc95pk0i30vn2sp5bql"; }; skins = config.skins; @@ -142,6 +142,7 @@ in RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedDirs} + ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedFiles} RewriteRule ${if config.enableUploads then "!^/images" else "^.*\$" diff --git a/nixos/modules/services/web-servers/apache-httpd/moodle.nix b/nixos/modules/services/web-servers/apache-httpd/moodle.nix new file mode 100644 index 00000000000..84c8281ecd8 --- /dev/null +++ b/nixos/modules/services/web-servers/apache-httpd/moodle.nix @@ -0,0 +1,193 @@ +{ config, lib, pkgs, serverInfo, php, ... }: + +with lib; + +let + + httpd = serverInfo.serverConfig.package; + + version24 = !versionOlder httpd.version "2.4"; + + allGranted = if version24 then '' + Require all granted + '' else '' + Order allow,deny + Allow from all + ''; + + moodleConfig = pkgs.writeText "config.php" + '' + <?php + unset($CFG); + global $CFG; + $CFG = new stdClass(); + $CFG->dbtype = '${config.dbType}'; + $CFG->dblibrary = 'native'; + $CFG->dbhost = '${config.dbHost}'; + $CFG->dbname = '${config.dbName}'; + $CFG->dbuser = '${config.dbUser}'; + $CFG->dbpass = '${config.dbPassword}'; + $CFG->prefix = '${config.dbPrefix}'; + $CFG->dboptions = array( + 'dbpersist' => false, + 'dbsocket' => false, + 'dbport' => "${config.dbPort}", + ); + $CFG->wwwroot = '${config.wwwRoot}'; + $CFG->dataroot = '${config.dataRoot}'; + $CFG->directorypermissions = 02777; + $CFG->admin = 'admin'; + ${optionalString (config.debug.noEmailEver == true) '' + $CFG->noemailever = true; + ''} + + ${config.extraConfig} + require_once(dirname(__FILE__) . '/lib/setup.php'); // Do not edit + ''; + # Unpack Moodle and put the config file in its root directory. + moodleRoot = pkgs.stdenv.mkDerivation rec { + name= "moodle-2.8.5"; + + src = pkgs.fetchurl { + url = "https://download.moodle.org/stable28/${name}.tgz"; + sha256 = "1a159a193010cddedce10ee009184502e6f732e4d7c85167d8597fe5dff9e190"; + }; + + buildPhase = + '' + ''; + + installPhase = + '' + mkdir -p $out + cp -r * $out + cp ${moodleConfig} $out/config.php + ''; + }; + +in + +{ + + extraConfig = + '' + # this should be config.urlPrefix instead of / + Alias / ${moodleRoot}/ + <Directory ${moodleRoot}> + DirectoryIndex index.php + </Directory> + ''; + + documentRoot = moodleRoot; # TODO: fix this, should be config.urlPrefix + + enablePHP = true; + + options = { + + id = mkOption { + default = "main"; + description = '' + A unique identifier necessary to keep multiple Moodle server + instances on the same machine apart. + ''; + }; + + dbType = mkOption { + default = "postgres"; + example = "mysql"; + description = "Database type."; + }; + + dbName = mkOption { + default = "moodle"; + description = "Name of the database that holds the Moodle data."; + }; + + dbHost = mkOption { + default = "localhost"; + example = "10.0.2.2"; + description = '' + The location of the database server. + ''; + }; + + dbPort = mkOption { + default = ""; # use the default port + example = "12345"; + description = '' + The port that is used to connect to the database server. + ''; + }; + + dbUser = mkOption { + default = "moodle"; + description = "The user name for accessing the database."; + }; + + dbPassword = mkOption { + default = ""; + example = "password"; + description = '' + The password of the database user. Warning: this is stored in + cleartext in the Nix store! + ''; + }; + + dbPrefix = mkOption { + default = "mdl_"; + example = "my_other_mdl_"; + description = '' + A prefix for each table, if multiple moodles should run in a single database. + ''; + }; + + wwwRoot = mkOption { + type = types.string; + example = "http://my.machine.com/my-moodle"; + description = '' + The full web address where moodle has been installed. + ''; + }; + + dataRoot = mkOption { + default = "/var/lib/moodledata"; + example = "/var/lib/moodledata"; + description = '' + The data directory for moodle. Needs to be writable! + ''; + type = types.path; + }; + + + extraConfig = mkOption { + default = ""; + example = + '' + ''; + description = '' + Any additional text to be appended to Moodle's + configuration file. This is a PHP script. + ''; + }; + + debug = { + noEmailEver = mkOption { + default = false; + example = "true"; + description = '' + Set this to true to prevent Moodle from ever sending any email. + ''; + }; + }; + }; + + startupScript = pkgs.writeScript "moodle_startup.sh" '' + echo "Checking for existence of ${config.dataRoot}" + if [ ! -e "${config.dataRoot}" ] + then + mkdir -p "${config.dataRoot}" + chown ${serverInfo.serverConfig.user}.${serverInfo.serverConfig.group} "${config.dataRoot}" + fi + ''; + +} diff --git a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix index 76f55a63e32..5abcc5e7490 100644 --- a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix +++ b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix @@ -56,6 +56,13 @@ with lib; description = "Path to server SSL certificate key."; }; + sslServerChain = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/ca.pem"; + description = "Path to server SSL chain file."; + }; + adminAddr = mkOption ({ type = types.nullOr types.str; example = "admin@example.org"; @@ -90,7 +97,7 @@ with lib; default = []; example = [ { urlPath = "/foo/bar.png"; - dir = "/home/eelco/some-file.png"; + files = "/home/eelco/some-file.png"; } ]; description = '' diff --git a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix new file mode 100644 index 00000000000..01b6cfc62af --- /dev/null +++ b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix @@ -0,0 +1,209 @@ +{ config, lib, pkgs, serverInfo, php, ... }: + +with lib; + +let + # https://wordpress.org/plugins/postgresql-for-wordpress/ + # Wordpress plugin 'postgresql-for-wordpress' installation example + postgresqlForWordpressPlugin = pkgs.stdenv.mkDerivation { + name = "postgresql-for-wordpress-plugin"; + # Download the theme from the wordpress site + src = pkgs.fetchurl { + url = https://downloads.wordpress.org/plugin/postgresql-for-wordpress.1.3.1.zip; + sha256 = "f11a5d76af884c7bec2bc653ed5bd29d3ede9a8657bd67ab7824e329e5d809e8"; + }; + # We need unzip to build this package + buildInputs = [ pkgs.unzip ]; + # Installing simply means copying all files to the output directory + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + + # Our bare-bones wp-config.php file using the above settings + wordpressConfig = pkgs.writeText "wp-config.php" '' + <?php + define('DB_NAME', '${config.dbName}'); + define('DB_USER', '${config.dbUser}'); + define('DB_PASSWORD', '${config.dbPassword}'); + define('DB_HOST', '${config.dbHost}'); + define('DB_CHARSET', 'utf8'); + $table_prefix = '${config.tablePrefix}'; + if ( !defined('ABSPATH') ) + define('ABSPATH', dirname(__FILE__) . '/'); + require_once(ABSPATH . 'wp-settings.php'); + ${config.extraConfig} + ''; + + # .htaccess to support pretty URLs + htaccess = pkgs.writeText "htaccess" '' + <IfModule mod_rewrite.c> + RewriteEngine On + RewriteBase / + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule . /index.php [L] + </IfModule> + ''; + + # The wordpress package itself + wordpressRoot = pkgs.stdenv.mkDerivation rec { + name = "wordpress"; + # Fetch directly from the wordpress site, want to upgrade? + # Just change the version URL and update the hash + src = pkgs.fetchurl { + url = http://wordpress.org/wordpress-4.1.1.tar.gz; + sha256 = "1s9y0i9ms3m6dswb9gqrr95plnx6imahc07fyhvrp5g35f6c12k1"; + }; + installPhase = '' + mkdir -p $out + # Copy all the wordpress files we downloaded + cp -R * $out/ + # We'll symlink the wordpress config + ln -s ${wordpressConfig} $out/wp-config.php + # As well as our custom .htaccess + ln -s ${htaccess} $out/.htaccess + # And the uploads directory + ln -s ${config.wordpressUploads} $out/wp-content/uploads + # And the theme(s) + ${concatMapStrings (theme: "ln -s ${theme} $out/wp-content/themes/${theme.name}\n") config.themes} + # And the plugin(s) + # remove bundled plugin(s) coming with wordpress + rm -Rf $out/wp-content/plugins/akismet + # install plugins + ${concatMapStrings (plugin: "ln -s ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins ++ [ postgresqlForWordpressPlugin]) } + ''; + }; + +in + +{ + + # And some httpd extraConfig to make things work nicely + extraConfig = '' + <Directory ${wordpressRoot}> + DirectoryIndex index.php + Allow from * + Options FollowSymLinks + AllowOverride All + </Directory> + ''; + + enablePHP = true; + + options = { + dbHost = mkOption { + default = "localhost"; + description = "The location of the database server."; + example = "localhost"; + }; + dbName = mkOption { + default = "wordpress"; + description = "Name of the database that holds the Wordpress data."; + example = "localhost"; + }; + dbUser = mkOption { + default = "wordpress"; + description = "The dbUser, read the username, for the database."; + example = "wordpress"; + }; + dbPassword = mkOption { + default = "wordpress"; + description = "The password to the respective dbUser."; + example = "wordpress"; + }; + tablePrefix = mkOption { + default = "wp_"; + description = '' + The $table_prefix is the value placed in the front of your database tables. Change the value if you want to use something other than wp_ for your database prefix. Typically this is changed if you are installing multiple WordPress blogs in the same database. See <link xlink:href='http://codex.wordpress.org/Editing_wp-config.php#table_prefix'/>. + ''; + }; + wordpressUploads = mkOption { + default = "/data/uploads"; + description = '' + This directory is used for uploads of pictures and must be accessible (read: owned) by the httpd running user. The directory passed here is automatically created and permissions are given to the httpd running user. + ''; + }; + plugins = mkOption { + default = []; + type = types.listOf types.path; + description = + '' + List of path(s) to respective plugin(s) which are symlinked from the 'plugins' directory. Note: These plugins need to be packaged before use. + ''; + example = '' + # Wordpress plugin 'akismet' installation example + akismetPlugin = pkgs.stdenv.mkDerivation { + name = "akismet-plugin"; + # Download the theme from the wordpress site + src = pkgs.fetchurl { + url = https://downloads.wordpress.org/plugin/akismet.3.1.zip; + sha256 = "1i4k7qyzna08822ncaz5l00wwxkwcdg4j9h3z2g0ay23q640pclg"; + }; + # We need unzip to build this package + buildInputs = [ pkgs.unzip ]; + # Installing simply means copying all files to the output directory + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + + And then pass this theme to the themes list like this: + plugins = [ akismetPlugin ]; + ''; + }; + themes = mkOption { + default = []; + type = types.listOf types.path; + description = + '' + List of path(s) to respective theme(s) which are symlinked from the 'theme' directory. Note: These themes need to be packaged before use. + ''; + example = '' + # For shits and giggles, let's package the responsive theme + responsiveTheme = pkgs.stdenv.mkDerivation { + name = "responsive-theme"; + # Download the theme from the wordpress site + src = pkgs.fetchurl { + url = http://wordpress.org/themes/download/responsive.1.9.7.6.zip; + sha256 = "06i26xlc5kdnx903b1gfvnysx49fb4kh4pixn89qii3a30fgd8r8"; + }; + # We need unzip to build this package + buildInputs = [ pkgs.unzip ]; + # Installing simply means copying all files to the output directory + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + + And then pass this theme to the themes list like this: + themes = [ responsiveTheme ]; + ''; + }; + extraConfig = mkOption { + default = ""; + example = + '' + define( 'AUTOSAVE_INTERVAL', 60 ); // Seconds + ''; + description = '' + Any additional text to be appended to Wordpress's wp-config.php + configuration file. This is a PHP script. For configuration + settings, see <link xlink:href='http://codex.wordpress.org/Editing_wp-config.php'/>. + ''; + }; + }; + + documentRoot = wordpressRoot; + + startupScript = pkgs.writeScript "init-wordpress.sh" '' + #!/bin/sh + mkdir -p ${config.wordpressUploads} + chown ${serverInfo.serverConfig.user} ${config.wordpressUploads} + + # we should use systemd dependencies here + #waitForUnit("network-interfaces.target"); + if [ ! -d ${serverInfo.fullConfig.services.mysql.dataDir}/${config.dbName} ]; then + # Wait until MySQL is up + while [ ! -e /var/run/mysql/mysqld.pid ]; do + sleep 1 + done + ${pkgs.mysql}/bin/mysql -e 'CREATE DATABASE ${config.dbName};' + ${pkgs.mysql}/bin/mysql -e 'GRANT ALL ON ${config.dbName}.* TO ${config.dbUser}@localhost IDENTIFIED BY "${config.dbPassword}";' + fi + ''; +} diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 0f21ef01263..fe50c182bfe 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -102,6 +102,7 @@ in ''; serviceConfig = { ExecStart = "${nginx}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; RestartSec = "10s"; StartLimitInterval = "1min"; diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 6398a15bfcc..d53f119c955 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -21,7 +21,7 @@ let destination = "/share/applications/mimeapps.list"; text = '' [Default Applications] - inode/directory=nautilus.desktop + inode/directory=nautilus.desktop;org.gnome.Nautilus.desktop ''; }; @@ -80,6 +80,7 @@ in { services.telepathy.enable = mkDefault true; networking.networkmanager.enable = mkDefault true; services.upower.enable = config.powerManagement.enable; + hardware.bluetooth.enable = mkDefault true; fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell_fonts ]; @@ -108,7 +109,7 @@ in { # Override default mimeapps export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share - # Let gnome-control-center find gnome-shell search providers + # Let gnome-control-center find gnome-shell search providers. GNOME 3.12 compatibility. export GNOME_SEARCH_PROVIDERS_DIR=${config.system.path}/share/gnome-shell/search-providers/ # Let nautilus find extensions @@ -120,6 +121,9 @@ in { # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update + # Find the mouse + export XCURSOR_PATH=~/.icons:${config.system.path}/share/icons + ${gnome3.gnome_session}/bin/gnome-session& waitPID=$! ''; @@ -128,52 +132,15 @@ in { environment.variables.GIO_EXTRA_MODULES = [ "${gnome3.dconf}/lib/gio/modules" "${gnome3.glib_networking}/lib/gio/modules" "${gnome3.gvfs}/lib/gio/modules" ]; - environment.systemPackages = - [ pkgs.desktop_file_utils - gnome3.glib_networking - gnome3.gtk3 # for gtk-update-icon-cache - pkgs.ibus - pkgs.shared_mime_info # for update-mime-database - gnome3.gvfs - gnome3.dconf - gnome3.gnome-backgrounds - gnome3.gnome_control_center - gnome3.gnome_icon_theme - gnome3.gnome-menus - gnome3.gnome_settings_daemon - gnome3.gnome_shell - gnome3.gnome_themes_standard - ] ++ cfg.sessionPath ++ (removePackagesByName [ - gnome3.baobab - gnome3.empathy - gnome3.eog - gnome3.epiphany - gnome3.evince - gnome3.gucharmap - gnome3.nautilus - gnome3.totem - gnome3.vino - gnome3.yelp - gnome3.gnome-calculator - gnome3.gnome-contacts - gnome3.gnome-font-viewer - gnome3.gnome-screenshot - gnome3.gnome-shell-extensions - gnome3.gnome-system-log - gnome3.gnome-system-monitor - gnome3.gnome_terminal - gnome3.gnome-user-docs - - gnome3.bijiben - gnome3.evolution - gnome3.file-roller - gnome3.gedit - gnome3.gnome-clocks - gnome3.gnome-music - gnome3.gnome-tweak-tool - gnome3.gnome-photos - gnome3.nautilus-sendto - ] config.environment.gnome3.excludePackages); + environment.systemPackages = gnome3.corePackages ++ cfg.sessionPath + ++ (removePackagesByName gnome3.optionalPackages config.environment.gnome3.excludePackages); + + # Use the correct gnome3 packageSet + networking.networkmanager.basePackages = + { inherit (pkgs) networkmanager modemmanager wpa_supplicant; + inherit (gnome3) networkmanager_openvpn networkmanager_vpnc + networkmanager_openconnect networkmanager_pptp + networkmanager_l2tp; }; # Needed for themes and backgrounds environment.pathsToLink = [ "/share" ]; diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index a7ebafa28b3..6c3c5273086 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -58,14 +58,14 @@ in # Find the mouse XCURSOR_PATH = "~/.icons:${config.system.path}/share/icons"; }; - execCmd = "exec ${gdm}/sbin/gdm"; + execCmd = "exec ${gdm}/bin/gdm"; }; # Because sd_login_monitor_new requires /run/systemd/machines systemd.services.display-manager.wants = [ "systemd-machined.service" ]; systemd.services.display-manager.after = [ "systemd-machined.service" ]; - systemd.services.display-manager.path = [ gnome3.gnome_shell gnome3.caribou ]; + systemd.services.display-manager.path = [ gnome3.gnome_shell gnome3.caribou pkgs.xlibs.xhost pkgs.dbus_tools ]; services.dbus.packages = [ gdm ]; diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 6a7b810261d..4aeaed8cd32 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -19,7 +19,7 @@ let ''; theme = pkgs.gnome3.gnome_themes_standard; - icons = pkgs.gnome3.gnome_icon_theme; + icons = pkgs.gnome3.defaultIconTheme; # The default greeter provided with this expression is the GTK greeter. # Again, we need a few things in the environment for the greeter to run with @@ -69,6 +69,7 @@ let xserver-command = ${xserverWrapper} session-wrapper = ${dmcfg.session.script} greeter-session = ${cfg.greeter.name} + ${cfg.extraSeatDefaults} ''; gtkGreeterConf = writeText "lightdm-gtk-greeter.conf" @@ -109,6 +110,15 @@ in ''; }; + extraSeatDefaults = mkOption { + type = types.lines; + default = ""; + example = '' + greeter-show-manual-login=true + ''; + description = "Extra lines to append to SeatDefaults section."; + }; + }; }; diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 64e0d4d8050..5198864ef6e 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -41,16 +41,24 @@ let }; in imap mkHead cfg.xrandrHeads; - xrandrDeviceSection = flip concatMapStrings xrandrHeads (h: '' - Option "monitor-${h.output}" "${h.name}" - ''); + xrandrDeviceSection = let + monitors = flip map xrandrHeads (h: '' + Option "monitor-${h.output}" "${h.name}" + ''); + # First option is indented through the space in the config but any + # subsequent options aren't so we need to apply indentation to + # them here + monitorsIndented = if length monitors > 1 + then singleton (head monitors) ++ map (m: " " + m) (tail monitors) + else monitors; + in concatStrings monitorsIndented; # Here we chain every monitor from the left to right, so we have: # m4 right of m3 right of m2 right of m1 .----.----.----.----. # Which will end up in reverse ----------> | m1 | m2 | m3 | m4 | # `----^----^----^----' xrandrMonitorSections = let - mkMonitor = previous: current: previous ++ singleton { + mkMonitor = previous: current: singleton { inherit (current) name; value = '' Section "Monitor" @@ -60,8 +68,8 @@ let ''} EndSection ''; - }; - monitors = foldl mkMonitor [] xrandrHeads; + } ++ previous; + monitors = reverseList (foldl mkMonitor [] xrandrHeads); in concatMapStrings (getAttr "value") monitors; configFile = pkgs.stdenv.mkDerivation { @@ -147,6 +155,19 @@ in ''; }; + inputClassSections = mkOption { + type = types.listOf types.lines; + default = []; + example = [ '' + Identifier "Trackpoint Wheel Emulation" + MatchProduct "ThinkPad USB Keyboard with TrackPoint" + Option "EmulateWheel" "true + Option "EmulateWheelButton" "2" + Option "Emulate3Buttons" "false" + '' ]; + description = "Content of additional InputClass sections of the X server configuration file."; + }; + modules = mkOption { type = types.listOf types.path; default = []; @@ -522,6 +543,14 @@ in Option "XkbVariant" "${cfg.xkbVariant}" EndSection + # Additional "InputClass" sections + ${flip concatMapStrings cfg.inputClassSections (inputClassSection: '' + Section "InputClass" + ${inputClassSection} + EndSection + '')} + + Section "ServerLayout" Identifier "Layout[all]" ${cfg.serverLayoutSection} @@ -593,4 +622,3 @@ in }; } - diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index 7aa4b12a654..4289740322a 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -322,7 +322,9 @@ foreach my $device (keys %$prevSwaps) { # Should we have systemd re-exec itself? -my $restartSystemd = abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd"); +my $prevSystemd = abs_path("/proc/1/exe") or die; +my $newSystemd = abs_path("@systemd@/lib/systemd/systemd") or die; +my $restartSystemd = $prevSystemd ne $newSystemd; sub filterUnits { diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index 2ef1fca1983..81009e9fb82 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -468,8 +468,8 @@ sub getEfiTarget { if ($grubTargetEfi eq "") { die } else {return "only" } } else { - # at least one grub target has to be given - die + # prevent an installation if neither grub nor grubEfi is given + return "neither" } } diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix new file mode 100644 index 00000000000..0221374ab83 --- /dev/null +++ b/nixos/modules/system/boot/networkd.nix @@ -0,0 +1,670 @@ +{ config, lib, pkgs, ... }: + +with lib; +with import ./systemd-unit-options.nix { inherit config lib; }; +with import ./systemd-lib.nix { inherit config lib pkgs; }; + +let + + cfg = config.systemd.network; + + checkLink = checkUnitConfig "Link" [ + (assertOnlyFields [ + "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name" + "MTUBytes" "BitsPerSecond" "Duplex" "WakeOnLan" + ]) + (assertValueOneOf "MACAddressPolicy" ["persistent" "random"]) + (assertMacAddress "MACAddress") + (assertValueOneOf "NamePolicy" [ + "kernel" "database" "onboard" "slot" "path" "mac" + ]) + (assertByteFormat "MTUBytes") + (assertByteFormat "BitsPerSecond") + (assertValueOneOf "Duplex" ["half" "full"]) + (assertValueOneOf "WakeOnLan" ["phy" "magic" "off"]) + ]; + + checkNetdev = checkUnitConfig "Netdev" [ + (assertOnlyFields [ + "Description" "Name" "Kind" "MTUBytes" "MACAddress" + ]) + (assertHasField "Name") + (assertHasField "Kind") + (assertValueOneOf "Kind" [ + "bridge" "bond" "vlan" "macvlan" "vxlan" "ipip" + "gre" "sit" "vti" "veth" "tun" "tap" "dummy" + ]) + (assertByteFormat "MTUBytes") + (assertMacAddress "MACAddress") + ]; + + checkVlan = checkUnitConfig "VLAN" [ + (assertOnlyFields ["Id"]) + (assertRange "Id" 0 4094) + ]; + + checkMacvlan = checkUnitConfig "MACVLAN" [ + (assertOnlyFields ["Mode"]) + (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"]) + ]; + + checkVxlan = checkUnitConfig "VXLAN" [ + (assertOnlyFields ["Id" "Group" "TOS" "TTL" "MacLearning"]) + (assertRange "TTL" 0 255) + (assertValueOneOf "MacLearning" boolValues) + ]; + + checkTunnel = checkUnitConfig "Tunnel" [ + (assertOnlyFields ["Local" "Remote" "TOS" "TTL" "DiscoverPathMTU"]) + (assertRange "TTL" 0 255) + (assertValueOneOf "DiscoverPathMTU" boolValues) + ]; + + checkPeer = checkUnitConfig "Peer" [ + (assertOnlyFields ["Name" "MACAddress"]) + (assertMacAddress "MACAddress") + ]; + + tunTapChecks = [ + (assertOnlyFields ["OneQueue" "MultiQueue" "PacketInfo" "User" "Group"]) + (assertValueOneOf "OneQueue" boolValues) + (assertValueOneOf "MultiQueue" boolValues) + (assertValueOneOf "PacketInfo" boolValues) + ]; + + checkTun = checkUnitConfig "Tun" tunTapChecks; + + checkTap = checkUnitConfig "Tap" tunTapChecks; + + checkBond = checkUnitConfig "Bond" [ + (assertOnlyFields [ + "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec" + "UpDelaySec" "DownDelaySec" + ]) + (assertValueOneOf "Mode" [ + "balance-rr" "active-backup" "balance-xor" + "broadcast" "802.3ad" "balance-tlb" "balance-alb" + ]) + (assertValueOneOf "TransmitHashPolicy" [ + "layer2" "layer3+4" "layer2+3" "encap2+3" "802.3ad" "encap3+4" + ]) + (assertValueOneOf "LACPTransmitRate" ["slow" "fast"]) + ]; + + checkNetwork = checkUnitConfig "Network" [ + (assertOnlyFields [ + "Description" "DHCP" "DHCPServer" "IPv4LL" "IPv4LLRoute" + "LLMNR" "Domains" "Bridge" "Bond" + ]) + (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"]) + (assertValueOneOf "DHCPServer" boolValues) + (assertValueOneOf "IPv4LL" boolValues) + (assertValueOneOf "IPv4LLRoute" boolValues) + (assertValueOneOf "LLMNR" boolValues) + ]; + + checkAddress = checkUnitConfig "Address" [ + (assertOnlyFields ["Address" "Peer" "Broadcast" "Label"]) + (assertHasField "Address") + ]; + + checkRoute = checkUnitConfig "Route" [ + (assertOnlyFields ["Gateway" "Destination" "Metric"]) + (assertHasField "Gateway") + ]; + + checkDhcp = checkUnitConfig "DHCP" [ + (assertOnlyFields [ + "UseDNS" "UseMTU" "SendHostname" "UseHostname" "UseDomains" "UseRoutes" + "CriticalConnections" "VendorClassIdentifier" "RequestBroadcast" + "RouteMetric" + ]) + (assertValueOneOf "UseDNS" boolValues) + (assertValueOneOf "UseMTU" boolValues) + (assertValueOneOf "SendHostname" boolValues) + (assertValueOneOf "UseHostname" boolValues) + (assertValueOneOf "UseDomains" boolValues) + (assertValueOneOf "UseRoutes" boolValues) + (assertValueOneOf "CriticalConnections" boolValues) + (assertValueOneOf "RequestBroadcast" boolValues) + ]; + + commonNetworkOptions = { + + enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to manage network configuration using <command>systemd-network</command>. + ''; + }; + + matchConfig = mkOption { + default = {}; + example = { Name = "eth0"; }; + type = types.attrsOf unitOption; + description = '' + Each attribute in this set specifies an option in the + <literal>[Match]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details. + ''; + }; + + }; + + linkOptions = commonNetworkOptions // { + + linkConfig = mkOption { + default = {}; + example = { MACAddress = "00:ff:ee:aa:cc:dd"; }; + type = types.addCheck (types.attrsOf unitOption) checkLink; + description = '' + Each attribute in this set specifies an option in the + <literal>[Link]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.link</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + }; + + netdevOptions = commonNetworkOptions // { + + netdevConfig = mkOption { + default = {}; + example = { Name = "mybridge"; Kind = "bridge"; }; + type = types.addCheck (types.attrsOf unitOption) checkNetdev; + description = '' + Each attribute in this set specifies an option in the + <literal>[Netdev]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + vlanConfig = mkOption { + default = {}; + example = { Id = "4"; }; + type = types.addCheck (types.attrsOf unitOption) checkVlan; + description = '' + Each attribute in this set specifies an option in the + <literal>[VLAN]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + macvlanConfig = mkOption { + default = {}; + example = { Mode = "private"; }; + type = types.addCheck (types.attrsOf unitOption) checkMacvlan; + description = '' + Each attribute in this set specifies an option in the + <literal>[MACVLAN]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + vxlanConfig = mkOption { + default = {}; + example = { Id = "4"; }; + type = types.addCheck (types.attrsOf unitOption) checkVxlan; + description = '' + Each attribute in this set specifies an option in the + <literal>[VXLAN]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + tunnelConfig = mkOption { + default = {}; + example = { Remote = "192.168.1.1"; }; + type = types.addCheck (types.attrsOf unitOption) checkTunnel; + description = '' + Each attribute in this set specifies an option in the + <literal>[Tunnel]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + peerConfig = mkOption { + default = {}; + example = { Name = "veth2"; }; + type = types.addCheck (types.attrsOf unitOption) checkPeer; + description = '' + Each attribute in this set specifies an option in the + <literal>[Peer]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + tunConfig = mkOption { + default = {}; + example = { User = "openvpn"; }; + type = types.addCheck (types.attrsOf unitOption) checkTun; + description = '' + Each attribute in this set specifies an option in the + <literal>[Tun]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + tapConfig = mkOption { + default = {}; + example = { User = "openvpn"; }; + type = types.addCheck (types.attrsOf unitOption) checkTap; + description = '' + Each attribute in this set specifies an option in the + <literal>[Tap]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + bondConfig = mkOption { + default = {}; + example = { Mode = "802.3ad"; }; + type = types.addCheck (types.attrsOf unitOption) checkBond; + description = '' + Each attribute in this set specifies an option in the + <literal>[Bond]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.netdev</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + }; + + addressOptions = { + + addressConfig = mkOption { + default = {}; + example = { Address = "192.168.0.100/24"; }; + type = types.addCheck (types.attrsOf unitOption) checkAddress; + description = '' + Each attribute in this set specifies an option in the + <literal>[Address]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + }; + + routeOptions = { + + routeConfig = mkOption { + default = {}; + example = { Gateway = "192.168.0.1"; }; + type = types.addCheck (types.attrsOf unitOption) checkRoute; + description = '' + Each attribute in this set specifies an option in the + <literal>[Route]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + }; + + networkOptions = commonNetworkOptions // { + + networkConfig = mkOption { + default = {}; + example = { Description = "My Network"; }; + type = types.addCheck (types.attrsOf unitOption) checkNetwork; + description = '' + Each attribute in this set specifies an option in the + <literal>[Network]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + dhcpConfig = mkOption { + default = {}; + example = { UseDNS = true; UseRoutes = true; }; + type = types.addCheck (types.attrsOf unitOption) checkDhcp; + description = '' + Each attribute in this set specifies an option in the + <literal>[DHCP]</literal> section of the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + name = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The name of the network interface to match against. + ''; + }; + + DHCP = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Whether to enable DHCP on the interfaces matched. + ''; + }; + + domains = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + description = '' + A list of domains to pass to the network config. + ''; + }; + + address = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of addresses to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + gateway = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of gateways to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + dns = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of dns servers to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + ntp = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of ntp servers to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + vlan = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of vlan interfaces to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + macvlan = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of macvlan interfaces to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + vxlan = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of vxlan interfaces to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + tunnel = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + A list of tunnel interfaces to be added to the network section of the + unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + addresses = mkOption { + default = [ ]; + type = types.listOf types.optionSet; + options = [ addressOptions ]; + description = '' + A list of address sections to be added to the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + routes = mkOption { + default = [ ]; + type = types.listOf types.optionSet; + options = [ routeOptions ]; + description = '' + A list of route sections to be added to the unit. See + <citerefentry><refentrytitle>systemd.network</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> for details. + ''; + }; + + }; + + networkConfig = { name, config, ... }: { + config = { + matchConfig = optionalAttrs (config.name != null) { + Name = config.name; + }; + networkConfig = optionalAttrs (config.DHCP != null) { + DHCP = config.DHCP; + } // optionalAttrs (config.domains != null) { + Domains = concatStringsSep " " config.domains; + }; + }; + }; + + linkToUnit = name: def: + { inherit (def) enable; + text = commonMatchText def + + '' + [Link] + ${attrsToSection def.linkConfig} + ''; + }; + + netdevToUnit = name: def: + { inherit (def) enable; + 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} + + ''} + ''; + }; + + networkToUnit = name: def: + { inherit (def) enable; + text = commonMatchText def + + '' + [Network] + ${attrsToSection def.networkConfig} + ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)} + ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)} + ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)} + ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)} + ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)} + ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)} + ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)} + ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)} + + ${optionalString (def.dhcpConfig != { }) '' + [DHCP] + ${attrsToSection def.dhcpConfig} + + ''} + ${flip concatMapStrings def.addresses (x: '' + [Address] + ${attrsToSection x.addressConfig} + + '')} + ${flip concatMapStrings def.routes (x: '' + [Route] + ${attrsToSection x.routeConfig} + + '')} + ''; + }; + +in + +{ + + options = { + + systemd.network.enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable networkd or not. + ''; + }; + + systemd.network.links = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ linkOptions ]; + description = "Definition of systemd network links."; + }; + + systemd.network.netdevs = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ netdevOptions ]; + description = "Definition of systemd network devices."; + }; + + systemd.network.networks = mkOption { + default = {}; + type = types.attrsOf types.optionSet; + options = [ networkOptions networkConfig ]; + description = "Definition of systemd networks."; + }; + + systemd.network.units = mkOption { + description = "Definition of networkd units."; + default = {}; + type = types.attrsOf types.optionSet; + options = { name, config, ... }: + { options = concreteUnitOptions; + config = { + unit = mkDefault (makeUnit name config); + }; + }; + }; + + }; + + config = mkIf config.systemd.network.enable { + + systemd.additionalUpstreamSystemUnits = + [ "systemd-networkd.service" "systemd-networkd-wait-online.service" ]; + + systemd.network.units = + mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links + // mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs + // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks; + + environment.etc."systemd/network".source = + generateUnits "network" cfg.units [] []; + + users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; + users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network; + + systemd.services.systemd-networkd = { + wantedBy = [ "multi-user.target" ]; + before = [ "network-interfaces.target" ]; + restartTriggers = [ config.environment.etc."systemd/network".source ]; + }; + + systemd.services.systemd-networkd-wait-online = { + before = [ "network-online.target" "ip-up.target" ]; + wantedBy = [ "network-online.target" "ip-up.target" ]; + }; + + systemd.services."systemd-network-wait-online@" = { + description = "Wait for Network Interface %I to be Configured"; + conflicts = [ "shutdown.target" ]; + requisite = [ "systemd-networkd.service" ]; + after = [ "systemd-networkd.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I"; + }; + }; + + services.resolved.enable = mkDefault true; + services.timesyncd.enable = mkDefault config.services.ntp.enable; + + }; + +} diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix new file mode 100644 index 00000000000..ecd547322d3 --- /dev/null +++ b/nixos/modules/system/boot/resolved.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + + options = { + + services.resolved.enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable the systemd DNS resolver daemon. + ''; + }; + + }; + + config = mkIf config.services.resolved.enable { + + systemd.additionalUpstreamSystemUnits = [ "systemd-resolved.service" ]; + + systemd.services.systemd-resolved = { + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ]; + }; + + environment.etc."systemd/resolved.conf".text = '' + [Resolve] + DNS=${concatStringsSep " " config.networking.nameservers} + ''; + + users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve; + users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve; + + }; + +} diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix index 6155bb37cc5..c0ef4e02d1f 100644 --- a/nixos/modules/system/boot/stage-2.nix +++ b/nixos/modules/system/boot/stage-2.nix @@ -24,7 +24,6 @@ let path = [ pkgs.coreutils pkgs.utillinux - pkgs.sysvtools pkgs.openresolv ] ++ optional config.nix.readOnlyStore readonlyMountpoint; postBootCommands = pkgs.writeText "local-cmds" diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix new file mode 100644 index 00000000000..e8cfd3395cb --- /dev/null +++ b/nixos/modules/system/boot/systemd-lib.nix @@ -0,0 +1,118 @@ +{ config, lib, pkgs }: + +with lib; + +let cfg = config.systemd; in + +rec { + + shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s); + + makeUnit = name: unit: + let + pathSafeName = lib.replaceChars ["@" ":" "\\"] ["-" "-" "-"] name; + in + if unit.enable then + pkgs.runCommand "unit-${pathSafeName}" { preferLocalBuild = true; inherit (unit) text; } + '' + mkdir -p $out + echo -n "$text" > $out/${shellEscape name} + '' + else + pkgs.runCommand "unit-${pathSafeName}-disabled" { preferLocalBuild = true; } + '' + mkdir -p $out + ln -s /dev/null $out/${shellEscape name} + ''; + + generateUnits = type: units: upstreamUnits: upstreamWants: + pkgs.runCommand "${type}-units" { preferLocalBuild = true; } '' + mkdir -p $out + + # Copy the upstream systemd units we're interested in. + for i in ${toString upstreamUnits}; do + fn=${cfg.package}/example/systemd/${type}/$i + if ! [ -e $fn ]; then echo "missing $fn"; false; fi + if [ -L $fn ]; then + target="$(readlink "$fn")" + if [ ''${target:0:3} = ../ ]; then + ln -s "$(readlink -f "$fn")" $out/ + else + cp -pd $fn $out/ + fi + else + ln -s $fn $out/ + fi + done + + # Copy .wants links, but only those that point to units that + # we're interested in. + for i in ${toString upstreamWants}; do + fn=${cfg.package}/example/systemd/${type}/$i + if ! [ -e $fn ]; then echo "missing $fn"; false; fi + x=$out/$(basename $fn) + mkdir $x + for i in $fn/*; do + y=$x/$(basename $i) + cp -pd $i $y + if ! [ -e $y ]; then rm $y; fi + done + done + + # Symlink all units provided listed in systemd.packages. + for i in ${toString cfg.packages}; do + for fn in $i/etc/systemd/${type}/* $i/lib/systemd/${type}/*; do + if ! [[ "$fn" =~ .wants$ ]]; then + ln -s $fn $out/ + fi + done + done + + # Symlink all units defined by systemd.units. If these are also + # provided by systemd or systemd.packages, then add them as + # <unit-name>.d/overrides.conf, which makes them extend the + # upstream unit. + for i in ${toString (mapAttrsToList (n: v: v.unit) units)}; do + fn=$(basename $i/*) + if [ -e $out/$fn ]; then + if [ "$(readlink -f $i/$fn)" = /dev/null ]; then + ln -sfn /dev/null $out/$fn + else + mkdir $out/$fn.d + ln -s $i/$fn $out/$fn.d/overrides.conf + fi + else + ln -fs $i/$fn $out/ + fi + done + + # Created .wants and .requires symlinks from the wantedBy and + # requiredBy options. + ${concatStrings (mapAttrsToList (name: unit: + concatMapStrings (name2: '' + mkdir -p $out/'${name2}.wants' + ln -sfn '../${name}' $out/'${name2}.wants'/ + '') unit.wantedBy) units)} + + ${concatStrings (mapAttrsToList (name: unit: + concatMapStrings (name2: '' + mkdir -p $out/'${name2}.requires' + ln -sfn '../${name}' $out/'${name2}.requires'/ + '') unit.requiredBy) units)} + + ${optionalString (type == "system") '' + # Stupid misc. symlinks. + ln -s ${cfg.defaultUnit} $out/default.target + + ln -s rescue.target $out/kbrequest.target + + mkdir -p $out/getty.target.wants/ + ln -s ../autovt@tty1.service $out/getty.target.wants/ + + ln -s ../local-fs.target ../remote-fs.target ../network.target \ + ../nss-lookup.target ../nss-user-lookup.target ../swap.target \ + $out/multi-user.target.wants/ + ''} + ''; # */ + +} diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix index 2f4786c7896..785634cbf66 100644 --- a/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixos/modules/system/boot/systemd-unit-options.nix @@ -62,126 +62,7 @@ let ]) ]; - checkLink = checkUnitConfig "Link" [ - (assertOnlyFields [ - "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name" - "MTUBytes" "BitsPerSecond" "Duplex" "WakeOnLan" - ]) - (assertValueOneOf "MACAddressPolicy" ["persistent" "random"]) - (assertMacAddress "MACAddress") - (assertValueOneOf "NamePolicy" [ - "kernel" "database" "onboard" "slot" "path" "mac" - ]) - (assertByteFormat "MTUBytes") - (assertByteFormat "BitsPerSecond") - (assertValueOneOf "Duplex" ["half" "full"]) - (assertValueOneOf "WakeOnLan" ["phy" "magic" "off"]) - ]; - - checkNetdev = checkUnitConfig "Netdev" [ - (assertOnlyFields [ - "Description" "Name" "Kind" "MTUBytes" "MACAddress" - ]) - (assertHasField "Name") - (assertHasField "Kind") - (assertValueOneOf "Kind" [ - "bridge" "bond" "vlan" "macvlan" "vxlan" "ipip" - "gre" "sit" "vti" "veth" "tun" "tap" "dummy" - ]) - (assertByteFormat "MTUBytes") - (assertMacAddress "MACAddress") - ]; - - checkVlan = checkUnitConfig "VLAN" [ - (assertOnlyFields ["Id"]) - (assertRange "Id" 0 4094) - ]; - - checkMacvlan = checkUnitConfig "MACVLAN" [ - (assertOnlyFields ["Mode"]) - (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"]) - ]; - - checkVxlan = checkUnitConfig "VXLAN" [ - (assertOnlyFields ["Id" "Group" "TOS" "TTL" "MacLearning"]) - (assertRange "TTL" 0 255) - (assertValueOneOf "MacLearning" boolValues) - ]; - - checkTunnel = checkUnitConfig "Tunnel" [ - (assertOnlyFields ["Local" "Remote" "TOS" "TTL" "DiscoverPathMTU"]) - (assertRange "TTL" 0 255) - (assertValueOneOf "DiscoverPathMTU" boolValues) - ]; - - checkPeer = checkUnitConfig "Peer" [ - (assertOnlyFields ["Name" "MACAddress"]) - (assertMacAddress "MACAddress") - ]; - - tunTapChecks = [ - (assertOnlyFields ["OneQueue" "MultiQueue" "PacketInfo" "User" "Group"]) - (assertValueOneOf "OneQueue" boolValues) - (assertValueOneOf "MultiQueue" boolValues) - (assertValueOneOf "PacketInfo" boolValues) - ]; - - checkTun = checkUnitConfig "Tun" tunTapChecks; - - checkTap = checkUnitConfig "Tap" tunTapChecks; - - checkBond = checkUnitConfig "Bond" [ - (assertOnlyFields [ - "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec" - "UpDelaySec" "DownDelaySec" - ]) - (assertValueOneOf "Mode" [ - "balance-rr" "active-backup" "balance-xor" - "broadcast" "802.3ad" "balance-tlb" "balance-alb" - ]) - (assertValueOneOf "TransmitHashPolicy" [ - "layer2" "layer3+4" "layer2+3" "encap2+3" "802.3ad" "encap3+4" - ]) - (assertValueOneOf "LACPTransmitRate" ["slow" "fast"]) - ]; - - checkNetwork = checkUnitConfig "Network" [ - (assertOnlyFields [ - "Description" "DHCP" "DHCPServer" "IPv4LL" "IPv4LLRoute" - "LLMNR" "Domains" "Bridge" "Bond" - ]) - (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"]) - (assertValueOneOf "DHCPServer" boolValues) - (assertValueOneOf "IPv4LL" boolValues) - (assertValueOneOf "IPv4LLRoute" boolValues) - (assertValueOneOf "LLMNR" boolValues) - ]; - - checkAddress = checkUnitConfig "Address" [ - (assertOnlyFields ["Address" "Peer" "Broadcast" "Label"]) - (assertHasField "Address") - ]; - - checkRoute = checkUnitConfig "Route" [ - (assertOnlyFields ["Gateway" "Destination" "Metric"]) - (assertHasField "Gateway") - ]; - - checkDhcp = checkUnitConfig "DHCP" [ - (assertOnlyFields [ - "UseDNS" "UseMTU" "SendHostname" "UseHostname" "UseDomains" "UseRoutes" - "CriticalConnections" "VendorClassIdentifier" "RequestBroadcast" - "RouteMetric" - ]) - (assertValueOneOf "UseDNS" boolValues) - (assertValueOneOf "UseMTU" boolValues) - (assertValueOneOf "SendHostname" boolValues) - (assertValueOneOf "UseHostname" boolValues) - (assertValueOneOf "UseDomains" boolValues) - (assertValueOneOf "UseRoutes" boolValues) - (assertValueOneOf "CriticalConnections" boolValues) - (assertValueOneOf "RequestBroadcast" boolValues) - ]; +in rec { unitOption = mkOptionType { name = "systemd option"; @@ -195,8 +76,6 @@ let else mergeOneOption loc defs'; }; -in rec { - sharedOptions = { enable = mkOption { @@ -619,345 +498,4 @@ in rec { targetOptions = commonUnitOptions; - commonNetworkOptions = { - - enable = mkOption { - default = true; - type = types.bool; - description = '' - If set to false, this unit will be a symlink to - /dev/null. - ''; - }; - - matchConfig = mkOption { - default = {}; - example = { Name = "eth0"; }; - type = types.attrsOf unitOption; - description = '' - Each attribute in this set specifies an option in the - <literal>[Match]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry> - <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry> - <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> - for details. - ''; - }; - - }; - - linkOptions = commonNetworkOptions // { - - linkConfig = mkOption { - default = {}; - example = { MACAddress = "00:ff:ee:aa:cc:dd"; }; - type = types.addCheck (types.attrsOf unitOption) checkLink; - description = '' - Each attribute in this set specifies an option in the - <literal>[Link]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.link</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - }; - - netdevOptions = commonNetworkOptions // { - - netdevConfig = mkOption { - default = {}; - example = { Name = "mybridge"; Kind = "bridge"; }; - type = types.addCheck (types.attrsOf unitOption) checkNetdev; - description = '' - Each attribute in this set specifies an option in the - <literal>[Netdev]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - vlanConfig = mkOption { - default = {}; - example = { Id = "4"; }; - type = types.addCheck (types.attrsOf unitOption) checkVlan; - description = '' - Each attribute in this set specifies an option in the - <literal>[VLAN]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - macvlanConfig = mkOption { - default = {}; - example = { Mode = "private"; }; - type = types.addCheck (types.attrsOf unitOption) checkMacvlan; - description = '' - Each attribute in this set specifies an option in the - <literal>[MACVLAN]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - vxlanConfig = mkOption { - default = {}; - example = { Id = "4"; }; - type = types.addCheck (types.attrsOf unitOption) checkVxlan; - description = '' - Each attribute in this set specifies an option in the - <literal>[VXLAN]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - tunnelConfig = mkOption { - default = {}; - example = { Remote = "192.168.1.1"; }; - type = types.addCheck (types.attrsOf unitOption) checkTunnel; - description = '' - Each attribute in this set specifies an option in the - <literal>[Tunnel]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - peerConfig = mkOption { - default = {}; - example = { Name = "veth2"; }; - type = types.addCheck (types.attrsOf unitOption) checkPeer; - description = '' - Each attribute in this set specifies an option in the - <literal>[Peer]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - tunConfig = mkOption { - default = {}; - example = { User = "openvpn"; }; - type = types.addCheck (types.attrsOf unitOption) checkTun; - description = '' - Each attribute in this set specifies an option in the - <literal>[Tun]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - tapConfig = mkOption { - default = {}; - example = { User = "openvpn"; }; - type = types.addCheck (types.attrsOf unitOption) checkTap; - description = '' - Each attribute in this set specifies an option in the - <literal>[Tap]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - bondConfig = mkOption { - default = {}; - example = { Mode = "802.3ad"; }; - type = types.addCheck (types.attrsOf unitOption) checkBond; - description = '' - Each attribute in this set specifies an option in the - <literal>[Bond]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.netdev</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - }; - - addressOptions = { - - addressConfig = mkOption { - default = {}; - example = { Address = "192.168.0.100/24"; }; - type = types.addCheck (types.attrsOf unitOption) checkAddress; - description = '' - Each attribute in this set specifies an option in the - <literal>[Address]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - }; - - routeOptions = { - - routeConfig = mkOption { - default = {}; - example = { Gateway = "192.168.0.1"; }; - type = types.addCheck (types.attrsOf unitOption) checkRoute; - description = '' - Each attribute in this set specifies an option in the - <literal>[Route]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - }; - - networkOptions = commonNetworkOptions // { - - networkConfig = mkOption { - default = {}; - example = { Description = "My Network"; }; - type = types.addCheck (types.attrsOf unitOption) checkNetwork; - description = '' - Each attribute in this set specifies an option in the - <literal>[Network]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - dhcpConfig = mkOption { - default = {}; - example = { UseDNS = true; UseRoutes = true; }; - type = types.addCheck (types.attrsOf unitOption) checkDhcp; - description = '' - Each attribute in this set specifies an option in the - <literal>[DHCP]</literal> section of the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - name = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - The name of the network interface to match against. - ''; - }; - - DHCP = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Whether to enable DHCP on the interfaces matched. - ''; - }; - - domains = mkOption { - type = types.nullOr (types.listOf types.str); - default = null; - description = '' - A list of domains to pass to the network config. - ''; - }; - - address = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of addresses to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - gateway = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of gateways to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - dns = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of dns servers to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - ntp = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of ntp servers to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - vlan = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of vlan interfaces to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - macvlan = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of macvlan interfaces to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - vxlan = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of vxlan interfaces to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - tunnel = mkOption { - default = [ ]; - type = types.listOf types.str; - description = '' - A list of tunnel interfaces to be added to the network section of the - unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - addresses = mkOption { - default = [ ]; - type = types.listOf types.optionSet; - options = [ addressOptions ]; - description = '' - A list of address sections to be added to the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - routes = mkOption { - default = [ ]; - type = types.listOf types.optionSet; - options = [ routeOptions ]; - description = '' - A list of route sections to be added to the unit. See - <citerefentry><refentrytitle>systemd.network</refentrytitle> - <manvolnum>5</manvolnum></citerefentry> for details. - ''; - }; - - }; - } diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 29c449d4d0b..78aac7fe96f 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -3,6 +3,7 @@ with utils; with lib; with import ./systemd-unit-options.nix { inherit config lib; }; +with import ./systemd-lib.nix { inherit config lib pkgs; }; let @@ -10,24 +11,6 @@ let systemd = cfg.package; - - makeUnit = name: unit: - let - pathSafeName = lib.replaceChars ["@" ":" "\\"] ["-" "-" "-"] name; - in - if unit.enable then - pkgs.runCommand "unit-${pathSafeName}" { preferLocalBuild = true; inherit (unit) text; } - '' - mkdir -p $out - echo -n "$text" > $out/${shellEscape name} - '' - else - pkgs.runCommand "unit-${pathSafeName}-disabled" { preferLocalBuild = true; } - '' - mkdir -p $out - ln -s /dev/null $out/${shellEscape name} - ''; - upstreamSystemUnits = [ # Targets. "basic.target" @@ -97,12 +80,6 @@ let "systemd-modules-load.service" "kmod-static-nodes.service" - # Networking - "systemd-networkd.service" - "systemd-networkd-wait-online.service" - "systemd-resolved.service" - "systemd-timesyncd.service" - # Filesystems. "systemd-fsck@.service" "systemd-fsck-root.service" @@ -196,8 +173,6 @@ let "timers.target" ]; - shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s); - makeJobScript = name: text: let x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${shellEscape name}"; inherit text; }; in "${x}/bin/${shellEscape name}"; @@ -301,19 +276,6 @@ let }; }; - networkConfig = { name, config, ... }: { - config = { - matchConfig = optionalAttrs (config.name != null) { - Name = config.name; - }; - networkConfig = optionalAttrs (config.DHCP != null) { - DHCP = config.DHCP; - } // optionalAttrs (config.domains != null) { - Domains = concatStringsSep " " config.domains; - }; - }; - }; - toOption = x: if x == true then "true" else if x == false then "false" @@ -412,188 +374,6 @@ let ${attrsToSection def.matchConfig} ''; - linkToUnit = name: def: - { inherit (def) enable; - text = commonMatchText def + - '' - [Link] - ${attrsToSection def.linkConfig} - ''; - }; - - netdevToUnit = name: def: - { inherit (def) enable; - 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} - - ''} - ''; - }; - - networkToUnit = name: def: - { inherit (def) enable; - text = commonMatchText def + - '' - [Network] - ${attrsToSection def.networkConfig} - ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)} - ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)} - ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)} - ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)} - ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)} - ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)} - ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)} - ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)} - - ${optionalString (def.dhcpConfig != { }) '' - [DHCP] - ${attrsToSection def.dhcpConfig} - - ''} - ${flip concatMapStrings def.addresses (x: '' - [Address] - ${attrsToSection x.addressConfig} - - '')} - ${flip concatMapStrings def.routes (x: '' - [Route] - ${attrsToSection x.routeConfig} - - '')} - ''; - }; - - generateUnits = type: units: upstreamUnits: upstreamWants: - pkgs.runCommand "${type}-units" { preferLocalBuild = true; } '' - mkdir -p $out - - # Copy the upstream systemd units we're interested in. - for i in ${toString upstreamUnits}; do - fn=${systemd}/example/systemd/${type}/$i - if ! [ -e $fn ]; then echo "missing $fn"; false; fi - if [ -L $fn ]; then - target="$(readlink "$fn")" - if [ ''${target:0:3} = ../ ]; then - ln -s "$(readlink -f "$fn")" $out/ - else - cp -pd $fn $out/ - fi - else - ln -s $fn $out/ - fi - done - - # Copy .wants links, but only those that point to units that - # we're interested in. - for i in ${toString upstreamWants}; do - fn=${systemd}/example/systemd/${type}/$i - if ! [ -e $fn ]; then echo "missing $fn"; false; fi - x=$out/$(basename $fn) - mkdir $x - for i in $fn/*; do - y=$x/$(basename $i) - cp -pd $i $y - if ! [ -e $y ]; then rm $y; fi - done - done - - # Symlink all units provided listed in systemd.packages. - for i in ${toString cfg.packages}; do - for fn in $i/etc/systemd/${type}/* $i/lib/systemd/${type}/*; do - if ! [[ "$fn" =~ .wants$ ]]; then - ln -s $fn $out/ - fi - done - done - - # Symlink all units defined by systemd.units. If these are also - # provided by systemd or systemd.packages, then add them as - # <unit-name>.d/overrides.conf, which makes them extend the - # upstream unit. - for i in ${toString (mapAttrsToList (n: v: v.unit) units)}; do - fn=$(basename $i/*) - if [ -e $out/$fn ]; then - if [ "$(readlink -f $i/$fn)" = /dev/null ]; then - ln -sfn /dev/null $out/$fn - else - mkdir $out/$fn.d - ln -s $i/$fn $out/$fn.d/overrides.conf - fi - else - ln -fs $i/$fn $out/ - fi - done - - # Created .wants and .requires symlinks from the wantedBy and - # requiredBy options. - ${concatStrings (mapAttrsToList (name: unit: - concatMapStrings (name2: '' - mkdir -p $out/'${name2}.wants' - ln -sfn '../${name}' $out/'${name2}.wants'/ - '') unit.wantedBy) units)} - - ${concatStrings (mapAttrsToList (name: unit: - concatMapStrings (name2: '' - mkdir -p $out/'${name2}.requires' - ln -sfn '../${name}' $out/'${name2}.requires'/ - '') unit.requiredBy) units)} - - ${optionalString (type == "system") '' - # Stupid misc. symlinks. - ln -s ${cfg.defaultUnit} $out/default.target - - ln -s rescue.target $out/kbrequest.target - - mkdir -p $out/getty.target.wants/ - ln -s ../autovt@tty1.service $out/getty.target.wants/ - - ln -s ../local-fs.target ../remote-fs.target ../network.target \ - ../nss-lookup.target ../nss-user-lookup.target ../swap.target \ - $out/multi-user.target.wants/ - ''} - ''; # */ - in { @@ -683,47 +463,6 @@ in ''; }; - systemd.network.enable = mkOption { - default = false; - type = types.bool; - description = '' - Whether to enable networkd or not. - ''; - }; - - systemd.network.links = mkOption { - default = {}; - type = types.attrsOf types.optionSet; - options = [ linkOptions ]; - description = "Definition of systemd network links."; - }; - - systemd.network.netdevs = mkOption { - default = {}; - type = types.attrsOf types.optionSet; - options = [ netdevOptions ]; - description = "Definition of systemd network devices."; - }; - - systemd.network.networks = mkOption { - default = {}; - type = types.attrsOf types.optionSet; - options = [ networkOptions networkConfig ]; - description = "Definition of systemd networks."; - }; - - systemd.network.units = mkOption { - description = "Definition of networkd units."; - default = {}; - type = types.attrsOf types.optionSet; - options = { name, config, ... }: - { options = concreteUnitOptions; - config = { - unit = mkDefault (makeUnit name config); - }; - }; - }; - systemd.defaultUnit = mkOption { default = "multi-user.target"; type = types.str; @@ -807,22 +546,6 @@ in ''; }; - services.resolved.enable = mkOption { - default = false; - type = types.bool; - description = '' - Enables the systemd dns resolver daemon. - ''; - }; - - services.timesyncd.enable = mkOption { - default = false; - type = types.bool; - description = '' - Enables the systemd ntp client daemon. - ''; - }; - systemd.tmpfiles.rules = mkOption { type = types.listOf types.str; default = []; @@ -886,7 +609,7 @@ in ###### implementation - config = mkMerge [ { + config = { warnings = concatLists (mapAttrsToList (name: service: optional (service.serviceConfig.Type or "" == "oneshot" && service.serviceConfig.Restart or "no" != "no") @@ -899,9 +622,6 @@ in environment.etc."systemd/system".source = generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants; - environment.etc."systemd/network".source = - generateUnits "network" cfg.network.units [] []; - environment.etc."systemd/user".source = generateUnits "user" cfg.user.units upstreamUserUnits []; @@ -979,11 +699,6 @@ in (v: let n = escapeSystemdPath v.where; in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts); - systemd.network.units = - mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.network.links - // mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.network.netdevs - // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.network.networks; - systemd.user.units = mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.user.sockets @@ -1006,15 +721,6 @@ in users.extraUsers.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway; users.extraGroups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway; - users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; - users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network; - - users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve; - users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve; - - users.extraUsers.systemd-timesync.uid = config.ids.uids.systemd-timesync; - users.extraGroups.systemd-timesync.gid = config.ids.gids.systemd-timesync; - # Generate timer units for all services that have a ‘startAt’ value. systemd.timers = mapAttrs (name: service: @@ -1053,57 +759,6 @@ in systemd.services.systemd-remount-fs.restartIfChanged = false; systemd.services.systemd-journal-flush.restartIfChanged = false; - } - (mkIf config.systemd.network.enable { - systemd.services.systemd-networkd = { - wantedBy = [ "multi-user.target" ]; - before = [ "network-interfaces.target" ]; - restartTriggers = [ config.environment.etc."systemd/network".source ]; - }; - - systemd.services.systemd-networkd-wait-online = { - before = [ "network-online.target" "ip-up.target" ]; - wantedBy = [ "network-online.target" "ip-up.target" ]; - }; - - systemd.services."systemd-network-wait-online@" = { - description = "Wait for Network Interface %I to be Configured"; - conflicts = [ "shutdown.target" ]; - requisite = [ "systemd-networkd.service" ]; - after = [ "systemd-networkd.service" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I"; - }; - }; - - services.resolved.enable = mkDefault true; - services.timesyncd.enable = mkDefault config.services.ntp.enable; - }) - (mkIf config.services.resolved.enable { - systemd.services.systemd-resolved = { - wantedBy = [ "multi-user.target" ]; - restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ]; - }; - - environment.etc."systemd/resolved.conf".text = '' - [Resolve] - DNS=${concatStringsSep " " config.networking.nameservers} - ''; - }) - (mkIf config.services.timesyncd.enable { - systemd.services.systemd-timesyncd = { - wantedBy = [ "sysinit.target" ]; - restartTriggers = [ config.environment.etc."systemd/timesyncd.conf".source ]; - }; - - environment.etc."systemd/timesyncd.conf".text = '' - [Time] - NTP=${concatStringsSep " " config.services.ntp.servers} - ''; + }; - systemd.services.ntpd.enable = false; - }) - ]; } diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix new file mode 100644 index 00000000000..cba965b1cd2 --- /dev/null +++ b/nixos/modules/system/boot/timesyncd.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + + options = { + + services.timesyncd.enable = mkOption { + default = false; + type = types.bool; + description = '' + Enables the systemd NTP client daemon. + ''; + }; + + }; + + config = mkIf config.services.timesyncd.enable { + + systemd.additionalUpstreamSystemUnits = [ "systemd-timesyncd.service" ]; + + systemd.services.systemd-timesyncd = { + wantedBy = [ "sysinit.target" ]; + restartTriggers = [ config.environment.etc."systemd/timesyncd.conf".source ]; + }; + + environment.etc."systemd/timesyncd.conf".text = '' + [Time] + NTP=${concatStringsSep " " config.services.ntp.servers} + ''; + + systemd.services.ntpd.enable = false; + + users.extraUsers.systemd-timesync.uid = config.ids.uids.systemd-timesync; + users.extraGroups.systemd-timesync.gid = config.ids.gids.systemd-timesync; + + }; + +} diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index c6f2f072352..ce8d6079faa 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -137,9 +137,7 @@ in # Add the mount helpers to the system path so that `mount' can find them. system.fsPackages = [ pkgs.dosfstools ]; - environment.systemPackages = - [ pkgs.ntfs3g pkgs.fuse ] - ++ config.system.fsPackages; + environment.systemPackages = [ pkgs.fuse ] ++ config.system.fsPackages; environment.etc.fstab.text = let diff --git a/nixos/modules/tasks/filesystems/cifs.nix b/nixos/modules/tasks/filesystems/cifs.nix index 3932b5c9acf..a928fcae415 100644 --- a/nixos/modules/tasks/filesystems/cifs.nix +++ b/nixos/modules/tasks/filesystems/cifs.nix @@ -11,7 +11,7 @@ in { config = { - system.fsPackages = [ pkgs.cifs_utils ]; + system.fsPackages = mkIf (any (fs: fs == "cifs") config.boot.supportedFilesystems) [ pkgs.cifs_utils ]; boot.initrd.availableKernelModules = mkIf inInitrd [ "cifs" "nls_utf8" "hmac" "md4" "ecb" "des_generic" "sha256" ]; diff --git a/nixos/modules/tasks/filesystems/ntfs.nix b/nixos/modules/tasks/filesystems/ntfs.nix new file mode 100644 index 00000000000..c40d2a1a80b --- /dev/null +++ b/nixos/modules/tasks/filesystems/ntfs.nix @@ -0,0 +1,11 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + config = mkIf (any (fs: fs == "ntfs" || fs == "ntfs-3g") config.boot.supportedFilesystems) { + + system.fsPackages = [ pkgs.ntfs3g ]; + + }; +} diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index fd545a723e7..328d94cbb05 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -107,7 +107,7 @@ in ips = interfaceIps i; in nameValuePair "network-addresses-${i.name}" - { description = "Addresss configuration of ${i.name}"; + { description = "Address configuration of ${i.name}"; wantedBy = [ "network-interfaces.target" ]; before = [ "network-interfaces.target" ]; bindsTo = [ (subsystemDevice i.name) ]; diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index a7e8953827a..67047541102 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -9,6 +9,7 @@ with lib; # Disable some features that are not useful in a container. sound.enable = mkDefault false; services.udisks2.enable = mkDefault false; + powerManagement.enable = mkDefault false; networking.useHostResolvConf = true; @@ -20,6 +21,8 @@ with lib; systemd.services.systemd-remount-fs.enable = false; + systemd.services.systemd-random-seed.enable = false; + }; } diff --git a/nixos/modules/virtualisation/docker-image.nix b/nixos/modules/virtualisation/docker-image.nix index 0195ca5c6dc..9535e3e0d67 100644 --- a/nixos/modules/virtualisation/docker-image.nix +++ b/nixos/modules/virtualisation/docker-image.nix @@ -2,7 +2,7 @@ { imports = [ - ../profiles/container.nix + ../profiles/docker-container.nix # FIXME, shouldn't include something from profiles/ ]; boot.postBootCommands = diff --git a/nixos/modules/virtualisation/google-compute-config.nix b/nixos/modules/virtualisation/google-compute-config.nix index 9e6be93b6d9..f6bca1aa857 100644 --- a/nixos/modules/virtualisation/google-compute-config.nix +++ b/nixos/modules/virtualisation/google-compute-config.nix @@ -1,5 +1,5 @@ -{ config, pkgs, modulesPath, ... }: +{ config, pkgs, ... }: { - imports = [ "${modulesPath}/virtualisation/google-compute-image.nix" ]; + imports = [ <nixpkgs/nixos/modules/virtualisation/google-compute-image.nix> ]; } diff --git a/nixos/modules/virtualisation/lxc-container.nix b/nixos/modules/virtualisation/lxc-container.nix index 2fa749d542e..0208787e779 100644 --- a/nixos/modules/virtualisation/lxc-container.nix +++ b/nixos/modules/virtualisation/lxc-container.nix @@ -4,7 +4,7 @@ with lib; { imports = [ - ../profiles/container.nix + ../profiles/docker-container.nix # FIXME, shouldn't include something from profiles/ ]; # Allow the user to login as root without password. diff --git a/nixos/tests/gnome3_16.nix b/nixos/tests/gnome3_16.nix new file mode 100644 index 00000000000..23a66aba50c --- /dev/null +++ b/nixos/tests/gnome3_16.nix @@ -0,0 +1,34 @@ +import ./make-test.nix { + name = "gnome3"; + + machine = + { config, pkgs, ... }: + + { imports = [ ./common/user-account.nix ]; + + services.xserver.enable = true; + + services.xserver.displayManager.auto.enable = true; + services.xserver.displayManager.auto.user = "alice"; + services.xserver.desktopManager.gnome3.enable = true; + + environment.gnome3.packageSet = pkgs.gnome3_16; + + virtualisation.memorySize = 512; + }; + + testScript = + '' + $machine->waitForX; + $machine->sleep(15); + + # Check that logging in has given the user ownership of devices. + $machine->succeed("getfacl /dev/snd/timer | grep -q alice"); + + $machine->succeed("su - alice -c 'DISPLAY=:0.0 gnome-terminal &'"); + $machine->waitForWindow(qr/Terminal/); + $machine->sleep(20); + $machine->screenshot("screen"); + ''; + +} diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 46d0422f9c6..2ea96ecb7ca 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -64,26 +64,26 @@ import ./make-test.nix ({ networkd, test, ... }: $client->fail("systemctl status dhcpcd.service"); # Test vlan 1 - $client->succeed("ping -c 1 192.168.1.1"); - $client->succeed("ping -c 1 192.168.1.2"); - $client->succeed("ping -c 1 192.168.1.3"); - $client->succeed("ping -c 1 192.168.1.10"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.10"); - $router->succeed("ping -c 1 192.168.1.1"); - $router->succeed("ping -c 1 192.168.1.2"); - $router->succeed("ping -c 1 192.168.1.3"); - $router->succeed("ping -c 1 192.168.1.10"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.10"); # Test vlan 2 - $client->succeed("ping -c 1 192.168.2.1"); - $client->succeed("ping -c 1 192.168.2.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); - $router->succeed("ping -c 1 192.168.2.1"); - $router->succeed("ping -c 1 192.168.2.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); # Test default gateway - $router->succeed("ping -c 1 192.168.3.1"); - $client->succeed("ping -c 1 192.168.3.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.3.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.3.1"); ''; }; dhcpSimple = { @@ -109,22 +109,22 @@ import ./make-test.nix ({ networkd, test, ... }: $router->waitForUnit("network.target"); # Wait until we have an ip address on each interface - $client->succeed("while ! ip addr show dev eth1 | grep '192.168.1'; do true; done"); - $client->succeed("while ! ip addr show dev eth2 | grep '192.168.2'; do true; done"); + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); + $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'"); # Test vlan 1 - $client->succeed("ping -c 1 192.168.1.1"); - $client->succeed("ping -c 1 192.168.1.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->succeed("ping -c 1 192.168.1.1"); - $router->succeed("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); # Test vlan 2 - $client->succeed("ping -c 1 192.168.2.1"); - $client->succeed("ping -c 1 192.168.2.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); - $router->succeed("ping -c 1 192.168.2.1"); - $router->succeed("ping -c 1 192.168.2.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); ''; }; dhcpOneIf = { @@ -147,26 +147,27 @@ import ./make-test.nix ({ networkd, test, ... }: '' startAll; + # Wait for networking to come up $client->waitForUnit("network-interfaces.target"); $client->waitForUnit("network.target"); $router->waitForUnit("network-interfaces.target"); $router->waitForUnit("network.target"); # Wait until we have an ip address on each interface - $client->succeed("while ! ip addr show dev eth1 | grep '192.168.1'; do true; done"); + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); # Test vlan 1 - $client->succeed("ping -c 1 192.168.1.1"); - $client->succeed("ping -c 1 192.168.1.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->succeed("ping -c 1 192.168.1.1"); - $router->succeed("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); # Test vlan 2 - $client->succeed("ping -c 1 192.168.2.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); $client->fail("ping -c 1 192.168.2.2"); - $router->succeed("ping -c 1 192.168.2.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); $router->fail("ping -c 1 192.168.2.2"); ''; }; @@ -195,17 +196,18 @@ import ./make-test.nix ({ networkd, test, ... }: '' startAll; + # Wait for networking to come up $client1->waitForUnit("network-interfaces.target"); $client1->waitForUnit("network.target"); $client2->waitForUnit("network-interfaces.target"); $client2->waitForUnit("network.target"); # Test bonding - $client1->succeed("ping -c 2 192.168.1.1"); - $client1->succeed("ping -c 2 192.168.1.2"); + $client1->waitUntilSucceeds("ping -c 2 192.168.1.1"); + $client1->waitUntilSucceeds("ping -c 2 192.168.1.2"); - $client2->succeed("ping -c 2 192.168.1.1"); - $client2->succeed("ping -c 2 192.168.1.2"); + $client2->waitUntilSucceeds("ping -c 2 192.168.1.1"); + $client2->waitUntilSucceeds("ping -c 2 192.168.1.2"); ''; }; bridge = let @@ -240,6 +242,7 @@ import ./make-test.nix ({ networkd, test, ... }: '' startAll; + # Wait for networking to come up $client1->waitForUnit("network-interfaces.target"); $client1->waitForUnit("network.target"); $client2->waitForUnit("network-interfaces.target"); @@ -248,17 +251,17 @@ import ./make-test.nix ({ networkd, test, ... }: $router->waitForUnit("network.target"); # Test bridging - $client1->succeed("ping -c 1 192.168.1.1"); - $client1->succeed("ping -c 1 192.168.1.2"); - $client1->succeed("ping -c 1 192.168.1.3"); + $client1->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client1->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client1->waitUntilSucceeds("ping -c 1 192.168.1.3"); - $client2->succeed("ping -c 1 192.168.1.1"); - $client2->succeed("ping -c 1 192.168.1.2"); - $client2->succeed("ping -c 1 192.168.1.3"); + $client2->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client2->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client2->waitUntilSucceeds("ping -c 1 192.168.1.3"); - $router->succeed("ping -c 1 192.168.1.1"); - $router->succeed("ping -c 1 192.168.1.2"); - $router->succeed("ping -c 1 192.168.1.3"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); ''; }; macvlan = { @@ -278,23 +281,28 @@ import ./make-test.nix ({ networkd, test, ... }: '' startAll; + # Wait for networking to come up $client->waitForUnit("network-interfaces.target"); $client->waitForUnit("network.target"); $router->waitForUnit("network-interfaces.target"); $router->waitForUnit("network.target"); # Wait until we have an ip address on each interface - $client->succeed("while ! ip addr show dev eth1 | grep '192.168.1'; do true; done"); - $client->succeed("while ! ip addr show dev macvlan | grep '192.168.1'; do true; done"); + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); + $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'"); - # Test macvlan - $client->succeed("ping -c 1 192.168.1.1"); - $client->succeed("ping -c 1 192.168.1.2"); - $client->succeed("ping -c 1 192.168.1.3"); + # Print diagnosting information + $router->succeed("ip addr >&2"); + $client->succeed("ip addr >&2"); - $router->succeed("ping -c 1 192.168.1.1"); - $router->succeed("ping -c 1 192.168.1.2"); - $router->succeed("ping -c 1 192.168.1.3"); + # Test macvlan creates routable ips + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); + + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); ''; }; sit = let @@ -323,20 +331,22 @@ import ./make-test.nix ({ networkd, test, ... }: '' startAll; + # Wait for networking to be configured $client1->waitForUnit("network-interfaces.target"); $client1->waitForUnit("network.target"); $client2->waitForUnit("network-interfaces.target"); $client2->waitForUnit("network.target"); + # Print diagnostic information $client1->succeed("ip addr >&2"); $client2->succeed("ip addr >&2"); # Test ipv6 - $client1->succeed("ping6 -c 1 fc00::1"); - $client1->succeed("ping6 -c 1 fc00::2"); + $client1->waitUntilSucceeds("ping6 -c 1 fc00::1"); + $client1->waitUntilSucceeds("ping6 -c 1 fc00::2"); - $client2->succeed("ping6 -c 1 fc00::1"); - $client2->succeed("ping6 -c 1 fc00::2"); + $client2->waitUntilSucceeds("ping6 -c 1 fc00::1"); + $client2->waitUntilSucceeds("ping6 -c 1 fc00::2"); ''; }; vlan = let @@ -364,6 +374,7 @@ import ./make-test.nix ({ networkd, test, ... }: '' startAll; + # Wait for networking to be configured $client1->waitForUnit("network-interfaces.target"); $client1->waitForUnit("network.target"); $client2->waitForUnit("network-interfaces.target"); |