From e66e349c3b811a32e1d7be00e7379425c4b4a56e Mon Sep 17 00:00:00 2001 From: niten Date: Tue, 14 Dec 2021 13:41:17 -0800 Subject: [PATCH] Added chute job, working on discourse --- lib/fudo/acme-certs.nix | 19 ++------- lib/fudo/postgres.nix | 12 +++--- lib/fudo/secrets.nix | 18 +++++++- lib/fudo/system.nix | 4 +- lib/informis/chute.nix | 89 ++++++++++++++++++++++++++++++++++++++++ lib/informis/default.nix | 1 + 6 files changed, 120 insertions(+), 23 deletions(-) create mode 100644 lib/informis/chute.nix diff --git a/lib/fudo/acme-certs.nix b/lib/fudo/acme-certs.nix index bc398c8..2480e71 100644 --- a/lib/fudo/acme-certs.nix +++ b/lib/fudo/acme-certs.nix @@ -115,15 +115,16 @@ in { challenge-path = mkOption { type = str; description = "Web-accessible path for responding to ACME challenges."; - default = "/run/fudo-acme/challenge"; + # Sigh. Leave it the same as nginx default, so it works whether or not + # nginx feels like helping or not. + default = "/var/lib/acme/acme-challenge"; }; }; config = { security.acme.certs = mapAttrs (domain: domainOpts: { email = domainOpts.admin-email; - # IF you won't do it all the time, nginx, you can't do it at all - webroot = mkForce cfg.challenge-path; + webroot = cfg.challenge-path; extraDomainNames = domainOpts.extra-domains; }) localDomains; @@ -136,18 +137,6 @@ in { recommendedOptimisation = true; recommendedTlsSettings = true; recommendedProxySettings = true; - - virtualHosts.${config.instance.host-fqdn} = { - serverAliases = attrNames localDomains; - locations = { - "/.well-known/acme-challenge" = { - root = cfg.challenge-path; - }; - "/" = { - return = "301 https://$host$request_uri"; - }; - }; - }; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; diff --git a/lib/fudo/postgres.nix b/lib/fudo/postgres.nix index 8ab72cc..a3ea125 100644 --- a/lib/fudo/postgres.nix +++ b/lib/fudo/postgres.nix @@ -72,8 +72,8 @@ let password-setter-script = user: password-file: sql-file: '' unset PASSWORD - if [ ! -f ${password-file} ]; then - echo "file does not exist: ${password-file}" + if [ ! -r ${password-file} ]; then + echo "unable to read file: ${password-file}" exit 1 fi PASSWORD=$(cat ${password-file}) @@ -82,7 +82,7 @@ let ''; passwords-setter-script = users: - pkgs.writeScript "postgres-set-passwords.sh" '' + pkgs.writeShellScript "postgres-set-passwords.sh" '' if [ $# -ne 1 ]; then echo "usage: $0 output-file.sql" exit 1 @@ -311,7 +311,7 @@ in { postgresql-password-setter = let passwords-script = passwords-setter-script cfg.users; password-wrapper-script = - pkgs.writeScript "password-script-wrapper.sh" '' + pkgs.writeShellScript "password-script-wrapper.sh" '' TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d -t postgres-XXXXXXXXXX) echo "using temp dir $TMPDIR" PASSWORD_SQL_FILE=$TMPDIR/user-passwords.sql @@ -334,18 +334,20 @@ in { "A service to set postgresql user passwords after the server has started."; after = [ "postgresql.service" ] ++ cfg.required-services; requires = [ "postgresql.service" ] ++ cfg.required-services; + wantedBy = [ "postgresql.service" ]; serviceConfig = { Type = "oneshot"; User = config.services.postgresql.superUser; + ExecStart = "${password-wrapper-script}"; }; partOf = [ cfg.systemd-target ]; - script = "${password-wrapper-script}"; }; postgresql = { requires = cfg.required-services; after = cfg.required-services; partOf = [ cfg.systemd-target ]; + wants = [ "postgresql-password-setter.service" ]; postStart = let allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;"; diff --git a/lib/fudo/secrets.nix b/lib/fudo/secrets.nix index a321f60..4f83f26 100644 --- a/lib/fudo/secrets.nix +++ b/lib/fudo/secrets.nix @@ -35,7 +35,8 @@ let secret-service = target-host: secret-name: { source-file, target-file, user, group, permissions, ... }: { description = "decrypt secret ${secret-name} for ${target-host}."; - wantedBy = [ "default.target" ]; + wantedBy = [ cfg.secret-target ]; + before = [ cfg.secret-target ]; serviceConfig = { Type = "oneshot"; ExecStart = let @@ -163,6 +164,12 @@ in { "Paths which contain (only) secrets. The contents will be reabable by the secret-group."; default = [ ]; }; + + secret-target = mkOption { + type = str; + description = "Target indicating that all secrets are available."; + default = "fudo-secrets.target"; + }; }; config = mkIf cfg.enable { @@ -219,6 +226,15 @@ in { }; }; + targets = let + strip-ext = filename: head (builtins.match "^(.+)[.]target$" filename); + in { + ${strip-ext cfg.secret-target} = { + description = "Target indicating that all Fudo secrets are available."; + wantedBy = [ "default.target" ]; + }; + }; + paths.fudo-secrets-watcher = mkIf (length cfg.secret-paths > 0) { wantedBy = [ "default.target" ]; description = "Watch fudo secret paths, and correct perms on changes."; diff --git a/lib/fudo/system.nix b/lib/fudo/system.nix index 25cf931..e4a5b61 100644 --- a/lib/fudo/system.nix +++ b/lib/fudo/system.nix @@ -80,7 +80,7 @@ let description = "Environment variables supplied to this service."; default = { }; }; - environment-file = mkOption { + environmentFile = mkOption { type = nullOr str; description = "File containing environment variables supplied to this service."; @@ -423,7 +423,7 @@ in { ProtectKernelLogs = opts.protectKernelLogs; KeyringMode = opts.keyringMode; EnvironmentFile = - mkIf (opts.environment-file != null) opts.environment-file; + mkIf (opts.environmentFile != null) opts.environmentFile; # This is more complicated than it looks... # CapabilityBoundingSet = restrict-capabilities opts.requiredCapabilities; diff --git a/lib/informis/chute.nix b/lib/informis/chute.nix new file mode 100644 index 0000000..590493f --- /dev/null +++ b/lib/informis/chute.nix @@ -0,0 +1,89 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + currencyOpts = { ... }: { + options = { + stop-percentile = mkOption { + type = int; + description = "Percentile of observed max at which to sell."; + }; + }; + }; + + stageOpts = { ... }: { + options = with types; { + currencies = mkOption { + type = attrsOf (submodule currencyOpts); + description = "Map of cryptocurrencies to chute currency settings."; + }; + + package = mkOption { + type = package; + description = "Chute package to use for this stage."; + default = pkgs.chute; + }; + + credential-file = mkOption { + type = str; + description = '' + Path to a host-local env file containing definitions for: + + COINBASE_API_HOSTNAME + COINBASE_API_SECRET + COINBASE_API_PASSPHRASE + COINBASE_API_KEY + ''; + }; + }; + }; + + concatMapAttrs = f: attrs: + foldr (a: b: a // b) {} (mapAttrsToList f attrs); + + chute-job-definition = { stage, credential-file, currency, stop-at-percent, package }: { + after = [ "network-online.target" ]; + wantedBy = [ "chute.target" ]; + partOf = [ "chute.target" ]; + description = "Chute ${stage} job for ${currency}"; + path = [ package ]; + environmentFile = credential-file; + execStart = "chute --currency=${currency} --stop-at-percent=${stop-at-percent}"; + privateNetwork = false; + addressFamilies = [ "AF_INET" ]; + }; + +in { + options.informis.chute = with types; { + enable = mkEnableOption "Enable Chute cryptocurrency parachute."; + + stages = mkOption { + type = attrsOf (submodule stageOpts); + description = "Map of stage names to stage options."; + example = { + staging = { + credential-file = "/path/to/credentials-file"; + currencies = { + btc.stop-percentile = 90; + ada.stop-percentile = 85; + }; + }; + }; + default = {}; + }; + }; + + config = mkIf (cfg.enable) { + fudo = { + system.services = concatMapAttrs (stage: stageOpts: + mapAttrs (currency: currencyOpts: { + "chute-${stage}-${currency}" = chute-job-definition { + inherit stage currency; + credential-file = stageOpts.credential-file; + package = stageOpts.package; + stop-at-percent = currencyOpts.stop-percentile; + }; + }) stageOpts.currencies) cfg.stages; + }; + }; +} diff --git a/lib/informis/default.nix b/lib/informis/default.nix index 702c6d3..fb8618e 100644 --- a/lib/informis/default.nix +++ b/lib/informis/default.nix @@ -2,6 +2,7 @@ { imports = [ + ./chute.nix ./cl-gemini.nix ]; }