1{ config, lib, pkgs, ... }:
2
3let
4 inherit (lib)
5 collect
6 concatLists
7 concatStringsSep
8 flip
9 getAttrFromPath
10 hasPrefix
11 isList
12 length
13 literalExpression
14 literalMD
15 mapAttrsRecursiveCond
16 mapAttrsToList
17 mkEnableOption
18 mkIf
19 mkMerge
20 mkOption
21 mkPackageOption
22 optional
23 optionalAttrs
24 optionalString
25 types
26 ;
27
28 cfg = config.services.thanos;
29
30 nullOpt = type: description: mkOption {
31 type = types.nullOr type;
32 default = null;
33 description = description;
34 };
35
36 optionToArgs = opt: v : optional (v != null) ''--${opt}="${toString v}"'';
37 flagToArgs = opt: v : optional v "--${opt}";
38 listToArgs = opt: vs : map (v: ''--${opt}="${v}"'') vs;
39 attrsToArgs = opt: kvs: mapAttrsToList (k: v: ''--${opt}=${k}=\"${v}\"'') kvs;
40
41 mkParamDef = type: default: description: mkParam type (description + ''
42
43 Defaults to `${toString default}` in Thanos
44 when set to `null`.
45 '');
46
47 mkParam = type: description: {
48 toArgs = optionToArgs;
49 option = nullOpt type description;
50 };
51
52 mkFlagParam = description: {
53 toArgs = flagToArgs;
54 option = mkOption {
55 type = types.bool;
56 default = false;
57 description = description;
58 };
59 };
60
61 mkListParam = opt: description: {
62 toArgs = _opt: listToArgs opt;
63 option = mkOption {
64 type = types.listOf types.str;
65 default = [];
66 description = description;
67 };
68 };
69
70 mkAttrsParam = opt: description: {
71 toArgs = _opt: attrsToArgs opt;
72 option = mkOption {
73 type = types.attrsOf types.str;
74 default = {};
75 description = description;
76 };
77 };
78
79 mkStateDirParam = opt: default: description: {
80 toArgs = _opt: stateDir: optionToArgs opt "/var/lib/${stateDir}";
81 option = mkOption {
82 type = types.str;
83 inherit default;
84 description = description;
85 };
86 };
87
88 toYAML = name: attrs: pkgs.runCommand name {
89 preferLocalBuild = true;
90 json = builtins.toFile "${name}.json" (builtins.toJSON attrs);
91 nativeBuildInputs = [ pkgs.remarshal ];
92 } "json2yaml -i $json -o $out";
93
94 thanos = cmd: "${cfg.package}/bin/thanos ${cmd}" +
95 (let args = cfg.${cmd}.arguments;
96 in optionalString (length args != 0) (" \\\n " +
97 concatStringsSep " \\\n " args));
98
99 argumentsOf = cmd: concatLists (collect isList
100 (flip mapParamsRecursive params.${cmd} (path: param:
101 let opt = concatStringsSep "." path;
102 v = getAttrFromPath path cfg.${cmd};
103 in param.toArgs opt v)));
104
105 mkArgumentsOption = cmd: mkOption {
106 type = types.listOf types.str;
107 default = argumentsOf cmd;
108 defaultText = literalMD ''
109 calculated from `config.services.thanos.${cmd}`
110 '';
111 description = ''
112 Arguments to the `thanos ${cmd}` command.
113
114 Defaults to a list of arguments formed by converting the structured
115 options of {option}`services.thanos.${cmd}` to a list of arguments.
116
117 Overriding this option will cause none of the structured options to have
118 any effect. So only set this if you know what you're doing!
119 '';
120 };
121
122 mapParamsRecursive =
123 let noParam = attr: !(attr ? toArgs && attr ? option);
124 in mapAttrsRecursiveCond noParam;
125
126 paramsToOptions = mapParamsRecursive (_path: param: param.option);
127
128 params = {
129
130 log = {
131
132 log.level = mkParamDef (types.enum ["debug" "info" "warn" "error" "fatal"]) "info" ''
133 Log filtering level.
134 '';
135
136 log.format = mkParam types.str ''
137 Log format to use.
138 '';
139 };
140
141 tracing = cfg: {
142 tracing.config-file = {
143 toArgs = _opt: path: optionToArgs "tracing.config-file" path;
144 option = mkOption {
145 type = with types; nullOr str;
146 default = if cfg.tracing.config == null then null
147 else toString (toYAML "tracing.yaml" cfg.tracing.config);
148 defaultText = literalExpression ''
149 if config.services.thanos.<cmd>.tracing.config == null then null
150 else toString (toYAML "tracing.yaml" config.services.thanos.<cmd>.tracing.config);
151 '';
152 description = ''
153 Path to YAML file that contains tracing configuration.
154
155 See format details: <https://thanos.io/tip/thanos/tracing.md/#configuration>
156 '';
157 };
158 };
159
160 tracing.config =
161 {
162 toArgs = _opt: _attrs: [];
163 option = nullOpt types.attrs ''
164 Tracing configuration.
165
166 When not `null` the attribute set gets converted to
167 a YAML file and stored in the Nix store. The option
168 {option}`tracing.config-file` will default to its path.
169
170 If {option}`tracing.config-file` is set this option has no effect.
171
172 See format details: <https://thanos.io/tip/thanos/tracing.md/#configuration>
173 '';
174 };
175 };
176
177 common = cfg: params.log // params.tracing cfg // {
178
179 http-address = mkParamDef types.str "0.0.0.0:10902" ''
180 Listen `host:port` for HTTP endpoints.
181 '';
182
183 grpc-address = mkParamDef types.str "0.0.0.0:10901" ''
184 Listen `ip:port` address for gRPC endpoints (StoreAPI).
185
186 Make sure this address is routable from other components.
187 '';
188
189 grpc-server-tls-cert = mkParam types.str ''
190 TLS Certificate for gRPC server, leave blank to disable TLS
191 '';
192
193 grpc-server-tls-key = mkParam types.str ''
194 TLS Key for the gRPC server, leave blank to disable TLS
195 '';
196
197 grpc-server-tls-client-ca = mkParam types.str ''
198 TLS CA to verify clients against.
199
200 If no client CA is specified, there is no client verification on server side.
201 (tls.NoClientCert)
202 '';
203 };
204
205 objstore = cfg: {
206
207 objstore.config-file = {
208 toArgs = _opt: path: optionToArgs "objstore.config-file" path;
209 option = mkOption {
210 type = with types; nullOr str;
211 default = if cfg.objstore.config == null then null
212 else toString (toYAML "objstore.yaml" cfg.objstore.config);
213 defaultText = literalExpression ''
214 if config.services.thanos.<cmd>.objstore.config == null then null
215 else toString (toYAML "objstore.yaml" config.services.thanos.<cmd>.objstore.config);
216 '';
217 description = ''
218 Path to YAML file that contains object store configuration.
219
220 See format details: <https://thanos.io/tip/thanos/storage.md/#configuring-access-to-object-storage>
221 '';
222 };
223 };
224
225 objstore.config =
226 {
227 toArgs = _opt: _attrs: [];
228 option = nullOpt types.attrs ''
229 Object store configuration.
230
231 When not `null` the attribute set gets converted to
232 a YAML file and stored in the Nix store. The option
233 {option}`objstore.config-file` will default to its path.
234
235 If {option}`objstore.config-file` is set this option has no effect.
236
237 See format details: <https://thanos.io/tip/thanos/storage.md/#configuring-access-to-object-storage>
238 '';
239 };
240 };
241
242 sidecar = params.common cfg.sidecar // params.objstore cfg.sidecar // {
243
244 prometheus.url = mkParamDef types.str "http://localhost:9090" ''
245 URL at which to reach Prometheus's API.
246
247 For better performance use local network.
248 '';
249
250 tsdb.path = {
251 toArgs = optionToArgs;
252 option = mkOption {
253 type = types.str;
254 default = "/var/lib/${config.services.prometheus.stateDir}/data";
255 defaultText = literalExpression ''"/var/lib/''${config.services.prometheus.stateDir}/data"'';
256 description = ''
257 Data directory of TSDB.
258 '';
259 };
260 };
261
262 reloader.config-file = mkParam types.str ''
263 Config file watched by the reloader.
264 '';
265
266 reloader.config-envsubst-file = mkParam types.str ''
267 Output file for environment variable substituted config file.
268 '';
269
270 reloader.rule-dirs = mkListParam "reloader.rule-dir" ''
271 Rule directories for the reloader to refresh.
272 '';
273
274 };
275
276 store = params.common cfg.store // params.objstore cfg.store // {
277
278 stateDir = mkStateDirParam "data-dir" "thanos-store" ''
279 Data directory relative to `/var/lib`
280 in which to cache remote blocks.
281 '';
282
283 index-cache-size = mkParamDef types.str "250MB" ''
284 Maximum size of items held in the index cache.
285 '';
286
287 chunk-pool-size = mkParamDef types.str "2GB" ''
288 Maximum size of concurrently allocatable bytes for chunks.
289 '';
290
291 store.limits.request-samples = mkParamDef types.int 0 ''
292 The maximum samples allowed for a single Series request.
293 The Series call fails if this limit is exceeded.
294
295 `0` means no limit.
296
297 NOTE: For efficiency the limit is internally implemented as 'chunks limit'
298 considering each chunk contains a maximum of 120 samples.
299 '';
300
301 store.grpc.series-max-concurrency = mkParamDef types.int 20 ''
302 Maximum number of concurrent Series calls.
303 '';
304
305 sync-block-duration = mkParamDef types.str "3m" ''
306 Repeat interval for syncing the blocks between local and remote view.
307 '';
308
309 block-sync-concurrency = mkParamDef types.int 20 ''
310 Number of goroutines to use when syncing blocks from object storage.
311 '';
312
313 min-time = mkParamDef types.str "0000-01-01T00:00:00Z" ''
314 Start of time range limit to serve.
315
316 Thanos Store serves only metrics, which happened later than this
317 value. Option can be a constant time in RFC3339 format or time duration
318 relative to current time, such as -1d or 2h45m. Valid duration units are
319 ms, s, m, h, d, w, y.
320 '';
321
322 max-time = mkParamDef types.str "9999-12-31T23:59:59Z" ''
323 End of time range limit to serve.
324
325 Thanos Store serves only blocks, which happened earlier than this
326 value. Option can be a constant time in RFC3339 format or time duration
327 relative to current time, such as -1d or 2h45m. Valid duration units are
328 ms, s, m, h, d, w, y.
329 '';
330 };
331
332 query = params.common cfg.query // {
333
334 grpc-client-tls-secure = mkFlagParam ''
335 Use TLS when talking to the gRPC server
336 '';
337
338 grpc-client-tls-cert = mkParam types.str ''
339 TLS Certificates to use to identify this client to the server
340 '';
341
342 grpc-client-tls-key = mkParam types.str ''
343 TLS Key for the client's certificate
344 '';
345
346 grpc-client-tls-ca = mkParam types.str ''
347 TLS CA Certificates to use to verify gRPC servers
348 '';
349
350 grpc-client-server-name = mkParam types.str ''
351 Server name to verify the hostname on the returned gRPC certificates.
352 See <https://tools.ietf.org/html/rfc4366#section-3.1>
353 '';
354
355 grpc-compression = mkParam types.str ''
356 Compression algorithm to use for gRPC requests to other clients.
357 '';
358
359 web.route-prefix = mkParam types.str ''
360 Prefix for API and UI endpoints.
361
362 This allows thanos UI to be served on a sub-path. This option is
363 analogous to {option}`web.route-prefix` of Promethus.
364 '';
365
366 web.external-prefix = mkParam types.str ''
367 Static prefix for all HTML links and redirect URLs in the UI query web
368 interface.
369
370 Actual endpoints are still served on / or the
371 {option}`web.route-prefix`. This allows thanos UI to be served
372 behind a reverse proxy that strips a URL sub-path.
373 '';
374
375 web.prefix-header = mkParam types.str ''
376 Name of HTTP request header used for dynamic prefixing of UI links and
377 redirects.
378
379 This option is ignored if the option
380 `web.external-prefix` is set.
381
382 Security risk: enable this option only if a reverse proxy in front of
383 thanos is resetting the header.
384
385 The setting `web.prefix-header="X-Forwarded-Prefix"`
386 can be useful, for example, if Thanos UI is served via Traefik reverse
387 proxy with `PathPrefixStrip` option enabled, which
388 sends the stripped prefix value in `X-Forwarded-Prefix`
389 header. This allows thanos UI to be served on a sub-path.
390 '';
391
392 query.timeout = mkParamDef types.str "2m" ''
393 Maximum time to process query by query node.
394 '';
395
396 query.max-concurrent = mkParamDef types.int 20 ''
397 Maximum number of queries processed concurrently by query node.
398 '';
399
400 query.replica-labels = mkListParam "query.replica-label" ''
401 Labels to treat as a replica indicator along which data is
402 deduplicated.
403
404 Still you will be able to query without deduplication using
405 'dedup=false' parameter. Data includes time series, recording
406 rules, and alerting rules.
407 '';
408
409 selector-labels = mkAttrsParam "selector-label" ''
410 Query selector labels that will be exposed in info endpoint.
411 '';
412
413 endpoints = mkListParam "endpoint" ''
414 Addresses of statically configured Thanos API servers (repeatable).
415
416 The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect
417 Thanos API servers through respective DNS lookups.
418 '';
419
420 store.sd-files = mkListParam "store.sd-files" ''
421 Path to files that contain addresses of store API servers. The path
422 can be a glob pattern.
423 '';
424
425 store.sd-interval = mkParamDef types.str "5m" ''
426 Refresh interval to re-read file SD files. It is used as a resync fallback.
427 '';
428
429 store.sd-dns-interval = mkParamDef types.str "30s" ''
430 Interval between DNS resolutions.
431 '';
432
433 store.unhealthy-timeout = mkParamDef types.str "5m" ''
434 Timeout before an unhealthy store is cleaned from the store UI page.
435 '';
436
437 query.auto-downsampling = mkFlagParam ''
438 Enable automatic adjustment (step / 5) to what source of data should
439 be used in store gateways if no
440 `max_source_resolution` param is specified.
441 '';
442
443 query.partial-response = mkFlagParam ''
444 Enable partial response for queries if no
445 `partial_response` param is specified.
446 '';
447
448 query.default-evaluation-interval = mkParamDef types.str "1m" ''
449 Set default evaluation interval for sub queries.
450 '';
451
452 store.response-timeout = mkParamDef types.str "0ms" ''
453 If a Store doesn't send any data in this specified duration then a
454 Store will be ignored and partial data will be returned if it's
455 enabled. `0` disables timeout.
456 '';
457 };
458
459 query-frontend = params.common cfg.query-frontend // {
460 query-frontend.downstream-url = mkParamDef types.str "http://localhost:9090" ''
461 URL of downstream Prometheus Query compatible API.
462 '';
463 };
464
465 rule = params.common cfg.rule // params.objstore cfg.rule // {
466
467 labels = mkAttrsParam "label" ''
468 Labels to be applied to all generated metrics.
469
470 Similar to external labels for Prometheus,
471 used to identify ruler and its blocks as unique source.
472 '';
473
474 stateDir = mkStateDirParam "data-dir" "thanos-rule" ''
475 Data directory relative to `/var/lib`.
476 '';
477
478 rule-files = mkListParam "rule-file" ''
479 Rule files that should be used by rule manager. Can be in glob format.
480 '';
481
482 eval-interval = mkParamDef types.str "1m" ''
483 The default evaluation interval to use.
484 '';
485
486 tsdb.block-duration = mkParamDef types.str "2h" ''
487 Block duration for TSDB block.
488 '';
489
490 tsdb.retention = mkParamDef types.str "48h" ''
491 Block retention time on local disk.
492 '';
493
494 alertmanagers.urls = mkListParam "alertmanagers.url" ''
495 Alertmanager replica URLs to push firing alerts.
496
497 Ruler claims success if push to at least one alertmanager from
498 discovered succeeds. The scheme may be prefixed with
499 `dns+` or `dnssrv+` to detect
500 Alertmanager IPs through respective DNS lookups. The port defaults to
501 `9093` or the SRV record's value. The URL path is
502 used as a prefix for the regular Alertmanager API path.
503 '';
504
505 alertmanagers.send-timeout = mkParamDef types.str "10s" ''
506 Timeout for sending alerts to alertmanager.
507 '';
508
509 alert.query-url = mkParam types.str ''
510 The external Thanos Query URL that would be set in all alerts 'Source' field.
511 '';
512
513 alert.label-drop = mkListParam "alert.label-drop" ''
514 Labels by name to drop before sending to alertmanager.
515
516 This allows alert to be deduplicated on replica label.
517
518 Similar Prometheus alert relabelling
519 '';
520
521 web.route-prefix = mkParam types.str ''
522 Prefix for API and UI endpoints.
523
524 This allows thanos UI to be served on a sub-path.
525
526 This option is analogous to `--web.route-prefix` of Promethus.
527 '';
528
529 web.external-prefix = mkParam types.str ''
530 Static prefix for all HTML links and redirect URLs in the UI query web
531 interface.
532
533 Actual endpoints are still served on / or the
534 {option}`web.route-prefix`. This allows thanos UI to be served
535 behind a reverse proxy that strips a URL sub-path.
536 '';
537
538 web.prefix-header = mkParam types.str ''
539 Name of HTTP request header used for dynamic prefixing of UI links and
540 redirects.
541
542 This option is ignored if the option
543 {option}`web.external-prefix` is set.
544
545 Security risk: enable this option only if a reverse proxy in front of
546 thanos is resetting the header.
547
548 The header `X-Forwarded-Prefix` can be useful, for
549 example, if Thanos UI is served via Traefik reverse proxy with
550 `PathPrefixStrip` option enabled, which sends the
551 stripped prefix value in `X-Forwarded-Prefix`
552 header. This allows thanos UI to be served on a sub-path.
553 '';
554
555 query.addresses = mkListParam "query" ''
556 Addresses of statically configured query API servers.
557
558 The scheme may be prefixed with `dns+` or
559 `dnssrv+` to detect query API servers through
560 respective DNS lookups.
561 '';
562
563 query.sd-files = mkListParam "query.sd-files" ''
564 Path to file that contain addresses of query peers.
565 The path can be a glob pattern.
566 '';
567
568 query.sd-interval = mkParamDef types.str "5m" ''
569 Refresh interval to re-read file SD files. (used as a fallback)
570 '';
571
572 query.sd-dns-interval = mkParamDef types.str "30s" ''
573 Interval between DNS resolutions.
574 '';
575 };
576
577 compact = params.log // params.tracing cfg.compact // params.objstore cfg.compact // {
578
579 http-address = mkParamDef types.str "0.0.0.0:10902" ''
580 Listen `host:port` for HTTP endpoints.
581 '';
582
583 stateDir = mkStateDirParam "data-dir" "thanos-compact" ''
584 Data directory relative to `/var/lib`
585 in which to cache blocks and process compactions.
586 '';
587
588 consistency-delay = mkParamDef types.str "30m" ''
589 Minimum age of fresh (non-compacted) blocks before they are being
590 processed. Malformed blocks older than the maximum of consistency-delay
591 and 30m0s will be removed.
592 '';
593
594 retention.resolution-raw = mkParamDef types.str "0d" ''
595 How long to retain raw samples in bucket.
596
597 `0d` - disables this retention
598 '';
599
600 retention.resolution-5m = mkParamDef types.str "0d" ''
601 How long to retain samples of resolution 1 (5 minutes) in bucket.
602
603 `0d` - disables this retention
604 '';
605
606 retention.resolution-1h = mkParamDef types.str "0d" ''
607 How long to retain samples of resolution 2 (1 hour) in bucket.
608
609 `0d` - disables this retention
610 '';
611
612 startAt = {
613 toArgs = _opt: startAt: flagToArgs "wait" (startAt == null);
614 option = nullOpt types.str ''
615 When this option is set to a `systemd.time`
616 specification the Thanos compactor will run at the specified period.
617
618 When this option is `null` the Thanos compactor service
619 will run continuously. So it will not exit after all compactions have
620 been processed but wait for new work.
621 '';
622 };
623
624 downsampling.disable = mkFlagParam ''
625 Disables downsampling.
626
627 This is not recommended as querying long time ranges without
628 non-downsampled data is not efficient and useful e.g it is not possible
629 to render all samples for a human eye anyway
630 '';
631
632 compact.concurrency = mkParamDef types.int 1 ''
633 Number of goroutines to use when compacting groups.
634 '';
635 };
636
637 downsample = params.log // params.tracing cfg.downsample // params.objstore cfg.downsample // {
638
639 stateDir = mkStateDirParam "data-dir" "thanos-downsample" ''
640 Data directory relative to `/var/lib`
641 in which to cache blocks and process downsamplings.
642 '';
643
644 };
645
646 receive = params.common cfg.receive // params.objstore cfg.receive // {
647
648 receive.grpc-compression = mkParam types.str ''
649 Compression algorithm to use for gRPC requests to other receivers.
650 '';
651
652 remote-write.address = mkParamDef types.str "0.0.0.0:19291" ''
653 Address to listen on for remote write requests.
654 '';
655
656 stateDir = mkStateDirParam "tsdb.path" "thanos-receive" ''
657 Data directory relative to `/var/lib` of TSDB.
658 '';
659
660 labels = mkAttrsParam "label" ''
661 External labels to announce.
662
663 This flag will be removed in the future when handling multiple tsdb
664 instances is added.
665 '';
666
667 tsdb.retention = mkParamDef types.str "15d" ''
668 How long to retain raw samples on local storage.
669
670 `0d` - disables this retention
671 '';
672 };
673
674 };
675
676 assertRelativeStateDir = cmd: {
677 assertions = [
678 {
679 assertion = !hasPrefix "/" cfg.${cmd}.stateDir;
680 message =
681 "The option services.thanos.${cmd}.stateDir should not be an absolute directory." +
682 " It should be a directory relative to /var/lib.";
683 }
684 ];
685 };
686
687in {
688
689 options.services.thanos = {
690
691 package = mkPackageOption pkgs "thanos" {};
692
693 sidecar = paramsToOptions params.sidecar // {
694 enable = mkEnableOption "the Thanos sidecar for Prometheus server";
695 arguments = mkArgumentsOption "sidecar";
696 };
697
698 store = paramsToOptions params.store // {
699 enable = mkEnableOption "the Thanos store node giving access to blocks in a bucket provider.";
700 arguments = mkArgumentsOption "store";
701 };
702
703 query = paramsToOptions params.query // {
704 enable = mkEnableOption ("the Thanos query node exposing PromQL enabled Query API " +
705 "with data retrieved from multiple store nodes");
706 arguments = mkArgumentsOption "query";
707 };
708
709 query-frontend = paramsToOptions params.query-frontend // {
710 enable = mkEnableOption ("the Thanos query frontend implements a service deployed in front of queriers to
711 improve query parallelization and caching.");
712 arguments = mkArgumentsOption "query-frontend";
713 };
714
715 rule = paramsToOptions params.rule // {
716 enable = mkEnableOption ("the Thanos ruler service which evaluates Prometheus rules against" +
717 " given Query nodes, exposing Store API and storing old blocks in bucket");
718 arguments = mkArgumentsOption "rule";
719 };
720
721 compact = paramsToOptions params.compact // {
722 enable = mkEnableOption "the Thanos compactor which continuously compacts blocks in an object store bucket";
723 arguments = mkArgumentsOption "compact";
724 };
725
726 downsample = paramsToOptions params.downsample // {
727 enable = mkEnableOption "the Thanos downsampler which continuously downsamples blocks in an object store bucket";
728 arguments = mkArgumentsOption "downsample";
729 };
730
731 receive = paramsToOptions params.receive // {
732 enable = mkEnableOption ("the Thanos receiver which accept Prometheus remote write API requests and write to local tsdb");
733 arguments = mkArgumentsOption "receive";
734 };
735 };
736
737 config = mkMerge [
738
739 (mkIf cfg.sidecar.enable {
740 assertions = [
741 {
742 assertion = config.services.prometheus.enable;
743 message =
744 "Please enable services.prometheus when enabling services.thanos.sidecar.";
745 }
746 {
747 assertion = !(config.services.prometheus.globalConfig.external_labels == null ||
748 config.services.prometheus.globalConfig.external_labels == {});
749 message =
750 "services.thanos.sidecar requires uniquely identifying external labels " +
751 "to be configured in the Prometheus server. " +
752 "Please set services.prometheus.globalConfig.external_labels.";
753 }
754 ];
755 systemd.services.thanos-sidecar = {
756 wantedBy = [ "multi-user.target" ];
757 after = [ "network.target" "prometheus.service" ];
758 serviceConfig = {
759 User = "prometheus";
760 Restart = "always";
761 ExecStart = thanos "sidecar";
762 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
763 };
764 };
765 })
766
767 (mkIf cfg.store.enable (mkMerge [
768 (assertRelativeStateDir "store")
769 {
770 systemd.services.thanos-store = {
771 wantedBy = [ "multi-user.target" ];
772 after = [ "network.target" ];
773 serviceConfig = {
774 DynamicUser = true;
775 StateDirectory = cfg.store.stateDir;
776 Restart = "always";
777 ExecStart = thanos "store";
778 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
779 };
780 };
781 }
782 ]))
783
784 (mkIf cfg.query.enable {
785 systemd.services.thanos-query = {
786 wantedBy = [ "multi-user.target" ];
787 after = [ "network.target" ];
788 serviceConfig = {
789 DynamicUser = true;
790 Restart = "always";
791 ExecStart = thanos "query";
792 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
793 };
794 };
795 })
796
797 (mkIf cfg.query-frontend.enable {
798 systemd.services.thanos-query-frontend = {
799 wantedBy = [ "multi-user.target" ];
800 after = [ "network.target" ];
801 serviceConfig = {
802 DynamicUser = true;
803 Restart = "always";
804 ExecStart = thanos "query-frontend";
805 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
806 };
807 };
808 })
809
810 (mkIf cfg.rule.enable (mkMerge [
811 (assertRelativeStateDir "rule")
812 {
813 systemd.services.thanos-rule = {
814 wantedBy = [ "multi-user.target" ];
815 after = [ "network.target" ];
816 serviceConfig = {
817 DynamicUser = true;
818 StateDirectory = cfg.rule.stateDir;
819 Restart = "always";
820 ExecStart = thanos "rule";
821 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
822 };
823 };
824 }
825 ]))
826
827 (mkIf cfg.compact.enable (mkMerge [
828 (assertRelativeStateDir "compact")
829 {
830 systemd.services.thanos-compact =
831 let wait = cfg.compact.startAt == null; in {
832 wantedBy = [ "multi-user.target" ];
833 after = [ "network.target" ];
834 serviceConfig = {
835 Type = if wait then "simple" else "oneshot";
836 Restart = if wait then "always" else "no";
837 DynamicUser = true;
838 StateDirectory = cfg.compact.stateDir;
839 ExecStart = thanos "compact";
840 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
841 };
842 } // optionalAttrs (!wait) { inherit (cfg.compact) startAt; };
843 }
844 ]))
845
846 (mkIf cfg.downsample.enable (mkMerge [
847 (assertRelativeStateDir "downsample")
848 {
849 systemd.services.thanos-downsample = {
850 wantedBy = [ "multi-user.target" ];
851 after = [ "network.target" ];
852 serviceConfig = {
853 DynamicUser = true;
854 StateDirectory = cfg.downsample.stateDir;
855 Restart = "always";
856 ExecStart = thanos "downsample";
857 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
858 };
859 };
860 }
861 ]))
862
863 (mkIf cfg.receive.enable (mkMerge [
864 (assertRelativeStateDir "receive")
865 {
866 systemd.services.thanos-receive = {
867 wantedBy = [ "multi-user.target" ];
868 after = [ "network.target" ];
869 serviceConfig = {
870 DynamicUser = true;
871 StateDirectory = cfg.receive.stateDir;
872 Restart = "always";
873 ExecStart = thanos "receive";
874 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
875 };
876 };
877 }
878 ]))
879
880 ];
881}