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