Skip to content
This repository has been archived by the owner on Oct 15, 2022. It is now read-only.

lorri daemon: systemd service #96

Closed
Kiwi opened this issue Jun 13, 2019 · 52 comments
Closed

lorri daemon: systemd service #96

Kiwi opened this issue Jun 13, 2019 · 52 comments
Labels
documentation Doc improvements needed feature request Request for new functionality user-facing Improvement that increases user experience

Comments

@Kiwi
Copy link

Kiwi commented Jun 13, 2019

I've started using the branch with the lorri daemon PR and it's pretty cool! 1 annoyance it carries over from regular lorri is that it still requires an extra sacrificial terminal... with a shell.nix (any shell.nix it seems?) to launch the daemon and remain open. At least it's only 1 as opposed to many.

Anyway, it'd be nice if it could run as a (systemd, etc.) service.

Thanks, everyone! I've been really enjoying lorri

@Profpatsch
Copy link
Collaborator

I haven’t set up anything in that direction yet, but I suppose a simple systemd --user service file should be enough for starters? Or do you have something different in mind?

@Kiwi
Copy link
Author

Kiwi commented Jun 17, 2019

I'm not all that familiar with the different ways systemd services can work. So, probably? I don't think it needs to be terribly complex.

This is what I do currently:

lorri daemon &> lorri-log.txt &
tail -f lorri-log.txt

I do the tail mostly so I know not to close the terminal and I can kill it if i want to use it temporarily without killing the daemon. It works ok but a service would be a little cleaner I think. but more work. I don't know how much work so it might be asking a lot.

@Profpatsch
Copy link
Collaborator

I have set up a small systemd user service (by copying from another user service with systemctl cat <service>), which works pretty well so far:

[Unit]
Description=lorri user daemon

WantedBy=graphical-session.target

[Service]
Environment="LOCALE_ARCHIVE=/nix/store/skrsp96qgmkp0b6a565yqg3hsl4s75s4-glibc-locales-2.27/lib/locale/locale-archive"
Environment="TZDIR=/nix/store/fs26ijjyf60l6xxnyg8rkr9b1ld9c7nb-tzdata-2019a/share/zoneinfo"

ExecStart=/home/philip/kot/work/tweag/lorri/target/debug/lorri daemon

Restart=on-failure
RestartSec=5s

I’m not exactly sure how we should integrate it into our repo though. home-manager could be one way.

@Profpatsch Profpatsch added documentation Doc improvements needed feature request Request for new functionality good first issue Good for newcomers user-facing Improvement that increases user experience labels Jun 25, 2019
@Profpatsch
Copy link
Collaborator

People have come up with other ways to integrate lorri watch into their system, see #2

@colonelpanic8
Copy link
Contributor

@Profpatsch Just wanted to clarify whether you think it definitely makes sense for lorri to be a user unit rather than a system unit. If its going to be a user unit then we wont be able to add a nixos module that handles running the service for you. I added this to my nixos configuration

  systemd.services.lorri-daemon = {
    description = "lorri daemon";
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      ExecStart = "${lorri}/bin/lorri daemon";
    };
  };

but it doesn't quite work, beecause the way lorri looks for paths depends on the current user. This daemon runs as root, and so it stores the daemon file in roots home directory, so e.g. lorri ping_ fails to connect.

@peterhoeg
Copy link

This works with lorri daemon as a user service:

# lorri.socket
[Unit]
Description=Lorri Build Daemon

[Socket]
ListenStream=%t/lorri/daemon.socket
RuntimeDirectory=lorri

[Install]
WantedBy=sockets.target
# lorri.service
[Unit]
ConditionUser=!@system
Description=Lorri Build Daemon
After=lorri.socket
Wants=lorri.socket

[Service]
ExecStart=%h/.nix-profile/bin/lorri daemon
PrivateTmp=true
ProtectSystem=strict
Restart=on-failure
WorkingDirectory=%h
# $HOME/.config/direnv/direnvrc
use_nix() {
  eval "$(lorri direnv)"
}

You don't have to manually start the service - it will be activated when lorri direnv tries to connect to the socket.

@colonelpanic8
Copy link
Contributor

@peterhoeg ah the socket is a nice touch. Still would be nice to be able to use nix configuration to set it up though, which could be done if it were runnable in multi-user mode.

@Profpatsch
Copy link
Collaborator

Yeah, I don’t think it makes sense at all to run lorri as a system service. It’s per-user.

@peterhoeg
Copy link

which could be done if it were runnable in multi-user mode.

Just to clarify, the approach above sets up a socket per user.

@manveru
Copy link

manveru commented Jun 28, 2019

Here's a configuration for home-manager:

