commit
716aac2519
@ -0,0 +1,288 @@ |
||||
<chapter xmlns="http://docbook.org/ns/docbook" |
||||
xmlns:xlink="http://www.w3.org/1999/xlink" |
||||
xml:id="users-guide-to-the-erlang-infrastructure"> |
||||
|
||||
<title>User's Guide to the Erlang Infrastructure</title> |
||||
|
||||
<section xml:id="how-to-install-erlang-packages"> |
||||
<title>How to install Erlang packages</title> |
||||
<para> |
||||
Erlang packages are not registered in the top level simply because |
||||
they are not relevant to the vast majority of Nix users. They are |
||||
installable using the <literal>erlangPackages</literal> attribute set. |
||||
|
||||
You can list the avialable packages in the |
||||
<literal>erlangPackages</literal> with the following command: |
||||
</para> |
||||
|
||||
<programlisting> |
||||
$ nix-env -f "<nixpkgs>" -qaP -A erlangPackages |
||||
erlangPackages.esqlite esqlite-0.2.1 |
||||
erlangPackages.goldrush goldrush-0.1.7 |
||||
erlangPackages.ibrowse ibrowse-4.2.2 |
||||
erlangPackages.jiffy jiffy-0.14.5 |
||||
erlangPackages.lager lager-3.0.2 |
||||
erlangPackages.meck meck-0.8.3 |
||||
erlangPackages.rebar3-pc pc-1.1.0 |
||||
</programlisting> |
||||
<para> |
||||
To install any of those packages into your profile, refer to them by |
||||
their attribute path (first column): |
||||
</para> |
||||
<programlisting> |
||||
$ nix-env -f "<nixpkgs>" -iA erlangPackages.ibrowse |
||||
</programlisting> |
||||
<para> |
||||
The attribute path of any Erlang packages corresponds to the name |
||||
of that particular package in Hex or its OTP Application/Release name. |
||||
</para> |
||||
</section> |
||||
<section xml:id="packaging-erlang-applications"> |
||||
<title>Packaging Erlang Applications</title> |
||||
<section xml:id="rebar3-packages"> |
||||
<title>Rebar3 Packages</title> |
||||
<para> |
||||
There is a Nix functional called |
||||
<literal>buildRebar3</literal>. We use this function to make a |
||||
derivation that understands how to build the rebar3 project. For |
||||
example, the epression we use to build the <link |
||||
xlink:href="https://github.com/erlang-nix/hex2nix">hex2nix</link> |
||||
project follows. |
||||
</para> |
||||
<programlisting> |
||||
{stdenv, fetchFromGitHub, buildRebar3, ibrowse, jsx, erlware_commons }: |
||||
|
||||
buildRebar3 rec { |
||||
name = "hex2nix"; |
||||
version = "0.0.1"; |
||||
|
||||
src = fetchFromGitHub { |
||||
owner = "ericbmerritt"; |
||||
repo = "hex2nix"; |
||||
rev = "${version}"; |
||||
sha256 = "1w7xjidz1l5yjmhlplfx7kphmnpvqm67w99hd2m7kdixwdxq0zqg"; |
||||
}; |
||||
|
||||
erlangDeps = [ ibrowse jsx erlware_commons ]; |
||||
} |
||||
</programlisting> |
||||
<para> |
||||
The only visible difference between this derivation and |
||||
something like <literal>stdenv.mkDerivation</literal> is that we |
||||
have added <literal>erlangDeps</literal> to the derivation. If |
||||
you add your Erlang dependencies here they will be correctly |
||||
handled by the system. |
||||
</para> |
||||
<para> |
||||
If your package needs to compile native code via Rebar's port |
||||
compilation mechenism. You should add <literal>compilePort = |
||||
true;</literal> to the derivation. |
||||
</para> |
||||
</section> |
||||
|
||||
<section xml:id="hex-packages"> |
||||
<title>Hex Packages</title> |
||||
<para> |
||||
Hex packages are based on Rebar packages. In fact, at the moment |
||||
we can only compile Hex packages that are buildable with |
||||
Rebar3. Packages that use Mix and other build systems are not |
||||
supported. That being said, we know a lot more about Hex and can |
||||
do more for you. |
||||
</para> |
||||
<programlisting> |
||||
{ buildHex }: |
||||
buildHex { |
||||
name = "esqlite"; |
||||
version = "0.2.1"; |
||||
sha256 = "1296fn1lz4lz4zqzn4dwc3flgkh0i6n4sydg501faabfbv8d3wkr"; |
||||
compilePort = true; |
||||
} |
||||
</programlisting> |
||||
<para> |
||||
For Hex packages you need to provide the name, the version, and |
||||
the Sha 256 digest of the package and use |
||||
<literal>buildHex</literal> to build it. Obviously, the package |
||||
needs to have already been published to Hex. |
||||
</para> |
||||
</section> |
||||
</section> |
||||
<section xml:id="how-to-develop"> |
||||
<title>How to develop</title> |
||||
<section xml:id="accessing-an-environment"> |
||||
<title>Accessing an Environment</title> |
||||
<para> |
||||
Often, all you want to do is be able to access a valid |
||||
environment that contains a specific package and its |
||||
dependencies. we can do that with the <literal>env</literal> |
||||
part of a derivation. For example, lets say we want to access an |
||||
erlang repl with ibrowse loaded up. We could do the following. |
||||
</para> |
||||
<programlisting> |
||||
~/w/nixpkgs ❯❯❯ nix-shell -A erlangPackages.ibrowse.env --run "erl" |
||||
Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] |
||||
|
||||
Eshell V7.0 (abort with ^G) |
||||
1> m(ibrowse). |
||||
Module: ibrowse |
||||
MD5: 3b3e0137d0cbb28070146978a3392945 |
||||
Compiled: January 10 2016, 23:34 |
||||
Object file: /nix/store/g1rlf65rdgjs4abbyj4grp37ry7ywivj-ibrowse-4.2.2/lib/erlang/lib/ibrowse-4.2.2/ebin/ibrowse.beam |
||||
Compiler options: [{outdir,"/tmp/nix-build-ibrowse-4.2.2.drv-0/hex-source-ibrowse-4.2.2/_build/default/lib/ibrowse/ebin"}, |
||||
debug_info,debug_info,nowarn_shadow_vars, |
||||
warn_unused_import,warn_unused_vars,warnings_as_errors, |
||||
{i,"/tmp/nix-build-ibrowse-4.2.2.drv-0/hex-source-ibrowse-4.2.2/_build/default/lib/ibrowse/include"}] |
||||
Exports: |
||||
add_config/1 send_req_direct/7 |
||||
all_trace_off/0 set_dest/3 |
||||
code_change/3 set_max_attempts/3 |
||||
get_config_value/1 set_max_pipeline_size/3 |
||||
get_config_value/2 set_max_sessions/3 |
||||
get_metrics/0 show_dest_status/0 |
||||
get_metrics/2 show_dest_status/1 |
||||
handle_call/3 show_dest_status/2 |
||||
handle_cast/2 spawn_link_worker_process/1 |
||||
handle_info/2 spawn_link_worker_process/2 |
||||
init/1 spawn_worker_process/1 |
||||
module_info/0 spawn_worker_process/2 |
||||
module_info/1 start/0 |
||||
rescan_config/0 start_link/0 |
||||
rescan_config/1 stop/0 |
||||
send_req/3 stop_worker_process/1 |
||||
send_req/4 stream_close/1 |
||||
send_req/5 stream_next/1 |
||||
send_req/6 terminate/2 |
||||
send_req_direct/4 trace_off/0 |
||||
send_req_direct/5 trace_off/2 |
||||
send_req_direct/6 trace_on/0 |
||||
trace_on/2 |
||||
ok |
||||
2> |
||||
</programlisting> |
||||
<para> |
||||
Notice the <literal>-A erlangPackages.ibrowse.env</literal>.That |
||||
is the key to this functionality. |
||||
</para> |
||||
</section> |
||||
<section xml:id="creating-a-shell"> |
||||
<title>Creating a Shell</title> |
||||
<para> |
||||
Getting access to an environment often isn't enough to do real |
||||
development. Many times we need to create a |
||||
<literal>shell.nix</literal> file and do our development inside |
||||
of the environment specified by that file. This file looks a lot |
||||
like the packageing described above. The main difference is that |
||||
<literal>src</literal> points to project root and we call the |
||||
package directly. |
||||
</para> |
||||
<programlisting> |
||||
{ pkgs ? import "<nixpkgs"> {} }: |
||||
|
||||
with pkgs; |
||||
|
||||
let |
||||
|
||||
f = { buildHex, ibrowse, jsx, erlware_commons }: |
||||
buildHex { |
||||
name = "hex2nix"; |
||||
version = "0.1.0"; |
||||
src = ./.; |
||||
erlangDeps = [ ibrowse jsx erlware_commons ]; |
||||
}; |
||||
drv = erlangPackages.callPackage f {}; |
||||
|
||||
in |
||||
drv |
||||
</programlisting> |
||||
<section xml:id="building-in-a-shell"> |
||||
<title>Building in a shell</title> |
||||
<para> |
||||
Unfortunatly for us users of Nix, Rebar isn't very cooperative |
||||
with us from the standpoint of building a hermetic |
||||
environment. When building the rebar3 support we had to do some |
||||
sneaky things to get it not to go out and pull packages on its |
||||
own. Also unfortunately, you have to do some of the same things |
||||
when building a project inside of a Nix shell. |
||||
|
||||
<orderedlist numeration="arabic"> |
||||
<listitem> |
||||
<para>Run <literal>rebar3-nix-bootstrap</literal> every time |
||||
dependencies change</para> |
||||
</listitem> |
||||
<listitem> |
||||
<para>Set Home to the current directory.</para> |
||||
</listitem> |
||||
</orderedlist> |
||||
|
||||
If you do these two things then Rebar will be happy with you. I |
||||
codify these into a makefile. Forunately, rebar3-nix-bootstrap |
||||
is idempotent and fairly quick. so you can run it as often as |
||||
you like. |
||||
</para> |
||||
<programlisting> |
||||
# ============================================================================= |
||||
# Rules |
||||
# ============================================================================= |
||||
.PHONY= all test clean repl shell build test analyze bootstrap |
||||
|
||||
all: test |
||||
|
||||
clean: |
||||
rm -rf _build |
||||
rm -rf .cache |
||||
|
||||
repl: |
||||
nix-shell --run "erl" |
||||
|
||||
shell: |
||||
nix-shell --run "bash" |
||||
|
||||
bootstrap: |
||||
nix-shell --pure --run "rebar3-nix-bootstrap" |
||||
|
||||
build: bootstrap |
||||
nix-shell --pure --run "HOME=$(CURDIR) rebar3 compile" |
||||
|
||||
analyze: bootstrap |
||||
nix-shell --pure --run "HOME=$(CURDIR) rebar3 do compile,dialyzer" |
||||
|
||||
test: bootstrap |
||||
nix-shell --pure --run "HOME=$(CURDIR) rebar3 do compile,dialyzer,eunit" |
||||
|
||||
</programlisting> |
||||
<para> |
||||
If you add the <literal>shell.nix</literal> as described and |
||||
user rebar as follows things should simply work. |
||||
</para> |
||||
</section> |
||||
</section> |
||||
</section> |
||||
<section xml:id="generating-packages-from-hex-with-hex2nix"> |
||||
<title>Generating Packages from Hex with Hex2Nix</title> |
||||
<para> |
||||
Updating the Hex packages requires the use of the |
||||
<literal>hex2nix</literal> tool. Given the path to the Erlang |
||||
modules (usually |
||||
<literal>pkgs/development/erlang-modules</literal>). It will |
||||
happily dump a file called |
||||
<literal>hex-packages.nix</literal>. That file will contain all |
||||
the packages that use a recognized build system in Hex. However, |
||||
it can't know whether or not all those packages are buildable. |
||||
</para> |
||||
<para> |
||||
To make life easier for our users, it makes good sense to go |
||||
ahead and attempt to build all those packages and remove the |
||||
ones that don't build. To do that, simply run the command (in |
||||
the root of your <literal>nixpkgs</literal> repository). that follows. |
||||
</para> |
||||
<programlisting> |
||||
$ nix-build -A erlangPackages |
||||
</programlisting> |
||||
<para> |
||||
That will build every package in |
||||
<literal>erlangPackages</literal>. Then you can go through and |
||||
manually remove the ones that fail. Hopefully, someone will |
||||
improve <literal>hex2nix</literal> in the future to automate |
||||
that. |
||||
</para> |
||||
</section> |
||||
</chapter> |
@ -1,15 +0,0 @@ |
||||
{pkgs, config, ...}: |
||||
|
||||
let |
||||
wis_go7007 = config.boot.kernelPackages.wis_go7007; |
||||
in |
||||
|
||||
{ |
||||
boot.extraModulePackages = [ wis_go7007 ]; |
||||
|
||||
environment.systemPackages = [ wis_go7007 ]; |
||||
|
||||
hardware.firmware = [ wis_go7007 ]; |
||||
|
||||
services.udev.packages = [ wis_go7007 ]; |
||||
} |
@ -0,0 +1,114 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
cfge = config.environment; |
||||
|
||||
cfg = config.programs.fish; |
||||
|
||||
fishAliases = concatStringsSep "\n" ( |
||||
mapAttrsFlatten (k: v: "alias ${k} '${v}'") cfg.shellAliases |
||||
); |
||||
|
||||
in |
||||
|
||||
{ |
||||
|
||||
options = { |
||||
|
||||
programs.fish = { |
||||
|
||||
enable = mkOption { |
||||
default = false; |
||||
description = '' |
||||
Whether to configure fish as an interactive shell. |
||||
''; |
||||
type = types.bool; |
||||
}; |
||||
|
||||
shellAliases = mkOption { |
||||
default = config.environment.shellAliases; |
||||
description = '' |
||||
Set of aliases for fish shell. See <option>environment.shellAliases</option> |
||||
for an option format description. |
||||
''; |
||||
type = types.attrs; |
||||
}; |
||||
|
||||
shellInit = mkOption { |
||||
default = ""; |
||||
description = '' |
||||
Shell script code called during fish shell initialisation. |
||||
''; |
||||
type = types.lines; |
||||
}; |
||||
|
||||
loginShellInit = mkOption { |
||||
default = ""; |
||||
description = '' |
||||
Shell script code called during fish login shell initialisation. |
||||
''; |
||||
type = types.lines; |
||||
}; |
||||
|
||||
interactiveShellInit = mkOption { |
||||
default = ""; |
||||
description = '' |
||||
Shell script code called during interactive fish shell initialisation. |
||||
''; |
||||
type = types.lines; |
||||
}; |
||||
|
||||
promptInit = mkOption { |
||||
default = ""; |
||||
description = '' |
||||
Shell script code used to initialise fish prompt. |
||||
''; |
||||
type = types.lines; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
environment.etc."fish/foreign-env/shellInit".text = cfge.shellInit; |
||||
environment.etc."fish/foreign-env/loginShellInit".text = cfge.loginShellInit; |
||||
environment.etc."fish/foreign-env/interactiveShellInit".text = cfge.interactiveShellInit; |
||||
|
||||
environment.etc."fish/config.fish".text = '' |
||||
# /etc/fish/config.fish: DO NOT EDIT -- this file has been generated automatically. |
||||
|
||||
set fish_function_path $fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions |
||||
|
||||
fenv source ${config.system.build.setEnvironment} 1> /dev/null |
||||
fenv source /etc/fish/foreign-env/shellInit 1> /dev/null |
||||
|
||||
${cfg.shellInit} |
||||
|
||||
if builtin status --is-login |
||||
fenv source /etc/fish/foreign-env/loginShellInit 1> /dev/null |
||||
${cfg.loginShellInit} |
||||
end |
||||
|
||||
if builtin status --is-interactive |
||||
${fishAliases} |
||||
fenv source /etc/fish/foreign-env/interactiveShellInit 1> /dev/null |
||||
${cfg.interactiveShellInit} |
||||
end |
||||
''; |
||||
|
||||
environment.systemPackages = [ pkgs.fish ]; |
||||
|
||||
environment.shells = [ |
||||
"/run/current-system/sw/bin/fish" |
||||
"/var/run/current-system/sw/bin/fish" |
||||
"${pkgs.fish}/bin/fish" |
||||
]; |
||||
|
||||
}; |
||||
|
||||
} |
@ -0,0 +1,109 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.security.audit; |
||||
|
||||
failureModes = { |
||||
silent = 0; |
||||
printk = 1; |
||||
panic = 2; |
||||
}; |
||||
|
||||
# TODO: it seems like people like their rules to be somewhat secret, yet they will not be if |
||||
# put in the store like this. At the same time, it doesn't feel like a huge deal and working |
||||
# around that is a pain so I'm leaving it like this for now. |
||||
startScript = pkgs.writeScript "audit-start" '' |
||||
#!${pkgs.stdenv.shell} -eu |
||||
# Clear out any rules we may start with |
||||
auditctl -D |
||||
|
||||
# Put the rules in a temporary file owned and only readable by root |
||||
rulesfile="$(mktemp)" |
||||
${concatMapStrings (x: "echo '${x}' >> $rulesfile\n") cfg.rules} |
||||
|
||||
# Apply the requested rules |
||||
auditctl -R "$rulesfile" |
||||
|
||||
# Enable and configure auditing |
||||
auditctl \ |
||||
-e ${if cfg.enable == "lock" then "2" else "1"} \ |
||||
-b ${toString cfg.backlogLimit} \ |
||||
-f ${toString failureModes.${cfg.failureMode}} \ |
||||
-r ${toString cfg.rateLimit} |
||||
''; |
||||
|
||||
stopScript = pkgs.writeScript "audit-stop" '' |
||||
#!${pkgs.stdenv.shell} -eu |
||||
# Clear the rules |
||||
auditctl -D |
||||
|
||||
# Disable auditing |
||||
auditctl -e 0 |
||||
''; |
||||
in { |
||||
options = { |
||||
security.audit = { |
||||
enable = mkOption { |
||||
type = types.enum [ false true "lock" ]; |
||||
default = true; # The kernel seems to enable it by default with no rules anyway |
||||
description = '' |
||||
Whether to enable the Linux audit system. The special `lock' value can be used to |
||||
enable auditing and prevent disabling it until a restart. Be careful about locking |
||||
this, as it will prevent you from changing your audit configuration until you |
||||
restart. If possible, test your configuration using build-vm beforehand. |
||||
''; |
||||
}; |
||||
|
||||
failureMode = mkOption { |
||||
type = types.enum [ "silent" "printk" "panic" ]; |
||||
default = "printk"; |
||||
description = "How to handle critical errors in the auditing system"; |
||||
}; |
||||
|
||||
backlogLimit = mkOption { |
||||
type = types.int; |
||||
default = 64; # Apparently the kernel default |
||||
description = '' |
||||
The maximum number of outstanding audit buffers allowed; exceeding this is |
||||
considered a failure and handled in a manner specified by failureMode. |
||||
''; |
||||
}; |
||||
|
||||
rateLimit = mkOption { |
||||
type = types.int; |
||||
default = 0; |
||||
description = '' |
||||
The maximum messages per second permitted before triggering a failure as |
||||
specified by failureMode. Setting it to zero disables the limit. |
||||
''; |
||||
}; |
||||
|
||||
rules = mkOption { |
||||
type = types.listOf types.str; # (types.either types.str (types.submodule rule)); |
||||
default = []; |
||||
example = [ "-a exit,always -F arch=b64 -S execve" ]; |
||||
description = '' |
||||
The ordered audit rules, with each string appearing as one line of the audit.rules file. |
||||
''; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf (cfg.enable == "lock" || cfg.enable) { |
||||
systemd.services.audit = { |
||||
description = "pseudo-service representing the kernel audit state"; |
||||
wantedBy = [ "basic.target" ]; |
||||
|
||||
path = [ pkgs.audit ]; |
||||
|
||||
serviceConfig = { |
||||
Type = "oneshot"; |
||||
RemainAfterExit = true; |
||||
ExecStart = "@${startScript} audit-start"; |
||||
ExecStop = "@${stopScript} audit-stop"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -1,115 +0,0 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
let |
||||
cfg = config.services.fuppesd; |
||||
in |
||||
|
||||
with lib; |
||||
|
||||
{ |
||||
options = { |
||||
services.fuppesd = { |
||||
enable = mkOption { |
||||
default = false; |
||||
type = with types; bool; |
||||
description = '' |
||||
Enables Fuppes (UPnP A/V Media Server). Can be used to watch |
||||
photos, video and listen to music from a phone/tv connected to the |
||||
local network. |
||||
''; |
||||
}; |
||||
|
||||
name = mkOption { |
||||
example = "Media Center"; |
||||
type = types.str; |
||||
description = '' |
||||
Enables Fuppes (UPnP A/V Media Server). Can be used to watch |
||||
photos, video and listen to music from a phone/tv connected to the |
||||
local network. |
||||
''; |
||||
}; |
||||
|
||||
log = { |
||||
level = mkOption { |
||||
default = 0; |
||||
example = 3; |
||||
type = with types; uniq int; |
||||
description = '' |
||||
Logging level of fuppes, An integer between 0 and 3. |
||||
''; |
||||
}; |
||||
|
||||
file = mkOption { |
||||
default = "/var/log/fuppes.log"; |
||||
type = types.str; |
||||
description = '' |
||||
File which will contains the log produced by the daemon. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
config = mkOption { |
||||
example = "/etc/fuppes/fuppes.cfg"; |
||||
type = types.str; |
||||
description = '' |
||||
Mutable configuration file which can be edited with the web |
||||
interface. Due to possible modification, double quote the full |
||||
path of the filename stored in your filesystem to avoid attempts |
||||
to modify the content of the nix store. |
||||
''; |
||||
}; |
||||
|
||||
vfolder = mkOption { |
||||
example = literalExample "/etc/fuppes/vfolder.cfg"; |
||||
description = '' |
||||
XML file describing the layout of virtual folder visible by the |
||||
client. |
||||
''; |
||||
}; |
||||
|
||||
database = mkOption { |
||||
default = "/var/lib/fuppes/fuppes.db"; |
||||
type = types.str; |
||||
description = '' |
||||
Database file which index all shared files. |
||||
''; |
||||
}; |
||||
|
||||
## At the moment, no plugins are packaged. |
||||
/* |
||||
plugins = mkOption { |
||||
type = with types; listOf package; |
||||
description = '' |
||||
List of Fuppes plugins. |
||||
''; |
||||
}; |
||||
*/ |
||||
|
||||
user = mkOption { |
||||
default = "root"; # The default is not secure. |
||||
example = "fuppes"; |
||||
type = types.str; |
||||
description = '' |
||||
Name of the user which own the configuration files and under which |
||||
the fuppes daemon will be executed. |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
jobs.fuppesd = { |
||||
description = "UPnP A/V Media Server. (${cfg.name})"; |
||||
startOn = "ip-up"; |
||||
daemonType = "fork"; |
||||
exec = ''/var/setuid-wrappers/sudo -u ${cfg.user} -- ${pkgs.fuppes}/bin/fuppesd --friendly-name ${cfg.name} --log-level ${toString cfg.log.level} --log-file ${cfg.log.file} --config-file ${cfg.config} --vfolder-config-file ${cfg.vfolder} --database-file ${cfg.database}''; |
||||
}; |
||||
|
||||
services.fuppesd.name = mkDefault config.networking.hostName; |
||||
|
||||
services.fuppesd.vfolder = mkDefault ./fuppes/vfolder.cfg; |
||||
|
||||
security.sudo.enable = true; |
||||
}; |
||||
} |
@ -1,155 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<fuppes_vfolder_config version="0.2"> |
||||
|
||||
<vfolder_layout device="default" enabled="false"> |
||||
|
||||
<vfolder name="Genre"> |
||||
<vfolders property="genre"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Genre/Artists"> |
||||
<vfolders property="genre"> |
||||
<vfolders property="artist"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Artists/Albums"> |
||||
<vfolders property="artist"> |
||||
<vfolders property="album"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="ABC/Artists/Albums"> |
||||
<vfolders split="ABC"> |
||||
<vfolders property="artist"> |
||||
<vfolders property="album"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolders> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Photos"> |
||||
<vfolder name="All"> |
||||
<items type="imageItem" /> |
||||
</vfolder> |
||||
<vfolder name="Folders"> |
||||
<folders filter="contains(imageItem)" /> |
||||
</vfolder> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Videos"> |
||||
<vfolder name="All"> |
||||
<items type="videoItem" /> |
||||
</vfolder> |
||||
<vfolder name="Folders"> |
||||
<folders filter="contains(videoItem)" /> |
||||
</vfolder> |
||||
</vfolder> |
||||
|
||||
<vfolder name="shared dirs"> |
||||
<shared_dirs full_extend="true" /> |
||||
</vfolder> |
||||
|
||||
</vfolder_layout> |
||||
|
||||
<vfolder_layout device="Xbox 360" enabled="false"> |
||||
|
||||
<vfolder name="Music" id="1"> |
||||
<vfolder name="Album" id="7"> |
||||
<vfolders property="album"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="All Music" id="4"> |
||||
<items type="audioItem" /> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Artist" id="6"> |
||||
<vfolders property="artist"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Folders" id="20"> |
||||
<folders filter="contains(audioItem)" /> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Genre" id="5"> |
||||
<vfolders property="genre"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Playlist" id="15" /> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Pictures" id="3"> |
||||
<vfolder name="Album" id="13" /> |
||||
|
||||
<vfolder name="All Pictures" id="11"> |
||||
<items type="imageItem" /> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Date Taken" id="12" /> |
||||
|
||||
<vfolder name="Folders" id="22"> |
||||
<folders filter="contains(imageItem)" /> |
||||
</vfolder> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Playlists" id="18"> |
||||
<vfolder name="All Playlists" id="19" /> |
||||
<vfolder name="Folders" id="23" /> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Video" id="2"> |
||||
<vfolder name="Actor" id="10" /> |
||||
<vfolder name="Album" id="14" /> |
||||
<vfolder name="All Video" id="8"> |
||||
<items type="videoItem" /> |
||||
</vfolder> |
||||
<vfolder name="Folders" id="21"> |
||||
<folders filter="contains(videoItem)" /> |
||||
</vfolder> |
||||
<vfolder name="Genre" id="9" /> |
||||
</vfolder> |
||||
|
||||
</vfolder_layout> |
||||
|
||||
<vfolder_layout device="Yamaha" enabled="false" create_references="true" > |
||||
|
||||
<vfolder name="Playlists" /> |
||||
|
||||
<vfolder name="Artists"> |
||||
<vfolders property="artist"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Albums"> |
||||
<vfolders property="album"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Songs"> |
||||
<items type="audioItem" /> |
||||
</vfolder> |
||||
|
||||
<vfolder name="Genres"> |
||||
<vfolders property="genre"> |
||||
<items type="audioItem" /> |
||||
</vfolders> |
||||
</vfolder> |
||||
|
||||
</vfolder_layout> |
||||
|
||||
</fuppes_vfolder_config> |
@ -0,0 +1,30 @@ |
||||
# |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
cfg = config.services.irqbalance; |
||||
|
||||
in |
||||
{ |
||||
options.services.irqbalance.enable = mkEnableOption "irqbalance daemon"; |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
systemd.services = { |
||||
irqbalance = { |
||||
description = "irqbalance daemon"; |
||||
path = [ pkgs.irqbalance ]; |
||||
serviceConfig = |
||||
{ ExecStart = "${pkgs.irqbalance}/bin/irqbalance --foreground"; }; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
}; |
||||
}; |
||||
|
||||
environment.systemPackages = [ pkgs.irqbalance ]; |
||||
|
||||
}; |
||||
|
||||
} |
@ -0,0 +1,147 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
cfg = config.services.dspam; |
||||
|
||||
dspam = pkgs.dspam; |
||||
|
||||
defaultSock = "/run/dspam/dspam.sock"; |
||||
|
||||
cfgfile = pkgs.writeText "dspam.conf" '' |
||||
Home /var/lib/dspam |
||||
StorageDriver ${dspam}/lib/dspam/lib${cfg.storageDriver}_drv.so |
||||
|
||||
Trust root |
||||
Trust ${cfg.user} |
||||
SystemLog on |
||||
UserLog on |
||||
|
||||
${optionalString (cfg.domainSocket != null) ''ServerDomainSocketPath "${cfg.domainSocket}"''} |
||||
|
||||
${cfg.extraConfig} |
||||
''; |
||||
|
||||
in { |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.dspam = { |
||||
|
||||
enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = "Whether to enable the dspam spam filter."; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.str; |
||||
default = "dspam"; |
||||
description = "User for the dspam daemon."; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.str; |
||||
default = "dspam"; |
||||
description = "Group for the dspam daemon."; |
||||
}; |
||||
|
||||
storageDriver = mkOption { |
||||
type = types.str; |
||||
default = "hash"; |
||||
description = "Storage driver backend to use for dspam."; |
||||
}; |
||||
|
||||
domainSocket = mkOption { |
||||
type = types.nullOr types.path; |
||||
default = defaultSock; |
||||
description = "Path to local domain socket which is used for communication with the daemon. Set to null to disable UNIX socket."; |
||||
}; |
||||
|
||||
extraConfig = mkOption { |
||||
type = types.lines; |
||||
default = ""; |
||||
description = "Additional dspam configuration."; |
||||
}; |
||||
|
||||
maintenanceInterval = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
description = "If set, maintenance script will be run at specified (in systemd.timer format) interval"; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable (mkMerge [ |
||||
{ |
||||
users.extraUsers = optionalAttrs (cfg.user == "dspam") (singleton |
||||
{ name = "dspam"; |
||||
group = cfg.group; |
||||
uid = config.ids.uids.dspam; |
||||
}); |
||||
|
||||
users.extraGroups = optionalAttrs (cfg.group == "dspam") (singleton |
||||
{ name = "dspam"; |
||||
gid = config.ids.gids.dspam; |
||||
}); |
||||
|
||||
environment.systemPackages = [ dspam ]; |
||||
|
||||
environment.etc."dspam/dspam.conf".source = cfgfile; |
||||
|
||||
systemd.services.dspam = { |
||||
description = "dspam spam filtering daemon"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
restartTriggers = [ cfgfile ]; |
||||
|
||||
serviceConfig = { |
||||
ExecStart = "${dspam}/bin/dspam --daemon --nofork"; |
||||
User = cfg.user; |
||||
Group = cfg.group; |
||||
RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam"; |
||||
PermissionsStartOnly = true; |
||||
}; |
||||
|
||||
preStart = '' |
||||
mkdir -m750 -p /var/lib/dspam |
||||
chown -R "${cfg.user}:${cfg.group}" /var/lib/dspam |
||||
|
||||
mkdir -m750 -p /var/log/dspam |
||||
chown -R "${cfg.user}:${cfg.group}" /var/log/dspam |
||||
''; |
||||
}; |
||||
} |
||||
|
||||
(mkIf (cfg.maintenanceInterval != null) { |
||||
systemd.timers.dspam-maintenance = { |
||||
description = "Timer for dspam maintenance script"; |
||||
wantedBy = [ "timers.target" ]; |
||||
timerConfig = { |
||||
OnCalendar = cfg.maintenanceInterval; |
||||
Unit = "dspam-maintenance.service"; |
||||
}; |
||||
}; |
||||
|
||||
systemd.services.dspam-maintenance = { |
||||
description = "dspam maintenance script"; |
||||
restartTriggers = [ cfgfile ]; |
||||
|
||||
serviceConfig = { |
||||
ExecStart = "${dspam}/bin/dspam_maintenance"; |
||||
Type = "oneshot"; |
||||
User = cfg.user; |
||||
Group = cfg.group; |
||||
}; |
||||
}; |
||||
}) |
||||
]); |
||||
} |
@ -0,0 +1,109 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
cfg = config.services.opendkim; |
||||
|
||||
defaultSock = "local:/run/opendkim/opendkim.sock"; |
||||
|
||||
args = [ "-f" "-l" |
||||
"-p" cfg.socket |
||||
"-d" cfg.domains |
||||
"-k" cfg.keyFile |
||||
"-s" cfg.selector |
||||
] ++ optionals (cfg.configFile != null) [ "-x" cfg.configFile ]; |
||||
|
||||
in { |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.opendkim = { |
||||
|
||||
enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = "Whether to enable the OpenDKIM sender authentication system."; |
||||
}; |
||||
|
||||
socket = mkOption { |
||||
type = types.str; |
||||
default = defaultSock; |
||||
description = "Socket which is used for communication with OpenDKIM."; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.str; |
||||
default = "opendkim"; |
||||
description = "User for the daemon."; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.str; |
||||
default = "opendkim"; |
||||
description = "Group for the daemon."; |
||||
}; |
||||
|
||||
domains = mkOption { |
||||
type = types.str; |
||||
description = "Local domains set; messages from them are signed, not verified."; |
||||
}; |
||||
|
||||
keyFile = mkOption { |
||||
type = types.path; |
||||
description = "Secret key file used for signing messages."; |
||||
}; |
||||
|
||||
selector = mkOption { |
||||
type = types.str; |
||||
description = "Selector to use when signing."; |
||||
}; |
||||
|
||||
configFile = mkOption { |
||||
type = types.nullOr types.path; |
||||
default = null; |
||||
description = "Additional opendkim configuration."; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
services.opendkim.domains = mkDefault "csl:${config.networking.hostName}"; |
||||
|
||||
users.extraUsers = optionalAttrs (cfg.user == "opendkim") (singleton |
||||
{ name = "opendkim"; |
||||
group = cfg.group; |
||||
uid = config.ids.uids.opendkim; |
||||
}); |
||||
|
||||
users.extraGroups = optionalAttrs (cfg.group == "opendkim") (singleton |
||||
{ name = "opendkim"; |
||||
gid = config.ids.gids.opendkim; |
||||
}); |
||||
|
||||
environment.systemPackages = [ pkgs.opendkim ]; |
||||
|
||||
systemd.services.opendkim = { |
||||
description = "OpenDKIM signing and verification daemon"; |
||||
after = [ "network.target" ]; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
|
||||
serviceConfig = { |
||||
ExecStart = "${pkgs.opendkim}/bin/opendkim ${concatMapStringsSep " " escapeShellArg args}"; |
||||
User = cfg.user; |
||||
Group = cfg.group; |
||||
RuntimeDirectory = optional (cfg.socket == defaultSock) "opendkim"; |
||||
}; |
||||
}; |
||||
|
||||
}; |
||||
} |
@ -0,0 +1,107 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
cfg = config.services.postsrsd; |
||||
|
||||
in { |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.postsrsd = { |
||||
|
||||
enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = "Whether to enable the postsrsd SRS server for Postfix."; |
||||
}; |
||||
|
||||
domain = mkOption { |
||||
type = types.str; |
||||
description = "Domain name for rewrite"; |
||||
}; |
||||
|
||||
secretsFile = mkOption { |
||||
type = types.path; |
||||
default = "/var/lib/postsrsd/postsrsd.secret"; |
||||
description = "Secret keys used for signing and verification"; |
||||
}; |
||||
|
||||
forwardPort = mkOption { |
||||
type = types.int; |
||||
default = 10001; |
||||
description = "Port for the forward SRS lookup"; |
||||
}; |
||||
|
||||
reversePort = mkOption { |
||||
type = types.int; |
||||
default = 10002; |
||||
description = "Port for the reverse SRS lookup"; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.str; |
||||
default = "postsrsd"; |
||||
description = "User for the daemon"; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.str; |
||||
default = "postsrsd"; |
||||
description = "Group for the daemon"; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
services.postsrsd.domain = mkDefault config.networking.hostName; |
||||
|
||||
users.extraUsers = optionalAttrs (cfg.user == "postsrsd") (singleton |
||||
{ name = "postsrsd"; |
||||
group = cfg.group; |
||||
uid = config.ids.uids.postsrsd; |
||||
}); |
||||
|
||||
users.extraGroups = optionalAttrs (cfg.group == "postsrsd") (singleton |
||||
{ name = "postsrsd"; |
||||
gid = config.ids.gids.postsrsd; |
||||
}); |
||||
|
||||
systemd.services.postsrsd = { |
||||
description = "PostSRSd SRS rewriting server"; |
||||
after = [ "network.target" ]; |
||||
before = [ "postfix.service" ]; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
|
||||
path = [ pkgs.coreutils ]; |
||||
|
||||
serviceConfig = { |
||||
ExecStart = ''${pkgs.postsrsd}/sbin/postsrsd "-s${cfg.secretsFile}" "-d${cfg.domain}" -f${toString cfg.forwardPort} -r${toString cfg.reversePort}''; |
||||
User = cfg.user; |
||||
Group = cfg.group; |
||||
PermissionsStartOnly = true; |
||||
}; |
||||
|
||||
preStart = '' |
||||
if [ ! -e "${cfg.secretsFile}" ]; then |
||||
echo "WARNING: secrets file not found, autogenerating!" |
||||
mkdir -p -m750 "$(dirname "${cfg.secretsFile}")" |
||||
dd if=/dev/random bs=18 count=1 | base64 > "${cfg.secretsFile}" |
||||
chmod 600 "${cfg.secretsFile}" |
||||
fi |
||||
chown "${cfg.user}:${cfg.group}" "${cfg.secretsFile}" |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
} |
@ -0,0 +1,189 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
rspamdCfg = config.services.rspamd; |
||||
cfg = config.services.rmilter; |
||||
|
||||
rmilterConf = '' |
||||
pidfile = /run/rmilter/rmilter.pid; |
||||
bind_socket = ${cfg.bindSocket}; |
||||
tempdir = /tmp; |
||||
|
||||
'' + (with cfg.rspamd; if enable then '' |
||||
spamd { |
||||
servers = ${concatStringsSep ", " servers}; |
||||
connect_timeout = 1s; |
||||
results_timeout = 20s; |
||||
error_time = 10; |
||||
dead_time = 300; |
||||
maxerrors = 10; |
||||
reject_message = "${rejectMessage}"; |
||||
${optionalString (length whitelist != 0) "whitelist = ${concatStringsSep ", " whitelist};"} |
||||
|
||||
# rspamd_metric - metric for using with rspamd |
||||
# Default: "default" |
||||
rspamd_metric = "default"; |
||||
${extraConfig} |
||||
}; |
||||
'' else "") + cfg.extraConfig; |
||||
|
||||
rmilterConfigFile = pkgs.writeText "rmilter.conf" rmilterConf; |
||||
|
||||
in |
||||
|
||||
{ |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.rmilter = { |
||||
|
||||
enable = mkOption { |
||||
default = cfg.rspamd.enable; |
||||
description = "Whether to run the rmilter daemon."; |
||||
}; |
||||
|
||||
debug = mkOption { |
||||
default = false; |
||||
description = "Whether to run the rmilter daemon in debug mode."; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.string; |
||||
default = "rmilter"; |
||||
description = '' |
||||
User to use when no root privileges are required. |
||||
''; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.string; |
||||
default = "rmilter"; |
||||
description = '' |
||||
Group to use when no root privileges are required. |
||||
''; |
||||
}; |
||||
|
||||
bindSocket = mkOption { |
||||
type = types.string; |
||||
default = "unix:/run/rmilter/rmilter.sock"; |
||||
description = "Socket to listed for MTA requests"; |
||||
example = '' |
||||
"unix:/run/rmilter/rmilter.sock" or |
||||
"inet:11990@127.0.0.1" |
||||
''; |
||||
}; |
||||
|
||||
rspamd = { |
||||
enable = mkOption { |
||||
default = rspamdCfg.enable; |
||||
description = "Whether to use rspamd to filter mails"; |
||||
}; |
||||
|
||||
servers = mkOption { |
||||
type = types.listOf types.str; |
||||
default = ["r:0.0.0.0:11333"]; |
||||
description = '' |
||||
Spamd socket definitions. |
||||
Is server name is prefixed with r: it is rspamd server. |
||||
''; |
||||
}; |
||||
|
||||
whitelist = mkOption { |
||||
type = types.listOf types.str; |
||||
default = [ ]; |
||||
description = "list of ips or nets that should be not checked with spamd"; |
||||
}; |
||||
|
||||
rejectMessage = mkOption { |
||||
type = types.str; |
||||
default = "Spam message rejected; If this is not spam contact abuse"; |
||||
description = "reject message for spam"; |
||||
}; |
||||
|
||||
extraConfig = mkOption { |
||||
type = types.lines; |
||||
default = ""; |
||||
description = "Custom snippet to append to end of `spamd' section"; |
||||
}; |
||||
}; |
||||
|
||||
extraConfig = mkOption { |
||||
type = types.lines; |
||||
default = ""; |
||||
description = "Custom snippet to append to rmilter config"; |
||||
}; |
||||
|
||||
postfix = { |
||||
enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = "Add rmilter to postfix main.conf"; |
||||
}; |
||||
|
||||
configFragment = mkOption { |
||||
type = types.str; |
||||
description = "Addon to postfix configuration"; |
||||
default = '' |
||||
smtpd_milters = ${cfg.bindSocket} |
||||
# or for TCP socket |
||||
# # smtpd_milters = inet:localhost:9900 |
||||
milter_protocol = 6 |
||||
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen} |
||||
# skip mail without checks if milter will die |
||||
milter_default_action = accept |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
users.extraUsers = singleton { |
||||
name = cfg.user; |
||||
description = "rspamd daemon"; |
||||
uid = config.ids.uids.rmilter; |
||||
group = cfg.group; |
||||
}; |
||||
|
||||
users.extraGroups = singleton { |
||||
name = cfg.group; |
||||
gid = config.ids.gids.rmilter; |
||||
}; |
||||
|
||||
systemd.services.rmilter = { |
||||
description = "Rmilter Service"; |
||||
|
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network.target" ]; |
||||
|
||||
serviceConfig = { |
||||
ExecStart = "${pkgs.rmilter}/bin/rmilter ${optionalString cfg.debug "-d"} -n -c ${rmilterConfigFile}"; |
||||
User = cfg.user; |
||||
Group = cfg.group; |
||||
PermissionsStartOnly = true; |
||||
Restart = "always"; |
||||
}; |
||||
|
||||
preStart = '' |
||||
${pkgs.coreutils}/bin/mkdir -p /run/rmilter |
||||
${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /run/rmilter |
||||
''; |
||||
|
||||
}; |
||||
|
||||
services.postfix.extraConfig = optionalString cfg.postfix.enable cfg.postfix.configFragment; |
||||
|
||||
}; |
||||
|
||||
} |
@ -0,0 +1,90 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
|
||||
cfg = config.services.rspamd; |
||||
|
||||
in |
||||
|
||||
{ |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.rspamd = { |
||||
|
||||
enable = mkOption { |
||||
default = false; |
||||
description = "Whether to run the rspamd daemon."; |
||||
}; |
||||
|
||||
debug = mkOption { |
||||
default = false; |
||||
description = "Whether to run the rspamd daemon in debug mode."; |
||||
}; |
||||
|
||||
user = mkOption { |
||||
type = types.string; |
||||
default = "rspamd"; |
||||
description = '' |
||||
User to use when no root privileges are required. |
||||
''; |
||||
}; |
||||
|
||||
group = mkOption { |
||||
type = types.string; |
||||
default = "rspamd"; |
||||
description = '' |
||||
Group to use when no root privileges are required. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
# Allow users to run 'rspamc' and 'rspamadm'. |
||||
environment.systemPackages = [ pkgs.rspamd ]; |
||||
|
||||
users.extraUsers = singleton { |
||||
name = cfg.user; |
||||
description = "rspamd daemon"; |
||||
uid = config.ids.uids.rspamd; |
||||
group = cfg.group; |
||||
}; |
||||
|
||||
users.extraGroups = singleton { |
||||
name = cfg.group; |
||||
gid = config.ids.gids.spamd; |
||||
}; |
||||
|
||||
systemd.services.rspamd = { |
||||
description = "Rspamd Service"; |
||||
|
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network.target" ]; |
||||
|
||||
serviceConfig = { |
||||
ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -f"; |
||||
RuntimeDirectory = "/var/lib/rspamd"; |
||||
PermissionsStartOnly = true; |
||||
Restart = "always"; |
||||
}; |
||||
|
||||
preStart = '' |
||||
${pkgs.coreutils}/bin/mkdir -p /var/{lib,log}/rspamd |
||||
${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd |
||||
''; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
} |
@ -0,0 +1,54 @@ |
||||
{ pkgs, lib, config, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.mathics; |
||||
|
||||
in { |
||||
options = { |
||||
services.mathics = { |
||||
enable = mkEnableOption "Mathics notebook service"; |
||||
|
||||
external = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = "Listen on all interfaces, rather than just localhost?"; |
||||
}; |
||||
|
||||
port = mkOption { |
||||
type = types.int; |
||||
default = 8000; |
||||
description = "TCP port to listen on."; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
users.extraUsers.mathics = { |
||||
group = config.users.extraGroups.mathics.name; |
||||
description = "Mathics user"; |
||||
home = "/var/lib/mathics"; |
||||
createHome = true; |
||||
uid = config.ids.uids.mathics; |
||||
}; |
||||
|
||||
users.extraGroups.mathics.gid = config.ids.gids.mathics; |
||||
|
||||
systemd.services.mathics = { |
||||
description = "Mathics notebook server"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network.target" ]; |
||||
serviceConfig = { |
||||
User = config.users.extraUsers.mathics.name; |
||||
Group = config.users.extraGroups.mathics.name; |
||||
ExecStart = concatStringsSep " " [ |
||||
"${pkgs.mathics}/bin/mathicsserver" |
||||
"--port" (toString cfg.port) |
||||
(if cfg.external then "--external" else "") |
||||
]; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,25 @@ |
||||
version: 1 |
||||
|
||||
# In systemd's journal, loglevel is implicitly stored, so let's omit it |
||||
# from the message text. |
||||
formatters: |
||||
journal_fmt: |
||||
format: '%(name)s: [%(request)s] %(message)s' |
||||
|
||||
filters: |
||||
context: |
||||
(): synapse.util.logcontext.LoggingContextFilter |
||||
request: "" |
||||
|
||||
handlers: |
||||
journal: |
||||
class: systemd.journal.JournalHandler |
||||
formatter: journal_fmt |
||||
filters: [context] |
||||
SYSLOG_IDENTIFIER: synapse |
||||
|
||||
root: |
||||
level: INFO |
||||
handlers: [journal] |
||||
|
||||
disable_existing_loggers: False |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue