Merge branch 'master' into add/hashdeep-package

This commit is contained in:
Domen Kožar 2020-03-20 11:51:25 +01:00 committed by GitHub
commit a28e401fd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1522 changed files with 48733 additions and 26791 deletions

View File

@ -235,5 +235,5 @@ package manager uses. To update the expressions run the `generate.sh` script
that is stored in the `pkgs/development/mobile/androidenv/` sub directory: that is stored in the `pkgs/development/mobile/androidenv/` sub directory:
```bash ```bash
sh ./generate.sh ./generate.sh
``` ```

View File

@ -233,7 +233,7 @@ mkDerivation {
</term> </term>
<listitem> <listitem>
<para> <para>
You can rely on applications depending on the library set the necessary environment variables but that it often easy to miss. Instead we recommend to patch the paths in the source code whenever possible. Here are some examples: You can rely on applications depending on the library setting the necessary environment variables but that is often easy to miss. Instead we recommend to patch the paths in the source code whenever possible. Here are some examples:
<itemizedlist> <itemizedlist>
<listitem xml:id="ssec-gnome-common-issues-unwrappable-package-gnome-shell-ext"> <listitem xml:id="ssec-gnome-common-issues-unwrappable-package-gnome-shell-ext">
<para> <para>

View File

@ -53,14 +53,16 @@ all crate sources of this package. Currently it is obtained by inserting a
fake checksum into the expression and building the package once. The correct fake checksum into the expression and building the package once. The correct
checksum can be then take from the failed build. checksum can be then take from the failed build.
When the `Cargo.lock`, provided by upstream, is not in sync with the Per the instructions in the [Cargo Book](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html)
`Cargo.toml`, it is possible to use `cargoPatches` to update it. All patches best practices guide, Rust applications should always commit the `Cargo.lock`
added in `cargoPatches` will also be prepended to the patches in `patches` at file in git to ensure a reproducible build. However, a few packages do not, and
build-time. Nix depends on this file, so if it missing you can use `cargoPatches` to apply
it in the `patchPhase`. Consider sending a PR upstream with a note to the
maintainer describing why it's important to include in the application.
Unless `legacyCargoFetcher` is set to `true`, the fetcher will also verify that The fetcher will verify that the `Cargo.lock` file is in sync with the `src`
the `Cargo.lock` file is in sync with the `src` attribute, and will compress the attribute, and fail the build if not. It will also will compress the vendor
vendor directory into a tar.gz archive. directory into a tar.gz archive.
### Building a crate for a different target ### Building a crate for a different target

View File

@ -131,7 +131,12 @@ rec {
origArgs = auto // args; origArgs = auto // args;
pkgs = f origArgs; pkgs = f origArgs;
mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs; mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
in lib.mapAttrs mkAttrOverridable pkgs; in
if lib.isDerivation pkgs then throw
("function `callPackages` was called on a *single* derivation "
+ ''"${pkgs.name or "<unknown-name>"}";''
+ " did you mean to use `callPackage` instead?")
else lib.mapAttrs mkAttrOverridable pkgs;
/* Add attributes to each output of a derivation without changing /* Add attributes to each output of a derivation without changing

View File

@ -24,6 +24,7 @@ let
# packaging # packaging
customisation = callLibs ./customisation.nix; customisation = callLibs ./customisation.nix;
maintainers = import ../maintainers/maintainer-list.nix; maintainers = import ../maintainers/maintainer-list.nix;
teams = callLibs ../maintainers/team-list.nix;
meta = callLibs ./meta.nix; meta = callLibs ./meta.nix;
sources = callLibs ./sources.nix; sources = callLibs ./sources.nix;
versions = callLibs ./versions.nix; versions = callLibs ./versions.nix;
@ -55,6 +56,9 @@ let
# back-compat aliases # back-compat aliases
platforms = systems.doubles; platforms = systems.doubles;
# linux kernel configuration
kernel = callLibs ./kernel.nix;
inherit (builtins) add addErrorContext attrNames concatLists inherit (builtins) add addErrorContext attrNames concatLists
deepSeq elem elemAt filter genericClosure genList getAttr deepSeq elem elemAt filter genericClosure genList getAttr
hasAttr head isAttrs isBool isInt isList isString length hasAttr head isAttrs isBool isInt isList isString length

View File

@ -76,10 +76,14 @@ rec {
* mkKeyValue is the same as in toINI. * mkKeyValue is the same as in toINI.
*/ */
toKeyValue = { toKeyValue = {
mkKeyValue ? mkKeyValueDefault {} "=" mkKeyValue ? mkKeyValueDefault {} "=",
}: attrs: listsAsDuplicateKeys ? false
}:
let mkLine = k: v: mkKeyValue k v + "\n"; let mkLine = k: v: mkKeyValue k v + "\n";
in libStr.concatStrings (libAttr.mapAttrsToList mkLine attrs); mkLines = if listsAsDuplicateKeys
then k: v: map (mkLine k) (if lib.isList v then v else [v])
else k: v: [ (mkLine k v) ];
in attrs: libStr.concatStrings (lib.concatLists (libAttr.mapAttrsToList mkLines attrs));
/* Generate an INI-style config file from an /* Generate an INI-style config file from an
@ -106,7 +110,9 @@ rec {
# apply transformations (e.g. escapes) to section names # apply transformations (e.g. escapes) to section names
mkSectionName ? (name: libStr.escape [ "[" "]" ] name), mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
# format a setting line from key and value # format a setting line from key and value
mkKeyValue ? mkKeyValueDefault {} "=" mkKeyValue ? mkKeyValueDefault {} "=",
# allow lists as values for duplicate keys
listsAsDuplicateKeys ? false
}: attrsOfAttrs: }: attrsOfAttrs:
let let
# map function to string for each key val # map function to string for each key val
@ -115,7 +121,7 @@ rec {
(libAttr.mapAttrsToList mapFn attrs); (libAttr.mapAttrsToList mapFn attrs);
mkSection = sectName: sectValues: '' mkSection = sectName: sectValues: ''
[${mkSectionName sectName}] [${mkSectionName sectName}]
'' + toKeyValue { inherit mkKeyValue; } sectValues; '' + toKeyValue { inherit mkKeyValue listsAsDuplicateKeys; } sectValues;
in in
# map input to ini sections # map input to ini sections
mapAttrsToStringsSep "\n" mkSection attrsOfAttrs; mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;

View File

@ -1,12 +1,7 @@
{ lib, version }: { lib }:
with lib; with lib;
{ {
# Common patterns/legacy
whenAtLeast = ver: mkIf (versionAtLeast version ver);
whenOlder = ver: mkIf (versionOlder version ver);
# range is (inclusive, exclusive)
whenBetween = verLow: verHigh: mkIf (versionAtLeast version verLow && versionOlder version verHigh);
# Keeping these around in case we decide to change this horrible implementation :) # Keeping these around in case we decide to change this horrible implementation :)
@ -18,4 +13,14 @@ with lib;
module = { tristate = "m"; }; module = { tristate = "m"; };
freeform = x: { freeform = x; }; freeform = x: { freeform = x; };
/*
Common patterns/legacy used in common-config/hardened-config.nix
*/
whenHelpers = version: {
whenAtLeast = ver: mkIf (versionAtLeast version ver);
whenOlder = ver: mkIf (versionOlder version ver);
# range is (inclusive, exclusive)
whenBetween = verLow: verHigh: mkIf (versionAtLeast version verLow && versionOlder version verHigh);
};
} }

View File

