depot/third_party/nixpkgs/nixos/modules/services/web-servers/keter/default.nix
Default email 13da32182d Project import generated by Copybara.
GitOrigin-RevId: a7855f2235a1876f97473a76151fec2afa02b287
2022-08-21 15:32:41 +02:00

162 lines
4.8 KiB
Nix

{ config, pkgs, lib, ... }:
let
cfg = config.services.keter;
in
{
meta = {
maintainers = with lib.maintainers; [ jappie ];
};
options.services.keter = {
enable = lib.mkEnableOption ''keter, a web app deployment manager.
Note that this module only support loading of webapps:
Keep an old app running and swap the ports when the new one is booted.
'';
keterRoot = lib.mkOption {
type = lib.types.str;
default = "/var/lib/keter";
description = "Mutable state folder for keter";
};
keterPackage = lib.mkOption {
type = lib.types.package;
default = pkgs.haskellPackages.keter;
defaultText = lib.literalExpression "pkgs.haskellPackages.keter";
description = "The keter package to be used";
};
globalKeterConfig = lib.mkOption {
type = lib.types.attrs;
default = {
ip-from-header = true;
listeners = [{
host = "*4";
port = 6981;
}];
};
# You want that ip-from-header in the nginx setup case
# so it's not set to 127.0.0.1.
# using a port above 1024 allows you to avoid needing CAP_NET_BIND_SERVICE
defaultText = lib.literalExpression ''
{
ip-from-header = true;
listeners = [{
host = "*4";
port = 6981;
}];
}
'';
description = "Global config for keter";
};
bundle = {
appName = lib.mkOption {
type = lib.types.str;
default = "myapp";
description = "The name keter assigns to this bundle";
};
executable = lib.mkOption {
type = lib.types.path;
description = "The executable to be run";
};
domain = lib.mkOption {
type = lib.types.str;
default = "example.com";
description = "The domain keter will bind to";
};
publicScript = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Allows loading of public environment variables,
these are emitted to the log so it shouldn't contain secrets.
'';
example = "ADMIN_EMAIL=hi@example.com";
};
secretScript = lib.mkOption {
type = lib.types.str;
default = "";
description = "Allows loading of private environment variables";
example = "MY_AWS_KEY=$(cat /run/keys/AWS_ACCESS_KEY_ID)";
};
};
};
config = lib.mkIf cfg.enable (
let
incoming = "${cfg.keterRoot}/incoming";
globalKeterConfigFile = pkgs.writeTextFile {
name = "keter-config.yml";
text = (lib.generators.toYAML { } (cfg.globalKeterConfig // { root = cfg.keterRoot; }));
};
# If things are expected to change often, put it in the bundle!
bundle = pkgs.callPackage ./bundle.nix
(cfg.bundle // { keterExecutable = executable; keterDomain = cfg.bundle.domain; });
# This indirection is required to ensure the nix path
# gets copied over to the target machine in remote deployments.
# Furthermore, it's important that we use exec to
# run the binary otherwise we get process leakage due to this
# being executed on every change.
executable = pkgs.writeShellScript "bundle-wrapper" ''
set -e
${cfg.bundle.secretScript}
set -xe
${cfg.bundle.publicScript}
exec ${cfg.bundle.executable}
'';
in
{
systemd.services.keter = {
description = "keter app loader";
script = ''
set -xe
mkdir -p ${incoming}
{ tail -F ${cfg.keterRoot}/log/keter/current.log -n 0 & ${cfg.keterPackage}/bin/keter ${globalKeterConfigFile}; }
'';
wantedBy = [ "multi-user.target" "nginx.service" ];
serviceConfig = {
Restart = "always";
RestartSec = "10s";
};
after = [
"network.target"
"local-fs.target"
"postgresql.service"
];
};
# On deploy this will load our app, by moving it into the incoming dir
# If the bundle content changes, this will run again.
# Because the bundle content contains the nix path to the exectuable,
# we inherit nix based cache busting.
systemd.services.load-keter-bundle = {
description = "load keter bundle into incoming folder";
after = [ "keter.service" ];
wantedBy = [ "multi-user.target" ];
# we can't override keter bundles because it'll stop the previous app
# https://github.com/snoyberg/keter#deploying
script = ''
set -xe
cp ${bundle}/bundle.tar.gz.keter ${incoming}/${cfg.bundle.appName}.keter
'';
path = [
executable
cfg.bundle.executable
]; # this is a hack to get the executable copied over to the machine.
};
}
);
}