{ description = "A simple self-contained daemon to gather nix statistics"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; rust-overlay.url = "github:oxalica/rust-overlay"; rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = { self, nixpkgs, rust-overlay, }: let systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"]; forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f (import nixpkgs { inherit system; overlays = [(import rust-overlay)]; })); in { packages = forAllSystems (pkgs: { default = pkgs.rustPlatform.buildRustPackage { pname = "nod"; version = "0.1.0"; src = ./.; cargoLock.lockFile = ./Cargo.lock; nativeBuildInputs = [pkgs.pkg-config]; buildInputs = [pkgs.sqlite] ++ ( if pkgs.stdenv.isDarwin then [pkgs.iconv] else [] ); }; }); devShells = forAllSystems (pkgs: { default = pkgs.mkShell { buildInputs = [ pkgs.rust-bin.stable.latest.default pkgs.pkg-config pkgs.sqlite ] ++ ( if pkgs.stdenv.isDarwin then [pkgs.iconv] else [] ); }; }); nixosModules.default = { config, lib, pkgs, ... }: let cfg = config.services.nod; in { options.services.nod = { enable = lib.mkEnableOption "Nix Observability Daemon"; package = lib.mkOption { type = lib.types.package; default = self.packages.${pkgs.system}.default; description = "The nod package to use."; }; user = lib.mkOption { type = lib.types.str; default = "nod"; description = "User to run the nod daemon as."; }; group = lib.mkOption { type = lib.types.str; default = "nod"; description = '' Group for the nod daemon. Other services that need read access to the database (e.g. a monitoring agent) should be added to this group. ''; }; socketPath = lib.mkOption { type = lib.types.path; default = "/run/nod/nod.sock"; description = "Path to the Unix socket. Exposed via NOD_SOCKET in the session environment."; }; databasePath = lib.mkOption { type = lib.types.path; default = "/var/lib/nod/nod.db"; description = "Path to the SQLite database"; }; }; config = lib.mkIf cfg.enable { users.users.${cfg.user} = { isSystemUser = true; group = cfg.group; description = "Nix Observability Daemon"; }; users.groups.${cfg.group} = {}; # Tell nix to forward its internal JSON log to the socket nix.settings.json-log-path = cfg.socketPath; # Make the socket path available to interactive shells so users # can run `nod stats` without passing --socket explicitly. environment.sessionVariables.NOD_SOCKET = cfg.socketPath; systemd.services.nod = { description = "Nix Observability Daemon"; wantedBy = ["multi-user.target"]; after = ["network.target"]; serviceConfig = { User = cfg.user; Group = cfg.group; ExecStart = "${cfg.package}/bin/nod daemon --db ${cfg.databasePath} --socket ${cfg.socketPath}"; Restart = "always"; StateDirectory = "nod"; StateDirectoryMode = "0750"; # /run/nod must be world-searchable so nix (running as any user) can reach the socket. RuntimeDirectory = "nod"; RuntimeDirectoryMode = "0755"; # SQLite WAL mode requires write access to the -shm file even for read-only connections. UMask = "0117"; }; }; }; }; }; }