@ -93,7 +93,11 @@ rec {
res set._definedNames res set._definedNames
else else
res; res;
result = { inherit options config; }; result = {
inherit options;
config = removeAttrs config [ "_module" ];
inherit (config) _module;
};
in result; in result;
# collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ] # collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
@ -389,7 +393,7 @@ rec {
let let
# Process mkMerge and mkIf properties. # Process mkMerge and mkIf properties.
defs' = concatMap (m: defs' = concatMap (m:
map (value: { inherit (m) file; inherit value; }) (dischargeProperties m.value) map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
) defs; ) defs;
# Process mkOverride properties. # Process mkOverride properties.
@ -410,10 +414,9 @@ rec {
# Type-check the remaining definitions, and merge them. Or throw if no definitions. # Type-check the remaining definitions, and merge them. Or throw if no definitions.
mergedValue = mergedValue =
if isDefined then if isDefined then
foldl' (res: def: if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
if type.check def.value then res else let firstInvalid = findFirst (def: ! type.check def.value) null defsFinal;
else throw "The option value `${showOption loc}' in `${def.file}' is not of type `${type.description}'." in throw "The option value `${showOption loc}' in `${firstInvalid.file}' is not of type `${type.description}'."
) (type.merge loc defsFinal) defsFinal
else else
# (nixos-option detects this specific error message and gives it special # (nixos-option detects this specific error message and gives it special
# handling. If changed here, please change it there too.) # handling. If changed here, please change it there too.)

View File

@ -159,7 +159,7 @@ rec {
let ss = opt.type.getSubOptions opt.loc; let ss = opt.type.getSubOptions opt.loc;
in if ss != {} then optionAttrSetToDocList' opt.loc ss else []; in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
in in
[ docOption ] ++ subOptions) (collect isOption options); [ docOption ] ++ optionals docOption.visible subOptions) (collect isOption options);
/* This function recursively removes all derivation attributes from /* This function recursively removes all derivation attributes from

View File

@ -26,7 +26,13 @@ let
"riscv32-linux" "riscv64-linux" "riscv32-linux" "riscv64-linux"
"aarch64-none" "avr-none" "arm-none" "i686-none" "x86_64-none" "powerpc-none" "msp430-none" "riscv64-none" "riscv32-none" "vc4-none" "arm-none" "armv6l-none" "aarch64-none"
"avr-none"
"i686-none" "x86_64-none"
"powerpc-none"
"msp430-none"
"riscv64-none" "riscv32-none"
"vc4-none"
"js-ghcjs" "js-ghcjs"
]; ];

View File

@ -348,6 +348,18 @@ runTests {
''; '';
}; };
testToINIDuplicateKeys = {
expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; };
expected = ''
[baz]
qux=1
qux=false
[foo]
bar=true
'';
};
testToINIDefaultEscapes = { testToINIDefaultEscapes = {
expr = generators.toINI {} { expr = generators.toINI {} {
"no [ and ] allowed unescaped" = { "no [ and ] allowed unescaped" = {

View File

@ -185,6 +185,14 @@ checkConfigError 'The option .* defined in .* does not exist' config.enable ./di
# Check that imports can depend on derivations # Check that imports can depend on derivations
checkConfigOutput "true" config.enable ./import-from-store.nix checkConfigOutput "true" config.enable ./import-from-store.nix
# Check that configs can be conditional on option existence
checkConfigOutput true config.enable ./define-option-dependently.nix ./declare-enable.nix ./declare-int-positive-value.nix
checkConfigOutput 360 config.value ./define-option-dependently.nix ./declare-enable.nix ./declare-int-positive-value.nix
checkConfigOutput 7 config.value ./define-option-dependently.nix ./declare-int-positive-value.nix
checkConfigOutput true config.set.enable ./define-option-dependently-nested.nix ./declare-enable-nested.nix ./declare-int-positive-value-nested.nix
checkConfigOutput 360 config.set.value ./define-option-dependently-nested.nix ./declare-enable-nested.nix ./declare-int-positive-value-nested.nix
checkConfigOutput 7 config.set.value ./define-option-dependently-nested.nix ./declare-int-positive-value-nested.nix
# Check attrsOf and lazyAttrsOf. Only lazyAttrsOf should be lazy, and only # Check attrsOf and lazyAttrsOf. Only lazyAttrsOf should be lazy, and only
# attrsOf should work with conditional definitions # attrsOf should work with conditional definitions
# In addition, lazyAttrsOf should honor an options emptyValue # In addition, lazyAttrsOf should honor an options emptyValue
@ -194,6 +202,11 @@ checkConfigOutput "true" config.conditionalWorks ./declare-attrsOf.nix ./attrsOf
checkConfigOutput "false" config.conditionalWorks ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix checkConfigOutput "false" config.conditionalWorks ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix
checkConfigOutput "empty" config.value.foo ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix checkConfigOutput "empty" config.value.foo ./declare-lazyAttrsOf.nix ./attrsOf-conditional-check.nix
# Even with multiple assignments, a type error should be thrown if any of them aren't valid
checkConfigError 'The option value .* in .* is not of type .*' \
config.value ./declare-int-unsigned-value.nix ./define-value-list.nix ./define-value-int-positive.nix
cat <<EOF cat <<EOF
====== module tests ====== ====== module tests ======
$pass Pass $pass Pass

View File

@ -0,0 +1,14 @@
{ lib, ... }:
{
options.set = {
enable = lib.mkOption {
default = false;
example = true;
type = lib.types.bool;
description = ''
Some descriptive text
'';
};
};
}

View File

@ -0,0 +1,9 @@
{ lib, ... }:
{
options.set = {
value = lib.mkOption {
type = lib.types.ints.positive;
};
};
}

View File

@ -0,0 +1,16 @@
{ lib, options, ... }:
# Some modules may be distributed separately and need to adapt to other modules
# that are distributed and versioned separately.
{
# Always defined, but the value depends on the presence of an option.
config.set = {
value = if options ? set.enable then 360 else 7;
}
# Only define if possible.
// lib.optionalAttrs (options ? set.enable) {
enable = true;
};
}

View File

@ -0,0 +1,16 @@
{ lib, options, ... }:
# Some modules may be distributed separately and need to adapt to other modules
# that are distributed and versioned separately.
{
# Always defined, but the value depends on the presence of an option.
config = {
value = if options ? enable then 360 else 7;
}
# Only define if possible.
// lib.optionalAttrs (options ? enable) {
enable = true;
};
}

View File

@ -14,7 +14,7 @@ let
in with lib.systems.doubles; lib.runTests { in with lib.systems.doubles; lib.runTests {
testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ wasi ++ windows ++ embedded ++ js); testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ wasi ++ windows ++ embedded ++ js);
testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7a-linux" "armv7l-linux" "arm-none" "armv7a-darwin" ]; testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv6l-none" "armv7a-linux" "armv7l-linux" "arm-none" "armv7a-darwin" ];
testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" "i686-none" "i686-darwin" ]; testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" "i686-none" "i686-darwin" ];
testmips = mseteq mips [ "mipsel-linux" ]; testmips = mseteq mips [ "mipsel-linux" ];
testx86_64 = mseteq x86_64 [ "x86_64-linux" "x86_64-darwin" "x86_64-freebsd" "x86_64-openbsd" "x86_64-netbsd" "x86_64-cygwin" "x86_64-solaris" "x86_64-windows" "x86_64-none" ]; testx86_64 = mseteq x86_64 [ "x86_64-linux" "x86_64-darwin" "x86_64-freebsd" "x86_64-openbsd" "x86_64-netbsd" "x86_64-cygwin" "x86_64-solaris" "x86_64-windows" "x86_64-none" ];

View File

@ -1,5 +1,5 @@
/* List of NixOS maintainers. /* List of NixOS maintainers.
```nix
handle = { handle = {
# Required # Required
name = "Your name"; name = "Your name";
@ -13,6 +13,7 @@
fingerprint = "AAAA BBBB CCCC DDDD EEEE FFFF 0000 1111 2222 3333"; fingerprint = "AAAA BBBB CCCC DDDD EEEE FFFF 0000 1111 2222 3333";
}]; }];
}; };
```
where where
@ -38,7 +39,7 @@
Please keep the list alphabetically sorted. Please keep the list alphabetically sorted.
See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data. See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data.
*/ */
{ {
"0x4A6F" = { "0x4A6F" = {
email = "0x4A6F@shackspace.de"; email = "0x4A6F@shackspace.de";
@ -710,6 +711,12 @@
githubId = 55833; githubId = 55833;
name = "Troels Henriksen"; name = "Troels Henriksen";
}; };
atkinschang = {
email = "atkinschang+nixpkgs@gmail.com";
github = "AtkinsChang";
githubId = 5193600;
name = "Atkins Chang";
};
atnnn = { atnnn = {
email = "etienne@atnnn.com"; email = "etienne@atnnn.com";
github = "atnnn"; github = "atnnn";
@ -1461,6 +1468,16 @@
githubId = 5684605; githubId = 5684605;
name = "Cole Scott"; name = "Cole Scott";
}; };
cole-h = {
name = "Cole Helbling";
email = "cole.e.helbling@outlook.com";
github = "cole-h";
githubId = 28582702;
keys = [{
longkeyid = "rsa4096/0xB37E0F2371016A4C";
fingerprint = "68B8 0D57 B2E5 4AC3 EC1F 49B0 B37E 0F23 7101 6A4C";
}];
};
copumpkin = { copumpkin = {
email = "pumpkingod@gmail.com"; email = "pumpkingod@gmail.com";
github = "copumpkin"; github = "copumpkin";
@ -1562,10 +1579,12 @@
githubId = 2217136; githubId = 2217136;
name = "Ștefan D. Mihăilă"; name = "Ștefan D. Mihăilă";
keys = [ keys = [
{ longkeyid = "rsa4096/6E68A39BF16A3ECB"; {
longkeyid = "rsa4096/6E68A39BF16A3ECB";
fingerprint = "CBC9 C7CC 51F0 4A61 3901 C723 6E68 A39B F16A 3ECB"; fingerprint = "CBC9 C7CC 51F0 4A61 3901 C723 6E68 A39B F16A 3ECB";
} }
{ longkeyid = "rsa4096/6220AD7846220A52"; {
longkeyid = "rsa4096/6220AD7846220A52";
fingerprint = "7EAB 1447 5BBA 7DDE 7092 7276 6220 AD78 4622 0A52"; fingerprint = "7EAB 1447 5BBA 7DDE 7092 7276 6220 AD78 4622 0A52";
} }
]; ];
@ -1782,7 +1801,7 @@
name = "Didier J. Devroye"; name = "Didier J. Devroye";
}; };
devhell = { devhell = {
email = "\"^\"@regexmail.net"; email = ''"^"@regexmail.net'';
github = "devhell"; github = "devhell";
githubId = 896182; githubId = 896182;
name = "devhell"; name = "devhell";
@ -1948,7 +1967,7 @@
drewrisinger = { drewrisinger = {
email = "drisinger+nixpkgs@gmail.com"; email = "drisinger+nixpkgs@gmail.com";
github = "drewrisinger"; github = "drewrisinger";
gitHubId = 10198051; githubId = 10198051;
name = "Drew Risinger"; name = "Drew Risinger";
}; };
dsferruzza = { dsferruzza = {
@ -2121,7 +2140,7 @@
}; };
ehmry = { ehmry = {
email = "ehmry@posteo.net"; email = "ehmry@posteo.net";
github= "ehmry"; github = "ehmry";
githubId = 537775; githubId = 537775;
name = "Emery Hemingway"; name = "Emery Hemingway";
}; };
@ -2735,6 +2754,12 @@
githubId = 3217744; githubId = 3217744;
name = "Peter Ferenczy"; name = "Peter Ferenczy";
}; };
gila = {
email = "jeffry.molanus@gmail.com";
github = "gila";
githubId = 15957973;
name = "Jeffry Molanus";
};
gilligan = { gilligan = {
email = "tobias.pflug@gmail.com"; email = "tobias.pflug@gmail.com";
github = "gilligan"; github = "gilligan";
@ -3086,6 +3111,12 @@
githubId = 4401220; githubId = 4401220;
name = "Michael Eden"; name = "Michael Eden";
}; };
illiusdope = {
email = "mat@marini.ca";
github = "illiusdope";
githubId = 61913481;
name = "Mat Marini";
};
ilya-fedin = { ilya-fedin = {
email = "fedin-ilja2010@ya.ru"; email = "fedin-ilja2010@ya.ru";
github = "ilya-fedin"; github = "ilya-fedin";
@ -3580,6 +3611,12 @@
github = "jorsn"; github = "jorsn";
githubId = 4646725; githubId = 4646725;
}; };
joshuafern = {
name = "Joshua Fern";
email = "joshuafern@protonmail.com";
github = "JoshuaFern";
githubId = 4300747;
};
jpas = { jpas = {
name = "Jarrod Pas"; name = "Jarrod Pas";
email = "jarrod@jarrodpas.com"; email = "jarrod@jarrodpas.com";
@ -3688,6 +3725,16 @@
githubId = 66669; githubId = 66669;
name = "Jeff Zellner"; name = "Jeff Zellner";
}; };
kaction = {
name = "Dmitry Bogatov";
email = "KAction@disroot.org";
github = "kaction";
githubId = 44864956;
key = [{
longkeyid = "ed25519/0x749FD4DFA2E94236";
fingerprint = "3F87 0A7C A7B4 3731 2F13 6083 749F D4DF A2E9 4236";
}];
};
kaiha = { kaiha = {
email = "kai.harries@gmail.com"; email = "kai.harries@gmail.com";
github = "kaiha"; github = "kaiha";
@ -4113,6 +4160,12 @@
github = "leonardoce"; github = "leonardoce";
name = "Leonardo Cecchi"; name = "Leonardo Cecchi";
}; };
leshainc = {
email = "leshainc@fomalhaut.me";
github = "LeshaInc";
githubId = 42153076;
name = "Alexey Nikashkin";
};
lethalman = { lethalman = {
email = "lucabru@src.gnome.org"; email = "lucabru@src.gnome.org";
github = "lethalman"; github = "lethalman";
@ -4125,6 +4178,16 @@
githubId = 3425311; githubId = 3425311;
name = "Antoine Eiche"; name = "Antoine Eiche";
}; };
lexuge = {
name = "Harry Ying";
email = "lexugeyky@outlook.com";
github = "LEXUGE";
githubId = 13804737;
keys = [{
longkeyid = "rsa4096/0xAE53B4C2E58EDD45";
fingerprint = "7FE2 113A A08B 695A C8B8 DDE6 AE53 B4C2 E58E DD45";
}];
};
lheckemann = { lheckemann = {
email = "git@sphalerite.org"; email = "git@sphalerite.org";
github = "lheckemann"; github = "lheckemann";
@ -4528,6 +4591,12 @@
githubId = 1711539; githubId = 1711539;
name = "matklad"; name = "matklad";
}; };
matt-snider = {
email = "matt.snider@protonmail.com";
github = "matt-snider";
githubId = 11810057;
name = "Matt Snider";
};
matthewbauer = { matthewbauer = {
email = "mjbauer95@gmail.com"; email = "mjbauer95@gmail.com";
github = "matthewbauer"; github = "matthewbauer";
@ -4562,6 +4631,12 @@
githubId = 1269099; githubId = 1269099;
name = "Marius Bakke"; name = "Marius Bakke";
}; };
mbaillie = {
email = "martin@baillie.email";
github = "martinbaillie";
githubId = 613740;
name = "Martin Baillie";
};
mbbx6spp = { mbbx6spp = {
email = "me@susanpotter.net"; email = "me@susanpotter.net";
github = "mbbx6spp"; github = "mbbx6spp";
@ -4868,11 +4943,11 @@
mmilata = { mmilata = {
email = "martin@martinmilata.cz"; email = "martin@martinmilata.cz";
github = "mmilata"; github = "mmilata";
gitHubId = 85857; githubId = 85857;
name = "Martin Milata"; name = "Martin Milata";
}; };
mmlb = { mmlb = {
email = "me.mmlb@mmlb.me"; email = "manny@peekaboo.mmlb.icu";
github = "mmlb"; github = "mmlb";
name = "Manuel Mendez"; name = "Manuel Mendez";
}; };
@ -4945,6 +5020,12 @@
githubId = 118035; githubId = 118035;
name = "Corbin Simpson"; name = "Corbin Simpson";
}; };
mothsart = {
email = "jerem.ferry@gmail.com";
github = "mothsart";
githubId = 10601196;
name = "Jérémie Ferry";
};
mounium = { mounium = {
email = "muoniurn@gmail.com"; email = "muoniurn@gmail.com";
github = "mounium"; github = "mounium";
@ -5482,6 +5563,12 @@
githubId = 11016164; githubId = 11016164;
name = "Fedor Pakhomov"; name = "Fedor Pakhomov";
}; };
paluh = {
email = "paluho@gmail.com";
github = "paluh";
githubId = 190249;
name = "Tomasz Rybarczyk";
};
pamplemousse = { pamplemousse = {
email = "xav.maso@gmail.com"; email = "xav.maso@gmail.com";
github = "Pamplemousse"; github = "Pamplemousse";
@ -5755,11 +5842,10 @@
github = "pradyuman"; github = "pradyuman";
githubId = 9904569; githubId = 9904569;
name = "Pradyuman Vig"; name = "Pradyuman Vig";
keys = [ keys = [{
{ longkeyid = "rsa4096/4F74D5361C4CA31E"; longkeyid = "rsa4096/4F74D5361C4CA31E";
fingerprint = "240B 57DE 4271 2480 7CE3 EAC8 4F74 D536 1C4C A31E"; fingerprint = "240B 57DE 4271 2480 7CE3 EAC8 4F74 D536 1C4C A31E";
} }];
];
}; };
prikhi = { prikhi = {
email = "pavan.rikhi@gmail.com"; email = "pavan.rikhi@gmail.com";
@ -5773,10 +5859,12 @@
githubId = 7537109; githubId = 7537109;
name = "Michael Weiss"; name = "Michael Weiss";
keys = [ keys = [
{ longkeyid = "ed25519/0x130826A6C2A389FD"; # Git only {
longkeyid = "ed25519/0x130826A6C2A389FD"; # Git only
fingerprint = "86A7 4A55 07D0 58D1 322E 37FD 1308 26A6 C2A3 89FD"; fingerprint = "86A7 4A55 07D0 58D1 322E 37FD 1308 26A6 C2A3 89FD";
} }
{ longkeyid = "rsa3072/0xBCA9943DD1DF4C04"; # Email, etc. {
longkeyid = "rsa3072/0xBCA9943DD1DF4C04"; # Email, etc.
fingerprint = "AF85 991C C950 49A2 4205 1933 BCA9 943D D1DF 4C04"; fingerprint = "AF85 991C C950 49A2 4205 1933 BCA9 943D D1DF 4C04";
} }
]; ];
@ -5871,6 +5959,12 @@
githubId = 4579165; githubId = 4579165;
name = "Danny Bautista"; name = "Danny Bautista";
}; };
peelz = {
email = "peelz.dev+nixpkgs@gmail.com";
github = "louistakepillz";
githubId = 920910;
name = "peelz";
};
q3k = { q3k = {
email = "q3k@q3k.org"; email = "q3k@q3k.org";
github = "q3k"; github = "q3k";
@ -6136,12 +6230,10 @@
github = "rnhmjoj"; github = "rnhmjoj";
githubId = 2817565; githubId = 2817565;
name = "Michele Guerini Rocco"; name = "Michele Guerini Rocco";
keys = keys = [{
[ longkeyid = "ed25519/0xBFBAF4C975F76450";
{ longkeyid = "ed25519/0xBFBAF4C975F76450";
fingerprint = "92B2 904F D293 C94D C4C9 3E6B BFBA F4C9 75F7 6450"; fingerprint = "92B2 904F D293 C94D C4C9 3E6B BFBA F4C9 75F7 6450";
} }];
];
}; };
rob = { rob = {
email = "rob.vermaas@gmail.com"; email = "rob.vermaas@gmail.com";
@ -6661,6 +6753,12 @@
githubId = 848812; githubId = 848812;
name = "Stephan Jau"; name = "Stephan Jau";
}; };
sjfloat = {
email = "steve+nixpkgs@jonescape.com";
github = "sjfloat";
githubId = 216167;
name = "Steve Jones";
};
sjmackenzie = { sjmackenzie = {
email = "setori88@gmail.com"; email = "setori88@gmail.com";
github = "sjmackenzie"; github = "sjmackenzie";
@ -7219,6 +7317,12 @@
githubId = 844343; githubId = 844343;
name = "Thiago K. Okada"; name = "Thiago K. Okada";
}; };
thmzlt = {
email = "git@thomazleite.com";
github = "thmzlt";
githubId = 7709;
name = "Thomaz Leite";
};
ThomasMader = { ThomasMader = {
email = "thomas.mader@gmail.com"; email = "thomas.mader@gmail.com";
github = "ThomasMader"; github = "ThomasMader";
@ -7294,10 +7398,10 @@
github = "tkerber"; github = "tkerber";
githubId = 5722198; githubId = 5722198;
name = "Thomas Kerber"; name = "Thomas Kerber";
keys = [ { keys = [{
longkeyid = "rsa4096/0x8489B911F9ED617B"; longkeyid = "rsa4096/0x8489B911F9ED617B";
fingerprint = "556A 403F B0A2 D423 F656 3424 8489 B911 F9ED 617B"; fingerprint = "556A 403F B0A2 D423 F656 3424 8489 B911 F9ED 617B";
} ]; }];
}; };
tmplt = { tmplt = {
email = "tmplt@dragons.rocks"; email = "tmplt@dragons.rocks";
@ -7577,7 +7681,8 @@
}; };
vcunat = { vcunat = {
name = "Vladimír Čunát"; name = "Vladimír Čunát";
email = "v@cunat.cz"; # vcunat@gmail.com predominated in commits before 2019/03 # vcunat@gmail.com predominated in commits before 2019/03
email = "v@cunat.cz";
github = "vcunat"; github = "vcunat";
githubId = 1785925; githubId = 1785925;
keys = [{ keys = [{

View File

@ -6,6 +6,7 @@ use warnings;
use CPAN::Meta(); use CPAN::Meta();
use CPANPLUS::Backend(); use CPANPLUS::Backend();
use Module::CoreList;
use Getopt::Long::Descriptive qw( describe_options ); use Getopt::Long::Descriptive qw( describe_options );
use JSON::PP qw( encode_json ); use JSON::PP qw( encode_json );
use Log::Log4perl qw(:easy); use Log::Log4perl qw(:easy);
@ -164,7 +165,7 @@ Readonly::Hash my %LICENSE_MAP => (
# License not provided in metadata. # License not provided in metadata.
unknown => { unknown => {
licenses => [qw( unknown )], licenses => [],
amb => 1 amb => 1
} }
); );
@ -278,14 +279,8 @@ sub get_deps {
foreach my $n ( $deps->required_modules ) { foreach my $n ( $deps->required_modules ) {
next if $n eq "perl"; next if $n eq "perl";
# Figure out whether the module is a core module by attempting my @core = Module::CoreList->find_modules(qr/^$n$/);
# to `use` the module in a pure Perl interpreter and checking next if (@core);
# whether it succeeded. Note, $^X is a magic variable holding
# the path to the running Perl interpreter.
if ( system("env -i $^X -M$n -e1 >/dev/null 2>&1") == 0 ) {
DEBUG("skipping Perl-builtin module $n");
next;
}
my $pkg = module_to_pkg( $cb, $n ); my $pkg = module_to_pkg( $cb, $n );

33
maintainers/team-list.nix Normal file
View File

@ -0,0 +1,33 @@
/* List of maintainer teams.
name = {
# Required
members = [ maintainer1 maintainer2 ];
scope = "Maintain foo packages.";
};
where
- `members` is the list of maintainers belonging to the group,
- `scope` describes the scope of the group.
More fields may be added in the future.
Please keep the list alphabetically sorted.
*/
{ lib }:
with lib.maintainers; {
freedesktop = {
members = [ jtojnar worldofpeace ];
scope = "Maintain Freedesktop.org packages for graphical desktop.";
};
gnome = {
members = [
hedning
jtojnar
worldofpeace
];
scope = "Maintain GNOME desktop environment and platform.";
};
}

View File

@ -21,7 +21,6 @@
<xi:include href="xfce.xml" /> <xi:include href="xfce.xml" />
<xi:include href="networking.xml" /> <xi:include href="networking.xml" />
<xi:include href="linux-kernel.xml" /> <xi:include href="linux-kernel.xml" />
<xi:include href="matrix.xml" />
<xi:include href="../generated/modules.xml" xpointer="xpointer(//section[@id='modules']/*)" /> <xi:include href="../generated/modules.xml" xpointer="xpointer(//section[@id='modules']/*)" />
<xi:include href="profiles.xml" /> <xi:include href="profiles.xml" />
<xi:include href="kubernetes.xml" /> <xi:include href="kubernetes.xml" />

View File

@ -154,7 +154,7 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
The <literal>99-main.network</literal> file was removed. Maching all The <literal>99-main.network</literal> file was removed. Matching all
network interfaces caused many breakages, see network interfaces caused many breakages, see
<link xlink:href="https://github.com/NixOS/nixpkgs/pull/18962">#18962</link> <link xlink:href="https://github.com/NixOS/nixpkgs/pull/18962">#18962</link>
and <link xlink:href="https://github.com/NixOS/nixpkgs/pull/71106">#71106</link>. and <link xlink:href="https://github.com/NixOS/nixpkgs/pull/71106">#71106</link>.
@ -196,10 +196,10 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
There is now only one Xfce package-set and module. This means attributes, <literal>xfce4-14</literal> There is now only one Xfce package-set and module. This means that attributes <literal>xfce4-14</literal>
<literal>xfce4-12</literal>, and <literal>xfceUnstable</literal> all now point to the latest Xfce 4.14 and <literal>xfceUnstable</literal> all now point to the latest Xfce 4.14
packages. And in future NixOS releases will be the latest released version of Xfce available at the packages. And in the future NixOS releases will be the latest released version of Xfce available at the
time during the releases development (if viable). time of the release's development (if viable).
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -235,7 +235,7 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
<listitem> <listitem>
<para> <para>
The <literal>buildRustCrate</literal> infrastructure now produces <literal>lib</literal> outputs in addition to the <literal>out</literal> output. The <literal>buildRustCrate</literal> infrastructure now produces <literal>lib</literal> outputs in addition to the <literal>out</literal> output.
This has led to drastically reduced closed sizes for some rust crates since development dependencies are now in the <literal>lib</literal> output. This has led to drastically reduced closure sizes for some rust crates since development dependencies are now in the <literal>lib</literal> output.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -641,6 +641,13 @@ auth required pam_succeed_if.so uid >= 1000 quiet
The previous behavior can be restored by setting <literal>config.riot-web.conf = { disable_guests = false; piwik = true; }</literal>. The previous behavior can be restored by setting <literal>config.riot-web.conf = { disable_guests = false; piwik = true; }</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
Stand-alone usage of <literal>Upower</literal> now requires
<option>services.upower.enable</option> instead of just installing into
<xref linkend="opt-environment.systemPackages"/>.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
@ -703,6 +710,72 @@ auth required pam_succeed_if.so uid >= 1000 quiet
via <option>boot.initrd.luks.fido2Support</option>. via <option>boot.initrd.luks.fido2Support</option>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
Predicatbly named network-interfaces get renamed in stage-1. This means that it's possible
to use the proper interface name for e.g. dropbear-setups.
</para>
<para>
For further reference, please read <link xlink:href="https://github.com/NixOS/nixpkgs/pull/68953">#68953</link> or the corresponding <link xlink:href="https://discourse.nixos.org/t/predictable-network-interface-names-in-initrd/4055">discourse thread</link>.
</para>
</listitem>
<listitem>
<para>
The <package>matrix-synapse</package>-package has been updated to
<link xlink:href="https://github.com/matrix-org/synapse/releases/tag/v1.11.1">v1.11.1</link>.
Due to <link xlink:href="https://github.com/matrix-org/synapse/releases/tag/v1.10.0rc1">stricter requirements</link>
for database configuration when using <package>postgresql</package>, the automated database setup
of the module has been removed to avoid any further edge-cases.
</para>
<para>
<package>matrix-synapse</package> expects <literal>postgresql</literal>-databases to have the options
<literal>LC_COLLATE</literal> and <literal>LC_CTYPE</literal> set to
<link xlink:href="https://www.postgresql.org/docs/12/locale.html"><literal>'C'</literal></link> which basically
instructs <literal>postgresql</literal> to ignore any locale-based preferences.
</para>
<para>
Depending on your setup, you need to incorporate one of the following changes in your setup to
upgrade to 20.03:
<itemizedlist>
<listitem><para>If you use <literal>sqlite3</literal> you don't need to do anything.</para></listitem>
<listitem><para>If you use <literal>postgresql</literal> on a different server, you don't need
to change anything as well since this module was never designed to configure remote databases.
</para></listitem>
<listitem><para>If you use <literal>postgresql</literal> and configured your synapse initially on
<literal>19.09</literal> or older, you simply need to enable <package>postgresql</package>-support
explicitly:
<programlisting>{ ... }: {
services.matrix-synapse = {
<link linkend="opt-services.matrix-synapse.enable">enable</link> = true;
/* and all the other config you've defined here */
};
<link linkend="opt-services.postgresql.enable">services.postgresql.enable</link> = true;
}</programlisting>
</para></listitem>
<listitem><para>If you deploy a fresh <package>matrix-synapse</package>, you need to configure
the database yourself (e.g. by using the
<link linkend="opt-services.postgresql.initialScript">services.postgresql.initialScript</link>
option). An example for this can be found in the
<link linkend="module-services-matrix">documentation of the Matrix module</link>.
</para></listitem>
<listitem><para>If you initially deployed your <package>matrix-synapse</package> on
<literal>nixos-unstable</literal> <emphasis>after</emphasis> the <literal>19.09</literal>-release,
your database is misconfigured due to a regression in NixOS. For now, <package>matrix-synapse</package> will
startup with a warning, but it's recommended to reconfigure the database to set the values
<literal>LC_COLLATE</literal> and <literal>LC_CTYPE</literal> to
<link xlink:href="https://www.postgresql.org/docs/12/locale.html"><literal>'C'</literal></link>.
</para></listitem>
</itemizedlist>
</para>
</listitem>
<listitem>
<para>
The <link linkend="opt-systemd.network.links">systemd.network.links</link> option is now respected
even when <link linkend="opt-systemd.network.enable">systemd-networkd</link> is disabled.
This mirrors the behaviour of systemd - It's udev that parses <literal>.link</literal> files,
not <command>systemd-networkd</command>.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
</section> </section>

View File

@ -23,6 +23,20 @@
Support is planned until the end of April 2021, handing over to 21.03. Support is planned until the end of April 2021, handing over to 21.03.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
PHP now defaults to PHP 7.4, updated from 7.3.
</para>
</listitem>
<listitem>
<para>
Two new options, <link linkend="opt-services.openssh.authorizedKeysCommand">authorizedKeysCommand</link>
and <link linkend="opt-services.openssh.authorizedKeysCommandUser">authorizedKeysCommandUser</link>, have
been added to the <literal>openssh</literal> module. If you have <literal>AuthorizedKeysCommand</literal>
in your <link linkend="opt-services.openssh.extraConfig">services.openssh.extraConfig</link> you should
make use of these new options instead.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
@ -72,6 +86,16 @@
}</programlisting> }</programlisting>
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The <link linkend="opt-services.supybot.enable">supybot</link> module now uses <literal>/var/lib/supybot</literal>
as its default <link linkend="opt-services.supybot.stateDir">stateDir</link> path if <literal>stateVersion</literal>
is 20.09 or higher. It also enables number of
<link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Sandboxing">systemd sandboxing options</link>
which may possibly interfere with some plugins. If this is the case you can disable the options through attributes in
<option>systemd.services.supybot.serviceConfig</option>.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>

View File

@ -41,6 +41,12 @@ let
# default to the argument. That way this new default could propagate all # default to the argument. That way this new default could propagate all
# they way through, but has the last priority behind everything else. # they way through, but has the last priority behind everything else.
nixpkgs.system = lib.mkDefault system; nixpkgs.system = lib.mkDefault system;
# Stash the value of the `system` argument. When using `nesting.children`
# we want to have the same default value behavior (immediately above)
# without any interference from the user's configuration.
nixpkgs.initialSystem = system;
_module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_); _module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
}; };
}; };
@ -55,7 +61,7 @@ in rec {
args = extraArgs; args = extraArgs;
specialArgs = specialArgs =
{ modulesPath = builtins.toString ../modules; } // specialArgs; { modulesPath = builtins.toString ../modules; } // specialArgs;
}) config options; }) config options _module;
# These are the extra arguments passed to every module. In # These are the extra arguments passed to every module. In
# particular, Nixpkgs is passed through the "pkgs" argument. # particular, Nixpkgs is passed through the "pkgs" argument.
@ -63,5 +69,5 @@ in rec {
inherit baseModules extraModules modules; inherit baseModules extraModules modules;
}; };
inherit (config._module.args) pkgs; inherit (_module.args) pkgs;
} }

View File

@ -175,13 +175,13 @@ in rec {
nodeNames = builtins.attrNames nodes; nodeNames = builtins.attrNames nodes;
invalidNodeNames = lib.filter invalidNodeNames = lib.filter
(node: builtins.match "^[A-z_][A-z0-9_]+$" node == null) nodeNames; (node: builtins.match "^[A-z_]([A-z0-9_]+)?$" node == null) nodeNames;
in in
if lib.length invalidNodeNames > 0 then if lib.length invalidNodeNames > 0 then
throw '' throw ''
Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})! Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
All machines are referenced as perl variables in the testing framework which will break the All machines are referenced as python variables in the testing framework which will break the
script when special characters are used. script when special characters are used.
Please stick to alphanumeric chars and underscores as separation. Please stick to alphanumeric chars and underscores as separation.

