1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 format = pkgs.formats.json { };
9 commonOptions =
10 {
11 pkgName,
12 flavour ? pkgName,
13 }:
14 lib.mkOption {
15 default = { };
16 description = ''
17 Attribute set of ${flavour} instances.
18 Creates independent `${flavour}-''${name}.service` systemd units for each instance defined here.
19 '';
20 type =
21 with lib.types;
22 attrsOf (
23 submodule (
24 { name, ... }:
25 {
26 options = {
27 enable = lib.mkEnableOption "this ${flavour} instance" // {
28 default = true;
29 };
30
31 package = lib.mkPackageOption pkgs pkgName { };
32
33 user = lib.mkOption {
34 type = types.str;
35 default = "root";
36 description = ''
37 User under which this instance runs.
38 '';
39 };
40
41 group = lib.mkOption {
42 type = types.str;
43 default = "root";
44 description = ''
45 Group under which this instance runs.
46 '';
47 };
48
49 settings = lib.mkOption {
50 type = types.submodule {
51 freeformType = format.type;
52
53 options = {
54 pid_file = lib.mkOption {
55 default = "/run/${flavour}/${name}.pid";
56 type = types.str;
57 description = ''
58 Path to use for the pid file.
59 '';
60 };
61 };
62 };
63
64 default = { };
65
66 description =
67 let
68 upstreamDocs =
69 if flavour == "vault-agent" then
70 "https://developer.hashicorp.com/vault/docs/agent#configuration-file-options"
71 else
72 "https://github.com/hashicorp/consul-template/blob/main/docs/configuration.md#configuration-file";
73 in
74 ''
75 Free-form settings written directly to the `config.json` file.
76 Refer to <${upstreamDocs}> for supported values.
77
78 ::: {.note}
79 Resulting format is JSON not HCL.
80 Refer to <https://www.hcl2json.com/> if you are unsure how to convert HCL options to JSON.
81 :::
82 '';
83 };
84 };
85 }
86 )
87 );
88 };
89
90 createAgentInstance =
91 {
92 instance,
93 name,
94 flavour,
95 }:
96 let
97 configFile = format.generate "${name}.json" instance.settings;
98 in
99 lib.mkIf (instance.enable) {
100 description = "${flavour} daemon - ${name}";
101 wantedBy = [ "multi-user.target" ];
102 after = [ "network.target" ];
103 path = [ pkgs.getent ];
104 startLimitIntervalSec = 60;
105 startLimitBurst = 3;
106 serviceConfig = {
107 User = instance.user;
108 Group = instance.group;
109 RuntimeDirectory = flavour;
110 ExecStart = "${lib.getExe instance.package} ${
111 lib.optionalString (flavour == "vault-agent") "agent"
112 } -config ${configFile}";
113 ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
114 KillSignal = "SIGINT";
115 TimeoutStopSec = "30s";
116 Restart = "on-failure";
117 };
118 };
119in
120{
121 options = {
122 services.consul-template.instances = commonOptions { pkgName = "consul-template"; };
123 services.vault-agent.instances = commonOptions {
124 pkgName = "vault";
125 flavour = "vault-agent";
126 };
127 };
128
129 config = lib.mkMerge (
130 map
131 (
132 flavour:
133 let
134 cfg = config.services.${flavour};
135 in
136 lib.mkIf (cfg.instances != { }) {
137 systemd.services = lib.mapAttrs' (
138 name: instance:
139 lib.nameValuePair "${flavour}-${name}" (createAgentInstance {
140 inherit name instance flavour;
141 })
142 ) cfg.instances;
143 }
144 )
145 [
146 "consul-template"
147 "vault-agent"
148 ]
149 );
150
151 meta.maintainers = with lib.maintainers; [
152 emilylange
153 tcheronneau
154 ];
155}