Merge remote-tracking branch 'channels/nixpkgs-unstable' into tbs

This commit is contained in:
Christian Kögler
2018-04-29 19:02:46 +02:00
1814 changed files with 37928 additions and 21430 deletions
+4
View File
@@ -26,3 +26,7 @@ indent_size = 4
# Match diffs, avoid to trim trailing whitespace # Match diffs, avoid to trim trailing whitespace
[*.{diff,patch}] [*.{diff,patch}]
trim_trailing_whitespace = false trim_trailing_whitespace = false
# https://github.com/NixOS/nixpkgs/pull/39336#discussion_r183387754
[.version]
insert_final_newline = false
+1
View File
@@ -14,6 +14,7 @@
/lib @edolstra @nbp /lib @edolstra @nbp
/lib/systems @nbp @ericson2314 /lib/systems @nbp @ericson2314
/lib/generators.nix @edolstra @nbp @Profpatsch /lib/generators.nix @edolstra @nbp @Profpatsch
/lib/debug.nix @edolstra @nbp @Profpatsch
# Nixpkgs Internals # Nixpkgs Internals
/default.nix @nbp /default.nix @nbp
+1 -1
View File
@@ -1 +1 @@
18.09 18.09
+39 -1
View File
@@ -14,6 +14,8 @@ true:</para>
its <literal>meta.broken</literal> set to its <literal>meta.broken</literal> set to
<literal>true</literal>.</para></listitem> <literal>true</literal>.</para></listitem>
<listitem><para>The package isn't intended to run on the given system, as none of its <literal>meta.platforms</literal> match the given system.</para></listitem>
<listitem><para>The package's <literal>meta.license</literal> is set <listitem><para>The package's <literal>meta.license</literal> is set
to a license which is considered to be unfree.</para></listitem> to a license which is considered to be unfree.</para></listitem>
@@ -88,6 +90,42 @@ distributing the software.</para>
</itemizedlist> </itemizedlist>
</section> </section>
<section xml:id="sec-allow-unsupported-system">
<title>Installing packages on unsupported systems</title>
<para>
There are also two ways to try compiling a package which has been marked as unsuported for the given system.
</para>
<itemizedlist>
<listitem><para>
For allowing the build of a broken package once, you can use an environment variable for a single invocation of the nix tools:
<programlisting>$ export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1</programlisting>
</para></listitem>
<listitem>
<para>
For permanently allowing broken packages to be built, you may add <literal>allowUnsupportedSystem = true;</literal> to your user's configuration file, like this:
<programlisting>
{
allowUnsupportedSystem = true;
}
</programlisting>
</para>
</listitem>
</itemizedlist>
<para>
The difference between an a package being unsupported on some system and being broken is admittedly a bit fuzzy.
If a program <emphasis>ought</emphasis> to work on a certain platform, but doesn't, the platform should be included in <literal>meta.platforms</literal>, but marked as broken with e.g. <literal>meta.broken = !hostPlatform.isWindows</literal>.
Of course, this begs the question of what "ought" means exactly.
That is left to the package maintainer.
</para>
</section>
<section xml:id="sec-allow-unfree"> <section xml:id="sec-allow-unfree">
<title>Installing unfree packages</title> <title>Installing unfree packages</title>
@@ -397,7 +435,7 @@ fi
</para> </para>
</section> </section>
<section xml:id="sec-gnu-info-setup"> <section xml:id="sec-gnu-info-setup">
<title>GNU info setup</title> <title>GNU info setup</title>
+1 -1
View File
@@ -75,7 +75,7 @@
An example of such a tool is LLVM. An example of such a tool is LLVM.
</para> </para>
<para> <para>
Although the existance of a "target platfom" is arguably a historical mistake, it is a common one: examples of tools that suffer from it are GCC, Binutils, GHC and Autoconf. Although the existence of a "target platfom" is arguably a historical mistake, it is a common one: examples of tools that suffer from it are GCC, Binutils, GHC and Autoconf.
Nixpkgs tries to avoid sharing in the mistake where possible. Nixpkgs tries to avoid sharing in the mistake where possible.
Still, because the concept of a target platform is so ingrained, it is best to support it as is. Still, because the concept of a target platform is so ingrained, it is best to support it as is.
</para> </para>
+16
View File
@@ -294,6 +294,22 @@ merge:"diff3"
</section> </section>
<section xml:id="sec-debug">
<title>Debugging Nix Expressions</title>
<para>Nix is a unityped, dynamic language, this means every value can
potentially appear anywhere. Since it is also non-strict, evaluation order
and what ultimately is evaluated might surprise you. Therefore it is important
to be able to debug nix expressions.</para>
<para>In the <literal>lib/debug.nix</literal> file you will find a number of
functions that help (pretty-)printing values while evaluation is runnnig. You
can even specify how deep these values should be printed recursively, and
transform them on the fly. Please consult the docstrings in
<literal>lib/debug.nix</literal> for usage information.</para>
</section>
<section xml:id="sec-fhs-environments"> <section xml:id="sec-fhs-environments">
<title>buildFHSUserEnv</title> <title>buildFHSUserEnv</title>
@@ -666,6 +666,56 @@ prefer one built with GHC 7.8.x in the first place. However, for users who
cannot use GHC 7.10.x at all for some reason, the approach of downgrading to an cannot use GHC 7.10.x at all for some reason, the approach of downgrading to an
older version might be useful. older version might be useful.
### How to override packages in all compiler-specific package sets
In the previous section we learned how to override a package in a single
compiler-specific package set. You may have some overrides defined that you want
to use across multiple package sets. To accomplish this you could use the
technique that we learned in the previous section by repeating the overrides for
all the compiler-specific package sets. For example:
```nix
{
packageOverrides = super: let self = super.pkgs; in
{
haskell = super.haskell // {
packages = super.haskell.packages // {
ghc784 = super.haskell.packages.ghc784.override {
overrides = self: super: {
my-package = ...;
my-other-package = ...;
};
};
ghc822 = super.haskell.packages.ghc784.override {
overrides = self: super: {
my-package = ...;
my-other-package = ...;
};
};
...
};
};
};
}
```
However there's a more convenient way to override all compiler-specific package
sets at once:
```nix
{
packageOverrides = super: let self = super.pkgs; in
{
haskell = super.haskell // {
packageOverrides = self: super: {
my-package = ...;
my-other-package = ...;
};
};
};
}
```
### How to recover from GHC's infamous non-deterministic library ID bug ### How to recover from GHC's infamous non-deterministic library ID bug
GHC and distributed build farms don't get along well: GHC and distributed build farms don't get along well:
+1 -1
View File
@@ -374,7 +374,7 @@ and `CFLAGS`.
description = "A pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms"; description = "A pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms";
homepage = http://hgomersall.github.com/pyFFTW/; homepage = http://hgomersall.github.com/pyFFTW/;
license = with licenses; [ bsd2 bsd3 ]; license = with licenses; [ bsd2 bsd3 ];
maintainer = with maintainers; [ fridh ]; maintainers = with maintainers; [ fridh ];
}; };
}; };
} }
+8 -2
View File
@@ -36,10 +36,16 @@
<para>Here you find how to write a derivation that produces multiple outputs.</para> <para>Here you find how to write a derivation that produces multiple outputs.</para>
<para>In nixpkgs there is a framework supporting multiple-output derivations. It tries to cover most cases by default behavior. You can find the source separated in &lt;<filename>nixpkgs/pkgs/build-support/setup-hooks/multiple-outputs.sh</filename>&gt;; it's relatively well-readable. The whole machinery is triggered by defining the <varname>outputs</varname> attribute to contain the list of desired output names (strings).</para> <para>In nixpkgs there is a framework supporting multiple-output derivations. It tries to cover most cases by default behavior. You can find the source separated in &lt;<filename>nixpkgs/pkgs/build-support/setup-hooks/multiple-outputs.sh</filename>&gt;; it's relatively well-readable. The whole machinery is triggered by defining the <varname>outputs</varname> attribute to contain the list of desired output names (strings).</para>
<programlisting>outputs = [ "bin" "dev" "out" "doc" ];</programlisting> <programlisting>outputs = [ "bin" "dev" "out" "doc" ];</programlisting>
<para>Often such a single line is enough. For each output an equally named environment variable is passed to the builder and contains the path in nix store for that output. By convention, the first output should contain the executable programs provided by the package as that output is used by Nix in string conversions, allowing references to binaries like <literal>${pkgs.perl}/bin/perl</literal> to always work. Typically you also want to have the main <varname>out</varname> output, as it catches any files that didn't get elsewhere.</para> <para>Often such a single line is enough. For each output an equally named environment variable is passed to the builder and contains the path in nix store for that output. Typically you also want to have the main <varname>out</varname> output, as it catches any files that didn't get elsewhere.</para>
<note><para>There is a special handling of the <varname>debug</varname> output, described at <xref linkend="stdenv-separateDebugInfo" />.</para></note> <note><para>There is a special handling of the <varname>debug</varname> output, described at <xref linkend="stdenv-separateDebugInfo" />.</para></note>
<section xml:id="multiple-output-file-binaries-first-convention">
<title><quote>Binaries first</quote></title>
<para>A commonly adopted convention in <literal>nixpkgs</literal> is that executables provided by the package are contained within its first output. This convention allows the dependent packages to reference the executables provided by packages in a uniform manner. For instance, provided with the knowledge that the <literal>perl</literal> package contains a <literal>perl</literal> executable it can be referenced as <literal>${pkgs.perl}/bin/perl</literal> within a Nix derivation that needs to execute a Perl script.</para>
<para>The <literal>glibc</literal> package is a deliberate single exception to the <quote>binaries first</quote> convention. The <literal>glibc</literal> has <literal>libs</literal> as its first output allowing the libraries provided by <literal>glibc</literal> to be referenced directly (e.g. <literal>${stdenv.glibc}/lib/ld-linux-x86-64.so.2</literal>). The executables provided by <literal>glibc</literal> can be accessed via its <literal>bin</literal> attribute (e.g. <literal>${stdenv.glibc.bin}/bin/ldd</literal>).</para>
<para>The reason for why <literal>glibc</literal> deviates from the convention is because referencing a library provided by <literal>glibc</literal> is a very common operation among Nix packages. For instance, third-party executables packaged by Nix are typically patched and relinked with the relevant version of <literal>glibc</literal> libraries from Nix packages (please see the documentation on <link xlink:href="https://nixos.org/patchelf.html">patchelf</link> for more details).</para>
</section>
<section xml:id="multiple-output-file-type-groups"> <section xml:id="multiple-output-file-type-groups">
<title>File type groups</title> <title>File type groups</title>
<para>The support code currently recognizes some particular kinds of outputs and either instructs the build system of the package to put files into their desired outputs or it moves the files during the fixup phase. Each group of file types has an <varname>outputFoo</varname> variable specifying the output name where they should go. If that variable isn't defined by the derivation writer, it is guessed &ndash; a default output name is defined, falling back to other possibilities if the output isn't defined.</para> <para>The support code currently recognizes some particular kinds of outputs and either instructs the build system of the package to put files into their desired outputs or it moves the files during the fixup phase. Each group of file types has an <varname>outputFoo</varname> variable specifying the output name where they should go. If that variable isn't defined by the derivation writer, it is guessed &ndash; a default output name is defined, falling back to other possibilities if the output isn't defined.</para>
+3 -1
View File
@@ -23,7 +23,9 @@
xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc">most xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc">most
recently</link> and the <link recently</link> and the <link
xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc">least xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc">least
recently</link> updated pull-requests.</para> recently</link> updated pull-requests.
We highly encourage looking at <link xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+review%3Anone+status%3Asuccess+-label%3A%222.status%3A+work-in-progress%22+no%3Aproject+no%3Aassignee+no%3Amilestone">
this list of ready to merge, unreviewed pull requests</link>.</para>
<para>When reviewing a pull request, please always be nice and polite. <para>When reviewing a pull request, please always be nice and polite.
Controversial changes can lead to controversial opinions, but it is important Controversial changes can lead to controversial opinions, but it is important
+128 -56
View File
@@ -1,34 +1,67 @@
/* Collection of functions useful for debugging
broken nix expressions.
* `trace`-like functions take two values, print
the first to stderr and return the second.
* `traceVal`-like functions take one argument
which both printed and returned.
* `traceSeq`-like functions fully evaluate their
traced value before printing (not just to weak
head normal form like trace does by default).
* Functions that end in `-Fn` take an additional
function as their first argument, which is applied
to the traced value before it is printed.
*/
{ lib }: { lib }:
let let
inherit (builtins) trace isAttrs isList isInt
inherit (builtins) trace attrNamesToStr isAttrs isList isInt head substring attrNames;
isString isBool head substring attrNames; inherit (lib) id elem isFunction;
inherit (lib) all id mapAttrsFlatten elem isFunction;
in in
rec { rec {
inherit (builtins) addErrorContext; # -- TRACING --
addErrorContextToAttrs = lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v); /* Trace msg, but only if pred is true.
traceIf = p: msg: x: if p then trace msg x else x; Example:
traceIf true "hello" 3
trace: hello
=> 3
*/
traceIf = pred: msg: x: if pred then trace msg x else x;
traceVal = x: trace x x; /* Trace the value and also return it.
traceXMLVal = x: trace (builtins.toXML x) x;
traceXMLValMarked = str: x: trace (str + builtins.toXML x) x;
# strict trace functions (traced structure is fully evaluated and printed) Example:
traceValFn (v: "mystring ${v}") "foo"
trace: mystring foo
=> "foo"
*/
traceValFn = f: x: trace (f x) x;
traceVal = traceValFn id;
/* `builtins.trace`, but the value is `builtins.deepSeq`ed first. */ /* `builtins.trace`, but the value is `builtins.deepSeq`ed first.
Example:
trace { a.b.c = 3; } null
trace: { a = <CODE>; }
=> null
traceSeq { a.b.c = 3; } null
trace: { a = { b = { c = 3; }; }; }
=> null
*/
traceSeq = x: y: trace (builtins.deepSeq x x) y; traceSeq = x: y: trace (builtins.deepSeq x x) y;
/* Like `traceSeq`, but only down to depth n. /* Like `traceSeq`, but only evaluate down to depth n.
* This is very useful because lots of `traceSeq` usages This is very useful because lots of `traceSeq` usages
* lead to an infinite recursion. lead to an infinite recursion.
Example:
traceSeqN 2 { a.b.c = 3; } null
trace: { a = { b = {}; }; }
=> null
*/ */
traceSeqN = depth: x: y: with lib; traceSeqN = depth: x: y: with lib;
let snip = v: if isList v then noQuotes "[]" v let snip = v: if isList v then noQuotes "[]" v
@@ -43,39 +76,16 @@ rec {
in trace (generators.toPretty { allowPrettyValues = true; } in trace (generators.toPretty { allowPrettyValues = true; }
(modify depth snip x)) y; (modify depth snip x)) y;
/* `traceSeq`, but the same value is traced and returned */ /* A combination of `traceVal` and `traceSeq` */
traceValSeq = v: traceVal (builtins.deepSeq v v); traceValSeqFn = f: v: traceVal f (builtins.deepSeq v v);
/* `traceValSeq` but with fixed depth */ traceValSeq = traceValSeqFn id;
traceValSeqN = depth: v: traceSeqN depth v v;
/* A combination of `traceVal` and `traceSeqN`. */
traceValSeqNFn = f: depth: v: traceSeqN depth (f v) v;
traceValSeqN = traceValSeqNFn id;
# this can help debug your code as well - designed to not produce thousands of lines # -- TESTING --
traceShowVal = x: trace (showVal x) x;
traceShowValMarked = str: x: trace (str + showVal x) x;
attrNamesToStr = a: lib.concatStringsSep "; " (map (x: "${x}=") (attrNames a));
showVal = x:
if isAttrs x then
if x ? outPath then "x is a derivation, name ${if x ? name then x.name else "<no name>"}, { ${attrNamesToStr x} }"
else "x is attr set { ${attrNamesToStr x} }"
else if isFunction x then "x is a function"
else if x == [] then "x is an empty list"
else if isList x then "x is a list, first element is: ${showVal (head x)}"
else if x == true then "x is boolean true"
else if x == false then "x is boolean false"
else if x == null then "x is null"
else if isInt x then "x is an integer `${toString x}'"
else if isString x then "x is a string `${substring 0 50 x}...'"
else "x is probably a path `${substring 0 50 (toString x)}...'";
# trace the arguments passed to function and its result
# maybe rewrite these functions in a traceCallXml like style. Then one function is enough
traceCall = n: f: a: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a));
traceCall2 = n: f: a: b: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b));
traceCall3 = n: f: a: b: c: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b) (t "arg 3" c));
# FIXME: rename this?
traceValIfNot = c: x:
if c x then true else trace (showVal x) false;
/* Evaluate a set of tests. A test is an attribute set {expr, /* Evaluate a set of tests. A test is an attribute set {expr,
expected}, denoting an expression and its expected result. The expected}, denoting an expression and its expected result. The
@@ -99,9 +109,68 @@ rec {
# usage: { testX = allTrue [ true ]; } # usage: { testX = allTrue [ true ]; }
testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; testAllTrue = expr: { inherit expr; expected = map (x: true) expr; };
strict = v:
trace "Warning: strict is deprecated and will be removed in the next release" # -- DEPRECATED --
(builtins.seq v v);
traceShowVal = x: trace (showVal x) x;
traceShowValMarked = str: x: trace (str + showVal x) x;
attrNamesToStr = a:
trace ( "Warning: `attrNamesToStr` is deprecated "
+ "and will be removed in the next release. "
+ "Please use more specific concatenation "
+ "for your uses (`lib.concat(Map)StringsSep`)." )
(lib.concatStringsSep "; " (map (x: "${x}=") (attrNames a)));
showVal = with lib;
trace ( "Warning: `showVal` is deprecated "
+ "and will be removed in the next release, "
+ "please use `traceSeqN`" )
(let
modify = v:
let pr = f: { __pretty = f; val = v; };
in if isDerivation v then pr
(drv: "<δ:${drv.name}:${concatStringsSep ","
(attrNames drv)}>")
else if [] == v then pr (const "[]")
else if isList v then pr (l: "[ ${go (head l)}, ]")
else if isAttrs v then pr
(a: "{ ${ concatStringsSep ", " (attrNames a)} }")
else v;
go = x: generators.toPretty
{ allowPrettyValues = true; }
(modify x);
in go);
traceXMLVal = x:
trace ( "Warning: `traceXMLVal` is deprecated "
+ "and will be removed in the next release. "
+ "Please use `traceValFn builtins.toXML`." )
(trace (builtins.toXML x) x);
traceXMLValMarked = str: x:
trace ( "Warning: `traceXMLValMarked` is deprecated "
+ "and will be removed in the next release. "
+ "Please use `traceValFn (x: str + builtins.toXML x)`." )
(trace (str + builtins.toXML x) x);
# trace the arguments passed to function and its result
# maybe rewrite these functions in a traceCallXml like style. Then one function is enough
traceCall = n: f: a: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a));
traceCall2 = n: f: a: b: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b));
traceCall3 = n: f: a: b: c: let t = n2: x: traceShowValMarked "${n} ${n2}:" x; in t "result" (f (t "arg 1" a) (t "arg 2" b) (t "arg 3" c));
traceValIfNot = c: x:
trace ( "Warning: `traceValIfNot` is deprecated "
+ "and will be removed in the next release. "
+ "Please use `if/then/else` and `traceValSeq 1`.")
(if c x then true else traceSeq (showVal x) false);
addErrorContextToAttrs = attrs:
trace ( "Warning: `addErrorContextToAttrs` is deprecated "
+ "and will be removed in the next release. "
+ "Please use `builtins.addErrorContext` directly." )
(lib.mapAttrs (a: v: lib.addErrorContext "while evaluating ${a}" v) attrs);
# example: (traceCallXml "myfun" id 3) will output something like # example: (traceCallXml "myfun" id 3) will output something like
# calling myfun arg 1: 3 result: 3 # calling myfun arg 1: 3 result: 3
@@ -109,17 +178,20 @@ rec {
# note: if result doesn't evaluate you'll get no trace at all (FIXME) # note: if result doesn't evaluate you'll get no trace at all (FIXME)
# args should be printed in any case # args should be printed in any case
traceCallXml = a: traceCallXml = a:
if !isInt a then trace ( "Warning: `traceCallXml` is deprecated "
+ "and will be removed in the next release. "
+ "Please complain if you use the function regularly." )
(if !isInt a then
traceCallXml 1 "calling ${a}\n" traceCallXml 1 "calling ${a}\n"
else else
let nr = a; let nr = a;
in (str: expr: in (str: expr:
if isFunction expr then if isFunction expr then
(arg: (arg:
traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (strict arg)}" (expr arg) traceCallXml (builtins.add 1 nr) "${str}\n arg ${builtins.toString nr} is \n ${builtins.toXML (builtins.seq arg arg)}" (expr arg)
) )
else else
let r = strict expr; let r = builtins.seq expr expr;
in trace "${str}\n result:\n${builtins.toXML r}" r in trace "${str}\n result:\n${builtins.toXML r}" r
); ));
} }
+5 -4
View File
@@ -115,11 +115,12 @@ let
unknownModule mkOption; unknownModule mkOption;
inherit (types) isType setType defaultTypeMerge defaultFunctor inherit (types) isType setType defaultTypeMerge defaultFunctor
isOptionType mkOptionType; isOptionType mkOptionType;
inherit (debug) addErrorContextToAttrs traceIf traceVal inherit (debug) addErrorContextToAttrs traceIf traceVal traceValFn
traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq traceXMLVal traceXMLValMarked traceSeq traceSeqN traceValSeq
traceValSeqN traceShowVal traceShowValMarked traceValSeqFn traceValSeqN traceValSeqNFn traceShowVal
showVal traceCall traceCall2 traceCall3 traceValIfNot runTests traceShowValMarked showVal traceCall traceCall2 traceCall3
testAllTrue strict traceCallXml attrNamesToStr; traceValIfNot runTests testAllTrue traceCallXml
attrNamesToStr;
inherit (misc) maybeEnv defaultMergeArg defaultMerge foldArgs inherit (misc) maybeEnv defaultMergeArg defaultMerge foldArgs
defaultOverridableDelayableArgs composedArgsAndFun defaultOverridableDelayableArgs composedArgsAndFun
maybeAttrNullable maybeAttr ifEnable checkFlag getValue maybeAttrNullable maybeAttr ifEnable checkFlag getValue
+15 -11
View File
@@ -143,18 +143,13 @@ rec {
(This means fn is type Val -> String.) */ (This means fn is type Val -> String.) */
allowPrettyValues ? false allowPrettyValues ? false
}@args: v: with builtins; }@args: v: with builtins;
if isInt v then toString v let isPath = v: typeOf v == "path";
in if isInt v then toString v
else if isString v then ''"${libStr.escape [''"''] v}"'' else if isString v then ''"${libStr.escape [''"''] v}"''
else if true == v then "true" else if true == v then "true"
else if false == v then "false" else if false == v then "false"
else if null == v then "null" else if null == v then "null"
else if isFunction v then else if isPath v then toString v
let fna = lib.functionArgs v;
showFnas = concatStringsSep "," (libAttr.mapAttrsToList
(name: hasDefVal: if hasDefVal then "(${name})" else name)
fna);
in if fna == {} then "<λ>"
else "<λ:{${showFnas}}>"
else if isList v then "[ " else if isList v then "[ "
+ libStr.concatMapStringsSep " " (toPretty args) v + libStr.concatMapStringsSep " " (toPretty args) v
+ " ]" + " ]"
@@ -163,12 +158,21 @@ rec {
if attrNames v == [ "__pretty" "val" ] && allowPrettyValues if attrNames v == [ "__pretty" "val" ] && allowPrettyValues
then v.__pretty v.val then v.__pretty v.val
# TODO: there is probably a better representation? # TODO: there is probably a better representation?
else if v ? type && v.type == "derivation" then "<δ>" else if v ? type && v.type == "derivation" then
"<δ:${v.name}>"
# "<δ:${concatStringsSep "," (builtins.attrNames v)}>"
else "{ " else "{ "
+ libStr.concatStringsSep " " (libAttr.mapAttrsToList + libStr.concatStringsSep " " (libAttr.mapAttrsToList
(name: value: (name: value:
"${toPretty args name} = ${toPretty args value};") v) "${toPretty args name} = ${toPretty args value};") v)
+ " }" + " }"
else abort "generators.toPretty: should never happen (v = ${v})"; else if isFunction v then
let fna = lib.functionArgs v;
showFnas = concatStringsSep "," (libAttr.mapAttrsToList
(name: hasDefVal: if hasDefVal then "(${name})" else name)
fna);
in if fna == {} then "<λ>"
else "<λ:{${showFnas}}>"
else abort "toPretty: should never happen (v = ${v})";
} }
+2 -2
View File
@@ -159,7 +159,7 @@ rec {
context = name: ''while evaluating the module argument `${name}' in "${key}":''; context = name: ''while evaluating the module argument `${name}' in "${key}":'';
extraArgs = builtins.listToAttrs (map (name: { extraArgs = builtins.listToAttrs (map (name: {
inherit name; inherit name;
value = addErrorContext (context name) value = builtins.addErrorContext (context name)
(args.${name} or config._module.args.${name}); (args.${name} or config._module.args.${name});
}) requiredArgs); }) requiredArgs);
@@ -309,7 +309,7 @@ rec {
res.mergedValue; res.mergedValue;
in opt // in opt //
{ value = addErrorContext "while evaluating the option `${showOption loc}':" value; { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
definitions = map (def: def.value) res.defsFinal; definitions = map (def: def.value) res.defsFinal;
files = map (def: def.file) res.defsFinal; files = map (def: def.file) res.defsFinal;
inherit (res) isDefined; inherit (res) isDefined;
+2
View File
@@ -44,6 +44,8 @@ rec {
}; };
# Misc boolean options # Misc boolean options
useAndroidPrebuilt = false; useAndroidPrebuilt = false;
useiOSPrebuilt = false;
isiPhoneSimulator = false;
} // mapAttrs (n: v: v final.parsed) inspect.predicates } // mapAttrs (n: v: v final.parsed) inspect.predicates
// args; // args;
in assert final.useAndroidPrebuilt -> final.isAndroid; in assert final.useAndroidPrebuilt -> final.isAndroid;
+1 -1
View File
@@ -26,7 +26,7 @@ in rec {
none = []; none = [];
arm = filterDoubles predicates.isArm; arm = filterDoubles predicates.isAarch32;
aarch64 = filterDoubles predicates.isAarch64; aarch64 = filterDoubles predicates.isAarch64;
x86 = filterDoubles predicates.isx86; x86 = filterDoubles predicates.isx86;
i686 = filterDoubles predicates.isi686; i686 = filterDoubles predicates.isi686;
+1 -1
View File
@@ -7,7 +7,7 @@ in rec {
all = [ {} ]; # `{}` matches anything all = [ {} ]; # `{}` matches anything
none = []; none = [];
arm = [ patterns.isArm ]; arm = [ patterns.isAarch32 ];
aarch64 = [ patterns.isAarch64 ]; aarch64 = [ patterns.isAarch64 ];
x86 = [ patterns.isx86 ]; x86 = [ patterns.isx86 ];
i686 = [ patterns.isi686 ]; i686 = [ patterns.isi686 ];
+5 -2
View File
@@ -9,8 +9,8 @@ rec {
isx86_64 = { cpu = cpuTypes.x86_64; }; isx86_64 = { cpu = cpuTypes.x86_64; };
isPowerPC = { cpu = cpuTypes.powerpc; }; isPowerPC = { cpu = cpuTypes.powerpc; };
isx86 = { cpu = { family = "x86"; }; }; isx86 = { cpu = { family = "x86"; }; };
isArm = { cpu = { family = "arm"; }; }; isAarch32 = { cpu = { family = "arm"; bits = 32; }; };
isAarch64 = { cpu = { family = "aarch64"; }; }; isAarch64 = { cpu = { family = "arm"; bits = 64; }; };
isMips = { cpu = { family = "mips"; }; }; isMips = { cpu = { family = "mips"; }; };
isRiscV = { cpu = { family = "riscv"; }; }; isRiscV = { cpu = { family = "riscv"; }; };
isWasm = { cpu = { family = "wasm"; }; }; isWasm = { cpu = { family = "wasm"; }; };
@@ -41,6 +41,9 @@ rec {
isEfi = map (family: { cpu.family = family; }) isEfi = map (family: { cpu.family = family; })
[ "x86" "arm" "aarch64" ]; [ "x86" "arm" "aarch64" ];
# Deprecated
isArm = isAarch32;
}; };
matchAnyAttrs = patterns: matchAnyAttrs = patterns:
+5 -5
View File
@@ -34,7 +34,7 @@ rec {
################################################################################ ################################################################################
types.openSignifiantByte = mkOptionType { types.openSignificantByte = mkOptionType {
name = "significant-byte"; name = "significant-byte";
description = "Endianness"; description = "Endianness";
merge = mergeOneOption; merge = mergeOneOption;
@@ -42,7 +42,7 @@ rec {
types.significantByte = enum (attrValues significantBytes); types.significantByte = enum (attrValues significantBytes);
significantBytes = setTypes types.openSignifiantByte { significantBytes = setTypes types.openSignificantByte {
bigEndian = {}; bigEndian = {};
littleEndian = {}; littleEndian = {};
}; };
@@ -72,7 +72,7 @@ rec {
armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; }; armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; };
armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; }; armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; };
armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; }; armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; };
aarch64 = { bits = 64; significantByte = littleEndian; family = "aarch64"; }; aarch64 = { bits = 64; significantByte = littleEndian; family = "arm"; };
i686 = { bits = 32; significantByte = littleEndian; family = "x86"; }; i686 = { bits = 32; significantByte = littleEndian; family = "x86"; };
x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; }; x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; };
mips = { bits = 32; significantByte = bigEndian; family = "mips"; }; mips = { bits = 32; significantByte = bigEndian; family = "mips"; };
@@ -201,7 +201,7 @@ rec {
################################################################################ ################################################################################
types.system = mkOptionType { types.parsedPlatform = mkOptionType {
name = "system"; name = "system";
description = "fully parsed representation of llvm- or nix-style platform tuple"; description = "fully parsed representation of llvm- or nix-style platform tuple";
merge = mergeOneOption; merge = mergeOneOption;
@@ -215,7 +215,7 @@ rec {
isSystem = isType "system"; isSystem = isType "system";
mkSystem = components: mkSystem = components:
assert types.system.check components; assert types.parsedPlatform.check components;
setType "system" components; setType "system" components;
mkSkeletonFromList = l: { mkSkeletonFromList = l: {
+5 -3
View File
@@ -317,7 +317,8 @@ runTests {
expr = mapAttrs (const (generators.toPretty {})) rec { expr = mapAttrs (const (generators.toPretty {})) rec {
int = 42; int = 42;
bool = true; bool = true;
string = "fnord"; string = ''fno"rd'';
path = /. + "/foo"; # toPath returns a string
null_ = null; null_ = null;
function = x: x; function = x: x;
functionArgs = { arg ? 4, foo }: arg; functionArgs = { arg ? 4, foo }: arg;
@@ -328,13 +329,14 @@ runTests {
expected = rec { expected = rec {
int = "42"; int = "42";
bool = "true"; bool = "true";
string = "\"fnord\""; string = ''"fno\"rd"'';
path = "/foo";
null_ = "null"; null_ = "null";
function = "<λ>"; function = "<λ>";
functionArgs = "<λ:{(arg),foo}>"; functionArgs = "<λ:{(arg),foo}>";
list = "[ 3 4 ${function} [ false ] ]"; list = "[ 3 4 ${function} [ false ] ]";
attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }"; attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }";
drv = "<δ>"; drv = "<δ:test>";
}; };
}; };
+68 -8
View File
@@ -28,6 +28,11 @@
github = "AndersonTorres"; github = "AndersonTorres";
name = "Anderson Torres"; name = "Anderson Torres";
}; };
Anton-Latukha = {
email = "anton.latuka+nixpkgs@gmail.com";
github = "Anton-Latukha";
name = "Anton Latukha";
};
Baughn = { Baughn = {
email = "sveina@gmail.com"; email = "sveina@gmail.com";
github = "Baughn"; github = "Baughn";
@@ -305,6 +310,16 @@
github = "akru"; github = "akru";
name = "Alexander Krupenkin "; name = "Alexander Krupenkin ";
}; };
alexchapman = {
name = "Alex Chapman";
email = "alex@farfromthere.net";
github = "AJChapman";
};
alexfmpe = {
email = "alexandre.fmp.esteves@gmail.com";
github = "alexfmpe";
name = "Alexandre Esteves";
};
alexvorobiev = { alexvorobiev = {
email = "alexander.vorobiev@gmail.com"; email = "alexander.vorobiev@gmail.com";
github = "alexvorobiev"; github = "alexvorobiev";
@@ -582,6 +597,11 @@
github = "bergey"; github = "bergey";
name = "Daniel Bergey"; name = "Daniel Bergey";
}; };
bfortz = {
email = "bernard.fortz@gmail.com";
github = "bfortz";
name = "Bernard Fortz";
};
bgamari = { bgamari = {
email = "ben@smart-cactus.org"; email = "ben@smart-cactus.org";
github = "bgamari"; github = "bgamari";
@@ -700,6 +720,11 @@
github = "canndrew"; github = "canndrew";
name = "Andrew Cann"; name = "Andrew Cann";
}; };
carlosdagos = {
email = "m@cdagostino.io";
github = "carlosdagos";
name = "Carlos D'Agostino";
};
carlsverre = { carlsverre = {
email = "accounts@carlsverre.com"; email = "accounts@carlsverre.com";
github = "carlsverre"; github = "carlsverre";
@@ -1216,7 +1241,7 @@
name = "Mabry Cervin"; name = "Mabry Cervin";
}; };
eqyiel = { eqyiel = {
email = "r@rkm.id.au"; email = "ruben@maher.fyi";
github = "eqyiel"; github = "eqyiel";
name = "Ruben Maher"; name = "Ruben Maher";
}; };
@@ -1701,6 +1726,11 @@
github = "jbedo"; github = "jbedo";
name = "Justin Bedő"; name = "Justin Bedő";
}; };
jbgi = {
email = "jb@giraudeau.info";
github = "jbgi";
name = "Jean-Baptiste Giraudeau";
};
jcumming = { jcumming = {
email = "jack@mudshark.org"; email = "jack@mudshark.org";
name = "Jack Cummings"; name = "Jack Cummings";
@@ -1716,7 +1746,7 @@
name = "Jeffrey David Johnson"; name = "Jeffrey David Johnson";
}; };
jensbin = { jensbin = {
email = "jensbin@protonmail.com"; email = "jensbin+git@pm.me";
github = "jensbin"; github = "jensbin";
name = "Jens Binkert"; name = "Jens Binkert";
}; };
@@ -1966,6 +1996,11 @@
github = "kragniz"; github = "kragniz";
name = "Louis Taylor"; name = "Louis Taylor";
}; };
krav = {
email = "kristoffer@microdisko.no";
github = "krav";
name = "Kristoffer Thømt Ravneberg";
};
kristoff3r = { kristoff3r = {
email = "k.soeholm@gmail.com"; email = "k.soeholm@gmail.com";
github = "kristoff3r"; github = "kristoff3r";
@@ -2491,6 +2526,11 @@
github = "fstamour"; github = "fstamour";
name = "Francis St-Amour"; name = "Francis St-Amour";
}; };
mrkkrp = {
email = "markkarpov92@gmail.com";
github = "mrkkrp";
name = "Mark Karpov";
};
mrVanDalo = { mrVanDalo = {
email = "contact@ingolf-wagner.de"; email = "contact@ingolf-wagner.de";
github = "mrVanDalo"; github = "mrVanDalo";
@@ -2645,6 +2685,11 @@
github = "nmattia"; github = "nmattia";
name = "Nicolas Mattia"; name = "Nicolas Mattia";
}; };
nocent = {
email = "nocent@protonmail.ch";
github = "nocent";
name = "nocent";
};
nocoolnametom = { nocoolnametom = {
email = "nocoolnametom@gmail.com"; email = "nocoolnametom@gmail.com";
github = "nocoolnametom"; github = "nocoolnametom";
@@ -3406,6 +3451,11 @@
github = "grwlf"; github = "grwlf";
name = "Sergey Mironov"; name = "Sergey Mironov";
}; };
sna = {
email = "abouzahra.9@wright.edu";
github = "s-na";
name = "S. Nordin Abouzahra";
};
snyh = { snyh = {
email = "snyh@snyh.org"; email = "snyh@snyh.org";
github = "snyh"; github = "snyh";
@@ -3451,6 +3501,11 @@
github = "spwhitt"; github = "spwhitt";
name = "Spencer Whitt"; name = "Spencer Whitt";
}; };
srghma = {
email = "srghma@gmail.com";
github = "srghma";
name = "Sergei Khoma";
};
srhb = { srhb = {
email = "sbrofeldt@gmail.com"; email = "sbrofeldt@gmail.com";
github = "srhb"; github = "srhb";
@@ -3760,6 +3815,11 @@
github = "twey"; github = "twey";
name = "James Twey Kay"; name = "James Twey Kay";
}; };
typetetris = {
email = "ericwolf42@mail.com";
github = "typetetris";
name = "Eric Wolf";
};
unode = { unode = {
email = "alves.rjc@gmail.com"; email = "alves.rjc@gmail.com";
github = "unode"; github = "unode";
@@ -3966,6 +4026,11 @@
github = "womfoo"; github = "womfoo";
name = "Kranium Gikos Mendoza"; name = "Kranium Gikos Mendoza";
}; };
worldofpeace = {
email = "worldofpeace@users.noreply.github.com";
github = "worldofpeace";
name = "Worldofpeace";
};
wscott = { wscott = {
email = "wsc9tt@gmail.com"; email = "wsc9tt@gmail.com";
github = "wscott"; github = "wscott";
@@ -3984,7 +4049,7 @@
xeji = { xeji = {
email = "xeji@cat3.de"; email = "xeji@cat3.de";
github = "xeji"; github = "xeji";
name = "xeji"; name = "Uli Baum";
}; };
xnaveira = { xnaveira = {
email = "xnaveira@gmail.com"; email = "xnaveira@gmail.com";
@@ -4130,9 +4195,4 @@
github = "zzamboni"; github = "zzamboni";
name = "Diego Zamboni"; name = "Diego Zamboni";
}; };
srghma = {
email = "srghma@gmail.com";
github = "srghma";
name = "Sergei Khoma";
};
} }
+19 -14
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i python -p pythonFull pythonPackages.requests pythonPackages.pyquery pythonPackages.click #!nix-shell -i python3 -p 'python3.withPackages(ps: with ps; [ requests pyquery click ])'
# To use, just execute this script with --help to display help. # To use, just execute this script with --help to display help.
@@ -16,7 +16,7 @@ maintainers_json = subprocess.check_output([
'nix-instantiate', '-E', 'import ./maintainers/maintainer-list.nix {}', '--eval', '--json' 'nix-instantiate', '-E', 'import ./maintainers/maintainer-list.nix {}', '--eval', '--json'
]) ])
maintainers = json.loads(maintainers_json) maintainers = json.loads(maintainers_json)
MAINTAINERS = {v: k for k, v in maintainers.iteritems()} MAINTAINERS = {v: k for k, v in maintainers.items()}
def get_response_text(url): def get_response_text(url):
@@ -45,6 +45,17 @@ def get_maintainers(attr_name):
except: except:
return [] return []
def print_build(table_row):
a = pq(table_row)('a')[1]
print("- [ ] [{}]({})".format(a.text, a.get('href')), flush=True)
maintainers = get_maintainers(a.text)
if maintainers:
print(" - maintainers: {}".format(", ".join(map(lambda u: '@' + u, maintainers))))
# TODO: print last three persons that touched this file
# TODO: pinpoint the diff that broke this build, or maybe it's transient or maybe it never worked?
sys.stdout.flush()
@click.command() @click.command()
@click.option( @click.option(
@@ -73,23 +84,17 @@ def cli(jobset):
# TODO: aborted evaluations # TODO: aborted evaluations
# TODO: dependency failed without propagated builds # TODO: dependency failed without propagated builds
print('\nFailures:')
for tr in d('img[alt="Failed"]').parents('tr'): for tr in d('img[alt="Failed"]').parents('tr'):
a = pq(tr)('a')[1] print_build(tr)
print("- [ ] [{}]({})".format(a.text, a.get('href')))
sys.stdout.flush() print('\nDependency failures:')
for tr in d('img[alt="Dependency failed"]').parents('tr'):
maintainers = get_maintainers(a.text) print_build(tr)
if maintainers:
print(" - maintainers: {}".format(", ".join(map(lambda u: '@' + u, maintainers))))
# TODO: print last three persons that touched this file
# TODO: pinpoint the diff that broke this build, or maybe it's transient or maybe it never worked?
sys.stdout.flush()
if __name__ == "__main__": if __name__ == "__main__":
try: try:
cli() cli()
except: except Exception as e:
import pdb;pdb.post_mortem() import pdb;pdb.post_mortem()
+1 -1
View File
@@ -53,7 +53,7 @@ manual</link> for the rest.</para>
</row> </row>
<row> <row>
<entry><literal>{ x = 1; y = 2; }</literal></entry> <entry><literal>{ x = 1; y = 2; }</literal></entry>
<entry>An set with attributes names <literal>x</literal> and <literal>y</literal></entry> <entry>A set with attributes named <literal>x</literal> and <literal>y</literal></entry>
</row> </row>
<row> <row>
<entry><literal>{ foo.bar = 1; }</literal></entry> <entry><literal>{ foo.bar = 1; }</literal></entry>
@@ -0,0 +1,59 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="sec-importing-modules">
<title>Importing Modules</title>
<para>
Sometimes NixOS modules need to be used in configuration but exist
outside of Nixpkgs. These modules can be imported:
</para>
<programlisting>
{ config, lib, pkgs, ... }:
{
imports =
[ # Use a locally-available module definition in
# ./example-module/default.nix
./example-module
];
services.exampleModule.enable = true;
}
</programlisting>
<para>
The environment variable <literal>NIXOS_EXTRA_MODULE_PATH</literal> is
an absolute path to a NixOS module that is included alongside the
Nixpkgs NixOS modules. Like any NixOS module, this module can import
additional modules:
</para>
<programlisting>
# ./module-list/default.nix
[
./example-module1
./example-module2
]
</programlisting>
<programlisting>
# ./extra-module/default.nix
{ imports = import ./module-list.nix; }
</programlisting>
<programlisting>
# NIXOS_EXTRA_MODULE_PATH=/absolute/path/to/extra-module
{ config, lib, pkgs, ... }:
{
# No `imports` needed
services.exampleModule1.enable = true;
}
</programlisting>
</section>
@@ -180,6 +180,7 @@ in {
<xi:include href="option-def.xml" /> <xi:include href="option-def.xml" />
<xi:include href="assertions.xml" /> <xi:include href="assertions.xml" />
<xi:include href="meta-attributes.xml" /> <xi:include href="meta-attributes.xml" />
<xi:include href="importing-modules.xml" />
<xi:include href="replace-modules.xml" /> <xi:include href="replace-modules.xml" />
</chapter> </chapter>
@@ -51,7 +51,7 @@ ISO, copy its contents verbatim to your drive, then either:
<listitem> <listitem>
<para>If you want to load the contents of the ISO to ram after bootin <para>If you want to load the contents of the ISO to ram after bootin
(So you can remove the stick after bootup) you can append the parameter (So you can remove the stick after bootup) you can append the parameter
<literal>copytoram</literal>to the <literal>options</literal> field.</para> <literal>copytoram</literal> to the <literal>options</literal> field.</para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>
+7 -11
View File
@@ -115,23 +115,17 @@ for a UEFI installation is by and large the same as a BIOS installation. The dif
<varlistentry><term>UEFI systems</term> <varlistentry><term>UEFI systems</term>
<listitem><para>For creating boot partitions: <listitem><para>For creating boot partitions:
<command>mkfs.fat</command>. Again its recommended to assign a <command>mkfs.fat</command>. Again its recommended to assign a
label to the boot partition: <option>-L label to the boot partition: <option>-n
<replaceable>label</replaceable></option>. For example: <replaceable>label</replaceable></option>. For example:
<screen> <screen>
# mkfs.fat -F 32 -L boot /dev/sda3</screen> # mkfs.fat -F 32 -n boot /dev/sda3</screen>
</para></listitem></varlistentry></variablelist></listitem> </para></listitem></varlistentry></variablelist></listitem>
<listitem><para>For creating LVM volumes, the LVM commands, e.g., <listitem><para>For creating LVM volumes, the LVM commands, e.g.,
<command>pvcreate</command>, <command>vgcreate</command>, and
<screen> <command>lvcreate</command>.</para></listitem>
# pvcreate /dev/sda1 /dev/sdb1
# vgcreate MyVolGroup /dev/sda1 /dev/sdb1
# lvcreate --size 2G --name bigdisk MyVolGroup
# lvcreate --size 1G --name smalldisk MyVolGroup</screen>
</para></listitem>
<listitem><para>For creating software RAID devices, use <listitem><para>For creating software RAID devices, use
<command>mdadm</command>.</para></listitem> <command>mdadm</command>.</para></listitem>
@@ -155,6 +149,7 @@ for a UEFI installation is by and large the same as a BIOS installation. The dif
<listitem><para>Mount the boot file system on <filename>/mnt/boot</filename>, e.g. <listitem><para>Mount the boot file system on <filename>/mnt/boot</filename>, e.g.
<screen> <screen>
# mkdir -p /mnt/boot
# mount /dev/disk/by-label/boot /mnt/boot # mount /dev/disk/by-label/boot /mnt/boot
</screen> </screen>
@@ -366,8 +361,9 @@ drive (here <filename>/dev/sda</filename>). <xref linkend="ex-config"
# mkfs.ext4 -L nixos /dev/sda1 # mkfs.ext4 -L nixos /dev/sda1
# mkswap -L swap /dev/sda2 # mkswap -L swap /dev/sda2
# swapon /dev/sda2 # swapon /dev/sda2
# mkfs.fat -F 32 -L boot /dev/sda3 # <lineannotation>(for UEFI systems only)</lineannotation> # mkfs.fat -F 32 -n boot /dev/sda3 # <lineannotation>(for UEFI systems only)</lineannotation>
# mount /dev/disk/by-label/nixos /mnt # mount /dev/disk/by-label/nixos /mnt
# mkdir -p /mnt/boot # <lineannotation>(for UEFI systems only)</lineannotation>
# mount /dev/disk/by-label/boot /mnt/boot # <lineannotation>(for UEFI systems only)</lineannotation> # mount /dev/disk/by-label/boot /mnt/boot # <lineannotation>(for UEFI systems only)</lineannotation>
# nixos-generate-config --root /mnt # nixos-generate-config --root /mnt
# nano /mnt/etc/nixos/configuration.nix # nano /mnt/etc/nixos/configuration.nix
+3 -3
View File
@@ -40,7 +40,7 @@ points to the generated virtual network.
test1 = {pkgs, config, ...}: test1 = {pkgs, config, ...}:
{ {
services.openssh.enable = true; services.openssh.enable = true;
nixpkgs.system = "i686-linux"; nixpkgs.localSystem.system = "i686-linux";
deployment.targetHost = "test1.example.net"; deployment.targetHost = "test1.example.net";
# Other NixOS options # Other NixOS options
@@ -51,7 +51,7 @@ points to the generated virtual network.
services.openssh.enable = true; services.openssh.enable = true;
services.httpd.enable = true; services.httpd.enable = true;
environment.systemPackages = [ pkgs.lynx ]; environment.systemPackages = [ pkgs.lynx ];
nixpkgs.system = "x86_64-linux"; nixpkgs.localSystem.system = "x86_64-linux";
deployment.targetHost = "test2.example.net"; deployment.targetHost = "test2.example.net";
# Other NixOS options # Other NixOS options
@@ -66,7 +66,7 @@ In each NixOS configuration, two attributes have a special meaning.
The <varname>deployment.targetHost</varname> specifies the address The <varname>deployment.targetHost</varname> specifies the address
(domain name or IP address) (domain name or IP address)
of the system which is used by <command>ssh</command> to perform of the system which is used by <command>ssh</command> to perform
remote deployment operations. The <varname>nixpkgs.system</varname> remote deployment operations. The <varname>nixpkgs.localSystem.system</varname>
attribute can be used to specify an architecture for the target machine, attribute can be used to specify an architecture for the target machine,
such as <varname>i686-linux</varname> which builds a 32-bit NixOS such as <varname>i686-linux</varname> which builds a 32-bit NixOS
configuration. Omitting this property will build the configuration configuration. Omitting this property will build the configuration
@@ -56,6 +56,11 @@ has the following highlights: </para>
following incompatible changes:</para> following incompatible changes:</para>
<itemizedlist> <itemizedlist>
<listitem>
<para>
<literal>lib.strict</literal> is removed. Use <literal>builtins.seq</literal> instead.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The <literal>clementine</literal> package points now to the free derivation. The <literal>clementine</literal> package points now to the free derivation.
@@ -77,6 +82,46 @@ following incompatible changes:</para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
<literal>lib.attrNamesToStr</literal> has been deprecated. Use
more specific concatenation (<literal>lib.concat(Map)StringsSep</literal>)
instead.
</para>
</listitem>
<listitem>
<para>
<literal>lib.addErrorContextToAttrs</literal> has been deprecated. Use
<literal>builtins.addErrorContext</literal> directly.
</para>
</listitem>
<listitem>
<para>
<literal>lib.showVal</literal> has been deprecated. Use
<literal>lib.traceSeqN</literal> instead.
</para>
</listitem>
<listitem>
<para>
<literal>lib.traceXMLVal</literal> has been deprecated. Use
<literal>lib.traceValFn builtins.toXml</literal> instead.
</para>
</listitem>
<listitem>
<para>
<literal>lib.traceXMLValMarked</literal> has been deprecated. Use
<literal>lib.traceValFn (x: str + builtins.toXML x)</literal> instead.
</para>
</listitem>
<listitem>
<para>
<literal>lib.traceValIfNot</literal> has been deprecated. Use
<literal>if/then/else</literal> and <literal>lib.traceValSeq</literal>
instead.
</para>
</listitem>
<listitem>
<para>
<literal>lib.traceCallXml</literal> has been deprecated. Please complain
if you use the function regularly.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
+2 -2
View File
@@ -26,7 +26,7 @@
, lib ? import ../../lib , lib ? import ../../lib
}: }:
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; let extraArgs_ = extraArgs; pkgs_ = pkgs;
extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH"; extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH";
in if e == "" then [] else [(import (builtins.toPath e))]; in if e == "" then [] else [(import (builtins.toPath e))];
in in
@@ -36,7 +36,7 @@ let
_file = ./eval-config.nix; _file = ./eval-config.nix;
key = _file; key = _file;
config = { config = {
nixpkgs.system = lib.mkDefault system_; nixpkgs.localSystem = lib.mkDefault { inherit system; };
_module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_); _module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
}; };
}; };
+1 -1
View File
@@ -9,7 +9,7 @@
]; ];
qemuSerialDevice = if pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64 then "ttyS0" qemuSerialDevice = if pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64 then "ttyS0"
else if pkgs.stdenv.isArm || pkgs.stdenv.isAarch64 then "ttyAMA0" else if pkgs.stdenv.isAarch32 || pkgs.stdenv.isAarch64 then "ttyAMA0"
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.system}'"; else throw "Unknown QEMU serial device for system '${pkgs.stdenv.system}'";
qemuBinary = qemuPkg: { qemuBinary = qemuPkg: {
+1 -1
View File
@@ -612,7 +612,7 @@ sub waitForX {
my ($self, $regexp) = @_; my ($self, $regexp) = @_;
$self->nest("waiting for the X11 server", sub { $self->nest("waiting for the X11 server", sub {
retry sub { retry sub {
my ($status, $out) = $self->execute("journalctl -b SYSLOG_IDENTIFIER=systemd | grep 'session opened'"); my ($status, $out) = $self->execute("journalctl -b SYSLOG_IDENTIFIER=systemd | grep 'Reached target Current graphical'");
return 0 if $status != 0; return 0 if $status != 0;
($status, $out) = $self->execute("[ -e /tmp/.X11-unix/X0 ]"); ($status, $out) = $self->execute("[ -e /tmp/.X11-unix/X0 ]");
return 1 if $status == 0; return 1 if $status == 0;
+3 -1
View File
@@ -111,6 +111,8 @@ in rec {
ocrProg = tesseract_4.override { enableLanguages = [ "eng" ]; }; ocrProg = tesseract_4.override { enableLanguages = [ "eng" ]; };
imagemagick_tiff = imagemagick_light.override { inherit libtiff; };
# Generate onvenience wrappers for running the test driver # Generate onvenience wrappers for running the test driver
# interactively with the specified network, and for starting the # interactively with the specified network, and for starting the
# VMs from the command line. # VMs from the command line.
@@ -128,7 +130,7 @@ in rec {
wrapProgram $out/bin/nixos-test-driver \ wrapProgram $out/bin/nixos-test-driver \
--add-flags "''${vms[*]}" \ --add-flags "''${vms[*]}" \
${lib.optionalString enableOCR ${lib.optionalString enableOCR
"--prefix PATH : '${ocrProg}/bin:${imagemagick}/bin'"} \ "--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
--run "export testScript=\"\$(cat $out/test-script)\"" \ --run "export testScript=\"\$(cat $out/test-script)\"" \
--set VLANS '${toString vlans}' --set VLANS '${toString vlans}'
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
+2 -2
View File
@@ -26,11 +26,11 @@ with lib;
nano zile nano zile
texinfo # for the stand-alone Info reader texinfo # for the stand-alone Info reader
] ]
++ stdenv.lib.optional (!stdenv.isArm) grub2; ++ stdenv.lib.optional (!stdenv.isAarch32) grub2;
# GNU GRUB, where available. # GNU GRUB, where available.
boot.loader.grub.enable = !pkgs.stdenv.isArm; boot.loader.grub.enable = !pkgs.stdenv.isAarch32;
boot.loader.grub.version = 2; boot.loader.grub.version = 2;
# GNU lsh. # GNU lsh.
+2
View File
@@ -214,6 +214,8 @@ in {
(mkIf cfg.enable { (mkIf cfg.enable {
environment.systemPackages = [ overriddenPackage ]; environment.systemPackages = [ overriddenPackage ];
sound.enable = true;
environment.etc = [ environment.etc = [
{ target = "asound.conf"; { target = "asound.conf";
source = alsaConf; } source = alsaConf; }
+1 -1
View File
@@ -92,7 +92,7 @@ let
group = mkOption { group = mkOption {
type = types.str; type = types.str;
apply = x: assert (builtins.stringLength x < 17 || abort "Group name '${x}' is longer than 16 characters which is not allowed!"); x; apply = x: assert (builtins.stringLength x < 32 || abort "Group name '${x}' is longer than 31 characters which is not allowed!"); x;
default = "nogroup"; default = "nogroup";
description = "The user's primary group."; description = "The user's primary group.";
}; };
+4 -4
View File
@@ -25,16 +25,16 @@ in
type = types.bool; type = types.bool;
description = '' description = ''
Enable in-memory compressed swap space provided by the zram kernel Enable in-memory compressed swap space provided by the zram kernel
module. It is recommended to enable only for kernel 3.14 or higher. module.
See https://www.kernel.org/doc/Documentation/blockdev/zram.txt
''; '';
}; };
numDevices = mkOption { numDevices = mkOption {
default = 4; default = 1;
type = types.int; type = types.int;
description = '' description = ''
Number of zram swap devices to create. It should be equal to the Number of zram swap devices to create.
number of CPU cores your system has.
''; '';
}; };
+78 -76
View File
@@ -14,7 +14,6 @@ let
name = "mesa-drivers+txc-${p.mesa_drivers.version}"; name = "mesa-drivers+txc-${p.mesa_drivers.version}";
paths = paths =
[ p.mesa_drivers [ p.mesa_drivers
p.mesa_drivers.out # mainly for libGL
(if cfg.s3tcSupport then p.libtxc_dxtn else p.libtxc_dxtn_s2tc) (if cfg.s3tcSupport then p.libtxc_dxtn else p.libtxc_dxtn_s2tc)
]; ];
}; };
@@ -33,89 +32,92 @@ in
{ {
options = { options = {
hardware.opengl.enable = mkOption {
description = ''
Whether to enable OpenGL drivers. This is needed to enable
OpenGL support in X11 systems, as well as for Wayland compositors
like sway, way-cooler and Weston. It is enabled by default
by the corresponding modules, so you do not usually have to
set it yourself, only if there is no module for your wayland
compositor of choice. See services.xserver.enable,
programs.sway.enable, and programs.way-cooler.enable.
'';
type = types.bool;
default = false;
};
hardware.opengl.driSupport = mkOption { hardware.opengl = {
type = types.bool; enable = mkOption {
default = true; description = ''
description = '' Whether to enable OpenGL drivers. This is needed to enable
Whether to enable accelerated OpenGL rendering through the OpenGL support in X11 systems, as well as for Wayland compositors
Direct Rendering Interface (DRI). like sway, way-cooler and Weston. It is enabled by default
''; by the corresponding modules, so you do not usually have to
}; set it yourself, only if there is no module for your wayland
compositor of choice. See services.xserver.enable,
programs.sway.enable, and programs.way-cooler.enable.
'';
type = types.bool;
default = false;
};
hardware.opengl.driSupport32Bit = mkOption { driSupport = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
description = '' description = ''
On 64-bit systems, whether to support Direct Rendering for Whether to enable accelerated OpenGL rendering through the
32-bit applications (such as Wine). This is currently only Direct Rendering Interface (DRI).
supported for the <literal>nvidia</literal> and '';
<literal>ati_unfree</literal> drivers, as well as };
<literal>Mesa</literal>.
'';
};
hardware.opengl.s3tcSupport = mkOption { driSupport32Bit = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Make S3TC(S3 Texture Compression) via libtxc_dxtn available On 64-bit systems, whether to support Direct Rendering for
to OpenGL drivers instead of the patent-free S2TC replacement. 32-bit applications (such as Wine). This is currently only
supported for the <literal>nvidia</literal> and
<literal>ati_unfree</literal> drivers, as well as
<literal>Mesa</literal>.
'';
};
Using this library may require a patent license depending on your location. s3tcSupport = mkOption {
''; type = types.bool;
}; default = false;
description = ''
Make S3TC(S3 Texture Compression) via libtxc_dxtn available
to OpenGL drivers instead of the patent-free S2TC replacement.
hardware.opengl.package = mkOption { Using this library may require a patent license depending on your location.
type = types.package; '';
internal = true; };
description = ''
The package that provides the OpenGL implementation.
'';
};
hardware.opengl.package32 = mkOption { package = mkOption {
type = types.package; type = types.package;
internal = true; internal = true;
description = '' description = ''
The package that provides the 32-bit OpenGL implementation on The package that provides the OpenGL implementation.
64-bit systems. Used when <option>driSupport32Bit</option> is '';
set. };
'';
};
hardware.opengl.extraPackages = mkOption { package32 = mkOption {
type = types.listOf types.package; type = types.package;
default = []; internal = true;
example = literalExample "with pkgs; [ vaapiIntel libvdpau-va-gl vaapiVdpau intel-ocl ]"; description = ''
description = '' The package that provides the 32-bit OpenGL implementation on
Additional packages to add to OpenGL drivers. This can be used 64-bit systems. Used when <option>driSupport32Bit</option> is
to add OpenCL drivers, VA-API/VDPAU drivers etc. set.
''; '';
}; };
hardware.opengl.extraPackages32 = mkOption { extraPackages = mkOption {
type = types.listOf types.package; type = types.listOf types.package;
default = []; default = [];
example = literalExample "with pkgs.pkgsi686Linux; [ vaapiIntel libvdpau-va-gl vaapiVdpau ]"; example = literalExample "with pkgs; [ vaapiIntel libvdpau-va-gl vaapiVdpau intel-ocl ]";
description = '' description = ''
Additional packages to add to 32-bit OpenGL drivers on Additional packages to add to OpenGL drivers. This can be used
64-bit systems. Used when <option>driSupport32Bit</option> is to add OpenCL drivers, VA-API/VDPAU drivers etc.
set. This can be used to add OpenCL drivers, VA-API/VDPAU drivers etc. '';
''; };
extraPackages32 = mkOption {
type = types.listOf types.package;
default = [];
example = literalExample "with pkgs.pkgsi686Linux; [ vaapiIntel libvdpau-va-gl vaapiVdpau ]";
description = ''
Additional packages to add to 32-bit OpenGL drivers on
64-bit systems. Used when <option>driSupport32Bit</option> is
set. This can be used to add OpenCL drivers, VA-API/VDPAU drivers etc.
'';
};
}; };
}; };
+2 -9
View File
@@ -25,13 +25,6 @@ let
nvidia_x11 = nvidiaForKernel config.boot.kernelPackages; nvidia_x11 = nvidiaForKernel config.boot.kernelPackages;
nvidia_libs32 = (nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; }; nvidia_libs32 = (nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; };
nvidiaPackage = nvidia: pkgs:
if !nvidia.useGLVND then nvidia.out
else pkgs.buildEnv {
name = "nvidia-libs";
paths = [ pkgs.libglvnd nvidia.out ];
};
enabled = nvidia_x11 != null; enabled = nvidia_x11 != null;
in in
@@ -57,8 +50,8 @@ in
source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc"; source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc";
}; };
hardware.opengl.package = nvidiaPackage nvidia_x11 pkgs; hardware.opengl.package = nvidia_x11.out;
hardware.opengl.package32 = nvidiaPackage nvidia_libs32 pkgs_i686; hardware.opengl.package32 = nvidia_libs32.out;
environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ] environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ]
++ lib.filter (p: p != null) [ nvidia_x11.persistenced ]; ++ lib.filter (p: p != null) [ nvidia_x11.persistenced ];
@@ -21,7 +21,9 @@ let
if [ ! -e $out/nixos/nixpkgs ]; then if [ ! -e $out/nixos/nixpkgs ]; then
ln -s . $out/nixos/nixpkgs ln -s . $out/nixos/nixpkgs
fi fi
echo -n ${config.system.nixos.revision} > $out/nixos/.git-revision
echo -n ${config.system.nixos.versionSuffix} > $out/nixos/.version-suffix echo -n ${config.system.nixos.versionSuffix} > $out/nixos/.version-suffix
echo ${config.system.nixos.versionSuffix} | sed -e s/pre// > $out/nixos/svn-revision
''; '';
in in
+3 -2
View File
@@ -59,7 +59,7 @@ let
INITRD /boot/${config.system.boot.loader.initrdFile} INITRD /boot/${config.system.boot.loader.initrdFile}
# A variant to boot with verbose logging to the console # A variant to boot with verbose logging to the console
LABEL boot-nomodeset LABEL boot-debug
MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug) MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug)
LINUX /boot/${config.system.boot.loader.kernelFile} LINUX /boot/${config.system.boot.loader.kernelFile}
APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7 APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7
@@ -73,7 +73,8 @@ let
APPEND ${toString config.boot.loader.grub.memtest86.params} APPEND ${toString config.boot.loader.grub.memtest86.params}
''; '';
isolinuxCfg = baseIsolinuxCfg + (optionalString config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry); isolinuxCfg = concatStringsSep "\n"
([ baseIsolinuxCfg ] ++ optional config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry);
# The EFI boot image. # The EFI boot image.
efiDir = pkgs.runCommand "efi-directory" {} '' efiDir = pkgs.runCommand "efi-directory" {} ''
@@ -1,6 +1,6 @@
{ {
x86_64-linux = "/nix/store/6p2gambjac7xdkd2a7w1dsxdk1q5cq4d-nix-2.0"; x86_64-linux = "/nix/store/2gk7rk2sx2dkmsjr59gignrfdmya8f6s-nix-2.0.1";
i686-linux = "/nix/store/zznnaijjk3nwx0cmpczxsvngmqzhl7r4-nix-2.0"; i686-linux = "/nix/store/5160glkphiv13qggnivyidg8r0491pbl-nix-2.0.1";
aarch64-linux = "/nix/store/ci96w9kxfkmlc7x2vwqiz4da0r6abxnq-nix-2.0"; aarch64-linux = "/nix/store/jk29zz3ns9vdkkclcyzzkpzp8dhv1x3i-nix-2.0.1";
x86_64-darwin = "/nix/store/xmi4fylvx4qc79ji9v5q3zfy9vfdy4sv-nix-2.0"; x86_64-darwin = "/nix/store/4a9czmrpd4hf3r80zcmga2c2lm3hbbvv-nix-2.0.1";
} }
+2 -1
View File
@@ -51,8 +51,9 @@ if [[ ! -e $mountPoint/etc/NIXOS ]]; then
exit 126 exit 126
fi fi
mkdir -m 0755 -p "$mountPoint/dev" mkdir -m 0755 -p "$mountPoint/dev" "$mountPoint/sys"
mount --rbind /dev "$mountPoint/dev" mount --rbind /dev "$mountPoint/dev"
mount --rbind /sys "$mountPoint/sys"
# Run the activation script. Set $LOCALE_ARCHIVE to supress some Perl locale warnings. # Run the activation script. Set $LOCALE_ARCHIVE to supress some Perl locale warnings.
LOCALE_ARCHIVE=$system/sw/lib/locale/locale-archive chroot "$mountPoint" "$system/activate" >&2 || true LOCALE_ARCHIVE=$system/sw/lib/locale/locale-archive chroot "$mountPoint" "$system/activate" >&2 || true
@@ -577,15 +577,14 @@ $bootLoaderConfig
# Set your time zone. # Set your time zone.
# time.timeZone = "Europe/Amsterdam"; # time.timeZone = "Europe/Amsterdam";
# List packages installed in system profile. To search by name, run: # List packages installed in system profile. To search, run:
# \$ nix-env -qaP | grep wget # \$ nix search wget
# environment.systemPackages = with pkgs; [ # environment.systemPackages = with pkgs; [
# wget vim # wget vim
# ]; # ];
# Some programs need SUID wrappers, can be configured further or are # Some programs need SUID wrappers, can be configured further or are
# started in user sessions. # started in user sessions.
# programs.bash.enableCompletion = true;
# programs.mtr.enable = true; # programs.mtr.enable = true;
# programs.gnupg.agent = { enable = true; enableSSHSupport = true; }; # programs.gnupg.agent = { enable = true; enableSSHSupport = true; };
+31 -12
View File
@@ -16,7 +16,10 @@ let cfg = config.documentation; in
description = '' description = ''
Whether to install documentation of packages from Whether to install documentation of packages from
<option>environment.systemPackages</option> into the generated system path. <option>environment.systemPackages</option> into the generated system path.
See "Multiple-output packages" chapter in the nixpkgs manual for more info.
''; '';
# which is at ../../../doc/multiple-output.xml
}; };
man.enable = mkOption { man.enable = mkOption {
@@ -28,6 +31,15 @@ let cfg = config.documentation; in
''; '';
}; };
info.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install info pages and the <command>info</command> command.
This also includes "info" outputs.
'';
};
doc.enable = mkOption { doc.enable = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
@@ -38,12 +50,19 @@ let cfg = config.documentation; in
''; '';
}; };
info.enable = mkOption { dev.enable = mkOption {
type = types.bool; type = types.bool;
default = true; default = false;
description = '' description = ''
Whether to install info pages and the <command>info</command> command. Whether to install documentation targeted at developers.
This also includes "info" outputs. <itemizedlist>
<listitem><para>This includes man pages targeted at developers if <option>man.enable</option> is
set (this also includes "devman" outputs).</para></listitem>
<listitem><para>This includes info pages targeted at developers if <option>info.enable</option>
is set (this also includes "devinfo" outputs).</para></listitem>
<listitem><para>This includes other pages targeted at developers if <option>doc.enable</option>
is set (this also includes "devdoc" outputs).</para></listitem>
</itemizedlist>
''; '';
}; };
@@ -56,20 +75,20 @@ let cfg = config.documentation; in
(mkIf cfg.man.enable { (mkIf cfg.man.enable {
environment.systemPackages = [ pkgs.man-db ]; environment.systemPackages = [ pkgs.man-db ];
environment.pathsToLink = [ "/share/man" ]; environment.pathsToLink = [ "/share/man" ];
environment.extraOutputsToInstall = [ "man" ]; environment.extraOutputsToInstall = [ "man" ] ++ optional cfg.dev.enable [ "devman" ];
})
(mkIf cfg.info.enable {
environment.systemPackages = [ pkgs.texinfoInteractive ];
environment.pathsToLink = [ "/share/info" ];
environment.extraOutputsToInstall = [ "info" ] ++ optional cfg.dev.enable [ "devinfo" ];
}) })
(mkIf cfg.doc.enable { (mkIf cfg.doc.enable {
# TODO(@oxij): put it here and remove from profiles? # TODO(@oxij): put it here and remove from profiles?
# environment.systemPackages = [ pkgs.w3m ]; # w3m-nox? # environment.systemPackages = [ pkgs.w3m ]; # w3m-nox?
environment.pathsToLink = [ "/share/doc" ]; environment.pathsToLink = [ "/share/doc" ];
environment.extraOutputsToInstall = [ "doc" ]; environment.extraOutputsToInstall = [ "doc" ] ++ optional cfg.dev.enable [ "devdoc" ];
})
(mkIf cfg.info.enable {
environment.systemPackages = [ pkgs.texinfoInteractive ];
environment.pathsToLink = [ "/share/info" ];
environment.extraOutputsToInstall = [ "info" ];
}) })
]); ]);
+2 -2
View File
@@ -56,7 +56,7 @@
#dialout = 27; # unused #dialout = 27; # unused
polkituser = 28; polkituser = 28;
#utmp = 29; # unused #utmp = 29; # unused
ddclient = 30; # ddclient = 30; # converted to DynamicUser = true
davfs2 = 31; davfs2 = 31;
#disnix = 33; # unused #disnix = 33; # unused
osgi = 34; osgi = 34;
@@ -344,7 +344,7 @@
dialout = 27; dialout = 27;
#polkituser = 28; # currently unused, polkitd doesn't need a group #polkituser = 28; # currently unused, polkitd doesn't need a group
utmp = 29; utmp = 29;
ddclient = 30; # ddclient = 30; # converted to DynamicUser = true
davfs2 = 31; davfs2 = 31;
disnix = 33; disnix = 33;
osgi = 34; osgi = 34;
+15 -2
View File
@@ -97,7 +97,7 @@ in {
Whether not to index bind mounts Whether not to index bind mounts
''; '';
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -133,13 +133,26 @@ in {
systemd.services.update-locatedb = systemd.services.update-locatedb =
{ description = "Update Locate Database"; { description = "Update Locate Database";
path = mkIf (!isMLocate) [ pkgs.su ]; path = mkIf (!isMLocate) [ pkgs.su ];
# mlocate's updatedb takes flags via a configuration file or
# on the command line, but not by environment variable.
script = script =
if isMLocate
then let toFlags = x: optional (cfg.${x} != [])
"--${lib.toLower x} '${concatStringsSep " " cfg.${x}}'";
args = concatLists (map toFlags ["pruneFS" "pruneNames" "prunePaths"]);
in ''
exec ${cfg.locate}/bin/updatedb \
--output ${toString cfg.output} ${concatStringsSep " " args} \
--prune-bind-mounts ${if cfg.pruneBindMounts then "yes" else "no"} \
${concatStringsSep " " cfg.extraFlags}
'' ''
else ''
exec ${cfg.locate}/bin/updatedb \ exec ${cfg.locate}/bin/updatedb \
${optionalString (cfg.localuser != null && ! isMLocate) ''--localuser=${cfg.localuser}''} \ ${optionalString (cfg.localuser != null && ! isMLocate) ''--localuser=${cfg.localuser}''} \
--output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags} --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
''; '';
environment = { environment = optionalAttrs (!isMLocate) {
PRUNEFS = concatStringsSep " " cfg.pruneFS; PRUNEFS = concatStringsSep " " cfg.pruneFS;
PRUNEPATHS = concatStringsSep " " cfg.prunePaths; PRUNEPATHS = concatStringsSep " " cfg.prunePaths;
PRUNENAMES = concatStringsSep " " cfg.pruneNames; PRUNENAMES = concatStringsSep " " cfg.pruneNames;
+60 -15
View File
@@ -33,7 +33,11 @@ let
configType = mkOptionType { configType = mkOptionType {
name = "nixpkgs-config"; name = "nixpkgs-config";
description = "nixpkgs config"; description = "nixpkgs config";
check = traceValIfNot isConfig; check = x:
let traceXIfNot = c:
if c x then true
else lib.traceSeqN 1 x false;
in traceXIfNot isConfig;
merge = args: fold (def: mergeConfig def.value) {}; merge = args: fold (def: mergeConfig def.value) {};
}; };
@@ -58,10 +62,13 @@ in
pkgs = mkOption { pkgs = mkOption {
defaultText = literalExample defaultText = literalExample
''import "''${nixos}/.." { ''import "''${nixos}/.." {
inherit (config.nixpkgs) config overlays system; inherit (config.nixpkgs) config overlays localSystem crossSystem;
} }
''; '';
default = import ../../.. { inherit (cfg) config overlays system crossSystem; }; default = import ../../.. {
localSystem = { inherit (cfg) system; } // cfg.localSystem;
inherit (cfg) config overlays crossSystem;
};
type = pkgsType; type = pkgsType;
example = literalExample ''import <nixpkgs> {}''; example = literalExample ''import <nixpkgs> {}'';
description = '' description = ''
@@ -73,8 +80,9 @@ in
relative to the location of this NixOS module, because relative to the location of this NixOS module, because
NixOS and Nixpkgs are distributed together for consistency, NixOS and Nixpkgs are distributed together for consistency,
so the <code>nixos</code> in the default value is in fact a so the <code>nixos</code> in the default value is in fact a
relative path. The <code>config</code>, <code>overlays</code> relative path. The <code>config</code>, <code>overlays</code>,
and <code>system</code> come from this option's siblings. <code>localSystem</code>, and <code>crossSystem</code> come
from this option's siblings.
This option can be used by applications like NixOps to increase This option can be used by applications like NixOps to increase
the performance of evaluation, or to create packages that depend the performance of evaluation, or to create packages that depend
@@ -130,13 +138,40 @@ in
''; '';
}; };
crossSystem = mkOption { localSystem = mkOption {
type = types.nullOr types.attrs; type = types.attrs; # TODO utilize lib.systems.parsedPlatform
default = null; default = { system = builtins.currentSystem; };
example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
defaultText = literalExample
''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
description = '' description = ''
The description of the system we're cross-compiling to, or null Specifies the platform on which NixOS should be built. When
if this isn't a cross-compile. See the description of the <code>nixpkgs.crossSystem</code> is unset, it also specifies
crossSystem argument in the nixpkgs manual. the platform <emphasis>for</emphasis> which NixOS should be
built. If this option is unset, it defaults to the platform
type of the machine where evaluation happens. Specifying this
option is useful when doing distributed multi-platform
deployment, or when building virtual machines. See its
description in the Nixpkgs manual for more details.
Ignored when <code>nixpkgs.pkgs</code> is set.
'';
};
crossSystem = mkOption {
type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform
default = null;
example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
defaultText = literalExample
''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
description = ''
Specifies the platform for which NixOS should be
built. Specify this only if it is different from
<code>nixpkgs.localSystem</code>, the platform
<emphasis>on</emphasis> which NixOS should be built. In other
words, specify this to cross-compile NixOS. Otherwise it
should be set as null, the default. See its description in the
Nixpkgs manual for more details.
Ignored when <code>nixpkgs.pkgs</code> is set. Ignored when <code>nixpkgs.pkgs</code> is set.
''; '';
@@ -146,10 +181,20 @@ in
type = types.str; type = types.str;
example = "i686-linux"; example = "i686-linux";
description = '' description = ''
Specifies the Nix platform type for which NixOS should be built. Specifies the Nix platform type on which NixOS should be built.
If unset, it defaults to the platform type of your host system. It is better to specify <code>nixpkgs.localSystem</code> instead.
Specifying this option is useful when doing distributed <programlisting>
multi-platform deployment, or when building virtual machines. {
nixpkgs.system = ..;
}
</programlisting>
is the same as
<programlisting>
{
nixpkgs.localSystem.system = ..;
}
</programlisting>
See <code>nixpkgs.localSystem</code> for more information.
Ignored when <code>nixpkgs.pkgs</code> is set. Ignored when <code>nixpkgs.pkgs</code> is set.
''; '';
-15
View File
@@ -16,21 +16,6 @@ in
options.system = { options.system = {
# XXX: Reintroduce old options to make nixops before 1.6 able to evaluate configurations
# XXX: Remove after nixops has been bumped to a compatible version
nixosVersion = mkOption {
readOnly = true;
internal = true;
type = types.str;
default = config.system.nixos.version;
};
nixosVersionSuffix = mkOption {
readOnly = true;
internal = true;
type = types.str;
default = config.system.nixos.versionSuffix;
};
nixos.version = mkOption { nixos.version = mkOption {
internal = true; internal = true;
type = types.str; type = types.str;
+7 -2
View File
@@ -166,6 +166,7 @@
./services/backup/crashplan-small-business.nix ./services/backup/crashplan-small-business.nix
./services/backup/mysql-backup.nix ./services/backup/mysql-backup.nix
./services/backup/postgresql-backup.nix ./services/backup/postgresql-backup.nix
./services/backup/restic.nix
./services/backup/rsnapshot.nix ./services/backup/rsnapshot.nix
./services/backup/tarsnap.nix ./services/backup/tarsnap.nix
./services/backup/znapzend.nix ./services/backup/znapzend.nix
@@ -194,6 +195,7 @@
./services/databases/clickhouse.nix ./services/databases/clickhouse.nix
./services/databases/couchdb.nix ./services/databases/couchdb.nix
./services/databases/firebird.nix ./services/databases/firebird.nix
./services/databases/foundationdb.nix
./services/databases/hbase.nix ./services/databases/hbase.nix
./services/databases/influxdb.nix ./services/databases/influxdb.nix
./services/databases/memcached.nix ./services/databases/memcached.nix
@@ -325,7 +327,7 @@
./services/misc/geoip-updater.nix ./services/misc/geoip-updater.nix
./services/misc/gitea.nix ./services/misc/gitea.nix
#./services/misc/gitit.nix #./services/misc/gitit.nix
#./services/misc/gitlab.nix ./services/misc/gitlab.nix
./services/misc/gitolite.nix ./services/misc/gitolite.nix
./services/misc/gitweb.nix ./services/misc/gitweb.nix
./services/misc/gogs.nix ./services/misc/gogs.nix
@@ -480,6 +482,7 @@
./services/networking/gnunet.nix ./services/networking/gnunet.nix
./services/networking/gogoclient.nix ./services/networking/gogoclient.nix
./services/networking/gvpe.nix ./services/networking/gvpe.nix
./services/networking/hans.nix
./services/networking/haproxy.nix ./services/networking/haproxy.nix
./services/networking/heyefi.nix ./services/networking/heyefi.nix
./services/networking/hostapd.nix ./services/networking/hostapd.nix
@@ -533,7 +536,7 @@
./services/networking/prayer.nix ./services/networking/prayer.nix
./services/networking/privoxy.nix ./services/networking/privoxy.nix
./services/networking/prosody.nix ./services/networking/prosody.nix
# ./services/networking/quagga.nix ./services/networking/quagga.nix
./services/networking/quassel.nix ./services/networking/quassel.nix
./services/networking/racoon.nix ./services/networking/racoon.nix
./services/networking/radicale.nix ./services/networking/radicale.nix
@@ -547,6 +550,7 @@
./services/networking/searx.nix ./services/networking/searx.nix
./services/networking/seeks.nix ./services/networking/seeks.nix
./services/networking/skydns.nix ./services/networking/skydns.nix
./services/networking/shadowsocks.nix
./services/networking/shairport-sync.nix ./services/networking/shairport-sync.nix
./services/networking/shout.nix ./services/networking/shout.nix
./services/networking/sniproxy.nix ./services/networking/sniproxy.nix
@@ -558,6 +562,7 @@
./services/networking/ssh/lshd.nix ./services/networking/ssh/lshd.nix
./services/networking/ssh/sshd.nix ./services/networking/ssh/sshd.nix
./services/networking/strongswan.nix ./services/networking/strongswan.nix
./services/networking/strongswan-swanctl/module.nix
./services/networking/stunnel.nix ./services/networking/stunnel.nix
./services/networking/supplicant.nix ./services/networking/supplicant.nix
./services/networking/supybot.nix ./services/networking/supybot.nix
+1 -1
View File
@@ -110,7 +110,7 @@ in
}; };
enableCompletion = mkOption { enableCompletion = mkOption {
default = false; default = true;
description = '' description = ''
Enable Bash completion for all interactive bash shells. Enable Bash completion for all interactive bash shells.
''; '';
+11 -11
View File
@@ -23,6 +23,8 @@ with lib;
(config: (config:
let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config; let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config;
in if enabled then [ pkgs.gutenprint ] else [ ])) in if enabled then [ pkgs.gutenprint ] else [ ]))
(mkRenamedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ])
(mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "")
(mkRenamedOptionModule [ "services" "elasticsearch" "host" ] [ "services" "elasticsearch" "listenAddress" ]) (mkRenamedOptionModule [ "services" "elasticsearch" "host" ] [ "services" "elasticsearch" "listenAddress" ])
(mkRenamedOptionModule [ "services" "graphite" "api" "host" ] [ "services" "graphite" "api" "listenAddress" ]) (mkRenamedOptionModule [ "services" "graphite" "api" "host" ] [ "services" "graphite" "api" "listenAddress" ])
(mkRenamedOptionModule [ "services" "graphite" "web" "host" ] [ "services" "graphite" "web" "listenAddress" ]) (mkRenamedOptionModule [ "services" "graphite" "web" "host" ] [ "services" "graphite" "web" "listenAddress" ])
@@ -187,22 +189,20 @@ with lib;
(mkRenamedOptionModule [ "services" "xserver" "desktopManager" "kde5" ] [ "services" "xserver" "desktopManager" "plasma5" ]) (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "kde5" ] [ "services" "xserver" "desktopManager" "plasma5" ])
# Fontconfig # Fontconfig
(mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "allowBitmaps" ] [ "config" "fonts" "fontconfig" "allowBitmaps" ]) (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowBitmaps" ] [ "fonts" "fontconfig" "allowBitmaps" ])
(mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "allowType1" ] [ "config" "fonts" "fontconfig" "allowType1" ]) (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowType1" ] [ "fonts" "fontconfig" "allowType1" ])
(mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ] [ "config" "fonts" "fontconfig" "useEmbeddedBitmaps" ]) (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ] [ "fonts" "fontconfig" "useEmbeddedBitmaps" ])
(mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "config" "fonts" "fontconfig" "forceAutohint" ]) (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "fonts" "fontconfig" "forceAutohint" ])
(mkRenamedOptionModule [ "config" "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "config" "fonts" "fontconfig" "renderMonoTTFAsBitmap" ]) (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ])
# Profile splitting # Profile splitting
(mkRenamedOptionModule [ "virtualization" "growPartition" ] [ "boot" "growPartition" ]) (mkRenamedOptionModule [ "virtualization" "growPartition" ] [ "boot" "growPartition" ])
# misc/version.nix # misc/version.nix
#(mkRenamedOptionModule [ "config" "system" "nixosVersion" ] [ "config" "system" "nixos" "version" ]) (mkRenamedOptionModule [ "system" "nixosVersion" ] [ "system" "nixos" "version" ])
(mkRenamedOptionModule [ "config" "system" "nixosRelease" ] [ "config" "system" "nixos" "release" ]) (mkRenamedOptionModule [ "system" "nixosVersionSuffix" ] [ "system" "nixos" "versionSuffix" ])
#(mkRenamedOptionModule [ "config" "system" "nixosVersionSuffix" ] [ "config" "system" "nixos" "versionSuffix" ]) (mkRenamedOptionModule [ "system" "nixosRevision" ] [ "system" "nixos" "revision" ])
(mkRenamedOptionModule [ "config" "system" "nixosRevision" ] [ "config" "system" "nixos" "revision" ]) (mkRenamedOptionModule [ "system" "nixosLabel" ] [ "system" "nixos" "label" ])
(mkRenamedOptionModule [ "config" "system" "nixosCodeName" ] [ "config" "system" "nixos" "codeName" ])
(mkRenamedOptionModule [ "config" "system" "nixosLabel" ] [ "config" "system" "nixos" "label" ])
# Users # Users
(mkAliasOptionModule [ "users" "extraUsers" ] [ "users" "users" ]) (mkAliasOptionModule [ "users" "extraUsers" ] [ "users" "users" ])
+80 -33
View File
@@ -58,9 +58,11 @@ let
default = ""; default = "";
example = "systemctl reload nginx.service"; example = "systemctl reload nginx.service";
description = '' description = ''
Commands to run after certificates are re-issued. Typically Commands to run after new certificates go live. Typically
the web server and other servers using certificates need to the web server and other servers using certificates need to
be reloaded. be reloaded.
Executed in the same directory with the new certificate.
''; '';
}; };
@@ -78,6 +80,27 @@ let
''; '';
}; };
activationDelay = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Systemd time span expression to delay copying new certificates to main
state directory. See <citerefentry><refentrytitle>systemd.time</refentrytitle>
<manvolnum>7</manvolnum></citerefentry>.
'';
};
preDelay = mkOption {
type = types.lines;
default = "";
description = ''
Commands to run after certificates are re-issued but before they are
activated. Typically the new certificate is published to DNS.
Executed in the same directory with the new certificate.
'';
};
extraDomains = mkOption { extraDomains = mkOption {
type = types.attrsOf (types.nullOr types.str); type = types.attrsOf (types.nullOr types.str);
default = {}; default = {};
@@ -186,14 +209,15 @@ in
servicesLists = mapAttrsToList certToServices cfg.certs; servicesLists = mapAttrsToList certToServices cfg.certs;
certToServices = cert: data: certToServices = cert: data:
let let
cpath = "${cfg.directory}/${cert}"; domain = if data.domain != null then data.domain else cert;
cpath = lpath + optionalString (data.activationDelay != null) ".staging";
lpath = "${cfg.directory}/${cert}";
rights = if data.allowKeysForGroup then "750" else "700"; rights = if data.allowKeysForGroup then "750" else "700";
cmdline = [ "-v" "-d" data.domain "--default_root" data.webroot "--valid_min" cfg.validMin ] cmdline = [ "-v" "-d" data.domain "--default_root" data.webroot "--valid_min" cfg.validMin ]
++ optionals (data.email != null) [ "--email" data.email ] ++ optionals (data.email != null) [ "--email" data.email ]
++ concatMap (p: [ "-f" p ]) data.plugins ++ concatMap (p: [ "-f" p ]) data.plugins
++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains) ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains)
++ (if cfg.production then [] ++ optionals (!cfg.production) ["--server" "https://acme-staging.api.letsencrypt.org/directory"];
else ["--server" "https://acme-staging.api.letsencrypt.org/directory"]);
acmeService = { acmeService = {
description = "Renew ACME Certificate for ${cert}"; description = "Renew ACME Certificate for ${cert}";
after = [ "network.target" "network-online.target" ]; after = [ "network.target" "network-online.target" ];
@@ -206,7 +230,7 @@ in
Group = data.group; Group = data.group;
PrivateTmp = true; PrivateTmp = true;
}; };
path = [ pkgs.simp_le ]; path = with pkgs; [ simp_le systemd ];
preStart = '' preStart = ''
mkdir -p '${cfg.directory}' mkdir -p '${cfg.directory}'
chown 'root:root' '${cfg.directory}' chown 'root:root' '${cfg.directory}'
@@ -229,17 +253,39 @@ in
exit "$EXITCODE" exit "$EXITCODE"
''; '';
postStop = '' postStop = ''
cd '${cpath}'
if [ -e /tmp/lastExitCode ] && [ "$(cat /tmp/lastExitCode)" = "0" ]; then if [ -e /tmp/lastExitCode ] && [ "$(cat /tmp/lastExitCode)" = "0" ]; then
echo "Executing postRun hook..." ${if data.activationDelay != null then ''
${data.postRun}
${data.preDelay}
if [ -d '${lpath}' ]; then
systemd-run --no-block --on-active='${data.activationDelay}' --unit acme-setlive-${cert}.service
else
systemctl --wait start acme-setlive-${cert}.service
fi
'' else data.postRun}
fi fi
''; '';
before = [ "acme-certificates.target" ]; before = [ "acme-certificates.target" ];
wantedBy = [ "acme-certificates.target" ]; wantedBy = [ "acme-certificates.target" ];
}; };
delayService = {
description = "Set certificate for ${cert} live";
path = with pkgs; [ rsync ];
serviceConfig = {
Type = "oneshot";
};
script = ''
rsync -a --delete-after '${cpath}/' '${lpath}'
'';
postStop = data.postRun;
};
selfsignedService = { selfsignedService = {
description = "Create preliminary self-signed certificate for ${cert}"; description = "Create preliminary self-signed certificate for ${cert}";
path = [ pkgs.openssl ];
preStart = '' preStart = ''
if [ ! -d '${cpath}' ] if [ ! -d '${cpath}' ]
then then
@@ -250,37 +296,41 @@ in
''; '';
script = script =
'' ''
# Create self-signed key workdir="$(mktemp -d)"
workdir="/run/acme-selfsigned-${cert}"
${pkgs.openssl.bin}/bin/openssl genrsa -des3 -passout pass:x -out $workdir/server.pass.key 2048 # Create CA
${pkgs.openssl.bin}/bin/openssl rsa -passin pass:x -in $workdir/server.pass.key -out $workdir/server.key openssl genrsa -des3 -passout pass:x -out $workdir/ca.pass.key 2048
${pkgs.openssl.bin}/bin/openssl req -new -key $workdir/server.key -out $workdir/server.csr \ openssl rsa -passin pass:x -in $workdir/ca.pass.key -out $workdir/ca.key
openssl req -new -key $workdir/ca.key -out $workdir/ca.csr \
-subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=Security Department/CN=example.com"
openssl x509 -req -days 1 -in $workdir/ca.csr -signkey $workdir/ca.key -out $workdir/ca.crt
# Create key
openssl genrsa -des3 -passout pass:x -out $workdir/server.pass.key 2048
openssl rsa -passin pass:x -in $workdir/server.pass.key -out $workdir/server.key
openssl req -new -key $workdir/server.key -out $workdir/server.csr \
-subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com" -subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com"
${pkgs.openssl.bin}/bin/openssl x509 -req -days 1 -in $workdir/server.csr -signkey $workdir/server.key -out $workdir/server.crt openssl x509 -req -days 1 -in $workdir/server.csr -CA $workdir/ca.crt \
-CAkey $workdir/ca.key -CAserial $workdir/ca.srl -CAcreateserial \
-out $workdir/server.crt
# Move key to destination # Copy key to destination
mv $workdir/server.key ${cpath}/key.pem cp $workdir/server.key ${cpath}/key.pem
mv $workdir/server.crt ${cpath}/fullchain.pem
# Create full.pem for e.g. lighttpd (same format as "simp_le ... -f full.pem" creates) # Create fullchain.pem (same format as "simp_le ... -f fullchain.pem" creates)
cat "${cpath}/key.pem" "${cpath}/fullchain.pem" > "${cpath}/full.pem" cat $workdir/{server.crt,ca.crt} > "${cpath}/fullchain.pem"
# Clean up working directory # Create full.pem for e.g. lighttpd
rm $workdir/server.csr cat $workdir/{server.key,server.crt,ca.crt} > "${cpath}/full.pem"
rm $workdir/server.pass.key
# Give key acme permissions # Give key acme permissions
chmod ${rights} '${cpath}/key.pem' chown '${data.user}:${data.group}' "${cpath}/"{key,fullchain,full}.pem
chown '${data.user}:${data.group}' '${cpath}/key.pem' chmod ${rights} "${cpath}/"{key,fullchain,full}.pem
chmod ${rights} '${cpath}/fullchain.pem'
chown '${data.user}:${data.group}' '${cpath}/fullchain.pem'
chmod ${rights} '${cpath}/full.pem'
chown '${data.user}:${data.group}' '${cpath}/full.pem'
''; '';
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RuntimeDirectory = "acme-selfsigned-${cert}";
PermissionsStartOnly = true; PermissionsStartOnly = true;
PrivateTmp = true;
User = data.user; User = data.user;
Group = data.group; Group = data.group;
}; };
@@ -297,11 +347,8 @@ in
}; };
in ( in (
[ { name = "acme-${cert}"; value = acmeService; } ] [ { name = "acme-${cert}"; value = acmeService; } ]
++ ++ optional cfg.preliminarySelfsigned { name = "acme-selfsigned-${cert}"; value = selfsignedService; }
(if cfg.preliminarySelfsigned ++ optional (data.activationDelay != null) { name = "acme-setlive-${cert}"; value = delayService; }
then [ { name = "acme-selfsigned-${cert}"; value = selfsignedService; } ]
else []
)
); );
servicesAttr = listToAttrs services; servicesAttr = listToAttrs services;
injectServiceDep = { injectServiceDep = {
+9 -2
View File
@@ -234,6 +234,11 @@ let
password, KDE will prompt separately after login. password, KDE will prompt separately after login.
''; '';
}; };
sssdStrictAccess = mkOption {
default = false;
type = types.bool;
description = "enforce sssd access control";
};
enableGnomeKeyring = mkOption { enableGnomeKeyring = mkOption {
default = false; default = false;
@@ -264,11 +269,13 @@ let
text = mkDefault text = mkDefault
('' (''
# Account management. # Account management.
account sufficient pam_unix.so account ${if cfg.sssdStrictAccess then "required" else "sufficient"} pam_unix.so
${optionalString use_ldap ${optionalString use_ldap
"account sufficient ${pam_ldap}/lib/security/pam_ldap.so"} "account sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
${optionalString config.services.sssd.enable ${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false)
"account sufficient ${pkgs.sssd}/lib/security/pam_sss.so"} "account sufficient ${pkgs.sssd}/lib/security/pam_sss.so"}
${optionalString (config.services.sssd.enable && cfg.sssdStrictAccess)
"account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so"}
${optionalString config.krb5.enable ${optionalString config.krb5.enable
"account sufficient ${pam_krb5}/lib/security/pam_krb5.so"} "account sufficient ${pam_krb5}/lib/security/pam_krb5.so"}
+1 -1
View File
@@ -10,8 +10,8 @@
#include <errno.h> #include <errno.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <sys/capability.h> #include <sys/capability.h>
#include <linux/prctl.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <limits.h>
#include <cap-ng.h> #include <cap-ng.h>
// Make sure assertions are not compiled out, we use them to codify // Make sure assertions are not compiled out, we use them to codify
+5
View File
@@ -54,6 +54,11 @@ in
description = '' description = ''
Whether to enable volume and capture control with keyboard media keys. Whether to enable volume and capture control with keyboard media keys.
You want to leave this disabled if you run a desktop environment
like KDE, Gnome, Xfce, etc, as those handle such things themselves.
You might want to enable this if you run a minimalistic desktop
environment or work from bare linux ttys/framebuffers.
Enabling this will turn on <option>services.actkbd</option>. Enabling this will turn on <option>services.actkbd</option>.
''; '';
}; };
+150
View File
@@ -0,0 +1,150 @@
{ config, lib, pkgs, ... }:
with lib;
{
options.services.restic.backups = mkOption {
description = ''
Periodic backups to create with Restic.
'';
type = types.attrsOf (types.submodule ({ name, config, ... }: {
options = {
passwordFile = mkOption {
type = types.str;
description = ''
Read the repository password from a file.
'';
example = "/etc/nixos/restic-password";
};
repository = mkOption {
type = types.str;
description = ''
repository to backup to.
'';
example = "sftp:backup@192.168.1.100:/backups/${name}";
};
paths = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Which paths to backup.
'';
example = [
"/var/lib/postgresql"
"/home/user/backup"
];
};
timerConfig = mkOption {
type = types.attrsOf types.str;
default = {
OnCalendar = "daily";
};
description = ''
When to run the backup. See man systemd.timer for details.
'';
example = {
OnCalendar = "00:05";
RandomizedDelaySec = "5h";
};
};
user = mkOption {
type = types.str;
default = "root";
description = ''
As which user the backup should run.
'';
example = "postgresql";
};
extraBackupArgs = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Extra arguments passed to restic backup.
'';
example = [
"--exclude-file=/etc/nixos/restic-ignore"
];
};
extraOptions = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Extra extended options to be passed to the restic --option flag.
'';
example = [
"sftp.command='ssh backup@192.168.1.100 -i /home/user/.ssh/id_rsa -s sftp'"
];
};
initialize = mkOption {
type = types.bool;
default = false;
description = ''
Create the repository if it doesn't exist.
'';
};
};
}));
default = {};
example = {
localbackup = {
paths = [ "/home" ];
repository = "/mnt/backup-hdd";
passwordFile = "/etc/nixos/secrets/restic-password";
initialize = true;
};
remotebackup = {
paths = [ "/home" ];
repository = "sftp:backup@host:/backups/home";
passwordFile = "/etc/nixos/secrets/restic-password";
extraOptions = [
"sftp.command='ssh backup@host -i /etc/nixos/secrets/backup-private-key -s sftp'"
];
timerConfig = {
OnCalendar = "00:05";
RandomizedDelaySec = "5h";
};
};
};
};
config = {
systemd.services =
mapAttrs' (name: backup:
let
extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
connectTo = elemAt (splitString ":" backup.repository) 1;
resticCmd = "${pkgs.restic}/bin/restic${extraOptions}";
in nameValuePair "restic-backups-${name}" ({
environment = {
RESTIC_PASSWORD_FILE = backup.passwordFile;
RESTIC_REPOSITORY = backup.repository;
};
path = with pkgs; [
openssh
];
restartIfChanged = false;
serviceConfig = {
Type = "oneshot";
ExecStart = "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${concatStringsSep " " backup.paths}";
User = backup.user;
};
} // optionalAttrs backup.initialize {
preStart = ''
${resticCmd} snapshots || ${resticCmd} init
'';
})
) config.services.restic.backups;
systemd.timers =
mapAttrs' (name: backup: nameValuePair "restic-backups-${name}" {
wantedBy = [ "timers.target" ];
timerConfig = backup.timerConfig;
}) config.services.restic.backups;
};
}
@@ -6,6 +6,13 @@ let
cfg = config.services.boinc; cfg = config.services.boinc;
allowRemoteGuiRpcFlag = optionalString cfg.allowRemoteGuiRpc "--allow_remote_gui_rpc"; allowRemoteGuiRpcFlag = optionalString cfg.allowRemoteGuiRpc "--allow_remote_gui_rpc";
fhsEnv = pkgs.buildFHSUserEnv {
name = "boinc-fhs-env";
targetPkgs = pkgs': [ cfg.package ] ++ cfg.extraEnvPackages;
runScript = "/bin/boinc_client";
};
fhsEnvExecutable = "${fhsEnv}/bin/${fhsEnv.name}";
in in
{ {
options.services.boinc = { options.services.boinc = {
@@ -49,6 +56,43 @@ in
See also: <link xlink:href="http://boinc.berkeley.edu/wiki/Controlling_BOINC_remotely#Remote_access"/> See also: <link xlink:href="http://boinc.berkeley.edu/wiki/Controlling_BOINC_remotely#Remote_access"/>
''; '';
}; };
extraEnvPackages = mkOption {
type = types.listOf types.package;
default = [];
example = "[ pkgs.virtualbox ]";
description = ''
Additional packages to make available in the environment in which
BOINC will run. Common choices are:
<variablelist>
<varlistentry>
<term><varname>pkgs.virtualbox</varname></term>
<listitem><para>
The VirtualBox virtual machine framework. Required by some BOINC
projects, such as ATLAS@home.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>pkgs.ocl-icd</varname></term>
<listitem><para>
OpenCL infrastructure library. Required by BOINC projects that
use OpenCL, in addition to a device-specific OpenCL driver.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>pkgs.linuxPackages.nvidia_x11</varname></term>
<listitem><para>
Provides CUDA libraries. Required by BOINC projects that use
CUDA. Note that this requires an NVIDIA graphics device to be
present on the system.
</para><para>
Also provides OpenCL drivers for NVIDIA GPUs;
<varname>pkgs.ocl-icd</varname> is also needed in this case.
</para></listitem>
</varlistentry>
</variablelist>
'';
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -70,7 +114,7 @@ in
chown boinc ${cfg.dataDir} chown boinc ${cfg.dataDir}
''; '';
script = '' script = ''
${cfg.package}/bin/boinc_client --dir ${cfg.dataDir} --redirectio ${allowRemoteGuiRpcFlag} ${fhsEnvExecutable} --dir ${cfg.dataDir} --redirectio ${allowRemoteGuiRpcFlag}
''; '';
serviceConfig = { serviceConfig = {
PermissionsStartOnly = true; # preStart must be run as root PermissionsStartOnly = true; # preStart must be run as root
@@ -17,7 +17,7 @@ let
hooksDir = let hooksDir = let
mkHookEntry = name: value: '' mkHookEntry = name: value: ''
cat > $out/${name} <<EOF cat > $out/${name} <<'EOF'
#! ${pkgs.runtimeShell} #! ${pkgs.runtimeShell}
set -e set -e
${value} ${value}
@@ -0,0 +1,360 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.foundationdb;
# used for initial cluster configuration
initialIpAddr = if (cfg.publicAddress != "auto") then cfg.publicAddress else "127.0.0.1";
fdbServers = n:
concatStringsSep "\n" (map (x: "[fdbserver.${toString (x+cfg.listenPortStart)}]") (range 0 (n - 1)));
backupAgents = n:
concatStringsSep "\n" (map (x: "[backup_agent.${toString x}]") (range 1 n));
configFile = pkgs.writeText "foundationdb.conf" ''
[general]
cluster_file = /etc/foundationdb/fdb.cluster
[fdbmonitor]
restart_delay = ${toString cfg.restartDelay}
user = ${cfg.user}
group = ${cfg.group}
[fdbserver]
command = ${pkgs.foundationdb}/bin/fdbserver
public_address = ${cfg.publicAddress}:$ID
listen_address = ${cfg.listenAddress}
datadir = ${cfg.dataDir}/$ID
logdir = ${cfg.logDir}
logsize = ${cfg.logSize}
maxlogssize = ${cfg.maxLogSize}
${optionalString (cfg.class != null) "class = ${cfg.class}"}
memory = ${cfg.memory}
storage_memory = ${cfg.storageMemory}
${optionalString (cfg.locality.machineId != null) "locality_machineid=${cfg.locality.machineId}"}
${optionalString (cfg.locality.zoneId != null) "locality_zoneid=${cfg.locality.zoneId}"}
${optionalString (cfg.locality.datacenterId != null) "locality_dcid=${cfg.locality.datacenterId}"}
${optionalString (cfg.locality.dataHall != null) "locality_data_hall=${cfg.locality.dataHall}"}
${fdbServers cfg.serverProcesses}
[backup_agent]
command = ${pkgs.foundationdb}/libexec/backup_agent
${backupAgents cfg.backupProcesses}
'';
in
{
options.services.foundationdb = {
enable = mkEnableOption "FoundationDB Server";
publicAddress = mkOption {
type = types.str;
default = "auto";
description = "Publicly visible IP address of the process. Port is determined by process ID";
};
listenAddress = mkOption {
type = types.str;
default = "public";
description = "Publicly visible IP address of the process. Port is determined by process ID";
};
listenPortStart = mkOption {
type = types.int;
default = 4500;
description = ''
Starting port number for database listening sockets. Every FDB process binds to a
subsequent port, to this number reflects the start of the overall range. e.g. having
8 server processes will use all ports between 4500 and 4507.
'';
};
openFirewall = mkOption {
type = types.bool;
default = false;
description = ''
Open the firewall ports corresponding to FoundationDB processes and coordinators
using <option>config.networking.firewall.*</option>.
'';
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/foundationdb";
description = "Data directory. All cluster data will be put under here.";
};
logDir = mkOption {
type = types.path;
default = "/var/log/foundationdb";
description = "Log directory.";
};
user = mkOption {
type = types.str;
default = "foundationdb";
description = "User account under which FoundationDB runs.";
};
group = mkOption {
type = types.str;
default = "foundationdb";
description = "Group account under which FoundationDB runs.";
};
class = mkOption {
type = types.nullOr (types.enum [ "storage" "transaction" "stateless" ]);
default = null;
description = "Process class";
};
restartDelay = mkOption {
type = types.int;
default = 10;
description = "Number of seconds to wait before restarting servers.";
};
logSize = mkOption {
type = types.string;
default = "10MiB";
description = ''
Roll over to a new log file after the current log file
reaches the specified size.
'';
};
maxLogSize = mkOption {
type = types.string;
default = "100MiB";
description = ''
Delete the oldest log file when the total size of all log
files exceeds the specified size. If set to 0, old log files
will not be deleted.
'';
};
serverProcesses = mkOption {
type = types.int;
default = 1;
description = "Number of fdbserver processes to run.";
};
backupProcesses = mkOption {
type = types.int;
default = 1;
description = "Number of backup_agent processes to run for snapshots.";
};
memory = mkOption {
type = types.string;
default = "8GiB";
description = ''
Maximum memory used by the process. The default value is
<literal>8GiB</literal>. When specified without a unit,
<literal>MiB</literal> is assumed. This parameter does not
change the memory allocation of the program. Rather, it sets
a hard limit beyond which the process will kill itself and
be restarted. The default value of <literal>8GiB</literal>
is double the intended memory usage in the default
configuration (providing an emergency buffer to deal with
memory leaks or similar problems). It is not recommended to
decrease the value of this parameter below its default
value. It may be increased if you wish to allocate a very
large amount of storage engine memory or cache. In
particular, when the <literal>storageMemory</literal>
parameter is increased, the <literal>memory</literal>
parameter should be increased by an equal amount.
'';
};
storageMemory = mkOption {
type = types.string;
default = "1GiB";
description = ''
Maximum memory used for data storage. The default value is
<literal>1GiB</literal>. When specified without a unit,
<literal>MB</literal> is assumed. Clusters using the memory
storage engine will be restricted to using this amount of
memory per process for purposes of data storage. Memory
overhead associated with storing the data is counted against
this total. If you increase the
<literal>storageMemory</literal>, you should also increase
the <literal>memory</literal> parameter by the same amount.
'';
};
locality = mkOption {
default = {
machineId = null;
zoneId = null;
datacenterId = null;
dataHall = null;
};
description = ''
FoundationDB locality settings.
'';
type = types.submodule ({
options = {
machineId = mkOption {
default = null;
type = types.nullOr types.str;
description = ''
Machine identifier key. All processes on a machine should share a
unique id. By default, processes on a machine determine a unique id to share.
This does not generally need to be set.
'';
};
zoneId = mkOption {
default = null;
type = types.nullOr types.str;
description = ''
Zone identifier key. Processes that share a zone id are
considered non-unique for the purposes of data replication.
If unset, defaults to machine id.
'';
};
datacenterId = mkOption {
default = null;
type = types.nullOr types.str;
description = ''
Data center identifier key. All processes physically located in a
data center should share the id. If you are depending on data
center based replication this must be set on all processes.
'';
};
dataHall = mkOption {
default = null;
type = types.nullOr types.str;
description = ''
Data hall identifier key. All processes physically located in a
data hall should share the id. If you are depending on data
hall based replication this must be set on all processes.
'';
};
};
});
};
extraReadWritePaths = mkOption {
default = [ ];
type = types.listOf types.path;
description = ''
An extra set of filesystem paths that FoundationDB can read to
and write from. By default, FoundationDB runs under a heavily
namespaced systemd environment without write access to most of
the filesystem outside of its data and log directories. By
adding paths to this list, the set of writeable paths will be
expanded. This is useful for allowing e.g. backups to local files,
which must be performed on behalf of the foundationdb service.
'';
};
pidfile = mkOption {
type = types.path;
default = "/run/foundationdb.pid";
description = "Path to pidfile for fdbmonitor.";
};
};
config = mkIf cfg.enable {
meta.doc = ./foundationdb.xml;
meta.maintainers = with lib.maintainers; [ thoughtpolice ];
environment.systemPackages = [ pkgs.foundationdb ];
users.extraUsers = optionalAttrs (cfg.user == "foundationdb") (singleton
{ name = "foundationdb";
description = "FoundationDB User";
uid = config.ids.uids.foundationdb;
group = cfg.group;
});
users.extraGroups = optionalAttrs (cfg.group == "foundationdb") (singleton
{ name = "foundationdb";
gid = config.ids.gids.foundationdb;
});
networking.firewall.allowedTCPPortRanges = mkIf cfg.openFirewall
[ { from = cfg.listenPortStart;
to = (cfg.listenPortStart + cfg.serverProcesses) - 1;
}
];
systemd.services.foundationdb = {
description = "FoundationDB Service";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
unitConfig =
{ RequiresMountsFor = "${cfg.dataDir} ${cfg.logDir}";
};
serviceConfig =
let rwpaths = [ cfg.dataDir cfg.logDir cfg.pidfile "/etc/foundationdb" ]
++ cfg.extraReadWritePaths;
in
{ Type = "simple";
Restart = "always";
RestartSec = 5;
User = cfg.user;
Group = cfg.group;
PIDFile = "${cfg.pidfile}";
PermissionsStartOnly = true; # setup needs root perms
TimeoutSec = 120; # give reasonable time to shut down
# Security options
NoNewPrivileges = true;
ProtectHome = true;
ProtectSystem = "strict";
ProtectKernelTunables = true;
ProtectControlGroups = true;
PrivateTmp = true;
PrivateDevices = true;
ReadWritePaths = lib.concatStringsSep " " (map (x: "-" + x) rwpaths);
};
path = [ pkgs.foundationdb pkgs.coreutils ];
preStart = ''
rm -f ${cfg.pidfile} && \
touch ${cfg.pidfile} && \
chown -R ${cfg.user}:${cfg.group} ${cfg.pidfile}
for x in "${cfg.logDir}" "${cfg.dataDir}" /etc/foundationdb; do
[ ! -d "$x" ] && mkdir -m 0700 -vp "$x" && chown -R ${cfg.user}:${cfg.group} "$x";
done
if [ ! -f /etc/foundationdb/fdb.cluster ]; then
cf=/etc/foundationdb/fdb.cluster
desc=$(tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c8)
rand=$(tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c8)
echo ''${desc}:''${rand}@${initialIpAddr}:${builtins.toString cfg.listenPortStart} > $cf
chmod 0660 $cf && chown -R ${cfg.user}:${cfg.group} $cf
touch "${cfg.dataDir}/.first_startup"
fi
'';
script = ''
exec fdbmonitor --lockfile ${cfg.pidfile} --conffile ${configFile};
'';
postStart = ''
if [ -e "${cfg.dataDir}/.first_startup" ]; then
fdbcli --exec "configure new single ssd"
rm -f "${cfg.dataDir}/.first_startup";
fi
'';
};
};
}
@@ -0,0 +1,280 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="module-foundationdb">
<title>FoundationDB</title>
<para><emphasis>Source:</emphasis> <filename>modules/services/databases/foundationdb.nix</filename></para>
<para><emphasis>Upstream documentation:</emphasis> <link xlink:href="https://apple.github.io/foundationdb/"/></para>
<para><emphasis>Maintainer:</emphasis> Austin Seipp</para>
<para><emphasis>Default version:</emphasis> 5.1.x</para>
<para>FoundationDB (or "FDB") is a distributed, open source, high performance,
transactional key-value store. It can store petabytes of data and deliver
exceptional performance while maintaining consistency and ACID semantics
(serializable transactions) over a large cluster.</para>
<section><title>Configuring and basic setup</title>
<para>To enable FoundationDB, add the following to your
<filename>configuration.nix</filename>:
<programlisting>
services.foundationdb.enable = true;
</programlisting>
</para>
<para>After running <command>nixos-rebuild</command>, you can verify whether
FoundationDB is running by executing <command>fdbcli</command> (which is added
to <option>environment.systemPackages</option>):
<programlisting>
$ sudo -u foundationdb fdbcli
Using cluster file `/etc/foundationdb/fdb.cluster'.
The database is available.
Welcome to the fdbcli. For help, type `help'.
fdb> status
Using cluster file `/etc/foundationdb/fdb.cluster'.
Configuration:
Redundancy mode - single
Storage engine - memory
Coordinators - 1
Cluster:
FoundationDB processes - 1
Machines - 1
Memory availability - 5.4 GB per process on machine with least available
Fault Tolerance - 0 machines
Server time - 04/20/18 15:21:14
...
fdb>
</programlisting>
</para>
<para>FoundationDB is run under the <command>foundationdb</command> user and
group by default, but this may be changed in the NixOS configuration. The
systemd unit <command>foundationdb.service</command> controls the
<command>fdbmonitor</command> process.</para>
<para>By default, the NixOS module for FoundationDB creates a single
SSD-storage based database for development and basic usage. This storage engine
is designed for SSDs and will perform poorly on HDDs; however it can handle far
more data than the alternative "memory" engine and is a better default choice
for most deployments. (Note that you can change the storage backend on-the-fly
for a given FoundationDB cluster using <command>fdbcli</command>.)</para>
<para>Furthermore, only 1 server process and 1 backup agent are started in the
default configuration. See below for more on scaling to increase this.</para>
<para>FoundationDB stores all data for all server processes under
<filename>/var/lib/foundationdb</filename>. You can override this using
<option>services.foundationdb.dataDir</option>, e.g.
<programlisting>
services.foundationdb.dataDir = "/data/fdb";
</programlisting>
</para>
<para>Similarly, logs are stored under
<filename>/var/log/foundationdb</filename> by default, and there is a
corresponding <option>services.foundationdb.logDir</option> as well.</para>
</section>
<section><title>Scaling processes and backup agents</title>
<para>Scaling the number of server processes is quite easy; simply specify
<option>services.foundationdb.serverProcesses</option> to be the number of
FoundationDB worker processes that should be started on the machine.</para>
<para>FoundationDB worker processes typically require 4GB of RAM per-process at
minimum for good performance, so this option is set to 1 by default since the
maximum amount of RAM is unknown. You're advised to abide by this restriction,
so pick a number of processes so that each has 4GB or more.</para>
<para>A similar option exists in order to scale backup agent processes,
<option>services.foundationdb.backupProcesses</option>. Backup agents are not
as performance/RAM sensitive, so feel free to experiment with the number of
available backup processes.</para>
</section>
<section><title>Clustering</title>
<para>FoundationDB on NixOS works similarly to other Linux systems, so this
section will be brief. Please refer to the full FoundationDB documentation for
more on clustering.</para>
<para>FoundationDB organizes clusters using a set of
<emphasis>coordinators</emphasis>, which are just specially-designated worker
processes. By default, every installation of FoundationDB on NixOS will start
as its own individual cluster, with a single coordinator: the first worker
process on <command>localhost</command>.</para>
<para>Coordinators are specified globally using the
<command>/etc/foundationdb/fdb.cluster</command> file, which all servers and
client applications will use to find and join coordinators. Note that this file
<emphasis>can not</emphasis> be managed by NixOS so easily: FoundationDB is
designed so that it will rewrite the file at runtime for all clients and nodes
when cluster coordinators change, with clients transparently handling this
without intervention. It is fundamentally a mutable file, and you should not
try to manage it in any way in NixOS.</para>
<para>When dealing with a cluster, there are two main things you want to
do:</para>
<itemizedlist>
<listitem><para>Add a node to the cluster for storage/compute.</para></listitem>
<listitem><para>Promote an ordinary worker to a coordinator.</para></listitem>
</itemizedlist>
<para>A node must already be a member of the cluster in order to properly be
promoted to a coordinator, so you must always add it first if you wish to
promote it.</para>
<para>To add a machine to a FoundationDB cluster:</para>
<itemizedlist>
<listitem><para>Choose one of the servers to start as the initial coordinator.
</para></listitem>
<listitem><para>Copy the <command>/etc/foundationdb/fdb.cluster</command> file
from this server to all the other servers. Restart FoundationDB on all of
these other servers, so they join the cluster.</para></listitem>
<listitem><para>All of these servers are now connected and working together
in the cluster, under the chosen coordinator.</para></listitem>
</itemizedlist>
<para>At this point, you can add as many nodes as you want by just repeating
the above steps. By default there will still be a single coordinator: you can
use <command>fdbcli</command> to change this and add new coordinators.</para>
<para>As a convenience, FoundationDB can automatically assign coordinators
based on the redundancy mode you wish to achieve for the cluster. Once all the
nodes have been joined, simply set the replication policy, and then issue the
<command>coordinators auto</command> command</para>
<para>For example, assuming we have 3 nodes available, we can enable double
redundancy mode, then auto-select coordinators. For double redundancy, 3
coordinators is ideal: therefore FoundationDB will make
<emphasis>every</emphasis> node a coordinator automatically:</para>
<programlisting>
fdbcli> configure double ssd
fdbcli> coordinators auto
</programlisting>
<para>This will transparently update all the servers within seconds, and
appropriately rewrite the <command>fdb.cluster</command> file, as well as
informing all client processes to do the same.</para>
</section>
<section><title>Client connectivity</title>
<para>By default, all clients must use the current
<command>fdb.cluster</command> file to access a given FoundationDB cluster.
This file is located by default in
<command>/etc/foundationdb/fdb.cluster</command> on all machines with the
FoundationDB service enabled, so you may copy the active one from your cluster
to a new node in order to connect, if it is not part of the cluster.</para>
</section>
<section><title>Backups and Disaster Recovery</title>
<para>The usual rules for doing FoundationDB backups apply on NixOS as written
in the FoundationDB manual. However, one important difference is the security
profile for NixOS: by default, the <command>foundationdb</command> systemd unit
uses <emphasis>Linux namespaces</emphasis> to restrict write access to the
system, except for the log directory, data directory, and the
<command>/etc/foundationdb/</command> directory. This is enforced by default
and cannot be disabled.</para>
<para>However, a side effect of this is that the <command>fdbbackup</command>
command doesn't work properly for local filesystem backups: FoundationDB uses a
server process alongside the database processes to perform backups and copy the
backups to the filesystem. As a result, this process is put under the
restricted namespaces above: the backup process can only write to a limited
number of paths.</para>
<para>In order to allow flexible backup locations on local disks, the
FoundationDB NixOS module supports a
<option>services.foundationdb.extraReadWritePaths</option> option. This option
takes a list of paths, and adds them to the systemd unit, allowing the
processes inside the service to write (and read) the specified
directories.</para>
<para>For example, to create backups in <command>/opt/fdb-backups</command>,
first set up the paths in the module options:</para>
<programlisting>
services.foundationdb.extraReadWritePaths = [ "/opt/fdb-backups" ];
</programlisting>
<para>Restart the FoundationDB service, and it will now be able to write to
this directory (even if it does not yet exist.) Note: this path
<emphasis>must</emphasis> exist before restarting the unit. Otherwise, systemd
will not include it in the private FoundationDB namespace (and it will not add
it dynamically at runtime).</para>
<para>You can now perform a backup:</para>
<programlisting>
$ sudo -u foundationdb fdbbackup start -t default -d file:///opt/fdb-backups
$ sudo -u foundationdb fdbbackup status -t default
</programlisting>
</section>
<section><title>Known limitations</title>
<para>The FoundationDB setup for NixOS should currently be considered beta.
FoundationDB is not new software, but the NixOS compilation and integration has
only undergone fairly basic testing of all the available functionality.</para>
<itemizedlist>
<listitem><para>TLS plugin support is compiled in, but it's currently not
possible to specify the set of TLS certificate options in
<command>services.foundationdb</command></para></listitem>
<listitem><para>There is no way to specify individual parameters for
individual <command>fdbserver</command> processes. Currently, all server
processes inherit all the global <command>fdbmonitor</command> settings.
</para></listitem>
<listitem><para>Python bindings are not currently installed.</para></listitem>
<listitem><para>Ruby bindings are not currently installed.</para></listitem>
<listitem><para>Java bindings are not currently installed.</para></listitem>
<listitem><para>Go bindings are not currently installed.</para></listitem>
</itemizedlist>
</section>
<section><title>Options</title>
<para>NixOS's FoundationDB module allows you to configure all of the most
relevant configuration options for <command>fdbmonitor</command>, matching it
quite closely. For a complete list of all options, check <command>man
configuration.nix</command>.</para>
</section>
<section><title>Full documentation</title>
<para>FoundationDB is a complex piece of software, and requires careful
administration to properly use. Full documentation for administration can be
found here: <link xlink:href="https://apple.github.io/foundationdb/"/>.</para>
</section>
</chapter>
@@ -22,7 +22,7 @@ let
web_root = ${cfg.package}/etc/pgmanage/web_root web_root = ${cfg.package}/etc/pgmanage/web_root
data_root = ${cfg.dataRoot} sql_root = ${cfg.sqlRoot}
${optionalString (!isNull cfg.tls) '' ${optionalString (!isNull cfg.tls) ''
tls_cert = ${cfg.tls.cert} tls_cert = ${cfg.tls.cert}
@@ -130,7 +130,7 @@ let
''; '';
}; };
dataRoot = mkOption { sqlRoot = mkOption {
type = types.str; type = types.str;
default = "/var/lib/pgmanage"; default = "/var/lib/pgmanage";
description = '' description = ''
@@ -210,7 +210,7 @@ in {
users."${pgmanage}" = { users."${pgmanage}" = {
name = pgmanage; name = pgmanage;
group = pgmanage; group = pgmanage;
home = cfg.dataRoot; home = cfg.sqlRoot;
createHome = true; createHome = true;
}; };
groups."${pgmanage}" = { groups."${pgmanage}" = {
@@ -36,9 +36,6 @@ let
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
pre84 = versionOlder (builtins.parseDrvName postgresql.name).version "8.4";
in in
{ {
@@ -182,7 +179,7 @@ in
services.postgresql.authentication = mkAfter services.postgresql.authentication = mkAfter
'' ''
# Generated file; do not edit! # Generated file; do not edit!
local all all ident ${optionalString pre84 "sameuser"} local all all ident
host all all 127.0.0.1/32 md5 host all all 127.0.0.1/32 md5
host all all ::1/128 md5 host all all ::1/128 md5
''; '';
+20 -1
View File
@@ -15,6 +15,25 @@ let
fi fi
''; '';
desktopApplicationFile = pkgs.writeTextFile {
name = "emacsclient.desktop";
destination = "/share/applications/emacsclient.desktop";
text = ''
[Desktop Entry]
Name=Emacsclient
GenericName=Text Editor
Comment=Edit text
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
Exec=emacseditor %F
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=Emacs
Keywords=Text;Editor;
'';
};
in { in {
options.services.emacs = { options.services.emacs = {
@@ -74,7 +93,7 @@ in {
}; };
} // optionalAttrs cfg.enable { wantedBy = [ "default.target" ]; }; } // optionalAttrs cfg.enable { wantedBy = [ "default.target" ]; };
environment.systemPackages = [ cfg.package editorScript ]; environment.systemPackages = [ cfg.package editorScript desktopApplicationFile ];
environment.variables = { environment.variables = {
# This is required so that GTK applications launched from Emacs # This is required so that GTK applications launched from Emacs
+11 -1
View File
@@ -3,8 +3,8 @@
with lib; with lib;
let let
bluez-bluetooth = pkgs.bluez;
cfg = config.hardware.bluetooth; cfg = config.hardware.bluetooth;
bluez-bluetooth = cfg.package;
in { in {
@@ -21,6 +21,16 @@ in {
description = "Whether to power up the default Bluetooth controller on boot."; description = "Whether to power up the default Bluetooth controller on boot.";
}; };
package = mkOption {
type = types.package;
default = pkgs.bluez;
defaultText = "pkgs.bluez";
example = "pkgs.bluez.override { enableMidi = true; }";
description = ''
Which BlueZ package to use.
'';
};
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
+10 -3
View File
@@ -26,8 +26,15 @@ in {
name = "trezord-udev-rules"; name = "trezord-udev-rules";
destination = "/etc/udev/rules.d/51-trezor.rules"; destination = "/etc/udev/rules.d/51-trezor.rules";
text = '' text = ''
SUBSYSTEM=="usb", ATTR{idVendor}=="534c", ATTR{idProduct}=="0001", MODE="0666", GROUP="dialout", SYMLINK+="trezor%n" # Trezor 1
KERNEL=="hidraw*", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0666", GROUP="dialout" SUBSYSTEM=="usb", ATTR{idVendor}=="534c", ATTR{idProduct}=="0001", MODE="0666", GROUP="dialout", SYMLINK+="trezor%n"
KERNEL=="hidraw*", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0666", GROUP="dialout"
# Trezor 2 (Model-T)
SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c0", MODE="0661", GROUP="dialout", TAG+="uaccess", TAG+="udev-acl", SYMLINK+="trezor%n"
SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c1", MODE="0660", GROUP="dialout", TAG+="uaccess", TAG+="udev-acl", SYMLINK+="trezor%n"
KERNEL=="hidraw*", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", MODE="0660", GROUP="dialout", TAG+="uaccess", TAG+="udev-acl"
];
''; '';
}); });
@@ -38,7 +45,7 @@ in {
path = []; path = [];
serviceConfig = { serviceConfig = {
Type = "simple"; Type = "simple";
ExecStart = "${pkgs.trezord}/bin/trezord -f"; ExecStart = "${pkgs.trezord}/bin/trezord-go";
User = "trezord"; User = "trezord";
}; };
}; };
+1 -1
View File
@@ -158,7 +158,7 @@ in
services.dysnomia.properties = { services.dysnomia.properties = {
hostname = config.networking.hostName; hostname = config.networking.hostName;
system = if config.nixpkgs.system == "" then builtins.currentSystem else config.nixpkgs.system; inherit (config.nixpkgs.localSystem) system;
supportedTypes = (import "${pkgs.stdenv.mkDerivation { supportedTypes = (import "${pkgs.stdenv.mkDerivation {
name = "supportedtypes"; name = "supportedtypes";
+10 -19
View File
@@ -8,9 +8,6 @@ let
cfg = config.services.gitlab; cfg = config.services.gitlab;
ruby = cfg.packages.gitlab.ruby; ruby = cfg.packages.gitlab.ruby;
bundler = pkgs.bundler;
gemHome = "${cfg.packages.gitlab.rubyEnv}/${ruby.gemPath}";
gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket"; gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket";
gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket"; gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket";
@@ -137,8 +134,6 @@ let
gitlabEnv = { gitlabEnv = {
HOME = "${cfg.statePath}/home"; HOME = "${cfg.statePath}/home";
GEM_HOME = gemHome;
BUNDLE_GEMFILE = "${cfg.packages.gitlab}/share/gitlab/Gemfile";
UNICORN_PATH = "${cfg.statePath}/"; UNICORN_PATH = "${cfg.statePath}/";
GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/"; GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/";
GITLAB_STATE_PATH = "${cfg.statePath}"; GITLAB_STATE_PATH = "${cfg.statePath}";
@@ -158,19 +153,17 @@ let
gitlab-rake = pkgs.stdenv.mkDerivation rec { gitlab-rake = pkgs.stdenv.mkDerivation rec {
name = "gitlab-rake"; name = "gitlab-rake";
buildInputs = [ cfg.packages.gitlab cfg.packages.gitlab.rubyEnv pkgs.makeWrapper ]; buildInputs = [ pkgs.makeWrapper ];
phases = "installPhase fixupPhase"; dontBuild = true;
buildPhase = ""; unpackPhase = ":";
installPhase = '' installPhase = ''
mkdir -p $out/bin mkdir -p $out/bin
makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/bundle $out/bin/gitlab-bundle \ makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rake $out/bin/gitlab-rake \
${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \ ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \
--set GITLAB_CONFIG_PATH '${cfg.statePath}/config' \ --set GITLAB_CONFIG_PATH '${cfg.statePath}/config' \
--set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar config.services.postgresql.package ]}:$PATH' \ --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar config.services.postgresql.package ]}:$PATH' \
--set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \ --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \
--run 'cd ${cfg.packages.gitlab}/share/gitlab' --run 'cd ${cfg.packages.gitlab}/share/gitlab'
makeWrapper $out/bin/gitlab-bundle $out/bin/gitlab-rake \
--add-flags "exec rake"
''; '';
}; };
@@ -482,10 +475,10 @@ in {
Type = "simple"; Type = "simple";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutSec = "300"; TimeoutSec = "infinity";
Restart = "on-failure"; Restart = "on-failure";
WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
ExecStart="${cfg.packages.gitlab.rubyEnv}/bin/bundle exec \"sidekiq -C \"${cfg.packages.gitlab}/share/gitlab/config/sidekiq_queues.yml\" -e production -P ${cfg.statePath}/tmp/sidekiq.pid\""; ExecStart="${cfg.packages.gitlab.rubyEnv}/bin/sidekiq -C \"${cfg.packages.gitlab}/share/gitlab/config/sidekiq_queues.yml\" -e production -P ${cfg.statePath}/tmp/sidekiq.pid";
}; };
}; };
@@ -493,11 +486,9 @@ in {
after = [ "network.target" "gitlab.service" ]; after = [ "network.target" "gitlab.service" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
environment.HOME = gitlabEnv.HOME; environment.HOME = gitlabEnv.HOME;
environment.GEM_HOME = "${cfg.packages.gitaly.rubyEnv}/${ruby.gemPath}";
environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH; environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH;
path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv ruby ]; path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv cfg.packages.gitaly.rubyEnv.wrappedRuby ];
serviceConfig = { serviceConfig = {
#PermissionsStartOnly = true; # preStart must be run as root
Type = "simple"; Type = "simple";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
@@ -529,7 +520,7 @@ in {
Type = "simple"; Type = "simple";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutSec = "300"; TimeoutSec = "infinity";
Restart = "on-failure"; Restart = "on-failure";
WorkingDirectory = gitlabEnv.HOME; WorkingDirectory = gitlabEnv.HOME;
ExecStart = ExecStart =
@@ -658,10 +649,10 @@ in {
Type = "simple"; Type = "simple";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutSec = "300"; TimeoutSec = "infinity";
Restart = "on-failure"; Restart = "on-failure";
WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
ExecStart = "${cfg.packages.gitlab.rubyEnv}/bin/bundle exec \"unicorn -c ${cfg.statePath}/config/unicorn.rb -E production\""; ExecStart = "${cfg.packages.gitlab.rubyEnv}/bin/unicorn -c ${cfg.statePath}/config/unicorn.rb -E production";
}; };
}; };
+8
View File
@@ -32,6 +32,14 @@ in
''; '';
}; };
gitwebTheme = mkOption {
default = false;
type = types.bool;
description = ''
Use an alternative theme for gitweb, strongly inspired by GitHub.
'';
};
gitwebConfigFile = mkOption { gitwebConfigFile = mkOption {
default = pkgs.writeText "gitweb.conf" '' default = pkgs.writeText "gitweb.conf" ''
# path to git projects (<project>.git) # path to git projects (<project>.git)
+36 -6
View File
@@ -5,7 +5,10 @@ with lib;
let let
cfg = config.services.home-assistant; cfg = config.services.home-assistant;
configFile = pkgs.writeText "configuration.yaml" (builtins.toJSON cfg.config); # cfg.config != null can be assumed here
configFile = pkgs.writeText "configuration.json"
(builtins.toJSON (if cfg.applyDefaultConfig then
(lib.recursiveUpdate defaultConfig cfg.config) else cfg.config));
availableComponents = pkgs.home-assistant.availableComponents; availableComponents = pkgs.home-assistant.availableComponents;
@@ -38,6 +41,12 @@ let
then (cfg.package.override { inherit extraComponents; }) then (cfg.package.override { inherit extraComponents; })
else cfg.package; else cfg.package;
# If you are changing this, please update the description in applyDefaultConfig
defaultConfig = {
homeassistant.time_zone = config.time.timeZone;
http.server_port = (toString cfg.port);
};
in { in {
meta.maintainers = with maintainers; [ dotlambda ]; meta.maintainers = with maintainers; [ dotlambda ];
@@ -50,6 +59,26 @@ in {
description = "The config directory, where your <filename>configuration.yaml</filename> is located."; description = "The config directory, where your <filename>configuration.yaml</filename> is located.";
}; };
port = mkOption {
default = 8123;
type = types.int;
description = "The port on which to listen.";
};
applyDefaultConfig = mkOption {
default = true;
type = types.bool;
description = ''
Setting this option enables a few configuration options for HA based on NixOS configuration (such as time zone) to avoid having to manually specify configuration we already have.
</para>
<para>
Currently one side effect of enabling this is that the <literal>http</literal> component will be enabled.
</para>
<para>
This only takes effect if <literal>config != null</literal> in order to ensure that a manually managed <filename>configuration.yaml</filename> is not overwritten.
'';
};
config = mkOption { config = mkOption {
default = null; default = null;
type = with types; nullOr attrs; type = with types; nullOr attrs;
@@ -106,19 +135,20 @@ in {
description = "Home Assistant"; description = "Home Assistant";
after = [ "network.target" ]; after = [ "network.target" ];
preStart = lib.optionalString (cfg.config != null) '' preStart = lib.optionalString (cfg.config != null) ''
rm -f ${cfg.configDir}/configuration.yaml config=${cfg.configDir}/configuration.yaml
ln -s ${configFile} ${cfg.configDir}/configuration.yaml rm -f $config
${pkgs.remarshal}/bin/json2yaml -i ${configFile} -o $config
chmod 444 $config
''; '';
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
${package}/bin/hass --config "${cfg.configDir}"
'';
User = "hass"; User = "hass";
Group = "hass"; Group = "hass";
Restart = "on-failure"; Restart = "on-failure";
ProtectSystem = "strict"; ProtectSystem = "strict";
ReadWritePaths = "${cfg.configDir}"; ReadWritePaths = "${cfg.configDir}";
PrivateTmp = true; PrivateTmp = true;
RemoveIPC = true;
}; };
path = [ path = [
"/run/wrappers" # needed for ping "/run/wrappers" # needed for ping
+8 -1
View File
@@ -7,6 +7,13 @@ let
in { in {
options.services.logkeys = { options.services.logkeys = {
enable = mkEnableOption "logkeys service"; enable = mkEnableOption "logkeys service";
device = mkOption {
description = "Use the given device as keyboard input event device instead of /dev/input/eventX default.";
default = null;
type = types.nullOr types.string;
example = "/dev/input/event15";
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -14,7 +21,7 @@ in {
description = "LogKeys Keylogger Daemon"; description = "LogKeys Keylogger Daemon";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.logkeys}/bin/logkeys -s"; ExecStart = "${pkgs.logkeys}/bin/logkeys -s${lib.optionalString (cfg.device != null) " -d ${cfg.device}"}";
ExecStop = "${pkgs.logkeys}/bin/logkeys -k"; ExecStop = "${pkgs.logkeys}/bin/logkeys -k";
Type = "forking"; Type = "forking";
}; };
+1 -1
View File
@@ -213,7 +213,7 @@ in {
PermissionsStartOnly = true; PermissionsStartOnly = true;
}; };
preStart = '' preStart = ''
mkdir -m 0700 -p ${cfg.workDir} mkdir -m 0701 -p ${cfg.workDir}
''; '';
}; };
}; };
+1 -1
View File
@@ -23,7 +23,7 @@ let
options = options =
let let
scrubbedEval = evalModules { scrubbedEval = evalModules {
modules = [ { nixpkgs.system = config.nixpkgs.system; } ] ++ baseModules; modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ baseModules;
args = (config._module.args) // { modules = [ ]; }; args = (config._module.args) // { modules = [ ]; };
specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; };
}; };
@@ -50,7 +50,7 @@ in {
protocol = mkOption { protocol = mkOption {
description = "Which protocol to listen."; description = "Which protocol to listen.";
default = "http"; default = "http";
type = types.enum ["http" "https"]; type = types.enum ["http" "https" "socket"];
}; };
addr = mkOption { addr = mkOption {
@@ -20,6 +20,7 @@ let
exporterOpts = { exporterOpts = {
blackbox = import ./exporters/blackbox.nix { inherit config lib pkgs; }; blackbox = import ./exporters/blackbox.nix { inherit config lib pkgs; };
collectd = import ./exporters/collectd.nix { inherit config lib pkgs; }; collectd = import ./exporters/collectd.nix { inherit config lib pkgs; };
dovecot = import ./exporters/dovecot.nix { inherit config lib pkgs; };
fritzbox = import ./exporters/fritzbox.nix { inherit config lib pkgs; }; fritzbox = import ./exporters/fritzbox.nix { inherit config lib pkgs; };
json = import ./exporters/json.nix { inherit config lib pkgs; }; json = import ./exporters/json.nix { inherit config lib pkgs; };
minio = import ./exporters/minio.nix { inherit config lib pkgs; }; minio = import ./exporters/minio.nix { inherit config lib pkgs; };
@@ -0,0 +1,50 @@
{ config, lib, pkgs }:
with lib;
let
cfg = config.services.prometheus.exporters.dovecot;
in
{
port = 9166;
extraOpts = {
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
socketPath = mkOption {
type = types.path;
default = "/var/run/dovecot/stats";
example = "/var/run/dovecot2/stats";
description = ''
Path under which the stats socket is placed.
The user/group under which the exporter runs,
should be able to access the socket in order
to scrape the metrics successfully.
'';
};
scopes = mkOption {
type = types.listOf types.str;
default = [ "user" ];
example = [ "user" "global" ];
description = ''
Stats scopes to query.
'';
};
};
serviceOpts = {
serviceConfig = {
ExecStart = ''
${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.scopes ${concatStringsSep "," cfg.scopes} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
};
}
@@ -32,6 +32,33 @@ in
Path where Postfix places it's showq socket. Path where Postfix places it's showq socket.
''; '';
}; };
systemd = {
enable = mkEnableOption ''
reading metrics from the systemd-journal instead of from a logfile
'';
unit = mkOption {
type = types.str;
default = "postfix.service";
description = ''
Name of the postfix systemd unit.
'';
};
slice = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Name of the postfix systemd slice.
This overrides the <option>systemd.unit</option>.
'';
};
journalPath = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to the systemd journal.
'';
};
};
}; };
serviceOpts = { serviceOpts = {
serviceConfig = { serviceConfig = {
@@ -39,7 +66,15 @@ in
${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \ --web.telemetry-path ${cfg.telemetryPath} \
${concatStringsSep " \\\n " cfg.extraFlags} --postfix.showq_path ${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.jounal_path ${cfg.systemd.journalPath}"
++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${cfg.logfilePath}")}
''; '';
}; };
}; };
+7 -6
View File
@@ -6,6 +6,7 @@ let
confFile = pkgs.writeText "dante-sockd.conf" '' confFile = pkgs.writeText "dante-sockd.conf" ''
user.privileged: root user.privileged: root
user.unprivileged: dante user.unprivileged: dante
logoutput: syslog
${cfg.config} ${cfg.config}
''; '';
@@ -21,11 +22,10 @@ in
enable = mkEnableOption "Dante SOCKS proxy"; enable = mkEnableOption "Dante SOCKS proxy";
config = mkOption { config = mkOption {
default = null; type = types.lines;
type = types.nullOr types.str;
description = '' description = ''
Contents of Dante's configuration file Contents of Dante's configuration file.
NOTE: user.privileged/user.unprivileged are set by the service NOTE: user.privileged, user.unprivileged and logoutput are set by the service.
''; '';
}; };
}; };
@@ -33,7 +33,7 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ assertions = [
{ assertion = cfg.config != null; { assertion = cfg.config != "";
message = "please provide Dante configuration file contents"; message = "please provide Dante configuration file contents";
} }
]; ];
@@ -54,7 +54,8 @@ in
Type = "simple"; Type = "simple";
ExecStart = "${pkgs.dante}/bin/sockd -f ${confFile}"; ExecStart = "${pkgs.dante}/bin/sockd -f ${confFile}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
Restart = "always"; # Can crash sometimes; see https://github.com/NixOS/nixpkgs/pull/39005#issuecomment-381828708
Restart = "on-failure";
}; };
}; };
}; };
+60 -54
View File
@@ -3,24 +3,24 @@
let let
cfg = config.services.ddclient; cfg = config.services.ddclient;
boolToStr = bool: if bool then "yes" else "no"; boolToStr = bool: if bool then "yes" else "no";
dataDir = "/var/lib/ddclient";
configText = '' configText = ''
# This file can be used as a template for configFile or is automatically generated by Nix options. # This file can be used as a template for configFile or is automatically generated by Nix options.
daemon=${toString cfg.interval} cache=${dataDir}/ddclient.cache
cache=${cfg.homeDir}/ddclient.cache foreground=YES
pid=/run/ddclient/ddclient.pid
foreground=NO
use=${cfg.use} use=${cfg.use}
login=${cfg.username} login=${cfg.username}
password=${cfg.password} password=${cfg.password}
protocol=${cfg.protocol} protocol=${cfg.protocol}
${let server = cfg.server; in ${lib.optionalString (cfg.script != "") "script=${cfg.script}"}
lib.optionalString (server != "") "server=${server}"} ${lib.optionalString (cfg.server != "") "server=${cfg.server}"}
${lib.optionalString (cfg.zone != "") "zone=${cfg.zone}"}
ssl=${boolToStr cfg.ssl} ssl=${boolToStr cfg.ssl}
wildcard=YES wildcard=YES
quiet=${boolToStr cfg.quiet} quiet=${boolToStr cfg.quiet}
verbose=${boolToStr cfg.verbose} verbose=${boolToStr cfg.verbose}
${cfg.domain} ${lib.concatStringsSep "," cfg.domains}
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
@@ -44,17 +44,11 @@ with lib;
''; '';
}; };
homeDir = mkOption { domains = mkOption {
default = "/var/lib/ddclient"; default = [ "" ];
type = str; type = listOf str;
description = "Home directory for the daemon user.";
};
domain = mkOption {
default = "";
type = str;
description = '' description = ''
Domain name to synchronize. Domain name(s) to synchronize.
''; '';
}; };
@@ -62,7 +56,7 @@ with lib;
default = ""; default = "";
type = str; type = str;
description = '' description = ''
Username. User name.
''; '';
}; };
@@ -75,9 +69,12 @@ with lib;
}; };
interval = mkOption { interval = mkOption {
default = 600; default = "10min";
type = int; type = str;
description = "The interval at which to run the check and update."; description = ''
The interval at which to run the check and update.
See <command>man 7 systemd.time</command> for the format.
'';
}; };
configFile = mkOption { configFile = mkOption {
@@ -95,7 +92,7 @@ with lib;
default = "dyndns2"; default = "dyndns2";
type = str; type = str;
description = '' description = ''
Protocol to use with dynamic DNS provider (see http://sourceforge.net/apps/trac/ddclient/wiki/Protocols). Protocol to use with dynamic DNS provider (see https://sourceforge.net/p/ddclient/wiki/protocols).
''; '';
}; };
@@ -115,11 +112,20 @@ with lib;
''; '';
}; };
extraConfig = mkOption {
default = ""; quiet = mkOption {
type = lines; default = false;
type = bool;
description = '' description = ''
Extra configuration. Contents will be added verbatim to the configuration file. Print no messages for unnecessary updates.
'';
};
script = mkOption {
default = "";
type = str;
description = ''
script as required by some providers.
''; '';
}; };
@@ -139,11 +145,19 @@ with lib;
''; '';
}; };
quiet = mkOption { zone = mkOption {
default = false; default = "";
type = bool; type = str;
description = '' description = ''
Print no messages for unnecessary updates. zone as required by some providers.
'';
};
extraConfig = mkOption {
default = "";
type = lines;
description = ''
Extra configuration. Contents will be added verbatim to the configuration file.
''; '';
}; };
}; };
@@ -153,23 +167,8 @@ with lib;
###### implementation ###### implementation
config = mkIf config.services.ddclient.enable { config = mkIf config.services.ddclient.enable {
users = {
extraGroups.ddclient.gid = config.ids.gids.ddclient;
extraUsers.ddclient = {
uid = config.ids.uids.ddclient;
description = "ddclient daemon user";
group = "ddclient";
home = cfg.homeDir;
createHome = true;
};
};
environment.etc."ddclient.conf" = { environment.etc."ddclient.conf" = {
enable = cfg.configFile == "/etc/ddclient.conf"; enable = cfg.configFile == "/etc/ddclient.conf";
uid = config.ids.uids.ddclient;
gid = config.ids.gids.ddclient;
mode = "0600"; mode = "0600";
text = configText; text = configText;
}; };
@@ -180,15 +179,22 @@ with lib;
after = [ "network.target" ]; after = [ "network.target" ];
restartTriggers = [ config.environment.etc."ddclient.conf".source ]; restartTriggers = [ config.environment.etc."ddclient.conf".source ];
serviceConfig = { serviceConfig = rec {
RuntimeDirectory = "ddclient"; DynamicUser = true;
# we cannot run in forking mode as it swallows all the program output RuntimeDirectory = StateDirectory;
Type = "simple"; StateDirectory = builtins.baseNameOf dataDir;
User = "ddclient"; Type = "oneshot";
Group = "ddclient"; ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m666 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf";
ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -foreground -file ${cfg.configFile}"; ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf";
ProtectSystem = "full"; };
PrivateTmp = true; };
systemd.timers.ddclient = {
description = "Run ddclient";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = cfg.interval;
OnUnitInactiveSec = cfg.interval;
}; };
}; };
}; };
+24 -7
View File
@@ -9,12 +9,12 @@ let
mkdir -p $out/{servers,ip} mkdir -p $out/{servers,ip}
${concatMapStrings (ip: '' ${concatMapStrings (ip: ''
echo > "$out/ip/"${lib.escapeShellArg ip} touch "$out/ip/"${lib.escapeShellArg ip}
'') cfg.clientIps} '') cfg.clientIps}
${concatStrings (mapAttrsToList (host: ips: '' ${concatStrings (mapAttrsToList (host: ips: ''
${concatMapStrings (ip: '' ${concatMapStrings (ip: ''
echo ${lib.escapeShellArg ip} > "$out/servers/"${lib.escapeShellArg host} echo ${lib.escapeShellArg ip} >> "$out/servers/"${lib.escapeShellArg host}
'') ips} '') ips}
'') cfg.domainServers)} '') cfg.domainServers)}
@@ -34,33 +34,49 @@ in {
options = { options = {
services.dnscache = { services.dnscache = {
enable = mkOption { enable = mkOption {
default = false; default = false;
type = types.bool; type = types.bool;
description = "Whether to run the dnscache caching dns server"; description = "Whether to run the dnscache caching dns server.";
}; };
ip = mkOption { ip = mkOption {
default = "0.0.0.0"; default = "0.0.0.0";
type = types.str; type = types.str;
description = "IP address on which to listen for connections"; description = "IP address on which to listen for connections.";
}; };
clientIps = mkOption { clientIps = mkOption {
default = [ "127.0.0.1" ]; default = [ "127.0.0.1" ];
type = types.listOf types.str; type = types.listOf types.str;
description = "client IP addresses (or prefixes) from which to accept connections"; description = "Client IP addresses (or prefixes) from which to accept connections.";
example = ["192.168" "172.23.75.82"]; example = ["192.168" "172.23.75.82"];
}; };
domainServers = mkOption { domainServers = mkOption {
default = { }; default = { };
type = types.attrsOf (types.listOf types.str); type = types.attrsOf (types.listOf types.str);
description = "table of {hostname: server} pairs to use as authoritative servers for hosts (and subhosts)"; description = ''
Table of {hostname: server} pairs to use as authoritative servers for hosts (and subhosts).
If entry for @ is not specified predefined list of root servers is used.
'';
example = { example = {
"example.com" = ["8.8.8.8" "8.8.4.4"]; "@" = ["8.8.8.8" "8.8.4.4"];
"example.com" = ["192.168.100.100"];
}; };
}; };
forwardOnly = mkOption {
default = false;
type = types.bool;
description = ''
Whether to treat root servers (for @) as caching
servers, requesting addresses the same way a client does. This is
needed if you want to use e.g. Google DNS as your upstream DNS.
'';
};
}; };
}; };
@@ -82,6 +98,7 @@ in {
''; '';
script = '' script = ''
cd /var/lib/dnscache/ cd /var/lib/dnscache/
${optionalString cfg.forwardOnly "export FORWARDONLY=1"}
exec ./run exec ./run
''; '';
}; };
+145
View File
@@ -0,0 +1,145 @@
# NixOS module for hans, ip over icmp daemon
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.hans;
hansUser = "hans";
in
{
### configuration
options = {
services.hans = {
clients = mkOption {
default = {};
description = ''
Each attribute of this option defines a systemd service that
runs hans. Many or none may be defined.
The name of each service is
<literal>hans-<replaceable>name</replaceable></literal>
where <replaceable>name</replaceable> is the name of the
corresponding attribute name.
'';
example = literalExample ''
{
foo = {
server = "192.0.2.1";
extraConfig = "-v";
}
}
'';
type = types.attrsOf (types.submodule (
{
options = {
server = mkOption {
type = types.str;
default = "";
description = "IP address of server running hans";
example = "192.0.2.1";
};
extraConfig = mkOption {
type = types.str;
default = "";
description = "Additional command line parameters";
example = "-v";
};
passwordFile = mkOption {
type = types.str;
default = "";
description = "File that containts password";
};
};
}));
};
server = {
enable = mkOption {
type = types.bool;
default = false;
description = "enable hans server";
};
ip = mkOption {
type = types.str;
default = "";
description = "The assigned ip range";
example = "198.51.100.0";
};
respondToSystemPings = mkOption {
type = types.bool;
default = false;
description = "Force hans respond to ordinary pings";
};
extraConfig = mkOption {
type = types.str;
default = "";
description = "Additional command line parameters";
example = "-v";
};
passwordFile = mkOption {
type = types.str;
default = "";
description = "File that containts password";
};
};
};
};
### implementation
config = mkIf (cfg.server.enable || cfg.clients != {}) {
boot.kernel.sysctl = optionalAttrs cfg.server.respondToSystemPings {
"net.ipv4.icmp_echo_ignore_all" = 1;
};
boot.kernelModules = [ "tun" ];
systemd.services =
let
createHansClientService = name: cfg:
{
description = "hans client - ${name}";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script = "${pkgs.hans}/bin/hans -f -u ${hansUser} ${cfg.extraConfig} -c ${cfg.server} ${optionalString (cfg.passwordFile != "") "-p $(cat \"${cfg.passwordFile}\")"}";
serviceConfig = {
RestartSec = "30s";
Restart = "always";
};
};
in
listToAttrs (
mapAttrsToList
(name: value: nameValuePair "hans-${name}" (createHansClientService name value))
cfg.clients
) // {
hans = mkIf (cfg.server.enable) {
description = "hans, ip over icmp server daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
script = "${pkgs.hans}/bin/hans -f -u ${hansUser} ${cfg.server.extraConfig} -s ${cfg.server.ip} ${optionalString cfg.server.respondToSystemPings "-r"} ${optionalString (cfg.server.passwordFile != "") "-p $(cat \"${cfg.server.passwordFile}\")"}";
};
};
users.extraUsers = singleton {
name = hansUser;
description = "Hans daemon user";
};
};
meta.maintainers = with maintainers; [ gnidorah ];
}
+17 -5
View File
@@ -32,7 +32,7 @@ in
foo = { foo = {
server = "tunnel.mdomain.com"; server = "tunnel.mdomain.com";
relay = "8.8.8.8"; relay = "8.8.8.8";
extraConfig = "-P mysecurepassword"; extraConfig = "-v";
} }
} }
''; '';
@@ -57,7 +57,13 @@ in
type = types.str; type = types.str;
default = ""; default = "";
description = "Additional command line parameters"; description = "Additional command line parameters";
example = "-P mysecurepassword -l 192.168.1.10 -p 23"; example = "-l 192.168.1.10 -p 23";
};
passwordFile = mkOption {
type = types.str;
default = "";
description = "File that containts password";
}; };
}; };
})); }));
@@ -88,7 +94,13 @@ in
type = types.str; type = types.str;
default = ""; default = "";
description = "Additional command line parameters"; description = "Additional command line parameters";
example = "-P mysecurepassword -l 192.168.1.10 -p 23"; example = "-l 192.168.1.10 -p 23";
};
passwordFile = mkOption {
type = types.str;
default = "";
description = "File that containts password";
}; };
}; };
@@ -108,10 +120,10 @@ in
description = "iodine client - ${name}"; description = "iodine client - ${name}";
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
script = "${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "-P $(cat \"${cfg.passwordFile}\")"} ${cfg.relay} ${cfg.server}";
serviceConfig = { serviceConfig = {
RestartSec = "30s"; RestartSec = "30s";
Restart = "always"; Restart = "always";
ExecStart = "${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${cfg.relay} ${cfg.server}";
}; };
}; };
in in
@@ -124,7 +136,7 @@ in
description = "iodine, ip over dns server daemon"; description = "iodine, ip over dns server daemon";
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${cfg.server.ip} ${cfg.server.domain}"; script = "${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "-P $(cat \"${cfg.server.passwordFile}\")"} ${cfg.server.ip} ${cfg.server.domain}";
}; };
}; };
+1 -1
View File
@@ -26,7 +26,7 @@ in {
wants = [ "network.target" ]; wants = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.iwd}/bin/iwd"; serviceConfig.ExecStart = "${pkgs.iwd}/libexec/iwd";
}; };
}; };
+2 -1
View File
@@ -80,7 +80,7 @@ in
pidfile = mkOption { pidfile = mkOption {
type = types.path; type = types.path;
default = "/tmp/murmurd.pid"; default = "/run/murmur/murmurd.pid";
description = "Path to PID file for Murmur daemon."; description = "Path to PID file for Murmur daemon.";
}; };
@@ -252,6 +252,7 @@ in
serviceConfig = { serviceConfig = {
Type = "forking"; Type = "forking";
RuntimeDirectory = "murmur";
PIDFile = cfg.pidfile; PIDFile = cfg.pidfile;
Restart = "always"; Restart = "always";
User = "murmur"; User = "murmur";
+131 -6
View File
@@ -250,6 +250,46 @@ let
Use imports or pkgs.lib.readFile if you don't want this data in your config file. Use imports or pkgs.lib.readFile if you don't want this data in your config file.
''; '';
}; };
dnssec = mkEnableOption "DNSSEC";
dnssecPolicy = {
algorithm = mkOption {
type = types.str;
default = "RSASHA256";
description = "Which algorithm to use for DNSSEC";
};
keyttl = mkOption {
type = types.str;
default = "1h";
description = "TTL for dnssec records";
};
coverage = mkOption {
type = types.str;
default = "1y";
description = ''
The length of time to ensure that keys will be correct; no action will be taken to create new keys to be activated after this time.
'';
};
zsk = mkOption {
type = keyPolicy;
default = { keySize = 2048;
prePublish = "1w";
postPublish = "1w";
rollPeriod = "1mo";
};
description = "Key policy for zone signing keys";
};
ksk = mkOption {
type = keyPolicy;
default = { keySize = 4096;
prePublish = "1mo";
postPublish = "1mo";
rollPeriod = "0";
};
description = "Key policy for key signing keys";
};
};
maxRefreshSecs = mkOption { maxRefreshSecs = mkOption {
type = types.nullOr types.int; type = types.nullOr types.int;
@@ -367,10 +407,61 @@ let
and stats_noreset. and stats_noreset.
''; '';
}; };
}; };
}; };
keyPolicy = types.submodule {
options = {
keySize = mkOption {
type = types.int;
description = "Key size in bits";
};
prePublish = mkOption {
type = types.str;
description = "How long in advance to publish new keys";
};
postPublish = mkOption {
type = types.str;
description = "How long after deactivation to keep a key in the zone";
};
rollPeriod = mkOption {
type = types.str;
description = "How frequently to change keys";
};
};
};
dnssecZones = (filterAttrs (n: v: if v ? dnssec then v.dnssec else false) zoneConfigs);
dnssec = length (attrNames dnssecZones) != 0;
signZones = optionalString dnssec ''
mkdir -p ${stateDir}/dnssec
chown ${username}:${username} ${stateDir}/dnssec
chmod 0600 ${stateDir}/dnssec
${concatStrings (mapAttrsToList signZone dnssecZones)}
'';
signZone = name: zone: ''
${pkgs.bind}/bin/dnssec-keymgr -g ${pkgs.bind}/bin/dnssec-keygen -s ${pkgs.bind}/bin/dnssec-settime -K ${stateDir}/dnssec -c ${policyFile name zone.dnssecPolicy} ${name}
${pkgs.bind}/bin/dnssec-signzone -S -K ${stateDir}/dnssec -o ${name} -O full -N date ${stateDir}/zones/${name}
${nsdPkg}/sbin/nsd-checkzone ${name} ${stateDir}/zones/${name}.signed && mv -v ${stateDir}/zones/${name}.signed ${stateDir}/zones/${name}
'';
policyFile = name: policy: pkgs.writeText "${name}.policy" ''
zone ${name} {
algorithm ${policy.algorithm};
key-size zsk ${toString policy.zsk.keySize};
key-size ksk ${toString policy.ksk.keySize};
keyttl ${policy.keyttl};
pre-publish zsk ${policy.zsk.prePublish};
pre-publish ksk ${policy.ksk.prePublish};
post-publish zsk ${policy.zsk.postPublish};
post-publish ksk ${policy.ksk.postPublish};
roll-period zsk ${policy.zsk.rollPeriod};
roll-period ksk ${policy.ksk.rollPeriod};
coverage ${policy.coverage};
};
'';
in in
{ {
# options are ordered alphanumerically # options are ordered alphanumerically
@@ -380,6 +471,14 @@ in
bind8Stats = mkEnableOption "BIND8 like statistics"; bind8Stats = mkEnableOption "BIND8 like statistics";
dnssecInterval = mkOption {
type = types.str;
default = "1h";
description = ''
How often to check whether dnssec key rollover is required
'';
};
extraConfig = mkOption { extraConfig = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
@@ -741,7 +840,6 @@ in
}; };
zones = mkOption { zones = mkOption {
type = types.attrsOf zoneOptions; type = types.attrsOf zoneOptions;
default = {}; default = {};
@@ -785,7 +883,6 @@ in
serverGroup1. serverGroup1.
''; '';
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -832,9 +929,9 @@ in
mkdir -m 0700 -p "${stateDir}/var" mkdir -m 0700 -p "${stateDir}/var"
cat > "${stateDir}/don't touch anything in here" << EOF cat > "${stateDir}/don't touch anything in here" << EOF
Everything in this directory except NSD's state in var is Everything in this directory except NSD's state in var and dnssec
automatically generated and will be purged and redeployed is automatically generated and will be purged and redeployed by
by the nsd.service pre-start script. the nsd.service pre-start script.
EOF EOF
chown ${username}:${username} -R "${stateDir}/private" chown ${username}:${username} -R "${stateDir}/private"
@@ -848,6 +945,34 @@ in
''; '';
}; };
nixpkgs.config = mkIf dnssec {
bind.enablePython = true;
};
systemd.timers."nsd-dnssec" = mkIf dnssec {
description = "Automatic DNSSEC key rollover";
wantedBy = [ "nsd.service" ];
timerConfig = {
OnActiveSec = cfg.dnssecInterval;
OnUnitActiveSec = cfg.dnssecInterval;
};
};
systemd.services."nsd-dnssec" = mkIf dnssec {
description = "DNSSEC key rollover";
wantedBy = [ "nsd.service" ];
before = [ "nsd.service" ];
script = signZones;
postStop = ''
${pkgs.systemd}/bin/systemctl kill -s SIGHUP nsd.service
'';
};
}; };
meta.maintainers = with lib.maintainers; [ hrdinka ]; meta.maintainers = with lib.maintainers; [ hrdinka ];
@@ -65,7 +65,7 @@ let
path = [ pkgs.iptables pkgs.iproute pkgs.nettools ]; path = [ pkgs.iptables pkgs.iproute pkgs.nettools ];
serviceConfig.ExecStart = "@${openvpn}/sbin/openvpn openvpn --config ${configFile}"; serviceConfig.ExecStart = "@${openvpn}/sbin/openvpn openvpn --suppress-timestamps --config ${configFile}";
serviceConfig.Restart = "always"; serviceConfig.Restart = "always";
serviceConfig.Type = "notify"; serviceConfig.Type = "notify";
}; };
+20 -6
View File
@@ -301,6 +301,18 @@ in
default = "/var/lib/prosody"; default = "/var/lib/prosody";
}; };
user = mkOption {
type = types.str;
default = "prosody";
description = "User account under which prosody runs.";
};
group = mkOption {
type = types.str;
default = "prosody";
description = "Group account under which prosody runs.";
};
allowRegistration = mkOption { allowRegistration = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -427,7 +439,7 @@ in
environment.etc."prosody/prosody.cfg.lua".text = '' environment.etc."prosody/prosody.cfg.lua".text = ''
pidfile = "${cfg.dataDir}/prosody.pid" pidfile = "/run/prosody/prosody.pid"
log = "*syslog" log = "*syslog"
@@ -475,15 +487,15 @@ in
'') cfg.virtualHosts) } '') cfg.virtualHosts) }
''; '';
users.extraUsers.prosody = { users.extraUsers.prosody = mkIf (cfg.user == "prosody") {
uid = config.ids.uids.prosody; uid = config.ids.uids.prosody;
description = "Prosody user"; description = "Prosody user";
createHome = true; createHome = true;
group = "prosody"; inherit (cfg) group;
home = "${cfg.dataDir}"; home = "${cfg.dataDir}";
}; };
users.extraGroups.prosody = { users.extraGroups.prosody = mkIf (cfg.group == "prosody") {
gid = config.ids.gids.prosody; gid = config.ids.gids.prosody;
}; };
@@ -494,9 +506,11 @@ in
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
restartTriggers = [ config.environment.etc."prosody/prosody.cfg.lua".source ]; restartTriggers = [ config.environment.etc."prosody/prosody.cfg.lua".source ];
serviceConfig = { serviceConfig = {
User = "prosody"; User = cfg.user;
Group = cfg.group;
Type = "forking"; Type = "forking";
PIDFile = "${cfg.dataDir}/prosody.pid"; RuntimeDirectory = [ "prosody" ];
PIDFile = "/run/prosody/prosody.pid";
ExecStart = "${cfg.package}/bin/prosodyctl start"; ExecStart = "${cfg.package}/bin/prosodyctl start";
}; };
}; };
+1 -1
View File
@@ -133,7 +133,7 @@ in
users.groups = { users.groups = {
quagga = {}; quagga = {};
# Members of the quaggavty group can use vtysh to inspect the Quagga daemons # Members of the quaggavty group can use vtysh to inspect the Quagga daemons
quaggavty = {}; quaggavty = { members = [ "quagga" ]; };
}; };
systemd.services = systemd.services =
@@ -0,0 +1,112 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.shadowsocks;
opts = {
server = cfg.localAddress;
server_port = cfg.port;
method = cfg.encryptionMethod;
mode = cfg.mode;
user = "nobody";
fast_open = true;
} // optionalAttrs (cfg.password != null) { password = cfg.password; };
configFile = pkgs.writeText "shadowsocks.json" (builtins.toJSON opts);
in
{
###### interface
options = {
services.shadowsocks = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to run shadowsocks-libev shadowsocks server.
'';
};
localAddress = mkOption {
type = types.str;
default = "0.0.0.0";
description = ''
Local address to which the server binds.
'';
};
port = mkOption {
type = types.int;
default = 8388;
description = ''
Port which the server uses.
'';
};
password = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Password for connecting clients.
'';
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Password file with a password for connecting clients.
'';
};
mode = mkOption {
type = types.enum [ "tcp_only" "tcp_and_udp" "udp_only" ];
default = "tcp_and_udp";
description = ''
Relay protocols.
'';
};
encryptionMethod = mkOption {
type = types.str;
default = "chacha20-ietf-poly1305";
description = ''
Encryption method. See <link xlink:href="https://github.com/shadowsocks/shadowsocks-org/wiki/AEAD-Ciphers"/>.
'';
};
};
};
###### implementation
config = mkIf cfg.enable {
assertions = singleton
{ assertion = cfg.password == null || cfg.passwordFile == null;
message = "Cannot use both password and passwordFile for shadowsocks-libev";
};
systemd.services.shadowsocks-libev = {
description = "shadowsocks-libev Daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.shadowsocks-libev ] ++ optional (cfg.passwordFile != null) pkgs.jq;
serviceConfig.PrivateTmp = true;
script = ''
${optionalString (cfg.passwordFile != null) ''
cat ${configFile} | jq --arg password "$(cat "${cfg.passwordFile}")" '. + { password: $password }' > /tmp/shadowsocks.json
''}
exec ss-server -c ${if cfg.passwordFile != null then "/tmp/shadowsocks.json" else configFile}
'';
};
};
}
+62 -8
View File
@@ -213,6 +213,65 @@ in
description = "Files from which authorized keys are read."; description = "Files from which authorized keys are read.";
}; };
kexAlgorithms = mkOption {
type = types.listOf types.str;
default = [
"curve25519-sha256@libssh.org"
"diffie-hellman-group-exchange-sha256"
];
description = ''
Allowed key exchange algorithms
</para>
<para>
Defaults to recommended settings from both
<link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
and
<link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" />
'';
};
ciphers = mkOption {
type = types.listOf types.str;
default = [
"chacha20-poly1305@openssh.com"
"aes256-gcm@openssh.com"
"aes128-gcm@openssh.com"
"aes256-ctr"
"aes192-ctr"
"aes128-ctr"
];
description = ''
Allowed ciphers
</para>
<para>
Defaults to recommended settings from both
<link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
and
<link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" />
'';
};
macs = mkOption {
type = types.listOf types.str;
default = [
"hmac-sha2-512-etm@openssh.com"
"hmac-sha2-256-etm@openssh.com"
"umac-128-etm@openssh.com"
"hmac-sha2-512"
"hmac-sha2-256"
"umac-128@openssh.com"
];
description = ''
Allowed MACs
</para>
<para>
Defaults to recommended settings from both
<link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" />
and
<link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" />
'';
};
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
@@ -363,14 +422,9 @@ in
HostKey ${k.path} HostKey ${k.path}
'')} '')}
### Recommended settings from both: KexAlgorithms ${concatStringsSep "," cfg.kexAlgorithms}
# https://stribika.github.io/2015/01/04/secure-secure-shell.html Ciphers ${concatStringsSep "," cfg.ciphers}
# and MACs ${concatStringsSep "," cfg.macs}
# https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
# LogLevel VERBOSE logs user's key fingerprint on login. # LogLevel VERBOSE logs user's key fingerprint on login.
# Needed to have a clear audit track of which key was used to log in. # Needed to have a clear audit track of which key was used to log in.
@@ -0,0 +1,82 @@
{ config, lib, pkgs, ... }:
with lib;
with (import ./param-lib.nix lib);
let
cfg = config.services.strongswan-swanctl;
swanctlParams = import ./swanctl-params.nix lib;
in {
options.services.strongswan-swanctl = {
enable = mkEnableOption "strongswan-swanctl service";
package = mkOption {
type = types.package;
default = pkgs.strongswan;
defaultText = "pkgs.strongswan";
description = ''
The strongswan derivation to use.
'';
};
strongswan.extraConfig = mkOption {
type = types.str;
default = "";
description = ''
Contents of the <literal>strongswan.conf</literal> file.
'';
};
swanctl = paramsToOptions swanctlParams;
};
config = mkIf cfg.enable {
assertions = [
{ assertion = !config.services.strongswan.enable;
message = "cannot enable both services.strongswan and services.strongswan-swanctl. Choose either one.";
}
];
environment.etc."swanctl/swanctl.conf".text =
paramsToConf cfg.swanctl swanctlParams;
# The swanctl command complains when the following directories don't exist:
# See: https://wiki.strongswan.org/projects/strongswan/wiki/Swanctldirectory
system.activationScripts.strongswan-swanctl-etc = stringAfter ["etc"] ''
mkdir -p '/etc/swanctl/x509' # Trusted X.509 end entity certificates
mkdir -p '/etc/swanctl/x509ca' # Trusted X.509 Certificate Authority certificates
mkdir -p '/etc/swanctl/x509ocsp'
mkdir -p '/etc/swanctl/x509aa' # Trusted X.509 Attribute Authority certificates
mkdir -p '/etc/swanctl/x509ac' # Attribute Certificates
mkdir -p '/etc/swanctl/x509crl' # Certificate Revocation Lists
mkdir -p '/etc/swanctl/pubkey' # Raw public keys
mkdir -p '/etc/swanctl/private' # Private keys in any format
mkdir -p '/etc/swanctl/rsa' # PKCS#1 encoded RSA private keys
mkdir -p '/etc/swanctl/ecdsa' # Plain ECDSA private keys
mkdir -p '/etc/swanctl/bliss'
mkdir -p '/etc/swanctl/pkcs8' # PKCS#8 encoded private keys of any type
mkdir -p '/etc/swanctl/pkcs12' # PKCS#12 containers
'';
systemd.services.strongswan-swanctl = {
description = "strongSwan IPsec IKEv1/IKEv2 daemon using swanctl";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" "keys.target" ];
wants = [ "keys.target" ];
path = with pkgs; [ kmod iproute iptables utillinux ];
environment.STRONGSWAN_CONF = pkgs.writeTextFile {
name = "strongswan.conf";
text = cfg.strongswan.extraConfig;
};
restartTriggers = [ config.environment.etc."swanctl/swanctl.conf".source ];
serviceConfig = {
ExecStart = "${cfg.package}/sbin/charon-systemd";
Type = "notify";
ExecStartPost = "${cfg.package}/sbin/swanctl --load-all --noprompt";
ExecReload = "${cfg.package}/sbin/swanctl --reload";
Restart = "on-abnormal";
};
};
};
}
@@ -0,0 +1,162 @@
# In the following context a parameter is an attribute set that
# contains a NixOS option and a render function. It also contains the
# attribute: '_type = "param"' so we can distinguish it from other
# sets.
#
# The render function is used to convert the value of the option to a
# snippet of strongswan.conf. Most parameters simply render their
# value to a string. For example, take the following parameter:
#
# threads = mkIntParam 10 "Threads to use for request handling.";
#
# When a users defines the corresponding option as for example:
#
# services.strongswan-swanctl.strongswan.threads = 32;
#
# It will get rendered to the following snippet in strongswan.conf:
#
# threads = 32
#
# Some parameters however need to be able to change the attribute
# name. For example, take the following parameter:
#
# id = mkPrefixedAttrsOfParam (mkOptionalStrParam "") "...";
#
# A user can define the corresponding option as for example:
#
# id = {
# "foo" = "bar";
# "baz" = "qux";
# };
#
# This will get rendered to the following snippet:
#
# foo-id = bar
# baz-id = qux
#
# For this reason the render function is not simply a function from
# value -> string but a function from a value to an attribute set:
# { "${name}" = string }. This allows parameters to change the attribute
# name like in the previous example.
lib :
with lib;
with (import ./param-lib.nix lib);
rec {
mkParamOfType = type : strongswanDefault : description : {
_type = "param";
option = mkOption {
type = types.nullOr type;
default = null;
description = documentDefault description strongswanDefault;
};
render = single toString;
};
documentDefault = description : strongswanDefault :
if isNull strongswanDefault
then description
else description + ''
</para><para>
StrongSwan default: <literal><![CDATA[${builtins.toJSON strongswanDefault}]]></literal>
'';
single = f: name: value: { "${name}" = f value; };
mkStrParam = mkParamOfType types.str;
mkOptionalStrParam = mkStrParam null;
mkEnumParam = values : mkParamOfType (types.enum values);
mkIntParam = mkParamOfType types.int;
mkOptionalIntParam = mkIntParam null;
# We should have floats in Nix...
mkFloatParam = mkStrParam;
# TODO: Check for hex format:
mkHexParam = mkStrParam;
mkOptionalHexParam = mkOptionalStrParam;
# TODO: Check for duration format:
mkDurationParam = mkStrParam;
mkOptionalDurationParam = mkOptionalStrParam;
mkYesNoParam = strongswanDefault : description : {
_type = "param";
option = mkOption {
type = types.nullOr types.bool;
default = null;
description = documentDefault description strongswanDefault;
};
render = single (b: if b then "yes" else "no");
};
yes = true;
no = false;
mkSpaceSepListParam = mkSepListParam " ";
mkCommaSepListParam = mkSepListParam ",";
mkSepListParam = sep : strongswanDefault : description : {
_type = "param";
option = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
description = documentDefault description strongswanDefault;
};
render = single (value: concatStringsSep sep value);
};
mkAttrsOfParams = params :
mkAttrsOf params (types.submodule {options = paramsToOptions params;});
mkAttrsOfParam = param :
mkAttrsOf param param.option.type;
mkAttrsOf = param : option : description : {
_type = "param";
option = mkOption {
type = types.attrsOf option;
default = {};
inherit description;
};
render = single (attrs:
(paramsToRenderedStrings attrs
(mapAttrs (_n: _v: param) attrs)));
};
mkPrefixedAttrsOfParams = params :
mkPrefixedAttrsOf params (types.submodule {options = paramsToOptions params;});
mkPrefixedAttrsOfParam = param :
mkPrefixedAttrsOf param param.option.type;
mkPrefixedAttrsOf = p : option : description : {
_type = "param";
option = mkOption {
type = types.attrsOf option;
default = {};
inherit description;
};
render = prefix: attrs:
let prefixedAttrs = mapAttrs' (name: nameValuePair "${prefix}-${name}") attrs;
in paramsToRenderedStrings prefixedAttrs
(mapAttrs (_n: _v: p) prefixedAttrs);
};
mkPostfixedAttrsOfParams = params : description : {
_type = "param";
option = mkOption {
type = types.attrsOf (types.submodule {options = paramsToOptions params;});
default = {};
inherit description;
};
render = postfix: attrs:
let postfixedAttrs = mapAttrs' (name: nameValuePair "${name}-${postfix}") attrs;
in paramsToRenderedStrings postfixedAttrs
(mapAttrs (_n: _v: params) postfixedAttrs);
};
}
@@ -0,0 +1,82 @@
lib :
with lib;
rec {
paramsToConf = cfg : ps : mkConf 0 (paramsToRenderedStrings cfg ps);
# mkConf takes an indentation level (which usually starts at 0) and a nested
# attribute set of strings and will render that set to a strongswan.conf style
# configuration format. For example:
#
# mkConf 0 {a = "1"; b = { c = { "foo" = "2"; "bar" = "3"; }; d = "4";};} => ''
# a = 1
# b {
# c {
# foo = 2
# bar = 3
# }
# d = 4
# }''
mkConf = indent : ps :
concatMapStringsSep "\n"
(name:
let value = ps."${name}";
indentation = replicate indent " ";
in
indentation + (
if isAttrs value
then "${name} {\n" +
mkConf (indent + 2) value + "\n" +
indentation + "}"
else "${name} = ${value}"
)
)
(attrNames ps);
replicate = n : c : concatStrings (builtins.genList (_x : c) n);
# `paramsToRenderedStrings cfg ps` converts the NixOS configuration `cfg`
# (typically the "config" argument of a NixOS module) and the set of
# parameters `ps` (an attribute set where the values are constructed using the
# parameter constructors in ./param-constructors.nix) to a nested attribute
# set of strings (rendered parameters).
paramsToRenderedStrings = cfg : ps :
filterEmptySets (
(mapParamsRecursive (path: name: param:
let value = attrByPath path null cfg;
in optionalAttrs (!isNull value) (param.render name value)
) ps));
filterEmptySets = set : filterAttrs (n: v: !(isNull v)) (mapAttrs (name: value:
if isAttrs value
then let value' = filterEmptySets value;
in if value' == {}
then null
else value'
else value
) set);
# Recursively map over every parameter in the given attribute set.
mapParamsRecursive = mapAttrsRecursiveCond' (as: (!(as ? "_type" && as._type == "param")));
mapAttrsRecursiveCond' = cond: f: set:
let
recurse = path: set:
let
g =
name: value:
if isAttrs value && cond value
then { "${name}" = recurse (path ++ [name]) value; }
else f (path ++ [name]) name value;
in mapAttrs'' g set;
in recurse [] set;
mapAttrs'' = f: set:
foldl' (a: b: a // b) {} (map (attr: f attr set.${attr}) (attrNames set));
# Extract the options from the given set of parameters.
paramsToOptions = ps :
mapParamsRecursive (_path: name: param: { "${name}" = param.option; }) ps;
}
File diff suppressed because it is too large Load Diff
+32 -5
View File
@@ -4,22 +4,22 @@ let
cfg = config.services.unifi; cfg = config.services.unifi;
stateDir = "/var/lib/unifi"; stateDir = "/var/lib/unifi";
cmd = '' cmd = ''
@${pkgs.jre}/bin/java java \ @${cfg.jrePackage}/bin/java java \
${optionalString (cfg.initialJavaHeapSize != null) "-Xms${(toString cfg.initialJavaHeapSize)}m"} \ ${optionalString (cfg.initialJavaHeapSize != null) "-Xms${(toString cfg.initialJavaHeapSize)}m"} \
${optionalString (cfg.maximumJavaHeapSize != null) "-Xmx${(toString cfg.maximumJavaHeapSize)}m"} \ ${optionalString (cfg.maximumJavaHeapSize != null) "-Xmx${(toString cfg.maximumJavaHeapSize)}m"} \
-jar ${stateDir}/lib/ace.jar -jar ${stateDir}/lib/ace.jar
''; '';
mountPoints = [ mountPoints = [
{ {
what = "${pkgs.unifi}/dl"; what = "${cfg.unifiPackage}/dl";
where = "${stateDir}/dl"; where = "${stateDir}/dl";
} }
{ {
what = "${pkgs.unifi}/lib"; what = "${cfg.unifiPackage}/lib";
where = "${stateDir}/lib"; where = "${stateDir}/lib";
} }
{ {
what = "${pkgs.mongodb}/bin"; what = "${cfg.mongodbPackage}/bin";
where = "${stateDir}/bin"; where = "${stateDir}/bin";
} }
{ {
@@ -41,6 +41,33 @@ in
''; '';
}; };
services.unifi.jrePackage = mkOption {
type = types.package;
default = pkgs.jre8;
defaultText = "pkgs.jre8";
description = ''
The JRE package to use. Check the release notes to ensure it is supported.
'';
};
services.unifi.unifiPackage = mkOption {
type = types.package;
default = pkgs.unifiLTS;
defaultText = "pkgs.unifiLTS";
description = ''
The unifi package to use.
'';
};
services.unifi.mongodbPackage = mkOption {
type = types.package;
default = pkgs.mongodb;
defaultText = "pkgs.mongodb";
description = ''
The mongodb package to use.
'';
};
services.unifi.dataDir = mkOption { services.unifi.dataDir = mkOption {
type = types.str; type = types.str;
default = "${stateDir}/data"; default = "${stateDir}/data";
@@ -137,7 +164,7 @@ in
rm -rf "${stateDir}/webapps" rm -rf "${stateDir}/webapps"
mkdir -p "${stateDir}/webapps" mkdir -p "${stateDir}/webapps"
chown unifi "${stateDir}/webapps" chown unifi "${stateDir}/webapps"
ln -s "${pkgs.unifi}/webapps/ROOT" "${stateDir}/webapps/ROOT" ln -s "${cfg.unifiPackage}/webapps/ROOT" "${stateDir}/webapps/ROOT"
''; '';
postStop = '' postStop = ''
+48 -47
View File
@@ -53,30 +53,30 @@ let
}; };
preSetup = mkOption { preSetup = mkOption {
example = literalExample ['' example = literalExample ''
${pkgs.iproute}/bin/ip netns add foo ${pkgs.iproute}/bin/ip netns add foo
'']; '';
default = []; default = "";
type = with types; listOf str; type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
description = '' description = ''
A list of commands called at the start of the interface setup. Commands called at the start of the interface setup.
''; '';
}; };
postSetup = mkOption { postSetup = mkOption {
example = literalExample ['' example = literalExample ''
${pkgs.bash} -c 'printf "nameserver 10.200.100.1" | ${pkgs.openresolv}/bin/resolvconf -a wg0 -m 0' printf "nameserver 10.200.100.1" | ${pkgs.openresolv}/bin/resolvconf -a wg0 -m 0
'']; '';
default = []; default = "";
type = with types; listOf str; type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
description = "A list of commands called at the end of the interface setup."; description = "Commands called at the end of the interface setup.";
}; };
postShutdown = mkOption { postShutdown = mkOption {
example = literalExample ["${pkgs.openresolv}/bin/resolvconf -d wg0"]; example = literalExample "${pkgs.openresolv}/bin/resolvconf -d wg0";
default = []; default = "";
type = with types; listOf str; type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines;
description = "A list of commands called after shutting down the interface."; description = "Commands called after shutting down the interface.";
}; };
table = mkOption { table = mkOption {
@@ -182,9 +182,6 @@ let
}; };
ipCommand = "${pkgs.iproute}/bin/ip";
wgCommand = "${pkgs.wireguard}/bin/wg";
generateUnit = name: values: generateUnit = name: values:
# exactly one way to specify the private key must be set # exactly one way to specify the private key must be set
assert (values.privateKey != null) != (values.privateKeyFile != null); assert (values.privateKey != null) != (values.privateKeyFile != null);
@@ -196,49 +193,53 @@ let
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
environment.DEVICE = name; environment.DEVICE = name;
path = with pkgs; [ kmod iproute wireguard ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
ExecStart = flatten([ };
values.preSetup
"-${ipCommand} link del dev ${name}" script = ''
"${ipCommand} link add dev ${name} type wireguard" modprobe wireguard
(map (ip: ${values.preSetup}
"${ipCommand} address add ${ip} dev ${name}"
) values.ips)
("${wgCommand} set ${name} private-key ${privKey}" + ip link add dev ${name} type wireguard
optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}")
(map (peer: ${concatMapStringsSep "\n" (ip:
"ip address add ${ip} dev ${name}"
) values.ips}
wg set ${name} private-key ${privKey} ${
optionalString (values.listenPort != null) " listen-port ${toString values.listenPort}"}
${concatMapStringsSep "\n" (peer:
assert (peer.presharedKeyFile == null) || (peer.presharedKey == null); # at most one of the two must be set assert (peer.presharedKeyFile == null) || (peer.presharedKey == null); # at most one of the two must be set
let psk = if peer.presharedKey != null then pkgs.writeText "wg-psk" peer.presharedKey else peer.presharedKeyFile; let psk = if peer.presharedKey != null then pkgs.writeText "wg-psk" peer.presharedKey else peer.presharedKeyFile;
in in
"${wgCommand} set ${name} peer ${peer.publicKey}" + "wg set ${name} peer ${peer.publicKey}" +
optionalString (psk != null) " preshared-key ${psk}" + optionalString (psk != null) " preshared-key ${psk}" +
optionalString (peer.endpoint != null) " endpoint ${peer.endpoint}" + optionalString (peer.endpoint != null) " endpoint ${peer.endpoint}" +
optionalString (peer.persistentKeepalive != null) " persistent-keepalive ${toString peer.persistentKeepalive}" + optionalString (peer.persistentKeepalive != null) " persistent-keepalive ${toString peer.persistentKeepalive}" +
optionalString (peer.allowedIPs != []) " allowed-ips ${concatStringsSep "," peer.allowedIPs}" optionalString (peer.allowedIPs != []) " allowed-ips ${concatStringsSep "," peer.allowedIPs}"
) values.peers) ) values.peers}
"${ipCommand} link set up dev ${name}" ip link set up dev ${name}
(optionals (values.allowedIPsAsRoutes != false) (map (peer: ${optionalString (values.allowedIPsAsRoutes != false) (concatStringsSep "\n" (concatMap (peer:
(map (allowedIP: (map (allowedIP:
"${ipCommand} route replace ${allowedIP} dev ${name} table ${values.table}" "ip route replace ${allowedIP} dev ${name} table ${values.table}"
) peer.allowedIPs) ) peer.allowedIPs)
) values.peers)) ) values.peers))}
values.postSetup ${values.postSetup}
]); '';
ExecStop = flatten([
"${ipCommand} link del dev ${name}" preStop = ''
values.postShutdown ip link del dev ${name}
]); ${values.postShutdown}
}; '';
}; };
in in
+12 -3
View File
@@ -83,6 +83,8 @@ let
WebInterface ${if cfg.webInterface then "Yes" else "No"} WebInterface ${if cfg.webInterface then "Yes" else "No"}
LogLevel ${cfg.logLevel}
${cfg.extraConf} ${cfg.extraConf}
''; '';
@@ -165,6 +167,15 @@ in
''; '';
}; };
logLevel = mkOption {
type = types.str;
default = "info";
example = "debug";
description = ''
Specifies the cupsd logging verbosity.
'';
};
extraFilesConf = mkOption { extraFilesConf = mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
@@ -180,7 +191,7 @@ in
example = example =
'' ''
BrowsePoll cups.example.com BrowsePoll cups.example.com
LogLevel debug MaxCopies 42
''; '';
description = '' description = ''
Extra contents of the configuration file of the CUPS daemon Extra contents of the configuration file of the CUPS daemon
@@ -345,8 +356,6 @@ in
services.printing.extraConf = services.printing.extraConf =
'' ''
LogLevel info
DefaultAuthType Basic DefaultAuthType Basic
<Location /> <Location />
@@ -32,8 +32,11 @@ let
(if es5 then (pkgs.writeTextDir "log4j2.properties" cfg.logging) (if es5 then (pkgs.writeTextDir "log4j2.properties" cfg.logging)
else (pkgs.writeTextDir "logging.yml" cfg.logging)) else (pkgs.writeTextDir "logging.yml" cfg.logging))
]; ];
# Elasticsearch 5.x won't start when the scripts directory does not exist postBuild = concatStringsSep "\n" (concatLists [
postBuild = if es5 then "${pkgs.coreutils}/bin/mkdir -p $out/scripts" else ""; # Elasticsearch 5.x won't start when the scripts directory does not exist
(optional es5 "${pkgs.coreutils}/bin/mkdir -p $out/scripts")
(optional es6 "ln -s ${cfg.package}/config/jvm.options $out/jvm.options")
]);
}; };
esPlugins = pkgs.buildEnv { esPlugins = pkgs.buildEnv {
+103 -57
View File
@@ -6,70 +6,81 @@ with lib;
let let
cfg = config.services.oauth2_proxy; cfg = config.services.oauth2_proxy;
# Use like:
# repeatedArgs (arg: "--arg=${arg}") args
repeatedArgs = concatMapStringsSep " ";
# oauth2_proxy provides many options that are only relevant if you are using # oauth2_proxy provides many options that are only relevant if you are using
# a certain provider. This set maps from provider name to a function that # a certain provider. This set maps from provider name to a function that
# takes the configuration and returns a string that can be inserted into the # takes the configuration and returns a string that can be inserted into the
# command-line to launch oauth2_proxy. # command-line to launch oauth2_proxy.
providerSpecificOptions = { providerSpecificOptions = {
azure = cfg: '' azure = cfg: {
--azure-tenant=${cfg.azure.tenant} \ azure.tenant = cfg.azure.tenant;
--resource=${cfg.azure.resource} \ resource = cfg.azure.resource;
''; };
github = cfg: '' github = cfg: { github = {
${optionalString (!isNull cfg.github.org) "--github-org=${cfg.github.org}"} \ inherit (cfg.github) org team;
${optionalString (!isNull cfg.github.team) "--github-org=${cfg.github.team}"} \ }; };
'';
google = cfg: '' google = cfg: { google = with cfg.google; optionalAttrs (groups != []) {
--google-admin-email=${cfg.google.adminEmail} \ admin-email = adminEmail;
--google-service-account=${cfg.google.serviceAccountJSON} \ service-account = serviceAccountJSON;
${repeatedArgs (group: "--google-group=${group}") cfg.google.groups} \ group = groups;
''; }; };
}; };
authenticatedEmailsFile = pkgs.writeText "authenticated-emails" cfg.email.addresses; authenticatedEmailsFile = pkgs.writeText "authenticated-emails" cfg.email.addresses;
getProviderOptions = cfg: provider: providerSpecificOptions.${provider} or (_: "") cfg; getProviderOptions = cfg: provider: providerSpecificOptions.${provider} or (_: {}) cfg;
mkCommandLine = cfg: '' allConfig = with cfg; {
--provider='${cfg.provider}' \ inherit (cfg) provider scope upstream;
${optionalString (!isNull cfg.email.addresses) "--authenticated-emails-file='${authenticatedEmailsFile}'"} \ approval-prompt = approvalPrompt;
--approval-prompt='${cfg.approvalPrompt}' \ basic-auth-password = basicAuthPassword;
${optionalString (cfg.passBasicAuth && !isNull cfg.basicAuthPassword) "--basic-auth-password='${cfg.basicAuthPassword}'"} \ client-id = clientID;
--client-id='${cfg.clientID}' \ client-secret = clientSecret;
--client-secret='${cfg.clientSecret}' \ custom-templates-dir = customTemplatesDir;
${optionalString (!isNull cfg.cookie.domain) "--cookie-domain='${cfg.cookie.domain}'"} \ email-domain = email.domains;
--cookie-expire='${cfg.cookie.expire}' \ http-address = httpAddress;
--cookie-httponly=${boolToString cfg.cookie.httpOnly} \ login-url = loginURL;
--cookie-name='${cfg.cookie.name}' \ pass-access-token = passAccessToken;
--cookie-secret='${cfg.cookie.secret}' \ pass-basic-auth = passBasicAuth;
--cookie-secure=${boolToString cfg.cookie.secure} \ pass-host-header = passHostHeader;
${optionalString (!isNull cfg.cookie.refresh) "--cookie-refresh='${cfg.cookie.refresh}'"} \ proxy-prefix = proxyPrefix;
${optionalString (!isNull cfg.customTemplatesDir) "--custom-templates-dir='${cfg.customTemplatesDir}'"} \ profile-url = profileURL;
${repeatedArgs (x: "--email-domain='${x}'") cfg.email.domains} \ redeem-url = redeemURL;
--http-address='${cfg.httpAddress}' \ redirect-url = redirectURL;
${optionalString (!isNull cfg.htpasswd.file) "--htpasswd-file='${cfg.htpasswd.file}' --display-htpasswd-form=${boolToString cfg.htpasswd.displayForm}"} \ request-logging = requestLogging;
${optionalString (!isNull cfg.loginURL) "--login-url='${cfg.loginURL}'"} \ skip-auth-regex = skipAuthRegexes;
--pass-access-token=${boolToString cfg.passAccessToken} \ signature-key = signatureKey;
--pass-basic-auth=${boolToString cfg.passBasicAuth} \ validate-url = validateURL;
--pass-host-header=${boolToString cfg.passHostHeader} \ htpasswd-file = htpasswd.file;
--proxy-prefix='${cfg.proxyPrefix}' \ cookie = {
${optionalString (!isNull cfg.profileURL) "--profile-url='${cfg.profileURL}'"} \ inherit (cookie) domain secure expire name secret refresh;
${optionalString (!isNull cfg.redeemURL) "--redeem-url='${cfg.redeemURL}'"} \ httponly = cookie.httpOnly;
${optionalString (!isNull cfg.redirectURL) "--redirect-url='${cfg.redirectURL}'"} \ };
--request-logging=${boolToString cfg.requestLogging} \ set-xauthrequest = setXauthrequest;
${optionalString (!isNull cfg.scope) "--scope='${cfg.scope}'"} \ } // lib.optionalAttrs (!isNull cfg.email.addresses) {
${repeatedArgs (x: "--skip-auth-regex='${x}'") cfg.skipAuthRegexes} \ authenticated-emails-file = authenticatedEmailsFile;
${optionalString (!isNull cfg.signatureKey) "--signature-key='${cfg.signatureKey}'"} \ } // lib.optionalAttrs (cfg.passBasicAuth) {
--upstream='${cfg.upstream}' \ basic-auth-password = cfg.basicAuthPassword;
${optionalString (!isNull cfg.validateURL) "--validate-url='${cfg.validateURL}'"} \ } // lib.optionalAttrs (!isNull cfg.htpasswd.file) {
${optionalString cfg.tls.enable "--tls-cert='${cfg.tls.certificate}' --tls-key='${cfg.tls.key}' --https-address='${cfg.tls.httpsAddress}'"} \ display-htpasswd-file = cfg.htpasswd.displayForm;
'' + getProviderOptions cfg cfg.provider; } // lib.optionalAttrs tls.enable {
tls-cert = tls.certificate;
tls-key = tls.key;
https-address = tls.httpsAddress;
} // (getProviderOptions cfg cfg.provider) // cfg.extraConfig;
mapConfig = key: attr:
if (!isNull attr && attr != []) then (
if (builtins.typeOf attr) == "set" then concatStringsSep " "
(mapAttrsToList (name: value: mapConfig (key + "-" + name) value) attr) else
if (builtins.typeOf attr) == "list" then concatMapStringsSep " " (mapConfig key) attr else
if (builtins.typeOf attr) == "bool" then "--${key}=${boolToString attr}" else
if (builtins.typeOf attr) == "string" then "--${key}='${attr}'" else
"--${key}=${toString attr}")
else "";
configString = concatStringsSep " " (mapAttrsToList mapConfig allConfig);
in in
{ {
options.services.oauth2_proxy = { options.services.oauth2_proxy = {
@@ -110,7 +121,7 @@ in
}; };
clientID = mkOption { clientID = mkOption {
type = types.str; type = types.nullOr types.str;
description = '' description = ''
The OAuth Client ID. The OAuth Client ID.
''; '';
@@ -118,7 +129,7 @@ in
}; };
clientSecret = mkOption { clientSecret = mkOption {
type = types.str; type = types.nullOr types.str;
description = '' description = ''
The OAuth Client Secret. The OAuth Client Secret.
''; '';
@@ -272,7 +283,8 @@ in
#################################################### ####################################################
# UPSTREAM Configuration # UPSTREAM Configuration
upstream = mkOption { upstream = mkOption {
type = types.commas; type = with types; coercedTo string (x: [x]) (listOf string);
default = [];
description = '' description = ''
The http url(s) of the upstream endpoint or <literal>file://</literal> The http url(s) of the upstream endpoint or <literal>file://</literal>
paths for static files. Routing is based on the path. paths for static files. Routing is based on the path.
@@ -365,7 +377,7 @@ in
}; };
secret = mkOption { secret = mkOption {
type = types.str; type = types.nullOr types.str;
description = '' description = ''
The seed string for secure cookies. The seed string for secure cookies.
''; '';
@@ -494,10 +506,43 @@ in
''; '';
}; };
setXauthrequest = mkOption {
type = types.nullOr types.bool;
default = false;
description = ''
Set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode). Setting this to 'null' means using the upstream default (false).
'';
};
extraConfig = mkOption {
default = {};
description = ''
Extra config to pass to oauth2_proxy.
'';
};
keyFile = mkOption {
type = types.nullOr types.string;
default = null;
description = ''
oauth2_proxy allows passing sensitive configuration via environment variables.
Make a file that contains lines like
OAUTH2_PROXY_CLIENT_SECRET=asdfasdfasdf.apps.googleuserscontent.com
and specify the path here.
'';
example = "/run/keys/oauth2_proxy";
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.oauth2_proxy = mkIf (!isNull cfg.keyFile) {
clientID = mkDefault null;
clientSecret = mkDefault null;
cookie.secret = mkDefault null;
};
users.extraUsers.oauth2_proxy = { users.extraUsers.oauth2_proxy = {
description = "OAuth2 Proxy"; description = "OAuth2 Proxy";
}; };
@@ -511,7 +556,8 @@ in
serviceConfig = { serviceConfig = {
User = "oauth2_proxy"; User = "oauth2_proxy";
Restart = "always"; Restart = "always";
ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${mkCommandLine cfg}"; ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${configString}";
EnvironmentFile = mkIf (cfg.keyFile != null) cfg.keyFile;
}; };
}; };
+4 -6
View File
@@ -703,14 +703,10 @@ in
after = [ "network.target" ]; after = [ "network.target" ];
restartTriggers = [ torRcFile ]; restartTriggers = [ torRcFile ];
# Translated from the upstream contrib/dist/tor.service.in
preStart = ''
install -o tor -g tor -d ${torDirectory}/onion ${torRunDirectory}
${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config
'';
serviceConfig = serviceConfig =
{ Type = "simple"; { Type = "simple";
# Translated from the upstream contrib/dist/tor.service.in
ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config";
ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0"; ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
KillSignal = "SIGINT"; KillSignal = "SIGINT";
@@ -725,6 +721,8 @@ in
# DeviceAllow /dev/urandom r # DeviceAllow /dev/urandom r
# .. but we can't specify DeviceAllow multiple times. 'closed' # .. but we can't specify DeviceAllow multiple times. 'closed'
# is close enough. # is close enough.
RuntimeDirectory = "tor";
StateDirectory = [ "tor" "tor/onion" ];
PrivateTmp = "yes"; PrivateTmp = "yes";
DevicePolicy = "closed"; DevicePolicy = "closed";
InaccessibleDirectories = "/home"; InaccessibleDirectories = "/home";

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