2023-02-02 18:25:31 +00:00
|
|
|
{ config, pkgs, lib, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.cloudlog;
|
|
|
|
dbFile = let
|
|
|
|
password = if cfg.database.createLocally
|
|
|
|
then "''"
|
|
|
|
else "trim(file_get_contents('${cfg.database.passwordFile}'))";
|
|
|
|
in pkgs.writeText "database.php" ''
|
|
|
|
<?php
|
|
|
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
|
|
|
$active_group = 'default';
|
|
|
|
$query_builder = TRUE;
|
|
|
|
$db['default'] = array(
|
|
|
|
'dsn' => "",
|
|
|
|
'hostname' => '${cfg.database.host}',
|
|
|
|
'username' => '${cfg.database.user}',
|
|
|
|
'password' => ${password},
|
|
|
|
'database' => '${cfg.database.name}',
|
|
|
|
'dbdriver' => 'mysqli',
|
|
|
|
'dbprefix' => "",
|
|
|
|
'pconnect' => TRUE,
|
|
|
|
'db_debug' => (ENVIRONMENT !== 'production'),
|
|
|
|
'cache_on' => FALSE,
|
|
|
|
'cachedir' => "",
|
|
|
|
'char_set' => 'utf8mb4',
|
|
|
|
'dbcollat' => 'utf8mb4_general_ci',
|
|
|
|
'swap_pre' => "",
|
|
|
|
'encrypt' => FALSE,
|
|
|
|
'compress' => FALSE,
|
|
|
|
'stricton' => FALSE,
|
|
|
|
'failover' => array(),
|
|
|
|
'save_queries' => TRUE
|
|
|
|
);
|
|
|
|
'';
|
|
|
|
configFile = pkgs.writeText "config.php" ''
|
|
|
|
${strings.fileContents "${pkgs.cloudlog}/install/config/config.php"}
|
|
|
|
$config['datadir'] = "${cfg.dataDir}/";
|
|
|
|
$config['base_url'] = "${cfg.baseUrl}";
|
|
|
|
${cfg.extraConfig}
|
|
|
|
'';
|
|
|
|
package = pkgs.stdenv.mkDerivation rec {
|
|
|
|
pname = "cloudlog";
|
|
|
|
version = src.version;
|
|
|
|
src = pkgs.cloudlog;
|
|
|
|
installPhase = ''
|
|
|
|
mkdir -p $out
|
|
|
|
cp -r * $out/
|
|
|
|
|
|
|
|
ln -s ${configFile} $out/application/config/config.php
|
|
|
|
ln -s ${dbFile} $out/application/config/database.php
|
|
|
|
|
|
|
|
# link writable directories
|
|
|
|
for directory in updates uploads backup logbook; do
|
|
|
|
rm -rf $out/$directory
|
|
|
|
ln -s ${cfg.dataDir}/$directory $out/$directory
|
|
|
|
done
|
|
|
|
|
|
|
|
# link writable asset files
|
|
|
|
for asset in dok sota wwff; do
|
|
|
|
rm -rf $out/assets/json/$asset.txt
|
|
|
|
ln -s ${cfg.dataDir}/assets/json/$asset.txt $out/assets/json/$asset.txt
|
|
|
|
done
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options.services.cloudlog = with types; {
|
2023-02-09 11:40:11 +00:00
|
|
|
enable = mkEnableOption (mdDoc "Whether to enable Cloudlog");
|
2023-02-02 18:25:31 +00:00
|
|
|
dataDir = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "/var/lib/cloudlog";
|
|
|
|
description = mdDoc "Cloudlog data directory.";
|
|
|
|
};
|
|
|
|
baseUrl = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "http://localhost";
|
|
|
|
description = mdDoc "Cloudlog base URL";
|
|
|
|
};
|
|
|
|
user = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "cloudlog";
|
|
|
|
description = mdDoc "User account under which Cloudlog runs.";
|
|
|
|
};
|
|
|
|
database = {
|
|
|
|
createLocally = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = lib.mdDoc "Create the database and database user locally.";
|
|
|
|
};
|
|
|
|
host = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = mdDoc "MySQL database host";
|
|
|
|
default = "localhost";
|
|
|
|
};
|
|
|
|
name = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = mdDoc "MySQL database name.";
|
|
|
|
default = "cloudlog";
|
|
|
|
};
|
|
|
|
user = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = mdDoc "MySQL user name.";
|
|
|
|
default = "cloudlog";
|
|
|
|
};
|
|
|
|
passwordFile = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
description = mdDoc "MySQL user password file.";
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
poolConfig = mkOption {
|
|
|
|
type = attrsOf (oneOf [ str int bool ]);
|
|
|
|
default = {
|
|
|
|
"pm" = "dynamic";
|
|
|
|
"pm.max_children" = 32;
|
|
|
|
"pm.start_servers" = 2;
|
|
|
|
"pm.min_spare_servers" = 2;
|
|
|
|
"pm.max_spare_servers" = 4;
|
|
|
|
"pm.max_requests" = 500;
|
|
|
|
};
|
|
|
|
description = mdDoc ''
|
|
|
|
Options for Cloudlog's PHP-FPM pool.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
virtualHost = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
default = "localhost";
|
|
|
|
description = mdDoc ''
|
|
|
|
Name of the nginx virtualhost to use and setup. If null, do not setup
|
|
|
|
any virtualhost.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
|
|
description = mdDoc ''
|
|
|
|
Any additional text to be appended to the config.php
|
|
|
|
configuration file. This is a PHP script. For configuration
|
|
|
|
settings, see <https://github.com/magicbug/Cloudlog/wiki/Cloudlog.php-Configuration-File>.
|
|
|
|
'';
|
|
|
|
default = "";
|
|
|
|
type = str;
|
|
|
|
example = ''
|
|
|
|
$config['show_time'] = TRUE;
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
upload-lotw = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically upload logs to LoTW. If enabled, a systemd
|
|
|
|
timer will run the log upload task as specified by the interval
|
|
|
|
option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "daily";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the
|
|
|
|
time at which the LoTW upload will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
upload-clublog = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically upload logs to Clublog. If enabled, a systemd
|
|
|
|
timer will run the log upload task as specified by the interval option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "daily";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the time
|
|
|
|
at which the Clublog upload will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
update-lotw-users = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically update the list of LoTW users. If enabled, a
|
|
|
|
systemd timer will run the update task as specified by the interval
|
|
|
|
option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "weekly";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the
|
|
|
|
time at which the LoTW user update will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
update-dok = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically update the DOK resource file. If enabled, a
|
|
|
|
systemd timer will run the update task as specified by the interval option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "monthly";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the
|
|
|
|
time at which the DOK update will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
update-clublog-scp = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically update the Clublog SCP database. If enabled,
|
|
|
|
a systemd timer will run the update task as specified by the interval
|
|
|
|
option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "monthly";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the time
|
|
|
|
at which the Clublog SCP update will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
update-wwff = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically update the WWFF database. If enabled, a
|
|
|
|
systemd timer will run the update task as specified by the interval
|
|
|
|
option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "monthly";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the time
|
|
|
|
at which the WWFF update will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
upload-qrz = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically upload logs to QRZ. If enabled, a systemd
|
|
|
|
timer will run the update task as specified by the interval option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "daily";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the
|
|
|
|
time at which the QRZ upload will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
update-sota = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = bool;
|
|
|
|
default = true;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to periodically update the SOTA database. If enabled, a
|
|
|
|
systemd timer will run the update task as specified by the interval option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
interval = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "monthly";
|
|
|
|
description = mdDoc ''
|
|
|
|
Specification (in the format described by systemd.time(7)) of the time
|
|
|
|
at which the SOTA update will occur.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
|
|
|
|
assertions = [
|
|
|
|
{
|
|
|
|
assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
|
|
|
|
message = "services.cloudlog.database.passwordFile cannot be specified if services.cloudlog.database.createLocally is set to true.";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
services.phpfpm = {
|
|
|
|
pools.cloudlog = {
|
|
|
|
inherit (cfg) user;
|
|
|
|
group = config.services.nginx.group;
|
|
|
|
settings = {
|
|
|
|
"listen.owner" = config.services.nginx.user;
|
|
|
|
"listen.group" = config.services.nginx.group;
|
|
|
|
} // cfg.poolConfig;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
services.nginx = mkIf (cfg.virtualHost != null) {
|
|
|
|
enable = true;
|
|
|
|
virtualHosts = {
|
|
|
|
"${cfg.virtualHost}" = {
|
|
|
|
root = "${package}";
|
|
|
|
locations."/".tryFiles = "$uri /index.php$is_args$args";
|
|
|
|
locations."~ ^/index.php(/|$)".extraConfig = ''
|
|
|
|
include ${config.services.nginx.package}/conf/fastcgi_params;
|
|
|
|
include ${pkgs.nginx}/conf/fastcgi.conf;
|
|
|
|
fastcgi_split_path_info ^(.+\.php)(.+)$;
|
|
|
|
fastcgi_pass unix:${config.services.phpfpm.pools.cloudlog.socket};
|
|
|
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
services.mysql = mkIf cfg.database.createLocally {
|
|
|
|
enable = true;
|
|
|
|
ensureDatabases = [ cfg.database.name ];
|
|
|
|
ensureUsers = [{
|
|
|
|
name = cfg.database.user;
|
|
|
|
ensurePermissions = {
|
|
|
|
"${cfg.database.name}.*" = "ALL PRIVILEGES";
|
|
|
|
};
|
|
|
|
}];
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd = {
|
|
|
|
services = {
|
|
|
|
cloudlog-setup-database = mkIf cfg.database.createLocally {
|
|
|
|
description = "Set up cloudlog database";
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "oneshot";
|
|
|
|
RemainAfterExit = true;
|
|
|
|
};
|
|
|
|
wantedBy = [ "phpfpm-cloudlog.service" ];
|
|
|
|
after = [ "mysql.service" ];
|
|
|
|
script = let
|
|
|
|
mysql = "${config.services.mysql.package}/bin/mysql";
|
|
|
|
in ''
|
|
|
|
if [ ! -f ${cfg.dataDir}/.dbexists ]; then
|
|
|
|
${mysql} ${cfg.database.name} < ${pkgs.cloudlog}/install/assets/install.sql
|
|
|
|
touch ${cfg.dataDir}/.dbexists
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
cloudlog-upload-lotw = {
|
|
|
|
description = "Upload QSOs to LoTW if certs have been provided";
|
|
|
|
enable = cfg.upload-lotw.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/lotw/lotw_upload";
|
|
|
|
};
|
|
|
|
cloudlog-update-lotw-users = {
|
|
|
|
description = "Update LOTW Users Database";
|
|
|
|
enable = cfg.update-lotw-users.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/lotw/load_users";
|
|
|
|
};
|
|
|
|
cloudlog-update-dok = {
|
|
|
|
description = "Update DOK File for autocomplete";
|
|
|
|
enable = cfg.update-dok.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_dok";
|
|
|
|
};
|
|
|
|
cloudlog-update-clublog-scp = {
|
|
|
|
description = "Update Clublog SCP Database File";
|
|
|
|
enable = cfg.update-clublog-scp.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_clublog_scp";
|
|
|
|
};
|
|
|
|
cloudlog-update-wwff = {
|
|
|
|
description = "Update WWFF File for autocomplete";
|
|
|
|
enable = cfg.update-wwff.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_wwff";
|
|
|
|
};
|
|
|
|
cloudlog-upload-qrz = {
|
|
|
|
description = "Upload QSOs to QRZ Logbook";
|
|
|
|
enable = cfg.upload-qrz.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/qrz/upload";
|
|
|
|
};
|
|
|
|
cloudlog-update-sota = {
|
|
|
|
description = "Update SOTA File for autocomplete";
|
|
|
|
enable = cfg.update-sota.enable;
|
|
|
|
script = "${pkgs.curl}/bin/curl -s ${cfg.baseUrl}/update/update_sota";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
timers = {
|
|
|
|
cloudlog-upload-lotw = {
|
|
|
|
enable = cfg.upload-lotw.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-upload-lotw.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.upload-lotw.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-upload-clublog = {
|
|
|
|
enable = cfg.upload-clublog.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-upload-clublog.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.upload-clublog.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-update-lotw-users = {
|
|
|
|
enable = cfg.update-lotw-users.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-update-lotw-users.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.update-lotw-users.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-update-dok = {
|
|
|
|
enable = cfg.update-dok.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-update-dok.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.update-dok.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-update-clublog-scp = {
|
|
|
|
enable = cfg.update-clublog-scp.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-update-clublog-scp.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.update-clublog-scp.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-update-wwff = {
|
|
|
|
enable = cfg.update-wwff.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-update-wwff.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.update-wwff.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-upload-qrz = {
|
|
|
|
enable = cfg.upload-qrz.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-upload-qrz.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.upload-qrz.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
cloudlog-update-sota = {
|
|
|
|
enable = cfg.update-sota.enable;
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
partOf = [ "cloudlog-update-sota.service" ];
|
|
|
|
after = [ "phpfpm-cloudlog.service" ];
|
|
|
|
timerConfig = {
|
|
|
|
OnCalendar = cfg.update-sota.interval;
|
|
|
|
Persistent = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
tmpfiles.rules = let
|
|
|
|
group = config.services.nginx.group;
|
|
|
|
in [
|
|
|
|
"d ${cfg.dataDir} 0750 ${cfg.user} ${group} - -"
|
|
|
|
"d ${cfg.dataDir}/updates 0750 ${cfg.user} ${group} - -"
|
|
|
|
"d ${cfg.dataDir}/uploads 0750 ${cfg.user} ${group} - -"
|
|
|
|
"d ${cfg.dataDir}/backup 0750 ${cfg.user} ${group} - -"
|
|
|
|
"d ${cfg.dataDir}/logbook 0750 ${cfg.user} ${group} - -"
|
|
|
|
"d ${cfg.dataDir}/assets/json 0750 ${cfg.user} ${group} - -"
|
|
|
|
"d ${cfg.dataDir}/assets/qslcard 0750 ${cfg.user} ${group} - -"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
|
|
|
|
users.users."${cfg.user}" = {
|
|
|
|
isSystemUser = true;
|
|
|
|
group = config.services.nginx.group;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
meta.maintainers = with maintainers; [ melling ];
|
|
|
|
}
|