at master 5.8 kB view raw
1# TODO: create a common module generator for Taler and Libeufin? 2libeufinComponent: 3{ 4 lib, 5 pkgs, 6 config, 7 ... 8}: 9{ 10 options.services.libeufin.${libeufinComponent} = { 11 enable = lib.mkEnableOption "libeufin core banking system and web interface"; 12 package = lib.mkPackageOption pkgs "libeufin" { }; 13 debug = lib.mkEnableOption "debug logging"; 14 createLocalDatabase = lib.mkEnableOption "automatic creation of a local postgres database"; 15 openFirewall = lib.mkOption { 16 type = lib.types.bool; 17 default = false; 18 description = "Whether to open ports in the firewall"; 19 }; 20 }; 21 22 config = 23 let 24 cfg = cfgMain.${libeufinComponent}; 25 cfgMain = config.services.libeufin; 26 27 configFile = config.environment.etc."libeufin/libeufin.conf".source; 28 serviceName = "libeufin-${libeufinComponent}"; 29 isNexus = libeufinComponent == "nexus"; 30 31 # get database name from config 32 # TODO: should this always be the same db? In which case, should this be an option directly under `services.libeufin`? 33 dbName = 34 lib.removePrefix "postgresql:///" 35 cfg.settings."libeufin-${libeufinComponent}db-postgres".CONFIG; 36 37 bankPort = cfg.settings."${if isNexus then "nexus-httpd" else "libeufin-bank"}".PORT; 38 bankHost = lib.elemAt (lib.splitString "/" cfg.settings.libeufin-bank.BASE_URL) 2; 39 in 40 lib.mkIf cfg.enable { 41 services.libeufin.settings = cfg.settings; 42 43 # TODO add system-libeufin.slice? 44 systemd.services = { 45 # Main service 46 "${serviceName}" = { 47 serviceConfig = { 48 DynamicUser = true; 49 ExecStart = 50 let 51 args = lib.cli.toGNUCommandLineShell { } { 52 c = configFile; 53 L = if cfg.debug then "debug" else null; 54 }; 55 in 56 "${lib.getExe' cfg.package "libeufin-${libeufinComponent}"} serve ${args}"; 57 Restart = "on-failure"; 58 RestartSec = "10s"; 59 }; 60 requires = [ "libeufin-dbinit.service" ]; 61 after = [ "libeufin-dbinit.service" ]; 62 wantedBy = [ "multi-user.target" ]; 63 }; 64 65 # Database Initialisation 66 libeufin-dbinit = 67 let 68 dbScript = pkgs.writers.writeText "libeufin-db-permissions.sql" '' 69 GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA libeufin_bank TO "${serviceName}"; 70 GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA libeufin_nexus TO "${serviceName}"; 71 GRANT USAGE ON SCHEMA libeufin_bank TO "${serviceName}"; 72 GRANT USAGE ON SCHEMA libeufin_nexus TO "${serviceName}"; 73 ''; 74 75 # Accounts to be created after the bank database initialization. 76 # 77 # For example, if the bank's currency conversion is enabled, it's 78 # required that the exchange account is registered before the 79 # service starts. 80 initialAccountRegistration = lib.concatMapStringsSep "\n" ( 81 account: 82 let 83 args = lib.cli.toGNUCommandLineShell { } { 84 c = configFile; 85 inherit (account) username password name; 86 payto_uri = "payto://x-taler-bank/${bankHost}/${account.username}?receiver-name=${account.name}"; 87 exchange = lib.toLower account.username == "exchange"; 88 }; 89 in 90 "${lib.getExe' cfg.package "libeufin-bank"} create-account ${args}" 91 ) cfg.initialAccounts; 92 93 args = lib.cli.toGNUCommandLineShell { } { 94 c = configFile; 95 L = if cfg.debug then "debug" else null; 96 }; 97 in 98 { 99 path = [ 100 (if cfg.createLocalDatabase then config.services.postgresql.package else pkgs.postgresql) 101 ]; 102 serviceConfig = { 103 Type = "oneshot"; 104 DynamicUser = true; 105 StateDirectory = "libeufin-dbinit"; 106 StateDirectoryMode = "0750"; 107 User = dbName; 108 }; 109 script = lib.optionalString cfg.enable '' 110 ${lib.getExe' cfg.package "libeufin-${libeufinComponent}"} dbinit ${args} 111 ''; 112 # Grant DB permissions after schemas have been created 113 postStart = '' 114 psql -U "${dbName}" -f "${dbScript}" 115 '' 116 + lib.optionalString ((!isNexus) && (cfg.initialAccounts != [ ])) '' 117 # only register initial accounts once 118 if [ ! -e /var/lib/libeufin-dbinit/init ]; then 119 ${initialAccountRegistration} 120 121 touch /var/lib/libeufin-dbinit/init 122 echo "Bank initialisation complete" 123 fi 124 ''; 125 requires = lib.optionals cfg.createLocalDatabase [ "postgresql.target" ]; 126 after = [ "network.target" ] ++ lib.optionals cfg.createLocalDatabase [ "postgresql.target" ]; 127 }; 128 }; 129 130 networking.firewall = lib.mkIf cfg.openFirewall { 131 allowedTCPPorts = [ 132 bankPort 133 ]; 134 }; 135 136 environment.systemPackages = [ cfg.package ]; 137 138 services.postgresql = lib.mkIf cfg.createLocalDatabase { 139 enable = true; 140 ensureDatabases = [ dbName ]; 141 ensureUsers = [ 142 { name = serviceName; } 143 { 144 name = dbName; 145 ensureDBOwnership = true; 146 } 147 ]; 148 }; 149 150 assertions = [ 151 { 152 assertion = 153 cfg.createLocalDatabase || (cfg.settings."libeufin-${libeufinComponent}db-postgres" ? CONFIG); 154 message = "Libeufin ${libeufinComponent} database is not configured."; 155 } 156 ]; 157 158 }; 159}