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