at 25.11-pre 12 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 buildEnv, 6 ... 7}: 8 9let 10 cfg = config.services.peering-manager; 11 12 pythonFmt = pkgs.formats.pythonVars { }; 13 settingsFile = pythonFmt.generate "peering-manager-settings.py" cfg.settings; 14 extraConfigFile = pkgs.writeTextFile { 15 name = "peering-manager-extraConfig.py"; 16 text = cfg.extraConfig; 17 }; 18 configFile = pkgs.concatText "configuration.py" [ 19 settingsFile 20 extraConfigFile 21 ]; 22 23 pkg = 24 (pkgs.peering-manager.overrideAttrs (old: { 25 postInstall = 26 '' 27 ln -s ${configFile} $out/opt/peering-manager/peering_manager/configuration.py 28 '' 29 + lib.optionalString cfg.enableLdap '' 30 ln -s ${cfg.ldapConfigPath} $out/opt/peering-manager/peering_manager/ldap_config.py 31 '' 32 + lib.optionalString cfg.enableOidc '' 33 ln -s ${cfg.oidcConfigPath} $out/opt/peering-manager/peering_manager/oidc_config.py 34 ''; 35 })).override 36 { 37 inherit (cfg) plugins; 38 }; 39 peeringManagerManageScript = pkgs.writeScriptBin "peering-manager-manage" '' 40 #!${pkgs.stdenv.shell} 41 export PYTHONPATH=${pkg.pythonPath} 42 sudo -u peering-manager ${pkg}/bin/peering-manager "$@" 43 ''; 44 45in 46{ 47 options.services.peering-manager = with lib; { 48 enable = mkOption { 49 type = types.bool; 50 default = false; 51 description = '' 52 Enable Peering Manager. 53 54 This module requires a reverse proxy that serves `/static` separately. 55 See this [example](https://github.com/peering-manager/contrib/blob/main/nginx.conf) on how to configure this. 56 ''; 57 }; 58 59 enableScheduledTasks = mkOption { 60 type = types.bool; 61 default = true; 62 description = '' 63 Set up [scheduled tasks](https://peering-manager.readthedocs.io/en/stable/setup/8-scheduled-tasks/) 64 ''; 65 }; 66 67 listenAddress = mkOption { 68 type = types.str; 69 default = "[::1]"; 70 description = '' 71 Address the server will listen on. 72 ''; 73 }; 74 75 port = mkOption { 76 type = types.port; 77 default = 8001; 78 description = '' 79 Port the server will listen on. 80 ''; 81 }; 82 83 plugins = mkOption { 84 type = types.functionTo (types.listOf types.package); 85 default = _: [ ]; 86 defaultText = literalExpression '' 87 python3Packages: with python3Packages; []; 88 ''; 89 description = '' 90 List of plugin packages to install. 91 ''; 92 }; 93 94 secretKeyFile = mkOption { 95 type = types.path; 96 description = '' 97 Path to a file containing the secret key. 98 ''; 99 }; 100 101 peeringdbApiKeyFile = mkOption { 102 type = with types; nullOr path; 103 default = null; 104 description = '' 105 Path to a file containing the PeeringDB API key. 106 ''; 107 }; 108 109 settings = lib.mkOption { 110 description = '' 111 Configuration options to set in `configuration.py`. 112 See the [documentation](https://peering-manager.readthedocs.io/en/stable/configuration/optional-settings/) for more possible options. 113 ''; 114 115 default = { }; 116 117 type = lib.types.submodule { 118 freeformType = pythonFmt.type; 119 120 options = { 121 ALLOWED_HOSTS = lib.mkOption { 122 type = with lib.types; listOf str; 123 default = [ "*" ]; 124 description = '' 125 A list of valid fully-qualified domain names (FQDNs) and/or IP 126 addresses that can be used to reach the peering manager service. 127 ''; 128 }; 129 }; 130 }; 131 }; 132 133 extraConfig = mkOption { 134 type = types.lines; 135 default = ""; 136 description = '' 137 Additional lines of configuration appended to the `configuration.py`. 138 See the [documentation](https://peering-manager.readthedocs.io/en/stable/configuration/optional-settings/) for more possible options. 139 ''; 140 }; 141 142 enableLdap = mkOption { 143 type = types.bool; 144 default = false; 145 description = '' 146 Enable LDAP-Authentication for Peering Manager. 147 148 This requires a configuration file being pass through `ldapConfigPath`. 149 ''; 150 }; 151 152 ldapConfigPath = mkOption { 153 type = types.path; 154 description = '' 155 Path to the Configuration-File for LDAP-Authentication, will be loaded as `ldap_config.py`. 156 See the [documentation](https://peering-manager.readthedocs.io/en/stable/setup/6-ldap/#configuration) for possible options. 157 ''; 158 }; 159 160 enableOidc = mkOption { 161 type = types.bool; 162 default = false; 163 description = '' 164 Enable OIDC-Authentication for Peering Manager. 165 166 This requires a configuration file being pass through `oidcConfigPath`. 167 ''; 168 }; 169 170 oidcConfigPath = mkOption { 171 type = types.path; 172 description = '' 173 Path to the Configuration-File for OIDC-Authentication, will be loaded as `oidc_config.py`. 174 See the [documentation](https://peering-manager.readthedocs.io/en/stable/setup/6b-oidc/#configuration) for possible options. 175 ''; 176 }; 177 }; 178 179 config = lib.mkIf cfg.enable { 180 services.peering-manager = { 181 settings = { 182 DATABASE = { 183 NAME = "peering-manager"; 184 USER = "peering-manager"; 185 HOST = "/run/postgresql"; 186 }; 187 188 # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate 189 # configuration exists for each. Full connection details are required in both sections, and it is strongly recommended 190 # to use two separate database IDs. 191 REDIS = { 192 tasks = { 193 UNIX_SOCKET_PATH = config.services.redis.servers.peering-manager.unixSocket; 194 DATABASE = 0; 195 }; 196 caching = { 197 UNIX_SOCKET_PATH = config.services.redis.servers.peering-manager.unixSocket; 198 DATABASE = 1; 199 }; 200 }; 201 }; 202 203 extraConfig = 204 '' 205 with open("${cfg.secretKeyFile}", "r") as file: 206 SECRET_KEY = file.readline() 207 '' 208 + lib.optionalString (cfg.peeringdbApiKeyFile != null) '' 209 with open("${cfg.peeringdbApiKeyFile}", "r") as file: 210 PEERINGDB_API_KEY = file.readline() 211 ''; 212 213 plugins = ( 214 ps: 215 (lib.optionals cfg.enableLdap [ ps.django-auth-ldap ]) 216 ++ (lib.optionals cfg.enableOidc ( 217 with ps; 218 [ 219 mozilla-django-oidc 220 pyopenssl 221 josepy 222 ] 223 )) 224 ); 225 }; 226 227 system.build.peeringManagerPkg = pkg; 228 229 services.redis.servers.peering-manager.enable = true; 230 231 services.postgresql = { 232 enable = true; 233 ensureDatabases = [ "peering-manager" ]; 234 ensureUsers = [ 235 { 236 name = "peering-manager"; 237 ensureDBOwnership = true; 238 } 239 ]; 240 }; 241 242 environment.systemPackages = [ peeringManagerManageScript ]; 243 244 systemd.targets.peering-manager = { 245 description = "Target for all Peering Manager services"; 246 wantedBy = [ "multi-user.target" ]; 247 wants = [ "network-online.target" ]; 248 after = [ 249 "network-online.target" 250 "redis-peering-manager.service" 251 ]; 252 }; 253 254 systemd.services = 255 let 256 defaults = { 257 environment = { 258 PYTHONPATH = pkg.pythonPath; 259 }; 260 serviceConfig = { 261 WorkingDirectory = "/var/lib/peering-manager"; 262 User = "peering-manager"; 263 Group = "peering-manager"; 264 StateDirectory = "peering-manager"; 265 StateDirectoryMode = "0750"; 266 Restart = "on-failure"; 267 }; 268 }; 269 in 270 { 271 peering-manager-migration = lib.recursiveUpdate defaults { 272 description = "Peering Manager migrations"; 273 wantedBy = [ "peering-manager.target" ]; 274 serviceConfig = { 275 Type = "oneshot"; 276 ExecStart = "${pkg}/bin/peering-manager migrate"; 277 }; 278 }; 279 280 peering-manager = lib.recursiveUpdate defaults { 281 description = "Peering Manager WSGI Service"; 282 wantedBy = [ "peering-manager.target" ]; 283 after = [ "peering-manager-migration.service" ]; 284 285 preStart = '' 286 ${pkg}/bin/peering-manager remove_stale_contenttypes --no-input 287 ''; 288 289 serviceConfig = { 290 ExecStart = '' 291 ${pkg.python.pkgs.gunicorn}/bin/gunicorn peering_manager.wsgi \ 292 --bind ${cfg.listenAddress}:${toString cfg.port} \ 293 --pythonpath ${pkg}/opt/peering-manager 294 ''; 295 }; 296 }; 297 298 peering-manager-rq = lib.recursiveUpdate defaults { 299 description = "Peering Manager Request Queue Worker"; 300 wantedBy = [ "peering-manager.target" ]; 301 after = [ "peering-manager.service" ]; 302 serviceConfig.ExecStart = "${pkg}/bin/peering-manager rqworker high default low"; 303 }; 304 305 peering-manager-housekeeping = lib.recursiveUpdate defaults { 306 description = "Peering Manager housekeeping job"; 307 after = [ "peering-manager.service" ]; 308 serviceConfig = { 309 Type = "oneshot"; 310 ExecStart = "${pkg}/bin/peering-manager housekeeping"; 311 }; 312 }; 313 314 peering-manager-peeringdb-sync = lib.recursiveUpdate defaults { 315 description = "PeeringDB sync"; 316 after = [ "peering-manager.service" ]; 317 serviceConfig = { 318 Type = "oneshot"; 319 ExecStart = "${pkg}/bin/peering-manager peeringdb_sync"; 320 }; 321 }; 322 323 peering-manager-prefix-fetch = lib.recursiveUpdate defaults { 324 description = "Fetch IRR AS-SET prefixes"; 325 after = [ "peering-manager.service" ]; 326 serviceConfig = { 327 Type = "oneshot"; 328 ExecStart = "${pkg}/bin/peering-manager grab_prefixes"; 329 }; 330 }; 331 332 peering-manager-configuration-deployment = lib.recursiveUpdate defaults { 333 description = "Push configuration to routers"; 334 after = [ "peering-manager.service" ]; 335 serviceConfig = { 336 Type = "oneshot"; 337 ExecStart = "${pkg}/bin/peering-manager configure_routers"; 338 }; 339 }; 340 341 peering-manager-session-poll = lib.recursiveUpdate defaults { 342 description = "Poll peering sessions from routers"; 343 after = [ "peering-manager.service" ]; 344 serviceConfig = { 345 Type = "oneshot"; 346 ExecStart = "${pkg}/bin/peering-manager poll_bgp_sessions --all"; 347 }; 348 }; 349 }; 350 351 systemd.timers = { 352 peering-manager-housekeeping = { 353 description = "Run Peering Manager housekeeping job"; 354 wantedBy = [ "timers.target" ]; 355 timerConfig.OnCalendar = "daily"; 356 }; 357 358 peering-manager-peeringdb-sync = { 359 enable = lib.mkDefault cfg.enableScheduledTasks; 360 description = "Sync PeeringDB at 2:30"; 361 wantedBy = [ "timers.target" ]; 362 timerConfig.OnCalendar = "02:30:00"; 363 }; 364 365 peering-manager-prefix-fetch = { 366 enable = lib.mkDefault cfg.enableScheduledTasks; 367 description = "Fetch IRR AS-SET prefixes at 4:30"; 368 wantedBy = [ "timers.target" ]; 369 timerConfig.OnCalendar = "04:30:00"; 370 }; 371 372 peering-manager-configuration-deployment = { 373 enable = lib.mkDefault cfg.enableScheduledTasks; 374 description = "Push router configuration every hour 5 minutes before full hour"; 375 wantedBy = [ "timers.target" ]; 376 timerConfig.OnCalendar = "*:55:00"; 377 }; 378 379 peering-manager-session-poll = { 380 enable = lib.mkDefault cfg.enableScheduledTasks; 381 description = "Poll peering sessions from routers every hour"; 382 wantedBy = [ "timers.target" ]; 383 timerConfig.OnCalendar = "*:00:00"; 384 }; 385 }; 386 387 users.users.peering-manager = { 388 home = "/var/lib/peering-manager"; 389 isSystemUser = true; 390 group = "peering-manager"; 391 }; 392 users.groups.peering-manager = { }; 393 users.groups."${config.services.redis.servers.peering-manager.user}".members = [ 394 "peering-manager" 395 ]; 396 }; 397 398 meta.maintainers = with lib.maintainers; [ yuka ]; 399}