grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / web-apps / cloudlog.nix
blob6550d112d5373385e7ce721ecb30336c51ec1454
1 { config, pkgs, lib, ... }:
3 with lib;
5 let
6   cfg = config.services.cloudlog;
7   dbFile = let
8     password = if cfg.database.createLocally
9                then "''"
10                else "trim(file_get_contents('${cfg.database.passwordFile}'))";
11   in pkgs.writeText "database.php" ''
12     <?php
13     defined('BASEPATH') OR exit('No direct script access allowed');
14     $active_group = 'default';
15     $query_builder = TRUE;
16     $db['default'] = array(
17       'dsn' => "",
18       'hostname' => '${cfg.database.host}',
19       'username' => '${cfg.database.user}',
20       'password' => ${password},
21       'database' => '${cfg.database.name}',
22       'dbdriver' => 'mysqli',
23       'dbprefix' => "",
24       'pconnect' => TRUE,
25       'db_debug' => (ENVIRONMENT !== 'production'),
26       'cache_on' => FALSE,
27       'cachedir' => "",
28       'char_set' => 'utf8mb4',
29       'dbcollat' => 'utf8mb4_general_ci',
30       'swap_pre' => "",
31       'encrypt' => FALSE,
32       'compress' => FALSE,
33       'stricton' => FALSE,
34       'failover' => array(),
35       'save_queries' => TRUE
36     );
37   '';
38   configFile = pkgs.writeText "config.php" ''
39     <?php
40     include('${pkgs.cloudlog}/install/config/config.php');
41     $config['datadir'] = "${cfg.dataDir}/";
42     $config['base_url'] = "${cfg.baseUrl}";
43     ${cfg.extraConfig}
44   '';
45   package = pkgs.stdenv.mkDerivation rec {
46     pname = "cloudlog";
47     version = src.version;
48     src = pkgs.cloudlog;
49     installPhase = ''
50       mkdir -p $out
51       cp -r * $out/
53       ln -s ${configFile} $out/application/config/config.php
54       ln -s ${dbFile} $out/application/config/database.php
56       # link writable directories
57       for directory in updates uploads backup logbook; do
58         rm -rf $out/$directory
59         ln -s ${cfg.dataDir}/$directory $out/$directory
60       done
62       # link writable asset files
63       for asset in dok sota wwff; do
64         rm -rf $out/assets/json/$asset.txt
65         ln -s ${cfg.dataDir}/assets/json/$asset.txt $out/assets/json/$asset.txt
66       done
67     '';
68   };
71   options.services.cloudlog = with types; {
72     enable = mkEnableOption "Cloudlog";
73     dataDir = mkOption {
74       type = str;
75       default = "/var/lib/cloudlog";
76       description = "Cloudlog data directory.";
77     };
78     baseUrl = mkOption {
79       type = str;
80       default = "http://localhost";
81       description = "Cloudlog base URL";
82     };
83     user = mkOption {
84       type = str;
85       default = "cloudlog";
86       description = "User account under which Cloudlog runs.";
87     };
88     database = {
89       createLocally = mkOption {
90         type = types.bool;
91         default = true;
92         description = "Create the database and database user locally.";
93       };
94       host = mkOption {
95         type = str;
96         description = "MySQL database host";
97         default = "localhost";
98       };
99       name = mkOption {
100         type = str;
101         description = "MySQL database name.";
102         default = "cloudlog";
103       };
104       user = mkOption {
105         type = str;
106         description = "MySQL user name.";
107         default = "cloudlog";
108       };
109       passwordFile = mkOption {
110         type = nullOr str;
111         description = "MySQL user password file.";
112         default = null;
113       };
114     };
115     poolConfig = mkOption {
116       type = attrsOf (oneOf [ str int bool ]);
117       default = {
118         "pm" = "dynamic";
119         "pm.max_children" = 32;
120         "pm.start_servers" = 2;
121         "pm.min_spare_servers" = 2;
122         "pm.max_spare_servers" = 4;
123         "pm.max_requests" = 500;
124       };
125       description = ''
126         Options for Cloudlog's PHP-FPM pool.
127       '';
128     };
129     virtualHost = mkOption {
130       type = nullOr str;
131       default = "localhost";
132       description = ''
133         Name of the nginx virtualhost to use and setup. If null, do not setup
134          any virtualhost.
135       '';
136     };
137     extraConfig = mkOption {
138       description = ''
139        Any additional text to be appended to the config.php
140        configuration file. This is a PHP script. For configuration
141        settings, see <https://github.com/magicbug/Cloudlog/wiki/Cloudlog.php-Configuration-File>.
142       '';
143       default = "";
144       type = str;
145       example = ''
146         $config['show_time'] = TRUE;
147       '';
148     };
149     upload-lotw = {
150       enable = mkOption {
151         type = bool;
152         default = true;
153         description = ''
154           Whether to periodically upload logs to LoTW. If enabled, a systemd
155           timer will run the log upload task as specified by the interval
156            option.
157         '';
158       };
159       interval = mkOption {
160         type = str;
161         default = "daily";
162         description = ''
163           Specification (in the format described by systemd.time(7)) of the
164           time at which the LoTW upload will occur.
165         '';
166       };
167     };
168     upload-clublog = {
169       enable = mkOption {
170         type = bool;
171         default = true;
172         description = ''
173           Whether to periodically upload logs to Clublog. If enabled, a systemd
174           timer will run the log upload task as specified by the interval option.
175         '';
176       };
177       interval = mkOption {
178         type = str;
179         default = "daily";
180         description = ''
181           Specification (in the format described by systemd.time(7)) of the time
182           at which the Clublog upload will occur.
183         '';
184       };
185     };
186     update-lotw-users = {
187       enable = mkOption {
188         type = bool;
189         default = true;
190         description = ''
191           Whether to periodically update the list of LoTW users. If enabled, a
192           systemd timer will run the update task as specified by the interval
193           option.
194         '';
195       };
196       interval = mkOption {
197         type = str;
198         default = "weekly";
199         description = ''
200           Specification (in the format described by systemd.time(7)) of the
201           time at which the LoTW user update will occur.
202         '';
203       };
204     };
205     update-dok = {
206       enable = mkOption {
207         type = bool;
208         default = true;
209         description = ''
210           Whether to periodically update the DOK resource file. If enabled, a
211           systemd timer will run the update task as specified by the interval option.
212         '';
213       };
214       interval = mkOption {
215         type = str;
216         default = "monthly";
217         description = ''
218           Specification (in the format described by systemd.time(7)) of the
219           time at which the DOK update will occur.
220         '';
221       };
222     };
223     update-clublog-scp = {
224       enable = mkOption {
225         type = bool;
226         default = true;
227         description = ''
228           Whether to periodically update the Clublog SCP database. If enabled,
229           a systemd timer will run the update task as specified by the interval
230           option.
231         '';
232       };
233       interval = mkOption {
234         type = str;
235         default = "monthly";
236         description = ''
237           Specification (in the format described by systemd.time(7)) of the time
238           at which the Clublog SCP update will occur.
239         '';
240       };
241     };
242     update-wwff = {
243       enable = mkOption {
244         type = bool;
245         default = true;
246         description = ''
247           Whether to periodically update the WWFF database. If enabled, a
248           systemd timer will run the update task as specified by the interval
249           option.
250         '';
251       };
252       interval = mkOption {
253         type = str;
254         default = "monthly";
255         description = ''
256           Specification (in the format described by systemd.time(7)) of the time
257           at which the WWFF update will occur.
258         '';
259       };
260     };
261     upload-qrz = {
262       enable = mkOption {
263         type = bool;
264         default = true;
265         description = ''
266           Whether to periodically upload logs to QRZ. If enabled, a systemd
267           timer will run the update task as specified by the interval option.
268         '';
269       };
270       interval = mkOption {
271         type = str;
272         default = "daily";
273         description = ''
274           Specification (in the format described by systemd.time(7)) of the
275           time at which the QRZ upload will occur.
276         '';
277       };
278     };
279     update-sota = {
280       enable = mkOption {
281         type = bool;
282         default = true;
283         description = ''
284           Whether to periodically update the SOTA database. If enabled, a
285           systemd timer will run the update task as specified by the interval option.
286         '';
287       };
288       interval = mkOption {
289         type = str;
290         default = "monthly";
291         description = ''
292           Specification (in the format described by systemd.time(7)) of the time
293           at which the SOTA update will occur.
294         '';
295       };
296     };
297   };
298   config = mkIf cfg.enable {
300     assertions = [
301       {
302         assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
303         message = "services.cloudlog.database.passwordFile cannot be specified if services.cloudlog.database.createLocally is set to true.";
304       }
305     ];
307     services.phpfpm = {
308       pools.cloudlog = {
309         inherit (cfg) user;
310         group = config.services.nginx.group;
311         settings =  {
312           "listen.owner" = config.services.nginx.user;
313           "listen.group" = config.services.nginx.group;
314         } // cfg.poolConfig;
315       };
316     };
318     services.nginx = mkIf (cfg.virtualHost != null) {
319       enable = true;
320       virtualHosts = {
321         "${cfg.virtualHost}" = {
322           root = "${package}";
323           locations."/".tryFiles = "$uri /index.php$is_args$args";
324           locations."~ ^/index.php(/|$)".extraConfig = ''
325               include ${config.services.nginx.package}/conf/fastcgi_params;
326               include ${pkgs.nginx}/conf/fastcgi.conf;
327               fastcgi_split_path_info ^(.+\.php)(.+)$;
328               fastcgi_pass unix:${config.services.phpfpm.pools.cloudlog.socket};
329               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
330             '';
331         };
332       };
333     };
335     services.mysql = mkIf cfg.database.createLocally {
336       enable = true;
337       ensureDatabases = [ cfg.database.name ];
338       ensureUsers = [{
339         name = cfg.database.user;
340         ensurePermissions = {
341           "${cfg.database.name}.*" = "ALL PRIVILEGES";
342         };
343       }];
344     };
346     systemd = {
347       services = {
348         cloudlog-setup-database = mkIf cfg.database.createLocally {
349           description = "Set up cloudlog database";
350           serviceConfig = {
351             Type = "oneshot";
352             RemainAfterExit = true;
353           };
354           wantedBy = [ "phpfpm-cloudlog.service" ];
355           after = [ "mysql.service" ];
356           script = let
357             mysql = "${config.services.mysql.package}/bin/mysql";
358           in ''
359             if [ ! -f ${cfg.dataDir}/.dbexists ]; then
360               ${mysql} ${cfg.database.name} < ${pkgs.cloudlog}/install/assets/install.sql
361               touch ${cfg.dataDir}/.dbexists
362             fi
363         '';
364         };
365         cloudlog-upload-lotw = {
366           description = "Upload QSOs to LoTW if certs have been provided";
367           enable = cfg.upload-lotw.enable;
368           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/lotw/lotw_upload";
369         };
370         cloudlog-update-lotw-users = {
371           description = "Update LOTW Users Database";
372           enable = cfg.update-lotw-users.enable;
373           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/lotw/load_users";
374         };
375         cloudlog-update-dok = {
376           description = "Update DOK File for autocomplete";
377           enable = cfg.update-dok.enable;
378           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_dok";
379         };
380         cloudlog-update-clublog-scp = {
381           description = "Update Clublog SCP Database File";
382           enable = cfg.update-clublog-scp.enable;
383           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_clublog_scp";
384         };
385         cloudlog-update-wwff = {
386           description = "Update WWFF File for autocomplete";
387           enable = cfg.update-wwff.enable;
388           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_wwff";
389         };
390         cloudlog-upload-qrz = {
391           description = "Upload QSOs to QRZ Logbook";
392           enable = cfg.upload-qrz.enable;
393           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/qrz/upload";
394         };
395         cloudlog-update-sota = {
396           description = "Update SOTA File for autocomplete";
397           enable = cfg.update-sota.enable;
398           script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_sota";
399         };
400       };
401       timers = {
402         cloudlog-upload-lotw = {
403           enable = cfg.upload-lotw.enable;
404           wantedBy = [ "timers.target" ];
405           partOf = [ "cloudlog-upload-lotw.service" ];
406           after = [ "phpfpm-cloudlog.service" ];
407           timerConfig = {
408             OnCalendar = cfg.upload-lotw.interval;
409             Persistent = true;
410           };
411         };
412         cloudlog-upload-clublog = {
413           enable = cfg.upload-clublog.enable;
414           wantedBy = [ "timers.target" ];
415           partOf = [ "cloudlog-upload-clublog.service" ];
416           after = [ "phpfpm-cloudlog.service" ];
417           timerConfig = {
418             OnCalendar = cfg.upload-clublog.interval;
419             Persistent = true;
420           };
421         };
422         cloudlog-update-lotw-users = {
423           enable = cfg.update-lotw-users.enable;
424           wantedBy = [ "timers.target" ];
425           partOf = [ "cloudlog-update-lotw-users.service" ];
426           after = [ "phpfpm-cloudlog.service" ];
427           timerConfig = {
428             OnCalendar = cfg.update-lotw-users.interval;
429             Persistent = true;
430           };
431         };
432         cloudlog-update-dok = {
433           enable = cfg.update-dok.enable;
434           wantedBy = [ "timers.target" ];
435           partOf = [ "cloudlog-update-dok.service" ];
436           after = [ "phpfpm-cloudlog.service" ];
437           timerConfig = {
438             OnCalendar = cfg.update-dok.interval;
439             Persistent = true;
440           };
441         };
442         cloudlog-update-clublog-scp = {
443           enable = cfg.update-clublog-scp.enable;
444           wantedBy = [ "timers.target" ];
445           partOf = [ "cloudlog-update-clublog-scp.service" ];
446           after = [ "phpfpm-cloudlog.service" ];
447           timerConfig = {
448             OnCalendar = cfg.update-clublog-scp.interval;
449             Persistent = true;
450           };
451         };
452         cloudlog-update-wwff =  {
453           enable = cfg.update-wwff.enable;
454           wantedBy = [ "timers.target" ];
455           partOf = [ "cloudlog-update-wwff.service" ];
456           after = [ "phpfpm-cloudlog.service" ];
457           timerConfig = {
458             OnCalendar = cfg.update-wwff.interval;
459             Persistent = true;
460           };
461         };
462         cloudlog-upload-qrz = {
463           enable = cfg.upload-qrz.enable;
464           wantedBy = [ "timers.target" ];
465           partOf = [ "cloudlog-upload-qrz.service" ];
466           after = [ "phpfpm-cloudlog.service" ];
467           timerConfig = {
468             OnCalendar = cfg.upload-qrz.interval;
469             Persistent = true;
470           };
471         };
472         cloudlog-update-sota = {
473           enable = cfg.update-sota.enable;
474           wantedBy = [ "timers.target" ];
475           partOf = [ "cloudlog-update-sota.service" ];
476           after = [ "phpfpm-cloudlog.service" ];
477           timerConfig = {
478             OnCalendar = cfg.update-sota.interval;
479             Persistent = true;
480           };
481         };
482       };
483       tmpfiles.rules = let
484         group = config.services.nginx.group;
485       in [
486         "d ${cfg.dataDir}                0750 ${cfg.user} ${group} - -"
487         "d ${cfg.dataDir}/updates        0750 ${cfg.user} ${group} - -"
488         "d ${cfg.dataDir}/uploads        0750 ${cfg.user} ${group} - -"
489         "d ${cfg.dataDir}/backup         0750 ${cfg.user} ${group} - -"
490         "d ${cfg.dataDir}/logbook        0750 ${cfg.user} ${group} - -"
491         "d ${cfg.dataDir}/assets/json    0750 ${cfg.user} ${group} - -"
492         "d ${cfg.dataDir}/assets/qslcard 0750 ${cfg.user} ${group} - -"
493       ];
494     };
496     users.users."${cfg.user}" = {
497       isSystemUser = true;
498       group = config.services.nginx.group;
499     };
500   };
502   meta.maintainers = with maintainers; [ melling ];