1{
2 lib,
3 pkgs,
4 config,
5 ...
6}:
7let
8 cfg = config.services.grafana-image-renderer;
9
10 format = pkgs.formats.json { };
11
12 configFile = format.generate "grafana-image-renderer-config.json" cfg.settings;
13in
14{
15 options.services.grafana-image-renderer = {
16 enable = lib.mkEnableOption "grafana-image-renderer";
17
18 chromium = lib.mkOption {
19 type = lib.types.package;
20 description = ''
21 The chromium to use for image rendering.
22 '';
23 };
24
25 verbose = lib.mkEnableOption "verbosity for the service";
26
27 provisionGrafana = lib.mkEnableOption "Grafana configuration for grafana-image-renderer";
28
29 settings = lib.mkOption {
30 type = lib.types.submodule {
31 freeformType = format.type;
32
33 options = {
34 service = {
35 port = lib.mkOption {
36 type = lib.types.port;
37 default = 8081;
38 description = ''
39 The TCP port to use for the rendering server.
40 '';
41 };
42 logging.level = lib.mkOption {
43 type = lib.types.enum [
44 "error"
45 "warning"
46 "info"
47 "debug"
48 ];
49 default = "info";
50 description = ''
51 The log-level of the {file}`grafana-image-renderer.service`-unit.
52 '';
53 };
54 };
55 rendering = {
56 width = lib.mkOption {
57 default = 1000;
58 type = lib.types.ints.positive;
59 description = ''
60 Width of the PNG used to display the alerting graph.
61 '';
62 };
63 height = lib.mkOption {
64 default = 500;
65 type = lib.types.ints.positive;
66 description = ''
67 Height of the PNG used to display the alerting graph.
68 '';
69 };
70 mode = lib.mkOption {
71 default = "default";
72 type = lib.types.enum [
73 "default"
74 "reusable"
75 "clustered"
76 ];
77 description = ''
78 Rendering mode of `grafana-image-renderer`:
79
80 - `default:` Creates on browser-instance
81 per rendering request.
82 - `reusable:` One browser instance
83 will be started and reused for each rendering request.
84 - `clustered:` allows to precisely
85 configure how many browser-instances are supposed to be used. The values
86 for that mode can be declared in `rendering.clustering`.
87 '';
88 };
89 args = lib.mkOption {
90 type = lib.types.listOf lib.types.str;
91 default = [ "--no-sandbox" ];
92 description = ''
93 List of CLI flags passed to `chromium`.
94 '';
95 };
96 };
97 };
98 };
99
100 default = { };
101
102 description = ''
103 Configuration attributes for `grafana-image-renderer`.
104
105 See <https://github.com/grafana/grafana-image-renderer/blob/ce1f81438e5f69c7fd7c73ce08bab624c4c92e25/default.json>
106 for supported values.
107 '';
108 };
109 };
110
111 config = lib.mkIf cfg.enable {
112 assertions = [
113 {
114 assertion = cfg.provisionGrafana -> config.services.grafana.enable;
115 message = ''
116 To provision a Grafana instance to use grafana-image-renderer,
117 `services.grafana.enable` must be set to `true`!
118 '';
119 }
120 ];
121
122 services.grafana.settings.rendering = lib.mkIf cfg.provisionGrafana {
123 server_url = "http://localhost:${toString cfg.settings.service.port}/render";
124 callback_url = "http://${config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}";
125 };
126
127 services.grafana-image-renderer.chromium = lib.mkDefault pkgs.chromium;
128
129 services.grafana-image-renderer.settings = {
130 rendering = lib.mapAttrs (lib.const lib.mkDefault) {
131 chromeBin = "${cfg.chromium}/bin/chromium";
132 verboseLogging = cfg.verbose;
133 timezone = config.time.timeZone;
134 };
135
136 service = {
137 logging.level = lib.mkIf cfg.verbose (lib.mkDefault "debug");
138 metrics.enabled = lib.mkDefault false;
139 };
140 };
141
142 systemd.services.grafana-image-renderer = {
143 wantedBy = [ "multi-user.target" ];
144 after = [ "network.target" ];
145 description = " A Grafana backend plugin that handles rendering of panels & dashboards to PNGs using headless browser (Chromium/Chrome)";
146
147 environment = {
148 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = "true";
149 };
150
151 serviceConfig = {
152 DynamicUser = true;
153 PrivateTmp = true;
154 ExecStart = "${pkgs.grafana-image-renderer}/bin/grafana-image-renderer server --config=${configFile}";
155 Restart = "always";
156 };
157 };
158 };
159
160 meta.maintainers = with lib.maintainers; [ ma27 ];
161}