1{ options, config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.grafana;
7
8 envOptions = {
9 PATHS_DATA = cfg.dataDir;
10 PATHS_PLUGINS = "${cfg.dataDir}/plugins";
11 PATHS_LOGS = "${cfg.dataDir}/log";
12
13 SERVER_PROTOCOL = cfg.protocol;
14 SERVER_HTTP_ADDR = cfg.addr;
15 SERVER_HTTP_PORT = cfg.port;
16 SERVER_DOMAIN = cfg.domain;
17 SERVER_ROOT_URL = cfg.rootUrl;
18 SERVER_STATIC_ROOT_PATH = cfg.staticRootPath;
19 SERVER_CERT_FILE = cfg.certFile;
20 SERVER_CERT_KEY = cfg.certKey;
21
22 DATABASE_TYPE = cfg.database.type;
23 DATABASE_HOST = cfg.database.host;
24 DATABASE_NAME = cfg.database.name;
25 DATABASE_USER = cfg.database.user;
26 DATABASE_PASSWORD = cfg.database.password;
27 DATABASE_PATH = cfg.database.path;
28
29 SECURITY_ADMIN_USER = cfg.security.adminUser;
30 SECURITY_ADMIN_PASSWORD = cfg.security.adminPassword;
31 SECURITY_SECRET_KEY = cfg.security.secretKey;
32
33 USERS_ALLOW_SIGN_UP = boolToString cfg.users.allowSignUp;
34 USERS_ALLOW_ORG_CREATE = boolToString cfg.users.allowOrgCreate;
35 USERS_AUTO_ASSIGN_ORG = boolToString cfg.users.autoAssignOrg;
36 USERS_AUTO_ASSIGN_ORG_ROLE = cfg.users.autoAssignOrgRole;
37
38 AUTH_ANONYMOUS_ENABLED = boolToString cfg.auth.anonymous.enable;
39 AUTH_ANONYMOUS_ORG_NAME = cfg.auth.anonymous.org_name;
40 AUTH_ANONYMOUS_ORG_ROLE = cfg.auth.anonymous.org_role;
41
42 ANALYTICS_REPORTING_ENABLED = boolToString cfg.analytics.reporting.enable;
43 } // cfg.extraOptions;
44
45in {
46 options.services.grafana = {
47 enable = mkEnableOption "grafana";
48
49 protocol = mkOption {
50 description = "Which protocol to listen.";
51 default = "http";
52 type = types.enum ["http" "https"];
53 };
54
55 addr = mkOption {
56 description = "Listening address.";
57 default = "127.0.0.1";
58 type = types.str;
59 };
60
61 port = mkOption {
62 description = "Listening port.";
63 default = 3000;
64 type = types.int;
65 };
66
67 domain = mkOption {
68 description = "The public facing domain name used to access grafana from a browser.";
69 default = "localhost";
70 type = types.str;
71 };
72
73 rootUrl = mkOption {
74 description = "Full public facing url.";
75 default = "%(protocol)s://%(domain)s:%(http_port)s/";
76 type = types.str;
77 };
78
79 certFile = mkOption {
80 description = "Cert file for ssl.";
81 default = "";
82 type = types.str;
83 };
84
85 certKey = mkOption {
86 description = "Cert key for ssl.";
87 default = "";
88 type = types.str;
89 };
90
91 staticRootPath = mkOption {
92 description = "Root path for static assets.";
93 default = "${cfg.package}/share/grafana/public";
94 type = types.str;
95 };
96
97 package = mkOption {
98 description = "Package to use.";
99 default = pkgs.grafana;
100 defaultText = "pkgs.grafana";
101 type = types.package;
102 };
103
104 dataDir = mkOption {
105 description = "Data directory.";
106 default = "/var/lib/grafana";
107 type = types.path;
108 };
109
110 database = {
111 type = mkOption {
112 description = "Database type.";
113 default = "sqlite3";
114 type = types.enum ["mysql" "sqlite3" "postgresql"];
115 };
116
117 host = mkOption {
118 description = "Database host.";
119 default = "127.0.0.1:3306";
120 type = types.str;
121 };
122
123 name = mkOption {
124 description = "Database name.";
125 default = "grafana";
126 type = types.str;
127 };
128
129 user = mkOption {
130 description = "Database user.";
131 default = "root";
132 type = types.str;
133 };
134
135 password = mkOption {
136 description = "Database password.";
137 default = "";
138 type = types.str;
139 };
140
141 path = mkOption {
142 description = "Database path.";
143 default = "${cfg.dataDir}/data/grafana.db";
144 type = types.path;
145 };
146 };
147
148 security = {
149 adminUser = mkOption {
150 description = "Default admin username.";
151 default = "admin";
152 type = types.str;
153 };
154
155 adminPassword = mkOption {
156 description = "Default admin password.";
157 default = "admin";
158 type = types.str;
159 };
160
161 secretKey = mkOption {
162 description = "Secret key used for signing.";
163 default = "SW2YcwTIb9zpOOhoPsMm";
164 type = types.str;
165 };
166 };
167
168 users = {
169 allowSignUp = mkOption {
170 description = "Disable user signup / registration";
171 default = false;
172 type = types.bool;
173 };
174
175 allowOrgCreate = mkOption {
176 description = "Whether user is allowed to create organizations.";
177 default = false;
178 type = types.bool;
179 };
180
181 autoAssignOrg = mkOption {
182 description = "Whether to automatically assign new users to default org.";
183 default = true;
184 type = types.bool;
185 };
186
187 autoAssignOrgRole = mkOption {
188 description = "Default role new users will be auto assigned.";
189 default = "Viewer";
190 type = types.enum ["Viewer" "Editor"];
191 };
192 };
193
194 auth.anonymous = {
195 enable = mkOption {
196 description = "Whether to allow anonymous access";
197 default = false;
198 type = types.bool;
199 };
200 org_name = mkOption {
201 description = "Which organization to allow anonymous access to";
202 default = "Main Org.";
203 type = types.str;
204 };
205 org_role = mkOption {
206 description = "Which role anonymous users have in the organization";
207 default = "Viewer";
208 type = types.str;
209 };
210
211 };
212
213 analytics.reporting = {
214 enable = mkOption {
215 description = "Whether to allow anonymous usage reporting to stats.grafana.net";
216 default = true;
217 type = types.bool;
218 };
219 };
220
221 extraOptions = mkOption {
222 description = ''
223 Extra configuration options passed as env variables as specified in
224 <link xlink:href="http://docs.grafana.org/installation/configuration/">documentation</link>,
225 but without GF_ prefix
226 '';
227 default = {};
228 type = types.attrsOf types.str;
229 };
230 };
231
232 config = mkIf cfg.enable {
233 warnings = optional (
234 cfg.database.password != options.services.grafana.database.password.default ||
235 cfg.security.adminPassword != options.services.grafana.security.adminPassword.default
236 ) "Grafana passwords will be stored as plaintext in the Nix store!";
237
238 environment.systemPackages = [ cfg.package ];
239
240 systemd.services.grafana = {
241 description = "Grafana Service Daemon";
242 wantedBy = ["multi-user.target"];
243 after = ["networking.target"];
244 environment = mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions;
245 serviceConfig = {
246 ExecStart = "${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir}";
247 WorkingDirectory = cfg.dataDir;
248 User = "grafana";
249 };
250 preStart = ''
251 ln -fs ${cfg.package}/share/grafana/conf ${cfg.dataDir}
252 ln -fs ${cfg.package}/share/grafana/vendor ${cfg.dataDir}
253 '';
254 };
255
256 users.extraUsers.grafana = {
257 uid = config.ids.uids.grafana;
258 description = "Grafana user";
259 home = cfg.dataDir;
260 createHome = true;
261 };
262 };
263}