View File

@ -14,7 +14,7 @@ rec {
# becomes dev-xyzzy. FIXME: slow. # becomes dev-xyzzy. FIXME: slow.
escapeSystemdPath = s: escapeSystemdPath = s:
replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"]
(if hasPrefix "/" s then substring 1 (stringLength s) s else s); (removePrefix "/" s);
# Returns a system path for a given shell package # Returns a system path for a given shell package
toShellPath = shell: toShellPath = shell:

View File

@ -18,7 +18,7 @@ state_dir=$HOME/amis/ec2-images
home_region=eu-west-1 home_region=eu-west-1
bucket=nixos-amis bucket=nixos-amis
regions=(eu-west-1 eu-west-2 eu-west-3 eu-central-1 regions=(eu-west-1 eu-west-2 eu-west-3 eu-central-1 eu-north-1
us-east-1 us-east-2 us-west-1 us-west-2 us-east-1 us-east-2 us-west-1 us-west-2
ca-central-1 ca-central-1
ap-southeast-1 ap-southeast-2 ap-northeast-1 ap-northeast-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ap-northeast-2

View File

@ -35,12 +35,22 @@ in
''; '';
}; };
networking.hostFiles = lib.mkOption {
type = types.listOf types.path;
defaultText = lib.literalExample "Hosts from `networking.hosts` and `networking.extraHosts`";
example = lib.literalExample ''[ "''${pkgs.my-blocklist-package}/share/my-blocklist/hosts" ]'';
description = ''
Files that should be concatenated together to form <filename>/etc/hosts</filename>.
'';
};
networking.extraHosts = lib.mkOption { networking.extraHosts = lib.mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
example = "192.168.0.1 lanlocalhost"; example = "192.168.0.1 lanlocalhost";
description = '' description = ''
Additional verbatim entries to be appended to <filename>/etc/hosts</filename>. Additional verbatim entries to be appended to <filename>/etc/hosts</filename>.
For adding hosts from derivation results, use <option>networking.hostFiles</option> instead.
''; '';
}; };
@ -159,6 +169,15 @@ in
"::1" = [ "localhost" ]; "::1" = [ "localhost" ];
}; };
networking.hostFiles = let
stringHosts =
let
oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip} + "\n";
allToString = set: concatMapStrings (oneToString set) (attrNames set);
in pkgs.writeText "string-hosts" (allToString (filterAttrs (_: v: v != []) cfg.hosts));
extraHosts = pkgs.writeText "extra-hosts" cfg.extraHosts;
in mkBefore [ stringHosts extraHosts ];
environment.etc = environment.etc =
{ # /etc/services: TCP/UDP port assignments. { # /etc/services: TCP/UDP port assignments.
services.source = pkgs.iana-etc + "/etc/services"; services.source = pkgs.iana-etc + "/etc/services";
@ -167,12 +186,8 @@ in
protocols.source = pkgs.iana-etc + "/etc/protocols"; protocols.source = pkgs.iana-etc + "/etc/protocols";
# /etc/hosts: Hostname-to-IP mappings. # /etc/hosts: Hostname-to-IP mappings.
hosts.text = let hosts.source = pkgs.runCommandNoCC "hosts" {} ''
oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip}; cat ${escapeShellArgs cfg.hostFiles} > $out
allToString = set: concatMapStringsSep "\n" (oneToString set) (attrNames set);
in ''
${allToString (filterAttrs (_: v: v != []) cfg.hosts)}
${cfg.extraHosts}
''; '';
# /etc/host.conf: resolver configuration file # /etc/host.conf: resolver configuration file

View File

@ -133,7 +133,7 @@ in
tcpcryptd = 93; # tcpcryptd uses a hard-coded uid. We patch it in Nixpkgs to match this choice. tcpcryptd = 93; # tcpcryptd uses a hard-coded uid. We patch it in Nixpkgs to match this choice.
firebird = 95; firebird = 95;
#keys = 96; # unused #keys = 96; # unused
#haproxy = 97; # DynamicUser as of 2019-11-08 #haproxy = 97; # dynamically allocated as of 2020-03-11
mongodb = 98; mongodb = 98;
openldap = 99; openldap = 99;
#users = 100; # unused #users = 100; # unused
@ -448,7 +448,7 @@ in
#tcpcryptd = 93; # unused #tcpcryptd = 93; # unused
firebird = 95; firebird = 95;
keys = 96; keys = 96;
#haproxy = 97; # DynamicUser as of 2019-11-08 #haproxy = 97; # dynamically allocated as of 2020-03-11
#mongodb = 98; # unused #mongodb = 98; # unused
openldap = 99; openldap = 99;
munin = 102; munin = 102;

View File

@ -216,6 +216,14 @@ in
Ignored when <code>nixpkgs.pkgs</code> is set. Ignored when <code>nixpkgs.pkgs</code> is set.
''; '';
}; };
initialSystem = mkOption {
type = types.str;
internal = true;
description = ''
Preserved value of <literal>system</literal> passed to <literal>eval-config.nix</literal>.
'';
};
}; };
config = { config = {

View File

@ -200,6 +200,7 @@
./security/wrappers/default.nix ./security/wrappers/default.nix
./security/sudo.nix ./security/sudo.nix
./security/systemd-confinement.nix ./security/systemd-confinement.nix
./security/tpm2.nix
./services/admin/oxidized.nix ./services/admin/oxidized.nix
./services/admin/salt/master.nix ./services/admin/salt/master.nix
./services/admin/salt/minion.nix ./services/admin/salt/minion.nix
@ -247,9 +248,10 @@
./services/cluster/kubernetes/proxy.nix ./services/cluster/kubernetes/proxy.nix
./services/cluster/kubernetes/scheduler.nix ./services/cluster/kubernetes/scheduler.nix
./services/computing/boinc/client.nix ./services/computing/boinc/client.nix
./services/computing/torque/server.nix ./services/computing/foldingathome/client.nix
./services/computing/torque/mom.nix
./services/computing/slurm/slurm.nix ./services/computing/slurm/slurm.nix
./services/computing/torque/mom.nix
./services/computing/torque/server.nix
./services/continuous-integration/buildbot/master.nix ./services/continuous-integration/buildbot/master.nix
./services/continuous-integration/buildbot/worker.nix ./services/continuous-integration/buildbot/worker.nix
./services/continuous-integration/buildkite-agents.nix ./services/continuous-integration/buildkite-agents.nix
@ -297,6 +299,7 @@
./services/desktops/geoclue2.nix ./services/desktops/geoclue2.nix
./services/desktops/gsignond.nix ./services/desktops/gsignond.nix
./services/desktops/gvfs.nix ./services/desktops/gvfs.nix
./services/desktops/malcontent.nix
./services/desktops/pipewire.nix ./services/desktops/pipewire.nix
./services/desktops/gnome3/at-spi2-core.nix ./services/desktops/gnome3/at-spi2-core.nix
./services/desktops/gnome3/chrome-gnome-shell.nix ./services/desktops/gnome3/chrome-gnome-shell.nix
@ -405,6 +408,7 @@
./services/mail/sympa.nix ./services/mail/sympa.nix
./services/mail/nullmailer.nix ./services/mail/nullmailer.nix
./services/misc/airsonic.nix ./services/misc/airsonic.nix
./services/misc/ankisyncd.nix
./services/misc/apache-kafka.nix ./services/misc/apache-kafka.nix
./services/misc/autofs.nix ./services/misc/autofs.nix
./services/misc/autorandr.nix ./services/misc/autorandr.nix
@ -430,7 +434,6 @@
./services/misc/ethminer.nix ./services/misc/ethminer.nix
./services/misc/exhibitor.nix ./services/misc/exhibitor.nix
./services/misc/felix.nix ./services/misc/felix.nix
./services/misc/folding-at-home.nix
./services/misc/freeswitch.nix ./services/misc/freeswitch.nix
./services/misc/fstrim.nix ./services/misc/fstrim.nix
./services/misc/gammu-smsd.nix ./services/misc/gammu-smsd.nix
@ -660,6 +663,7 @@
./services/networking/ngircd.nix ./services/networking/ngircd.nix
./services/networking/nghttpx/default.nix ./services/networking/nghttpx/default.nix
./services/networking/nix-serve.nix ./services/networking/nix-serve.nix
./services/networking/nix-store-gcs-proxy.nix
./services/networking/nixops-dns.nix ./services/networking/nixops-dns.nix
./services/networking/nntp-proxy.nix ./services/networking/nntp-proxy.nix
./services/networking/nsd.nix ./services/networking/nsd.nix
@ -706,6 +710,7 @@
./services/networking/shorewall6.nix ./services/networking/shorewall6.nix
./services/networking/shout.nix ./services/networking/shout.nix
./services/networking/sniproxy.nix ./services/networking/sniproxy.nix
./services/networking/smartdns.nix
./services/networking/smokeping.nix ./services/networking/smokeping.nix
./services/networking/softether.nix ./services/networking/softether.nix
./services/networking/spacecookie.nix ./services/networking/spacecookie.nix
@ -723,6 +728,7 @@
./services/networking/syncthing.nix ./services/networking/syncthing.nix
./services/networking/syncthing-relay.nix ./services/networking/syncthing-relay.nix
./services/networking/syncplay.nix ./services/networking/syncplay.nix
./services/networking/tailscale.nix
./services/networking/tcpcrypt.nix ./services/networking/tcpcrypt.nix
./services/networking/teamspeak3.nix ./services/networking/teamspeak3.nix
./services/networking/tedicross.nix ./services/networking/tedicross.nix
@ -807,6 +813,7 @@
./services/ttys/agetty.nix ./services/ttys/agetty.nix
./services/ttys/gpm.nix ./services/ttys/gpm.nix
./services/ttys/kmscon.nix ./services/ttys/kmscon.nix
./services/wayland/cage.nix
./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/confluence.nix
./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/crowd.nix
./services/web-apps/atlassian/jira.nix ./services/web-apps/atlassian/jira.nix

View File

@ -5,28 +5,34 @@ with lib;
let let
cfg = config.programs.firejail; cfg = config.programs.firejail;
wrappedBins = pkgs.stdenv.mkDerivation { wrappedBins = pkgs.runCommand "firejail-wrapped-binaries"
name = "firejail-wrapped-binaries"; { preferLocalBuild = true;
nativeBuildInputs = with pkgs; [ makeWrapper ]; allowSubstitutes = false;
buildCommand = '' }
''
mkdir -p $out/bin mkdir -p $out/bin
${lib.concatStringsSep "\n" (lib.mapAttrsToList (command: binary: '' ${lib.concatStringsSep "\n" (lib.mapAttrsToList (command: binary: ''
cat <<_EOF >$out/bin/${command} cat <<_EOF >$out/bin/${command}
#!${pkgs.stdenv.shell} -e #! ${pkgs.runtimeShell} -e
/run/wrappers/bin/firejail ${binary} "\$@" exec /run/wrappers/bin/firejail ${binary} "\$@"
_EOF _EOF
chmod 0755 $out/bin/${command} chmod 0755 $out/bin/${command}
'') cfg.wrappedBinaries)} '') cfg.wrappedBinaries)}
''; '';
};
in { in {
options.programs.firejail = { options.programs.firejail = {
enable = mkEnableOption "firejail"; enable = mkEnableOption "firejail";
wrappedBinaries = mkOption { wrappedBinaries = mkOption {
type = types.attrs; type = types.attrsOf types.path;
default = {}; default = {};
example = literalExample ''
{
firefox = "''${lib.getBin pkgs.firefox}/bin/firefox";
mpv = "''${lib.getBin pkgs.mpv}/bin/mpv";
}
'';
description = '' description = ''
Wrap the binaries in firejail and place them in the global path. Wrap the binaries in firejail and place them in the global path.
</para> </para>
@ -41,7 +47,7 @@ in {
config = mkIf cfg.enable { config = mkIf cfg.enable {
security.wrappers.firejail.source = "${lib.getBin pkgs.firejail}/bin/firejail"; security.wrappers.firejail.source = "${lib.getBin pkgs.firejail}/bin/firejail";
environment.systemPackages = [ wrappedBins ]; environment.systemPackages = [ pkgs.firejail ] ++ [ wrappedBins ];
}; };
meta.maintainers = with maintainers; [ peterhoeg ]; meta.maintainers = with maintainers; [ peterhoeg ];

View File

@ -21,12 +21,12 @@ with lib;
(mkRemovedOptionModule [ "services" "firefox" "syncserver" "group" ] "") (mkRemovedOptionModule [ "services" "firefox" "syncserver" "group" ] "")
(mkRemovedOptionModule [ "services" "winstone" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "winstone" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.") (mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.")
(mkRemovedOptionModule [ "environment.blcr.enable" ] "The BLCR module has been removed") (mkRemovedOptionModule [ "environment" "blcr" "enable" ] "The BLCR module has been removed")
(mkRemovedOptionModule [ "services.beegfsEnable" ] "The BeeGFS module has been removed") (mkRemovedOptionModule [ "services" "beegfsEnable" ] "The BeeGFS module has been removed")
(mkRemovedOptionModule [ "services.beegfs" ] "The BeeGFS module has been removed") (mkRemovedOptionModule [ "services" "beegfs" ] "The BeeGFS module has been removed")
(mkRemovedOptionModule [ "services.osquery" ] "The osquery module has been removed") (mkRemovedOptionModule [ "services" "osquery" ] "The osquery module has been removed")
(mkRemovedOptionModule [ "services.fourStore" ] "The fourStore module has been removed") (mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed")
(mkRemovedOptionModule [ "services.fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed") (mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
(mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " + (mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " +
"https://way-cooler.org/blog/2020/01/09/way-cooler-post-mortem.html")) "https://way-cooler.org/blog/2020/01/09/way-cooler-post-mortem.html"))
(mkRemovedOptionModule [ "services" "xserver" "multitouch" ] '' (mkRemovedOptionModule [ "services" "xserver" "multitouch" ] ''

View File

@ -136,6 +136,27 @@ let
challenge to ensure the DNS entries required are available. challenge to ensure the DNS entries required are available.
''; '';
}; };
ocspMustStaple = mkOption {
type = types.bool;
default = false;
description = ''
Turns on the OCSP Must-Staple TLS extension.
Make sure you know what you're doing! See:
<itemizedlist>
<listitem><para><link xlink:href="https://blog.apnic.net/2019/01/15/is-the-web-ready-for-ocsp-must-staple/" /></para></listitem>
<listitem><para><link xlink:href="https://blog.hboeck.de/archives/886-The-Problem-with-OCSP-Stapling-and-Must-Staple-and-why-Certificate-Revocation-is-still-broken.html" /></para></listitem>
</itemizedlist>
'';
};
extraLegoRenewFlags = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Additional flags to pass to lego renew.
'';
};
}; };
}; };
@ -174,7 +195,7 @@ in
renewInterval = mkOption { renewInterval = mkOption {
type = types.str; type = types.str;
default = "weekly"; default = "daily";
description = '' description = ''
Systemd calendar expression when to check for renewal. See Systemd calendar expression when to check for renewal. See
<citerefentry><refentrytitle>systemd.time</refentrytitle> <citerefentry><refentrytitle>systemd.time</refentrytitle>
@ -281,15 +302,18 @@ in
lpath = "acme/${cert}"; lpath = "acme/${cert}";
apath = "/var/lib/${lpath}"; apath = "/var/lib/${lpath}";
spath = "/var/lib/acme/.lego"; spath = "/var/lib/acme/.lego";
rights = if data.allowKeysForGroup then "750" else "700"; fileMode = if data.allowKeysForGroup then "640" else "600";
globalOpts = [ "-d" data.domain "--email" data.email "--path" "." "--key-type" data.keyType ] globalOpts = [ "-d" data.domain "--email" data.email "--path" "." "--key-type" data.keyType ]
++ optionals (cfg.acceptTerms) [ "--accept-tos" ] ++ optionals (cfg.acceptTerms) [ "--accept-tos" ]
++ optionals (data.dnsProvider != null && !data.dnsPropagationCheck) [ "--dns.disable-cp" ] ++ optionals (data.dnsProvider != null && !data.dnsPropagationCheck) [ "--dns.disable-cp" ]
++ concatLists (mapAttrsToList (name: root: [ "-d" name ]) data.extraDomains) ++ concatLists (mapAttrsToList (name: root: [ "-d" name ]) data.extraDomains)
++ (if data.dnsProvider != null then [ "--dns" data.dnsProvider ] else [ "--http" "--http.webroot" data.webroot ]) ++ (if data.dnsProvider != null then [ "--dns" data.dnsProvider ] else [ "--http" "--http.webroot" data.webroot ])
++ optionals (cfg.server != null || data.server != null) ["--server" (if data.server == null then cfg.server else data.server)]; ++ optionals (cfg.server != null || data.server != null) ["--server" (if data.server == null then cfg.server else data.server)];
runOpts = escapeShellArgs (globalOpts ++ [ "run" ]); certOpts = optionals data.ocspMustStaple [ "--must-staple" ];
renewOpts = escapeShellArgs (globalOpts ++ [ "renew" "--days" (toString cfg.validMinDays) ]); runOpts = escapeShellArgs (globalOpts ++ [ "run" ] ++ certOpts);
renewOpts = escapeShellArgs (globalOpts ++
[ "renew" "--days" (toString cfg.validMinDays) ] ++
certOpts ++ data.extraLegoRenewFlags);
acmeService = { acmeService = {
description = "Renew ACME Certificate for ${cert}"; description = "Renew ACME Certificate for ${cert}";
after = [ "network.target" "network-online.target" ]; after = [ "network.target" "network-online.target" ];
@ -307,7 +331,7 @@ in
Group = data.group; Group = data.group;
PrivateTmp = true; PrivateTmp = true;
StateDirectory = "acme/.lego ${lpath}"; StateDirectory = "acme/.lego ${lpath}";
StateDirectoryMode = rights; StateDirectoryMode = if data.allowKeysForGroup then "750" else "700";
WorkingDirectory = spath; WorkingDirectory = spath;
# Only try loading the credentialsFile if the dns challenge is enabled # Only try loading the credentialsFile if the dns challenge is enabled
EnvironmentFile = if data.dnsProvider != null then data.credentialsFile else null; EnvironmentFile = if data.dnsProvider != null then data.credentialsFile else null;
@ -328,12 +352,13 @@ in
cp -p ${spath}/certificates/${keyName}.key key.pem cp -p ${spath}/certificates/${keyName}.key key.pem
cp -p ${spath}/certificates/${keyName}.crt fullchain.pem cp -p ${spath}/certificates/${keyName}.crt fullchain.pem
cp -p ${spath}/certificates/${keyName}.issuer.crt chain.pem cp -p ${spath}/certificates/${keyName}.issuer.crt chain.pem
ln -s fullchain.pem cert.pem ln -sf fullchain.pem cert.pem
cat key.pem fullchain.pem > full.pem cat key.pem fullchain.pem > full.pem
chmod ${rights} *.pem
chown '${data.user}:${data.group}' *.pem
fi fi
chmod ${fileMode} *.pem
chown '${data.user}:${data.group}' *.pem
${data.postRun} ${data.postRun}
''; '';
in in
@ -375,7 +400,7 @@ in
# Give key acme permissions # Give key acme permissions
chown '${data.user}:${data.group}' "${apath}/"{key,fullchain,full}.pem chown '${data.user}:${data.group}' "${apath}/"{key,fullchain,full}.pem
chmod ${rights} "${apath}/"{key,fullchain,full}.pem chmod ${fileMode} "${apath}/"{key,fullchain,full}.pem
''; '';
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
@ -400,7 +425,17 @@ in
systemd.tmpfiles.rules = systemd.tmpfiles.rules =
map (data: "d ${data.webroot}/.well-known/acme-challenge - ${data.user} ${data.group}") (filter (data: data.webroot != null) (attrValues cfg.certs)); map (data: "d ${data.webroot}/.well-known/acme-challenge - ${data.user} ${data.group}") (filter (data: data.webroot != null) (attrValues cfg.certs));
systemd.timers = flip mapAttrs' cfg.certs (cert: data: nameValuePair systemd.timers = let
# Allow systemd to pick a convenient time within the day
# to run the check.
# This allows the coalescing of multiple timer jobs.
# We divide by the number of certificates so that if you
# have many certificates, the renewals are distributed over
# the course of the day to avoid rate limits.
numCerts = length (attrNames cfg.certs);
_24hSecs = 60 * 60 * 24;
AccuracySec = "${toString (_24hSecs / numCerts)}s";
in flip mapAttrs' cfg.certs (cert: data: nameValuePair
("acme-${cert}") ("acme-${cert}")
({ ({
description = "Renew ACME Certificate for ${cert}"; description = "Renew ACME Certificate for ${cert}";
@ -409,8 +444,9 @@ in
OnCalendar = cfg.renewInterval; OnCalendar = cfg.renewInterval;
Unit = "acme-${cert}.service"; Unit = "acme-${cert}.service";
Persistent = "yes"; Persistent = "yes";
AccuracySec = "5m"; inherit AccuracySec;
RandomizedDelaySec = "1h"; # Skew randomly within the day, per https://letsencrypt.org/docs/integration-guide/.
RandomizedDelaySec = "24h";
}; };
}) })
); );

View File

@ -59,10 +59,8 @@ in
exec ${package}/bin/google_authorized_keys "$@" exec ${package}/bin/google_authorized_keys "$@"
''; '';
}; };
services.openssh.extraConfig = '' services.openssh.authorizedKeysCommand = "/etc/ssh/authorized_keys_command_google_oslogin %u";
AuthorizedKeysCommand /etc/ssh/authorized_keys_command_google_oslogin %u services.openssh.authorizedKeysCommandUser = "nobody";
AuthorizedKeysCommandUser nobody
'';
}; };
} }

