1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.blendfarm;
9 json = pkgs.formats.json { };
10 configFile = json.generate "ServerSettings" (defaultConfig // cfg.serverConfig);
11 defaultConfig = {
12 Port = 15000;
13 BroadcastPort = 16342;
14 BypassScriptUpdate = false;
15 BasicSecurityPassword = null;
16 };
17in
18{
19 meta.maintainers = with lib.maintainers; [ gador ];
20
21 options.services.blendfarm = with lib.types; {
22 enable = lib.mkEnableOption "Blendfarm, a render farm management software for Blender";
23 package = lib.mkPackageOption pkgs "blendfarm" { };
24 openFirewall = lib.mkEnableOption "allowing blendfarm network access through the firewall";
25
26 user = lib.mkOption {
27 description = "User under which blendfarm runs.";
28 default = "blendfarm";
29 type = str;
30 };
31
32 group = lib.mkOption {
33 description = "Group under which blendfarm runs.";
34 default = "blendfarm";
35 type = str;
36 };
37
38 basicSecurityPasswordFile = lib.mkOption {
39 description = ''
40 Path to the password file the client needs to connect to the server.
41 The password must not contain a forward slash.'';
42 default = null;
43 type = nullOr str;
44 };
45
46 blenderPackage = lib.mkPackageOption pkgs "blender" { };
47
48 serverConfig = lib.mkOption {
49 description = "Server configuration";
50 default = defaultConfig;
51 type = submodule {
52 freeformType = attrsOf anything;
53 options = {
54 Port = lib.mkOption {
55 description = "Default port blendfarm server listens on.";
56 default = 15000;
57 type = types.port;
58 };
59 BroadcastPort = lib.mkOption {
60 description = "Default port blendfarm server advertises itself on.";
61 default = 16342;
62 type = types.port;
63 };
64
65 BypassScriptUpdate = lib.mkOption {
66 description = "Prevents blendfarm from replacing the .py self-generated scripts.";
67 default = false;
68 type = bool;
69 };
70 };
71 };
72 };
73 };
74
75 config = lib.mkIf cfg.enable {
76 environment.systemPackages = [ cfg.package ];
77 networking.firewall = lib.optionalAttrs (cfg.openFirewall) {
78 allowedTCPPorts = [ cfg.serverConfig.Port ];
79 allowedUDPPorts = [ cfg.serverConfig.BroadcastPort ];
80 };
81
82 systemd.services.blendfarm-server = {
83 wantedBy = [ "multi-user.target" ];
84 after = [ "network-online.target" ];
85 wants = [ "network-online.target" ];
86 description = "blendfarm server";
87 path = [ cfg.blenderPackage ];
88 preStart = ''
89 rm -f ServerSettings
90 install -m640 ${configFile} ServerSettings
91 if [ ! -d "BlenderData/nix-blender-linux64" ]; then
92 mkdir -p BlenderData/nix-blender-linux64
93 echo "nix-blender" > VersionCustom
94 fi
95 rm -f BlenderData/nix-blender-linux64/blender
96 ln -s ${lib.getExe cfg.blenderPackage} BlenderData/nix-blender-linux64/blender
97 ''
98 + lib.optionalString (cfg.basicSecurityPasswordFile != null) ''
99 BLENDFARM_PASSWORD=$(${pkgs.systemd}/bin/systemd-creds cat BLENDFARM_PASS_FILE)
100 sed -i "s/null/\"$BLENDFARM_PASSWORD\"/g" ServerSettings
101 '';
102 serviceConfig = {
103 ExecStart = "${cfg.package}/bin/LogicReinc.BlendFarm.Server";
104 DynamicUser = true;
105 LogsDirectory = "blendfarm";
106 StateDirectory = "blendfarm";
107 WorkingDirectory = "/var/lib/blendfarm";
108 User = cfg.user;
109 Group = cfg.group;
110 StateDirectoryMode = "0755";
111 LoadCredential = lib.optional (
112 cfg.basicSecurityPasswordFile != null
113 ) "BLENDFARM_PASS_FILE:${cfg.basicSecurityPasswordFile}";
114 ReadWritePaths = "";
115 CapabilityBoundingSet = "";
116 RestrictAddressFamilies = [
117 "AF_UNIX"
118 "AF_INET"
119 "AF_INET6"
120 ];
121 RestrictNamespaces = true;
122 PrivateDevices = true;
123 PrivateUsers = true;
124 ProtectClock = true;
125 ProtectControlGroups = true;
126 ProtectHome = true;
127 ProtectKernelLogs = true;
128 ProtectKernelModules = true;
129 ProtectKernelTunables = true;
130 SystemCallArchitectures = "native";
131 SystemCallFilter = [
132 "@system-service"
133 "~@privileged"
134 "@chown"
135 ];
136 RestrictRealtime = true;
137 LockPersonality = true;
138 UMask = "0066";
139 ProtectHostname = true;
140 };
141 };
142
143 users.users.blendfarm = {
144 isSystemUser = true;
145 group = "blendfarm";
146 };
147 users.groups.blendfarm = { };
148 };
149}