1 { config, lib, pkgs, buildEnv, ... }:
4 cfg = config.services.peering-manager;
6 pythonFmt = pkgs.formats.pythonVars {};
7 settingsFile = pythonFmt.generate "peering-manager-settings.py" cfg.settings;
8 extraConfigFile = pkgs.writeTextFile {
9 name = "peering-manager-extraConfig.py";
10 text = cfg.extraConfig;
12 configFile = pkgs.concatText "configuration.py" [ settingsFile extraConfigFile ];
14 pkg = (pkgs.peering-manager.overrideAttrs (old: {
16 ln -s ${configFile} $out/opt/peering-manager/peering_manager/configuration.py
17 '' + lib.optionalString cfg.enableLdap ''
18 ln -s ${cfg.ldapConfigPath} $out/opt/peering-manager/peering_manager/ldap_config.py
19 '' + lib.optionalString cfg.enableOidc ''
20 ln -s ${cfg.oidcConfigPath} $out/opt/peering-manager/peering_manager/oidc_config.py
23 inherit (cfg) plugins;
25 peeringManagerManageScript = pkgs.writeScriptBin "peering-manager-manage" ''
26 #!${pkgs.stdenv.shell}
27 export PYTHONPATH=${pkg.pythonPath}
28 sudo -u peering-manager ${pkg}/bin/peering-manager "$@"
32 options.services.peering-manager = with lib; {
37 Enable Peering Manager.
39 This module requires a reverse proxy that serves `/static` separately.
40 See this [example](https://github.com/peering-manager/contrib/blob/main/nginx.conf on how to configure this.
44 enableScheduledTasks = mkOption {
48 Set up [scheduled tasks](https://peering-manager.readthedocs.io/en/stable/setup/8-scheduled-tasks/)
52 listenAddress = mkOption {
56 Address the server will listen on.
64 Port the server will listen on.
69 type = types.functionTo (types.listOf types.package);
71 defaultText = literalExpression ''
72 python3Packages: with python3Packages; [];
75 List of plugin packages to install.
79 secretKeyFile = mkOption {
82 Path to a file containing the secret key.
86 peeringdbApiKeyFile = mkOption {
87 type = with types; nullOr path;
90 Path to a file containing the PeeringDB API key.
94 settings = lib.mkOption {
96 Configuration options to set in `configuration.py`.
97 See the [documentation](https://peering-manager.readthedocs.io/en/stable/configuration/optional-settings/) for more possible options.
102 type = lib.types.submodule {
103 freeformType = pythonFmt.type;
106 ALLOWED_HOSTS = lib.mkOption {
107 type = with lib.types; listOf str;
110 A list of valid fully-qualified domain names (FQDNs) and/or IP
111 addresses that can be used to reach the peering manager service.
118 extraConfig = mkOption {
122 Additional lines of configuration appended to the `configuration.py`.
123 See the [documentation](https://peering-manager.readthedocs.io/en/stable/configuration/optional-settings/) for more possible options.
127 enableLdap = mkOption {
131 Enable LDAP-Authentication for Peering Manager.
133 This requires a configuration file being pass through `ldapConfigPath`.
137 ldapConfigPath = mkOption {
140 Path to the Configuration-File for LDAP-Authentication, will be loaded as `ldap_config.py`.
141 See the [documentation](https://peering-manager.readthedocs.io/en/stable/setup/6-ldap/#configuration) for possible options.
145 enableOidc = mkOption {
149 Enable OIDC-Authentication for Peering Manager.
151 This requires a configuration file being pass through `oidcConfigPath`.
155 oidcConfigPath = mkOption {
158 Path to the Configuration-File for OIDC-Authentication, will be loaded as `oidc_config.py`.
159 See the [documentation](https://peering-manager.readthedocs.io/en/stable/setup/6b-oidc/#configuration) for possible options.
164 config = lib.mkIf cfg.enable {
165 services.peering-manager = {
168 NAME = "peering-manager";
169 USER = "peering-manager";
170 HOST = "/run/postgresql";
173 # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate
174 # configuration exists for each. Full connection details are required in both sections, and it is strongly recommended
175 # to use two separate database IDs.
178 UNIX_SOCKET_PATH = config.services.redis.servers.peering-manager.unixSocket;
182 UNIX_SOCKET_PATH = config.services.redis.servers.peering-manager.unixSocket;
189 with open("${cfg.secretKeyFile}", "r") as file:
190 SECRET_KEY = file.readline()
191 '' + lib.optionalString (cfg.peeringdbApiKeyFile != null) ''
192 with open("${cfg.peeringdbApiKeyFile}", "r") as file:
193 PEERINGDB_API_KEY = file.readline()
197 (lib.optionals cfg.enableLdap [ ps.django-auth-ldap ]) ++
198 (lib.optionals cfg.enableOidc (with ps; [ mozilla-django-oidc pyopenssl josepy ]))
202 system.build.peeringManagerPkg = pkg;
204 services.redis.servers.peering-manager.enable = true;
206 services.postgresql = {
208 ensureDatabases = [ "peering-manager" ];
211 name = "peering-manager";
212 ensureDBOwnership = true;
217 environment.systemPackages = [ peeringManagerManageScript ];
219 systemd.targets.peering-manager = {
220 description = "Target for all Peering Manager services";
221 wantedBy = [ "multi-user.target" ];
222 wants = [ "network-online.target" ];
223 after = [ "network-online.target" "redis-peering-manager.service" ];
226 systemd.services = let
229 PYTHONPATH = pkg.pythonPath;
232 WorkingDirectory = "/var/lib/peering-manager";
233 User = "peering-manager";
234 Group = "peering-manager";
235 StateDirectory = "peering-manager";
236 StateDirectoryMode = "0750";
237 Restart = "on-failure";
241 peering-manager-migration = lib.recursiveUpdate defaults {
242 description = "Peering Manager migrations";
243 wantedBy = [ "peering-manager.target" ];
246 ExecStart = "${pkg}/bin/peering-manager migrate";
250 peering-manager = lib.recursiveUpdate defaults {
251 description = "Peering Manager WSGI Service";
252 wantedBy = [ "peering-manager.target" ];
253 after = [ "peering-manager-migration.service" ];
256 ${pkg}/bin/peering-manager remove_stale_contenttypes --no-input
261 ${pkg.python.pkgs.gunicorn}/bin/gunicorn peering_manager.wsgi \
262 --bind ${cfg.listenAddress}:${toString cfg.port} \
263 --pythonpath ${pkg}/opt/peering-manager
268 peering-manager-rq = lib.recursiveUpdate defaults {
269 description = "Peering Manager Request Queue Worker";
270 wantedBy = [ "peering-manager.target" ];
271 after = [ "peering-manager.service" ];
272 serviceConfig.ExecStart = "${pkg}/bin/peering-manager rqworker high default low";
275 peering-manager-housekeeping = lib.recursiveUpdate defaults {
276 description = "Peering Manager housekeeping job";
277 after = [ "peering-manager.service" ];
280 ExecStart = "${pkg}/bin/peering-manager housekeeping";
284 peering-manager-peeringdb-sync = lib.recursiveUpdate defaults {
285 description = "PeeringDB sync";
286 after = [ "peering-manager.service" ];
289 ExecStart = "${pkg}/bin/peering-manager peeringdb_sync";
293 peering-manager-prefix-fetch = lib.recursiveUpdate defaults {
294 description = "Fetch IRR AS-SET prefixes";
295 after = [ "peering-manager.service" ];
298 ExecStart = "${pkg}/bin/peering-manager grab_prefixes";
302 peering-manager-configuration-deployment = lib.recursiveUpdate defaults {
303 description = "Push configuration to routers";
304 after = [ "peering-manager.service" ];
307 ExecStart = "${pkg}/bin/peering-manager configure_routers";
311 peering-manager-session-poll = lib.recursiveUpdate defaults {
312 description = "Poll peering sessions from routers";
313 after = [ "peering-manager.service" ];
316 ExecStart = "${pkg}/bin/peering-manager poll_bgp_sessions --all";
322 peering-manager-housekeeping = {
323 description = "Run Peering Manager housekeeping job";
324 wantedBy = [ "timers.target" ];
325 timerConfig.OnCalendar = "daily";
328 peering-manager-peeringdb-sync = {
329 enable = lib.mkDefault cfg.enableScheduledTasks;
330 description = "Sync PeeringDB at 2:30";
331 wantedBy = [ "timers.target" ];
332 timerConfig.OnCalendar = "02:30:00";
335 peering-manager-prefix-fetch = {
336 enable = lib.mkDefault cfg.enableScheduledTasks;
337 description = "Fetch IRR AS-SET prefixes at 4:30";
338 wantedBy = [ "timers.target" ];
339 timerConfig.OnCalendar = "04:30:00";
342 peering-manager-configuration-deployment = {
343 enable = lib.mkDefault cfg.enableScheduledTasks;
344 description = "Push router configuration every hour 5 minutes before full hour";
345 wantedBy = [ "timers.target" ];
346 timerConfig.OnCalendar = "*:55:00";
349 peering-manager-session-poll = {
350 enable = lib.mkDefault cfg.enableScheduledTasks;
351 description = "Poll peering sessions from routers every hour";
352 wantedBy = [ "timers.target" ];
353 timerConfig.OnCalendar = "*:00:00";
357 users.users.peering-manager = {
358 home = "/var/lib/peering-manager";
360 group = "peering-manager";
362 users.groups.peering-manager = {};
363 users.groups."${config.services.redis.servers.peering-manager.user}".members = [ "peering-manager" ];
366 meta.maintainers = with lib.maintainers; [ yuka ];