View File

@ -0,0 +1,185 @@
{ lib, pkgs, config, ... }:
let
cfg = config.security.tpm2;
# This snippet is taken from tpm2-tss/dist/tpm-udev.rules, but modified to allow custom user/groups
# The idea is that the tssUser is allowed to acess the TPM and kernel TPM resource manager, while
# the tssGroup is only allowed to access the kernel resource manager
# Therefore, if either of the two are null, the respective part isn't generated
udevRules = tssUser: tssGroup: ''
${lib.optionalString (tssUser != null) ''KERNEL=="tpm[0-9]*", MODE="0660", OWNER="${tssUser}"''}
${lib.optionalString (tssUser != null || tssGroup != null)
''KERNEL=="tpmrm[0-9]*", MODE="0660"''
+ lib.optionalString (tssUser != null) '', OWNER="${tssUser}"''
+ lib.optionalString (tssGroup != null) '', GROUP="${tssGroup}"''
}
'';
in {
options.security.tpm2 = {
enable = lib.mkEnableOption "Trusted Platform Module 2 support";
tssUser = lib.mkOption {
description = ''
Name of the tpm device-owner and service user, set if applyUdevRules is
set.
'';
type = lib.types.nullOr lib.types.str;
default = if cfg.abrmd.enable then "tss" else "root";
defaultText = ''"tss" when using the userspace resource manager,'' +
''"root" otherwise'';
};
tssGroup = lib.mkOption {
description = ''
Group of the tpm kernel resource manager (tpmrm) device-group, set if
applyUdevRules is set.
'';
type = lib.types.nullOr lib.types.str;
default = "tss";
};
applyUdevRules = lib.mkOption {
description = ''
Whether to make the /dev/tpm[0-9] devices accessible by the tssUser, or
the /dev/tpmrm[0-9] by tssGroup respectively
'';
type = lib.types.bool;
default = true;
};
abrmd = {
enable = lib.mkEnableOption ''
Trusted Platform 2 userspace resource manager daemon
'';
package = lib.mkOption {
description = "tpm2-abrmd package to use";
type = lib.types.package;
default = pkgs.tpm2-abrmd;
defaultText = "pkgs.tpm2-abrmd";
};
};
pkcs11 = {
enable = lib.mkEnableOption ''
TPM2 PKCS#11 tool and shared library in system path
(<literal>/run/current-system/sw/lib/libtpm2_pkcs11.so</literal>)
'';
package = lib.mkOption {
description = "tpm2-pkcs11 package to use";
type = lib.types.package;
default = pkgs.tpm2-pkcs11;
defaultText = "pkgs.tpm2-pkcs11";
};
};
tctiEnvironment = {
enable = lib.mkOption {
description = ''
Set common TCTI environment variables to the specified value.
The variables are
<itemizedlist>
<listitem>
<para>
<literal>TPM2TOOLS_TCTI</literal>
</para>
</listitem>
<listitem>
<para>
<literal>TPM2_PKCS11_TCTI</literal>
</para>
</listitem>
</itemizedlist>
'';
type = lib.types.bool;
default = false;
};
interface = lib.mkOption {
description = ''
The name of the TPM command transmission interface (TCTI) library to
use.
'';
type = lib.types.enum [ "tabrmd" "device" ];
default = "device";
};
deviceConf = lib.mkOption {
description = ''
Configuration part of the device TCTI, e.g. the path to the TPM device.
Applies if interface is set to "device".
The format is specified in the
<link xlink:href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options">
tpm2-tools repository</link>.
'';
type = lib.types.str;
default = "/dev/tpmrm0";
};
tabrmdConf = lib.mkOption {
description = ''
Configuration part of the tabrmd TCTI, like the D-Bus bus name.
Applies if interface is set to "tabrmd".
The format is specified in the
<link xlink:href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options">
tpm2-tools repository</link>.
'';
type = lib.types.str;
default = "bus_name=com.intel.tss2.Tabrmd";
};
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
# PKCS11 tools and library
environment.systemPackages = lib.mkIf cfg.pkcs11.enable [
(lib.getBin cfg.pkcs11.package)
(lib.getLib cfg.pkcs11.package)
];
services.udev.extraRules = lib.mkIf cfg.applyUdevRules
(udevRules cfg.tssUser cfg.tssGroup);
# Create the tss user and group only if the default value is used
users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") {
isSystemUser = true;
};
users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") {};
environment.variables = lib.mkIf cfg.tctiEnvironment.enable (
lib.attrsets.genAttrs [
"TPM2TOOLS_TCTI"
"TPM2_PKCS11_TCTI"
] (_: ''${cfg.tctiEnvironment.interface}:${
if cfg.tctiEnvironment.interface == "tabrmd" then
cfg.tctiEnvironment.tabrmdConf
else
cfg.tctiEnvironment.deviceConf
}'')
);
}
(lib.mkIf cfg.abrmd.enable {
systemd.services."tpm2-abrmd" = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "dbus";
Restart = "always";
RestartSec = 30;
BusName = "com.intel.tss2.Tabrmd";
StandardOutput = "syslog";
ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd";
User = "tss";
Group = "nogroup";
};
};
services.dbus.packages = lib.singleton cfg.abrmd.package;
})
]);
meta.maintainers = with lib.maintainers; [ lschuermann ];
}

View File

@ -0,0 +1,81 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.foldingathome;
args =
["--team" "${toString cfg.team}"]
++ lib.optionals (cfg.user != null) ["--user" cfg.user]
++ cfg.extraArgs
;
in
{
imports = [
(mkRenamedOptionModule [ "services" "foldingAtHome" ] [ "services" "foldingathome" ])
(mkRenamedOptionModule [ "services" "foldingathome" "nickname" ] [ "services" "foldingathome" "user" ])
(mkRemovedOptionModule [ "services" "foldingathome" "config" ] ''
Use <literal>services.foldingathome.extraArgs instead<literal>
'')
];
options.services.foldingathome = {
enable = mkEnableOption "Enable the Folding@home client";
package = mkOption {
type = types.package;
default = pkgs.fahclient;
defaultText = "pkgs.fahclient";
description = ''
Which Folding@home client to use.
'';
};
user = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The user associated with the reported computation results. This will
be used in the ranking statistics.
'';
};
team = mkOption {
type = types.int;
default = 236565;
description = ''
The team ID associated with the reported computation results. This
will be used in the ranking statistics.
By default, use the NixOS folding@home team ID is being used.
'';
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Extra startup options for the FAHClient. Run
<literal>FAHClient --help</literal> to find all the available options.
'';
};
};
config = mkIf cfg.enable {
systemd.services.foldingathome = {
description = "Folding@home client";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script = ''
exec ${cfg.package}/bin/FAHClient ${lib.escapeShellArgs args}
'';
serviceConfig = {
DynamicUser = true;
StateDirectory = "foldingathome";
WorkingDirectory = "%S/foldingathome";
};
};
};
meta = {
maintainers = with lib.maintainers; [ zimbatm ];
};
}

View File

@ -21,6 +21,11 @@ let
installOptions = installOptions =
"${mysqldOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}"; "${mysqldOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}";
settingsFile = pkgs.writeText "my.cnf" (
generators.toINI { listsAsDuplicateKeys = true; } cfg.settings +
optionalString (cfg.extraOptions != null) "[mysqld]\n${cfg.extraOptions}"
);
in in
{ {
@ -76,9 +81,64 @@ in
description = "Location where MySQL stores its table files"; description = "Location where MySQL stores its table files";
}; };
configFile = mkOption {
type = types.path;
default = settingsFile;
defaultText = "settingsFile";
description = ''
Override the configuration file used by MySQL. By default,
NixOS generates one automatically from <option>services.mysql.settings</option>.
'';
example = literalExample ''
pkgs.writeText "my.cnf" '''
[mysqld]
datadir = /var/lib/mysql
bind-address = 127.0.0.1
port = 3336
plugin-load-add = auth_socket.so
!includedir /etc/mysql/conf.d/
''';
'';
};
settings = mkOption {
type = with types; attrsOf (attrsOf (oneOf [ bool int str (listOf str) ]));
default = {};
description = ''
MySQL configuration. Refer to
<link xlink:href="https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html"/>,
<link xlink:href="https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html"/>,
and <link xlink:href="https://mariadb.com/kb/en/server-system-variables/"/>
for details on supported values.
<note>
<para>
MySQL configuration options such as <literal>--quick</literal> should be treated as
boolean options and provided values such as <literal>true</literal>, <literal>false</literal>,
<literal>1</literal>, or <literal>0</literal>. See the provided example below.
</para>
</note>
'';
example = literalExample ''
{
mysqld = {
key_buffer_size = "6G";
table_cache = 1600;
log-error = "/var/log/mysql_err.log";
plugin-load-add = [ "server_audit" "ed25519=auth_ed25519" ];
};
mysqldump = {
quick = true;
max_allowed_packet = "16M";
};
}
'';
};
extraOptions = mkOption { extraOptions = mkOption {
type = types.lines; type = with types; nullOr lines;
default = ""; default = null;
example = '' example = ''
key_buffer_size = 6G key_buffer_size = 6G
table_cache = 1600 table_cache = 1600
@ -252,10 +312,27 @@ in
config = mkIf config.services.mysql.enable { config = mkIf config.services.mysql.enable {
warnings = optional (cfg.extraOptions != null) "services.mysql.`extraOptions` is deprecated, please use services.mysql.`settings`.";
services.mysql.dataDir = services.mysql.dataDir =
mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql"
else "/var/mysql"); else "/var/mysql");
services.mysql.settings.mysqld = mkMerge [
{
datadir = cfg.dataDir;
bind-address = mkIf (cfg.bind != null) cfg.bind;
port = cfg.port;
plugin-load-add = optional (cfg.ensureUsers != []) "auth_socket.so";
}
(mkIf (cfg.replication.role == "master" || cfg.replication.role == "slave") {
log-bin = "mysql-bin-${toString cfg.replication.serverId}";
log-bin-index = "mysql-bin-${toString cfg.replication.serverId}.index";
relay-log = "mysql-relay-bin";
server-id = cfg.replication.serverId;
})
];
users.users.mysql = { users.users.mysql = {
description = "MySQL server user"; description = "MySQL server user";
group = "mysql"; group = "mysql";
@ -266,25 +343,7 @@ in
environment.systemPackages = [mysql]; environment.systemPackages = [mysql];
environment.etc."my.cnf".text = environment.etc."my.cnf".source = cfg.configFile;
''
[mysqld]
port = ${toString cfg.port}
datadir = ${cfg.dataDir}
${optionalString (cfg.bind != null) "bind-address = ${cfg.bind}" }
${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave")
''
log-bin=mysql-bin-${toString cfg.replication.serverId}
log-bin-index=mysql-bin-${toString cfg.replication.serverId}.index
relay-log=mysql-relay-bin
server-id = ${toString cfg.replication.serverId}
''}
${optionalString (cfg.ensureUsers != [])
''
plugin-load-add = auth_socket.so
''}
${cfg.extraOptions}
'';
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${cfg.user} mysql -" "d '${cfg.dataDir}' 0700 ${cfg.user} mysql -"
@ -297,7 +356,7 @@ in
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
restartTriggers = [ config.environment.etc."my.cnf".source ]; restartTriggers = [ cfg.configFile ];
unitConfig.RequiresMountsFor = "${cfg.dataDir}"; unitConfig.RequiresMountsFor = "${cfg.dataDir}";

View File

@ -0,0 +1,32 @@
# Malcontent daemon.
{ config, lib, pkgs, ... }:
with lib;
{
###### interface
options = {
services.malcontent = {
enable = mkEnableOption "Malcontent";
};
};
###### implementation
config = mkIf config.services.malcontent.enable {
environment.systemPackages = [ pkgs.malcontent ];
services.dbus.packages = [ pkgs.malcontent ];
};
}

View File

@ -14,9 +14,24 @@ let
base_dir = ${baseDir} base_dir = ${baseDir}
protocols = ${concatStringsSep " " cfg.protocols} protocols = ${concatStringsSep " " cfg.protocols}
sendmail_path = /run/wrappers/bin/sendmail sendmail_path = /run/wrappers/bin/sendmail
# defining mail_plugins must be done before the first protocol {} filter because of https://doc.dovecot.org/configuration_manual/config_file/config_file_syntax/#variable-expansion
mail_plugins = $mail_plugins ${concatStringsSep " " cfg.mailPlugins.globally.enable}
'' ''
(if cfg.sslServerCert == null then '' (
concatStringsSep "\n" (
mapAttrsToList (
protocol: plugins: ''
protocol ${protocol} {
mail_plugins = $mail_plugins ${concatStringsSep " " plugins.enable}
}
''
) cfg.mailPlugins.perProtocol
)
)
(
if cfg.sslServerCert == null then ''
ssl = no ssl = no
disable_plaintext_auth = no disable_plaintext_auth = no
'' else '' '' else ''
@ -25,7 +40,8 @@ let
${optionalString (cfg.sslCACert != null) ("ssl_ca = <" + cfg.sslCACert)} ${optionalString (cfg.sslCACert != null) ("ssl_ca = <" + cfg.sslCACert)}
ssl_dh = <${config.security.dhparams.params.dovecot2.path} ssl_dh = <${config.security.dhparams.params.dovecot2.path}
disable_plaintext_auth = yes disable_plaintext_auth = yes
'') ''
)
'' ''
default_internal_user = ${cfg.user} default_internal_user = ${cfg.user}
@ -45,7 +61,8 @@ let
} }
'' ''
(optionalString cfg.enablePAM '' (
optionalString cfg.enablePAM ''
userdb { userdb {
driver = passwd driver = passwd
} }
@ -54,25 +71,30 @@ let
driver = pam driver = pam
args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2 args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2
} }
'') ''
)
(optionalString (cfg.sieveScripts != {}) '' (
optionalString (cfg.sieveScripts != {}) ''
plugin { plugin {
${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)} ${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
} }
'') ''
)
(optionalString (cfg.mailboxes != []) '' (
optionalString (cfg.mailboxes != []) ''
protocol imap { protocol imap {
namespace inbox { namespace inbox {
inbox=yes inbox=yes
${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)} ${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)}
} }
} }
'') ''
)
(optionalString cfg.enableQuota '' (
mail_plugins = $mail_plugins quota optionalString cfg.enableQuota ''
service quota-status { service quota-status {
executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix
inet_listener { inet_listener {
@ -81,10 +103,6 @@ let
client_limit = 1 client_limit = 1
} }
protocol imap {
mail_plugins = $mail_plugins imap_quota
}
plugin { plugin {
quota_rule = *:storage=${cfg.quotaGlobalPerUser} quota_rule = *:storage=${cfg.quotaGlobalPerUser}
quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working
@ -93,7 +111,8 @@ let
quota_status_overquota = "552 5.2.2 Mailbox is full" quota_status_overquota = "552 5.2.2 Mailbox is full"
quota_grace = 10%% quota_grace = 10%%
} }
'') ''
)
cfg.extraConfig cfg.extraConfig
]; ];
@ -160,7 +179,7 @@ in
protocols = mkOption { protocols = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; default = [];
description = "Additional listeners to start when Dovecot is enabled."; description = "Additional listeners to start when Dovecot is enabled.";
}; };
@ -183,6 +202,43 @@ in
description = "Additional entries to put verbatim into Dovecot's config file."; description = "Additional entries to put verbatim into Dovecot's config file.";
}; };
mailPlugins =
let
plugins = hint: types.submodule {
options = {
enable = mkOption {
type = types.listOf types.str;
default = [];
description = "mail plugins to enable as a list of strings to append to the ${hint} <literal>$mail_plugins</literal> configuration variable";
};
};
};
in
mkOption {
type = with types; submodule {
options = {
globally = mkOption {
description = "Additional entries to add to the mail_plugins variable for all protocols";
type = plugins "top-level";
example = { enable = [ "virtual" ]; };
default = { enable = []; };
};
perProtocol = mkOption {
description = "Additional entries to add to the mail_plugins variable, per protocol";
type = attrsOf (plugins "corresponding per-protocol");
default = {};
example = { imap = [ "imap_acl" ]; };
};
};
};
description = "Additional entries to add to the mail_plugins variable, globally and per protocol";
example = {
globally.enable = [ "acl" ];
perProtocol.imap.enable = [ "imap_acl" ];
};
default = { globally.enable = []; perProtocol = {}; };
};
configFile = mkOption { configFile = mkOption {
type = types.nullOr types.path; type = types.nullOr types.path;
default = null; default = null;
@ -310,22 +366,28 @@ in
++ optional cfg.enablePop3 "pop3" ++ optional cfg.enablePop3 "pop3"
++ optional cfg.enableLmtp "lmtp"; ++ optional cfg.enableLmtp "lmtp";
services.dovecot2.mailPlugins = mkIf cfg.enableQuota {
globally.enable = [ "quota" ];
perProtocol.imap.enable = [ "imap_quota" ];
};
users.users = { users.users = {
dovenull = dovenull =
{ uid = config.ids.uids.dovenull2; {
uid = config.ids.uids.dovenull2;
description = "Dovecot user for untrusted logins"; description = "Dovecot user for untrusted logins";
group = "dovenull"; group = "dovenull";
}; };
} // optionalAttrs (cfg.user == "dovecot2") { } // optionalAttrs (cfg.user == "dovecot2") {
dovecot2 = dovecot2 =
{ uid = config.ids.uids.dovecot2; {
uid = config.ids.uids.dovecot2;
description = "Dovecot user"; description = "Dovecot user";
group = cfg.group; group = cfg.group;
}; };
} // optionalAttrs (cfg.createMailUser && cfg.mailUser != null) { } // optionalAttrs (cfg.createMailUser && cfg.mailUser != null) {
${cfg.mailUser} = ${cfg.mailUser} =
{ description = "Virtual Mail User"; } // { description = "Virtual Mail User"; } // optionalAttrs (cfg.mailGroup != null)
optionalAttrs (cfg.mailGroup != null)
{ group = cfg.mailGroup; }; { group = cfg.mailGroup; };
}; };
@ -334,7 +396,7 @@ in
} // optionalAttrs (cfg.group == "dovecot2") { } // optionalAttrs (cfg.group == "dovecot2") {
dovecot2.gid = config.ids.gids.dovecot2; dovecot2.gid = config.ids.gids.dovecot2;
} // optionalAttrs (cfg.createMailUser && cfg.mailGroup != null) { } // optionalAttrs (cfg.createMailUser && cfg.mailGroup != null) {
${cfg.mailGroup} = { }; ${cfg.mailGroup} = {};
}; };
environment.etc."dovecot/modules".source = modulesDir; environment.etc."dovecot/modules".source = modulesDir;
@ -363,7 +425,9 @@ in
rm -rf ${stateDir}/sieve rm -rf ${stateDir}/sieve
'' + optionalString (cfg.sieveScripts != {}) '' '' + optionalString (cfg.sieveScripts != {}) ''
mkdir -p ${stateDir}/sieve mkdir -p ${stateDir}/sieve
${concatStringsSep "\n" (mapAttrsToList (to: from: '' ${concatStringsSep "\n" (
mapAttrsToList (
to: from: ''
if [ -d '${from}' ]; then if [ -d '${from}' ]; then
mkdir '${stateDir}/sieve/${to}' mkdir '${stateDir}/sieve/${to}'
cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}' cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}'
@ -371,7 +435,9 @@ in
cp -p '${from}' '${stateDir}/sieve/${to}' cp -p '${from}' '${stateDir}/sieve/${to}'
fi fi
${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}' ${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
'') cfg.sieveScripts)} ''
) cfg.sieveScripts
)}
chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve' chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve'
''; '';
}; };
@ -379,17 +445,21 @@ in
environment.systemPackages = [ dovecotPkg ]; environment.systemPackages = [ dovecotPkg ];
assertions = [ assertions = [
{ assertion = intersectLists cfg.protocols [ "pop3" "imap" ] != []; {
assertion = intersectLists cfg.protocols [ "pop3" "imap" ] != [];
message = "dovecot needs at least one of the IMAP or POP3 listeners enabled"; message = "dovecot needs at least one of the IMAP or POP3 listeners enabled";
} }
{ assertion = (cfg.sslServerCert == null) == (cfg.sslServerKey == null) {
assertion = (cfg.sslServerCert == null) == (cfg.sslServerKey == null)
&& (cfg.sslCACert != null -> !(cfg.sslServerCert == null || cfg.sslServerKey == null)); && (cfg.sslCACert != null -> !(cfg.sslServerCert == null || cfg.sslServerKey == null));
message = "dovecot needs both sslServerCert and sslServerKey defined for working crypto"; message = "dovecot needs both sslServerCert and sslServerKey defined for working crypto";
} }
{ assertion = cfg.showPAMFailure -> cfg.enablePAM; {
assertion = cfg.showPAMFailure -> cfg.enablePAM;
message = "dovecot is configured with showPAMFailure while enablePAM is disabled"; message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
} }
{ assertion = cfg.sieveScripts != {} -> (cfg.mailUser != null && cfg.mailGroup != null); {
assertion = cfg.sieveScripts != {} -> (cfg.mailUser != null && cfg.mailGroup != null);
message = "dovecot requires mailUser and mailGroup to be set when sieveScripts is set"; message = "dovecot requires mailUser and mailGroup to be set when sieveScripts is set";
} }
]; ];

