at 25.11-pre 3.7 kB view raw
1{ 2 pkgs, 3 lib, 4 config, 5 ... 6}: 7let 8 cfg = config.services.devpi-server; 9 10 secretsFileName = "devpi-secret-file"; 11 12 stateDirName = "devpi"; 13 14 runtimeDir = "/run/${stateDirName}"; 15 serverDir = "/var/lib/${stateDirName}"; 16in 17{ 18 options.services.devpi-server = { 19 enable = lib.mkEnableOption "Devpi Server"; 20 21 package = lib.mkPackageOption pkgs "devpi-server" { }; 22 23 primaryUrl = lib.mkOption { 24 type = lib.types.str; 25 description = "Url for the primary node. Required option for replica nodes."; 26 }; 27 28 replica = lib.mkOption { 29 type = lib.types.bool; 30 default = false; 31 description = '' 32 Run node as a replica. 33 Requires the secretFile option and the primaryUrl to be enabled. 34 ''; 35 }; 36 37 secretFile = lib.mkOption { 38 type = lib.types.nullOr lib.types.path; 39 default = null; 40 description = '' 41 Path to a shared secret file used for synchronization, 42 Required for all nodes in a replica/primary setup. 43 ''; 44 }; 45 46 host = lib.mkOption { 47 type = lib.types.str; 48 default = "localhost"; 49 description = '' 50 domain/ip address to listen on 51 ''; 52 }; 53 54 port = lib.mkOption { 55 type = lib.types.port; 56 default = 3141; 57 description = "The port on which Devpi Server will listen."; 58 }; 59 60 openFirewall = lib.mkEnableOption "opening the default ports in the firewall for Devpi Server"; 61 }; 62 63 config = lib.mkIf cfg.enable { 64 65 systemd.services.devpi-server = { 66 enable = true; 67 description = "devpi PyPI-compatible server"; 68 documentation = [ "https://devpi.net/docs/devpi/devpi/stable/+d/index.html" ]; 69 wants = [ "network-online.target" ]; 70 wantedBy = [ "multi-user.target" ]; 71 after = [ "network-online.target" ]; 72 # Since at least devpi-server 6.10.0, devpi requires the secrets file to 73 # have 0600 permissions. 74 preStart = 75 '' 76 ${lib.optionalString ( 77 !isNull cfg.secretFile 78 ) "install -Dm 0600 \${CREDENTIALS_DIRECTORY}/devpi-secret ${runtimeDir}/${secretsFileName}"} 79 80 if [ -f ${serverDir}/.nodeinfo ]; then 81 # already initialized the package index, exit gracefully 82 exit 0 83 fi 84 ${cfg.package}/bin/devpi-init --serverdir ${serverDir} '' 85 + lib.optionalString cfg.replica "--role=replica --master-url=${cfg.primaryUrl}"; 86 87 serviceConfig = { 88 LoadCredential = lib.mkIf (!isNull cfg.secretFile) [ 89 "devpi-secret:${cfg.secretFile}" 90 ]; 91 Restart = "always"; 92 ExecStart = 93 let 94 args = 95 [ 96 "--request-timeout=5" 97 "--serverdir=${serverDir}" 98 "--host=${cfg.host}" 99 "--port=${builtins.toString cfg.port}" 100 ] 101 ++ lib.optionals (!isNull cfg.secretFile) [ 102 "--secretfile=${runtimeDir}/${secretsFileName}" 103 ] 104 ++ ( 105 if cfg.replica then 106 [ 107 "--role=replica" 108 "--master-url=${cfg.primaryUrl}" 109 ] 110 else 111 [ "--role=master" ] 112 ); 113 in 114 "${cfg.package}/bin/devpi-server ${lib.concatStringsSep " " args}"; 115 DynamicUser = true; 116 StateDirectory = stateDirName; 117 RuntimeDirectory = stateDirName; 118 PrivateDevices = true; 119 PrivateTmp = true; 120 ProtectHome = true; 121 ProtectSystem = "strict"; 122 }; 123 }; 124 125 networking.firewall = lib.mkIf cfg.openFirewall { 126 allowedTCPPorts = [ cfg.port ]; 127 }; 128 }; 129 130 meta.maintainers = [ lib.maintainers.cafkafk ]; 131}