nixpkgs/nixos/modules/services/web-apps/oncall.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

204 lines
6 KiB
Nix
Raw Normal View History

2025-03-10 16:58:58 +01:00
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.oncall;
settingsFormat = pkgs.formats.yaml { };
configFile = settingsFormat.generate "oncall_extra_settings.yaml" cfg.settings;
in
{
options.services.oncall = {
enable = lib.mkEnableOption "Oncall web app";
package = lib.mkPackageOption pkgs "oncall" { };
database.createLocally = lib.mkEnableOption "Create the database and database user locally." // {
default = true;
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
options = {
oncall_host = lib.mkOption {
type = lib.types.str;
default = "localhost";
description = "FQDN for the Oncall instance.";
};
db.conn = {
kwargs = {
user = lib.mkOption {
type = lib.types.str;
default = "oncall";
description = "Database user.";
};
host = lib.mkOption {
type = lib.types.str;
default = "localhost";
description = "Database host.";
};
database = lib.mkOption {
type = lib.types.str;
default = "oncall";
description = "Database name.";
};
};
str = lib.mkOption {
type = lib.types.str;
default = "%(scheme)s://%(user)s@%(host)s:%(port)s/%(database)s?charset=%(charset)s&unix_socket=/run/mysqld/mysqld.sock";
description = ''
Database connection scheme. The default specifies the
connection through a local socket.
'';
};
require_auth = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether authentication is required to access the web app.
'';
};
};
};
};
default = { };
description = ''
Extra configuration options to append or override.
For available and default option values see
[upstream configuration file](https://github.com/linkedin/oncall/blob/master/configs/config.yaml)
and the administration part in the
[offical documentation](https://oncall.tools/docs/admin_guide.html).
'';
};
secretFile = lib.mkOption {
type = lib.types.pathWith {
inStore = false;
absolute = true;
};
example = "/run/keys/oncall-dbpassword";
description = ''
A YAML file containing secrets such as database or user passwords.
Some variables that can be considered secrets are:
- db.conn.kwargs.password:
Password used to authenticate to the database.
- session.encrypt_key:
Key for encrypting/signing session cookies.
Change to random long values in production.
- session.sign_key:
Key for encrypting/signing session cookies.
Change to random long values in production.
'';
};
};
config = lib.mkIf cfg.enable {
# Disable debug, only needed for development
services.oncall.settings = lib.mkMerge [
({
debug = lib.mkDefault false;
auth.debug = lib.mkDefault false;
})
];
services.uwsgi = {
enable = true;
plugins = [ "python3" ];
user = "oncall";
instance = {
type = "emperor";
vassals = {
oncall = {
type = "normal";
env = [
"PYTHONPATH=${pkgs.oncall.pythonPath}"
(
"ONCALL_EXTRA_CONFIG="
+ (lib.concatStringsSep "," (
[ configFile ] ++ lib.optional (cfg.secretFile != null) cfg.secretFile
))
)
"STATIC_ROOT=/var/lib/oncall"
];
module = "oncall.app:get_wsgi_app()";
socket = "${config.services.uwsgi.runDir}/oncall.sock";
socketGroup = "nginx";
immediate-gid = "nginx";
chmod-socket = "770";
pyargv = "${pkgs.oncall}/share/configs/config.yaml";
buffer-size = 32768;
};
};
};
};
services.nginx = {
enable = lib.mkDefault true;
virtualHosts."${cfg.settings.oncall_host}".locations = {
"/".extraConfig = "uwsgi_pass unix://${config.services.uwsgi.runDir}/oncall.sock;";
};
};
services.mysql = lib.mkIf cfg.database.createLocally {
enable = true;
package = lib.mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.settings.db.conn.kwargs.database ];
ensureUsers = [
{
name = cfg.settings.db.conn.kwargs.user;
ensurePermissions = {
"${cfg.settings.db.conn.kwargs.database}.*" = "ALL PRIVILEGES";
};
}
];
};
users.users.oncall = {
group = "nginx";
isSystemUser = true;
};
systemd = {
services = {
uwsgi.serviceConfig.StateDirectory = "oncall";
oncall-setup-database = lib.mkIf cfg.database.createLocally {
description = "Set up Oncall database";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
requiredBy = [ "uwsgi.service" ];
after = [ "mysql.service" ];
script =
let
mysql = "${lib.getExe' config.services.mysql.package "mysql"}";
in
''
if [ ! -f /var/lib/oncall/.dbexists ]; then
# Load database schema provided with package
${mysql} ${cfg.settings.db.conn.kwargs.database} < ${cfg.package}/share/db/schema.v0.sql
${mysql} ${cfg.settings.db.conn.kwargs.database} < ${cfg.package}/share/db/schema-update.v0-1602184489.sql
touch /var/lib/oncall/.dbexists
fi
'';
};
};
};
};
meta.maintainers = with lib.maintainers; [ onny ];
}