{ pkgs, ... }:
let
  lorri = import (fetchTarball {
    url = "https://github.com/target/lorri/archive/rolling-release.tar.gz";
  }) { };

  path = with pkgs; lib.makeSearchPath "bin" [ nix gnutar git mercurial ];
in {
  home.packages = [ lorri ];

  systemd.user.sockets.lorri = {
    Unit = { Description = "lorri build daemon"; };
    Socket = { ListenStream = "%t/lorri/daemon.socket"; };
    Install = { WantedBy = [ "sockets.target" ]; };
  };

  systemd.user.services.lorri = {
    Unit = {
      Description = "lorri build daemon";
      Documentation = "https://github.com/target/lorri";
      ConditionUser = "!@system";
      Requires = "lorri.socket";
      After = "lorri.socket";
      RefuseManualStart = true;
    };

    Service = {
      ExecStart = "${lorri}/bin/lorri daemon";
      PrivateTmp = true;
      ProtectSystem = "strict";
      WorkingDirectory = "%h";
      Restart = "on-failure";
      Environment = "PATH=${path} RUST_BACKTRACE=1";
    };
  };
}

@peterhoeg
Copy link

@manveru, you probably want to change:

      Requires = "lorri.socket";
      Wants = "lorri.socket";

to

      Requires = "lorri.socket";
      After = "lorri.socket";

Requires is a "stronger" version of Wants.

@Moredread
Copy link

Moredread commented Jul 18, 2019

      Environment = ''
        PATH=${pkgs.nix}/bin
        RUST_BACKTRACE=1
      '';

This doesn't work correctly, as the line wrap is rendered in the service file as

[Service]
Environment=PATH=/nix/store/nqpyfg13b9bpr7ihrfqhndckzmldnr5g-nix-2.2.2/bin
RUST_BACKTRACE=1

Changing it to one line should work though:

Environment = "PATH=${pkgs.nix}/bin RUST_BACKTRACE=1";

@manveru
Copy link

manveru commented Jul 26, 2019

I updated my comment with a better working version.

@Kiwi
Copy link
Author

Kiwi commented Jul 27, 2019

I don't use home-manager so I put this in a file lorri.nix that I import in configuration.nix and it seems to work. If anyone sees anything wrong please let me know, and hopefully someone else finds it useful! And thanks to @manveru for the original home-manager one.

{ pkgs, ... }:

let
  lorri = (import (fetchTarball {
    url = https://github.com/target/lorri/archive/rolling-release.tar.gz;
  }) {});
in
{
  systemd.user.sockets.lorri = {
    description = "lorri build daemon";
    listenStreams = [ "%t/lorri/daemon.socket" ];
    wantedBy = [ "sockets.target" ];
  };

  systemd.user.services.lorri = {
    description = "lorri build daemon";
    documentation = [ "https://github.com/target/lorri" ];
    requires = [ "lorri.socket" ];
    after = [ "lorri.socket" ];
    unitConfig = {
      ConditionUser = "!@system";
      RefuseManualStart = true;
    };

    serviceConfig = {
      ExecStart = "${lorri}/bin/lorri daemon";
      PrivateTmp = true;
      ProtectSystem = "strict";
      WorkingDirectory = "%h";
      Restart = "on-failure";
      RestartSec = "60s";
      Environment = "PATH=${pkgs.nix}/bin RUST_BACKTRACE=1";
    };
  };

  environment.systemPackages = [ lorri ];
}

@chreekat
Copy link

I'm trying out the user service + socket activation. So far so good 👍

@Gerschtli
Copy link

I have an issue with this systemd config. I'm using home-manager on my ubuntu machine, but I see following errors in the log:

Aug 06 12:55:26 devel-one lorri[2641]: Started
Aug 06 12:55:26 devel-one lorri[2641]: Failure(
Aug 06 12:55:26 devel-one lorri[2641]:     BuildExitFailure {
Aug 06 12:55:26 devel-one lorri[2641]:         log_lines: [
Aug 06 12:55:26 devel-one lorri[2641]:             "error: file \'nixpkgs\' was not found in the Nix search path (add it using $NIX_PATH or -I), at /nix/store/pw5gwdil10ifv577zc5g6xp0r9bq4r4f-hm_profiles/php72.nix:3:13"
Aug 06 12:55:26 devel-one lorri[2641]:         ]
Aug 06 12:55:26 devel-one lorri[2641]:     }
Aug 06 12:55:26 devel-one lorri[2641]: )

How do you guys inject the NIX_PATH env var?

@chreekat
Copy link

chreekat commented Aug 6, 2019

Hey @Gerschtli, that looks like a build failure of something being evaluated, rather than an issue with lorri! The "hm_profiles" in the store path makes me suspect this has something to do with home-manager. I don't use that, so maybe somebody else can chime in.

@Gerschtli
Copy link

