nixos/hledger-web: add stateDir, use own user, fix ExecStart

This allows for shared hledger installations, where the web interface is
available via network and multiple user share a SSH access to the
hledger user.

Also added `--serve` to the CLI options, as hledger-web tries to open a
webbrowser otherwise:

hledger-web: xdg-open: rawSystem: runInteractiveProcess: exec: does not
exist (No such file or directory)

Co-authored-by: Aaron Andersen <aaron@fosslib.net>
This commit is contained in:
Justin Humm 2021-03-12 19:24:47 +01:00 committed by erictapen
parent 71c55e53d7
commit 569940b9fd
2 changed files with 71 additions and 31 deletions

View file

@ -34,11 +34,22 @@ in {
'';
};
journalFile = mkOption {
stateDir = mkOption {
type = types.path;
example = "/home/hledger/.hledger.journal";
default = "/var/lib/hledger-web";
description = ''
Input journal file.
Path the service has access to. If left as the default value this
directory will automatically be created before the hledger-web server
starts, otherwise the sysadmin is responsible for ensuring the
directory exists with appropriate ownership and permissions.
'';
};
journalFiles = mkOption {
type = types.listOf types.str;
default = [ ".hledger.journal" ];
description = ''
Paths to journal files relative to <option>services.hledger-web.stateDir</option>.
'';
};
@ -50,28 +61,61 @@ in {
Base URL, when sharing over a network.
'';
};
extraOptions = mkOption {
type = types.listOf types.str;
default = [];
example = [ "--forecast" ];
description = ''
Extra command line arguments to pass to hledger-web.
'';
};
};
config = mkIf cfg.enable {
systemd.services.hledger-web = {
users.users.hledger = {
name = "hledger";
group = "hledger";
isSystemUser = true;
home = cfg.stateDir;
useDefaultShell = true;
};
users.groups.hledger = {};
systemd.services.hledger-web = let
serverArgs = with cfg; escapeShellArgs ([
"--serve"
"--host=${host}"
"--port=${toString port}"
"--capabilities=${capabilityString}"
(optionalString (cfg.baseUrl != null) "--base-url=${cfg.baseUrl}")
(optionalString (cfg.serveApi) "--serve-api")
] ++ (map (f: "--file=${stateDir}/${f}") cfg.journalFiles)
++ extraOptions);
in {
description = "hledger-web - web-app for the hledger accounting tool.";
documentation = [ https://hledger.org/hledger-web.html ];
wantedBy = [ "multi-user.target" ];
after = [ "networking.target" ];
serviceConfig = {
ExecStart = ''
${pkgs.hledger-web}/bin/hledger-web \
--host=${cfg.host} \
--port=${toString cfg.port} \
--file=${cfg.journalFile} \
"--capabilities=${cfg.capabilities}" \
${optionalString (cfg.baseUrl != null) "--base-url=${cfg.baseUrl}"} \
${optionalString (cfg.serveApi) "--serve-api"}
'';
Restart = "always";
};
serviceConfig = mkMerge [
{
ExecStart = "${pkgs.hledger-web}/bin/hledger-web ${serverArgs}";
Restart = "always";
WorkingDirectory = cfg.stateDir;
User = "hledger";
Group = "hledger";
PrivateTmp = true;
}
(mkIf (cfg.stateDir == "/var/lib/hledger-web") {
StateDirectory = "hledger-web";
})
];
};
};
meta.maintainers = with lib.maintainers; [ marijanp ];
meta.maintainers = with lib.maintainers; [ marijanp erictapen ];
}

View file

@ -13,25 +13,21 @@ rec {
name = "hledger-web";
meta.maintainers = with lib.maintainers; [ marijanp ];
nodes = {
server = { config, pkgs, ... }: rec {
nodes = rec {
server = { config, pkgs, ... }: {
services.hledger-web = {
host = "127.0.0.1";
port = 5000;
enable = true;
journalFile = journal;
};
networking.firewall.allowedTCPPorts = [ services.hledger-web.port ];
networking.firewall.allowedTCPPorts = [ config.services.hledger-web.port ];
systemd.services.hledger-web.preStart = ''
ln -s ${journal} /var/lib/hledger-web/.hledger.journal
'';
};
apiserver = { config, pkgs, ... }: rec {
services.hledger-web = {
host = "127.0.0.1";
port = 5000;
enable = true;
serveApi = true;
journalFile = journal;
};
networking.firewall.allowedTCPPorts = [ services.hledger-web.port ];
apiserver = { ... }: {
imports = [ server ];
services.hledger-web.serveApi = true;
};
};
@ -42,7 +38,7 @@ rec {
server.wait_for_open_port(5000)
with subtest("Check if web UI is accessible"):
page = server.succeed("curl -L http://127.0.0.1:5000")
assert "test.journal" in page
assert ".hledger.journal" in page
apiserver.wait_for_unit("hledger-web.service")
apiserver.wait_for_open_port(5000)