1{
2 pkgs,
3 lib,
4 config,
5 ...
6}:
7let
8 cfg = config.services.dysnomia;
9
10 printProperties =
11 properties:
12 lib.concatMapStrings (
13 propertyName:
14 let
15 property = properties.${propertyName};
16 in
17 if lib.isList property then
18 "${propertyName}=(${
19 lib.concatMapStrings (elem: "\"${toString elem}\" ") (properties.${propertyName})
20 })\n"
21 else
22 "${propertyName}=\"${toString property}\"\n"
23 ) (builtins.attrNames properties);
24
25 properties = pkgs.stdenv.mkDerivation {
26 name = "dysnomia-properties";
27 buildCommand = ''
28 cat > $out << "EOF"
29 ${printProperties cfg.properties}
30 EOF
31 '';
32 };
33
34 containersDir = pkgs.stdenv.mkDerivation {
35 name = "dysnomia-containers";
36 buildCommand = ''
37 mkdir -p $out
38 cd $out
39
40 ${lib.concatMapStrings (
41 containerName:
42 let
43 containerProperties = cfg.containers.${containerName};
44 in
45 ''
46 cat > ${containerName} <<EOF
47 ${printProperties containerProperties}
48 type=${containerName}
49 EOF
50 ''
51 ) (builtins.attrNames cfg.containers)}
52 '';
53 };
54
55 linkMutableComponents =
56 { containerName }:
57 ''
58 mkdir ${containerName}
59
60 ${lib.concatMapStrings (
61 componentName:
62 let
63 component = cfg.components.${containerName}.${componentName};
64 in
65 "ln -s ${component} ${containerName}/${componentName}\n"
66 ) (builtins.attrNames (cfg.components.${containerName} or { }))}
67 '';
68
69 componentsDir = pkgs.stdenv.mkDerivation {
70 name = "dysnomia-components";
71 buildCommand = ''
72 mkdir -p $out
73 cd $out
74
75 ${lib.concatMapStrings (containerName: linkMutableComponents { inherit containerName; }) (
76 builtins.attrNames cfg.components
77 )}
78 '';
79 };
80
81 dysnomiaFlags = {
82 enableApacheWebApplication = config.services.httpd.enable;
83 enableAxis2WebService = config.services.tomcat.axis2.enable;
84 enableDockerContainer = config.virtualisation.docker.enable;
85 enableEjabberdDump = config.services.ejabberd.enable;
86 enableMySQLDatabase = config.services.mysql.enable;
87 enablePostgreSQLDatabase = config.services.postgresql.enable;
88 enableTomcatWebApplication = config.services.tomcat.enable;
89 enableMongoDatabase = config.services.mongodb.enable;
90 enableSubversionRepository = config.services.svnserve.enable;
91 enableInfluxDatabase = config.services.influxdb.enable;
92 };
93in
94{
95 options = {
96 services.dysnomia = {
97
98 enable = lib.mkOption {
99 type = lib.types.bool;
100 default = false;
101 description = "Whether to enable Dysnomia";
102 };
103
104 enableAuthentication = lib.mkOption {
105 type = lib.types.bool;
106 default = false;
107 description = "Whether to publish privacy-sensitive authentication credentials";
108 };
109
110 package = lib.mkOption {
111 type = lib.types.path;
112 description = "The Dysnomia package";
113 };
114
115 properties = lib.mkOption {
116 description = "An attribute set in which each attribute represents a machine property. Optionally, these values can be shell substitutions.";
117 default = { };
118 type = lib.types.attrs;
119 };
120
121 containers = lib.mkOption {
122 description = "An attribute set in which each key represents a container and each value an attribute set providing its configuration properties";
123 default = { };
124 type = lib.types.attrsOf lib.types.attrs;
125 };
126
127 components = lib.mkOption {
128 description = "An attribute set in which each key represents a container and each value an attribute set in which each key represents a component and each value a derivation constructing its initial state";
129 default = { };
130 type = lib.types.attrsOf lib.types.attrs;
131 };
132
133 extraContainerProperties = lib.mkOption {
134 description = "An attribute set providing additional container settings in addition to the default properties";
135 default = { };
136 type = lib.types.attrs;
137 };
138
139 extraContainerPaths = lib.mkOption {
140 description = "A list of paths containing additional container configurations that are added to the search folders";
141 default = [ ];
142 type = lib.types.listOf lib.types.path;
143 };
144
145 extraModulePaths = lib.mkOption {
146 description = "A list of paths containing additional modules that are added to the search folders";
147 default = [ ];
148 type = lib.types.listOf lib.types.path;
149 };
150
151 enableLegacyModules = lib.mkOption {
152 type = lib.types.bool;
153 default = true;
154 description = "Whether to enable Dysnomia legacy process and wrapper modules";
155 };
156 };
157 };
158
159 imports = [
160 (lib.mkRenamedOptionModule [ "dysnomia" ] [ "services" "dysnomia" ])
161 ];
162
163 config = lib.mkIf cfg.enable {
164
165 environment.etc = {
166 "dysnomia/containers" = {
167 source = containersDir;
168 };
169 "dysnomia/components" = {
170 source = componentsDir;
171 };
172 "dysnomia/properties" = {
173 source = properties;
174 };
175 };
176
177 environment.variables = {
178 DYSNOMIA_STATEDIR = "/var/state/dysnomia-nixos";
179 DYSNOMIA_CONTAINERS_PATH = "${
180 lib.concatMapStrings (containerPath: "${containerPath}:") cfg.extraContainerPaths
181 }/etc/dysnomia/containers";
182 DYSNOMIA_MODULES_PATH = "${
183 lib.concatMapStrings (modulePath: "${modulePath}:") cfg.extraModulePaths
184 }/etc/dysnomia/modules";
185 };
186
187 environment.systemPackages = [ cfg.package ];
188
189 services.dysnomia.package = pkgs.dysnomia.override (
190 origArgs:
191 dysnomiaFlags
192 // lib.optionalAttrs (cfg.enableLegacyModules) {
193 enableLegacy = builtins.trace ''
194 WARNING: Dysnomia has been configured to use the legacy 'process' and 'wrapper'
195 modules for compatibility reasons! If you rely on these modules, consider
196 migrating to better alternatives.
197
198 More information: <https://raw.githubusercontent.com/svanderburg/dysnomia/f65a9a84827bcc4024d6b16527098b33b02e4054/README-legacy.md>
199
200 If you have migrated already or don't rely on these Dysnomia modules, you can
201 disable legacy mode with the following NixOS configuration option:
202
203 dysnomia.enableLegacyModules = false;
204
205 In a future version of Dysnomia (and NixOS) the legacy option will go away!
206 '' true;
207 }
208 );
209
210 services.dysnomia.properties = {
211 hostname = config.networking.hostName;
212 inherit (pkgs.stdenv.hostPlatform) system;
213
214 supportedTypes =
215 [
216 "echo"
217 "fileset"
218 "process"
219 "wrapper"
220
221 # These are not base modules, but they are still enabled because they work with technology that are always enabled in NixOS
222 "systemd-unit"
223 "sysvinit-script"
224 "nixos-configuration"
225 ]
226 ++ lib.optional (dysnomiaFlags.enableApacheWebApplication) "apache-webapplication"
227 ++ lib.optional (dysnomiaFlags.enableAxis2WebService) "axis2-webservice"
228 ++ lib.optional (dysnomiaFlags.enableDockerContainer) "docker-container"
229 ++ lib.optional (dysnomiaFlags.enableEjabberdDump) "ejabberd-dump"
230 ++ lib.optional (dysnomiaFlags.enableInfluxDatabase) "influx-database"
231 ++ lib.optional (dysnomiaFlags.enableMySQLDatabase) "mysql-database"
232 ++ lib.optional (dysnomiaFlags.enablePostgreSQLDatabase) "postgresql-database"
233 ++ lib.optional (dysnomiaFlags.enableTomcatWebApplication) "tomcat-webapplication"
234 ++ lib.optional (dysnomiaFlags.enableMongoDatabase) "mongo-database"
235 ++ lib.optional (dysnomiaFlags.enableSubversionRepository) "subversion-repository";
236 };
237
238 services.dysnomia.containers = lib.recursiveUpdate (
239 {
240 process = { };
241 wrapper = { };
242 }
243 // lib.optionalAttrs (config.services.httpd.enable) {
244 apache-webapplication = {
245 documentRoot = config.services.httpd.virtualHosts.localhost.documentRoot;
246 };
247 }
248 // lib.optionalAttrs (config.services.tomcat.axis2.enable) { axis2-webservice = { }; }
249 // lib.optionalAttrs (config.services.ejabberd.enable) {
250 ejabberd-dump = {
251 ejabberdUser = config.services.ejabberd.user;
252 };
253 }
254 // lib.optionalAttrs (config.services.mysql.enable) {
255 mysql-database =
256 {
257 mysqlPort = config.services.mysql.settings.mysqld.port;
258 mysqlSocket = "/run/mysqld/mysqld.sock";
259 }
260 // lib.optionalAttrs cfg.enableAuthentication {
261 mysqlUsername = "root";
262 };
263 }
264 // lib.optionalAttrs (config.services.postgresql.enable) {
265 postgresql-database =
266 {
267 }
268 // lib.optionalAttrs (cfg.enableAuthentication) {
269 postgresqlUsername = "postgres";
270 };
271 }
272 // lib.optionalAttrs (config.services.tomcat.enable) {
273 tomcat-webapplication = {
274 tomcatPort = 8080;
275 };
276 }
277 // lib.optionalAttrs (config.services.mongodb.enable) { mongo-database = { }; }
278 // lib.optionalAttrs (config.services.influxdb.enable) {
279 influx-database = {
280 influxdbUsername = config.services.influxdb.user;
281 influxdbDataDir = "${config.services.influxdb.dataDir}/data";
282 influxdbMetaDir = "${config.services.influxdb.dataDir}/meta";
283 };
284 }
285 // lib.optionalAttrs (config.services.svnserve.enable) {
286 subversion-repository = {
287 svnBaseDir = config.services.svnserve.svnBaseDir;
288 };
289 }
290 ) cfg.extraContainerProperties;
291
292 boot.extraSystemdUnitPaths = [ "/etc/systemd-mutable/system" ];
293
294 system.activationScripts.dysnomia = ''
295 mkdir -p /etc/systemd-mutable/system
296 if [ ! -f /etc/systemd-mutable/system/dysnomia.target ]
297 then
298 ( echo "[Unit]"
299 echo "Description=Services that are activated and deactivated by Dysnomia"
300 echo "After=final.target"
301 ) > /etc/systemd-mutable/system/dysnomia.target
302 fi
303 '';
304 };
305}