View File

@ -0,0 +1,79 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.ankisyncd;
name = "ankisyncd";
stateDir = "/var/lib/${name}";
authDbPath = "${stateDir}/auth.db";
sessionDbPath = "${stateDir}/session.db";
configFile = pkgs.writeText "ankisyncd.conf" (lib.generators.toINI {} {
sync_app = {
host = cfg.host;
port = cfg.port;
data_root = stateDir;
auth_db_path = authDbPath;
session_db_path = sessionDbPath;
base_url = "/sync/";
base_media_url = "/msync/";
};
});
in
{
options.services.ankisyncd = {
enable = mkEnableOption "ankisyncd";
package = mkOption {
type = types.package;
default = pkgs.ankisyncd;
defaultText = literalExample "pkgs.ankisyncd";
description = "The package to use for the ankisyncd command.";
};
host = mkOption {
type = types.str;
default = "localhost";
description = "ankisyncd host";
};
port = mkOption {
type = types.int;
default = 27701;
description = "ankisyncd port";
};
openFirewall = mkOption {
default = false;
type = types.bool;
description = "Whether to open the firewall for the specified port.";
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
environment.etc."ankisyncd/ankisyncd.conf".source = configFile;
systemd.services.ankisyncd = {
description = "ankisyncd - Anki sync server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ cfg.package ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
StateDirectory = name;
ExecStart = "${cfg.package}/bin/ankisyncd";
Restart = "always";
};
};
};
}

View File

@ -48,5 +48,5 @@ in {
}; };
meta.maintainers = with maintainers; [ gnidorah ma27 ]; meta.maintainers = with maintainers; [ gnidorah ];
} }

View File