I don't think so.
I can reproduce it with following setup:

  1. cd into empty dir
  2. run lorri init
  3. run direnv allow .

The logs show this:

Aug 06 15:59:59 devel-one lorri[2641]: Started
Aug 06 15:59:59 devel-one lorri[2641]: Failure(
Aug 06 15:59:59 devel-one lorri[2641]:     BuildExitFailure {
Aug 06 15:59:59 devel-one lorri[2641]:         log_lines: [
Aug 06 15:59:59 devel-one lorri[2641]:             "error: file \'nixpkgs\' was not found in the Nix search path (add it using $NIX_PATH or -I), at /home/tobi/test/shell.nix:2:17"
Aug 06 15:59:59 devel-one lorri[2641]:         ]
Aug 06 15:59:59 devel-one lorri[2641]:     }
Aug 06 15:59:59 devel-one lorri[2641]: )

.envrc:

eval "$(lorri direnv)"

shell.nix:

let
  pkgs = import <nixpkgs> {};
in
  pkgs.mkShell {
    buildInputs = [
        pkgs.hello
    ];
  }

@Profpatsch
Copy link
Collaborator

But it works if you run it manually outside of your service manager?

You probably need to set the NIX_PATH in your service description.

@Gerschtli
Copy link

I will give it a try tomorrow.
But do have a clue how the NIX_PATH is set in the systemd service on NixOS systems? Seems like a bit magic in there.. The reason for my interest is, that I want to enable home-manager on non-NixOS systems to have the same nix-specifc setup like on NixOS systems.

@chreekat
Copy link

chreekat commented Aug 8, 2019 via email

@Gerschtli
Copy link

Yes, I do, configured with home-manager.. This is my expression: https://github.com/Gerschtli/home-manager-configurations/blob/master/modules/config/development/lorri.nix#L109

@Gerschtli
Copy link

It works now when I set NIX_PATH=/nix/var/nix/profiles/per-user/$USER/channels only for non NixOS systems. To integrate this service in home-manager it would be better to set NIX_PATH globally for all systemd user services, so we don't have to define a different service depending on the underlying OS. But I don't have a clue, how this is implemented for NixOS to work this way.

adomixaszvers added a commit to adomixaszvers/dotfiles-nix that referenced this issue Nov 2, 2019
adomixaszvers added a commit to adomixaszvers/dotfiles-nix that referenced this issue Nov 2, 2019
adomixaszvers added a commit to adomixaszvers/dotfiles-nix that referenced this issue Dec 29, 2019
@jkachmar
Copy link
Contributor

jkachmar commented Jan 29, 2020

So, for whatever reason, I've found that the example in @pawlowskialex's comment didn't work for me. However after poking around GitHub a bit, I found this example and adapted it a little bit to my liking.

This seems to work quite nicely; the daemon comes up as follows and I don't have to hard-code any of my paths.

jkachmar in ~/src ❯ launchctl list | rg "lorri"
60034	0	org.nixos.lorri

