Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add proper support for systemd templated services #5557

Open
ItsDrike opened this issue Jun 20, 2024 · 5 comments
Open

Add proper support for systemd templated services #5557

ItsDrike opened this issue Jun 20, 2024 · 5 comments

Comments

@ItsDrike
Copy link

ItsDrike commented Jun 20, 2024

Description

A systemd templated service is one that ends with @ and can be enabled multiple times with various values.

However, while I am able to define the service with home-manager, I'm not sure how to declaratively enable it for specific values. This is what I have:

    systemd.user.services = {
      "eww-window@" = {
        Unit = {
          Description = "Open %I eww (ElKowar's Wacky Widgets) window";
          After = [ "eww.service" ];
          PartOf = [ "graphical-session.target" ];
        };

        Service = {
          Type = "oneshot";
          RemainAfterExit = true;
          ExecStart = "${pkgs.eww}/bin/eww open %i";
          ExecStop = "${pkgs.eww}/bin/eww close %i";
          Restart = "on-failure";
        };

        Install.WantedBy = [ "graphical-session.target" ];
      };
    };

Current behavior with the above

This will create the eww-window@ user service and it does get put into ~/.config/systemd/user/[email protected] as expected, however, it also gets put into ~/.config/systemd/user/graphical-session.target.wants/[email protected], which doesn't make sense, as only the specific variants for this service should be getting enabled for the target.

It's not really possible to avoid this though, since home-manager will put it here whenever Install.WantedBy is set, though this setting is necessary to be in this template service, as the specific services that rely on this template are just symlinks to it, so this sections needs to be present, even though this service on it's own shouldn't be getting activated, but rather only it's variants.

That said, even though it's weird to have just the [email protected] in graphical-session.target.wants, it doesn't seem to cause any issues, so it's probably fine.

Manual enabling

I can now enable the various variants manually with a command, like: systemctl enable --user eww-window@bar0. Running this results in the following output:

Created symlink /home/itsdrike/.config/systemd/user/[email protected] → /nix/store/l4jk087fm76p6vlkkmj971swr0xwm8hq-eww-window-.service/[email protected].
Created symlink /home/itsdrike/.config/systemd/user/graphical-session.target.wants/[email protected] → /nix/store/l4jk087fm76p6vlkkmj971swr0xwm8hq-eww-window-.service/[email protected].

Notice that it made another service in ~/.config/systemd/user/ that's called [email protected] which is just a symlink to the original [email protected]. This however isn't even needed in this case, it would be enough to just make the ~/.config/systemd/user/graphical-session.target.wants/[email protected]. I'm not sure why it's making this symlink here.

That said, this isn't really a major issue either and it might just be something to do with systemd (though I know that on Arch linux, the link would only be in graphical-session.target.wants).

Core issue

The issues above are pretty minor and aren't really that important though. The main problem with this is that there is no way to declaratively enable this service for whatever values I need. It's necessary to do this manually with systemctl.

I have found NixOS/nixpkgs#80933, which does have a fix for system services, where it's possible to use overrideStrategy = "asDropin": and define a service like this:

{
  systemd.services."systemd-nspawn@archlinux" = {
    wantedBy = [ "machines.target" ];
    overrideStrategy = "asDropin";
  };
}

But this kind of setup doesn't work with home-manager and at least from the docs I found, I didn't see this being supported in any way.

I feel like this is a pretty important issue though, especially for someone like me who also uses home impermanence, so my home directory is getting wiped between each reboot, taking the manually made symlinks with it.

@rycee
Copy link
Member

rycee commented Jun 20, 2024

I think template services simply hasn't been very important in a HM setup since Nix is a decent templating language by itself. That is, typically one would simply directly generate the desired unit definition. Something like

systemd.user.services =
  let
    eww = name: {
      "eww-window-${name}" = {
        Unit = {
          Description = "Open ${name} eww (ElKowar's Wacky Widgets) window";
          After = [ "eww.service" ];
          PartOf = [ "graphical-session.target" ];
        };

        Service = {
          Type = "oneshot";
          RemainAfterExit = true;
          ExecStart = "${pkgs.eww}/bin/eww open ${name}";
          ExecStop = "${pkgs.eww}/bin/eww close ${name}";
          Restart = "on-failure";
        };

        Install.WantedBy = [ "graphical-session.target" ];
      };
    };
  in eww "bar0" // eww "bar1";

@ItsDrike
Copy link
Author

The issue is that I do have some need for the dynamicness here, as I'm starting barN service whenever a new monitor gets plugged in and only bar0 should be enabled by default (I'm on a laptop, and I often switch between docked/undocked modes).

This is probably a pretty rare case, I do understand that, but I do think that there could be benefit in supporting template services. For example I've seen people have services that they run like systemctl start --user myservice@$(date) to distniguish them, and this simply needs to be dynamic, it's not always possible to template everything in nix.

I can hack my way through this and especially in this case, where I can just call the eww commands manually in the script that gets run when I plug monitors in (though the advantage of this is that I can enable/disable systemd services from the script, not just start/stop, and if I restart eww service, these units will be restarted too, re-opening my bars), but I do believe that support for this could be beneficial to more people than just me.

@nyarly
Copy link
Contributor

nyarly commented Aug 3, 2024

I have an ongoing usecase for Systemd template units - I have a hacky fork of the polybar service so that I can have a polybar for each screen. Since screens change based on what's plugged into the computer, the only solution I've found for this is to use polybar@ and then have my arandr wrapper enable screens as they're attached etc.

@nyarly
Copy link
Contributor

nyarly commented Aug 3, 2024

My biggest current irritation with the level of support for templated units is that switch will report Failed to get properties: Unit name [email protected] is neither a valid invocation ID nor unit name.

Copy link

stale bot commented Jan 3, 2025

Thank you for your contribution! I marked this issue as stale due to inactivity. Please be considerate of people watching this issue and receiving notifications before commenting 'I have this issue too'. We welcome additional information that will help resolve this issue. Please read the relevant sections below before commenting.

If you are the original author of the issue

  • If this is resolved, please consider closing it so that the maintainers know not to focus on this.
  • If this might still be an issue, but you are not interested in promoting its resolution, please consider closing it while encouraging others to take over and reopen an issue if they care enough.
  • If you know how to solve the issue, please consider submitting a Pull Request that addresses this issue.

If you are not the original author of the issue

  • If you are also experiencing this issue, please add details of your situation to help with the debugging process.
  • If you know how to solve the issue, please consider submitting a Pull Request that addresses this issue.

Memorandum on closing issues

Don't be afraid to manually close an issue, even if it holds valuable information. Closed issues stay in the system for people to search, read, cross-reference, or even reopen – nothing is lost! Closing obsolete issues is an important way to help maintainers focus their time and effort.

@stale stale bot added the status: stale label Jan 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants