Commit 5513c368 authored by Will Fancher's avatar Will Fancher
Browse files

nixos/power-management: Handle resume correctly with `sleep.target`

Fixes `nixos.tests.hibernate` nondeterministic failure.

The documentation in `systemd.special(7)` recommends using this
`StopWhenUnneeded` method, rather than using custom unit logic
post-resume. This method is sufficiently general, and matches
systemd's typical model of using `ExecStart` and `ExecStop` as duals
that mirror each others processes across symmetric events in the
system's life cycle, e.g. bootup / shutdown.

This involved removing `post-resume.target`. This was introduced in
d5604f0b as a way to notify services
of resume events, but as discussed, this is not the typical model.

See: https://github.com/NixOS/nixpkgs/pull/488429/changes#r3038005884
parent 6201e203
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -137,6 +137,8 @@

- `services.uptime` has been removed because the package it relies on does not exist anymore in nixpkgs.

- `post-resume.target` has been removed. See {manpage}`systemd.special(7)` about `sleep.target` for instructions on ordering a process after resume with `ExecStop=`.

- `services.kubernetes.addons.dns.coredns` has been renamed to `services.kubernetes.addons.dns.corednsImage` and now expects a
package instead of attrs. Now, by default, nixpkgs.coredns in conjunction with dockerTools.buildImage is used, instead
of pulling the upstream container image from Docker Hub. If you want the old behavior, you can set:
+15 −42
Original line number Diff line number Diff line
@@ -90,68 +90,35 @@ in
      https://www.freedesktop.org/software/systemd/man/latest/systemd.special.html#sleep.target
    '';

    systemd.targets.post-resume = {
      description = "Post-Resume Actions";
      requires = [ "post-resume.service" ];
      after = [ "post-resume.service" ];
      wantedBy = [ "sleep.target" ];
      unitConfig.StopWhenUnneeded = true;
    };

    systemd.services = {
      # Service executed before suspending/hibernating.
      pre-sleep = {
        description = "Pre-Sleep Actions";
      sleep-actions = {
        description = "Sleep Actions";
        wantedBy = [ "sleep.target" ];
        before = [ "sleep.target" ];
        unitConfig.StopWhenUnneeded = true;
        script = ''
          # NixOS pre-sleep script

          # config.powerManagement.powerDownCommands
          ${cfg.powerDownCommands}
        '';
        serviceConfig.Type = "oneshot";
      };

      # Service executed after resuming from suspend/hibernate
      post-resume = {
        description = "Post-Resume Actions";
        # Pulled in by post-resume.service above
        after = [ "sleep.target" ];
        script = ''
        preStop = ''
          # NixOS pre-resume script

          /run/current-system/systemd/bin/systemctl try-restart --no-block post-resume.target

          # config.powerManagement.resumeCommands
          ${cfg.resumeCommands}

          # config.powerManagement.powerUpCommands
          ${cfg.powerUpCommands}
        '';
        serviceConfig.Type = "oneshot";
        serviceConfig = {
          Type = "oneshot";
          RemainAfterExit = true;
        };

      # Service executed before shutdown
      pre-shutdown = {
        description = "Pre-Shutdown Actions";
        wantedBy = [
          "shutdown.target"
        ];
        before = [
          "shutdown.target"
        ];
        script = ''
          # NixOS pre-shutdown script

          # config.powerManagement.powerDownCommands
          ${cfg.powerDownCommands}
        '';
        serviceConfig.Type = "oneshot";
        unitConfig.DefaultDependencies = false;
      };

      # Service executed after boot
      # Service executed after boot, and stopped during shutdown
      post-boot = {
        description = "Post-Boot Actions";
        # It's not well defined at what point in the bootup sequence this should run
@@ -167,6 +134,12 @@ in
          # config.powerManagement.powerUpCommands
          ${cfg.powerUpCommands}
        '';
        preStop = ''
          # NixOS pre-shutdown script

          # config.powerManagement.powerDownCommands
          ${cfg.powerDownCommands}
        '';
        serviceConfig = {
          Type = "oneshot";
          RemainAfterExit = true;
+16 −6
Original line number Diff line number Diff line
@@ -194,12 +194,7 @@ in
    systemd.services.undervolt = {
      description = "Intel Undervolting Service";

      # Apply undervolt on boot, nixos generation switch and resume
      wantedBy = [
        "multi-user.target"
        "post-resume.target"
      ];
      after = [ "post-resume.target" ]; # Not sure why but it won't work without this
      wantedBy = [ "multi-user.target" ];

      serviceConfig = {
        Type = "oneshot";
@@ -208,6 +203,21 @@ in
      };
    };

    systemd.services.undervolt-sleep = {
      description = "Preserve Intel Undervolting After Sleep";

      wantedBy = [ "sleep.target" ];
      before = [ "sleep.target" ];

      unitConfig.StopWhenUnneeded = true;
      serviceConfig = {
        Type = "oneshot";
        Restart = "no";
        RemainAfterExit = true;
        ExecStop = "${cfg.package}/bin/undervolt ${toString cliArgs}";
      };
    };

    systemd.timers.undervolt = lib.mkIf cfg.useTimer {
      description = "Undervolt timer to ensure voltage settings are always applied";
      partOf = [ "undervolt.service" ];