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