1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.grafana;
7
8 b2s = val: if val then "true" else "false";
9
10 cfgFile = pkgs.writeText "grafana.ini" ''
11 app_name = grafana
12 app_mode = production
13
14 [server]
15 ; protocol (http or https)
16 protocol = ${cfg.protocol}
17 ; the ip address to bind to, empty will bind to all interfaces
18 http_addr = ${cfg.addr}
19 ; the http port to use
20 http_port = ${toString cfg.port}
21 ; The public facing domain name used to access grafana from a browser
22 domain = ${cfg.domain}
23 ; the full public facing url
24 root_url = ${cfg.rootUrl}
25 router_logging = false
26 ; the path relative to the binary where the static (html/js/css) files are placed
27 static_root_path = ${cfg.staticRootPath}
28 ; enable gzip
29 enable_gzip = false
30 ; https certs & key file
31 cert_file = ${cfg.certFile}
32 cert_key = ${cfg.certKey}
33
34 [analytics]
35 # Server reporting, sends usage counters to stats.grafana.org every 24 hours.
36 # No ip addresses are being tracked, only simple counters to track
37 # running instances, dashboard and error counts. It is very helpful to us.
38 # Change this option to false to disable reporting.
39 reporting_enabled = true
40 ; Google Analytics universal tracking code, only enabled if you specify an id here
41 google_analytics_ua_id =
42
43 [database]
44 ; Either "mysql", "postgres" or "sqlite3", it's your choice
45 type = ${cfg.database.type}
46 host = ${cfg.database.host}
47 name = ${cfg.database.name}
48 user = ${cfg.database.user}
49 password = ${cfg.database.password}
50 ; For "postgres" only, either "disable", "require" or "verify-full"
51 ssl_mode = disable
52 ; For "sqlite3" only
53 path = ${cfg.database.path}
54
55 [session]
56 ; Either "memory", "file", "redis", "mysql", default is "memory"
57 provider = file
58 ; Provider config options
59 ; memory: not have any config yet
60 ; file: session file path, e.g. `data/sessions`
61 ; redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
62 ; mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
63 provider_config = data/sessions
64 ; Session cookie name
65 cookie_name = grafana_sess
66 ; If you use session in https only, default is false
67 cookie_secure = false
68 ; Session life time, default is 86400
69 session_life_time = 86400
70 ; session id hash func, Either "sha1", "sha256" or "md5" default is sha1
71 session_id_hashfunc = sha1
72 ; Session hash key, default is use random string
73 session_id_hashkey =
74
75 [security]
76 ; default admin user, created on startup
77 admin_user = ${cfg.security.adminUser}
78 ; default admin password, can be changed before first start of grafana, or in profile settings
79 admin_password = ${cfg.security.adminPassword}
80 ; used for signing
81 secret_key = ${cfg.security.secretKey}
82 ; Auto-login remember days
83 login_remember_days = 7
84 cookie_username = grafana_user
85 cookie_remember_name = grafana_remember
86
87 [users]
88 ; disable user signup / registration
89 allow_sign_up = ${b2s cfg.users.allowSignUp}
90 ; Allow non admin users to create organizations
91 allow_org_create = ${b2s cfg.users.allowOrgCreate}
92 # Set to true to automatically assign new users to the default organization (id 1)
93 auto_assign_org = ${b2s cfg.users.autoAssignOrg}
94 ; Default role new users will be automatically assigned (if disabled above is set to true)
95 auto_assign_org_role = ${cfg.users.autoAssignOrgRole}
96
97 [auth.anonymous]
98 ; enable anonymous access
99 enabled = ${b2s cfg.auth.anonymous.enable}
100 ; specify organization name that should be used for unauthenticated users
101 org_name = Main Org.
102 ; specify role for unauthenticated users
103 org_role = Viewer
104
105 [auth.github]
106 enabled = false
107 client_id = some_id
108 client_secret = some_secret
109 scopes = user:email
110 auth_url = https://github.com/login/oauth/authorize
111 token_url = https://github.com/login/oauth/access_token
112
113 [auth.google]
114 enabled = false
115 client_id = some_client_id
116 client_secret = some_client_secret
117 scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
118 auth_url = https://accounts.google.com/o/oauth2/auth
119 token_url = https://accounts.google.com/o/oauth2/token
120
121 [log]
122 root_path = data/log
123 ; Either "console", "file", default is "console"
124 ; Use comma to separate multiple modes, e.g. "console, file"
125 mode = console
126 ; Buffer length of channel, keep it as it is if you don't know what it is.
127 buffer_len = 10000
128 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
129 level = Info
130
131 ; For "console" mode only
132 [log.console]
133 level =
134
135 ; For "file" mode only
136 [log.file]
137 level =
138 ; This enables automated log rotate(switch of following options), default is true
139 log_rotate = true
140 ; Max line number of single file, default is 1000000
141 max_lines = 1000000
142 ; Max size shift of single file, default is 28 means 1 << 28, 256MB
143 max_lines_shift = 28
144 ; Segment log daily, default is true
145 daily_rotate = true
146 ; Expired days of log file(delete after max days), default is 7
147 max_days = 7
148
149 [event_publisher]
150 enabled = false
151 rabbitmq_url = amqp://localhost/
152 exchange = grafana_events
153 '';
154
155in {
156 options.services.grafana = {
157 enable = mkEnableOption "grafana";
158
159 protocol = mkOption {
160 description = "Which protocol to listen.";
161 default = "http";
162 type = types.enum ["http" "https"];
163 };
164
165 addr = mkOption {
166 description = "Listening address.";
167 default = "127.0.0.1";
168 type = types.str;
169 };
170
171 port = mkOption {
172 description = "Listening port.";
173 default = 3000;
174 type = types.int;
175 };
176
177 domain = mkOption {
178 description = "The public facing domain name used to access grafana from a browser.";
179 default = "localhost";
180 type = types.str;
181 };
182
183 rootUrl = mkOption {
184 description = "Full public facing url.";
185 default = "%(protocol)s://%(domain)s:%(http_port)s/";
186 type = types.str;
187 };
188
189 certFile = mkOption {
190 description = "Cert file for ssl.";
191 default = "";
192 type = types.str;
193 };
194
195 certKey = mkOption {
196 description = "Cert key for ssl.";
197 default = "";
198 type = types.str;
199 };
200
201 staticRootPath = mkOption {
202 description = "Root path for static assets.";
203 default = "${cfg.package}/share/go/src/github.com/grafana/grafana/public";
204 type = types.str;
205 };
206
207 package = mkOption {
208 description = "Package to use.";
209 default = pkgs.goPackages.grafana;
210 type = types.package;
211 };
212
213 dataDir = mkOption {
214 description = "Data directory.";
215 default = "/var/lib/grafana";
216 type = types.path;
217 };
218
219 database = {
220 type = mkOption {
221 description = "Database type.";
222 default = "sqlite3";
223 type = types.enum ["mysql" "sqlite3" "postgresql"];
224 };
225
226 host = mkOption {
227 description = "Database host.";
228 default = "127.0.0.1:3306";
229 type = types.str;
230 };
231
232 name = mkOption {
233 description = "Database name.";
234 default = "grafana";
235 type = types.str;
236 };
237
238 user = mkOption {
239 description = "Database user.";
240 default = "root";
241 type = types.str;
242 };
243
244 password = mkOption {
245 description = "Database password.";
246 default = "";
247 type = types.str;
248 };
249
250 path = mkOption {
251 description = "Database path.";
252 default = "${cfg.dataDir}/data/grafana.db";
253 type = types.path;
254 };
255 };
256
257 security = {
258 adminUser = mkOption {
259 description = "Default admin username.";
260 default = "admin";
261 type = types.str;
262 };
263
264 adminPassword = mkOption {
265 description = "Default admin password.";
266 default = "admin";
267 type = types.str;
268 };
269
270 secretKey = mkOption {
271 description = "Secret key used for signing.";
272 default = "SW2YcwTIb9zpOOhoPsMm";
273 type = types.str;
274 };
275 };
276
277 users = {
278 allowSignUp = mkOption {
279 description = "Disable user signup / registration";
280 default = false;
281 type = types.bool;
282 };
283
284 allowOrgCreate = mkOption {
285 description = "Whether user is allowed to create organizations.";
286 default = false;
287 type = types.bool;
288 };
289
290 autoAssignOrg = mkOption {
291 description = "Whether to automatically assign new users to default org.";
292 default = true;
293 type = types.bool;
294 };
295
296 autoAssignOrgRole = mkOption {
297 description = "Default role new users will be auto assigned.";
298 default = "Viewer";
299 type = types.enum ["Viewer" "Editor"];
300 };
301 };
302
303 auth.anonymous = {
304 enable = mkOption {
305 description = "Whether to allow anonymous access";
306 default = false;
307 type = types.bool;
308 };
309 };
310 };
311
312 config = mkIf cfg.enable {
313 warnings = [
314 "Grafana passwords will be stored as plaintext in nix store!"
315 ];
316
317 systemd.services.grafana = {
318 description = "Grafana Service Daemon";
319 wantedBy = ["multi-user.target"];
320 after = ["networking.target"];
321 serviceConfig = {
322 ExecStart = "${cfg.package}/bin/grafana --config ${cfgFile} web";
323 WorkingDirectory = cfg.dataDir;
324 User = "grafana";
325 };
326 };
327
328 users.extraUsers.grafana = {
329 uid = config.ids.uids.grafana;
330 description = "Grafana user";
331 home = cfg.dataDir;
332 createHome = true;
333 };
334 };
335}