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:
```bash
sh ./generate.sh
./generate.sh
```

View File

@ -233,7 +233,7 @@ mkDerivation {
</term>
<listitem>
<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>
<listitem xml:id="ssec-gnome-common-issues-unwrappable-package-gnome-shell-ext">
<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
checksum can be then take from the failed build.
When the `Cargo.lock`, provided by upstream, is not in sync with the
`Cargo.toml`, it is possible to use `cargoPatches` to update it. All patches
added in `cargoPatches` will also be prepended to the patches in `patches` at
build-time.
Per the instructions in the [Cargo Book](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html)
best practices guide, Rust applications should always commit the `Cargo.lock`
file in git to ensure a reproducible build. However, a few packages do not, and
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 `Cargo.lock` file is in sync with the `src` attribute, and will compress the
vendor directory into a tar.gz archive.
The fetcher will verify that the `Cargo.lock` file is in sync with the `src`
attribute, and fail the build if not. It will also will compress the vendor
directory into a tar.gz archive.
### Building a crate for a different target

View File

@ -131,7 +131,12 @@ rec {
origArgs = auto // args;
pkgs = f 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

View File

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

View File

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

View File

@ -1,12 +1,7 @@
{ lib, version }:
{ 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 :)
@ -18,4 +13,14 @@ with lib;
module = { tristate = "m"; };
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
else
res;
result = { inherit options config; };
result = {
inherit options;
config = removeAttrs config [ "_module" ];
inherit (config) _module;
};
in result;
# collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
@ -389,7 +393,7 @@ rec {
let
# Process mkMerge and mkIf properties.
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;
# Process mkOverride properties.
@ -410,10 +414,9 @@ rec {
# Type-check the remaining definitions, and merge them. Or throw if no definitions.
mergedValue =
if isDefined then
foldl' (res: def:
if type.check def.value then res
else throw "The option value `${showOption loc}' in `${def.file}' is not of type `${type.description}'."
) (type.merge loc defsFinal) defsFinal
if all (def: type.check def.value) defsFinal then type.merge loc defsFinal
else let firstInvalid = findFirst (def: ! type.check def.value) null defsFinal;
in throw "The option value `${showOption loc}' in `${firstInvalid.file}' is not of type `${type.description}'."
else
# (nixos-option detects this specific error message and gives it special
# handling. If changed here, please change it there too.)

View File

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

View File

@ -26,7 +26,13 @@ let
"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"
];

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 = {
expr = generators.toINI {} {
"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
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
# attrsOf should work with conditional definitions
# 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 "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
====== module tests ======
$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 {
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" ];
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" ];

View File

@ -1,5 +1,5 @@
/* List of NixOS maintainers.
```nix
handle = {
# Required
name = "Your name";
@ -13,32 +13,33 @@
fingerprint = "AAAA BBBB CCCC DDDD EEEE FFFF 0000 1111 2222 3333";
}];
};
```
where
where
- `handle` is the handle you are going to use in nixpkgs expressions,
- `name` is your, preferably real, name,
- `email` is your maintainer email address, and
- `github` is your GitHub handle (as it appears in the URL of your profile page, `https://github.com/<userhandle>`),
- `githubId` is your GitHub user ID, which can be found at `https://api.github.com/users/<userhandle>`,
- `keys` is a list of your PGP/GPG key IDs and fingerprints.
- `handle` is the handle you are going to use in nixpkgs expressions,
- `name` is your, preferably real, name,
- `email` is your maintainer email address, and
- `github` is your GitHub handle (as it appears in the URL of your profile page, `https://github.com/<userhandle>`),
- `githubId` is your GitHub user ID, which can be found at `https://api.github.com/users/<userhandle>`,
- `keys` is a list of your PGP/GPG key IDs and fingerprints.
`handle == github` is strongly preferred whenever `github` is an acceptable attribute name and is short and convenient.
`handle == github` is strongly preferred whenever `github` is an acceptable attribute name and is short and convenient.
Add PGP/GPG keys only if you actually use them to sign commits and/or mail.
Add PGP/GPG keys only if you actually use them to sign commits and/or mail.
To get the required PGP/GPG values for a key run
```shell
gpg --keyid-format 0xlong --fingerprint <email> | head -n 2
```
To get the required PGP/GPG values for a key run
```shell
gpg --keyid-format 0xlong --fingerprint <email> | head -n 2
```
!!! Note that PGP/GPG values stored here are for informational purposes only, don't use this file as a source of truth.
!!! Note that PGP/GPG values stored here are for informational purposes only, don't use this file as a source of truth.
More fields may be added in the future.
More fields may be added in the future.
Please keep the list alphabetically sorted.
See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data.
*/
Please keep the list alphabetically sorted.
See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data.
*/
{
"0x4A6F" = {
email = "0x4A6F@shackspace.de";
@ -710,6 +711,12 @@
githubId = 55833;
name = "Troels Henriksen";
};
atkinschang = {
email = "atkinschang+nixpkgs@gmail.com";
github = "AtkinsChang";
githubId = 5193600;
name = "Atkins Chang";
};
atnnn = {
email = "etienne@atnnn.com";
github = "atnnn";
@ -1461,6 +1468,16 @@
githubId = 5684605;
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 = {
email = "pumpkingod@gmail.com";
github = "copumpkin";
@ -1562,10 +1579,12 @@
githubId = 2217136;
name = "Ștefan D. Mihăilă";
keys = [
{ longkeyid = "rsa4096/6E68A39BF16A3ECB";
{
longkeyid = "rsa4096/6E68A39BF16A3ECB";
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";
}
];
@ -1782,7 +1801,7 @@
name = "Didier J. Devroye";
};
devhell = {
email = "\"^\"@regexmail.net";
email = ''"^"@regexmail.net'';
github = "devhell";
githubId = 896182;
name = "devhell";
@ -1948,7 +1967,7 @@
drewrisinger = {
email = "drisinger+nixpkgs@gmail.com";
github = "drewrisinger";
gitHubId = 10198051;
githubId = 10198051;
name = "Drew Risinger";
};
dsferruzza = {
@ -2121,7 +2140,7 @@
};
ehmry = {
email = "ehmry@posteo.net";
github= "ehmry";
github = "ehmry";
githubId = 537775;
name = "Emery Hemingway";
};
@ -2209,10 +2228,10 @@
name = "Jack Kelly";
};
enorris = {
name = "Eric Norris";
email = "erictnorris@gmail.com";
github = "ericnorris";
githubId = 1906605;
name = "Eric Norris";
email = "erictnorris@gmail.com";
github = "ericnorris";
githubId = 1906605;
};
Enteee = {
email = "nix@duckpond.ch";
@ -2735,6 +2754,12 @@
githubId = 3217744;
name = "Peter Ferenczy";
};
gila = {
email = "jeffry.molanus@gmail.com";
github = "gila";
githubId = 15957973;
name = "Jeffry Molanus";
};
gilligan = {
email = "tobias.pflug@gmail.com";
github = "gilligan";
@ -2881,7 +2906,7 @@
github = "hansjoergschurr";
githubId = 9850776;
name = "Hans-Jörg Schurr";
};
};
HaoZeke = {
email = "r95g10@gmail.com";
github = "haozeke";
@ -3086,6 +3111,12 @@
githubId = 4401220;
name = "Michael Eden";
};
illiusdope = {
email = "mat@marini.ca";
github = "illiusdope";
githubId = 61913481;
name = "Mat Marini";
};
ilya-fedin = {
email = "fedin-ilja2010@ya.ru";
github = "ilya-fedin";
@ -3580,6 +3611,12 @@
github = "jorsn";
githubId = 4646725;
};
joshuafern = {
name = "Joshua Fern";
email = "joshuafern@protonmail.com";
github = "JoshuaFern";
githubId = 4300747;
};
jpas = {
name = "Jarrod Pas";
email = "jarrod@jarrodpas.com";
@ -3688,6 +3725,16 @@
githubId = 66669;
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 = {
email = "kai.harries@gmail.com";
github = "kaiha";
@ -4113,6 +4160,12 @@
github = "leonardoce";
name = "Leonardo Cecchi";
};
leshainc = {
email = "leshainc@fomalhaut.me";
github = "LeshaInc";
githubId = 42153076;
name = "Alexey Nikashkin";
};
lethalman = {
email = "lucabru@src.gnome.org";
github = "lethalman";
@ -4125,6 +4178,16 @@
githubId = 3425311;
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 = {
email = "git@sphalerite.org";
github = "lheckemann";
@ -4208,10 +4271,10 @@
}];
};
luis = {
email = "luis.nixos@gmail.com";
github = "Luis-Hebendanz";
githubId = 22085373;
name = "Luis Hebendanz";
email = "luis.nixos@gmail.com";
github = "Luis-Hebendanz";
githubId = 22085373;
name = "Luis Hebendanz";
};
lionello = {
email = "lio@lunesu.com";
@ -4454,12 +4517,12 @@
githubId = 50230945;
name = "Marcus Boyd";
};
marenz = {
email = "marenz@arkom.men";
github = "marenz2569";
githubId = 12773269;
name = "Markus Schmidl";
};
marenz = {
email = "marenz@arkom.men";
github = "marenz2569";
githubId = 12773269;
name = "Markus Schmidl";
};
markus1189 = {
email = "markus1189@gmail.com";
github = "markus1189";
@ -4528,6 +4591,12 @@
githubId = 1711539;
name = "matklad";
};
matt-snider = {
email = "matt.snider@protonmail.com";
github = "matt-snider";
githubId = 11810057;
name = "Matt Snider";
};
matthewbauer = {
email = "mjbauer95@gmail.com";
github = "matthewbauer";
@ -4562,6 +4631,12 @@
githubId = 1269099;
name = "Marius Bakke";
};
mbaillie = {
email = "martin@baillie.email";
github = "martinbaillie";
githubId = 613740;
name = "Martin Baillie";
};
mbbx6spp = {
email = "me@susanpotter.net";
github = "mbbx6spp";
@ -4703,7 +4778,7 @@
githubId = 668926;
name = "Maximilian Güntner";
};
mhaselsteiner = {
mhaselsteiner = {
email = "magdalena.haselsteiner@gmx.at";
github = "mhaselsteiner";
githubId = 20536514;
@ -4868,11 +4943,11 @@
mmilata = {
email = "martin@martinmilata.cz";
github = "mmilata";
gitHubId = 85857;
githubId = 85857;
name = "Martin Milata";
};
mmlb = {
email = "me.mmlb@mmlb.me";
email = "manny@peekaboo.mmlb.icu";
github = "mmlb";
name = "Manuel Mendez";
};
@ -4945,6 +5020,12 @@
githubId = 118035;
name = "Corbin Simpson";
};
mothsart = {
email = "jerem.ferry@gmail.com";
github = "mothsart";
githubId = 10601196;
name = "Jérémie Ferry";
};
mounium = {
email = "muoniurn@gmail.com";
github = "mounium";
@ -5482,6 +5563,12 @@
githubId = 11016164;
name = "Fedor Pakhomov";
};
paluh = {
email = "paluho@gmail.com";
github = "paluh";
githubId = 190249;
name = "Tomasz Rybarczyk";
};
pamplemousse = {
email = "xav.maso@gmail.com";
github = "Pamplemousse";
@ -5755,11 +5842,10 @@
github = "pradyuman";
githubId = 9904569;
name = "Pradyuman Vig";
keys = [
{ longkeyid = "rsa4096/4F74D5361C4CA31E";
fingerprint = "240B 57DE 4271 2480 7CE3 EAC8 4F74 D536 1C4C A31E";
}
];
keys = [{
longkeyid = "rsa4096/4F74D5361C4CA31E";
fingerprint = "240B 57DE 4271 2480 7CE3 EAC8 4F74 D536 1C4C A31E";
}];
};
prikhi = {
email = "pavan.rikhi@gmail.com";
@ -5773,10 +5859,12 @@
githubId = 7537109;
name = "Michael Weiss";
keys = [
{ longkeyid = "ed25519/0x130826A6C2A389FD"; # Git only
{
longkeyid = "ed25519/0x130826A6C2A389FD"; # Git only
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";
}
];
@ -5871,6 +5959,12 @@
githubId = 4579165;
name = "Danny Bautista";
};
peelz = {
email = "peelz.dev+nixpkgs@gmail.com";
github = "louistakepillz";
githubId = 920910;
name = "peelz";
};
q3k = {
email = "q3k@q3k.org";
github = "q3k";
@ -6136,12 +6230,10 @@
github = "rnhmjoj";
githubId = 2817565;
name = "Michele Guerini Rocco";
keys =
[
{ longkeyid = "ed25519/0xBFBAF4C975F76450";
fingerprint = "92B2 904F D293 C94D C4C9 3E6B BFBA F4C9 75F7 6450";
}
];
keys = [{
longkeyid = "ed25519/0xBFBAF4C975F76450";
fingerprint = "92B2 904F D293 C94D C4C9 3E6B BFBA F4C9 75F7 6450";
}];
};
rob = {
email = "rob.vermaas@gmail.com";
@ -6346,10 +6438,10 @@
}];
};
samrose = {
email = "samuel.rose@gmail.com";
github = "samrose";
githubId = 115821;
name = "Sam Rose";
email = "samuel.rose@gmail.com";
github = "samrose";
githubId = 115821;
name = "Sam Rose";
};
samueldr = {
email = "samuel@dionne-riel.com";
@ -6661,6 +6753,12 @@
githubId = 848812;
name = "Stephan Jau";
};
sjfloat = {
email = "steve+nixpkgs@jonescape.com";
github = "sjfloat";
githubId = 216167;
name = "Steve Jones";
};
sjmackenzie = {
email = "setori88@gmail.com";
github = "sjmackenzie";
@ -7219,6 +7317,12 @@
githubId = 844343;
name = "Thiago K. Okada";
};
thmzlt = {
email = "git@thomazleite.com";
github = "thmzlt";
githubId = 7709;
name = "Thomaz Leite";
};
ThomasMader = {
email = "thomas.mader@gmail.com";
github = "ThomasMader";
@ -7294,10 +7398,10 @@
github = "tkerber";
githubId = 5722198;
name = "Thomas Kerber";
keys = [ {
keys = [{
longkeyid = "rsa4096/0x8489B911F9ED617B";
fingerprint = "556A 403F B0A2 D423 F656 3424 8489 B911 F9ED 617B";
} ];
}];
};
tmplt = {
email = "tmplt@dragons.rocks";
@ -7577,7 +7681,8 @@
};
vcunat = {
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";
githubId = 1785925;
keys = [{

View File

@ -6,6 +6,7 @@ use warnings;
use CPAN::Meta();
use CPANPLUS::Backend();
use Module::CoreList;
use Getopt::Long::Descriptive qw( describe_options );
use JSON::PP qw( encode_json );
use Log::Log4perl qw(:easy);
@ -164,7 +165,7 @@ Readonly::Hash my %LICENSE_MAP => (
# License not provided in metadata.
unknown => {
licenses => [qw( unknown )],
licenses => [],
amb => 1
}
);
@ -278,14 +279,8 @@ sub get_deps {
foreach my $n ( $deps->required_modules ) {
next if $n eq "perl";
# Figure out whether the module is a core module by attempting
# to `use` the module in a pure Perl interpreter and checking
# 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 @core = Module::CoreList->find_modules(qr/^$n$/);
next if (@core);
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="networking.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="profiles.xml" />
<xi:include href="kubernetes.xml" />

View File

@ -154,7 +154,7 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
</listitem>
<listitem>
<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
<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>.
@ -196,10 +196,10 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
</listitem>
<listitem>
<para>
There is now only one Xfce package-set and module. This means attributes, <literal>xfce4-14</literal>
<literal>xfce4-12</literal>, 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
time during the releases development (if viable).
There is now only one Xfce package-set and module. This means that attributes <literal>xfce4-14</literal>
and <literal>xfceUnstable</literal> all now point to the latest Xfce 4.14
packages. And in the future NixOS releases will be the latest released version of Xfce available at the
time of the release's development (if viable).
</para>
</listitem>
<listitem>
@ -235,7 +235,7 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
<listitem>
<para>
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>
</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>.
</para>
</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>
</section>
@ -703,6 +710,72 @@ auth required pam_succeed_if.so uid >= 1000 quiet
via <option>boot.initrd.luks.fido2Support</option>.
</para>
</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>
</section>
</section>

View File

@ -23,6 +23,20 @@
Support is planned until the end of April 2021, handing over to 21.03.
</para>
</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>
</section>
@ -72,6 +86,16 @@
}</programlisting>
</para>
</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>
</section>

View File

@ -41,6 +41,12 @@ let
# default to the argument. That way this new default could propagate all
# they way through, but has the last priority behind everything else.
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_);
};
};
@ -55,7 +61,7 @@ in rec {
args = extraArgs;
specialArgs =
{ modulesPath = builtins.toString ../modules; } // specialArgs;
}) config options;
}) config options _module;
# These are the extra arguments passed to every module. In
# particular, Nixpkgs is passed through the "pkgs" argument.
@ -63,5 +69,5 @@ in rec {
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;
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
if lib.length invalidNodeNames > 0 then
throw ''
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.
Please stick to alphanumeric chars and underscores as separation.

View File

@ -14,7 +14,7 @@ rec {
# becomes dev-xyzzy. FIXME: slow.
escapeSystemdPath = s:
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
toShellPath = shell:

View File

@ -18,7 +18,7 @@ state_dir=$HOME/amis/ec2-images
home_region=eu-west-1
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
ca-central-1
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 {
type = types.lines;
default = "";
example = "192.168.0.1 lanlocalhost";
description = ''
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" ];
};
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 =
{ # /etc/services: TCP/UDP port assignments.
services.source = pkgs.iana-etc + "/etc/services";
@ -167,12 +186,8 @@ in
protocols.source = pkgs.iana-etc + "/etc/protocols";
# /etc/hosts: Hostname-to-IP mappings.
hosts.text = let
oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip};
allToString = set: concatMapStringsSep "\n" (oneToString set) (attrNames set);
in ''
${allToString (filterAttrs (_: v: v != []) cfg.hosts)}
${cfg.extraHosts}
hosts.source = pkgs.runCommandNoCC "hosts" {} ''
cat ${escapeShellArgs cfg.hostFiles} > $out
'';
# /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.
firebird = 95;
#keys = 96; # unused
#haproxy = 97; # DynamicUser as of 2019-11-08
#haproxy = 97; # dynamically allocated as of 2020-03-11
mongodb = 98;
openldap = 99;
#users = 100; # unused
@ -448,7 +448,7 @@ in
#tcpcryptd = 93; # unused
firebird = 95;
keys = 96;
#haproxy = 97; # DynamicUser as of 2019-11-08
#haproxy = 97; # dynamically allocated as of 2020-03-11
#mongodb = 98; # unused
openldap = 99;
munin = 102;

View File

@ -216,6 +216,14 @@ in
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 = {

View File

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

View File

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

View File

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

View File

@ -136,6 +136,27 @@ let
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 {
type = types.str;
default = "weekly";
default = "daily";
description = ''
Systemd calendar expression when to check for renewal. See
<citerefentry><refentrytitle>systemd.time</refentrytitle>
@ -281,15 +302,18 @@ in
lpath = "acme/${cert}";
apath = "/var/lib/${lpath}";
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 ]
++ optionals (cfg.acceptTerms) [ "--accept-tos" ]
++ optionals (data.dnsProvider != null && !data.dnsPropagationCheck) [ "--dns.disable-cp" ]
++ concatLists (mapAttrsToList (name: root: [ "-d" name ]) data.extraDomains)
++ (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)];
runOpts = escapeShellArgs (globalOpts ++ [ "run" ]);
renewOpts = escapeShellArgs (globalOpts ++ [ "renew" "--days" (toString cfg.validMinDays) ]);
certOpts = optionals data.ocspMustStaple [ "--must-staple" ];
runOpts = escapeShellArgs (globalOpts ++ [ "run" ] ++ certOpts);
renewOpts = escapeShellArgs (globalOpts ++
[ "renew" "--days" (toString cfg.validMinDays) ] ++
certOpts ++ data.extraLegoRenewFlags);
acmeService = {
description = "Renew ACME Certificate for ${cert}";
after = [ "network.target" "network-online.target" ];
@ -307,7 +331,7 @@ in
Group = data.group;
PrivateTmp = true;
StateDirectory = "acme/.lego ${lpath}";
StateDirectoryMode = rights;
StateDirectoryMode = if data.allowKeysForGroup then "750" else "700";
WorkingDirectory = spath;
# Only try loading the credentialsFile if the dns challenge is enabled
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}.crt fullchain.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
chmod ${rights} *.pem
chown '${data.user}:${data.group}' *.pem
fi
chmod ${fileMode} *.pem
chown '${data.user}:${data.group}' *.pem
${data.postRun}
'';
in
@ -375,7 +400,7 @@ in
# Give key acme permissions
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 = {
Type = "oneshot";
@ -400,7 +425,17 @@ in
systemd.tmpfiles.rules =
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}")
({
description = "Renew ACME Certificate for ${cert}";
@ -409,8 +444,9 @@ in
OnCalendar = cfg.renewInterval;
Unit = "acme-${cert}.service";
Persistent = "yes";
AccuracySec = "5m";
RandomizedDelaySec = "1h";
inherit AccuracySec;
# 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 "$@"
'';
};
services.openssh.extraConfig = ''
AuthorizedKeysCommand /etc/ssh/authorized_keys_command_google_oslogin %u
AuthorizedKeysCommandUser nobody
'';
services.openssh.authorizedKeysCommand = "/etc/ssh/authorized_keys_command_google_oslogin %u";
services.openssh.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 =
"${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
{
@ -76,9 +81,64 @@ in
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 {
type = types.lines;
default = "";
type = with types; nullOr lines;
default = null;
example = ''
key_buffer_size = 6G
table_cache = 1600
@ -252,10 +312,27 @@ in
config = mkIf config.services.mysql.enable {
warnings = optional (cfg.extraOptions != null) "services.mysql.`extraOptions` is deprecated, please use services.mysql.`settings`.";
services.mysql.dataDir =
mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/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 = {
description = "MySQL server user";
group = "mysql";
@ -266,25 +343,7 @@ in
environment.systemPackages = [mysql];
environment.etc."my.cnf".text =
''
[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}
'';
environment.etc."my.cnf".source = cfg.configFile;
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${cfg.user} mysql -"
@ -297,7 +356,7 @@ in
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
restartTriggers = [ config.environment.etc."my.cnf".source ];
restartTriggers = [ cfg.configFile ];
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,18 +14,34 @@ let
base_dir = ${baseDir}
protocols = ${concatStringsSep " " cfg.protocols}
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 ''
ssl = no
disable_plaintext_auth = no
'' else ''
ssl_cert = <${cfg.sslServerCert}
ssl_key = <${cfg.sslServerKey}
${optionalString (cfg.sslCACert != null) ("ssl_ca = <" + cfg.sslCACert)}
ssl_dh = <${config.security.dhparams.params.dovecot2.path}
disable_plaintext_auth = yes
'')
(
concatStringsSep "\n" (
mapAttrsToList (
protocol: plugins: ''
protocol ${protocol} {
mail_plugins = $mail_plugins ${concatStringsSep " " plugins.enable}
}
''
) cfg.mailPlugins.perProtocol
)
)
(
if cfg.sslServerCert == null then ''
ssl = no
disable_plaintext_auth = no
'' else ''
ssl_cert = <${cfg.sslServerCert}
ssl_key = <${cfg.sslServerKey}
${optionalString (cfg.sslCACert != null) ("ssl_ca = <" + cfg.sslCACert)}
ssl_dh = <${config.security.dhparams.params.dovecot2.path}
disable_plaintext_auth = yes
''
)
''
default_internal_user = ${cfg.user}
@ -45,55 +61,58 @@ let
}
''
(optionalString cfg.enablePAM ''
userdb {
driver = passwd
}
passdb {
driver = pam
args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2
}
'')
(optionalString (cfg.sieveScripts != {}) ''
plugin {
${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
}
'')
(optionalString (cfg.mailboxes != []) ''
protocol imap {
namespace inbox {
inbox=yes
${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)}
(
optionalString cfg.enablePAM ''
userdb {
driver = passwd
}
}
'')
(optionalString cfg.enableQuota ''
mail_plugins = $mail_plugins quota
service quota-status {
executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix
inet_listener {
port = ${cfg.quotaPort}
passdb {
driver = pam
args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2
}
client_limit = 1
}
''
)
protocol imap {
mail_plugins = $mail_plugins imap_quota
}
(
optionalString (cfg.sieveScripts != {}) ''
plugin {
${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
}
''
)
plugin {
quota_rule = *:storage=${cfg.quotaGlobalPerUser}
quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working
quota_status_success = DUNNO
quota_status_nouser = DUNNO
quota_status_overquota = "552 5.2.2 Mailbox is full"
quota_grace = 10%%
}
'')
(
optionalString (cfg.mailboxes != []) ''
protocol imap {
namespace inbox {
inbox=yes
${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)}
}
}
''
)
(
optionalString cfg.enableQuota ''
service quota-status {
executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix
inet_listener {
port = ${cfg.quotaPort}
}
client_limit = 1
}
plugin {
quota_rule = *:storage=${cfg.quotaGlobalPerUser}
quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working
quota_status_success = DUNNO
quota_status_nouser = DUNNO
quota_status_overquota = "552 5.2.2 Mailbox is full"
quota_grace = 10%%
}
''
)
cfg.extraConfig
];
@ -107,7 +126,7 @@ let
mailbox "${mailbox.name}" {
auto = ${toString mailbox.auto}
'' + optionalString (mailbox.specialUse != null) ''
special_use = \${toString mailbox.specialUse}
special_use = \${toString mailbox.specialUse}
'' + "}";
mailboxes = { ... }: {
@ -160,7 +179,7 @@ in
protocols = mkOption {
type = types.listOf types.str;
default = [ ];
default = [];
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.";
};
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 {
type = types.nullOr types.path;
default = null;
@ -305,27 +361,33 @@ in
enable = true;
params.dovecot2 = {};
};
services.dovecot2.protocols =
optional cfg.enableImap "imap"
++ optional cfg.enablePop3 "pop3"
++ optional cfg.enableLmtp "lmtp";
services.dovecot2.protocols =
optional cfg.enableImap "imap"
++ optional cfg.enablePop3 "pop3"
++ optional cfg.enableLmtp "lmtp";
services.dovecot2.mailPlugins = mkIf cfg.enableQuota {
globally.enable = [ "quota" ];
perProtocol.imap.enable = [ "imap_quota" ];
};
users.users = {
dovenull =
{ uid = config.ids.uids.dovenull2;
{
uid = config.ids.uids.dovenull2;
description = "Dovecot user for untrusted logins";
group = "dovenull";
};
} // optionalAttrs (cfg.user == "dovecot2") {
dovecot2 =
{ uid = config.ids.uids.dovecot2;
description = "Dovecot user";
group = cfg.group;
};
{
uid = config.ids.uids.dovecot2;
description = "Dovecot user";
group = cfg.group;
};
} // optionalAttrs (cfg.createMailUser && cfg.mailUser != null) {
${cfg.mailUser} =
{ description = "Virtual Mail User"; } //
optionalAttrs (cfg.mailGroup != null)
{ description = "Virtual Mail User"; } // optionalAttrs (cfg.mailGroup != null)
{ group = cfg.mailGroup; };
};
@ -334,7 +396,7 @@ in
} // optionalAttrs (cfg.group == "dovecot2") {
dovecot2.gid = config.ids.gids.dovecot2;
} // optionalAttrs (cfg.createMailUser && cfg.mailGroup != null) {
${cfg.mailGroup} = { };
${cfg.mailGroup} = {};
};
environment.etc."dovecot/modules".source = modulesDir;
@ -363,15 +425,19 @@ in
rm -rf ${stateDir}/sieve
'' + optionalString (cfg.sieveScripts != {}) ''
mkdir -p ${stateDir}/sieve
${concatStringsSep "\n" (mapAttrsToList (to: from: ''
if [ -d '${from}' ]; then
mkdir '${stateDir}/sieve/${to}'
cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}'
else
cp -p '${from}' '${stateDir}/sieve/${to}'
fi
${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
'') cfg.sieveScripts)}
${concatStringsSep "\n" (
mapAttrsToList (
to: from: ''
if [ -d '${from}' ]; then
mkdir '${stateDir}/sieve/${to}'
cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}'
else
cp -p '${from}' '${stateDir}/sieve/${to}'
fi
${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
''
) cfg.sieveScripts
)}
chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve'
'';
};
@ -379,17 +445,21 @@ in
environment.systemPackages = [ dovecotPkg ];
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";
}
{ assertion = (cfg.sslServerCert == null) == (cfg.sslServerKey == null)
&& (cfg.sslCACert != null -> !(cfg.sslServerCert == null || cfg.sslServerKey == null));
{
assertion = (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";
}
{ assertion = cfg.showPAMFailure -> cfg.enablePAM;
{
assertion = cfg.showPAMFailure -> cfg.enablePAM;
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";
}
];

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";
services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService;
users.groups = singleton
{ name = "disnix";
gid = config.ids.gids.disnix;
};
users.groups.disnix.gid = config.ids.gids.disnix;
systemd.services = {
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 {
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 ''
{
homeassistant = {

View File

@ -111,6 +111,9 @@ app_service_config_files: ${builtins.toJSON cfg.app_service_config_files}
${cfg.extraConfig}
'';
hasLocalPostgresDB = let args = cfg.database_args; in
usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
in {
options = {
services.matrix-synapse = {
@ -354,13 +357,6 @@ in {
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 {
type = types.str;
default = "matrix-synapse";
@ -657,6 +653,25 @@ in {
};
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 = {
group = "matrix-synapse";
home = cfg.dataDir;
@ -669,18 +684,9 @@ in {
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 = {
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" ];
preStart = ''
${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
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 {
networking = {
hostName = "myhostname";
domain = "example.org";
<link linkend="opt-networking.hostName">hostName</link> = "myhostname";
<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 = {
enable = true;
<link linkend="opt-services.nginx.enable">enable</link> = true;
# only recommendedProxySettings and recommendedGzipSettings are strictly required,
# but the rest make sense as well
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedProxySettings = true;
<link linkend="opt-services.nginx.recommendedTlsSettings">recommendedTlsSettings</link> = true;
<link linkend="opt-services.nginx.recommendedOptimisation">recommendedOptimisation</link> = true;
<link linkend="opt-services.nginx.recommendedGzipSettings">recommendedGzipSettings</link> = 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,
# i.e. to delegate from the host being accessible as ${config.networking.domain}
# to another host actually running the Matrix homeserver.
"${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
# use 443 instead of the default 8448 port to unite
# the client-server and server-server port for simplicity
@ -68,7 +77,7 @@ in {
add_header Content-Type application/json;
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
client = {
"m.homeserver" = { "base_url" = "https://${fqdn}"; };
@ -84,34 +93,37 @@ in {
# Reverse proxy for Matrix client-server and server-server communication
${fqdn} = {
enableACME = true;
forceSSL = true;
<link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = 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.
# 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;
'';
# forward all Matrix API calls to the synapse Matrix homeserver
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 = {
enable = true;
server_name = config.networking.domain;
listeners = [
<link linkend="opt-services.matrix-synapse.enable">enable</link> = true;
<link linkend="opt-services.matrix-synapse.server_name">server_name</link> = config.networking.domain;
<link linkend="opt-services.matrix-synapse.listeners">listeners</link> = [
{
port = 8008;
bind_address = "::1";
type = "http";
tls = false;
x_forwarded = true;
resources = [
{ names = [ "client" "federation" ]; compress = false; }
<link linkend="opt-services.matrix-synapse.listeners._.port">port</link> = 8008;
<link linkend="opt-services.matrix-synapse.listeners._.bind_address">bind_address</link> = "::1";
<link linkend="opt-services.matrix-synapse.listeners._.type">type</link> = "http";
<link linkend="opt-services.matrix-synapse.listeners._.tls">tls</link> = false;
<link linkend="opt-services.matrix-synapse.listeners._.x_forwarded">x_forwarded</link> = true;
<link linkend="opt-services.matrix-synapse.listeners._.resources">resources</link> = [
{
<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>
If you want to run a server with public registration by anybody, you can
then enable <option>services.matrix-synapse.enable_registration =
true;</option>. Otherwise, or you can generate a registration secret with
then enable <literal><link linkend="opt-services.matrix-synapse.enable_registration">services.matrix-synapse.enable_registration</link> =
true;</literal>. Otherwise, or you can generate a registration secret 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
and have rebuilt NixOS:
<screen>
@ -154,8 +166,8 @@ Success!
<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
on your machine, so it makes sense to only temporarily activate the
<option>registration_shared_secret</option> option until a better solution
for NixOS is in place.
<link linkend="opt-services.matrix-synapse.registration_shared_secret">registration_shared_secret</link>
option until a better solution for NixOS is in place.
</para>
</section>
<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
featureset.
<programlisting>
services.nginx.virtualHosts."riot.${fqdn}" = {
enableACME = true;
forceSSL = true;
serverAliases = [
"riot.${config.networking.domain}"
];
{
services.nginx.virtualHosts."riot.${fqdn}" = {
<link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;
<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}"
];
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>
</para>

View File

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

View File

@ -77,6 +77,8 @@ in {
`config.services.zoneminder.database.createLocally` to true. Otherwise,
when set to `false` (the default), you will have to create the database
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 {
@ -330,6 +332,8 @@ in {
${config.services.mysql.package}/bin/mysql < ${pkg}/share/zoneminder/db/zm_create.sql
touch "/var/lib/${dirName}/db-created"
fi
${zoneminder}/bin/zmupdate.pl -nointeractive
'';
serviceConfig = {
User = user;

View File

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

View File

@ -9,12 +9,13 @@ let
# a wrapper that verifies that the configuration is valid
promtoolCheck = what: name: file:
pkgs.runCommand
"${name}-${replaceStrings [" "] [""] what}-checked"
{ buildInputs = [ cfg.package ]; } ''
ln -s ${file} $out
promtool ${what} $out
'';
if cfg.checkConfig then
pkgs.runCommand
"${name}-${replaceStrings [" "] [""] what}-checked"
{ buildInputs = [ cfg.package ]; } ''
ln -s ${file} $out
promtool ${what} $out
'' else file;
# Pretty-print JSON to a file
writePrettyJSON = name: x:
@ -601,6 +602,20 @@ in {
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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,7 +30,17 @@ in
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 = {
serviceConfig = {
@ -40,6 +50,7 @@ in
--nginx.ssl-verify ${toString cfg.sslVerify} \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
--prometheus.const-labels ${concatStringsSep "," cfg.constLabels} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};

View File

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

View File

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

View File

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

View File

@ -74,10 +74,10 @@ in
${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
--varnishstat-path ${cfg.varnishStatPath} \
--varnishstat-path ${escapeShellArg cfg.varnishStatPath} \
${concatStringsSep " \\\n " (cfg.extraFlags
++ 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.withGoMetrics "--with-go-metrics"
++ optional cfg.verbose "--verbose"

View File

@ -59,7 +59,7 @@ in {
${optionalString cfg.verbose "-v"} \
${optionalString cfg.singleSubnetPerField "-s"} \
${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
cjdnsExtraHosts = import (pkgs.runCommand "cjdns-hosts" {}
# Generate a builder that produces an output usable as a Nix string value
''
exec >$out
echo \'\'
${concatStringsSep "\n" (mapAttrsToList (k: v:
optionalString (v.hostname != "")
"echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}")
(cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
echo \'\'
'');
cjdnsExtraHosts = pkgs.runCommandNoCC "cjdns-hosts" {} ''
exec >$out
${concatStringsSep "\n" (mapAttrsToList (k: v:
optionalString (v.hostname != "")
"echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}")
(cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
'';
parseModules = x:
x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; };
@ -144,13 +140,15 @@ in
connectTo = mkOption {
type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
default = { };
example = {
"192.168.1.1:27313" = {
hostname = "homer.hype";
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
};
};
example = literalExample ''
{
"192.168.1.1:27313" = {
hostname = "homer.hype";
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
};
}
'';
description = ''
Credentials for making UDP tunnels.
'';
@ -189,13 +187,15 @@ in
connectTo = mkOption {
type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
default = { };
example = {
"01:02:03:04:05:06" = {
hostname = "homer.hype";
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
};
};
example = literalExample ''
{
"01:02:03:04:05:06" = {
hostname = "homer.hype";
password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
};
}
'';
description = ''
Credentials for connecting look similar to UDP credientials
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 = [
{ assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null );

View File

@ -546,9 +546,13 @@ in
options nf_conntrack nf_conntrack_helper=1
'';
assertions = [ { assertion = (cfg.checkReversePath != false) || kernelHasRPFilter;
message = "This kernel does not support rpfilter"; }
];
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"; }
];
systemd.services.firewall = {
description = "Firewall";

View File

@ -10,14 +10,15 @@ let
{
description = "FreeRadius server";
wantedBy = ["multi-user.target"];
after = ["network-online.target"];
wants = ["network-online.target"];
after = ["network.target"];
wants = ["network.target"];
preStart = ''
${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout
'';
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 = [
"${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout"
"${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
@ -66,6 +77,7 @@ in
};
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 {
type = types.nullOr types.lines;
default = null;
@ -49,7 +61,8 @@ with lib;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
DynamicUser = true;
User = cfg.user;
Group = cfg.group;
Type = "notify";
# when running the config test, don't be quiet so we can see what goes wrong
ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}";
@ -60,5 +73,16 @@ with lib;
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";
/* is this path made unreadable by ProtectHome = true ? */
isProtected = x: hasPrefix "/root" x || hasPrefix "/home" x;
in
{
imports = [
@ -35,45 +37,48 @@ in
corresponding attribute name.
'';
example = literalExample ''
{
foo = {
server = "tunnel.mdomain.com";
relay = "8.8.8.8";
extraConfig = "-v";
{
foo = {
server = "tunnel.mdomain.com";
relay = "8.8.8.8";
extraConfig = "-v";
}
}
}
'';
type = types.attrsOf (types.submodule (
{
options = {
server = mkOption {
type = types.str;
default = "";
description = "Domain or Subdomain of server running iodined";
example = "tunnel.mydomain.com";
};
type = types.attrsOf (
types.submodule (
{
options = {
server = mkOption {
type = types.str;
default = "";
description = "Hostname of server running iodined";
example = "tunnel.mydomain.com";
};
relay = mkOption {
type = types.str;
default = "";
description = "DNS server to use as a intermediate relay to the iodined server";
example = "8.8.8.8";
};
relay = mkOption {
type = types.str;
default = "";
description = "DNS server to use as an intermediate relay to the iodined server";
example = "8.8.8.8";
};
extraConfig = mkOption {
type = types.str;
default = "";
description = "Additional command line parameters";
example = "-l 192.168.1.10 -p 23";
};
extraConfig = mkOption {
type = types.str;
default = "";
description = "Additional command line parameters";
example = "-l 192.168.1.10 -p 23";
};
passwordFile = mkOption {
type = types.str;
default = "";
description = "File that contains password";
};
};
}));
passwordFile = mkOption {
type = types.str;
default = "";
description = "Path to a file containing the password.";
};
};
}
)
);
};
server = {
@ -121,31 +126,67 @@ in
boot.kernelModules = [ "tun" ];
systemd.services =
let
createIodineClientService = name: cfg:
{
description = "iodine client - ${name}";
after = [ "network.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}";
serviceConfig = {
RestartSec = "30s";
Restart = "always";
let
createIodineClientService = name: cfg:
{
description = "iodine client - ${name}";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${builtins.toString cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}";
serviceConfig = {
RestartSec = "30s";
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
listToAttrs (
mapAttrsToList
(name: value: nameValuePair "iodine-${name}" (createIodineClientService name value))
cfg.clients
) // {
iodined = mkIf (cfg.server.enable) {
description = "iodine, ip over dns server daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
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;
};
};
};
};
in
listToAttrs (
mapAttrsToList
(name: value: nameValuePair "iodine-${name}" (createIodineClientService name value))
cfg.clients
) // {
iodined = mkIf (cfg.server.enable) {
description = "iodine, ip over dns server daemon";
after = [ "network.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}";
};
};
users.users.${iodinedUser} = {
uid = config.ids.uids.iodined;

View File

@ -65,7 +65,7 @@ let
let
m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination;
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 ''
# Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself
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
${toString (map (server: "server " + server + " iburst\n") cfg.servers)}
${cfg.extraConfig}
'';
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 {
type = types.listOf types.str;
description = "Extra flags passed to the ntpd command.";

View File

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

View File

@ -26,13 +26,14 @@ in {
description = "The shorewall package to use.";
};
configs = lib.mkOption {
type = types.attrsOf types.str;
type = types.attrsOf types.lines;
default = {};
description = ''
This option defines the Shorewall configs.
The attribute name defines the name 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 = {
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 ];
};
};

View File

@ -26,13 +26,14 @@ in {
description = "The shorewall package to use.";
};
configs = lib.mkOption {
type = types.attrsOf types.str;
type = types.attrsOf types.lines;
default = {};
description = ''
This option defines the Shorewall configs.
The attribute name defines the name 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 = {
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 ];
};
};

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}
EOL
ssh-keygen -f mock-hostkey -N ""
ssh-keygen -q -f mock-hostkey -N ""
sshd -t -f $out -h mock-hostkey
'';
@ -238,6 +238,26 @@ in
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 {
type = types.listOf types.str;
default = [
@ -485,6 +505,10 @@ in
PrintMotd no # handled by pam_motd
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
${optionalString (cfg.authorizedKeysCommand != "none") ''
AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser}
''}
${flip concatMapStrings cfg.hostKeys (k: ''
HostKey ${k.path}

View File

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

View File

@ -3,32 +3,35 @@
with lib;
let
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
{
options = {
services.supybot = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable Supybot, an IRC bot";
description = "Enable Supybot, an IRC bot (also known as Limnoria).";
};
stateDir = mkOption {
# Setting this to /var/lib/supybot caused useradd to fail
default = "/home/supybot";
type = types.path;
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";
};
configFile = mkOption {
type = types.path;
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.
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 {
environment.systemPackages = [ pkgs.pythonPackages.limnoria ];
environment.systemPackages = [ pkgs.python3Packages.limnoria ];
users.users.supybot = {
uid = config.ids.uids.supybot;
group = "supybot";
description = "Supybot IRC bot user";
home = cfg.stateDir;
createHome = true;
isSystemUser = true;
};
users.groups.supybot = {
@ -59,19 +95,16 @@ in
systemd.services.supybot = {
description = "Supybot, an IRC bot";
documentation = [ "https://limnoria.readthedocs.io/" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.pythonPackages.limnoria ];
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
rm -f supybot.cfg.bak
rm -f '${cfg.stateDir}/supybot.cfg.bak'
'';
serviceConfig = {
ExecStart = "${pkgs.pythonPackages.limnoria}/bin/supybot ${cfg.stateDir}/supybot.cfg";
ExecStart = "${pyEnv}/bin/supybot ${cfg.stateDir}/supybot.cfg";
PIDFile = "/run/supybot.pid";
User = "supybot";
Group = "supybot";
@ -79,8 +112,50 @@ in
Restart = "on-abort";
StartLimitInterval = "5m";
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 ''
guest_enable=YES
guest_username=vsftpd
pam_service_name=vsftpd
''}
pam_service_name=vsftpd
${cfg.extraConfig}
'';

View File

@ -428,7 +428,7 @@ in
++ (attrValues (
mapAttrs (name: value: {
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))
++ map ({ interfaceName, peer, ... }: {
assertion = (peer.presharedKey == null) || (peer.presharedKeyFile == null);

View File

@ -69,13 +69,14 @@ in
environment.systemPackages = [ cfg.package ];
# Prevent systemd from potentially changing the MAC address
environment.etc."systemd/network/50-zerotier.link".text = ''
[Match]
OriginalName=zt*
[Link]
AutoNegotiation=false
MACAddressPolicy=none
'';
systemd.network.links."50-zerotier" = {
matchConfig = {
OriginalName = "zt*";
};
linkConfig = {
AutoNegotiation = false;
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.recommendedTlsSettings) ''
ssl_session_cache shared:SSL:42m;
ssl_session_timeout 23m;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;
# Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
ssl_session_timeout 1d;
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_verify on;
''}
@ -487,8 +494,9 @@ in
sslCiphers = mkOption {
type = types.str;
default = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL";
description = "Ciphers to choose from when negotiating tls handshakes.";
# Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
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 {

View File

@ -32,7 +32,7 @@ let
inherit plugins;
} // removeAttrs c [ "type" "pythonPackages" ]
// optionalAttrs (python != null) {
pythonpath = "${pythonEnv}/${python.sitePackages}";
pyhome = "${pythonEnv}";
env =
# Argh, uwsgi expects list of key-values there instead of a dictionary.
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/enso-os.nix
./lightdm-greeters/pantheon.nix
./lightdm-greeters/tiny.nix
];
options = {

View File

@ -183,7 +183,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
# active after the system has resumed, which probably
# should not be the case. Just ignore it.
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;
recordUnit($startListFile, $unit);
# 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;
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;
} else {
if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {

View File

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

View File

@ -6,7 +6,11 @@ let
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"
''
@ -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 {
default = [];
type = types.listOf types.str;
@ -89,49 +103,45 @@ in
boot.initrd.kernelModules = [ "af_packet" ];
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 (
# Search for interface definitions in command line.
''
ifaces=""
for o in $(cat /proc/cmdline); do
case $o in
ip=*)
ipconfig $o && hasNetwork=1
ipconfig $o && ifaces="$ifaces $(echo $o | cut -d: -f6)"
;;
esac
done
''
# Otherwise, use DHCP.
+ optionalString (config.networking.useDHCP || dhcpinterfaces != []) ''
if [ -z "$hasNetwork" ]; then
+ optionalString doDhcp ''
# Bring up all interfaces.
for iface in ${dhcpIfShellExpr}; do
echo "bringing up network interface $iface..."
ip link set "$iface" up && ifaces="$ifaces $iface"
done
# Bring up all interfaces.
for iface in $(ls /sys/class/net/); do
echo "bringing up network interface $iface..."
ip link set "$iface" up
done
# Acquire DHCP leases.
for iface in ${ if config.networking.useDHCP then
"$(ls /sys/class/net/ | grep -v ^lo$)"
else
lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces
}; do
echo "acquiring IP address via DHCP on $iface..."
udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1
done
fi
# Acquire DHCP leases.
for iface in ${dhcpIfShellExpr}; do
echo "acquiring IP address via DHCP on $iface..."
udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs}
done
''
+ ''
if [ -n "$hasNetwork" ]; then
echo "networking is up!"
${cfg.postCommands}
fi
'');
+ cfg.postCommands);
boot.initrd.postMountCommands = mkIf cfg.flushBeforeStage2 ''
for iface in $ifaces; do
ip address flush "$iface"
ip link down "$iface"
done
'';
};

View File

@ -192,139 +192,144 @@ in
###### implementation
config = mkIf (!config.boot.isContainer) {
config = mkMerge
[ (mkIf config.boot.initrd.enable {
boot.initrd.availableKernelModules =
[ # Note: most of these (especially the SATA/PATA modules)
# shouldn't be included by default since nixos-generate-config
# detects them, but I'm keeping them for now for backwards
# compatibility.
system.build = { inherit kernel; };
# Some SATA/PATA stuff.
"ahci"
"sata_nv"
"sata_via"
"sata_sis"
"sata_uli"
"ata_piix"
"pata_marvell"
system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
# Standard SCSI stuff.
"sd_mod"
"sr_mod"
# 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" ];
# SD cards and internal eMMC drives.
"mmc_block"
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
# Support USB keyboards, in case the boot fails and we only have
# a USB keyboard, or for LUKS passphrase prompt.
"uhci_hcd"
"ehci_hcd"
"ehci_pci"
"ohci_hcd"
"ohci_pci"
"xhci_hcd"
"xhci_pci"
"usbhid"
"hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
"hid_logitech_hidpp" "hid_logitech_dj"
boot.kernelModules = [ "loop" "atkbd" ];
] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [
# Misc. x86 keyboard stuff.
"pcips2" "atkbd" "i8042"
boot.initrd.availableKernelModules =
[ # Note: most of these (especially the SATA/PATA modules)
# shouldn't be included by default since nixos-generate-config
# detects them, but I'm keeping them for now for backwards
# compatibility.
# x86 RTC needed by the stage 2 init script.
"rtc_cmos"
];
# Some SATA/PATA stuff.
"ahci"
"sata_nv"
"sata_via"
"sata_sis"
"sata_uli"
"ata_piix"
"pata_marvell"
boot.initrd.kernelModules =
[ # For LVM.
"dm_mod"
];
})
# Standard SCSI stuff.
"sd_mod"
"sr_mod"
(mkIf (!config.boot.isContainer) {
system.build = { inherit kernel; };
# SD cards and internal eMMC drives.
"mmc_block"
system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
# Support USB keyboards, in case the boot fails and we only have
# a USB keyboard, or for LUKS passphrase prompt.
"uhci_hcd"
"ehci_hcd"
"ehci_pci"
"ohci_hcd"
"ohci_pci"
"xhci_hcd"
"xhci_pci"
"usbhid"
"hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
"hid_logitech_hidpp" "hid_logitech_dj"
# 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" ];
] ++ optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [
# Misc. x86 keyboard stuff.
"pcips2" "atkbd" "i8042"
boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
# x86 RTC needed by the stage 2 init script.
"rtc_cmos"
];
boot.kernelModules = [ "loop" "atkbd" ];
boot.initrd.kernelModules =
[ # For LVM.
"dm_mod"
];
# The Linux kernel >= 2.6.27 provides firmware.
hardware.firmware = [ kernel ];
# The Linux kernel >= 2.6.27 provides firmware.
hardware.firmware = [ kernel ];
# Create /etc/modules-load.d/nixos.conf, which is read by
# systemd-modules-load.service to load required kernel modules.
environment.etc =
{ "modules-load.d/nixos.conf".source = kernelModulesConf;
};
systemd.services.systemd-modules-load =
{ wantedBy = [ "multi-user.target" ];
restartTriggers = [ kernelModulesConf ];
serviceConfig =
{ # Ignore failed module loads. Typically some of the
# modules in boot.kernelModules are "nice to have but
# not required" (e.g. acpi-cpufreq), so we don't want to
# barf on those.
SuccessExitStatus = "0 1";
# Create /etc/modules-load.d/nixos.conf, which is read by
# systemd-modules-load.service to load required kernel modules.
environment.etc =
{ "modules-load.d/nixos.conf".source = kernelModulesConf;
};
};
lib.kernelConfig = {
isYes = option: {
assertion = config: config.isYes option;
message = "CONFIG_${option} is not yes!";
configLine = "CONFIG_${option}=y";
};
systemd.services.systemd-modules-load =
{ wantedBy = [ "multi-user.target" ];
restartTriggers = [ kernelModulesConf ];
serviceConfig =
{ # Ignore failed module loads. Typically some of the
# modules in boot.kernelModules are "nice to have but
# not required" (e.g. acpi-cpufreq), so we don't want to
# barf on those.
SuccessExitStatus = "0 1";
};
};
isNo = option: {
assertion = config: config.isNo option;
message = "CONFIG_${option} is not no!";
configLine = "CONFIG_${option}=n";
};
lib.kernelConfig = {
isYes = option: {
assertion = config: config.isYes option;
message = "CONFIG_${option} is not yes!";
configLine = "CONFIG_${option}=y";
};
isModule = option: {
assertion = config: config.isModule option;
message = "CONFIG_${option} is not built as a module!";
configLine = "CONFIG_${option}=m";
};
isNo = option: {
assertion = config: config.isNo option;
message = "CONFIG_${option} is not no!";
configLine = "CONFIG_${option}=n";
};
### Usually you will just want to use these two
# True if yes or module
isEnabled = option: {
assertion = config: config.isEnabled option;
message = "CONFIG_${option} is not enabled!";
configLine = "CONFIG_${option}=y";
};
isModule = option: {
assertion = config: config.isModule option;
message = "CONFIG_${option} is not built as a module!";
configLine = "CONFIG_${option}=m";
};
# True if no or omitted
isDisabled = option: {
assertion = config: config.isDisabled option;
message = "CONFIG_${option} is not disabled!";
configLine = "CONFIG_${option}=n";
};
};
### Usually you will just want to use these two
# True if yes or module
isEnabled = option: {
assertion = config: config.isEnabled option;
message = "CONFIG_${option} is not enabled!";
configLine = "CONFIG_${option}=y";
};
# The config options that all modules can depend upon
system.requiredKernelConfig = with config.lib.kernelConfig; [
# !!! Should this really be needed?
(isYes "MODULES")
(isYes "BINFMT_ELF")
] ++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
# True if no or omitted
isDisabled = option: {
assertion = config: config.isDisabled option;
message = "CONFIG_${option} is not disabled!";
configLine = "CONFIG_${option}=n";
};
};
# nixpkgs kernels are assumed to have all required features
assertions = if config.boot.kernelPackages.kernel ? features then [] else
let cfg = config.boot.kernelPackages.kernel.config; in map (attrs:
{ assertion = attrs.assertion cfg; inherit (attrs) message; }
) config.system.requiredKernelConfig;
# The config options that all modules can depend upon
system.requiredKernelConfig = with config.lib.kernelConfig;
[
# !!! Should this really be needed?
(isYes "MODULES")
(isYes "BINFMT_ELF")
] ++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
};
# nixpkgs kernels are assumed to have all required features
assertions = if config.boot.kernelPackages.kernel ? features then [] else
let cfg = config.boot.kernelPackages.kernel.config; in map (attrs:
{ assertion = attrs.assertion cfg; inherit (attrs) message; }
) config.system.requiredKernelConfig;
})
];
}

View File

@ -67,7 +67,12 @@ let
(assertOnlyFields [
"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
@ -181,7 +186,12 @@ let
(assertOnlyFields [
"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)
];
@ -235,6 +245,26 @@ let
(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" [
(assertOnlyFields [
"Gateway" "GatewayOnLink" "Destination" "Source" "Metric"
@ -325,6 +355,14 @@ let
};
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 {
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 = {
options = {
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 {
default = [ ];
type = with types; listOf (submodule routeOptions);
@ -928,6 +992,11 @@ let
[Route]
${attrsToSection x.routeConfig}
'')}
${flip concatMapStrings def.routingPolicyRules (x: ''
[RoutingPolicyRule]
${attrsToSection x.routingPolicyRuleConfig}
'')}
${def.extraConfig}
'';
@ -984,44 +1053,49 @@ 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;
}
users.users.systemd-network.group = "systemd-network";
(mkIf config.systemd.network.enable {
systemd.additionalUpstreamSystemUnits = [
"systemd-networkd.service" "systemd-networkd-wait-online.service"
];
users.users.systemd-network.group = "systemd-network";
systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links
// mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
// mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks;
systemd.additionalUpstreamSystemUnits = [
"systemd-networkd.service" "systemd-networkd-wait-online.service"
];
environment.etc = unitFiles;
systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
// mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks;
systemd.services.systemd-networkd = {
wantedBy = [ "multi-user.target" ];
restartTriggers = attrNames unitFiles;
# prevent race condition with interface renaming (#39069)
requires = [ "systemd-udev-settle.service" ];
after = [ "systemd-udev-settle.service" ];
};
systemd.services.systemd-networkd-wait-online = {
wantedBy = [ "network-online.target" ];
};
systemd.services."systemd-network-wait-online@" = {
description = "Wait for Network Interface %I to be Configured";
conflicts = [ "shutdown.target" ];
requisite = [ "systemd-networkd.service" ];
after = [ "systemd-networkd.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I";
systemd.services.systemd-networkd = {
wantedBy = [ "multi-user.target" ];
restartTriggers = attrNames unitFiles;
# prevent race condition with interface renaming (#39069)
requires = [ "systemd-udev-settle.service" ];
after = [ "systemd-udev-settle.service" ];
};
};
services.resolved.enable = mkDefault true;
};
systemd.services.systemd-networkd-wait-online = {
wantedBy = [ "network-online.target" ];
};
systemd.services."systemd-network-wait-online@" = {
description = "Wait for Network Interface %I to be Configured";
conflicts = [ "shutdown.target" ];
requisite = [ "systemd-networkd.service" ];
after = [ "systemd-networkd.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I";
};
};
services.resolved.enable = mkDefault true;
})
];
}

View File

@ -210,6 +210,8 @@ done
# Create device nodes in /dev.
@preDeviceCommands@
echo "running udev..."
mkdir -p /etc/systemd
ln -sfn @linkUnits@ /etc/systemd/network
mkdir -p /etc/udev
ln -sfn @udevRules@ /etc/udev/rules.d
mkdir -p /dev/.mdadm
@ -266,7 +268,7 @@ checkFS() {
return 0
fi
# Device might be already mounted manually
# Device might be already mounted manually
# e.g. NBD-device or the host filesystem of the file which contains encrypted root fs
if mount | grep -q "^$device on "; then
echo "skip checking already mounted $device"
@ -351,7 +353,7 @@ mountFS() {
elif [ "$fsType" = f2fs ]; then
echo "resizing $device..."
fsck.f2fs -fp "$device"
resize.f2fs "$device"
resize.f2fs "$device"
fi
;;
esac

View File

@ -120,6 +120,7 @@ let
# Copy udev.
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
for BIN in ${udev}/lib/udev/*_id; do
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" {
allowedReferences = [ extraUtils ];
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-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-net-setup-link.rules $out/
cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/
${config.boot.initrd.extraUdevRulesCommands}
@ -222,7 +233,7 @@ let
--replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \
--replace ${pkgs.mdadm}/sbin ${extraUtils}/sbin \
--replace ${pkgs.bash}/bin/sh ${extraUtils}/bin/sh \
--replace ${udev}/bin/udevadm ${extraUtils}/bin/udevadm
--replace ${udev} ${extraUtils}
done
# Work around a bug in QEMU, which doesn't implement the "READ
@ -257,7 +268,7 @@ let
${pkgs.buildPackages.busybox}/bin/ash -n $target
'';
inherit udevRules extraUtils modulesClosure;
inherit linkUnits udevRules extraUtils modulesClosure;
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 {
default = [ ];
type = types.listOf types.str;
@ -544,7 +566,7 @@ in
};
config = mkIf (!config.boot.isContainer) {
config = mkIf config.boot.initrd.enable {
assertions = [
{ assertion = any (fs: fs.mountPoint == "/") fileSystems;
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})
"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:
optional (attr ? ${name} && !elem attr.${name} values)

View File

@ -94,7 +94,7 @@ in
default = 0;
type = types.int;
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').
'';
};
@ -103,7 +103,7 @@ in
default = 0;
type = types.int;
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').
'';
};
@ -113,7 +113,7 @@ in
type = types.str;
description = ''
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>.
'';
};
@ -123,7 +123,7 @@ in
type = types.str;
description = ''
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>.
'';
};

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