Can’t use systemctl to control it, I looked at other packages and think I installed the service file correctly, so it is probably due to the commands I use not actually installing the package?
I was having an issue with it not finding bcc or psutil when running it without sudo, since it then re-executes itself here with os.execvp using sudo and I tried using wrapProgram to fix this, but it did not and that line in my nix file doesn’t actually solve anything and can be removed. It was the symbolic links that fixed this, but there is probably a better way to solve this?
Related to (2), I can’t run picosnitch dash for the same reason, I could probably add the symbolic links, but dash has a lot more dependencies and I’m pretty sure there is a better way.
systemctl is a systemd utility for managing services. Systemd expects a corresponding unit file to be present in either a user or system unit file directory.
nix-build just realizes (builds) nix store paths. installing is usually done through nixos-modules and some corresponding logic (e.g. nixos-rebuild switch).
Launching it as a system service should make it root by default. Ideally the service would just enable the required capabilities, but if the logic just checks for UID there’s not much you can do.
Additional context: since the nix store doesn’t have the SETUID bit, programs which do will have a corresponding entry in /run/wrappers/bin.
Related to (2), I can’t run picosnitch dash for the same reason, I could probably add the symbolic links, but dash has a lot more dependencies and I’m pretty sure there is a better way.
Probably related to above. I usually find that python applications usually make a lot of assumptions about your system or python environment which makes them packaging quite difficult.
On NixOS, the actual installation of systemd unit files in a way that systemd can see them is done through the module system.
If you want to use a systemd unit file packaged with something in Nix on some other distro, you have to symlink it into the appropriate place (/usr/lib/systemd/system, I think, though there may be preferable dirs under /etc or elsewhere) yourself, then run systemctl daemon-reload. This actually works pretty well so long as you symlink it in from the appropriate Nix profile (I would install the package as root and then symlink it in from /nix/var/nix/profiles/default/... and not directly from the Nix store.
Installing a Nix package with nix-env or nix profile install doesn’t muck about with the init system present on the base system. (I think Home Manager supports systemd user services, for things that aren’t systemwide and can run on a per-user basis.)
How does picosnitch figure out what Python interpreter to use in re-exec’ing itself?
I’m not sure if it’s Nixpkgs-worthy, but one thing I’ve done with some Python programs in other contexts is use writeScriptBin to manually write a simple wrapper that invokes a Python scripts using a python executable that comes from a python3.withPackages result.
I’d like to experiment with what you’ve got so far to give some real suggestions for improvements, but I’m exhausted tonight. I’ll see if I can figure something out that works better when I get the chance, though!
The daemon is the only part that needs root, and it has some logic to guess the UID if run as a service and not by the user, and the environment variable wasn’t set. The only things it needs the UID for is desktop notifications on dbus, and for getting the executable hash of AppImages without allow_other or allow_root.
Thanks! Right now I’m just using the NixOS demo appliance for VirtualBox to test this, but it’s good to know this sort of setup is possible and may consider it for myself at some point.
Thank you! Since the main issue comes from re-executing itself, maybe the simplest solution is just remove support for running it like that on nix and require starting it from systemctl or with sudo? With dash it re-executes itself with nohup and runs a small shell script that opens your web browser to localhost:5100 so I could probably modify it to just not do that with substituteInPlace. Ideally I’d like to get this in good enough shape to submit to Nixpkgs if possible.
I also tried substituteInPlace $out/${python3.sitePackages}/picosnitch.py --replace sys.executable "'${python3.interpreter}'" just to be sure and no difference.
I just created a new .nix file and everything seems to be working now (got rid of symlinks, wrapprogram, replaced cases of os.execvp, and added setuptools as a dependency)
{ lib
, pkgs
, python3
, bcc
}:
python3.pkgs.buildPythonApplication rec {
pname = "picosnitch";
version = "0.12.0";
src = python3.pkgs.fetchPypi {
inherit pname version;
sha256 = "b87654b4b92e28cf5418388ba1d3165b9fa9b17ba91af2a1a942f059128f68bc";
};
propagatedBuildInputs = with python3.pkgs; [
setuptools
bcc
psutil
dbus-python
requests
pandas
plotly
dash
];
serviceFile = ''
[Unit]
Description=picoSnitch
[Service]
Type=simple
Restart=always
RestartSec=5
ExecStart=$out/bin/picosnitch start-no-daemon
PIDFile=/run/picosnitch.pid
[Install]
WantedBy=multi-user.target
'';
postInstall = ''
substituteInPlace $out/${python3.sitePackages}/picosnitch.py --replace "os.execvp(\"bash\", args)" "return ui_dash()"
substituteInPlace $out/${python3.sitePackages}/picosnitch.py --replace "os.execvp(\"sudo\", args)" "assert sys.argv[1] not in ['start', 'stop', 'restart', 'start-no-daemon'], 'picosnitch requires root privileges to run'"
substituteInPlace $out/${python3.sitePackages}/picosnitch.py --replace "capeff & cap_sys_admin" "sys.argv[1] not in ['start', 'stop', 'restart', 'start-no-daemon'] or (capeff & cap_sys_admin)"
substituteInPlace $out/${python3.sitePackages}/picosnitch.py --replace "picosnitch daemon" "picosnitch daemon, WARNING: built in daemon mode is not supported on Nix, use picosnitch start-no-daemon or systemctl instead"
mkdir -p ./cmd/picosnitch
echo "${serviceFile}" > ./cmd/picosnitch/picosnitch.service
install -D -m0444 -t $out/lib/systemd/system ./cmd/picosnitch/picosnitch.service
'';
pythonImportsCheck = [ "picosnitch" ];
meta = with lib; {
description = "Monitor network traffic per executable with hashing";
homepage = "https://github.com/elesiuta/picosnitch";
changelog = "https://github.com/elesiuta/picosnitch/releases";
license = licenses.gpl3Plus;
maintainers = [ ];
platforms = platforms.linux;
};
}
I installed it by adding this to my configuration.nix file