commit
6f95cb1459
@ -0,0 +1,149 @@ |
||||
{ lib, pkgs, config, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.programs.yabar; |
||||
|
||||
mapExtra = v: lib.concatStringsSep "\n" (mapAttrsToList ( |
||||
key: val: "${key} = ${if (isString val) then "\"${val}\"" else "${builtins.toString val}"};" |
||||
) v); |
||||
|
||||
listKeys = r: concatStringsSep "," (map (n: "\"${n}\"") (attrNames r)); |
||||
|
||||
configFile = let |
||||
bars = mapAttrsToList ( |
||||
name: cfg: '' |
||||
${name}: { |
||||
font: "${cfg.font}"; |
||||
position: "${cfg.position}"; |
||||
|
||||
${mapExtra cfg.extra} |
||||
|
||||
block-list: [${listKeys cfg.indicators}] |
||||
|
||||
${concatStringsSep "\n" (mapAttrsToList ( |
||||
name: cfg: '' |
||||
${name}: { |
||||
exec: "${cfg.exec}"; |
||||
align: "${cfg.align}"; |
||||
${mapExtra cfg.extra} |
||||
}; |
||||
'' |
||||
) cfg.indicators)} |
||||
}; |
||||
'' |
||||
) cfg.bars; |
||||
in pkgs.writeText "yabar.conf" '' |
||||
bar-list = [${listKeys cfg.bars}]; |
||||
${concatStringsSep "\n" bars} |
||||
''; |
||||
in |
||||
{ |
||||
options.programs.yabar = { |
||||
enable = mkEnableOption "yabar"; |
||||
|
||||
package = mkOption { |
||||
default = pkgs.yabar; |
||||
example = literalExample "pkgs.yabar-unstable"; |
||||
type = types.package; |
||||
|
||||
description = '' |
||||
The package which contains the `yabar` binary. |
||||
|
||||
Nixpkgs provides the `yabar` and `yabar-unstable` |
||||
derivations since 18.03, so it's possible to choose. |
||||
''; |
||||
}; |
||||
|
||||
bars = mkOption { |
||||
default = {}; |
||||
type = types.attrsOf(types.submodule { |
||||
options = { |
||||
font = mkOption { |
||||
default = "sans bold 9"; |
||||
example = "Droid Sans, FontAwesome Bold 9"; |
||||
type = types.string; |
||||
|
||||
description = '' |
||||
The font that will be used to draw the status bar. |
||||
''; |
||||
}; |
||||
|
||||
position = mkOption { |
||||
default = "top"; |
||||
example = "bottom"; |
||||
type = types.enum [ "top" "bottom" ]; |
||||
|
||||
description = '' |
||||
The position where the bar will be rendered. |
||||
''; |
||||
}; |
||||
|
||||
extra = mkOption { |
||||
default = {}; |
||||
type = types.attrsOf types.string; |
||||
|
||||
description = '' |
||||
An attribute set which contains further attributes of a bar. |
||||
''; |
||||
}; |
||||
|
||||
indicators = mkOption { |
||||
default = {}; |
||||
type = types.attrsOf(types.submodule { |
||||
options.exec = mkOption { |
||||
example = "YABAR_DATE"; |
||||
type = types.string; |
||||
description = '' |
||||
The type of the indicator to be executed. |
||||
''; |
||||
}; |
||||
|
||||
options.align = mkOption { |
||||
default = "left"; |
||||
example = "right"; |
||||
type = types.enum [ "left" "center" "right" ]; |
||||
|
||||
description = '' |
||||
Whether to align the indicator at the left or right of the bar. |
||||
''; |
||||
}; |
||||
|
||||
options.extra = mkOption { |
||||
default = {}; |
||||
type = types.attrsOf (types.either types.string types.int); |
||||
|
||||
description = '' |
||||
An attribute set which contains further attributes of a indicator. |
||||
''; |
||||
}; |
||||
}); |
||||
|
||||
description = '' |
||||
Indicators that should be rendered by yabar. |
||||
''; |
||||
}; |
||||
}; |
||||
}); |
||||
|
||||
description = '' |
||||
List of bars that should be rendered by yabar. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
systemd.user.services.yabar = { |
||||
description = "yabar service"; |
||||
wantedBy = [ "graphical-session.target" ]; |
||||
partOf = [ "graphical-session.target" ]; |
||||
|
||||
script = '' |
||||
${cfg.package}/bin/yabar -c ${configFile} |
||||
''; |
||||
|
||||
serviceConfig.Restart = "always"; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,135 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.home-assistant; |
||||
|
||||
configFile = pkgs.writeText "configuration.yaml" (builtins.toJSON cfg.config); |
||||
|
||||
availableComponents = pkgs.home-assistant.availableComponents; |
||||
|
||||
# Given component "parentConfig.platform", returns whether config.parentConfig |
||||
# is a list containing a set with set.platform == "platform". |
||||
# |
||||
# For example, the component sensor.luftdaten is used as follows: |
||||
# config.sensor = [ { |
||||
# platform = "luftdaten"; |
||||
# ... |
||||
# } ]; |
||||
useComponentPlatform = component: |
||||
let |
||||
path = splitString "." component; |
||||
parentConfig = attrByPath (init path) null cfg.config; |
||||
platform = last path; |
||||
in isList parentConfig && any |
||||
(item: item.platform or null == platform) |
||||
parentConfig; |
||||
|
||||
# Returns whether component is used in config |
||||
useComponent = component: |
||||
hasAttrByPath (splitString "." component) cfg.config |
||||
|| useComponentPlatform component; |
||||
|
||||
# List of components used in config |
||||
extraComponents = filter useComponent availableComponents; |
||||
|
||||
package = if cfg.autoExtraComponents |
||||
then (cfg.package.override { inherit extraComponents; }) |
||||
else cfg.package; |
||||
|
||||
in { |
||||
meta.maintainers = with maintainers; [ dotlambda ]; |
||||
|
||||
options.services.home-assistant = { |
||||
enable = mkEnableOption "Home Assistant"; |
||||
|
||||
configDir = mkOption { |
||||
default = "/var/lib/hass"; |
||||
type = types.path; |
||||
description = "The config directory, where your <filename>configuration.yaml</filename> is located."; |
||||
}; |
||||
|
||||
config = mkOption { |
||||
default = null; |
||||
type = with types; nullOr attrs; |
||||
example = literalExample '' |
||||
{ |
||||
homeassistant = { |
||||
name = "Home"; |
||||
time_zone = "UTC"; |
||||
}; |
||||
frontend = { }; |
||||
http = { }; |
||||
feedreader.urls = [ "https://nixos.org/blogs.xml" ]; |
||||
} |
||||
''; |
||||
description = '' |
||||
Your <filename>configuration.yaml</filename> as a Nix attribute set. |
||||
Beware that setting this option will delete your previous <filename>configuration.yaml</filename>. |
||||
''; |
||||
}; |
||||
|
||||
package = mkOption { |
||||
default = pkgs.home-assistant; |
||||
defaultText = "pkgs.home-assistant"; |
||||
type = types.package; |
||||
example = literalExample '' |
||||
pkgs.home-assistant.override { |
||||
extraPackages = ps: with ps; [ colorlog ]; |
||||
} |
||||
''; |
||||
description = '' |
||||
Home Assistant package to use. |
||||
Override <literal>extraPackages</literal> in order to add additional dependencies. |
||||
''; |
||||
}; |
||||
|
||||
autoExtraComponents = mkOption { |
||||
default = true; |
||||
type = types.bool; |
||||
description = '' |
||||
If set to <literal>true</literal>, the components used in <literal>config</literal> |
||||
are set as the specified package's <literal>extraComponents</literal>. |
||||
This in turn adds all packaged dependencies to the derivation. |
||||
You might still see import errors in your log. |
||||
In this case, you will need to package the necessary dependencies yourself |
||||
or ask for someone else to package them. |
||||
If a dependency is packaged but not automatically added to this list, |
||||
you might need to specify it in <literal>extraPackages</literal>. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
systemd.services.home-assistant = { |
||||
description = "Home Assistant"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network.target" ]; |
||||
preStart = lib.optionalString (cfg.config != null) '' |
||||
rm -f ${cfg.configDir}/configuration.yaml |
||||
ln -s ${configFile} ${cfg.configDir}/configuration.yaml |
||||
''; |
||||
serviceConfig = { |
||||
ExecStart = '' |
||||
${package}/bin/hass --config "${cfg.configDir}" |
||||
''; |
||||
User = "hass"; |
||||
Group = "hass"; |
||||
Restart = "on-failure"; |
||||
ProtectSystem = "strict"; |
||||
ReadWritePaths = "${cfg.configDir}"; |
||||
PrivateTmp = true; |
||||
}; |
||||
}; |
||||
|
||||
users.extraUsers.hass = { |
||||
home = cfg.configDir; |
||||
createHome = true; |
||||
group = "hass"; |
||||
uid = config.ids.uids.hass; |
||||
}; |
||||
|
||||
users.extraGroups.hass.gid = config.ids.gids.hass; |
||||
}; |
||||
} |
@ -1,99 +0,0 @@ |
||||
{ config, pkgs, lib, ... }: |
||||
|
||||
let |
||||
inherit (lib) mkOption mkIf; |
||||
|
||||
cfg = config.services.openafsClient; |
||||
|
||||
cellServDB = pkgs.fetchurl { |
||||
url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14; |
||||
sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; |
||||
}; |
||||
|
||||
afsConfig = pkgs.runCommand "afsconfig" {} '' |
||||
mkdir -p $out |
||||
echo ${cfg.cellName} > $out/ThisCell |
||||
cp ${cellServDB} $out/CellServDB |
||||
echo "/afs:${cfg.cacheDirectory}:${cfg.cacheSize}" > $out/cacheinfo |
||||
''; |
||||
|
||||
openafsPkgs = config.boot.kernelPackages.openafsClient; |
||||
in |
||||
{ |
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.openafsClient = { |
||||
|
||||
enable = mkOption { |
||||
default = false; |
||||
description = "Whether to enable the OpenAFS client."; |
||||
}; |
||||
|
||||
cellName = mkOption { |
||||
default = "grand.central.org"; |
||||
description = "Cell name."; |
||||
}; |
||||
|
||||
cacheSize = mkOption { |
||||
default = "100000"; |
||||
description = "Cache size."; |
||||
}; |
||||
|
||||
cacheDirectory = mkOption { |
||||
default = "/var/cache/openafs"; |
||||
description = "Cache directory."; |
||||
}; |
||||
|
||||
crypt = mkOption { |
||||
default = false; |
||||
description = "Whether to enable (weak) protocol encryption."; |
||||
}; |
||||
|
||||
sparse = mkOption { |
||||
default = false; |
||||
description = "Minimal cell list in /afs."; |
||||
}; |
||||
|
||||
}; |
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
environment.systemPackages = [ openafsPkgs ]; |
||||
|
||||
environment.etc = [ |
||||
{ source = afsConfig; |
||||
target = "openafs"; |
||||
} |
||||
]; |
||||
|
||||
systemd.services.afsd = { |
||||
description = "AFS client"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "network.target" ]; |
||||
serviceConfig = { RemainAfterExit = true; }; |
||||
|
||||
preStart = '' |
||||
mkdir -p -m 0755 /afs |
||||
mkdir -m 0700 -p ${cfg.cacheDirectory} |
||||
${pkgs.kmod}/bin/insmod ${openafsPkgs}/lib/openafs/libafs-*.ko || true |
||||
${openafsPkgs}/sbin/afsd -confdir ${afsConfig} -cachedir ${cfg.cacheDirectory} ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} -fakestat -afsdb |
||||
${openafsPkgs}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} |
||||
''; |
||||
|
||||
# Doing this in preStop, because after these commands AFS is basically |
||||
# stopped, so systemd has nothing to do, just noticing it. If done in |
||||
# postStop, then we get a hang + kernel oops, because AFS can't be |
||||
# stopped simply by sending signals to processes. |
||||
preStop = '' |
||||
${pkgs.utillinux}/bin/umount /afs |
||||
${openafsPkgs}/sbin/afsd -shutdown |
||||
''; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,239 @@ |
||||
{ config, pkgs, lib, ... }: |
||||
|
||||
with import ./lib.nix { inherit lib; }; |
||||
|
||||
let |
||||
inherit (lib) getBin mkOption mkIf optionalString singleton types; |
||||
|
||||
cfg = config.services.openafsClient; |
||||
|
||||
cellServDB = pkgs.fetchurl { |
||||
url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14; |
||||
sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; |
||||
}; |
||||
|
||||
clientServDB = pkgs.writeText "client-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.cellServDB); |
||||
|
||||
afsConfig = pkgs.runCommand "afsconfig" {} '' |
||||
mkdir -p $out |
||||
echo ${cfg.cellName} > $out/ThisCell |
||||
cat ${cellServDB} ${clientServDB} > $out/CellServDB |
||||
echo "${cfg.mountPoint}:${cfg.cache.directory}:${toString cfg.cache.blocks}" > $out/cacheinfo |
||||
''; |
||||
|
||||
openafsMod = config.boot.kernelPackages.openafs; |
||||
openafsBin = lib.getBin pkgs.openafs; |
||||
in |
||||
{ |
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.openafsClient = { |
||||
|
||||
enable = mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = "Whether to enable the OpenAFS client."; |
||||
}; |
||||
|
||||
afsdb = mkOption { |
||||
default = true; |
||||
type = types.bool; |
||||
description = "Resolve cells via AFSDB DNS records."; |
||||
}; |
||||
|
||||
cellName = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Cell name."; |
||||
example = "grand.central.org"; |
||||
}; |
||||
|
||||
cellServDB = mkOption { |
||||
default = []; |
||||
type = with types; listOf (submodule { options = cellServDBConfig; }); |
||||
description = '' |
||||
This cell's database server records, added to the global |
||||
CellServDB. See CellServDB(5) man page for syntax. Ignored when |
||||
<literal>afsdb</literal> is set to <literal>true</literal>. |
||||
''; |
||||
example = '' |
||||
[ { ip = "1.2.3.4"; dnsname = "first.afsdb.server.dns.fqdn.org"; } |
||||
{ ip = "2.3.4.5"; dnsname = "second.afsdb.server.dns.fqdn.org"; } |
||||
] |
||||
''; |
||||
}; |
||||
|
||||
cache = { |
||||
blocks = mkOption { |
||||
default = 100000; |
||||
type = types.int; |
||||
description = "Cache size in 1KB blocks."; |
||||
}; |
||||
|
||||
chunksize = mkOption { |
||||
default = 0; |
||||
type = types.ints.between 0 30; |
||||
description = '' |
||||
Size of each cache chunk given in powers of |
||||
2. <literal>0</literal> resets the chunk size to its default |
||||
values (13 (8 KB) for memcache, 18-20 (256 KB to 1 MB) for |
||||
diskcache). Maximum value is 30. Important performance |
||||
parameter. Set to higher values when dealing with large files. |
||||
''; |
||||
}; |
||||
|
||||
directory = mkOption { |
||||
default = "/var/cache/openafs"; |
||||
type = types.str; |
||||
description = "Cache directory."; |
||||
}; |
||||
|
||||
diskless = mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = '' |
||||
Use in-memory cache for diskless machines. Has no real |
||||
performance benefit anymore. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
crypt = mkOption { |
||||
default = true; |
||||
type = types.bool; |
||||
description = "Whether to enable (weak) protocol encryption."; |
||||
}; |
||||
|
||||
daemons = mkOption { |
||||
default = 2; |
||||
type = types.int; |
||||
description = '' |
||||
Number of daemons to serve user requests. Numbers higher than 6 |
||||
usually do no increase performance. Default is sufficient for up |
||||
to five concurrent users. |
||||
''; |
||||
}; |
||||
|
||||
fakestat = mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = '' |
||||
Return fake data on stat() calls. If <literal>true</literal>, |
||||
always do so. If <literal>false</literal>, only do so for |
||||
cross-cell mounts (as these are potentially expensive). |
||||
''; |
||||
}; |
||||
|
||||
inumcalc = mkOption { |
||||
default = "compat"; |
||||
type = types.strMatching "compat|md5"; |
||||
description = '' |
||||
Inode calculation method. <literal>compat</literal> is |
||||
computationally less expensive, but <literal>md5</literal> greatly |
||||
reduces the likelihood of inode collisions in larger scenarios |
||||
involving multiple cells mounted into one AFS space. |
||||
''; |
||||
}; |
||||
|
||||
mountPoint = mkOption { |
||||
default = "/afs"; |
||||
type = types.str; |
||||
description = '' |
||||
Mountpoint of the AFS file tree, conventionally |
||||
<literal>/afs</literal>. When set to a different value, only |
||||
cross-cells that use the same value can be accessed. |
||||
''; |
||||
}; |
||||
|
||||
sparse = mkOption { |
||||
default = true; |
||||
type = types.bool; |
||||
description = "Minimal cell list in /afs."; |
||||
}; |
||||
|
||||
startDisconnected = mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = '' |
||||
Start up in disconnected mode. You need to execute |
||||
<literal>fs disco online</literal> (as root) to switch to |
||||
connected mode. Useful for roaming devices. |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
assertions = [ |
||||
{ assertion = cfg.afsdb || cfg.cellServDB != []; |
||||
message = "You should specify all cell-local database servers in config.services.openafsClient.cellServDB or set config.services.openafsClient.afsdb."; |
||||
} |
||||
{ assertion = cfg.cellName != ""; |
||||
message = "You must specify the local cell name in config.services.openafsClient.cellName."; |
||||
} |
||||
]; |
||||
|
||||
environment.systemPackages = [ pkgs.openafs ]; |
||||
|
||||
environment.etc = { |
||||
clientCellServDB = { |
||||
source = pkgs.runCommand "CellServDB" {} '' |
||||
cat ${cellServDB} ${clientServDB} > $out |
||||
''; |
||||
target = "openafs/CellServDB"; |
||||
mode = "0644"; |
||||
}; |
||||
clientCell = { |
||||
text = '' |
||||
${cfg.cellName} |
||||
''; |
||||
target = "openafs/ThisCell"; |
||||
mode = "0644"; |
||||
}; |
||||
}; |
||||
|
||||
systemd.services.afsd = { |
||||
description = "AFS client"; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = singleton (if cfg.startDisconnected then "network.target" else "network-online.target"); |
||||
serviceConfig = { RemainAfterExit = true; }; |
||||
restartIfChanged = false; |
||||
|
||||
preStart = '' |
||||
mkdir -p -m 0755 ${cfg.mountPoint} |
||||
mkdir -m 0700 -p ${cfg.cache.directory} |
||||
${pkgs.kmod}/bin/insmod ${openafsMod}/lib/modules/*/extra/openafs/libafs.ko.xz |
||||
${openafsBin}/sbin/afsd \ |
||||
-mountdir ${cfg.mountPoint} \ |
||||
-confdir ${afsConfig} \ |
||||
${optionalString (!cfg.cache.diskless) "-cachedir ${cfg.cache.directory}"} \ |
||||
-blocks ${toString cfg.cache.blocks} \ |
||||
-chunksize ${toString cfg.cache.chunksize} \ |
||||
${optionalString cfg.cache.diskless "-memcache"} \ |
||||
-inumcalc ${cfg.inumcalc} \ |
||||
${if cfg.fakestat then "-fakestat-all" else "-fakestat"} \ |
||||
${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} \ |
||||
${optionalString cfg.afsdb "-afsdb"} |
||||
${openafsBin}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} |
||||
${optionalString cfg.startDisconnected "${openafsBin}/bin/fs discon offline"} |
||||
''; |
||||
|
||||
# Doing this in preStop, because after these commands AFS is basically |
||||
# stopped, so systemd has nothing to do, just noticing it. If done in |
||||
# postStop, then we get a hang + kernel oops, because AFS can't be |
||||
# stopped simply by sending signals to processes. |
||||
preStop = '' |
||||
${pkgs.utillinux}/bin/umount ${cfg.mountPoint} |
||||
${openafsBin}/sbin/afsd -shutdown |
||||
${pkgs.kmod}/sbin/rmmod libafs |
||||
''; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,28 @@ |
||||
{ lib, ...}: |
||||
|
||||
let |
||||
inherit (lib) concatStringsSep mkOption types; |
||||
|
||||
in rec { |
||||
|
||||
mkCellServDB = cellName: db: '' |
||||
>${cellName} |
||||
'' + (concatStringsSep "\n" (map (dbm: if (dbm.ip != "" && dbm.dnsname != "") then dbm.ip + " #" + dbm.dnsname else "") |
||||
db)); |
||||
|
||||
# CellServDB configuration type |
||||
cellServDBConfig = { |
||||
ip = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "1.2.3.4"; |
||||
description = "IP Address of a database server"; |
||||
}; |
||||
dnsname = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
example = "afs.example.org"; |
||||
description = "DNS full-qualified domain name of a database server"; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,260 @@ |
||||
{ config, pkgs, lib, ... }: |
||||
|
||||
with import ./lib.nix { inherit lib; }; |
||||
|
||||
let |
||||
inherit (lib) concatStringsSep intersperse mapAttrsToList mkForce mkIf mkMerge mkOption optionalString types; |
||||
|
||||
bosConfig = pkgs.writeText "BosConfig" ('' |
||||
restrictmode 1 |
||||
restarttime 16 0 0 0 0 |
||||
checkbintime 3 0 5 0 0 |
||||
'' + (optionalString cfg.roles.database.enable '' |
||||
bnode simple vlserver 1 |
||||
parm ${openafsBin}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs} |
||||
end |
||||
bnode simple ptserver 1 |
||||
parm ${openafsBin}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs} |
||||
end |
||||
'') + (optionalString cfg.roles.fileserver.enable '' |
||||
bnode dafs dafs 1 |
||||
parm ${openafsBin}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs} |
||||
parm ${openafsBin}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs} |
||||
parm ${openafsBin}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs} |
||||
parm ${openafsBin}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs} |
||||
end |
||||
'') + (optionalString (cfg.roles.database.enable && cfg.roles.backup.enable) '' |
||||
bnode simple buserver 1 |
||||
parm ${openafsBin}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString (cfg.roles.backup.cellServDB != []) "-cellservdb /etc/openafs/backup/"} |
||||
end |
||||
'')); |
||||
|
||||
netInfo = if (cfg.advertisedAddresses != []) then |
||||
pkgs.writeText "NetInfo" ((concatStringsSep "\nf " cfg.advertisedAddresses) + "\n") |
||||
else null; |
||||
|
||||
buCellServDB = pkgs.writeText "backup-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.roles.backup.cellServDB); |
||||
|
||||
cfg = config.services.openafsServer; |
||||
|
||||
udpSizeStr = toString cfg.udpPacketSize; |
||||
|
||||
openafsBin = lib.getBin pkgs.openafs; |
||||
|
||||
in { |
||||
|
||||
options = { |
||||
|
||||
services.openafsServer = { |
||||
|
||||
enable = mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = '' |
||||
Whether to enable the OpenAFS server. An OpenAFS server needs a |
||||
complex setup. So, be aware that enabling this service and setting |
||||
some options does not give you a turn-key-ready solution. You need |
||||
at least a running Kerberos 5 setup, as OpenAFS relies on it for |
||||
authentication. See the Guide "QuickStartUnix" coming with |
||||
<literal>pkgs.openafs.doc</literal> for complete setup |
||||
instructions. |
||||
''; |
||||
}; |
||||
|
||||
advertisedAddresses = mkOption { |
||||
default = []; |
||||
description = "List of IP addresses this server is advertised under. See NetInfo(5)"; |
||||
}; |
||||
|
||||
cellName = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Cell name, this server will serve."; |
||||
example = "grand.central.org"; |
||||
}; |
||||
|
||||
cellServDB = mkOption { |
||||
default = []; |
||||
type = with types; listOf (submodule [ { options = cellServDBConfig;} ]); |
||||
description = "Definition of all cell-local database server machines."; |
||||
}; |
||||
|
||||
roles = { |
||||
fileserver = { |
||||
enable = mkOption { |
||||
default = true; |
||||
type = types.bool; |
||||
description = "Fileserver role, serves files and volumes from its local storage."; |
||||
}; |
||||
|
||||
fileserverArgs = mkOption { |
||||
default = "-vattachpar 128 -vhashsize 11 -L -rxpck 400 -cb 1000000"; |
||||
type = types.str; |
||||
description = "Arguments to the dafileserver process. See its man page."; |
||||
}; |
||||
|
||||
volserverArgs = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Arguments to the davolserver process. See its man page."; |
||||
example = "-sync never"; |
||||
}; |
||||
|
||||
salvageserverArgs = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Arguments to the salvageserver process. See its man page."; |
||||
example = "-showlog"; |
||||
}; |
||||
|
||||
salvagerArgs = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Arguments to the dasalvager process. See its man page."; |
||||
example = "-showlog -showmounts"; |
||||
}; |
||||
}; |
||||
|
||||
database = { |
||||
enable = mkOption { |
||||
default = true; |
||||
type = types.bool; |
||||
description = '' |
||||
Database server role, maintains the Volume Location Database, |
||||
Protection Database (and Backup Database, see |
||||
<literal>backup</literal> role). There can be multiple |
||||
servers in the database role for replication, which then need |
||||
reliable network connection to each other. |
||||
|
||||
Servers in this role appear in AFSDB DNS records or the |
||||
CellServDB. |
||||
''; |
||||
}; |
||||
|
||||
vlserverArgs = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Arguments to the vlserver process. See its man page."; |
||||
example = "-rxbind"; |
||||
}; |
||||
|
||||
ptserverArgs = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Arguments to the ptserver process. See its man page."; |
||||
example = "-restricted -default_access S---- S-M---"; |
||||
}; |
||||
}; |
||||
|
||||
backup = { |
||||
enable = mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = '' |
||||
Backup server role. Use in conjunction with the |
||||
<literal>database</literal> role to maintain the Backup |
||||
Database. Normally only used in conjunction with tape storage |
||||
or IBM's Tivoli Storage Manager. |
||||
''; |
||||
}; |
||||
|
||||
buserverArgs = mkOption { |
||||
default = ""; |
||||
type = types.str; |
||||
description = "Arguments to the buserver process. See its man page."; |
||||
example = "-p 8"; |
||||
}; |
||||
|
||||
cellServDB = mkOption { |
||||
default = []; |
||||
type = with types; listOf (submodule [ { options = cellServDBConfig;} ]); |
||||
description = '' |
||||
Definition of all cell-local backup database server machines. |
||||
Use this when your cell uses less backup database servers than |
||||
other database server machines. |
||||
''; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
dottedPrincipals= mkOption { |
||||
default = false; |
||||
type = types.bool; |
||||
description = '' |
||||
If enabled, allow principal names containing (.) dots. Enabling |
||||
this has security implications! |
||||
''; |
||||
}; |
||||
|
||||
udpPacketSize = mkOption { |
||||
default = 1310720; |
||||
type = types.int; |
||||
description = '' |
||||
UDP packet size to use in Bytes. Higher values can speed up |
||||
communications. The default of 1 MB is a sufficient in most |
||||
cases. Make sure to increase the kernel's UDP buffer size |
||||
accordingly via <literal>net.core(w|r|opt)mem_max</literal> |
||||
sysctl. |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
assertions = [ |
||||
{ assertion = cfg.cellServDB != []; |
||||
message = "You must specify all cell-local database servers in config.services.openafsServer.cellServDB."; |
||||
} |
||||
{ assertion = cfg.cellName != ""; |
||||
message = "You must specify the local cell name in config.services.openafsServer.cellName."; |
||||
} |
||||
]; |
||||
|
||||
environment.systemPackages = [ pkgs.openafs ]; |
||||
|
||||
environment.etc = { |
||||
bosConfig = { |
||||
source = bosConfig; |
||||
target = "openafs/BosConfig"; |
||||
mode = "0644"; |
||||
}; |
||||
cellServDB = { |
||||
text = mkCellServDB cfg.cellName cfg.cellServDB; |
||||
target = "openafs/server/CellServDB"; |
||||
mode = "0644"; |
||||
}; |
||||
thisCell = { |
||||
text = cfg.cellName; |
||||
target = "openafs/server/ThisCell"; |
||||
mode = "0644"; |
||||
}; |
||||
buCellServDB = { |
||||
enable = (cfg.roles.backup.cellServDB != []); |
||||
text = mkCellServDB cfg.cellName cfg.roles.backup.cellServDB; |
||||
target = "openafs/backup/CellServDB"; |
||||
}; |
||||
}; |
||||
|
||||
systemd.services = { |
||||
openafs-server = { |
||||
description = "OpenAFS server"; |
||||
after = [ "syslog.target" "network.target" ]; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
restartIfChanged = false; |
||||
unitConfig.ConditionPathExists = [ "/etc/openafs/server/rxkad.keytab" ]; |
||||
preStart = '' |
||||
mkdir -m 0755 -p /var/openafs |
||||
${optionalString (netInfo != null) "cp ${netInfo} /var/openafs/netInfo"} |
||||
${optionalString (cfg.roles.backup.cellServDB != []) "cp ${buCellServDB}"} |
||||
''; |
||||
serviceConfig = { |
||||
ExecStart = "${openafsBin}/bin/bosserver -nofork"; |
||||
ExecStop = "${openafsBin}/bin/bos shutdown localhost -wait -localauth"; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,238 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.services.monero; |
||||
dataDir = "/var/lib/monero"; |
||||
|
||||
listToConf = option: list: |
||||
concatMapStrings (value: "${option}=${value}\n") list; |
||||
|
||||
login = (cfg.rpc.user != null && cfg.rpc.password != null); |
||||
|
||||
configFile = with cfg; pkgs.writeText "monero.conf" '' |
||||
log-file=/dev/stdout |
||||
data-dir=${dataDir} |
||||
|
||||
${optionalString mining.enable '' |
||||
start-mining=${mining.address} |
||||
mining-threads=${toString mining.threads} |
||||
''} |
||||
|
||||
rpc-bind-ip=${rpc.address} |
||||
rpc-bind-port=${toString rpc.port} |
||||
${optionalString login '' |
||||
rpc-login=${rpc.user}:${rpc.password} |
||||
''} |
||||
${optionalString rpc.restricted '' |
||||
restrict-rpc=1 |
||||
''} |
||||
|
||||
limit-rate-up=${toString limits.upload} |
||||
limit-rate-down=${toString limits.download} |
||||
max-concurrency=${toString limits.threads} |
||||
block-sync-size=${toString limits.syncSize} |
||||
|
||||
${listToConf "add-peer" extraNodes} |
||||
${listToConf "add-priority-node" priorityNodes} |
||||
${listToConf "add-exclusive-node" exclusiveNodes} |
||||
|
||||
${extraConfig} |
||||
''; |
||||
|
||||
in |
||||
|
||||
{ |
||||
|
||||
###### interface |
||||
|
||||
options = { |
||||
|
||||
services.monero = { |
||||
|
||||
enable = mkEnableOption "Monero node daemon."; |
||||
|
||||
mining.enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Whether to mine moneroj. |
||||
''; |
||||
}; |
||||
|
||||
mining.address = mkOption { |
||||
type = types.str; |
||||
default = ""; |
||||
description = '' |
||||
Monero address where to send mining rewards. |
||||
''; |
||||
}; |
||||
|
||||
mining.threads = mkOption { |
||||
type = types.addCheck types.int (x: x>=0); |
||||
default = 0; |
||||
description = '' |
||||
Number of threads used for mining. |
||||
Set to <literal>0</literal> to use all available. |
||||
''; |
||||
}; |
||||
|
||||
rpc.user = mkOption { |
||||
type = types.nullOr types.str; |
||||
default = null; |
||||
description = '' |
||||
User name for RPC connections. |
||||
''; |
||||
}; |
||||
|
||||
rpc.password = mkOption { |
||||
type = types.str; |
||||
default = null; |
||||
description = '' |
||||
Password for RPC connections. |
||||
''; |
||||
}; |
||||
|
||||
rpc.address = mkOption { |
||||
type = types.str; |
||||
default = "127.0.0.1"; |
||||
description = '' |
||||
IP address the RPC server will bind to. |
||||
''; |
||||
}; |
||||
|
||||
rpc.port = mkOption { |
||||
type = types.int; |
||||
default = 18081; |
||||
description = '' |
||||
Port the RPC server will bind to. |
||||
''; |
||||
}; |
||||
|
||||
rpc.restricted = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = '' |
||||
Whether to restrict RPC to view only commands. |
||||
''; |
||||
}; |
||||
|
||||
limits.upload = mkOption { |
||||
type = types.addCheck types.int (x: x>=-1); |
||||
default = -1; |
||||
description = '' |
||||
Limit of the upload rate in kB/s. |
||||
Set to <literal>-1</literal> to leave unlimited. |
||||
''; |
||||
}; |
||||
|
||||
limits.download = mkOption { |
||||
type = types.addCheck types.int (x: x>=-1); |
||||
default = -1; |
||||
description = '' |
||||
Limit of the download rate in kB/s. |
||||
Set to <literal>-1</literal> to leave unlimited. |
||||
''; |
||||
}; |
||||
|
||||
limits.threads = mkOption { |
||||
type = types.addCheck types.int (x: x>=0); |
||||
default = 0; |
||||
description = '' |
||||
Maximum number of threads used for a parallel job. |
||||
Set to <literal>0</literal> to leave unlimited. |
||||
''; |
||||
}; |
||||
|
||||
limits.syncSize = mkOption { |
||||
type = types.addCheck types.int (x: x>=0); |
||||
default = 0; |
||||
description = '' |
||||
Maximum number of blocks to sync at once. |
||||
Set to <literal>0</literal> for adaptive. |
||||
''; |
||||
}; |
||||
|
||||
extraNodes = mkOption { |
||||
type = types.listOf types.str; |
||||
default = [ ]; |
||||
description = '' |
||||
List of additional peer IP addresses to add to the local list. |
||||
''; |
||||
}; |
||||
|
||||
priorityNodes = mkOption { |
||||
type = types.listOf types.str; |
||||
default = [ ]; |
||||
description = '' |
||||
List of peer IP addresses to connect to and |
||||
attempt to keep the connection open. |
||||
''; |
||||
}; |
||||
|
||||
exclusiveNodes = mkOption { |
||||
type = types.listOf types.str; |
||||
default = [ ]; |
||||
description = '' |
||||
List of peer IP addresses to connect to *only*. |
||||
If given the other peer options will be ignored. |
||||
''; |
||||
}; |
||||
|
||||
extraConfig = mkOption { |
||||
type = types.lines; |
||||
default = ""; |
||||
description = '' |
||||
Extra lines to be added verbatim to monerod configuration. |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
users.extraUsers = singleton { |
||||
name = "monero"; |
||||
uid = config.ids.uids.monero; |
||||
description = "Monero daemon user"; |
||||
home = dataDir; |
||||
createHome = true; |
||||
}; |
||||
|
||||
users.extraGroups = singleton { |
||||
name = "monero"; |
||||
gid = config.ids.gids.monero; |
||||
}; |
||||
|
||||
systemd.services.monero = { |
||||
description = "monero daemon"; |
||||
after = [ "network.target" ]; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
|
||||
serviceConfig = { |
||||
User = "monero"; |
||||
Group = "monero"; |
||||
ExecStart = "${pkgs.monero}/bin/monerod --config-file=${configFile} --non-interactive"; |
||||
Restart = "always"; |
||||
SuccessExitStatus = [ 0 1 ]; |
||||
}; |
||||
}; |
||||
|
||||
assertions = singleton { |
||||
assertion = cfg.mining.enable -> cfg.mining.address != ""; |
||||
message = '' |
||||
You need a Monero address to receive mining rewards: |
||||
specify one using option monero.mining.address. |
||||
''; |
||||
}; |
||||
|
||||
}; |
||||
|
||||
} |
||||
|
@ -0,0 +1,63 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.networking.rxe; |
||||
|
||||
runRxeCmd = cmd: ifcs: |
||||
concatStrings ( map (x: "${pkgs.rdma-core}/bin/rxe_cfg -n ${cmd} ${x};") ifcs); |
||||
|
||||
startScript = pkgs.writeShellScriptBin "rxe-start" '' |
||||
${pkgs.rdma-core}/bin/rxe_cfg -n start |
||||
${runRxeCmd "add" cfg.interfaces} |
||||
${pkgs.rdma-core}/bin/rxe_cfg |
||||
''; |
||||
|
||||
stopScript = pkgs.writeShellScriptBin "rxe-stop" '' |
||||
${runRxeCmd "remove" cfg.interfaces } |
||||
${pkgs.rdma-core}/bin/rxe_cfg -n stop |
||||
''; |
||||
|
||||
in { |
||||
###### interface |
||||
|
||||
options = { |
||||
networking.rxe = { |
||||
enable = mkEnableOption "RDMA over converged ethernet"; |
||||
interfaces = mkOption { |
||||
type = types.listOf types.str; |
||||
default = [ ]; |
||||
example = [ "eth0" ]; |
||||
description = '' |
||||
Enable RDMA on the listed interfaces. The corresponding virtual |
||||
RDMA interfaces will be named rxe0 ... rxeN where the ordering |
||||
will be as they are named in the list. UDP port 4791 must be |
||||
open on the respective ethernet interfaces. |
||||
''; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
|
||||
systemd.services.rxe = { |
||||
path = with pkgs; [ kmod rdma-core ]; |
||||
description = "RoCE interfaces"; |
||||
|
||||
wantedBy = [ "multi-user.target" ]; |
||||
after = [ "systemd-modules-load.service" "network-online.target" ]; |
||||
wants = [ "network-pre.target" ]; |
||||
|
||||
serviceConfig = { |
||||
Type = "oneshot"; |
||||
RemainAfterExit = true; |
||||
ExecStart = "${startScript}/bin/rxe-start"; |
||||
ExecStop = "${stopScript}/bin/rxe-stop"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
||||
|
@ -0,0 +1,46 @@ |
||||
import ./make-test.nix ({ pkgs, ... }: |
||||
|
||||
let |
||||
configDir = "/var/lib/foobar"; |
||||
|
||||
in { |
||||
name = "home-assistant"; |
||||
|
||||
nodes = { |
||||
hass = |
||||
{ config, pkgs, ... }: |
||||
{ |
||||
services.home-assistant = { |
||||
inherit configDir; |
||||
enable = true; |
||||
config = { |
||||
homeassistant = { |
||||
name = "Home"; |
||||
time_zone = "UTC"; |
||||
latitude = "0.0"; |
||||
longitude = "0.0"; |
||||
elevation = 0; |
||||
}; |
||||
frontend = { }; |
||||
http = { }; |
||||
}; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
startAll; |
||||
$hass->waitForUnit("home-assistant.service"); |
||||
|
||||
# Since config is specified using a Nix attribute set, |
||||
# configuration.yaml is a link to the Nix store |
||||
$hass->succeed("test -L ${configDir}/configuration.yaml"); |
||||
|
||||
# Check that Home Assistant's web interface and API can be reached |
||||
$hass->waitForOpenPort(8123); |
||||
$hass->succeed("curl --fail http://localhost:8123/states"); |
||||
$hass->succeed("curl --fail http://localhost:8123/api/ | grep 'API running'"); |
||||
|
||||
$hass->fail("cat ${configDir}/home-assistant.log | grep -qF ERROR"); |
||||
''; |
||||
}) |
@ -0,0 +1,30 @@ |
||||
import ./make-test.nix ({ pkgs, ... } : { |
||||
|
||||
name = "matrix-synapse"; |
||||
meta = with pkgs.stdenv.lib.maintainers; { |
||||
maintainers = [ corngood ]; |
||||
}; |
||||
|
||||
nodes = { |
||||
server_postgres = args: { |
||||
services.matrix-synapse.enable = true; |
||||
services.matrix-synapse.database_type = "psycopg2"; |
||||
}; |
||||
|
||||
server_sqlite = args: { |
||||
services.matrix-synapse.enable = true; |
||||
services.matrix-synapse.database_type = "sqlite3"; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
startAll; |
||||
$server_postgres->waitForUnit("matrix-synapse.service"); |
||||
$server_postgres->waitUntilSucceeds("curl -Lk https://localhost:8448/"); |
||||
$server_postgres->requireActiveUnit("postgresql.service"); |
||||
$server_sqlite->waitForUnit("matrix-synapse.service"); |
||||
$server_sqlite->waitUntilSucceeds("curl -Lk https://localhost:8448/"); |
||||
$server_sqlite->mustSucceed("[ -e /var/lib/matrix-synapse/homeserver.db ]"); |
||||
''; |
||||
|
||||
}) |
@ -0,0 +1,27 @@ |
||||
{ system ? builtins.currentSystem |
||||
, pkgs ? import ../.. { inherit system; } |
||||
}: |
||||
with import ../lib/testing.nix { inherit system; }; |
||||
let boolToString = x: if x then "yes" else "no"; in |
||||
let testWhenSetTo = predictable: withNetworkd: |
||||
makeTest { |
||||
name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}"; |
||||
meta = {}; |
||||
|
||||
machine = { config, pkgs, ... }: { |
||||
networking.usePredictableInterfaceNames = pkgs.stdenv.lib.mkForce predictable; |
||||
networking.useNetworkd = withNetworkd; |
||||
networking.dhcpcd.enable = !withNetworkd; |
||||
}; |
||||
|
||||
testScript = '' |
||||
print $machine->succeed("ip link"); |
||||
$machine->succeed("ip link show ${if predictable then "ens3" else "eth0"}"); |
||||
$machine->fail("ip link show ${if predictable then "eth0" else "ens3"}"); |
||||
''; |
||||
}; in |
||||
with pkgs.stdenv.lib.lists; |
||||
with pkgs.stdenv.lib.attrsets; |
||||
listToAttrs (map (drv: nameValuePair drv.name drv) ( |
||||
crossLists testWhenSetTo [[true false] [true false]] |
||||
)) |
@ -0,0 +1,140 @@ |
||||
{ system ? builtins.currentSystem }: |
||||
with import ../lib/testing.nix { inherit system; }; |
||||
with pkgs.lib; |
||||
let |
||||
initMachine = '' |
||||
startAll |
||||
$machine->waitForUnit("rspamd.service"); |
||||
$machine->succeed("id \"rspamd\" >/dev/null"); |
||||
''; |
||||
checkSocket = socket: user: group: mode: '' |
||||
$machine->succeed("ls ${socket} >/dev/null"); |
||||
$machine->succeed("[[ \"\$(stat -c %U ${socket})\" == \"${user}\" ]]"); |
||||
$machine->succeed("[[ \"\$(stat -c %G ${socket})\" == \"${group}\" ]]"); |
||||
$machine->succeed("[[ \"\$(stat -c %a ${socket})\" == \"${mode}\" ]]"); |
||||
''; |
||||
simple = name: socketActivation: enableIPv6: makeTest { |
||||
name = "rspamd-${name}"; |
||||
machine = { |
||||
services.rspamd = { |
||||
enable = true; |
||||
socketActivation = socketActivation; |
||||
}; |
||||
networking.enableIPv6 = enableIPv6; |
||||
}; |
||||
testScript = '' |
||||
startAll |
||||
$machine->waitForUnit("multi-user.target"); |
||||
$machine->waitForOpenPort(11334); |
||||
$machine->waitForUnit("rspamd.service"); |
||||
$machine->succeed("id \"rspamd\" >/dev/null"); |
||||
${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" } |
||||
sleep 10; |
||||
$machine->log($machine->succeed("cat /etc/rspamd.conf")); |
||||
$machine->log($machine->succeed("systemctl cat rspamd.service")); |
||||
${if socketActivation then '' |
||||
$machine->log($machine->succeed("systemctl cat rspamd-controller-1.socket")); |
||||
$machine->log($machine->succeed("systemctl cat rspamd-normal-1.socket")); |
||||
'' else '' |
||||
$machine->fail("systemctl cat rspamd-controller-1.socket"); |
||||
$machine->fail("systemctl cat rspamd-normal-1.socket"); |
||||
''} |
||||
$machine->log($machine->succeed("curl http://localhost:11334/auth")); |
||||
$machine->log($machine->succeed("curl http://127.0.0.1:11334/auth")); |
||||
${optionalString enableIPv6 '' |
||||
$machine->log($machine->succeed("curl http://[::1]:11334/auth")); |
||||
''} |
||||
''; |
||||
}; |
||||
in |
||||
{ |
||||
simple = simple "simple" false true; |
||||
ipv4only = simple "ipv4only" false false; |
||||
simple-socketActivated = simple "simple-socketActivated" true true; |
||||
ipv4only-socketActivated = simple "ipv4only-socketActivated" true false; |
||||
deprecated = makeTest { |
||||
name = "rspamd-deprecated"; |
||||
machine = { |
||||
services.rspamd = { |
||||
enable = true; |
||||
bindSocket = [ "/run/rspamd.sock mode=0600 user=root group=root" ]; |
||||
bindUISocket = [ "/run/rspamd-worker.sock mode=0666 user=root group=root" ]; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
${initMachine} |
||||
$machine->waitForFile("/run/rspamd.sock"); |
||||
${checkSocket "/run/rspamd.sock" "root" "root" "600" } |
||||
${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } |
||||
$machine->log($machine->succeed("cat /etc/rspamd.conf")); |
||||
$machine->fail("systemctl cat rspamd-normal-1.socket"); |
||||
$machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); |
||||
$machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); |
||||
''; |
||||
}; |
||||
|
||||
bindports = makeTest { |
||||
name = "rspamd-bindports"; |
||||
machine = { |
||||
services.rspamd = { |
||||
enable = true; |
||||
socketActivation = false; |
||||
workers.normal.bindSockets = [{ |
||||
socket = "/run/rspamd.sock"; |
||||
mode = "0600"; |
||||
owner = "root"; |
||||
group = "root"; |
||||
}]; |
||||
workers.controller.bindSockets = [{ |
||||
socket = "/run/rspamd-worker.sock"; |
||||
mode = "0666"; |
||||
owner = "root"; |
||||
group = "root"; |
||||
}]; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
${initMachine} |
||||
$machine->waitForFile("/run/rspamd.sock"); |
||||
${checkSocket "/run/rspamd.sock" "root" "root" "600" } |
||||
${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } |
||||
$machine->log($machine->succeed("cat /etc/rspamd.conf")); |
||||
$machine->fail("systemctl cat rspamd-normal-1.socket"); |
||||
$machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); |
||||
$machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); |
||||
''; |
||||
}; |
||||
socketActivated = makeTest { |
||||
name = "rspamd-socketActivated"; |
||||
machine = { |
||||
services.rspamd = { |
||||
enable = true; |
||||
workers.normal.bindSockets = [{ |
||||
socket = "/run/rspamd.sock"; |
||||
mode = "0600"; |
||||
owner = "root"; |
||||
group = "root"; |
||||
}]; |
||||
workers.controller.bindSockets = [{ |
||||
socket = "/run/rspamd-worker.sock"; |
||||
mode = "0666"; |
||||
owner = "root"; |
||||
group = "root"; |
||||
}]; |
||||
}; |
||||
}; |
||||
|
||||
testScript = '' |
||||
startAll |
||||
$machine->waitForFile("/run/rspamd.sock"); |
||||
${checkSocket "/run/rspamd.sock" "root" "root" "600" } |
||||
${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } |
||||
$machine->log($machine->succeed("cat /etc/rspamd.conf")); |
||||
$machine->log($machine->succeed("systemctl cat rspamd-normal-1.socket")); |
||||
$machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); |
||||
$machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); |
||||
''; |
||||
}; |
||||
} |
@ -0,0 +1,53 @@ |
||||
import ./make-test.nix ({ pkgs, ... } : |
||||
|
||||
let |
||||
node = { config, pkgs, lib, ... } : { |
||||
networking = { |
||||
firewall = { |
||||
allowedUDPPorts = [ 4791 ]; # open RoCE port |
||||
allowedTCPPorts = [ 4800 ]; # port for test utils |
||||
}; |
||||
rxe = { |
||||
enable = true; |
||||
interfaces = [ "eth1" ]; |
||||
}; |
||||
}; |
||||
|
||||
environment.systemPackages = with pkgs; [ rdma-core screen ]; |
||||
}; |
||||
|
||||
in { |
||||
name = "rxe"; |
||||
|
||||
nodes = { |
||||
server = node; |
||||
client = node; |
||||
}; |
||||
|
||||
testScript = '' |
||||
# Test if rxe interface comes up |
||||
$server->waitForUnit("default.target"); |
||||
$server->succeed("systemctl status rxe.service"); |
||||
$server->succeed("ibv_devices | grep rxe0"); |
||||
|
||||
$client->waitForUnit("default.target"); |
||||
|
||||
# ping pong test |
||||
$server->succeed("screen -dmS rc_pingpong ibv_rc_pingpong -p 4800 -g0"); |
||||
$client->succeed("sleep 2; ibv_rc_pingpong -p 4800 -g0 server"); |
||||
|
||||
$server->succeed("screen -dmS uc_pingpong ibv_uc_pingpong -p 4800 -g0"); |
||||
$client->succeed("sleep 2; ibv_uc_pingpong -p 4800 -g0 server"); |
||||
|
||||
$server->succeed("screen -dmS ud_pingpong ibv_ud_pingpong -p 4800 -s 1024 -g0"); |
||||
$client->succeed("sleep 2; ibv_ud_pingpong -p 4800 -s 1024 -g0 server"); |
||||
|
||||
$server->succeed("screen -dmS srq_pingpong ibv_srq_pingpong -p 4800 -g0"); |
||||
$client->succeed("sleep 2; ibv_srq_pingpong -p 4800 -g0 server"); |
||||
|
||||
$server->succeed("screen -dmS rping rping -s -a server -C 10"); |
||||
$client->succeed("sleep 2; rping -c -a server -C 10"); |
||||
''; |
||||
}) |
||||
|
||||
|
@ -0,0 +1,25 @@ |
||||
import ./make-test.nix ({ pkgs, lib }: |
||||
|
||||
with lib; |
||||
|
||||
{ |
||||
name = "yabar"; |
||||
meta = with pkgs.stdenv.lib.maintainers; { |
||||
maintainers = [ ma27 ]; |
||||
}; |
||||
|
||||
nodes.yabar = { |
||||
imports = [ ./common/x11.nix ./common/user-account.nix ]; |
||||
|
||||
services.xserver.displayManager.auto.user = "bob"; |
||||
|
||||
programs.yabar.enable = true; |
||||
}; |
||||
|
||||
testScript = '' |
||||
$yabar->start; |
||||
$yabar->waitForX; |
||||
|
||||
$yabar->waitForUnit("yabar.service", "bob"); |
||||
''; |
||||
}) |
@ -0,0 +1,27 @@ |
||||
{ lib, stdenv, fetchFromGitHub, cmake, pkgconfig, unbound, openssl, boost |
||||
, libunwind, lmdb, miniupnpc, readline }: |
||||
|
||||
stdenv.mkDerivation rec { |
||||
name = "dero-${version}"; |
||||
version = "0.11.3"; |
||||
|
||||
src = fetchFromGitHub { |
||||
owner = "deroproject"; |
||||
repo = "dero"; |
||||
rev = "v${version}"; |
||||
sha256 = "0cv4yg2lkmkdhlc3753gnbg1nzldk2kxwdyizwhvanq3ycqban4b"; |
||||
}; |
||||
|
||||
nativeBuildInputs = [ cmake pkgconfig ]; |
||||
buildInputs = [ boost miniupnpc openssl lmdb unbound readline ]; |
||||
|
||||
enableParallelBuilding = true; |
||||
|
||||
meta = with lib; { |
||||
description = "Secure, private blockchain with smart contracts based on Monero"; |
||||
homepage = "https://dero.io/"; |
||||
license = licenses.bsd3; |
||||
maintainers = with maintainers; [ fpletz ]; |
||||
platforms = platforms.linux; |
||||
}; |
||||
} |
@ -0,0 +1,35 @@ |
||||
{ lib, stdenv, fetchFromGitHub, cmake, unbound, openssl, boost |
||||
, libunwind, lmdb, miniupnpc }: |
||||
|
||||
stdenv.mkDerivation rec { |
||||
name = "sumokoin-${version}"; |
||||
version = "0.2.0.0"; |
||||
|
||||
src = fetchFromGitHub { |
||||
owner = "sumoprojects"; |
||||
repo = "sumokoin"; |
||||
rev = "v${version}"; |
||||
sha256 = "0ndgcawhxh3qb3llrrilrwzhs36qpxv7f53rxgcansbff9b3za6n"; |
||||
}; |
||||
|
||||
nativeBuildInputs = [ cmake ]; |
||||
buildInputs = [ unbound openssl boost libunwind lmdb miniupnpc ]; |
||||
|
||||
postPatch = '' |
||||
substituteInPlace src/blockchain_db/lmdb/db_lmdb.cpp --replace mdb_size_t size_t |
||||
''; |
||||
|
||||
cmakeFlags = [ |
||||
"-DLMDB_INCLUDE=${lmdb}/include" |
||||
]; |
||||
|
||||
enableParallelBuilding = true; |
||||
|
||||
meta = with lib; { |
||||
description = "Sumokoin is a fork of Monero and a truely fungible cryptocurrency"; |
||||
homepage = "https://www.sumokoin.org/"; |
||||
license = licenses.bsd3; |
||||
maintainers = with maintainers; [ fpletz ]; |
||||
platforms = platforms.linux; |
||||
}; |
||||
} |
@ -0,0 +1,37 @@ |
||||
{ stdenv, fetchFromGitHub, pkgconfig, cairomm, cmake, lv2, libpthreadstubs, libXdmcp, libXft, ntk, pcre, fftwFloat, zita-resampler }: |
||||
|
||||
stdenv.mkDerivation rec { |
||||
name = "infamousPlugins-v${version}"; |
||||
version = "0.2.04"; |
||||
|
||||
src = fetchFromGitHub { |
||||
owner = "ssj71"; |
||||
repo = "infamousPlugins"; |
||||
rev = "v${version}"; |
||||
sha256 = "0hmqk80w4qxq09iag7b7srf2g0wigkyhzq0ywxvhz2iz0hq9k0dh"; |
||||
}; |
||||
|
||||
nativeBuildInputs = [ pkgconfig cmake ]; |
||||
buildInputs = [ cairomm lv2 libpthreadstubs libXdmcp libXft ntk pcre fftwFloat zita-resampler ]; |
||||
|
||||
meta = with stdenv.lib; { |
||||
homepage = https://ssj71.github.io/infamousPlugins; |
||||
description = "A collection of open-source LV2 plugins"; |
||||
longDescription = '' |
||||
These are audio plugins in the LV2 format, developed for linux. Most are suitable for live use. |
||||
This collection contains: |
||||
* Cellular Automaton Synth - additive synthesizer, where 16 harmonics are added according to rules of elementary cellular automata |
||||
* Envelope Follower - a fully featured envelope follower plugin |
||||
* Hip2B - a distortion/destroyer plugin |
||||
* cheap distortion - another distortion plugin, but this one I wanted to get it as light as possible |
||||
* stuck - a clone of the electro-harmonix freeze |
||||
* power cut - this effect is commonly called tape stop |
||||
* power up - the opposite of the power cut |
||||
* ewham - a whammy style pitchshifter |
||||
* lushlife - a simulated double tracking plugin capable of everything from a thin beatle effect to thick lush choruses to weird outlandish effects |
||||
''; |
||||
license = licenses.gpl2; |
||||
maintainers = [ maintainers.magnetophon ]; |
||||
platforms = platforms.linux; |
||||
}; |
||||
} |
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue