about summary refs log tree commit diff
path: root/nixos/modules/system
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-04-17 18:52:31 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-04-17 18:52:31 +0200
commit179acfb664ed06519ac515eada7bbef677cbee87 (patch)
tree76c599294fe8ce8530b92c8a36f9b2adc7ee0595 /nixos/modules/system
parent8dcf76480c34520997816d1bf4cfd68c6280ebbd (diff)
downloadnixlib-179acfb664ed06519ac515eada7bbef677cbee87.tar
nixlib-179acfb664ed06519ac515eada7bbef677cbee87.tar.gz
nixlib-179acfb664ed06519ac515eada7bbef677cbee87.tar.bz2
nixlib-179acfb664ed06519ac515eada7bbef677cbee87.tar.lz
nixlib-179acfb664ed06519ac515eada7bbef677cbee87.tar.xz
nixlib-179acfb664ed06519ac515eada7bbef677cbee87.tar.zst
nixlib-179acfb664ed06519ac515eada7bbef677cbee87.zip
Allow upstream systemd units to be extended
If you define a unit, and either systemd or a package in
systemd.packages already provides that unit, then we now generate a
file /etc/systemd/system/<unit>.d/overrides.conf. This makes it
possible to use upstream units, while allowing them to be customised
from the NixOS configuration. For instance, the module nix-daemon.nix
now uses the units provided by the Nix package. And all unit
definitions that duplicated upstream systemd units are finally gone.

This makes the baseUnit option unnecessary, so I've removed it.
Diffstat (limited to 'nixos/modules/system')
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl10
-rw-r--r--nixos/modules/system/boot/kernel.nix33
-rw-r--r--nixos/modules/system/boot/systemd-unit-options.nix6
-rw-r--r--nixos/modules/system/boot/systemd.nix59
4 files changed, 61 insertions, 47 deletions
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index fd2b5b7950d5..13bd0b60f820 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -115,6 +115,14 @@ sub boolIsTrue {
     return $s eq "yes" || $s eq "true";
 }
 
+# As a fingerprint for determining whether a unit has changed, we use
+# its absolute path. If it has an override file, we append *its*
+# absolute path as well.
+sub fingerprintUnit {
+    my ($s) = @_;
+    return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
+}
+
 # Stop all services that no longer exist or have changed in the new
 # configuration.
 my (@unitsToStop, @unitsToSkip);
@@ -166,7 +174,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
             }
         }
 
-        elsif (abs_path($prevUnitFile) ne abs_path($newUnitFile)) {
+        elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
             if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") {
                 # Do nothing.  These cannot be restarted directly.
             } elsif ($unit =~ /\.mount$/) {
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index 2e036fafae60..5e5b2abbb9ca 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -147,12 +147,6 @@ in
 
   config = mkIf (!config.boot.isContainer) {
 
-    systemd.services.kmod-static-nodes =
-      { wantedBy = [ "sysinit.target" ];
-        baseUnit = "${config.systemd.package}/example/systemd/system/kmod-static-nodes.service";
-        environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules";
-      };
-
     system.build = { inherit kernel; };
 
     system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
@@ -224,37 +218,26 @@ in
 
     # Create /etc/modules-load.d/nixos.conf, which is read by
     # systemd-modules-load.service to load required kernel modules.
-    # FIXME: ensure that systemd-modules-load.service is restarted if
-    # this file changes.
     environment.etc = singleton
       { target = "modules-load.d/nixos.conf";
         source = kernelModulesConf;
       };
 
-    # Sigh.  This overrides systemd's systemd-modules-load.service
-    # just so we can set a restart trigger.  Also make
-    # multi-user.target pull it in so that it gets started if it
-    # failed earlier.
     systemd.services."systemd-modules-load" =
-      { description = "Load Kernel Modules";
-        wantedBy = [ "sysinit.target" "multi-user.target" ];
-        before = [ "sysinit.target" "shutdown.target" ];
-        conflicts = [ "shutdown.target" ];
-        unitConfig =
-          { DefaultDependencies = false;
-            ConditionCapability = "CAP_SYS_MODULE";
-          };
+      { wantedBy = [ "multi-user.target" ];
+        restartTriggers = [ kernelModulesConf ];
+        environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules";
         serviceConfig =
-          { Type = "oneshot";
-            RemainAfterExit = true;
-            ExecStart = "${config.systemd.package}/lib/systemd/systemd-modules-load";
-            # Ignore failed module loads.  Typically some of the
+          { # Ignore failed module loads.  Typically some of the
             # modules in ‘boot.kernelModules’ are "nice to have but
             # not required" (e.g. acpi-cpufreq), so we don't want to
             # barf on those.
             SuccessExitStatus = "0 1";
           };
-        restartTriggers = [ kernelModulesConf ];
+      };
+
+    systemd.services.kmod-static-nodes =
+      { wantedBy = [ "sysinit.target" ];
         environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules";
       };
 
diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix
index 20ea0ba874d6..a16263b390d7 100644
--- a/nixos/modules/system/boot/systemd-unit-options.nix
+++ b/nixos/modules/system/boot/systemd-unit-options.nix
@@ -41,12 +41,6 @@ in rec {
       '';
     };
 
-    baseUnit = mkOption {
-      type = types.nullOr types.path;
-      default = null;
-      description = "Path to an upstream unit file on which the NixOS unit configuration will be based.";
-    };
-
     description = mkOption {
       default = "";
       type = types.str;
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 5d144a3642bc..ee809a8ec44e 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -31,7 +31,6 @@ let
       "sockets.target"
       "graphical.target"
       "multi-user.target"
-      "getty.target"
       "network.target"
       "network-online.target"
       "nss-lookup.target"
@@ -50,10 +49,17 @@ let
       # Udev.
       "systemd-udevd-control.socket"
       "systemd-udevd-kernel.socket"
-      #"systemd-udevd.service"
+      "systemd-udevd.service"
       "systemd-udev-settle.service"
       "systemd-udev-trigger.service"
 
+      # Consoles.
+      "getty.target"
+      "getty@.service"
+      "serial-getty@.service"
+      "container-getty@.service"
+      "systemd-vconsole-setup.service"
+
       # Hardware (started by udev when a relevant device is plugged in).
       "sound.target"
       "bluetooth.target"
@@ -80,7 +86,8 @@ let
       "systemd-initctl.service"
 
       # Kernel module loading.
-      #"systemd-modules-load.service"
+      "systemd-modules-load.service"
+      "kmod-static-nodes.service"
 
       # Filesystems.
       "systemd-fsck@.service"
@@ -146,6 +153,9 @@ let
       "systemd-tmpfiles-clean.timer"
       "systemd-tmpfiles-setup.service"
       "systemd-tmpfiles-setup-dev.service"
+
+      # Misc.
+      "systemd-sysctl.service"
     ]
 
     ++ optionals cfg.enableEmergencyMode [
@@ -198,7 +208,7 @@ let
 
   serviceConfig = { name, config, ... }: {
     config = mkMerge
-      [ (mkIf (config.baseUnit == null) { # Default path for systemd services.  Should be quite minimal.
+      [ { # Default path for systemd services.  Should be quite minimal.
           path =
             [ pkgs.coreutils
               pkgs.findutils
@@ -207,7 +217,7 @@ let
               systemd
             ];
           environment.PATH = config.path;
-        })
+        }
         (mkIf (config.preStart != "")
           { serviceConfig.ExecStartPre = makeJobScript "${name}-pre-start" ''
               #! ${pkgs.stdenv.shell} -e
@@ -275,10 +285,7 @@ let
         (if isList value then value else [value]))
         as));
 
-  commonUnitText = def:
-    optionalString (def.baseUnit != null) ''
-      .include ${def.baseUnit}
-    '' + ''
+  commonUnitText = def: ''
       [Unit]
       ${attrsToSection def.unitConfig}
     '';
@@ -358,6 +365,8 @@ let
   units = pkgs.runCommand "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/system/$i
         if ! [ -e $fn ]; then echo "missing $fn"; false; fi
@@ -368,6 +377,8 @@ let
         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/system/$i
         if ! [ -e $fn ]; then echo "missing $fn"; false; fi
@@ -376,18 +387,35 @@ let
         for i in $fn/*; do
           y=$x/$(basename $i)
           cp -pd $i $y
-          if ! [ -e $y ]; then rm -v $y; fi
+          if ! [ -e $y ]; then rm $y; fi
         done
       done
 
-      for i in ${toString (mapAttrsToList (n: v: v.unit) cfg.units)}; do
-        ln -fs $i/* $out/
+      # Symlink all units provided listed in systemd.packages.
+      for i in ${toString cfg.packages}; do
+        ln -s $i/etc/systemd/system/* $i/lib/systemd/system/* $out/
       done
 
-      for i in ${toString cfg.packages}; do
-        ln -s $i/etc/systemd/system/* $out/
+      # 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) cfg.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'
@@ -400,6 +428,7 @@ let
             ln -sfn '../${name}' $out/'${name2}.requires'/
           '') unit.requiredBy) cfg.units)}
 
+      # Stupid misc. symlinks.
       ln -s ${cfg.defaultUnit} $out/default.target
 
       ln -s rescue.target $out/kbrequest.target
@@ -411,7 +440,7 @@ let
             ../nss-user-lookup.target ../swap.target $out/multi-user.target.wants/
 
       ${ optionalString config.services.journald.enableHttpGateway ''
-      ln -s ../systemd-journal-gatewayd.service $out/multi-user-target.wants/
+        ln -s ../systemd-journal-gatewayd.service $out/multi-user-target.wants/
       ''}
     ''; # */