1# TODO: create a common module generator for Taler and Libeufin?
2{
3 talerComponent ? "",
4 servicesDB ? [ ],
5 servicesNoDB ? [ ],
6 ...
7}:
8{
9 lib,
10 pkgs,
11 config,
12 ...
13}:
14let
15 cfg = cfgTaler.${talerComponent};
16 cfgTaler = config.services.taler;
17
18 settingsFormat = pkgs.formats.ini { };
19
20 configFile = config.environment.etc."taler/taler.conf".source;
21 componentConfigFile = settingsFormat.generate "generated-taler-${talerComponent}.conf" cfg.settings;
22
23 services = servicesDB ++ servicesNoDB;
24
25 dbName = "taler-${talerComponent}-httpd";
26 groupName = "taler-${talerComponent}-services";
27
28 inherit (cfgTaler) runtimeDir;
29in
30{
31 options = {
32 services.taler.${talerComponent} = {
33 enable = lib.mkEnableOption "the GNU Taler ${talerComponent}";
34 package = lib.mkPackageOption pkgs "taler-${talerComponent}" { };
35 # TODO: make option accept multiple debugging levels?
36 debug = lib.mkEnableOption "debug logging";
37 openFirewall = lib.mkOption {
38 type = lib.types.bool;
39 default = false;
40 description = "Whether to open ports in the firewall";
41 };
42 };
43 };
44
45 config = lib.mkIf cfg.enable {
46 services.taler.enable = cfg.enable;
47 services.taler.includes = [ componentConfigFile ];
48
49 systemd.services = lib.mergeAttrsList [
50 # Main services
51 (lib.genAttrs (map (n: "taler-${talerComponent}-${n}") services) (name: {
52 serviceConfig = {
53 DynamicUser = true;
54 User = dbName;
55 Group = groupName;
56 ExecStart = toString [
57 (lib.getExe' cfg.package name)
58 "-c ${configFile}"
59 (lib.optionalString cfg.debug " -L debug")
60 ];
61 RuntimeDirectory = name;
62 StateDirectory = name;
63 CacheDirectory = name;
64 ReadWritePaths = [ runtimeDir ];
65 Restart = "always";
66 RestartSec = "10s";
67 };
68 requires = [ "taler-${talerComponent}-dbinit.service" ];
69 after = [ "taler-${talerComponent}-dbinit.service" ];
70 wantedBy = [ "multi-user.target" ]; # TODO slice?
71 documentation = [
72 "man:taler-${talerComponent}-${name}(1)"
73 "info:taler-${talerComponent}"
74 ];
75 }))
76 # Database Initialisation
77 {
78 "taler-${talerComponent}-dbinit" = {
79 path = [ config.services.postgresql.package ];
80 documentation = [
81 "man:taler-${talerComponent}-dbinit(1)"
82 "info:taler-${talerComponent}"
83 ];
84 serviceConfig = {
85 Type = "oneshot";
86 DynamicUser = true;
87 User = dbName;
88 Group = groupName;
89 Restart = "on-failure";
90 RestartSec = "5s";
91 };
92 requires = [ "postgresql.target" ];
93 after = [ "postgresql.target" ];
94 };
95 }
96 ];
97
98 users.groups.${groupName} = { };
99 systemd.tmpfiles.settings = {
100 "10-taler-${talerComponent}" = {
101 "${runtimeDir}" = {
102 d = {
103 group = groupName;
104 user = "nobody";
105 mode = "070";
106 };
107 };
108 };
109 };
110
111 networking.firewall = lib.mkIf cfg.openFirewall {
112 allowedTCPPorts = [ cfg.settings."${talerComponent}".PORT ];
113 };
114
115 environment.systemPackages = [ cfg.package ];
116
117 services.postgresql = {
118 enable = true;
119 ensureDatabases = [ dbName ];
120 ensureUsers = [
121 {
122 name = dbName;
123 ensureDBOwnership = true;
124 }
125 ];
126 };
127 };
128}