@ -61,10 +61,7 @@ in
++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar"; ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar";
services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService; services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService;
users.groups = singleton users.groups.disnix.gid = config.ids.gids.disnix;
{ name = "disnix";
gid = config.ids.gids.disnix;
};
systemd.services = { systemd.services = {
disnix = mkIf cfg.enableMultiUser { disnix = mkIf cfg.enableMultiUser {

View File

@ -1,67 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
stateDir = "/var/lib/foldingathome";
cfg = config.services.foldingAtHome;
fahUser = "foldingathome";
in {
###### interface
options = {
services.foldingAtHome = {
enable = mkOption {
default = false;
description = ''
Whether to enable the Folding@Home to use idle CPU time.
'';
};
nickname = mkOption {
default = "Anonymous";
description = ''
A unique handle for statistics.
'';
};
config = mkOption {
default = "";
description = ''
Extra configuration. Contents will be added verbatim to the
configuration file.
'';
};
};
};
###### implementation
config = mkIf cfg.enable {
users.users.${fahUser} =
{ uid = config.ids.uids.foldingathome;
description = "Folding@Home user";
home = stateDir;
};
systemd.services.foldingathome = {
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
preStart = ''
mkdir -m 0755 -p ${stateDir}
chown ${fahUser} ${stateDir}
cp -f ${pkgs.writeText "client.cfg" cfg.config} ${stateDir}/client.cfg
'';
script = "${pkgs.su}/bin/su -s ${pkgs.runtimeShell} ${fahUser} -c 'cd ${stateDir}; ${pkgs.foldingathome}/bin/fah6'";
};
services.foldingAtHome.config = ''
[settings]
username=${cfg.nickname}
'';
};
}

View File

@ -96,7 +96,20 @@ in {
config = mkOption { config = mkOption {
default = null; default = null;
type = with types; nullOr attrs; # Migrate to new option types later: https://github.com/NixOS/nixpkgs/pull/75584
type = with lib.types; let
valueType = nullOr (oneOf [
bool
int
float
str
(lazyAttrsOf valueType)
(listOf valueType)
]) // {
description = "Yaml value";
emptyValue.value = {};
};
in valueType;
example = literalExample '' example = literalExample ''
{ {
homeassistant = { homeassistant = {

View File

@ -111,6 +111,9 @@ app_service_config_files: ${builtins.toJSON cfg.app_service_config_files}
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
hasLocalPostgresDB = let args = cfg.database_args; in
usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
in { in {
options = { options = {
services.matrix-synapse = { services.matrix-synapse = {
@ -354,13 +357,6 @@ in {
The database engine name. Can be sqlite or psycopg2. The database engine name. Can be sqlite or psycopg2.
''; '';
}; };
create_local_database = mkOption {
type = types.bool;
default = true;
description = ''
Whether to create a local database automatically.
'';
};
database_name = mkOption { database_name = mkOption {
type = types.str; type = types.str;
default = "matrix-synapse"; default = "matrix-synapse";
@ -657,6 +653,25 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [
{ assertion = hasLocalPostgresDB -> config.services.postgresql.enable;
message = ''
Cannot deploy matrix-synapse with a configuration for a local postgresql database
and a missing postgresql service. Since 20.03 it's mandatory to manually configure the
database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for
further reference).
If you
- try to deploy a fresh synapse, you need to configure the database yourself. An example
for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix>
- update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true`
to your configuration.
For further information about this update, please read the release-notes of 20.03 carefully.
'';
}
];
users.users.matrix-synapse = { users.users.matrix-synapse = {
group = "matrix-synapse"; group = "matrix-synapse";
home = cfg.dataDir; home = cfg.dataDir;
@ -669,18 +684,9 @@ in {
gid = config.ids.gids.matrix-synapse; gid = config.ids.gids.matrix-synapse;
}; };
services.postgresql = mkIf (usePostgresql && cfg.create_local_database) {
enable = mkDefault true;
ensureDatabases = [ cfg.database_name ];
ensureUsers = [{
name = cfg.database_user;
ensurePermissions = { "DATABASE \"${cfg.database_name}\"" = "ALL PRIVILEGES"; };
}];
};
systemd.services.matrix-synapse = { systemd.services.matrix-synapse = {
description = "Synapse Matrix homeserver"; description = "Synapse Matrix homeserver";
after = [ "network.target" ] ++ lib.optional config.services.postgresql.enable "postgresql.service" ; after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
preStart = '' preStart = ''
${cfg.package}/bin/homeserver \ ${cfg.package}/bin/homeserver \
@ -709,6 +715,12 @@ in {
The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0 The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0
as the behavior is now obsolete. as the behavior is now obsolete.
'') '')
(mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] ''
Database configuration must be done manually. An exemplary setup is demonstrated in
<nixpkgs/nixos/tests/matrix-synapse.nix>
'')
]; ];
meta.doc = ./matrix-synapse.xml;
} }

View File

@ -40,26 +40,35 @@ let
in join config.networking.hostName config.networking.domain; in join config.networking.hostName config.networking.domain;
in { in {
networking = { networking = {
hostName = "myhostname"; <link linkend="opt-networking.hostName">hostName</link> = "myhostname";
domain = "example.org"; <link linkend="opt-networking.domain">domain</link> = "example.org";
}; };
networking.firewall.allowedTCPPorts = [ 80 443 ]; <link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
<link linkend="opt-services.postgresql.enable">services.postgresql.enable</link> = true;
<link linkend="opt-services.postgresql.initialScript">services.postgresql.initialScript</link> = ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
'';
services.nginx = { services.nginx = {
enable = true; <link linkend="opt-services.nginx.enable">enable</link> = true;
# only recommendedProxySettings and recommendedGzipSettings are strictly required, # only recommendedProxySettings and recommendedGzipSettings are strictly required,
# but the rest make sense as well # but the rest make sense as well
recommendedTlsSettings = true; <link linkend="opt-services.nginx.recommendedTlsSettings">recommendedTlsSettings</link> = true;
recommendedOptimisation = true; <link linkend="opt-services.nginx.recommendedOptimisation">recommendedOptimisation</link> = true;
recommendedGzipSettings = true; <link linkend="opt-services.nginx.recommendedGzipSettings">recommendedGzipSettings</link> = true;
recommendedProxySettings = true; <link linkend="opt-services.nginx.recommendedProxySettings">recommendedProxySettings</link> = true;
virtualHosts = { <link linkend="opt-services.nginx.virtualHosts">virtualHosts</link> = {
# This host section can be placed on a different host than the rest, # This host section can be placed on a different host than the rest,
# i.e. to delegate from the host being accessible as ${config.networking.domain} # i.e. to delegate from the host being accessible as ${config.networking.domain}
# to another host actually running the Matrix homeserver. # to another host actually running the Matrix homeserver.
"${config.networking.domain}" = { "${config.networking.domain}" = {
locations."= /.well-known/matrix/server".extraConfig = <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.extraConfig">locations."= /.well-known/matrix/server".extraConfig</link> =
let let
# use 443 instead of the default 8448 port to unite # use 443 instead of the default 8448 port to unite
# the client-server and server-server port for simplicity # the client-server and server-server port for simplicity
@ -68,7 +77,7 @@ in {
add_header Content-Type application/json; add_header Content-Type application/json;
return 200 '${builtins.toJSON server}'; return 200 '${builtins.toJSON server}';
''; '';
locations."= /.well-known/matrix/client".extraConfig = <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.extraConfig">locations."= /.well-known/matrix/client".extraConfig</link> =
let let
client = { client = {
"m.homeserver" = { "base_url" = "https://${fqdn}"; }; "m.homeserver" = { "base_url" = "https://${fqdn}"; };
@ -84,34 +93,37 @@ in {
# Reverse proxy for Matrix client-server and server-server communication # Reverse proxy for Matrix client-server and server-server communication
${fqdn} = { ${fqdn} = {
enableACME = true; <link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;
forceSSL = true; <link linkend="opt-services.nginx.virtualHosts._name_.forceSSL">forceSSL</link> = true;
# Or do a redirect instead of the 404, or whatever is appropriate for you. # Or do a redirect instead of the 404, or whatever is appropriate for you.
# But do not put a Matrix Web client here! See the Riot Web section below. # But do not put a Matrix Web client here! See the Riot Web section below.
locations."/".extraConfig = '' <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.extraConfig">locations."/".extraConfig</link> = ''
return 404; return 404;
''; '';
# forward all Matrix API calls to the synapse Matrix homeserver # forward all Matrix API calls to the synapse Matrix homeserver
locations."/_matrix" = { locations."/_matrix" = {
proxyPass = "http://[::1]:8008"; # without a trailing / <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.proxyPass">proxyPass</link> = "http://[::1]:8008"; # without a trailing /
}; };
}; };
}; };
}; };
services.matrix-synapse = { services.matrix-synapse = {
enable = true; <link linkend="opt-services.matrix-synapse.enable">enable</link> = true;
server_name = config.networking.domain; <link linkend="opt-services.matrix-synapse.server_name">server_name</link> = config.networking.domain;
listeners = [ <link linkend="opt-services.matrix-synapse.listeners">listeners</link> = [
{ {
port = 8008; <link linkend="opt-services.matrix-synapse.listeners._.port">port</link> = 8008;
bind_address = "::1"; <link linkend="opt-services.matrix-synapse.listeners._.bind_address">bind_address</link> = "::1";
type = "http"; <link linkend="opt-services.matrix-synapse.listeners._.type">type</link> = "http";
tls = false; <link linkend="opt-services.matrix-synapse.listeners._.tls">tls</link> = false;
x_forwarded = true; <link linkend="opt-services.matrix-synapse.listeners._.x_forwarded">x_forwarded</link> = true;
resources = [ <link linkend="opt-services.matrix-synapse.listeners._.resources">resources</link> = [
{ names = [ "client" "federation" ]; compress = false; } {
<link linkend="opt-services.matrix-synapse.listeners._.resources._.names">names</link> = [ "client" "federation" ];
<link linkend="opt-services.matrix-synapse.listeners._.resources._.compress">compress</link> = false;
}
]; ];
} }
]; ];
@ -135,10 +147,10 @@ in {
<para> <para>
If you want to run a server with public registration by anybody, you can If you want to run a server with public registration by anybody, you can
then enable <option>services.matrix-synapse.enable_registration = then enable <literal><link linkend="opt-services.matrix-synapse.enable_registration">services.matrix-synapse.enable_registration</link> =
true;</option>. Otherwise, or you can generate a registration secret with true;</literal>. Otherwise, or you can generate a registration secret with
<command>pwgen -s 64 1</command> and set it with <command>pwgen -s 64 1</command> and set it with
<option>services.matrix-synapse.registration_shared_secret</option>. To <option><link linkend="opt-services.matrix-synapse.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. To
create a new user or admin, run the following after you have set the secret create a new user or admin, run the following after you have set the secret
and have rebuilt NixOS: and have rebuilt NixOS:
<screen> <screen>
@ -154,8 +166,8 @@ Success!
<literal>@your-username:example.org</literal>. Note that the registration <literal>@your-username:example.org</literal>. Note that the registration
secret ends up in the nix store and therefore is world-readable by any user secret ends up in the nix store and therefore is world-readable by any user
on your machine, so it makes sense to only temporarily activate the on your machine, so it makes sense to only temporarily activate the
<option>registration_shared_secret</option> option until a better solution <link linkend="opt-services.matrix-synapse.registration_shared_secret">registration_shared_secret</link>
for NixOS is in place. option until a better solution for NixOS is in place.
</para> </para>
</section> </section>
<section xml:id="module-services-matrix-riot-web"> <section xml:id="module-services-matrix-riot-web">
@ -177,15 +189,24 @@ Success!
Matrix Now!</link> for a list of existing clients and their supported Matrix Now!</link> for a list of existing clients and their supported
featureset. featureset.
<programlisting> <programlisting>
services.nginx.virtualHosts."riot.${fqdn}" = { {
enableACME = true; services.nginx.virtualHosts."riot.${fqdn}" = {
forceSSL = true; <link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;
serverAliases = [ <link linkend="opt-services.nginx.virtualHosts._name_.forceSSL">forceSSL</link> = true;
<link linkend="opt-services.nginx.virtualHosts._name_.serverAliases">serverAliases</link> = [
"riot.${config.networking.domain}" "riot.${config.networking.domain}"
]; ];
root = pkgs.riot-web; <link linkend="opt-services.nginx.virtualHosts._name_.root">root</link> = pkgs.riot-web.override {
}; conf = {
default_server_config."m.homeserver" = {
"base_url" = "${config.networking.domain}";
"server_name" = "${fqdn}";
};
};
};
};
}
</programlisting> </programlisting>
</para> </para>

View File

@ -88,9 +88,7 @@ in {
exec ${pkgs.sssd}/bin/sss_ssh_authorizedkeys "$@" exec ${pkgs.sssd}/bin/sss_ssh_authorizedkeys "$@"
''; '';
}; };
services.openssh.extraConfig = '' services.openssh.authorizedKeysCommand = "/etc/ssh/authorized_keys_command";
AuthorizedKeysCommand /etc/ssh/authorized_keys_command services.openssh.authorizedKeysCommandUser = "nobody";
AuthorizedKeysCommandUser nobody
'';
})]; })];
} }

View File

@ -77,6 +77,8 @@ in {
`config.services.zoneminder.database.createLocally` to true. Otherwise, `config.services.zoneminder.database.createLocally` to true. Otherwise,
when set to `false` (the default), you will have to create the database when set to `false` (the default), you will have to create the database
and database user as well as populate the database yourself. and database user as well as populate the database yourself.
Additionally, you will need to run `zmupdate.pl` yourself when
upgrading to a newer version.
''; '';
webserver = mkOption { webserver = mkOption {
@ -330,6 +332,8 @@ in {
${config.services.mysql.package}/bin/mysql < ${pkg}/share/zoneminder/db/zm_create.sql ${config.services.mysql.package}/bin/mysql < ${pkg}/share/zoneminder/db/zm_create.sql
touch "/var/lib/${dirName}/db-created" touch "/var/lib/${dirName}/db-created"
fi fi
${zoneminder}/bin/zmupdate.pl -nointeractive
''; '';
serviceConfig = { serviceConfig = {
User = user; User = user;

View File

@ -135,7 +135,6 @@ in {
serviceConfig.TimeoutStartSec=300; serviceConfig.TimeoutStartSec=300;
}; };
virtualisation.docker.enable = mkDefault true;
}) })
]; ];
} }

View File

@ -9,12 +9,13 @@ let
# a wrapper that verifies that the configuration is valid # a wrapper that verifies that the configuration is valid
promtoolCheck = what: name: file: promtoolCheck = what: name: file:
if cfg.checkConfig then
pkgs.runCommand pkgs.runCommand
"${name}-${replaceStrings [" "] [""] what}-checked" "${name}-${replaceStrings [" "] [""] what}-checked"
{ buildInputs = [ cfg.package ]; } '' { buildInputs = [ cfg.package ]; } ''
ln -s ${file} $out ln -s ${file} $out
promtool ${what} $out promtool ${what} $out
''; '' else file;
# Pretty-print JSON to a file # Pretty-print JSON to a file
writePrettyJSON = name: x: writePrettyJSON = name: x:
@ -601,6 +602,20 @@ in {
if Prometheus is served via a reverse proxy). if Prometheus is served via a reverse proxy).
''; '';
}; };
checkConfig = mkOption {
type = types.bool;
default = true;
description = ''
Check configuration with <literal>promtool
check</literal>. The call to <literal>promtool</literal> is
subject to sandboxing by Nix. When credentials are stored in
external files (<literal>password_file</literal>,
<literal>bearer_token_file</literal>, etc), they will not be
visible to <literal>promtool</literal> and it will report
errors, despite a correct configuration.
'';
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {

View File

@ -29,6 +29,7 @@ let
"fritzbox" "fritzbox"
"json" "json"
"mail" "mail"
"mikrotik"
"minio" "minio"
"nextcloud" "nextcloud"
"nginx" "nginx"
@ -197,13 +198,25 @@ in
config = mkMerge ([{ config = mkMerge ([{
assertions = [ { assertions = [ {
assertion = (cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null); assertion = cfg.snmp.enable -> (
(cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null)
);
message = '' message = ''
Please ensure you have either `services.prometheus.exporters.snmp.configuration' Please ensure you have either `services.prometheus.exporters.snmp.configuration'
or `services.prometheus.exporters.snmp.configurationPath' set! or `services.prometheus.exporters.snmp.configurationPath' set!
''; '';
} { } {
assertion = (cfg.mail.configFile == null) != (cfg.mail.configuration == {}); assertion = cfg.mikrotik.enable -> (
(cfg.mikrotik.configFile == null) != (cfg.mikrotik.configuration == null)
);
message = ''
Please specify either `services.prometheus.exporters.mikrotik.configuration'
or `services.prometheus.exporters.mikrotik.configFile'.
'';
} {
assertion = cfg.mail.enable -> (
(cfg.mail.configFile == null) != (cfg.mail.configuration == null)
);
message = '' message = ''
Please specify either 'services.prometheus.exporters.mail.configuration' Please specify either 'services.prometheus.exporters.mail.configuration'
or 'services.prometheus.exporters.mail.configFile'. or 'services.prometheus.exporters.mail.configFile'.

View File

@ -61,7 +61,7 @@ in {
ExecStart = '' ExecStart = ''
${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \ ${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--config.file ${adjustedConfigFile} \ --config.file ${escapeShellArg adjustedConfigFile} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";

View File

@ -66,7 +66,7 @@ in
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = ''
${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \ ${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \
-log.format ${cfg.logFormat} \ -log.format ${escapeShellArg cfg.logFormat} \
-log.level ${cfg.logLevel} \ -log.level ${cfg.logLevel} \
-web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
${collectSettingsArgs} \ ${collectSettingsArgs} \

View File

@ -30,7 +30,7 @@ in
${pkgs.prometheus-dnsmasq-exporter}/bin/dnsmasq_exporter \ ${pkgs.prometheus-dnsmasq-exporter}/bin/dnsmasq_exporter \
--listen ${cfg.listenAddress}:${toString cfg.port} \ --listen ${cfg.listenAddress}:${toString cfg.port} \
--dnsmasq ${cfg.dnsmasqListenAddress} \ --dnsmasq ${cfg.dnsmasqListenAddress} \
--leases_path ${cfg.leasesPath} \ --leases_path ${escapeShellArg cfg.leasesPath} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';
}; };

View File

@ -64,7 +64,7 @@ in
${pkgs.prometheus-dovecot-exporter}/bin/dovecot_exporter \ ${pkgs.prometheus-dovecot-exporter}/bin/dovecot_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \ --web.telemetry-path ${cfg.telemetryPath} \
--dovecot.socket-path ${cfg.socketPath} \ --dovecot.socket-path ${escapeShellArg cfg.socketPath} \
--dovecot.scopes ${concatStringsSep "," cfg.scopes} \ --dovecot.scopes ${concatStringsSep "," cfg.scopes} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';

View File

@ -27,7 +27,7 @@ in
ExecStart = '' ExecStart = ''
${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \ ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
--port ${toString cfg.port} \ --port ${toString cfg.port} \
${cfg.url} ${cfg.configFile} \ ${cfg.url} ${escapeShellArg cfg.configFile} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';
}; };

View File

@ -90,7 +90,7 @@ let
Timeout until mails are considered "didn't make it". Timeout until mails are considered "didn't make it".
''; '';
}; };
disableFileDelition = mkOption { disableFileDeletion = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
@ -127,8 +127,8 @@ in
''; '';
}; };
configuration = mkOption { configuration = mkOption {
type = types.submodule exporterOptions; type = types.nullOr (types.submodule exporterOptions);
default = {}; default = null;
description = '' description = ''
Specify the mailexporter configuration file to use. Specify the mailexporter configuration file to use.
''; '';
@ -147,8 +147,9 @@ in
ExecStart = '' ExecStart = ''
${pkgs.prometheus-mail-exporter}/bin/mailexporter \ ${pkgs.prometheus-mail-exporter}/bin/mailexporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
--config.file ${ --config.file ${
if cfg.configuration != {} then configurationFile else cfg.configFile if cfg.configuration != null then configurationFile else (escapeShellArg cfg.configFile)
} \ } \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';

View File

@ -0,0 +1,66 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.mikrotik;
in
{
port = 9436;
extraOpts = {
configFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to a mikrotik exporter configuration file. Mutually exclusive with
<option>configuration</option> option.
'';
example = literalExample "./mikrotik.yml";
};
configuration = mkOption {
type = types.nullOr types.attrs;
default = null;
description = ''
Mikrotik exporter configuration as nix attribute set. Mutually exclusive with
<option>configFile</option> option.
See <link xlink:href="https://github.com/nshttpd/mikrotik-exporter/blob/master/README.md"/>
for the description of the configuration file format.
'';
example = literalExample ''
{
devices = [
{
name = "my_router";
address = "10.10.0.1";
user = "prometheus";
password = "changeme";
}
];
features = {
bgp = true;
dhcp = true;
routes = true;
optics = true;
};
}
'';
};
};
serviceOpts = let
configFile = if cfg.configFile != null
then cfg.configFile
else "${pkgs.writeText "mikrotik-exporter.yml" (builtins.toJSON cfg.configuration)}";
in {
serviceConfig = {
# -port is misleading name, it actually accepts address too
ExecStart = ''
${pkgs.prometheus-mikrotik-exporter}/bin/mikrotik-exporter \
-config-file=${escapeShellArg configFile} \
-port=${cfg.listenAddress}:${toString cfg.port} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
};
}

View File

@ -54,8 +54,8 @@ in
${pkgs.prometheus-minio-exporter}/bin/minio-exporter \ ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \
-web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
-minio.server ${cfg.minioAddress} \ -minio.server ${cfg.minioAddress} \
-minio.access-key ${cfg.minioAccessKey} \ -minio.access-key ${escapeShellArg cfg.minioAccessKey} \
-minio.access-secret ${cfg.minioAccessSecret} \ -minio.access-secret ${escapeShellArg cfg.minioAccessSecret} \
${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \ ${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';

View File

@ -50,7 +50,7 @@ in
-u ${cfg.username} \ -u ${cfg.username} \
-t ${cfg.timeout} \ -t ${cfg.timeout} \
-l ${cfg.url} \ -l ${cfg.url} \
-p @${cfg.passwordFile} \ -p ${escapeShellArg "@${cfg.passwordFile}"} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';
}; };

View File

@ -30,7 +30,17 @@ in
Whether to perform certificate verification for https. Whether to perform certificate verification for https.
''; '';
}; };
constLabels = mkOption {
type = types.listOf types.str;
default = [];
example = [
"label1=value1"
"label2=value2"
];
description = ''
A list of constant labels that will be used in every metric.
'';
};
}; };
serviceOpts = { serviceOpts = {
serviceConfig = { serviceConfig = {
@ -40,6 +50,7 @@ in
--nginx.ssl-verify ${toString cfg.sslVerify} \ --nginx.ssl-verify ${toString cfg.sslVerify} \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \ --web.telemetry-path ${cfg.telemetryPath} \
--prometheus.const-labels ${concatStringsSep "," cfg.constLabels} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}
''; '';
}; };

View File

@ -67,15 +67,15 @@ in
${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \ --web.telemetry-path ${cfg.telemetryPath} \
--postfix.showq_path ${cfg.showqPath} \ --postfix.showq_path ${escapeShellArg cfg.showqPath} \
${concatStringsSep " \\\n " (cfg.extraFlags ${concatStringsSep " \\\n " (cfg.extraFlags
++ optional cfg.systemd.enable "--systemd.enable" ++ optional cfg.systemd.enable "--systemd.enable"
++ optional cfg.systemd.enable (if cfg.systemd.slice != null ++ optional cfg.systemd.enable (if cfg.systemd.slice != null
then "--systemd.slice ${cfg.systemd.slice}" then "--systemd.slice ${cfg.systemd.slice}"
else "--systemd.unit ${cfg.systemd.unit}") else "--systemd.unit ${cfg.systemd.unit}")
++ optional (cfg.systemd.enable && (cfg.systemd.journalPath != null)) ++ optional (cfg.systemd.enable && (cfg.systemd.journalPath != null))
"--systemd.journal_path ${cfg.systemd.journalPath}" "--systemd.journal_path ${escapeShellArg cfg.systemd.journalPath}"
++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${cfg.logfilePath}")} ++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${escapeShellArg cfg.logfilePath}")}
''; '';
}; };
}; };

View File

@ -19,7 +19,7 @@ in
configuration = mkOption { configuration = mkOption {
type = types.nullOr types.attrs; type = types.nullOr types.attrs;
default = {}; default = null;
description = '' description = ''
Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option. Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option.
''; '';
@ -36,15 +36,15 @@ in
}; };
logFormat = mkOption { logFormat = mkOption {
type = types.str; type = types.enum ["logfmt" "json"];
default = "logger:stderr"; default = "logfmt";
description = '' description = ''
Set the log target and format. Output format of log messages.
''; '';
}; };
logLevel = mkOption { logLevel = mkOption {
type = types.enum ["debug" "info" "warn" "error" "fatal"]; type = types.enum ["debug" "info" "warn" "error"];
default = "info"; default = "info";
description = '' description = ''
Only log messages with the given severity or above. Only log messages with the given severity or above.
@ -54,13 +54,13 @@ in
serviceOpts = let serviceOpts = let
configFile = if cfg.configurationPath != null configFile = if cfg.configurationPath != null
then cfg.configurationPath then cfg.configurationPath
else "${pkgs.writeText "snmp-eporter-conf.yml" (builtins.toJSON cfg.configuration)}"; else "${pkgs.writeText "snmp-exporter-conf.yml" (builtins.toJSON cfg.configuration)}";
in { in {
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = ''
${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \ ${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \
--config.file=${configFile} \ --config.file=${escapeShellArg configFile} \
--log.format=${cfg.logFormat} \ --log.format=${escapeShellArg cfg.logFormat} \
--log.level=${cfg.logLevel} \ --log.level=${cfg.logLevel} \
--web.listen-address=${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address=${cfg.listenAddress}:${toString cfg.port} \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}

View File

@ -55,8 +55,8 @@ in
${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \ ${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \
-telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \ -telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \
-unifi.addr ${cfg.unifiAddress} \ -unifi.addr ${cfg.unifiAddress} \
-unifi.username ${cfg.unifiUsername} \ -unifi.username ${escapeShellArg cfg.unifiUsername} \
-unifi.password ${cfg.unifiPassword} \ -unifi.password ${escapeShellArg cfg.unifiPassword} \
-unifi.timeout ${cfg.unifiTimeout} \ -unifi.timeout ${cfg.unifiTimeout} \
${optionalString cfg.unifiInsecure "-unifi.insecure" } \ ${optionalString cfg.unifiInsecure "-unifi.insecure" } \
${concatStringsSep " \\\n " cfg.extraFlags} ${concatStringsSep " \\\n " cfg.extraFlags}

View File

@ -74,10 +74,10 @@ in
${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \ ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \ --web.telemetry-path ${cfg.telemetryPath} \
--varnishstat-path ${cfg.varnishStatPath} \ --varnishstat-path ${escapeShellArg cfg.varnishStatPath} \
${concatStringsSep " \\\n " (cfg.extraFlags ${concatStringsSep " \\\n " (cfg.extraFlags
++ optional (cfg.healthPath != null) "--web.health-path ${cfg.healthPath}" ++ optional (cfg.healthPath != null) "--web.health-path ${cfg.healthPath}"
++ optional (cfg.instance != null) "-n ${cfg.instance}" ++ optional (cfg.instance != null) "-n ${escapeShellArg cfg.instance}"
++ optional cfg.noExit "--no-exit" ++ optional cfg.noExit "--no-exit"
++ optional cfg.withGoMetrics "--with-go-metrics" ++ optional cfg.withGoMetrics "--with-go-metrics"
++ optional cfg.verbose "--verbose" ++ optional cfg.verbose "--verbose"

View File

@ -59,7 +59,7 @@ in {
${optionalString cfg.verbose "-v"} \ ${optionalString cfg.verbose "-v"} \
${optionalString cfg.singleSubnetPerField "-s"} \ ${optionalString cfg.singleSubnetPerField "-s"} \
${optionalString cfg.withRemoteIp "-r"} \ ${optionalString cfg.withRemoteIp "-r"} \
${optionalString (cfg.wireguardConfig != null) "-n ${cfg.wireguardConfig}"} ${optionalString (cfg.wireguardConfig != null) "-n ${escapeShellArg cfg.wireguardConfig}"}
''; '';
}; };
}; };

View File

@ -29,17 +29,13 @@ let
}; };
# Additional /etc/hosts entries for peers with an associated hostname # Additional /etc/hosts entries for peers with an associated hostname
cjdnsExtraHosts = import (pkgs.runCommand "cjdns-hosts" {} cjdnsExtraHosts = pkgs.runCommandNoCC "cjdns-hosts" {} ''
# Generate a builder that produces an output usable as a Nix string value
''
exec >$out exec >$out
echo \'\'
${concatStringsSep "\n" (mapAttrsToList (k: v: ${concatStringsSep "\n" (mapAttrsToList (k: v:
optionalString (v.hostname != "") optionalString (v.hostname != "")
"echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}") "echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}")
(cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))} (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
echo \'\' '';
'');
parseModules = x: parseModules = x:
x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; }; x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; };
@ -144,13 +140,15 @@ in
connectTo = mkOption { connectTo = mkOption {
type = types.attrsOf ( types.submodule ( connectToSubmodule ) ); type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
default = { }; default = { };
example = { example = literalExample ''
{
"192.168.1.1:27313" = { "192.168.1.1:27313" = {
hostname = "homer.hype"; hostname = "homer.hype";
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM"; password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k"; publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
}; };
}; }
'';
description = '' description = ''
Credentials for making UDP tunnels. Credentials for making UDP tunnels.
''; '';
@ -189,13 +187,15 @@ in
connectTo = mkOption { connectTo = mkOption {
type = types.attrsOf ( types.submodule ( connectToSubmodule ) ); type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
default = { }; default = { };
example = { example = literalExample ''
{
"01:02:03:04:05:06" = { "01:02:03:04:05:06" = {
hostname = "homer.hype"; hostname = "homer.hype";
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM"; password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k"; publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
}; };
}; }
'';
description = '' description = ''
Credentials for connecting look similar to UDP credientials Credentials for connecting look similar to UDP credientials
except they begin with the mac address. except they begin with the mac address.
@ -278,7 +278,7 @@ in
}; };
}; };
networking.extraHosts = mkIf cfg.addExtraHosts cjdnsExtraHosts; networking.hostFiles = mkIf cfg.addExtraHosts [ cjdnsExtraHosts ];
assertions = [ assertions = [
{ assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null ); { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null );

View File

@ -546,7 +546,11 @@ in
options nf_conntrack nf_conntrack_helper=1 options nf_conntrack nf_conntrack_helper=1
''; '';
assertions = [ { assertion = (cfg.checkReversePath != false) || kernelHasRPFilter; assertions = [
# This is approximately "checkReversePath -> kernelHasRPFilter",
# but the checkReversePath option can include non-boolean
# values.
{ assertion = cfg.checkReversePath == false || kernelHasRPFilter;
message = "This kernel does not support rpfilter"; } message = "This kernel does not support rpfilter"; }
]; ];

View File

@ -10,14 +10,15 @@ let
{ {
description = "FreeRadius server"; description = "FreeRadius server";
wantedBy = ["multi-user.target"]; wantedBy = ["multi-user.target"];
after = ["network-online.target"]; after = ["network.target"];
wants = ["network-online.target"]; wants = ["network.target"];
preStart = '' preStart = ''
${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout
''; '';
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout -xx"; ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout" +
optionalString cfg.debug " -xx";
ExecReload = [ ExecReload = [
"${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" "${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout"
"${pkgs.coreutils}/bin/kill -HUP $MAINPID" "${pkgs.coreutils}/bin/kill -HUP $MAINPID"
@ -41,6 +42,16 @@ let
''; '';
}; };
debug = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable debug logging for freeradius (-xx
option). This should not be left on, since it includes
sensitive data such as passwords in the logs.
'';
};
}; };
in in
@ -66,6 +77,7 @@ in
}; };
systemd.services.freeradius = freeradiusService cfg; systemd.services.freeradius = freeradiusService cfg;
warnings = optional cfg.debug "Freeradius debug logging is enabled. This will log passwords in plaintext to the journal!";
}; };

View File

@ -26,6 +26,18 @@ with lib;
''; '';
}; };
user = mkOption {
type = types.str;
default = "haproxy";
description = "User account under which haproxy runs.";
};
group = mkOption {
type = types.str;
default = "haproxy";
description = "Group account under which haproxy runs.";
};
config = mkOption { config = mkOption {
type = types.nullOr types.lines; type = types.nullOr types.lines;
default = null; default = null;
@ -49,7 +61,8 @@ with lib;
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig = { serviceConfig = {
DynamicUser = true; User = cfg.user;
Group = cfg.group;
Type = "notify"; Type = "notify";
# when running the config test, don't be quiet so we can see what goes wrong # when running the config test, don't be quiet so we can see what goes wrong
ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}"; ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}";
@ -60,5 +73,16 @@ with lib;
AmbientCapabilities = "CAP_NET_BIND_SERVICE"; AmbientCapabilities = "CAP_NET_BIND_SERVICE";
}; };
}; };
users.users = optionalAttrs (cfg.user == "haproxy") {
haproxy = {
group = cfg.group;
isSystemUser = true;
};
};
users.groups = optionalAttrs (cfg.group == "haproxy") {
haproxy = {};
};
}; };
} }

View File

@ -9,6 +9,8 @@ let
iodinedUser = "iodined"; iodinedUser = "iodined";
/* is this path made unreadable by ProtectHome = true ? */
isProtected = x: hasPrefix "/root" x || hasPrefix "/home" x;
in in
{ {
imports = [ imports = [
@ -43,20 +45,21 @@ in
} }
} }
''; '';
type = types.attrsOf (types.submodule ( type = types.attrsOf (
types.submodule (
{ {
options = { options = {
server = mkOption { server = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = "Domain or Subdomain of server running iodined"; description = "Hostname of server running iodined";
example = "tunnel.mydomain.com"; example = "tunnel.mydomain.com";
}; };
relay = mkOption { relay = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = "DNS server to use as a intermediate relay to the iodined server"; description = "DNS server to use as an intermediate relay to the iodined server";
example = "8.8.8.8"; example = "8.8.8.8";
}; };
@ -70,10 +73,12 @@ in
passwordFile = mkOption { passwordFile = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = "File that contains password"; description = "Path to a file containing the password.";
}; };
}; };
})); }
)
);
}; };
server = { server = {
@ -127,10 +132,28 @@ in
description = "iodine client - ${name}"; description = "iodine client - ${name}";
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}"; script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${builtins.toString cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}";
serviceConfig = { serviceConfig = {
RestartSec = "30s"; RestartSec = "30s";
Restart = "always"; Restart = "always";
# hardening :
# Filesystem access
ProtectSystem = "strict";
ProtectHome = if isProtected cfg.passwordFile then "read-only" else "true" ;
PrivateTmp = true;
ReadWritePaths = "/dev/net/tun";
PrivateDevices = false;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
# Caps
NoNewPrivileges = true;
# Misc.
LockPersonality = true;
RestrictRealtime = true;
PrivateMounts = true;
MemoryDenyWriteExecute = true;
}; };
}; };
in in
@ -143,7 +166,25 @@ in
description = "iodine, ip over dns server daemon"; description = "iodine, ip over dns server daemon";
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}"; script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${builtins.toString cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}";
serviceConfig = {
# Filesystem access
ProtectSystem = "strict";
ProtectHome = if isProtected cfg.server.passwordFile then "read-only" else "true" ;
PrivateTmp = true;
ReadWritePaths = "/dev/net/tun";
PrivateDevices = false;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
# Caps
NoNewPrivileges = true;
# Misc.
LockPersonality = true;
RestrictRealtime = true;
PrivateMounts = true;
MemoryDenyWriteExecute = true;
};
}; };
}; };

View File

@ -65,7 +65,7 @@ let
let let
m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination; m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination;
destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0; destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0;
destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 1; destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1);
in '' in ''
# Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself
iptables -w -t nat -A nixos-nat-out \ iptables -w -t nat -A nixos-nat-out \

View File

@ -0,0 +1,75 @@
{ config, lib, pkgs, ... }:
with lib;
let
opts = { name, config, ... }: {
options = {
enable = mkOption {
default = true;
type = types.bool;
example = true;
description = "Whether to enable proxy for this bucket";
};
bucketName = mkOption {
type = types.str;
default = name;
example = "my-bucket-name";
description = "Name of Google storage bucket";
};
address = mkOption {
type = types.str;
example = "localhost:3000";
description = "The address of the proxy.";
};
};
};
enabledProxies = lib.filterAttrs (n: v: v.enable) config.services.nix-store-gcs-proxy;
mapProxies = function: lib.mkMerge (lib.mapAttrsToList function enabledProxies);
in
{
options.services.nix-store-gcs-proxy = mkOption {
type = types.attrsOf (types.submodule opts);
default = {};
description = ''
An attribute set describing an HTTP to GCS proxy that allows us to use GCS
bucket via HTTP protocol.
'';
};
config.systemd.services = mapProxies (name: cfg: {
"nix-store-gcs-proxy-${name}" = {
description = "A HTTP nix store that proxies requests to Google Storage";
wantedBy = ["multi-user.target"];
serviceConfig = {
RestartSec = 5;
StartLimitInterval = 10;
ExecStart = ''
${pkgs.nix-store-gcs-proxy}/bin/nix-store-gcs-proxy \
--bucket-name ${cfg.bucketName} \
--addr ${cfg.address}
'';
DynamicUser = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateUsers = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
NoNewPrivileges = true;
LockPersonality = true;
RestrictRealtime = true;
};
};
});
meta.maintainers = [ maintainers.mrkkrp ];
}

View File

@ -23,6 +23,8 @@ let
restrict -6 ::1 restrict -6 ::1
${toString (map (server: "server " + server + " iburst\n") cfg.servers)} ${toString (map (server: "server " + server + " iburst\n") cfg.servers)}
${cfg.extraConfig}
''; '';
ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup ${toString cfg.extraFlags}"; ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup ${toString cfg.extraFlags}";
@ -81,6 +83,17 @@ in
''; '';
}; };
extraConfig = mkOption {
type = types.lines;
default = "";
example = ''
fudge 127.127.1.0 stratum 10
'';
description = ''
Additional text appended to <filename>ntp.conf</filename>.
'';
};
extraFlags = mkOption { extraFlags = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
description = "Extra flags passed to the ntpd command."; description = "Extra flags passed to the ntpd command.";

View File

@ -244,7 +244,7 @@ in
group = "rslsync"; group = "rslsync";
}; };
users.groups = [ { name = "rslsync"; } ]; users.groups.rslsync = {};
systemd.services.resilio = with pkgs; { systemd.services.resilio = with pkgs; {
description = "Resilio Sync Service"; description = "Resilio Sync Service";

View File

@ -26,13 +26,14 @@ in {
description = "The shorewall package to use."; description = "The shorewall package to use.";
}; };
configs = lib.mkOption { configs = lib.mkOption {
type = types.attrsOf types.str; type = types.attrsOf types.lines;
default = {}; default = {};
description = '' description = ''
This option defines the Shorewall configs. This option defines the Shorewall configs.
The attribute name defines the name of the config, The attribute name defines the name of the config,
and the attribute value defines the content of the config. and the attribute value defines the content of the config.
''; '';
apply = lib.mapAttrs (name: text: pkgs.writeText "${name}" text);
}; };
}; };
}; };
@ -62,7 +63,7 @@ in {
''; '';
}; };
environment = { environment = {
etc = lib.mapAttrs' (name: conf: lib.nameValuePair "shorewall/${name}" {text=conf;}) cfg.configs; etc = lib.mapAttrs' (name: conf: lib.nameValuePair "shorewall/${name}" {source=conf;}) cfg.configs;
systemPackages = [ cfg.package ]; systemPackages = [ cfg.package ];
}; };
}; };

