nixos/oncall: init

Changed files
+206
nixos
doc
manual
release-notes
modules
services
web-apps
+2
nixos/doc/manual/release-notes/rl-2505.section.md
···
- [vwifi](https://github.com/Raizo62/vwifi), a Wi-Fi simulator daemon leveraging the `mac80211_hwsim` and `vhost_vsock` kernel modules for efficient simulation of multi-node Wi-Fi networks. Available as {option}`services.vwifi`.
+
- [Oncall](https://oncall.tools), a web-based calendar tool designed for scheduling and managing on-call shifts. Available as [services.oncall](options.html#opt-services.oncall).
+
- [Homer](https://homer-demo.netlify.app/), a very simple static homepage for your server. Available as [services.homer](options.html#opt-services.homer).
- [Ghidra](https://ghidra-sre.org/), a software reverse engineering (SRE) suite of tools. Available as [programs.ghidra](options.html#opt-programs.ghidra).
+1
nixos/modules/module-list.nix
···
./services/web-apps/nostr-rs-relay.nix
./services/web-apps/ocis.nix
./services/web-apps/olivetin.nix
+
./services/web-apps/oncall.nix
./services/web-apps/onlyoffice.nix
./services/web-apps/open-web-calendar.nix
./services/web-apps/openvscode-server.nix
+203
nixos/modules/services/web-apps/oncall.nix
···
+
{
+
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 ];
+
+
}