at 25.11-pre 6.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 9 cfg = config.services.oncall; 10 settingsFormat = pkgs.formats.yaml { }; 11 configFile = settingsFormat.generate "oncall_extra_settings.yaml" cfg.settings; 12 13in 14{ 15 options.services.oncall = { 16 17 enable = lib.mkEnableOption "Oncall web app"; 18 19 package = lib.mkPackageOption pkgs "oncall" { }; 20 21 database.createLocally = lib.mkEnableOption "Create the database and database user locally." // { 22 default = true; 23 }; 24 25 settings = lib.mkOption { 26 type = lib.types.submodule { 27 freeformType = settingsFormat.type; 28 options = { 29 oncall_host = lib.mkOption { 30 type = lib.types.str; 31 default = "localhost"; 32 description = "FQDN for the Oncall instance."; 33 }; 34 db.conn = { 35 kwargs = { 36 user = lib.mkOption { 37 type = lib.types.str; 38 default = "oncall"; 39 description = "Database user."; 40 }; 41 host = lib.mkOption { 42 type = lib.types.str; 43 default = "localhost"; 44 description = "Database host."; 45 }; 46 database = lib.mkOption { 47 type = lib.types.str; 48 default = "oncall"; 49 description = "Database name."; 50 }; 51 }; 52 str = lib.mkOption { 53 type = lib.types.str; 54 default = "%(scheme)s://%(user)s@%(host)s:%(port)s/%(database)s?charset=%(charset)s&unix_socket=/run/mysqld/mysqld.sock"; 55 description = '' 56 Database connection scheme. The default specifies the 57 connection through a local socket. 58 ''; 59 }; 60 require_auth = lib.mkOption { 61 type = lib.types.bool; 62 default = true; 63 description = '' 64 Whether authentication is required to access the web app. 65 ''; 66 }; 67 }; 68 }; 69 }; 70 default = { }; 71 description = '' 72 Extra configuration options to append or override. 73 For available and default option values see 74 [upstream configuration file](https://github.com/linkedin/oncall/blob/master/configs/config.yaml) 75 and the administration part in the 76 [offical documentation](https://oncall.tools/docs/admin_guide.html). 77 ''; 78 }; 79 80 secretFile = lib.mkOption { 81 type = lib.types.pathWith { 82 inStore = false; 83 absolute = true; 84 }; 85 example = "/run/keys/oncall-dbpassword"; 86 description = '' 87 A YAML file containing secrets such as database or user passwords. 88 Some variables that can be considered secrets are: 89 90 - db.conn.kwargs.password: 91 Password used to authenticate to the database. 92 93 - session.encrypt_key: 94 Key for encrypting/signing session cookies. 95 Change to random long values in production. 96 97 - session.sign_key: 98 Key for encrypting/signing session cookies. 99 Change to random long values in production. 100 ''; 101 }; 102 103 }; 104 105 config = lib.mkIf cfg.enable { 106 107 # Disable debug, only needed for development 108 services.oncall.settings = lib.mkMerge [ 109 ({ 110 debug = lib.mkDefault false; 111 auth.debug = lib.mkDefault false; 112 }) 113 ]; 114 115 services.uwsgi = { 116 enable = true; 117 plugins = [ "python3" ]; 118 user = "oncall"; 119 instance = { 120 type = "emperor"; 121 vassals = { 122 oncall = { 123 type = "normal"; 124 env = [ 125 "PYTHONPATH=${pkgs.oncall.pythonPath}" 126 ( 127 "ONCALL_EXTRA_CONFIG=" 128 + (lib.concatStringsSep "," ( 129 [ configFile ] ++ lib.optional (cfg.secretFile != null) cfg.secretFile 130 )) 131 ) 132 "STATIC_ROOT=/var/lib/oncall" 133 ]; 134 module = "oncall.app:get_wsgi_app()"; 135 socket = "${config.services.uwsgi.runDir}/oncall.sock"; 136 socketGroup = "nginx"; 137 immediate-gid = "nginx"; 138 chmod-socket = "770"; 139 pyargv = "${pkgs.oncall}/share/configs/config.yaml"; 140 buffer-size = 32768; 141 }; 142 }; 143 }; 144 }; 145 146 services.nginx = { 147 enable = lib.mkDefault true; 148 virtualHosts."${cfg.settings.oncall_host}".locations = { 149 "/".extraConfig = "uwsgi_pass unix://${config.services.uwsgi.runDir}/oncall.sock;"; 150 }; 151 }; 152 153 services.mysql = lib.mkIf cfg.database.createLocally { 154 enable = true; 155 package = lib.mkDefault pkgs.mariadb; 156 ensureDatabases = [ cfg.settings.db.conn.kwargs.database ]; 157 ensureUsers = [ 158 { 159 name = cfg.settings.db.conn.kwargs.user; 160 ensurePermissions = { 161 "${cfg.settings.db.conn.kwargs.database}.*" = "ALL PRIVILEGES"; 162 }; 163 } 164 ]; 165 }; 166 167 users.users.oncall = { 168 group = "nginx"; 169 isSystemUser = true; 170 }; 171 172 systemd = { 173 services = { 174 uwsgi.serviceConfig.StateDirectory = "oncall"; 175 oncall-setup-database = lib.mkIf cfg.database.createLocally { 176 description = "Set up Oncall database"; 177 serviceConfig = { 178 Type = "oneshot"; 179 RemainAfterExit = true; 180 }; 181 requiredBy = [ "uwsgi.service" ]; 182 after = [ "mysql.service" ]; 183 script = 184 let 185 mysql = "${lib.getExe' config.services.mysql.package "mysql"}"; 186 in 187 '' 188 if [ ! -f /var/lib/oncall/.dbexists ]; then 189 # Load database schema provided with package 190 ${mysql} ${cfg.settings.db.conn.kwargs.database} < ${cfg.package}/share/db/schema.v0.sql 191 ${mysql} ${cfg.settings.db.conn.kwargs.database} < ${cfg.package}/share/db/schema-update.v0-1602184489.sql 192 touch /var/lib/oncall/.dbexists 193 fi 194 ''; 195 }; 196 }; 197 }; 198 199 }; 200 201 meta.maintainers = with lib.maintainers; [ onny ]; 202 203}