View File

@ -26,13 +26,14 @@ in {
description = "The shorewall package to use."; description = "The shorewall package to use.";
}; };
configs = lib.mkOption { configs = lib.mkOption {
type = types.attrsOf types.str; type = types.attrsOf types.lines;
default = {}; default = {};
description = '' description = ''
This option defines the Shorewall configs. This option defines the Shorewall configs.
The attribute name defines the name of the config, The attribute name defines the name of the config,
and the attribute value defines the content of the config. and the attribute value defines the content of the config.
''; '';
apply = lib.mapAttrs (name: text: pkgs.writeText "${name}" text);
}; };
}; };
}; };
@ -62,7 +63,7 @@ in {
''; '';
}; };
environment = { environment = {
etc = lib.mapAttrs' (name: conf: lib.nameValuePair "shorewall6/${name}" {text=conf;}) cfg.configs; etc = lib.mapAttrs' (name: conf: lib.nameValuePair "shorewall6/${name}" {source=conf;}) cfg.configs;
systemPackages = [ cfg.package ]; systemPackages = [ cfg.package ];
}; };
}; };

View File

@ -0,0 +1,61 @@
{ lib, pkgs, config, ... }:
with lib;
let
inherit (lib.types) attrsOf coercedTo listOf oneOf str int bool;
cfg = config.services.smartdns;
confFile = pkgs.writeText "smartdns.conf" (with generators;
toKeyValue {
mkKeyValue = mkKeyValueDefault {
mkValueString = v:
if isBool v then
if v then "yes" else "no"
else
mkValueStringDefault { } v;
} " ";
listsAsDuplicateKeys =
true; # Allowing duplications because we need to deal with multiple entries with the same key.
} cfg.settings);
in {
options.services.smartdns = {
enable = mkEnableOption "SmartDNS DNS server";
bindPort = mkOption {
type = types.port;
default = 53;
description = "DNS listening port number.";
};
settings = mkOption {
type =
let atom = oneOf [ str int bool ];
in attrsOf (coercedTo atom toList (listOf atom));
example = literalExample ''
{
bind = ":5353 -no-rule -group example";
cache-size = 4096;
server-tls = [ "8.8.8.8:853" "1.1.1.1:853" ];
server-https = "https://cloudflare-dns.com/dns-query -exclude-default-group";
prefetch-domain = true;
speed-check-mode = "ping,tcp:80";
};
'';
description = ''
A set that will be generated into configuration file, see the <link xlink:href="https://github.com/pymumu/smartdns/blob/master/ReadMe_en.md#configuration-parameter">SmartDNS README</link> for details of configuration parameters.
You could override the options here like <option>services.smartdns.bindPort</option> by writing <literal>settings.bind = ":5353 -no-rule -group example";</literal>.
'';
};
};
config = lib.mkIf cfg.enable {
services.smartdns.settings.bind = mkDefault ":${toString cfg.bindPort}";
systemd.packages = [ pkgs.smartdns ];
systemd.services.smartdns.wantedBy = [ "multi-user.target" ];
environment.etc."smartdns/smartdns.conf".source = confFile;
environment.etc."default/smartdns".source =
"${pkgs.smartdns}/etc/default/smartdns";
};
}

View File

@ -17,7 +17,7 @@ let
${cfg.extraConfig} ${cfg.extraConfig}
EOL EOL
ssh-keygen -f mock-hostkey -N "" ssh-keygen -q -f mock-hostkey -N ""
sshd -t -f $out -h mock-hostkey sshd -t -f $out -h mock-hostkey
''; '';
@ -238,6 +238,26 @@ in
description = "Files from which authorized keys are read."; description = "Files from which authorized keys are read.";
}; };
authorizedKeysCommand = mkOption {
type = types.str;
default = "none";
description = ''
Specifies a program to be used to look up the user's public
keys. The program must be owned by root, not writable by group
or others and specified by an absolute path.
'';
};
authorizedKeysCommandUser = mkOption {
type = types.str;
default = "nobody";
description = ''
Specifies the user under whose account the AuthorizedKeysCommand
is run. It is recommended to use a dedicated user that has no
other role on the host than running authorized keys commands.
'';
};
kexAlgorithms = mkOption { kexAlgorithms = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ default = [
@ -485,6 +505,10 @@ in
PrintMotd no # handled by pam_motd PrintMotd no # handled by pam_motd
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles} AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
${optionalString (cfg.authorizedKeysCommand != "none") ''
AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser}
''}
${flip concatMapStrings cfg.hostKeys (k: '' ${flip concatMapStrings cfg.hostKeys (k: ''
HostKey ${k.path} HostKey ${k.path}

View File

@ -205,6 +205,7 @@ in
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig = { serviceConfig = {
Type = "notify";
AmbientCapabilities = "CAP_NET_BIND_SERVICE"; AmbientCapabilities = "CAP_NET_BIND_SERVICE";
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE"; CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
ExecStart = "${pkgs.stubby}/bin/stubby -C ${confFile} ${optionalString cfg.debugLogging "-l"}"; ExecStart = "${pkgs.stubby}/bin/stubby -C ${confFile} ${optionalString cfg.debugLogging "-l"}";

View File

@ -3,32 +3,35 @@
with lib; with lib;
let let
cfg = config.services.supybot; cfg = config.services.supybot;
isStateDirHome = hasPrefix "/home/" cfg.stateDir;
isStateDirVar = cfg.stateDir == "/var/lib/supybot";
pyEnv = pkgs.python3.withPackages (p: [ p.limnoria ] ++ (cfg.extraPackages p));
in in
{ {
options = { options = {
services.supybot = { services.supybot = {
enable = mkOption { enable = mkOption {
type = types.bool;
default = false; default = false;
description = "Enable Supybot, an IRC bot"; description = "Enable Supybot, an IRC bot (also known as Limnoria).";
}; };
stateDir = mkOption { stateDir = mkOption {
# Setting this to /var/lib/supybot caused useradd to fail type = types.path;
default = "/home/supybot"; default = if versionAtLeast config.system.stateVersion "20.09"
then "/var/lib/supybot"
else "/home/supybot";
defaultText = "/var/lib/supybot";
description = "The root directory, logs and plugins are stored here"; description = "The root directory, logs and plugins are stored here";
}; };
configFile = mkOption { configFile = mkOption {
type = types.path; type = types.path;
description = '' description = ''
Path to a supybot config file. This can be generated by Path to initial supybot config file. This can be generated by
running supybot-wizard. running supybot-wizard.
Note: all paths should include the full path to the stateDir Note: all paths should include the full path to the stateDir
@ -36,21 +39,54 @@ in
''; '';
}; };
plugins = mkOption {
type = types.attrsOf types.path;
default = {};
description = ''
Attribute set of additional plugins that will be symlinked to the
<filename>plugin</filename> subdirectory.
Please note that you still need to add the plugins to the config
file (or with <literal>!load</literal>) using their attribute name.
'';
example = literalExample ''
let
plugins = pkgs.fetchzip {
url = "https://github.com/ProgVal/Supybot-plugins/archive/57c2450c.zip";
sha256 = "077snf84ibnva3sbpzdfpfma6hcdw7dflwnhg6pw7mgnf0nd84qd";
};
in
{
Wikipedia = "''${plugins}/Wikipedia";
Decide = ./supy-decide;
}
'';
};
extraPackages = mkOption {
default = p: [];
description = ''
Extra Python packages available to supybot plugins. The
value must be a function which receives the attrset defined
in <varname>python3Packages</varname> as the sole argument.
'';
example = literalExample ''p: [ p.lxml p.requests ]'';
}; };
}; };
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.pythonPackages.limnoria ]; environment.systemPackages = [ pkgs.python3Packages.limnoria ];
users.users.supybot = { users.users.supybot = {
uid = config.ids.uids.supybot; uid = config.ids.uids.supybot;
group = "supybot"; group = "supybot";
description = "Supybot IRC bot user"; description = "Supybot IRC bot user";
home = cfg.stateDir; home = cfg.stateDir;
createHome = true; isSystemUser = true;
}; };
users.groups.supybot = { users.groups.supybot = {
@ -59,19 +95,16 @@ in
systemd.services.supybot = { systemd.services.supybot = {
description = "Supybot, an IRC bot"; description = "Supybot, an IRC bot";
documentation = [ "https://limnoria.readthedocs.io/" ];
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
path = [ pkgs.pythonPackages.limnoria ];
preStart = '' preStart = ''
cd ${cfg.stateDir}
mkdir -p backup conf data plugins logs/plugins tmp web
ln -sf ${cfg.configFile} supybot.cfg
# This needs to be created afresh every time # This needs to be created afresh every time
rm -f supybot.cfg.bak rm -f '${cfg.stateDir}/supybot.cfg.bak'
''; '';
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.pythonPackages.limnoria}/bin/supybot ${cfg.stateDir}/supybot.cfg"; ExecStart = "${pyEnv}/bin/supybot ${cfg.stateDir}/supybot.cfg";
PIDFile = "/run/supybot.pid"; PIDFile = "/run/supybot.pid";
User = "supybot"; User = "supybot";
Group = "supybot"; Group = "supybot";
@ -79,8 +112,50 @@ in
Restart = "on-abort"; Restart = "on-abort";
StartLimitInterval = "5m"; StartLimitInterval = "5m";
StartLimitBurst = "1"; StartLimitBurst = "1";
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
ProtectControlGroups = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
RestrictNamespaces = true;
RestrictRealtime = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
RemoveIPC = true;
ProtectHostname = true;
CapabilityBoundingSet = "";
ProtectSystem = "full";
}
// optionalAttrs isStateDirVar {
StateDirectory = "supybot";
ProtectSystem = "strict";
}
// optionalAttrs (!isStateDirHome) {
ProtectHome = true;
}; };
}; };
systemd.tmpfiles.rules = [
"d '${cfg.stateDir}' 0700 supybot supybot - -"
"d '${cfg.stateDir}/backup' 0750 supybot supybot - -"
"d '${cfg.stateDir}/conf' 0750 supybot supybot - -"
"d '${cfg.stateDir}/data' 0750 supybot supybot - -"
"d '${cfg.stateDir}/plugins' 0750 supybot supybot - -"
"d '${cfg.stateDir}/logs' 0750 supybot supybot - -"
"d '${cfg.stateDir}/logs/plugins' 0750 supybot supybot - -"
"d '${cfg.stateDir}/tmp' 0750 supybot supybot - -"
"d '${cfg.stateDir}/web' 0750 supybot supybot - -"
"L '${cfg.stateDir}/supybot.cfg' - - - - ${cfg.configFile}"
]
++ (flip mapAttrsToList cfg.plugins (name: dest:
"L+ '${cfg.stateDir}/plugins/${name}' - - - - ${dest}"
));
}; };
} }

View File

@ -0,0 +1,46 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.services.tailscale;
in {
meta.maintainers = with maintainers; [ danderson mbaillie ];
options.services.tailscale = {
enable = mkEnableOption "Tailscale client daemon";
port = mkOption {
type = types.port;
default = 41641;
description = "The port to listen on for tunnel traffic (0=autoselect).";
};
};
config = mkIf cfg.enable {
systemd.services.tailscale = {
description = "Tailscale client daemon";
after = [ "network-pre.target" ];
wants = [ "network-pre.target" ];
wantedBy = [ "multi-user.target" ];
unitConfig = {
StartLimitIntervalSec = 0;
StartLimitBurst = 0;
};
serviceConfig = {
ExecStart =
"${pkgs.tailscale}/bin/tailscaled --port ${toString cfg.port}";
RuntimeDirectory = "tailscale";
RuntimeDirectoryMode = 755;
StateDirectory = "tailscale";
StateDirectoryMode = 700;
Restart = "on-failure";
};
};
};
}

View File

@ -133,8 +133,8 @@ let
${optionalString cfg.enableVirtualUsers '' ${optionalString cfg.enableVirtualUsers ''
guest_enable=YES guest_enable=YES
guest_username=vsftpd guest_username=vsftpd
pam_service_name=vsftpd
''} ''}
pam_service_name=vsftpd
${cfg.extraConfig} ${cfg.extraConfig}
''; '';

View File

@ -428,7 +428,7 @@ in
++ (attrValues ( ++ (attrValues (
mapAttrs (name: value: { mapAttrs (name: value: {
assertion = value.generatePrivateKeyFile -> (value.privateKey == null); assertion = value.generatePrivateKeyFile -> (value.privateKey == null);
message = "networking.wireguard.interfaces.${name}.generatePrivateKey must not be set if networking.wireguard.interfaces.${name}.privateKey is set."; message = "networking.wireguard.interfaces.${name}.generatePrivateKeyFile must not be set if networking.wireguard.interfaces.${name}.privateKey is set.";
}) cfg.interfaces)) }) cfg.interfaces))
++ map ({ interfaceName, peer, ... }: { ++ map ({ interfaceName, peer, ... }: {
assertion = (peer.presharedKey == null) || (peer.presharedKeyFile == null); assertion = (peer.presharedKey == null) || (peer.presharedKeyFile == null);

View File

@ -69,13 +69,14 @@ in
environment.systemPackages = [ cfg.package ]; environment.systemPackages = [ cfg.package ];
# Prevent systemd from potentially changing the MAC address # Prevent systemd from potentially changing the MAC address
environment.etc."systemd/network/50-zerotier.link".text = '' systemd.network.links."50-zerotier" = {
[Match] matchConfig = {
OriginalName=zt* OriginalName = "zt*";
};
[Link] linkConfig = {
AutoNegotiation=false AutoNegotiation = false;
MACAddressPolicy=none MACAddressPolicy = "none";
''; };
};
}; };
} }

View File

@ -0,0 +1,99 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.services.cage;
in {
options.services.cage.enable = mkEnableOption "cage kiosk service";
options.services.cage.user = mkOption {
type = types.str;
default = "demo";
description = ''
User to log-in as.
'';
};
options.services.cage.extraArguments = mkOption {
type = types.listOf types.str;
default = [];
defaultText = "[]";
description = "Additional command line arguments to pass to Cage.";
example = ["-d"];
};
options.services.cage.program = mkOption {
type = types.path;
default = "${pkgs.xterm}/bin/xterm";
description = ''
Program to run in cage.
'';
};
config = mkIf cfg.enable {
# The service is partially based off of the one provided in the
# cage wiki at
# https://github.com/Hjdskes/cage/wiki/Starting-Cage-on-boot-with-systemd.
systemd.services."cage-tty1" = {
enable = true;
after = [
"systemd-user-sessions.service"
"plymouth-start.service"
"plymouth-quit.service"
"systemd-logind.service"
"getty@tty1.service"
];
before = [ "graphical.target" ];
wants = [ "dbus.socket" "systemd-logind.service" "plymouth-quit.service"];
wantedBy = [ "graphical.target" ];
conflicts = [ "getty@tty1.service" ];
restartIfChanged = false;
unitConfig.ConditionPathExists = "/dev/tty1";
serviceConfig = {
ExecStart = ''
${pkgs.cage}/bin/cage \
${escapeShellArgs cfg.extraArguments} \
-- ${cfg.program}
'';
User = cfg.user;
IgnoreSIGPIPE = "no";
# Log this user with utmp, letting it show up with commands 'w' and
# 'who'. This is needed since we replace (a)getty.
UtmpIdentifier = "%n";
UtmpMode = "user";
# A virtual terminal is needed.
TTYPath = "/dev/tty1";
TTYReset = "yes";
TTYVHangup = "yes";
TTYVTDisallocate = "yes";
# Fail to start if not controlling the virtual terminal.
StandardInput = "tty-fail";
StandardOutput = "syslog";
StandardError = "syslog";
# Set up a full (custom) user session for the user, required by Cage.
PAMName = "cage";
};
};
security.pam.services.cage.text = ''
auth required pam_unix.so nullok
account required pam_unix.so
session required pam_unix.so
session required ${pkgs.systemd}/lib/security/pam_systemd.so
'';
hardware.opengl.enable = mkDefault true;
systemd.targets.graphical.wants = [ "cage-tty1.service" ];
systemd.defaultUnit = "graphical.target";
};
meta.maintainers = with lib.maintainers; [ matthewbauer flokli ];
}

View File

@ -87,10 +87,17 @@ let
${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"} ${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"}
${optionalString (cfg.recommendedTlsSettings) '' ${optionalString (cfg.recommendedTlsSettings) ''
ssl_session_cache shared:SSL:42m; # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
ssl_session_timeout 23m;
ssl_ecdh_curve secp384r1; ssl_session_timeout 1d;
ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m;
# Breaks forward secrecy: https://github.com/mozilla/server-side-tls/issues/135
ssl_session_tickets off;
# We don't enable insecure ciphers by default, so this allows
# clients to pick the most performant, per https://github.com/mozilla/server-side-tls/issues/260
ssl_prefer_server_ciphers off;
# OCSP stapling
ssl_stapling on; ssl_stapling on;
ssl_stapling_verify on; ssl_stapling_verify on;
''} ''}
@ -487,8 +494,9 @@ in
sslCiphers = mkOption { sslCiphers = mkOption {
type = types.str; type = types.str;
default = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL"; # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
description = "Ciphers to choose from when negotiating tls handshakes."; default = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
description = "Ciphers to choose from when negotiating TLS handshakes.";
}; };
sslProtocols = mkOption { sslProtocols = mkOption {

View File

@ -32,7 +32,7 @@ let
inherit plugins; inherit plugins;
} // removeAttrs c [ "type" "pythonPackages" ] } // removeAttrs c [ "type" "pythonPackages" ]
// optionalAttrs (python != null) { // optionalAttrs (python != null) {
pythonpath = "${pythonEnv}/${python.sitePackages}"; pyhome = "${pythonEnv}";
env = env =
# Argh, uwsgi expects list of key-values there instead of a dictionary. # Argh, uwsgi expects list of key-values there instead of a dictionary.
let env' = c.env or []; let env' = c.env or [];

View File

@ -0,0 +1,92 @@
{ config, lib, pkgs, ... }:
with lib;
let
dmcfg = config.services.xserver.displayManager;
ldmcfg = dmcfg.lightdm;
cfg = ldmcfg.greeters.tiny;
in
{
options = {
services.xserver.displayManager.lightdm.greeters.tiny = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable lightdm-tiny-greeter as the lightdm greeter.
Note that this greeter starts only the default X session.
You can configure the default X session using
<xref linkend="opt-services.xserver.displayManager.defaultSession"/>.
'';
};
label = {
user = mkOption {
type = types.str;
default = "Username";
description = ''
The string to represent the user_text label.
'';
};
pass = mkOption {
type = types.str;
default = "Password";
description = ''
The string to represent the pass_text label.
'';
};
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Section to describe style and ui.
'';
};
};
};
config = mkIf (ldmcfg.enable && cfg.enable) {
services.xserver.displayManager.lightdm.greeters.gtk.enable = false;
nixpkgs.config.lightdm-tiny-greeter.conf =
let
configHeader = ''
#include <gtk/gtk.h>
static const char *user_text = "${cfg.label.user}";
static const char *pass_text = "${cfg.label.pass}";
static const char *session = "${dmcfg.defaultSession}";
'';
in
optionalString (cfg.extraConfig != "")
(configHeader + cfg.extraConfig);
services.xserver.displayManager.lightdm.greeter =
mkDefault {
package = pkgs.lightdm-tiny-greeter.xgreeters;
name = "lightdm-tiny-greeter";
};
assertions = [
{
assertion = dmcfg.defaultSession != null;
message = ''
Please set: services.xserver.displayManager.defaultSession
'';
}
];
};
}