Snip of my configuration (in case people don't want to follow links):

{ config, pkgs, ... }:

let
  inherit (pkgs) lorri;

in {
  environment.systemPackages = [ lorri ];

  # XXX: Copied verbatim from https://github.com/iknow/nix-channel/blob/7bf3584e0bef531836050b60a9bbd29024a1af81/darwin-modules/lorri.nix
  launchd.user.agents = {
    "lorri" = {
      serviceConfig = {
        WorkingDirectory = (builtins.getEnv "HOME");
        EnvironmentVariables = { };
        KeepAlive = true;
        RunAtLoad = true;
        StandardOutPath = "/var/tmp/lorri.log";
        StandardErrorPath = "/var/tmp/lorri.log";
      };
      script = ''
        source ${config.system.build.setEnvironment}
        exec ${lorri}/bin/lorri daemon
      '';
    };
  };
}

curiousleo added a commit to curiousleo/lorri that referenced this issue Jan 30, 2020
@curiousleo
Copy link
Collaborator

Thanks @jkachmar! I've added a link from the docs to your comment: #310.

curiousleo added a commit to curiousleo/lorri that referenced this issue Jan 30, 2020
@surajbarkale
Copy link

As a minimal solution, I created ~/Library/LaunchAgents/com.github.target.lorri.plist with following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.github.target.lorri</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/zsh</string>
        <string>-i</string>
        <string>-c</string>
        <string>lorri daemon</string>
    </array>
    <key>StandardOutPath</key>
    <string>/var/tmp/lorri.log</string>
    <key>StandardErrorPath</key>
    <string>/var/tmp/lorri.log</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
	<true/>
</dict>
</plist>

The daemon started working after executing launchctl load ~/Library/LaunchAgents/com.github.target.lorri.plist.

In nixpkgs I have found xquartz and skhd create the plist as part of installation. I am trying to adopt the same solution for lorri so this process is automated.

However, lorri crashes when launched from nixpkgs shell: env -i $(nix eval --raw '(import <nixpkgs> {}).stdenv.shell') -i -c "$(which lorri) daemon". I have attached the
crash report for your reference.

@nomeata
Copy link

nomeata commented Mar 30, 2020

I guess this is the right thread for such discussions. I am currently evaluationg lorri, and the first question I had was “why do I have to set up a deamon”. Many other non-system deamon-like systems (ssh control masters, pulseaudio etc.) don’t need a particular setup: They start the deamon automatically on first use, and maybe stop it after a while of disuse. Is there a particular reason why lorri can’t do the same? I could imagine that it could help adoption a lot (e.g. I’d be more willing to advocate for it in my company if I knew this would “just work”).

@curiousleo
Copy link
Collaborator

Many other non-system deamon-like systems (ssh control masters, pulseaudio etc.) don’t need a particular setup: They start the deamon automatically on first use, and maybe stop it after a while of disuse. Is there a particular reason why lorri can’t do the same? I could imagine that it could help adoption a lot (e.g. I’d be more willing to advocate for it in my company if I knew this would “just work”).

Doing daemon supervision right is non-trivial. On the other hand, there are a bunch of daemon supervision systems already out there that do the job really well: systemd, s6, launchd, etc.

So why reinvent the wheel? We opted instead for a design where lorri daemon plays well with the daemon supervisor of your choice.

Something that may not be clear from this long thread is that at least on NixOS or with home-manager, getting the service up and running is no more complicated than installing the binary: all it takes is a single line of configuration, see https://github.com/target/lorri#setup-on-nixos-or-with-home-manager-on-linux.

@nomeata
Copy link

nomeata commented Mar 31, 2020

with the daemon supervisor of your choice.

That already assumes a level of sophistication and geekery that raises the bar for adoption (as does using NixOS or home-manager). Not arguing that it’s technically the right choice, just saying that making things work-out-of-the box has it’s own merits.

@Profpatsch
Copy link
Collaborator

Profpatsch commented Apr 2, 2020

Personally, I like the approach Zoom takes towards usability ;)

But more seriously, we can kind of expect lorri users to be technical enough to write one or two lines of config. If a company wants to enforce it company-wide, they should be able to adapt our guides to their environment with ease (we made sure to make them as easy as possible to follow for the standard use-cases).

lorri does specifically not do any magic, in order to make it as easy as possible to adapt to different environments. Things like double-forking have (rightly) been shown to just make life of admins hell.

@chreekat
Copy link

chreekat commented Apr 2, 2020

@nomeata suggests needing to configure a daemon hurts adoption, and @Profpatsch says we can expect lorri users to be technical enough to write a config file. But these are not contradictory statements! I have extremely competent colleagues who are choosing not to use lorri, in part because it requires setting up a daemon. I am also reluctant to build any contributor tooling around it for the same reason.

But for our use cases, perhaps something like xzfc/cached-nix-shell is a better fit?

If lorri could choose some compromise that allowed for a Just Works workflow, I do think it would help. Actually, does lorri have a one shot mode? Could it behave similarly to cached-nix-shell?

@curiousleo
Copy link
Collaborator

Actually, does lorri have a one shot mode? Could it behave similarly to cached-nix-shell?

Check out lorri shell --help.

@Profpatsch
Copy link
Collaborator

Also, lorri watch --once.

@Profpatsch
Copy link
Collaborator

If lorri could choose some compromise that allowed for a Just Works workflow, I do think it would help. Actually, does lorri have a one shot mode? Could it behave similarly to cached-nix-shell?

Starting the daemon is the Just Works workflow.

@tricktron
Copy link

Lorri has been added to nix-darwin: LnL7/nix-darwin#222.

You can install it with:

environment.systemPackages = with pkgs; [ direnv ];
services.lorri.enable = true;

and the daemon will be configured automatically.

@curiousleo Could you add this to the README?

@Profpatsch
Copy link
Collaborator

@tricktron do you want to submit a PR with the documentation?

@Profpatsch
Copy link
Collaborator

Thanks to @jkachmar, documented in #479

@tricktron
Copy link

@jkachmar Thank you for jumping in and documenting it.

@pwm
Copy link

pwm commented May 10, 2022

@surajbarkale did you figure out why lorri crashed there? I'm on macOs + home-manager but not nix-darwin and would like to use your method.

@surajbarkale
Copy link

surajbarkale commented Oct 11, 2022 via email

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
documentation Doc improvements needed feature request Request for new functionality user-facing Improvement that increases user experience
Projects
None yet
Development

No branches or pull requests