View File

@ -77,6 +77,7 @@ in
./lightdm-greeters/mini.nix ./lightdm-greeters/mini.nix
./lightdm-greeters/enso-os.nix ./lightdm-greeters/enso-os.nix
./lightdm-greeters/pantheon.nix ./lightdm-greeters/pantheon.nix
./lightdm-greeters/tiny.nix
]; ];
options = { options = {

View File

@ -183,7 +183,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
# active after the system has resumed, which probably # active after the system has resumed, which probably
# should not be the case. Just ignore it. # should not be the case. Just ignore it.
if ($unit ne "suspend.target" && $unit ne "hibernate.target" && $unit ne "hybrid-sleep.target") { if ($unit ne "suspend.target" && $unit ne "hibernate.target" && $unit ne "hybrid-sleep.target") {
unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no")) { unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
$unitsToStart{$unit} = 1; $unitsToStart{$unit} = 1;
recordUnit($startListFile, $unit); recordUnit($startListFile, $unit);
# Don't spam the user with target units that always get started. # Don't spam the user with target units that always get started.
@ -222,7 +222,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
$unitsToReload{$unit} = 1; $unitsToReload{$unit} = 1;
recordUnit($reloadListFile, $unit); recordUnit($reloadListFile, $unit);
} }
elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") ) { elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
$unitsToSkip{$unit} = 1; $unitsToSkip{$unit} = 1;
} else { } else {
if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) { if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {

View File

@ -15,6 +15,7 @@ let
map (childConfig: map (childConfig:
(import ../../../lib/eval-config.nix { (import ../../../lib/eval-config.nix {
inherit baseModules; inherit baseModules;
system = config.nixpkgs.initialSystem;
modules = modules =
(optionals inheritParent modules) (optionals inheritParent modules)
++ [ ./no-clone.nix ] ++ [ ./no-clone.nix ]

View File

@ -6,7 +6,11 @@ let
cfg = config.boot.initrd.network; cfg = config.boot.initrd.network;
dhcpinterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); dhcpInterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {}));
doDhcp = config.networking.useDHCP || dhcpInterfaces != [];
dhcpIfShellExpr = if config.networking.useDHCP
then "$(ls /sys/class/net/ | grep -v ^lo$)"
else lib.concatMapStringsSep " " lib.escapeShellArg dhcpInterfaces;
udhcpcScript = pkgs.writeScript "udhcp-script" udhcpcScript = pkgs.writeScript "udhcp-script"
'' ''
@ -62,6 +66,16 @@ in
''; '';
}; };
boot.initrd.network.flushBeforeStage2 = mkOption {
type = types.bool;
default = true;
description = ''
Whether to clear the configuration of the interfaces that were set up in
the initrd right before stage 2 takes over. Stage 2 will do the regular network
configuration based on the NixOS networking options.
'';
};
boot.initrd.network.udhcpc.extraArgs = mkOption { boot.initrd.network.udhcpc.extraArgs = mkOption {
default = []; default = [];
type = types.listOf types.str; type = types.listOf types.str;
@ -89,49 +103,45 @@ in
boot.initrd.kernelModules = [ "af_packet" ]; boot.initrd.kernelModules = [ "af_packet" ];
boot.initrd.extraUtilsCommands = '' boot.initrd.extraUtilsCommands = ''
copy_bin_and_libs ${pkgs.mkinitcpio-nfs-utils}/bin/ipconfig copy_bin_and_libs ${pkgs.klibc}/lib/klibc/bin.static/ipconfig
''; '';
boot.initrd.preLVMCommands = mkBefore ( boot.initrd.preLVMCommands = mkBefore (
# Search for interface definitions in command line. # Search for interface definitions in command line.
'' ''
ifaces=""
for o in $(cat /proc/cmdline); do for o in $(cat /proc/cmdline); do
case $o in case $o in
ip=*) ip=*)
ipconfig $o && hasNetwork=1 ipconfig $o && ifaces="$ifaces $(echo $o | cut -d: -f6)"
;; ;;
esac esac
done done
'' ''
# Otherwise, use DHCP. # Otherwise, use DHCP.
+ optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' + optionalString doDhcp ''
if [ -z "$hasNetwork" ]; then
# Bring up all interfaces. # Bring up all interfaces.
for iface in $(ls /sys/class/net/); do for iface in ${dhcpIfShellExpr}; do
echo "bringing up network interface $iface..." echo "bringing up network interface $iface..."
ip link set "$iface" up ip link set "$iface" up && ifaces="$ifaces $iface"
done done
# Acquire DHCP leases. # Acquire DHCP leases.
for iface in ${ if config.networking.useDHCP then for iface in ${dhcpIfShellExpr}; do
"$(ls /sys/class/net/ | grep -v ^lo$)"
else
lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces
}; do
echo "acquiring IP address via DHCP on $iface..." echo "acquiring IP address via DHCP on $iface..."
udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs}
done done
fi
'' ''
+ '' + cfg.postCommands);
if [ -n "$hasNetwork" ]; then
echo "networking is up!" boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 ''
${cfg.postCommands} for iface in $ifaces; do
fi ip address flush "$iface"
''); ip link down "$iface"
done
'';
}; };

View File

@ -192,22 +192,8 @@ in
###### implementation ###### implementation
config = mkIf (!config.boot.isContainer) { config = mkMerge
[ (mkIf config.boot.initrd.enable {
system.build = { inherit kernel; };
system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
# Implement consoleLogLevel both in early boot and using sysctl
# (so you don't need to reboot to have changes take effect).
boot.kernelParams =
[ "loglevel=${toString config.boot.consoleLogLevel}" ] ++
optionals config.boot.vesa [ "vga=0x317" "nomodeset" ];
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
boot.kernelModules = [ "loop" "atkbd" ];
boot.initrd.availableKernelModules = boot.initrd.availableKernelModules =
[ # Note: most of these (especially the SATA/PATA modules) [ # Note: most of these (especially the SATA/PATA modules)
# shouldn't be included by default since nixos-generate-config # shouldn't be included by default since nixos-generate-config
@ -255,6 +241,22 @@ in
[ # For LVM. [ # For LVM.
"dm_mod" "dm_mod"
]; ];
})
(mkIf (!config.boot.isContainer) {
system.build = { inherit kernel; };
system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
# Implement consoleLogLevel both in early boot and using sysctl
# (so you don't need to reboot to have changes take effect).
boot.kernelParams =
[ "loglevel=${toString config.boot.consoleLogLevel}" ] ++
optionals config.boot.vesa [ "vga=0x317" "nomodeset" ];
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
boot.kernelModules = [ "loop" "atkbd" ];
# The Linux kernel >= 2.6.27 provides firmware. # The Linux kernel >= 2.6.27 provides firmware.
hardware.firmware = [ kernel ]; hardware.firmware = [ kernel ];
@ -313,7 +315,8 @@ in
}; };
# The config options that all modules can depend upon # The config options that all modules can depend upon
system.requiredKernelConfig = with config.lib.kernelConfig; [ system.requiredKernelConfig = with config.lib.kernelConfig;
[
# !!! Should this really be needed? # !!! Should this really be needed?
(isYes "MODULES") (isYes "MODULES")
(isYes "BINFMT_ELF") (isYes "BINFMT_ELF")
@ -325,6 +328,8 @@ in
{ assertion = attrs.assertion cfg; inherit (attrs) message; } { assertion = attrs.assertion cfg; inherit (attrs) message; }
) config.system.requiredKernelConfig; ) config.system.requiredKernelConfig;
}; })
];
} }

View File

@ -67,7 +67,12 @@ let
(assertOnlyFields [ (assertOnlyFields [
"PrivateKeyFile" "ListenPort" "FwMark" "PrivateKeyFile" "ListenPort" "FwMark"
]) ])
(assertRange "FwMark" 1 4294967295) # The following check won't work on nix <= 2.2
# see https://github.com/NixOS/nix/pull/2378
#
# Add this again when we'll have drop the
# nix < 2.2 support.
# (assertRange "FwMark" 1 4294967295)
]; ];
# NOTE The PresharedKey directive is missing on purpose here, please # NOTE The PresharedKey directive is missing on purpose here, please
@ -181,7 +186,12 @@ let
(assertOnlyFields [ (assertOnlyFields [
"InterfaceId" "Independent" "InterfaceId" "Independent"
]) ])
(assertRange "InterfaceId" 1 4294967295) # The following check won't work on nix <= 2.2
# see https://github.com/NixOS/nix/pull/2378
#
# Add this again when we'll have drop the
# nix < 2.2 support.
# (assertRange "InterfaceId" 1 4294967295)
(assertValueOneOf "Independent" boolValues) (assertValueOneOf "Independent" boolValues)
]; ];
@ -235,6 +245,26 @@ let
(assertValueOneOf "AutoJoin" boolValues) (assertValueOneOf "AutoJoin" boolValues)
]; ];
checkRoutingPolicyRule = checkUnitConfig "RoutingPolicyRule" [
(assertOnlyFields [
"TypeOfService" "From" "To" "FirewallMark" "Table" "Priority"
"IncomingInterface" "OutgoingInterface" "SourcePort" "DestinationPort"
"IPProtocol" "InvertRule" "Family"
])
(assertRange "TypeOfService" 0 255)
# The following check won't work on nix <= 2.2
# see https://github.com/NixOS/nix/pull/2378
#
# Add this again when we'll have drop the
# nix < 2.2 support.
# (assertRange "FirewallMark" 1 4294967295)
(assertInt "Priority")
(assertPort "SourcePort")
(assertPort "DestinationPort")
(assertValueOneOf "InvertRule" boolValues)
(assertValueOneOf "Family" ["ipv4" "ipv6" "both"])
];
checkRoute = checkUnitConfig "Route" [ checkRoute = checkUnitConfig "Route" [
(assertOnlyFields [ (assertOnlyFields [
"Gateway" "GatewayOnLink" "Destination" "Source" "Metric" "Gateway" "GatewayOnLink" "Destination" "Source" "Metric"
@ -325,6 +355,14 @@ let
}; };
linkOptions = commonNetworkOptions // { linkOptions = commonNetworkOptions // {
# overwrite enable option from above
enable = mkOption {
default = true;
type = types.bool;
description = ''
Whether to enable this .link unit. It's handled by udev no matter if <command>systemd-networkd</command> is enabled or not
'';
};
linkConfig = mkOption { linkConfig = mkOption {
default = {}; default = {};
@ -535,6 +573,22 @@ let
}; };
}; };
routingPolicyRulesOptions = {
options = {
routingPolicyRuleConfig = mkOption {
default = { };
example = { routingPolicyRuleConfig = { Table = 10; IncomingInterface = "eth1"; Family = "both"; } ;};
type = types.addCheck (types.attrsOf unitOption) checkRoutingPolicyRule;
description = ''
Each attribute in this set specifies an option in the
<literal>[RoutingPolicyRule]</literal> section of the unit. See
<citerefentry><refentrytitle>systemd.network</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> for details.
'';
};
};
};
routeOptions = { routeOptions = {
options = { options = {
routeConfig = mkOption { routeConfig = mkOption {
@ -772,6 +826,16 @@ let
''; '';
}; };
routingPolicyRules = mkOption {
default = [ ];
type = with types; listOf (submodule routingPolicyRulesOptions);
description = ''
A list of routing policy rules sections to be added to the unit. See
<citerefentry><refentrytitle>systemd.network</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> for details.
'';
};
routes = mkOption { routes = mkOption {
default = [ ]; default = [ ];
type = with types; listOf (submodule routeOptions); type = with types; listOf (submodule routeOptions);
@ -928,6 +992,11 @@ let
[Route] [Route]
${attrsToSection x.routeConfig} ${attrsToSection x.routeConfig}
'')}
${flip concatMapStrings def.routingPolicyRules (x: ''
[RoutingPolicyRule]
${attrsToSection x.routingPolicyRuleConfig}
'')} '')}
${def.extraConfig} ${def.extraConfig}
''; '';
@ -984,7 +1053,14 @@ in
}; };
config = mkIf config.systemd.network.enable { config = mkMerge [
# .link units are honored by udev, no matter if systemd-networkd is enabled or not.
{
systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links;
environment.etc = unitFiles;
}
(mkIf config.systemd.network.enable {
users.users.systemd-network.group = "systemd-network"; users.users.systemd-network.group = "systemd-network";
@ -992,12 +1068,9 @@ in
"systemd-networkd.service" "systemd-networkd-wait-online.service" "systemd-networkd.service" "systemd-networkd-wait-online.service"
]; ];
systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
// mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
// mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks; // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks;
environment.etc = unitFiles;
systemd.services.systemd-networkd = { systemd.services.systemd-networkd = {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
restartTriggers = attrNames unitFiles; restartTriggers = attrNames unitFiles;
@ -1023,5 +1096,6 @@ in
}; };
services.resolved.enable = mkDefault true; services.resolved.enable = mkDefault true;
}; })
];
} }

View File

@ -210,6 +210,8 @@ done
# Create device nodes in /dev. # Create device nodes in /dev.
@preDeviceCommands@ @preDeviceCommands@
echo "running udev..." echo "running udev..."
mkdir -p /etc/systemd
ln -sfn @linkUnits@ /etc/systemd/network
mkdir -p /etc/udev mkdir -p /etc/udev
ln -sfn @udevRules@ /etc/udev/rules.d ln -sfn @udevRules@ /etc/udev/rules.d
mkdir -p /dev/.mdadm mkdir -p /dev/.mdadm

View File

@ -120,6 +120,7 @@ let
# Copy udev. # Copy udev.
copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd
copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl
copy_bin_and_libs ${udev}/bin/udevadm copy_bin_and_libs ${udev}/bin/udevadm
for BIN in ${udev}/lib/udev/*_id; do for BIN in ${udev}/lib/udev/*_id; do
copy_bin_and_libs $BIN copy_bin_and_libs $BIN
@ -198,6 +199,14 @@ let
''; # */ ''; # */
linkUnits = pkgs.runCommand "link-units" {
allowedReferences = [ extraUtils ];
preferLocalBuild = true;
} ''
mkdir -p $out
cp -v ${udev}/lib/systemd/network/*.link $out/
'';
udevRules = pkgs.runCommand "udev-rules" { udevRules = pkgs.runCommand "udev-rules" {
allowedReferences = [ extraUtils ]; allowedReferences = [ extraUtils ];
preferLocalBuild = true; preferLocalBuild = true;
@ -208,7 +217,9 @@ let
cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/ cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/
cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/ cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/
cp -v ${udev}/lib/udev/rules.d/75-net-description.rules $out/
cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/ cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/
cp -v ${udev}/lib/udev/rules.d/80-net-setup-link.rules $out/
cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/ cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/
${config.boot.initrd.extraUdevRulesCommands} ${config.boot.initrd.extraUdevRulesCommands}
@ -222,7 +233,7 @@ let
--replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \ --replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \
--replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \ --replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \
--replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \ --replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \
--replace ${udev}/bin/udevadm ${extraUtils}/bin/udevadm --replace ${udev} ${extraUtils}
done done
# Work around a bug in QEMU, which doesn't implement the "READ # Work around a bug in QEMU, which doesn't implement the "READ
@ -257,7 +268,7 @@ let
${pkgs.buildPackages.busybox}/bin/ash -n $target ${pkgs.buildPackages.busybox}/bin/ash -n $target
''; '';
inherit udevRules extraUtils modulesClosure; inherit linkUnits udevRules extraUtils modulesClosure;
inherit (config.boot) resumeDevice; inherit (config.boot) resumeDevice;
@ -379,6 +390,17 @@ in
''; '';
}; };
boot.initrd.enable = mkOption {
type = types.bool;
default = !config.boot.isContainer;
defaultText = "!config.boot.isContainer";
description = ''
Whether to enable the NixOS initial RAM disk (initrd). This may be
needed to perform some initialisation tasks (like mounting
network/encrypted file systems) before continuing the boot process.
'';
};
boot.initrd.prepend = mkOption { boot.initrd.prepend = mkOption {
default = [ ]; default = [ ];
type = types.listOf types.str; type = types.listOf types.str;
@ -544,7 +566,7 @@ in
}; };
config = mkIf (!config.boot.isContainer) { config = mkIf config.boot.initrd.enable {
assertions = [ assertions = [
{ assertion = any (fs: fs.mountPoint == "/") fileSystems; { assertion = any (fs: fs.mountPoint == "/") fileSystems;
message = "The fileSystems option does not specify your root file system."; message = "The fileSystems option does not specify your root file system.";

View File

@ -59,6 +59,11 @@ in rec {
optional (attr ? ${name} && ! isMacAddress attr.${name}) optional (attr ? ${name} && ! isMacAddress attr.${name})
"Systemd ${group} field `${name}' must be a valid mac address."; "Systemd ${group} field `${name}' must be a valid mac address.";
isPort = i: i >= 0 && i <= 65535;
assertPort = name: group: attr:
optional (attr ? ${name} && ! isPort attr.${name})
"Error on the systemd ${group} field `${name}': ${attr.name} is not a valid port number.";
assertValueOneOf = name: values: group: attr: assertValueOneOf = name: values: group: attr:
optional (attr ? ${name} && !elem attr.${name} values) optional (attr ? ${name} && !elem attr.${name} values)

View File

@ -94,7 +94,7 @@ in
default = 0; default = 0;
type = types.int; type = types.int;
description = '' description = ''
UID of created file. Only takes affect when the file is UID of created file. Only takes effect when the file is
copied (that is, the mode is not 'symlink'). copied (that is, the mode is not 'symlink').
''; '';
}; };
@ -103,7 +103,7 @@ in
default = 0; default = 0;
type = types.int; type = types.int;
description = '' description = ''
GID of created file. Only takes affect when the file is GID of created file. Only takes effect when the file is
copied (that is, the mode is not 'symlink'). copied (that is, the mode is not 'symlink').
''; '';
}; };
@ -113,7 +113,7 @@ in
type = types.str; type = types.str;
description = '' description = ''
User name of created file. User name of created file.
Only takes affect when the file is copied (that is, the mode is not 'symlink'). Only takes effect when the file is copied (that is, the mode is not 'symlink').
Changing this option takes precedence over <literal>uid</literal>. Changing this option takes precedence over <literal>uid</literal>.
''; '';
}; };
@ -123,7 +123,7 @@ in
type = types.str; type = types.str;
description = '' description = ''
Group name of created file. Group name of created file.
Only takes affect when the file is copied (that is, the mode is not 'symlink'). Only takes effect when the file is copied (that is, the mode is not 'symlink').
Changing this option takes precedence over <literal>gid</literal>. Changing this option takes precedence over <literal>gid</literal>.
''; '';
}; };

Some files were not shown because too many files have changed in this diff Show More