Merge branch 'master' of github.com:NixOS/nixpkgs into update/jetbrains-2019.4

This commit is contained in:
kolaente 2019-12-02 18:36:18 +01:00
commit 305f2863cf
No known key found for this signature in database
GPG key ID: F40E70337AB24C9B
1402 changed files with 18857 additions and 19548 deletions

8
.github/CODEOWNERS vendored
View file

@ -47,6 +47,9 @@
/nixos/doc/manual/man-nixos-option.xml @nbp /nixos/doc/manual/man-nixos-option.xml @nbp
/nixos/modules/installer/tools/nixos-option.sh @nbp /nixos/modules/installer/tools/nixos-option.sh @nbp
# NixOS integration test driver
/nixos/lib/test-driver @tfc
# New NixOS modules # New NixOS modules
/nixos/modules/module-list.nix @Infinisil /nixos/modules/module-list.nix @Infinisil
@ -167,3 +170,8 @@
/nixos/modules/services/monitoring/prometheus/exporters.nix @WilliButz /nixos/modules/services/monitoring/prometheus/exporters.nix @WilliButz
/nixos/modules/services/monitoring/prometheus/exporters.xml @WilliButz /nixos/modules/services/monitoring/prometheus/exporters.xml @WilliButz
/nixos/tests/prometheus-exporters.nix @WilliButz /nixos/tests/prometheus-exporters.nix @WilliButz
# PHP
/pkgs/development/interpreters/php @etu
/pkgs/top-level/php-packages.nix @etu
/pkgs/build-support/build-pecl.nix @etu

View file

@ -74,7 +74,7 @@
preFixup = '' preFixup = ''
for f in $(find $out/bin/ $out/libexec/ -type f -executable); do for f in $(find $out/bin/ $out/libexec/ -type f -executable); do
wrapProgram "$f" \ wrapProgram "$f" \
--prefix GIO_EXTRA_MODULES : "${getLib gnome3.dconf}/lib/gio/modules" \ --prefix GIO_EXTRA_MODULES : "${getLib dconf}/lib/gio/modules" \
--prefix XDG_DATA_DIRS : "$out/share" \ --prefix XDG_DATA_DIRS : "$out/share" \
--prefix XDG_DATA_DIRS : "$out/share/gsettings-schemas/${name}" \ --prefix XDG_DATA_DIRS : "$out/share/gsettings-schemas/${name}" \
--prefix XDG_DATA_DIRS : "${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" \ --prefix XDG_DATA_DIRS : "${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" \
@ -102,7 +102,7 @@ preFixup = ''
</listitem> </listitem>
<listitem xml:id="ssec-gnome-hooks-dconf"> <listitem xml:id="ssec-gnome-hooks-dconf">
<para> <para>
<package>gnome3.dconf.lib</package> is a dependency of <package>wrapGAppsHook</package>, which then also adds it to the <envar>GIO_EXTRA_MODULES</envar> variable. <package>dconf.lib</package> is a dependency of <package>wrapGAppsHook</package>, which then also adds it to the <envar>GIO_EXTRA_MODULES</envar> variable.
</para> </para>
</listitem> </listitem>
<listitem xml:id="ssec-gnome-hooks-hicolor-icon-theme"> <listitem xml:id="ssec-gnome-hooks-hicolor-icon-theme">

View file

@ -25,14 +25,14 @@ avoided that by keeping all Haskell-related packages in a separate attribute
set called `haskellPackages`, which the following command will list: set called `haskellPackages`, which the following command will list:
``` ```
$ nix-env -f "<nixpkgs>" -qaP -A haskellPackages $ nix-env -f "<nixpkgs>" -qaP -A haskellPackages
haskellPackages.a50 a50-0.5 haskellPackages.a50 a50-0.5
haskellPackages.abacate haskell-abacate-0.0.0.0 haskellPackages.AAI AAI-0.2.0.1
haskellPackages.abcBridge haskell-abcBridge-0.12 haskellPackages.abacate abacate-0.0.0.0
haskellPackages.afv afv-0.1.1 haskellPackages.abc-puzzle abc-puzzle-0.2.1
haskellPackages.alex alex-3.1.4 haskellPackages.abcBridge abcBridge-0.15
haskellPackages.Allure Allure-0.4.101.1 haskellPackages.abcnotation abcnotation-1.9.0
haskellPackages.alms alms-0.6.7 haskellPackages.abeson abeson-0.1.0.1
[... some 8000 entries omitted ...] [... some 14000 entries omitted ...]
``` ```
To install any of those packages into your profile, refer to them by their To install any of those packages into your profile, refer to them by their
@ -101,19 +101,21 @@ to compile your Haskell packages with any GHC version you please. The following
command displays the complete list of available compilers: command displays the complete list of available compilers:
``` ```
$ nix-env -f "<nixpkgs>" -qaP -A haskell.compiler $ nix-env -f "<nixpkgs>" -qaP -A haskell.compiler
haskell.compiler.ghc6104 ghc-6.10.4 haskell.compiler.ghc822 ghc-8.2.2
haskell.compiler.ghc6123 ghc-6.12.3 haskell.compiler.integer-simple.ghc822 ghc-8.2.2
haskell.compiler.ghc704 ghc-7.0.4 haskell.compiler.ghc822Binary ghc-8.2.2-binary
haskell.compiler.ghc722 ghc-7.2.2 haskell.compiler.ghc844 ghc-8.4.4
haskell.compiler.ghc742 ghc-7.4.2 haskell.compiler.ghc863Binary ghc-8.6.3-binary
haskell.compiler.ghc763 ghc-7.6.3 haskell.compiler.ghc864 ghc-8.6.4
haskell.compiler.ghc784 ghc-7.8.4 haskell.compiler.integer-simple.ghc864 ghc-8.6.4
haskell.compiler.ghc7102 ghc-7.10.2 haskell.compiler.ghc865 ghc-8.6.5
haskell.compiler.ghcHEAD ghc-7.11.20150402 haskell.compiler.integer-simple.ghc865 ghc-8.6.5
haskell.compiler.ghcNokinds ghc-nokinds-7.11.20150704 haskell.compiler.ghc881 ghc-8.8.1
haskell.compiler.ghcjs ghcjs-0.1.0 haskell.compiler.integer-simple.ghc881 ghc-8.8.1
haskell.compiler.jhc jhc-0.8.2 haskell.compiler.ghcHEAD ghc-8.9.20190601
haskell.compiler.uhc uhc-1.1.9.0 haskell.compiler.integer-simple.ghcHEAD ghc-8.9.20190601
haskell.compiler.ghcjs84 ghcjs-8.4.0.1
haskell.compiler.ghcjs ghcjs-8.6.0.1
``` ```
We have no package sets for `jhc` or `uhc` yet, unfortunately, but for every We have no package sets for `jhc` or `uhc` yet, unfortunately, but for every

View file

@ -244,7 +244,7 @@
</question> </question>
<answer> <answer>
<para> <para>
Many packages assume that an unprefixed <command>ar</command> is available, but Nix doesn't provide one. It only provides a prefixed one, just as it only does for all the other binutils programs. It may be necessary to patch the package to fix the build system to use a prefixed `ar`. Many packages assume that an unprefixed <command>ar</command> is available, but Nix doesn't provide one. It only provides a prefixed one, just as it only does for all the other binutils programs. It may be necessary to patch the package to fix the build system to use a prefixed <command>ar</command>.
</para> </para>
</answer> </answer>
</qandaentry> </qandaentry>

View file

@ -1717,7 +1717,7 @@ someVar=$(stripHash $name)
</para> </para>
<para> <para>
The most typical use of the setup hook is actually to add other hooks which are then run (i.e. after all the setup hooks) on each dependency. For example, the C compiler wrapper's setup hook feeds itself flags for each dependency that contains relevant libraries and headers. This is done by defining a bash function, and appending its name to one of <envar>envBuildBuildHooks</envar>`, <envar>envBuildHostHooks</envar>`, <envar>envBuildTargetHooks</envar>`, <envar>envHostHostHooks</envar>`, <envar>envHostTargetHooks</envar>`, or <envar>envTargetTargetHooks</envar>`. These 6 bash variables correspond to the 6 sorts of dependencies by platform (there's 12 total but we ignore the propagated/non-propagated axis). The most typical use of the setup hook is actually to add other hooks which are then run (i.e. after all the setup hooks) on each dependency. For example, the C compiler wrapper's setup hook feeds itself flags for each dependency that contains relevant libraries and headers. This is done by defining a bash function, and appending its name to one of <envar>envBuildBuildHooks</envar>, <envar>envBuildHostHooks</envar>, <envar>envBuildTargetHooks</envar>, <envar>envHostHostHooks</envar>, <envar>envHostTargetHooks</envar>, or <envar>envTargetTargetHooks</envar>. These 6 bash variables correspond to the 6 sorts of dependencies by platform (there's 12 total but we ignore the propagated/non-propagated axis).
</para> </para>
<para> <para>

View file

@ -141,11 +141,10 @@
For a more useful example, try the following. This configuration only allows unfree packages named flash player and visual studio code: For a more useful example, try the following. This configuration only allows unfree packages named flash player and visual studio code:
<programlisting> <programlisting>
{ {
allowUnfreePredicate = (pkg: builtins.elem allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
(pkg.pname or (builtins.parseDrvName pkg.name).name) [ "flashplayer"
"flashplayer" "vscode"
"vscode" ];
]);
} }
</programlisting> </programlisting>
</para> </para>
@ -217,7 +216,7 @@
The following configuration example only allows insecure packages with very short names: The following configuration example only allows insecure packages with very short names:
<programlisting> <programlisting>
{ {
allowInsecurePredicate = (pkg: (builtins.stringLength (builtins.parseDrvName pkg.name).name) &lt;= 5); allowInsecurePredicate = pkg: builtins.stringLength (lib.getName pkg) &lt;= 5;
} }
</programlisting> </programlisting>
</para> </para>

View file

@ -84,7 +84,8 @@ let
hasInfix hasPrefix hasSuffix stringToCharacters stringAsChars escape hasInfix hasPrefix hasSuffix stringToCharacters stringAsChars escape
escapeShellArg escapeShellArgs replaceChars lowerChars escapeShellArg escapeShellArgs replaceChars lowerChars
upperChars toLower toUpper addContextFrom splitString upperChars toLower toUpper addContextFrom splitString
removePrefix removeSuffix versionOlder versionAtLeast getVersion removePrefix removeSuffix versionOlder versionAtLeast
getName getVersion
nameFromURL enableFeature enableFeatureAs withFeature nameFromURL enableFeature enableFeatureAs withFeature
withFeatureAs fixedWidthString fixedWidthNumber isStorePath withFeatureAs fixedWidthString fixedWidthNumber isStorePath
toInt readPathsFromFile fileContents; toInt readPathsFromFile fileContents;

View file

@ -472,6 +472,23 @@ rec {
*/ */
versionAtLeast = v1: v2: !versionOlder v1 v2; versionAtLeast = v1: v2: !versionOlder v1 v2;
/* This function takes an argument that's either a derivation or a
derivation's "name" attribute and extracts the name part from that
argument.
Example:
getName "youtube-dl-2016.01.01"
=> "youtube-dl"
getName pkgs.youtube-dl
=> "youtube-dl"
*/
getName = x:
let
parse = drv: (builtins.parseDrvName drv).name;
in if isString x
then parse x
else x.pname or (parse x.name);
/* This function takes an argument that's either a derivation or a /* This function takes an argument that's either a derivation or a
derivation's "name" attribute and extracts the version part from that derivation's "name" attribute and extracts the version part from that
argument. argument.

View file

@ -37,6 +37,7 @@ rec {
else if final.isAndroid then "bionic" else if final.isAndroid then "bionic"
else if final.isLinux /* default */ then "glibc" else if final.isLinux /* default */ then "glibc"
else if final.isMsp430 then "newlib" else if final.isMsp430 then "newlib"
else if final.isVc4 then "newlib"
else if final.isAvr then "avrlibc" else if final.isAvr then "avrlibc"
else if final.isNetBSD then "nblibc" else if final.isNetBSD then "nblibc"
# TODO(@Ericson2314) think more about other operating systems # TODO(@Ericson2314) think more about other operating systems

View file

@ -26,7 +26,7 @@ let
"riscv32-linux" "riscv64-linux" "riscv32-linux" "riscv64-linux"
"aarch64-none" "avr-none" "arm-none" "i686-none" "x86_64-none" "powerpc-none" "msp430-none" "riscv64-none" "riscv32-none" "aarch64-none" "avr-none" "arm-none" "i686-none" "x86_64-none" "powerpc-none" "msp430-none" "riscv64-none" "riscv32-none" "vc4-none"
]; ];
allParsed = map parse.mkSystemFromString all; allParsed = map parse.mkSystemFromString all;
@ -45,6 +45,7 @@ in {
x86_64 = filterDoubles predicates.isx86_64; x86_64 = filterDoubles predicates.isx86_64;
mips = filterDoubles predicates.isMips; mips = filterDoubles predicates.isMips;
riscv = filterDoubles predicates.isRiscV; riscv = filterDoubles predicates.isRiscV;
vc4 = filterDoubles predicates.isVc4;
cygwin = filterDoubles predicates.isCygwin; cygwin = filterDoubles predicates.isCygwin;
darwin = filterDoubles predicates.isDarwin; darwin = filterDoubles predicates.isDarwin;

View file

@ -118,6 +118,12 @@ rec {
config = "avr"; config = "avr";
}; };
vc4 = {
config = "vc4-elf";
libc = "newlib";
platform = {};
};
arm-embedded = { arm-embedded = {
config = "arm-none-eabi"; config = "arm-none-eabi";
libc = "newlib"; libc = "newlib";

View file

@ -21,6 +21,7 @@ rec {
isSparc = { cpu = { family = "sparc"; }; }; isSparc = { cpu = { family = "sparc"; }; };
isWasm = { cpu = { family = "wasm"; }; }; isWasm = { cpu = { family = "wasm"; }; };
isMsp430 = { cpu = { family = "msp430"; }; }; isMsp430 = { cpu = { family = "msp430"; }; };
isVc4 = { cpu = { family = "vc4"; }; };
isAvr = { cpu = { family = "avr"; }; }; isAvr = { cpu = { family = "avr"; }; };
isAlpha = { cpu = { family = "alpha"; }; }; isAlpha = { cpu = { family = "alpha"; }; };
isJavaScript = { cpu = cpuTypes.js; }; isJavaScript = { cpu = cpuTypes.js; };

View file

@ -112,6 +112,8 @@ rec {
msp430 = { bits = 16; significantByte = littleEndian; family = "msp430"; }; msp430 = { bits = 16; significantByte = littleEndian; family = "msp430"; };
avr = { bits = 8; family = "avr"; }; avr = { bits = 8; family = "avr"; };
vc4 = { bits = 32; significantByte = littleEndian; family = "vc4"; };
js = { bits = 32; significantByte = littleEndian; family = "js"; }; js = { bits = 32; significantByte = littleEndian; family = "js"; };
}; };

View file

@ -1484,6 +1484,16 @@
} }
]; ];
}; };
d-goldin = {
email = "dgoldin+github@protonmail.ch";
github = "d-goldin";
githubId = 43349662;
name = "Dima";
keys = [{
longkeyid = "rsa4096/BAB1D15FB7B4D4CE";
fingerprint = "1C4E F4FE 7F8E D8B7 1E88 CCDF BAB1 D15F B7B4 D4CE";
}];
};
dadada = { dadada = {
name = "dadada"; name = "dadada";
email = "dadada@dadada.li"; email = "dadada@dadada.li";
@ -1780,6 +1790,12 @@
githubId = 875324; githubId = 875324;
name = "David Johnson"; name = "David Johnson";
}; };
dmrauh = {
email = "dmrauh@posteo.de";
github = "dmrauh";
githubId = 37698547;
name = "Dominik Michael Rauh";
};
dmvianna = { dmvianna = {
email = "dmlvianna@gmail.com"; email = "dmlvianna@gmail.com";
github = "dmvianna"; github = "dmvianna";
@ -2515,6 +2531,7 @@
gazally = { gazally = {
email = "gazally@runbox.com"; email = "gazally@runbox.com";
github = "gazally"; github = "gazally";
githubId = 16470252;
name = "Gemini Lasswell"; name = "Gemini Lasswell";
}; };
gebner = { gebner = {
@ -3594,6 +3611,12 @@
github = "klntsky"; github = "klntsky";
githubId = 18447310; githubId = 18447310;
}; };
kmcopper = {
email = "kmcopper@danwin1210.me";
name = "Kyle Copperfield";
github = "kmcopper";
githubId = 57132115;
};
kmeakin = { kmeakin = {
email = "karlwfmeakin@gmail.com"; email = "karlwfmeakin@gmail.com";
name = "Karl Meakin"; name = "Karl Meakin";
@ -4139,6 +4162,12 @@
github = "marcweber"; github = "marcweber";
githubId = 34086; githubId = 34086;
name = "Marc Weber"; name = "Marc Weber";
};
marcus7070 = {
email = "marcus@geosol.com.au";
github = "marcus7070";
githubId = 50230945;
name = "Marcus Boyd";
}; };
marenz = { marenz = {
email = "marenz@arkom.men"; email = "marenz@arkom.men";
@ -4478,6 +4507,12 @@
githubId = 16974598; githubId = 16974598;
name = "Mike Playle"; name = "Mike Playle";
}; };
mkaito = {
email = "chris@mkaito.net";
github = "mkaito";
githubId = 20434;
name = "Christian Höppner";
};
mkazulak = { mkazulak = {
email = "kazulakm@gmail.com"; email = "kazulakm@gmail.com";
github = "mulderr"; github = "mulderr";
@ -4517,6 +4552,12 @@
githubId = 117842; githubId = 117842;
name = "Henri Bourcereau"; name = "Henri Bourcereau";
}; };
mmilata = {
email = "martin@martinmilata.cz";
github = "mmilata";
gitHubId = 85857;
name = "Martin Milata";
};
mmlb = { mmlb = {
email = "me.mmlb@mmlb.me"; email = "me.mmlb@mmlb.me";
github = "mmlb"; github = "mmlb";
@ -4631,6 +4672,12 @@
githubId = 2881922; githubId = 2881922;
name = "Francis St-Amour"; name = "Francis St-Amour";
}; };
mtrsk = {
email = "marcos.schonfinkel@protonmail.com";
github = "mtrsk";
githubId = 16356569;
name = "Marcos Benevides";
};
mredaelli = { mredaelli = {
email = "massimo@typish.io"; email = "massimo@typish.io";
github = "mredaelli"; github = "mredaelli";
@ -6099,7 +6146,7 @@
name = "Shahrukh Khan"; name = "Shahrukh Khan";
}; };
shanemikel = { shanemikel = {
email = "shanemikel1@gmail.com"; email = "shanepearlman@pm.me";
github = "shanemikel"; github = "shanemikel";
githubId = 6720672; githubId = 6720672;
name = "Shane Pearlman"; name = "Shane Pearlman";
@ -6720,6 +6767,12 @@
githubId = 42933; githubId = 42933;
name = "Andrew Childs"; name = "Andrew Childs";
}; };
thefenriswolf = {
email = "stefan.rohrbacher97@gmail.com";
github = "thefenriswolf";
githubId = "8547242";
name = "Stefan Rohrbacher";
};
thesola10 = { thesola10 = {
email = "thesola10@bobile.fr"; email = "thesola10@bobile.fr";
github = "thesola10"; github = "thesola10";
@ -7611,4 +7664,16 @@
githubId = 50867187; githubId = 50867187;
name = "Rakesh Gupta"; name = "Rakesh Gupta";
}; };
mlatus = {
email = "wqseleven@gmail.com";
github = "Ninlives";
githubId = 17873203;
name = "mlatus";
};
waiting-for-dev = {
email = "marc@lamarciana.com";
github = "waiting-for-dev";
githubId = 52650;
name = "Marc Busqué";
};
} }

View file

@ -126,7 +126,7 @@ let
packageData = package: { packageData = package: {
name = package.name; name = package.name;
pname = (builtins.parseDrvName package.name).name; pname = pkgs.lib.getName package;
updateScript = map builtins.toString (pkgs.lib.toList package.updateScript); updateScript = map builtins.toString (pkgs.lib.toList package.updateScript);
}; };

View file

@ -13,9 +13,7 @@
<para> <para>
It sets <xref linkend="opt-services.xserver.enable"/>, It sets <xref linkend="opt-services.xserver.enable"/>,
<xref linkend="opt-services.xserver.displayManager.sddm.enable"/>, <xref linkend="opt-services.xserver.displayManager.sddm.enable"/>,
<xref linkend="opt-services.xserver.desktopManager.plasma5.enable"/> ( <xref linkend="opt-services.xserver.desktopManager.plasma5.enable"/>, and
<link linkend="opt-services.xserver.desktopManager.plasma5.enableQt4Support">
without Qt4 Support</link>), and
<xref linkend="opt-services.xserver.libinput.enable"/> to true. It also <xref linkend="opt-services.xserver.libinput.enable"/> to true. It also
includes glxinfo and firefox in the system packages list. includes glxinfo and firefox in the system packages list.
</para> </para>

View file

@ -163,6 +163,57 @@
time during the releases development (if viable). time during the releases development (if viable).
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The <link linkend="opt-services.phpfpm.pools">phpfpm</link> module now sets
<literal>PrivateTmp=true</literal> in its systemd units for better process isolation.
If you rely on <literal>/tmp</literal> being shared with other services, explicitly override this by
setting <literal>serviceConfig.PrivateTmp</literal> to <literal>false</literal> for each phpfpm unit.
</para>
</listitem>
<listitem>
<para>
KDEs old multimedia framework Phonon no longer supports Qt 4. For that reason, Plasma desktop also does not have <option>enableQt4Support</option> option any more.
</para>
</listitem>
<listitem>
<para>
The BeeGFS module has been removed.
</para>
</listitem>
<listitem>
<para>
The osquery module has been removed.
</para>
</listitem>
<listitem>
<para>
Going forward, <literal>~/bin</literal> in the users home directory will no longer be in <literal>PATH</literal> by default.
If you depend on this you should set the option <literal>environment.homeBinInPath</literal> to <literal>true</literal>.
The aforementioned option was added this release.
</para>
</listitem>
<listitem>
<para>
The <literal>buildRustCrate</literal> infrastructure now produces <literal>lib</literal> outputs in addition to the <literal>out</literal> output.
This has led to drastically reduced closed sizes for some rust crates since development dependencies are now in the <literal>lib</literal> output.
</para>
</listitem>
<listitem>
<para>
The packages <literal>openobex</literal> and <literal>obexftp</literal>
are no loger installed when enabling bluetooth via
<option>hardware.bluetooth.enable</option>.
</para>
</listitem>
<listitem>
<para>
The <literal>dump1090</literal> derivation has been changed to use FlightAware's dump1090
as its upstream. However, this version does not have an internal webserver anymore. The
assets in the <literal>share/dump1090</literal> directory of the derivation can be used
in conjunction with an external webserver to replace this functionality.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>

View file

@ -86,7 +86,7 @@ let
optionsList = lib.sort optionLess optionsListDesc; optionsList = lib.sort optionLess optionsListDesc;
# Convert the list of options into an XML file. # Convert the list of options into an XML file.
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList); optionsXML = pkgs.writeText "options.xml" (builtins.toXML optionsList);
optionsNix = builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList); optionsNix = builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList);

View file

@ -3,7 +3,6 @@ from contextlib import contextmanager, _GeneratorContextManager
from xml.sax.saxutils import XMLGenerator from xml.sax.saxutils import XMLGenerator
import _thread import _thread
import atexit import atexit
import json
import os import os
import ptpython.repl import ptpython.repl
import pty import pty
@ -16,7 +15,9 @@ import sys
import tempfile import tempfile
import time import time
import unicodedata import unicodedata
from typing import Tuple, TextIO, Any, Callable, Dict, Iterator, Optional, List from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List
import shlex
import pathlib
CHAR_TO_KEY = { CHAR_TO_KEY = {
"A": "shift-a", "A": "shift-a",
@ -92,6 +93,10 @@ def eprint(*args: object, **kwargs: Any) -> None:
print(*args, file=sys.stderr, **kwargs) print(*args, file=sys.stderr, **kwargs)
def make_command(args: list) -> str:
return " ".join(map(shlex.quote, (map(str, args))))
def create_vlan(vlan_nr: str) -> Tuple[str, str, "subprocess.Popen[bytes]", Any]: def create_vlan(vlan_nr: str) -> Tuple[str, str, "subprocess.Popen[bytes]", Any]:
global log global log
log.log("starting VDE switch for network {}".format(vlan_nr)) log.log("starting VDE switch for network {}".format(vlan_nr))
@ -216,7 +221,7 @@ class Machine:
return path return path
self.state_dir = create_dir("vm-state-{}".format(self.name)) self.state_dir = create_dir("vm-state-{}".format(self.name))
self.shared_dir = create_dir("xchg-shared") self.shared_dir = create_dir("{}/xchg".format(self.state_dir))
self.booted = False self.booted = False
self.connected = False self.connected = False
@ -525,6 +530,33 @@ class Machine:
if ret.returncode != 0: if ret.returncode != 0:
raise Exception("Cannot convert screenshot") raise Exception("Cannot convert screenshot")
def copy_from_vm(self, source: str, target_dir: str = "") -> None:
"""Copy a file from the VM (specified by an in-VM source path) to a path
relative to `$out`. The file is copied via the `shared_dir` shared among
all the VMs (using a temporary directory).
"""
# Compute the source, target, and intermediate shared file names
out_dir = pathlib.Path(os.environ.get("out", os.getcwd()))
vm_src = pathlib.Path(source)
with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td:
shared_temp = pathlib.Path(shared_td)
vm_shared_temp = pathlib.Path("/tmp/xchg") / shared_temp.name
vm_intermediate = vm_shared_temp / vm_src.name
intermediate = shared_temp / vm_src.name
# Copy the file to the shared directory inside VM
self.succeed(make_command(["mkdir", "-p", vm_shared_temp]))
self.succeed(make_command(["cp", "-r", vm_src, vm_intermediate]))
self.succeed("sync")
abs_target = out_dir / target_dir / vm_src.name
abs_target.parent.mkdir(exist_ok=True, parents=True)
# Copy the file from the shared directory outside VM
if intermediate.is_dir():
shutil.copytree(intermediate, abs_target)
else:
shutil.copy(intermediate, abs_target)
# Make sure the cleanup is synced into VM
self.succeed("sync")
def dump_tty_contents(self, tty: str) -> None: def dump_tty_contents(self, tty: str) -> None:
"""Debugging: Dump the contents of the TTY<n> """Debugging: Dump the contents of the TTY<n>
""" """
@ -771,7 +803,9 @@ def run_tests() -> None:
machine.execute("sync") machine.execute("sync")
if nr_tests != 0: if nr_tests != 0:
log.log("{} out of {} tests succeeded".format(nr_succeeded, nr_tests)) eprint("{} out of {} tests succeeded".format(nr_succeeded, nr_tests))
if nr_tests > nr_succeeded:
sys.exit(1)
@contextmanager @contextmanager

View file

@ -122,7 +122,7 @@ in
description = '' description = ''
Include ~/bin/ in $PATH. Include ~/bin/ in $PATH.
''; '';
default = true; default = false;
type = types.bool; type = types.bool;
}; };

View file

@ -1,41 +0,0 @@
{ config, lib, ... }:
with lib;
let
cfg = config.networking.vpnc;
mkServiceDef = name: value:
{
name = "vpnc/${name}.conf";
value = { text = value; };
};
in
{
options = {
networking.vpnc = {
services = mkOption {
type = types.attrsOf types.str;
default = {};
example = literalExample ''
{ test = '''
IPSec gateway 192.168.1.1
IPSec ID someID
IPSec secret secretKey
Xauth username name
Xauth password pass
''';
}
'';
description =
''
The names of cisco VPNs and their associated definitions
'';
};
};
};
config.environment.etc = mapAttrs' mkServiceDef cfg.services;
}

View file

@ -111,9 +111,10 @@ in
config = mkIf enabled { config = mkIf enabled {
assertions = [ assertions = [
{ {
assertion = with config.services.xserver.displayManager; gdm.enable -> !gdm.wayland; assertion = with config.services.xserver.displayManager; gdm.nvidiaWayland -> cfg.modesetting.enable;
message = "NVIDIA drivers don't support wayland, set services.xserver.displayManager.gdm.wayland=false"; message = "You cannot use wayland with GDM without modesetting enabled for NVIDIA drivers, set `hardware.nvidia.modesetting.enable = true`";
} }
{ {
assertion = !optimusCfg.enable || assertion = !optimusCfg.enable ||
(optimusCfg.nvidiaBusId != "" && optimusCfg.intelBusId != ""); (optimusCfg.nvidiaBusId != "" && optimusCfg.intelBusId != "");

View file

@ -55,7 +55,7 @@ in
# Without dconf enabled it is impossible to use IBus # Without dconf enabled it is impossible to use IBus
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
gnome3.dconf ibusAutostart dconf ibusAutostart
]; ];
environment.variables = { environment.variables = {

View file

@ -11,7 +11,6 @@ with lib;
services.xserver = { services.xserver = {
desktopManager.plasma5 = { desktopManager.plasma5 = {
enable = true; enable = true;
enableQt4Support = false;
}; };
# Automatically login as nixos. # Automatically login as nixos.

View file

@ -35,7 +35,6 @@
./config/terminfo.nix ./config/terminfo.nix
./config/unix-odbc-drivers.nix ./config/unix-odbc-drivers.nix
./config/users-groups.nix ./config/users-groups.nix
./config/vpnc.nix
./config/vte.nix ./config/vte.nix
./config/zram.nix ./config/zram.nix
./hardware/acpilight.nix ./hardware/acpilight.nix
@ -308,6 +307,7 @@
./services/desktops/gnome3/sushi.nix ./services/desktops/gnome3/sushi.nix
./services/desktops/gnome3/tracker.nix ./services/desktops/gnome3/tracker.nix
./services/desktops/gnome3/tracker-miners.nix ./services/desktops/gnome3/tracker-miners.nix
./services/desktops/neard.nix
./services/desktops/profile-sync-daemon.nix ./services/desktops/profile-sync-daemon.nix
./services/desktops/system-config-printer.nix ./services/desktops/system-config-printer.nix
./services/desktops/telepathy.nix ./services/desktops/telepathy.nix
@ -519,7 +519,6 @@
./services/monitoring/munin.nix ./services/monitoring/munin.nix
./services/monitoring/nagios.nix ./services/monitoring/nagios.nix
./services/monitoring/netdata.nix ./services/monitoring/netdata.nix
./services/monitoring/osquery.nix
./services/monitoring/prometheus/default.nix ./services/monitoring/prometheus/default.nix
./services/monitoring/prometheus/alertmanager.nix ./services/monitoring/prometheus/alertmanager.nix
./services/monitoring/prometheus/exporters.nix ./services/monitoring/prometheus/exporters.nix
@ -539,7 +538,6 @@
./services/monitoring/zabbix-agent.nix ./services/monitoring/zabbix-agent.nix
./services/monitoring/zabbix-proxy.nix ./services/monitoring/zabbix-proxy.nix
./services/monitoring/zabbix-server.nix ./services/monitoring/zabbix-server.nix
./services/network-filesystems/beegfs.nix
./services/network-filesystems/cachefilesd.nix ./services/network-filesystems/cachefilesd.nix
./services/network-filesystems/davfs2.nix ./services/network-filesystems/davfs2.nix
./services/network-filesystems/drbd.nix ./services/network-filesystems/drbd.nix

View file

@ -9,7 +9,6 @@
displayManager.sddm.enable = true; displayManager.sddm.enable = true;
desktopManager.plasma5 = { desktopManager.plasma5 = {
enable = true; enable = true;
enableQt4Support = false;
}; };
libinput.enable = true; # for touchpad support on many laptops libinput.enable = true; # for touchpad support on many laptops
}; };

View file

@ -32,13 +32,13 @@ in
environment.etc = optionals (cfg.profiles != {}) environment.etc = optionals (cfg.profiles != {})
(mapAttrsToList mkDconfProfile cfg.profiles); (mapAttrsToList mkDconfProfile cfg.profiles);
services.dbus.packages = [ pkgs.gnome3.dconf ]; services.dbus.packages = [ pkgs.dconf ];
# For dconf executable # For dconf executable
environment.systemPackages = [ pkgs.gnome3.dconf ]; environment.systemPackages = [ pkgs.dconf ];
# Needed for unwrapped applications # Needed for unwrapped applications
environment.variables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.gnome3.dconf.lib}/lib/gio/modules" ]; environment.variables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.dconf.lib}/lib/gio/modules" ];
}; };
} }

View file

@ -8,18 +8,16 @@
with lib; with lib;
let let
cfg = config.services.ssmtp;
cfg = config.networking.defaultMailServer;
in in
{ {
options = { options = {
networking.defaultMailServer = { services.ssmtp = {
directDelivery = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
@ -29,7 +27,7 @@ in
<command>sendmail</command> or <command>postfix</command> on <command>sendmail</command> or <command>postfix</command> on
your machine, set this option to <literal>true</literal>, and your machine, set this option to <literal>true</literal>, and
set the option set the option
<option>networking.defaultMailServer.hostName</option> to the <option>services.ssmtp.hostName</option> to the
host name of your preferred mail server. host name of your preferred mail server.
''; '';
}; };
@ -129,9 +127,9 @@ in
}; };
config = mkIf cfg.directDelivery { config = mkIf cfg.enable {
networking.defaultMailServer.authPassFile = mkIf (cfg.authPass != "") services.ssmtp.authPassFile = mkIf (cfg.authPass != "")
(mkDefault (toString (pkgs.writeTextFile { (mkDefault (toString (pkgs.writeTextFile {
name = "ssmtp-authpass"; name = "ssmtp-authpass";
text = cfg.authPass; text = cfg.authPass;

View file

@ -10,6 +10,9 @@ with lib;
(mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) (mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
(mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) (mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
(mkRenamedOptionModule [ "networking" "networkmanager" "useDnsmasq" ] [ "networking" "networkmanager" "dns" ]) (mkRenamedOptionModule [ "networking" "networkmanager" "useDnsmasq" ] [ "networking" "networkmanager" "dns" ])
(mkRenamedOptionModule [ "networking" "connman" ] [ "services" "connman" ])
(mkRenamedOptionModule [ "networking" "defaultMailServer" ] [ "services" "ssmtp" ])
(mkRenamedOptionModule [ "services" "ssmtp" "directDelivery" ] [ "services" "ssmtp" "enable" ])
(mkChangedOptionModule [ "services" "printing" "gutenprint" ] [ "services" "printing" "drivers" ] (mkChangedOptionModule [ "services" "printing" "gutenprint" ] [ "services" "printing" "drivers" ]
(config: (config:
let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config; let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config;
@ -235,6 +238,7 @@ with lib;
(mkRemovedOptionModule [ "services" "zabbixServer" "dbPassword" ] "Use services.zabbixServer.database.passwordFile instead.") (mkRemovedOptionModule [ "services" "zabbixServer" "dbPassword" ] "Use services.zabbixServer.database.passwordFile instead.")
(mkRemovedOptionModule [ "systemd" "generator-packages" ] "Use systemd.packages instead.") (mkRemovedOptionModule [ "systemd" "generator-packages" ] "Use systemd.packages instead.")
(mkRemovedOptionModule [ "fonts" "enableCoreFonts" ] "Use fonts.fonts = [ pkgs.corefonts ]; instead.") (mkRemovedOptionModule [ "fonts" "enableCoreFonts" ] "Use fonts.fonts = [ pkgs.corefonts ]; instead.")
(mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.")
# ZSH # ZSH
(mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ])
@ -279,6 +283,13 @@ with lib;
# BLCR # BLCR
(mkRemovedOptionModule [ "environment.blcr.enable" ] "The BLCR module has been removed") (mkRemovedOptionModule [ "environment.blcr.enable" ] "The BLCR module has been removed")
# beegfs
(mkRemovedOptionModule [ "services.beegfsEnable" ] "The BeeGFS module has been removed")
(mkRemovedOptionModule [ "services.beegfs" ] "The BeeGFS module has been removed")
# osquery
(mkRemovedOptionModule [ "services.osquery" ] "The osquery module has been removed")
# Redis # Redis
(mkRemovedOptionModule [ "services" "redis" "user" ] "The redis module now is hardcoded to the redis user.") (mkRemovedOptionModule [ "services" "redis" "user" ] "The redis module now is hardcoded to the redis user.")
(mkRemovedOptionModule [ "services" "redis" "dbpath" ] "The redis module now uses /var/lib/redis as data directory.") (mkRemovedOptionModule [ "services" "redis" "dbpath" ] "The redis module now uses /var/lib/redis as data directory.")

View file

@ -66,7 +66,8 @@ in {
if cfg.user == "roon-server" then { if cfg.user == "roon-server" then {
isSystemUser = true; isSystemUser = true;
description = "Roon Server user"; description = "Roon Server user";
groups = [ cfg.group "audio" ]; group = cfg.group;
extraGroups = [ "audio" ];
} }
else {}; else {};
}; };

View file

@ -8,15 +8,11 @@ let
mysql = cfg.package; mysql = cfg.package;
isMariaDB = isMariaDB = lib.getName mysql == lib.getName pkgs.mariadb;
let
pName = _p: (builtins.parseDrvName (_p.name)).name;
in pName mysql == pName pkgs.mariadb;
isMysqlAtLeast57 = isMysqlAtLeast57 =
let (lib.getName mysql == lib.getName pkgs.mysql57)
pName = _p: (builtins.parseDrvName (_p.name)).name; && (builtins.compareVersions mysql.version "5.7" >= 0);
in (pName mysql == pName pkgs.mysql57)
&& ((builtins.compareVersions mysql.version "5.7") >= 0);
mysqldOptions = mysqldOptions =
"--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}"; "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${mysql}";

View file

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

View file

@ -43,7 +43,7 @@ in
serviceConfig = { serviceConfig = {
DynamicUser = true; DynamicUser = true;
StateDirectory = "openarena"; StateDirectory = "openarena";
ExecStart = "${pkgs.openarena}/bin/openarena-server +set fs_basepath ${pkgs.openarena}/openarena-0.8.8 +set fs_homepath /var/lib/openarena ${concatStringsSep " " cfg.extraFlags}"; ExecStart = "${pkgs.openarena}/bin/oa_ded +set fs_basepath ${pkgs.openarena}/openarena-0.8.8 +set fs_homepath /var/lib/openarena ${concatStringsSep " " cfg.extraFlags}";
Restart = "on-failure"; Restart = "on-failure";
# Hardening # Hardening

View file

@ -36,17 +36,25 @@ in {
''; '';
}; };
config = mkOption {
type = with types; attrsOf (attrsOf (oneOf [ bool int str ]));
example = {
General = {
ControllerMode = "bredr";
};
};
description = "Set configuration for system-wide bluetooth (/etc/bluetooth/main.conf).";
};
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = with types; nullOr lines;
default = ""; default = null;
example = '' example = ''
[General] [General]
ControllerMode = bredr ControllerMode = bredr
''; '';
description = '' description = ''
Set additional configuration for system-wide bluetooth (/etc/bluetooth/main.conf). Set additional configuration for system-wide bluetooth (/etc/bluetooth/main.conf).
NOTE: We already include [Policy], so any configuration under the Policy group should come first.
''; '';
}; };
}; };
@ -56,16 +64,18 @@ in {
###### implementation ###### implementation
config = mkIf cfg.enable { config = mkIf cfg.enable {
warnings = optional (cfg.extraConfig != null) "hardware.bluetooth.`extraConfig` is deprecated, please use hardware.bluetooth.`config`.";
environment.systemPackages = [ bluez-bluetooth pkgs.openobex pkgs.obexftp ]; hardware.bluetooth.config = {
Policy = {
AutoEnable = mkDefault cfg.powerOnBoot;
};
};
environment.systemPackages = [ bluez-bluetooth ];
environment.etc = singleton { environment.etc = singleton {
source = pkgs.writeText "main.conf" '' source = pkgs.writeText "main.conf" (generators.toINI { } cfg.config + optionalString (cfg.extraConfig != null) cfg.extraConfig);
[Policy]
AutoEnable=${lib.boolToString cfg.powerOnBoot}
${cfg.extraConfig}
'';
target = "bluetooth/main.conf"; target = "bluetooth/main.conf";
}; };

View file

@ -44,7 +44,8 @@ in
serviceConfig = { serviceConfig = {
DynamicUser = true; DynamicUser = true;
Restart = "always"; Restart = "always";
ExecStart = "${pkg}/bin/beanstalkd -l ${cfg.listen.address} -p ${toString cfg.listen.port}"; ExecStart = "${pkg}/bin/beanstalkd -l ${cfg.listen.address} -p ${toString cfg.listen.port} -b $STATE_DIRECTORY";
StateDirectory = "beanstalkd";
}; };
}; };

View file

@ -394,6 +394,28 @@ in
WorkingDirectory = cfg.stateDir; WorkingDirectory = cfg.stateDir;
ExecStart = "${gitea.bin}/bin/gitea web"; ExecStart = "${gitea.bin}/bin/gitea web";
Restart = "always"; Restart = "always";
# Filesystem
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
ReadWritePaths = cfg.stateDir;
# Caps
CapabilityBoundingSet = "";
NoNewPrivileges = true;
# Misc.
LockPersonality = true;
RestrictRealtime = true;
PrivateMounts = true;
PrivateUsers = true;
MemoryDenyWriteExecute = true;
SystemCallFilter = "~@chown @clock @cpu-emulation @debug @keyring @memlock @module @mount @obsolete @privileged @raw-io @reboot @resources @setuid @swap";
SystemCallArchitectures = "native";
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
}; };
environment = { environment = {

View file

@ -1,91 +0,0 @@
{ config, lib, pkgs, ... }:
with builtins;
with lib;
let
cfg = config.services.osquery;
in
{
options = {
services.osquery = {
enable = mkEnableOption "osquery";
loggerPath = mkOption {
type = types.path;
description = "Base directory used for logging.";
default = "/var/log/osquery";
};
pidfile = mkOption {
type = types.path;
description = "Path used for pid file.";
default = "/var/osquery/osqueryd.pidfile";
};
utc = mkOption {
type = types.bool;
description = "Attempt to convert all UNIX calendar times to UTC.";
default = true;
};
databasePath = mkOption {
type = types.path;
description = "Path used for database file.";
default = "/var/osquery/osquery.db";
};
extraConfig = mkOption {
type = types.attrs // {
merge = loc: foldl' (res: def: recursiveUpdate res def.value) {};
};
description = "Extra config to be recursively merged into the JSON config file.";
default = { };
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.osquery ];
environment.etc."osquery/osquery.conf".text = toJSON (
recursiveUpdate {
options = {
config_plugin = "filesystem";
logger_plugin = "filesystem";
logger_path = cfg.loggerPath;
database_path = cfg.databasePath;
utc = cfg.utc;
};
} cfg.extraConfig
);
systemd.services.osqueryd = {
description = "The osquery Daemon";
after = [ "network.target" "syslog.service" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.osquery ];
preStart = ''
mkdir -p ${escapeShellArg cfg.loggerPath}
mkdir -p "$(dirname ${escapeShellArg cfg.pidfile})"
mkdir -p "$(dirname ${escapeShellArg cfg.databasePath})"
'';
serviceConfig = {
TimeoutStartSec = "infinity";
ExecStart = "${pkgs.osquery}/bin/osqueryd --logger_path ${escapeShellArg cfg.loggerPath} --pidfile ${escapeShellArg cfg.pidfile} --database_path ${escapeShellArg cfg.databasePath}";
KillMode = "process";
KillSignal = "SIGTERM";
Restart = "on-failure";
};
};
};
}

View file

@ -197,6 +197,9 @@ in
services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey; services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey;
})] ++ [(mkIf config.services.rspamd.enable { })] ++ [(mkIf config.services.rspamd.enable {
services.prometheus.exporters.rspamd.url = mkDefault "http://localhost:11334/stat"; services.prometheus.exporters.rspamd.url = mkDefault "http://localhost:11334/stat";
})] ++ [(mkIf config.services.nginx.enable {
systemd.services.prometheus-nginx-exporter.after = [ "nginx.service" ];
systemd.services.prometheus-nginx-exporter.requires = [ "nginx.service" ];
})] ++ (mapAttrsToList (name: conf: })] ++ (mapAttrsToList (name: conf:
mkExporterConf { mkExporterConf {
inherit name; inherit name;

View file

@ -1,357 +0,0 @@
{ config, lib, pkgs, ...} :
with lib;
let
cfg = config.services.beegfs;
# functions for the generations of config files
configMgmtd = name: cfg: pkgs.writeText "mgmt-${name}.conf" ''
storeMgmtdDirectory = ${cfg.mgmtd.storeDir}
storeAllowFirstRunInit = false
connAuthFile = ${cfg.connAuthFile}
connPortShift = ${toString cfg.connPortShift}
${cfg.mgmtd.extraConfig}
'';
configAdmon = name: cfg: pkgs.writeText "admon-${name}.conf" ''
sysMgmtdHost = ${cfg.mgmtdHost}
connAuthFile = ${cfg.connAuthFile}
connPortShift = ${toString cfg.connPortShift}
${cfg.admon.extraConfig}
'';
configMeta = name: cfg: pkgs.writeText "meta-${name}.conf" ''
storeMetaDirectory = ${cfg.meta.storeDir}
sysMgmtdHost = ${cfg.mgmtdHost}
connAuthFile = ${cfg.connAuthFile}
connPortShift = ${toString cfg.connPortShift}
storeAllowFirstRunInit = false
${cfg.meta.extraConfig}
'';
configStorage = name: cfg: pkgs.writeText "storage-${name}.conf" ''
storeStorageDirectory = ${cfg.storage.storeDir}
sysMgmtdHost = ${cfg.mgmtdHost}
connAuthFile = ${cfg.connAuthFile}
connPortShift = ${toString cfg.connPortShift}
storeAllowFirstRunInit = false
${cfg.storage.extraConfig}
'';
configHelperd = name: cfg: pkgs.writeText "helperd-${name}.conf" ''
connAuthFile = ${cfg.connAuthFile}
${cfg.helperd.extraConfig}
'';
configClientFilename = name : "/etc/beegfs/client-${name}.conf";
configClient = name: cfg: ''
sysMgmtdHost = ${cfg.mgmtdHost}
connAuthFile = ${cfg.connAuthFile}
connPortShift = ${toString cfg.connPortShift}
${cfg.client.extraConfig}
'';
serviceList = [
{ service = "admon"; cfgFile = configAdmon; }
{ service = "meta"; cfgFile = configMeta; }
{ service = "mgmtd"; cfgFile = configMgmtd; }
{ service = "storage"; cfgFile = configStorage; }
];
# functions to generate systemd.service entries
systemdEntry = service: cfgFile: (mapAttrs' ( name: cfg:
(nameValuePair "beegfs-${service}-${name}" (mkIf cfg.${service}.enable {
wantedBy = [ "multi-user.target" ];
requires = [ "network-online.target" ];
after = [ "network-online.target" ];
serviceConfig = rec {
ExecStart = ''
${pkgs.beegfs}/bin/beegfs-${service} \
cfgFile=${cfgFile name cfg} \
pidFile=${PIDFile}
'';
PIDFile = "/run/beegfs-${service}-${name}.pid";
TimeoutStopSec = "300";
};
}))) cfg);
systemdHelperd = mapAttrs' ( name: cfg:
(nameValuePair "beegfs-helperd-${name}" (mkIf cfg.client.enable {
wantedBy = [ "multi-user.target" ];
requires = [ "network-online.target" ];
after = [ "network-online.target" ];
serviceConfig = rec {
ExecStart = ''
${pkgs.beegfs}/bin/beegfs-helperd \
cfgFile=${configHelperd name cfg} \
pidFile=${PIDFile}
'';
PIDFile = "/run/beegfs-helperd-${name}.pid";
TimeoutStopSec = "300";
};
}))) cfg;
# wrappers to beegfs tools. Avoid typing path of config files
utilWrappers = mapAttrsToList ( name: cfg:
( pkgs.runCommand "beegfs-utils-${name}" {
nativeBuildInputs = [ pkgs.makeWrapper ];
preferLocalBuild = true;
} ''
mkdir -p $out/bin
makeWrapper ${pkgs.beegfs}/bin/beegfs-check-servers \
$out/bin/beegfs-check-servers-${name} \
--add-flags "-c ${configClientFilename name}" \
--prefix PATH : ${lib.makeBinPath [ pkgs.beegfs ]}
makeWrapper ${pkgs.beegfs}/bin/beegfs-ctl \
$out/bin/beegfs-ctl-${name} \
--add-flags "--cfgFile=${configClientFilename name}"
makeWrapper ${pkgs.beegfs}/bin/beegfs-ctl \
$out/bin/beegfs-df-${name} \
--add-flags "--cfgFile=${configClientFilename name}" \
--add-flags --listtargets \
--add-flags --hidenodeid \
--add-flags --pools \
--add-flags --spaceinfo
makeWrapper ${pkgs.beegfs}/bin/beegfs-fsck \
$out/bin/beegfs-fsck-${name} \
--add-flags "--cfgFile=${configClientFilename name}"
''
)) cfg;
in
{
###### interface
options = {
services.beegfsEnable = mkEnableOption "BeeGFS";
services.beegfs = mkOption {
default = {};
description = ''
BeeGFS configurations. Every mount point requires a separate configuration.
'';
type = with types; attrsOf (submodule ({ ... } : {
options = {
mgmtdHost = mkOption {
type = types.str;
default = null;
example = "master";
description = ''Hostname of managament host.'';
};
connAuthFile = mkOption {
type = types.str;
default = "";
example = "/etc/my.key";
description = "File containing shared secret authentication.";
};
connPortShift = mkOption {
type = types.int;
default = 0;
example = 5;
description = ''
For each additional beegfs configuration shift all
service TCP/UDP ports by at least 5.
'';
};
client = {
enable = mkEnableOption "BeeGFS client";
mount = mkOption {
type = types.bool;
default = true;
description = "Create fstab entry automatically";
};
mountPoint = mkOption {
type = types.str;
default = "/run/beegfs";
description = ''
Mount point under which the beegfs filesytem should be mounted.
If mounted manually the mount option specifing the config file is needed:
cfgFile=/etc/beegfs/beegfs-client-&lt;name&gt;.conf
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines for beegfs-client.conf.
See documentation for further details.
'';
};
};
helperd = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Enable the BeeGFS helperd.
The helpered is need for logging purposes on the client.
Disabling <literal>helperd</literal> allows for runing the client
with <literal>allowUnfree = false</literal>.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines for beegfs-helperd.conf. See documentation
for further details.
'';
};
};
mgmtd = {
enable = mkEnableOption "BeeGFS mgmtd daemon";
storeDir = mkOption {
type = types.path;
default = null;
example = "/data/beegfs-mgmtd";
description = ''
Data directory for mgmtd.
Must not be shared with other beegfs daemons.
This directory must exist and it must be initialized
with beegfs-setup-mgmtd, e.g. "beegfs-setup-mgmtd -C -p &lt;storeDir&gt;"
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines for beegfs-mgmtd.conf. See documentation
for further details.
'';
};
};
admon = {
enable = mkEnableOption "BeeGFS admon daemon";
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines for beegfs-admon.conf. See documentation
for further details.
'';
};
};
meta = {
enable = mkEnableOption "BeeGFS meta data daemon";
storeDir = mkOption {
type = types.path;
default = null;
example = "/data/beegfs-meta";
description = ''
Data directory for meta data service.
Must not be shared with other beegfs daemons.
The underlying filesystem must be mounted with xattr turned on.
This directory must exist and it must be initialized
with beegfs-setup-meta, e.g.
"beegfs-setup-meta -C -s &lt;serviceID&gt; -p &lt;storeDir&gt;"
'';
};
extraConfig = mkOption {
type = types.str;
default = "";
description = ''
Additional lines for beegfs-meta.conf. See documentation
for further details.
'';
};
};
storage = {
enable = mkEnableOption "BeeGFS storage daemon";
storeDir = mkOption {
type = types.path;
default = null;
example = "/data/beegfs-storage";
description = ''
Data directories for storage service.
Must not be shared with other beegfs daemons.
The underlying filesystem must be mounted with xattr turned on.
This directory must exist and it must be initialized
with beegfs-setup-storage, e.g.
"beegfs-setup-storage -C -s &lt;serviceID&gt; -i &lt;storageTargetID&gt; -p &lt;storeDir&gt;"
'';
};
extraConfig = mkOption {
type = types.str;
default = "";
description = ''
Addional lines for beegfs-storage.conf. See documentation
for further details.
'';
};
};
};
}));
};
};
###### implementation
config =
mkIf config.services.beegfsEnable {
environment.systemPackages = utilWrappers;
# Put the client.conf files in /etc since they are needed
# by the commandline tools
environment.etc = mapAttrs' ( name: cfg:
(nameValuePair "beegfs/client-${name}.conf" (mkIf (cfg.client.enable)
{
enable = true;
text = configClient name cfg;
}))) cfg;
# Kernel module, we need it only once per host.
boot = mkIf (
foldr (a: b: a || b) false
(map (x: x.client.enable) (collect (x: x ? client) cfg)))
{
kernelModules = [ "beegfs" ];
extraModulePackages = [ pkgs.linuxPackages.beegfs-module ];
};
# generate fstab entries
fileSystems = mapAttrs' (name: cfg:
(nameValuePair cfg.client.mountPoint (optionalAttrs cfg.client.mount (mkIf cfg.client.enable {
device = "beegfs_nodev";
fsType = "beegfs";
mountPoint = cfg.client.mountPoint;
options = [ "cfgFile=${configClientFilename name}" "_netdev" ];
})))) cfg;
# generate systemd services
systemd.services = systemdHelperd //
foldr (a: b: a // b) {}
(map (x: systemdEntry x.service x.cfgFile) serviceList);
};
}

View file

@ -115,7 +115,7 @@ in
type = types.package; type = types.package;
default = pkgs.samba; default = pkgs.samba;
defaultText = "pkgs.samba"; defaultText = "pkgs.samba";
example = literalExample "pkgs.samba3"; example = literalExample "pkgs.samba4Full";
description = '' description = ''
Defines which package should be used for the samba server. Defines which package should be used for the samba server.
''; '';

View file

@ -4,7 +4,7 @@ with pkgs;
with lib; with lib;
let let
cfg = config.networking.connman; cfg = config.services.connman;
configFile = pkgs.writeText "connman.conf" '' configFile = pkgs.writeText "connman.conf" ''
[General] [General]
NetworkInterfaceBlacklist=${concatStringsSep "," cfg.networkInterfaceBlacklist} NetworkInterfaceBlacklist=${concatStringsSep "," cfg.networkInterfaceBlacklist}
@ -17,7 +17,7 @@ in {
options = { options = {
networking.connman = { services.connman = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
@ -71,13 +71,13 @@ in {
assertions = [{ assertions = [{
assertion = !config.networking.useDHCP; assertion = !config.networking.useDHCP;
message = "You can not use services.networking.connman with services.networking.useDHCP"; message = "You can not use services.connman with networking.useDHCP";
}{ }{
assertion = config.networking.wireless.enable; assertion = config.networking.wireless.enable;
message = "You must use services.networking.connman with services.networking.wireless"; message = "You must use services.connman with networking.wireless";
}{ }{
assertion = !config.networking.networkmanager.enable; assertion = !config.networking.networkmanager.enable;
message = "You can not use services.networking.connman with services.networking.networkmanager"; message = "You can not use services.connman with networking.networkmanager";
}]; }];
environment.systemPackages = [ connman ]; environment.systemPackages = [ connman ];

View file

@ -137,7 +137,7 @@ in
]; ];
services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveDNSChainQueries { services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveDNSChainQueries {
forwardZones = forwardZonesRecurse =
{ bit = "127.0.0.1:${toString cfg.dns.port}"; { bit = "127.0.0.1:${toString cfg.dns.port}";
dns = "127.0.0.1:${toString cfg.dns.port}"; dns = "127.0.0.1:${toString cfg.dns.port}";
}; };

View file

@ -90,11 +90,19 @@ in {
}; };
forwardZones = mkOption { forwardZones = mkOption {
type = types.attrs;
default = {};
description = ''
DNS zones to be forwarded to other authoritative servers.
'';
};
forwardZonesRecurse = mkOption {
type = types.attrs; type = types.attrs;
example = { eth = "127.0.0.1:5353"; }; example = { eth = "127.0.0.1:5353"; };
default = {}; default = {};
description = '' description = ''
DNS zones to be forwarded to other servers. DNS zones to be forwarded to other recursive servers.
''; '';
}; };
@ -158,7 +166,8 @@ in {
webserver-port = cfg.api.port; webserver-port = cfg.api.port;
webserver-allow-from = cfg.api.allowFrom; webserver-allow-from = cfg.api.allowFrom;
forward-zones = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZones; forward-zones = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZones;
forward-zones-recurse = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZonesRecurse;
export-etc-hosts = cfg.exportHosts; export-etc-hosts = cfg.exportHosts;
dnssec = cfg.dnssecValidation; dnssec = cfg.dnssecValidation;
serve-rfc1918 = cfg.serveRFC1918; serve-rfc1918 = cfg.serveRFC1918;

View file

@ -236,9 +236,12 @@ in {
${if ifaces == [] then '' ${if ifaces == [] then ''
for i in $(cd /sys/class/net && echo *); do for i in $(cd /sys/class/net && echo *); do
DEVTYPE= DEVTYPE=
source /sys/class/net/$i/uevent UEVENT_PATH=/sys/class/net/$i/uevent
if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then if [ -e "$UEVENT_PATH" ]; then
ifaces="$ifaces''${ifaces:+ -N} -i$i" source "$UEVENT_PATH"
if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then
ifaces="$ifaces''${ifaces:+ -N} -i$i"
fi
fi fi
done done
'' else '' '' else ''

View file

@ -239,7 +239,7 @@ in
services.znc = { services.znc = {
configFile = mkDefault (pkgs.writeText "znc-generated.conf" semanticString); configFile = mkDefault (pkgs.writeText "znc-generated.conf" semanticString);
config = { config = {
Version = (builtins.parseDrvName pkgs.znc.name).version; Version = lib.getVersion pkgs.znc;
Listener.l.Port = mkDefault 5000; Listener.l.Port = mkDefault 5000;
Listener.l.SSL = mkDefault true; Listener.l.SSL = mkDefault true;
}; };

View file

@ -84,12 +84,6 @@ GRANT ALL PRIVILEGES ON matomo.* TO 'matomo'@'localhost';
<title>Issues</title> <title>Issues</title>
<itemizedlist> <itemizedlist>
<listitem>
<para>
Matomo's file integrity check will warn you. This is due to the patches
necessary for NixOS, you can safely ignore this.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
Matomo will warn you that the JavaScript tracker is not writable. This is Matomo will warn you that the JavaScript tracker is not writable. This is

View file

@ -390,6 +390,7 @@ in {
in { in {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
before = [ "phpfpm-nextcloud.service" ]; before = [ "phpfpm-nextcloud.service" ];
path = [ occ ];
script = '' script = ''
chmod og+x ${cfg.home} chmod og+x ${cfg.home}
ln -sf ${pkgs.nextcloud}/apps ${cfg.home}/ ln -sf ${pkgs.nextcloud}/apps ${cfg.home}/

View file

@ -262,6 +262,7 @@ in {
in { in {
Slice = "phpfpm.slice"; Slice = "phpfpm.slice";
PrivateDevices = true; PrivateDevices = true;
PrivateTmp = true;
ProtectSystem = "full"; ProtectSystem = "full";
ProtectHome = true; ProtectHome = true;
# XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work

View file

@ -27,20 +27,13 @@ in
example = "vlc"; example = "vlc";
description = "Phonon audio backend to install."; description = "Phonon audio backend to install.";
}; };
enableQt4Support = mkOption {
type = types.bool;
default = true;
description = ''
Enable support for Qt 4-based applications. Particularly, install a
default backend for Phonon.
'';
};
}; };
}; };
imports = [
(mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "enableQt4Support" ] "Phonon no longer supports Qt 4.")
];
config = mkMerge [ config = mkMerge [
(mkIf cfg.enable { (mkIf cfg.enable {
@ -173,12 +166,10 @@ in
# Phonon audio backend # Phonon audio backend
++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer ++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer
++ lib.optional (cfg.phononBackend == "gstreamer" && cfg.enableQt4Support) pkgs.phonon-backend-gstreamer
++ lib.optional (cfg.phononBackend == "vlc") libsForQt5.phonon-backend-vlc ++ lib.optional (cfg.phononBackend == "vlc") libsForQt5.phonon-backend-vlc
++ lib.optional (cfg.phononBackend == "vlc" && cfg.enableQt4Support) pkgs.phonon-backend-vlc
# Optional hardware support features # Optional hardware support features
++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt ] ++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt openobex obexftp ]
++ lib.optional config.networking.networkmanager.enable plasma-nm ++ lib.optional config.networking.networkmanager.enable plasma-nm
++ lib.optional config.hardware.pulseaudio.enable plasma-pa ++ lib.optional config.hardware.pulseaudio.enable plasma-pa
++ lib.optional config.powerManagement.enable powerdevil ++ lib.optional config.powerManagement.enable powerdevil

View file

@ -31,6 +31,44 @@ let
load-module module-position-event-sounds load-module module-position-event-sounds
''; '';
dmDefault = config.services.xserver.desktopManager.default;
wmDefault = config.services.xserver.windowManager.default;
hasDefaultUserSession = dmDefault != "none" || wmDefault != "none";
defaultSessionName = dmDefault + optionalString (wmDefault != "none") ("+" + wmDefault);
setSessionScript = pkgs.python3.pkgs.buildPythonApplication {
name = "set-session";
format = "other";
src = ./set-session.py;
dontUnpack = true;
strictDeps = false;
nativeBuildInputs = with pkgs; [
wrapGAppsHook
gobject-introspection
];
buildInputs = with pkgs; [
accountsservice
glib
];
propagatedBuildInputs = with pkgs.python3.pkgs; [
pygobject3
ordered-set
];
installPhase = ''
mkdir -p $out/bin
cp $src $out/bin/set-session
chmod +x $out/bin/set-session
'';
};
in in
{ {
@ -88,11 +126,21 @@ in
wayland = mkOption { wayland = mkOption {
default = true; default = true;
description = '' description = ''
Allow GDM run on Wayland instead of Xserver Allow GDM to run on Wayland instead of Xserver.
Note to enable Wayland with Nvidia you need to
enable the <option>nvidiaWayland</option>.
''; '';
type = types.bool; type = types.bool;
}; };
nvidiaWayland = mkOption {
default = false;
description = ''
Whether to allow wayland to be used with the proprietary
NVidia graphics driver.
'';
};
autoSuspend = mkOption { autoSuspend = mkOption {
default = true; default = true;
description = '' description = ''
@ -156,6 +204,8 @@ in
cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF
yes yes
EOF EOF
'' + optionalString hasDefaultUserSession ''
${setSessionScript}/bin/set-session ${defaultSessionName}
''; '';
}; };
@ -197,6 +247,19 @@ in
services.dbus.packages = [ gdm ]; services.dbus.packages = [ gdm ];
# We duplicate upstream's udev rules manually to make wayland with nvidia configurable
services.udev.extraRules = ''
# disable Wayland on Cirrus chipsets
ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", RUN+="${gdm}/libexec/gdm-disable-wayland"
# disable Wayland on Hi1710 chipsets
ATTR{vendor}=="0x19e5", ATTR{device}=="0x1711", RUN+="${gdm}/libexec/gdm-disable-wayland"
${optionalString (!cfg.gdm.nvidiaWayland) ''
DRIVER=="nvidia", RUN+="${gdm}/libexec/gdm-disable-wayland"
''}
# disable Wayland when modesetting is disabled
IMPORT{cmdline}="nomodeset", RUN+="${gdm}/libexec/gdm-disable-wayland"
'';
systemd.user.services.dbus.wantedBy = [ "default.target" ]; systemd.user.services.dbus.wantedBy = [ "default.target" ];
programs.dconf.profiles.gdm = programs.dconf.profiles.gdm =
@ -218,7 +281,7 @@ in
customDconfDb = pkgs.stdenv.mkDerivation { customDconfDb = pkgs.stdenv.mkDerivation {
name = "gdm-dconf-db"; name = "gdm-dconf-db";
buildCommand = '' buildCommand = ''
${pkgs.gnome3.dconf}/bin/dconf compile $out ${customDconf}/dconf ${pkgs.dconf}/bin/dconf compile $out ${customDconf}/dconf
''; '';
}; };
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {

View file

@ -0,0 +1,86 @@
#!/usr/bin/env python
import gi, argparse, os, logging, sys
gi.require_version("AccountsService", "1.0")
from gi.repository import AccountsService, GLib
from ordered_set import OrderedSet
def get_session_file(session):
system_data_dirs = GLib.get_system_data_dirs()
session_dirs = OrderedSet(
os.path.join(data_dir, session)
for data_dir in system_data_dirs
for session in {"wayland-sessions", "xsessions"}
)
session_files = OrderedSet(
os.path.join(dir, session + ".desktop")
for dir in session_dirs
if os.path.exists(os.path.join(dir, session + ".desktop"))
)
# Deal with duplicate wayland-sessions and xsessions.
# Needed for the situation in gnome-session, where there's
# a xsession named the same as a wayland session.
if any(map(is_session_wayland, session_files)):
session_files = OrderedSet(
session for session in session_files if is_session_wayland(session)
)
else:
session_files = OrderedSet(
session for session in session_files if is_session_xsession(session)
)
if len(session_files) == 0:
logging.warning("No session files are found.")
sys.exit(0)
else:
return session_files[0]
def is_session_xsession(session_file):
return "/xsessions/" in session_file
def is_session_wayland(session_file):
return "/wayland-sessions/" in session_file
def main():
parser = argparse.ArgumentParser(
description="Set session type for all normal users."
)
parser.add_argument("session", help="Name of session to set.")
args = parser.parse_args()
session = getattr(args, "session")
session_file = get_session_file(session)
user_manager = AccountsService.UserManager.get_default()
users = user_manager.list_users()
for user in users:
if user.is_system_account():
continue
else:
if is_session_wayland(session_file):
logging.debug(
f"Setting session name: {session}, as we found the existing wayland-session: {session_file}"
)
user.set_session(session)
elif is_session_xsession(session_file):
logging.debug(
f"Setting session name: {session}, as we found the existing xsession: {session_file}"
)
user.set_x_session(session)
else:
logging.error(f"Couldn't figure out session type for {session_file}")
sys.exit(1)
if __name__ == "__main__":
main()

View file

@ -47,8 +47,8 @@ let
grub = f grub; grub = f grub;
grubTarget = f (grub.grubTarget or ""); grubTarget = f (grub.grubTarget or "");
shell = "${pkgs.runtimeShell}"; shell = "${pkgs.runtimeShell}";
fullName = (builtins.parseDrvName realGrub.name).name; fullName = lib.getName realGrub;
fullVersion = (builtins.parseDrvName realGrub.name).version; fullVersion = lib.getVersion realGrub;
grubEfi = f grubEfi; grubEfi = f grubEfi;
grubTargetEfi = if cfg.efiSupport && (cfg.version == 2) then f (grubEfi.grubTarget or "") else ""; grubTargetEfi = if cfg.efiSupport && (cfg.version == 2) then f (grubEfi.grubTarget or "") else "";
bootPath = args.path; bootPath = args.path;

View file

@ -201,7 +201,7 @@ let
(assertValueOneOf "IPv6AcceptRA" boolValues) (assertValueOneOf "IPv6AcceptRA" boolValues)
(assertValueOneOf "IPv4ProxyARP" boolValues) (assertValueOneOf "IPv4ProxyARP" boolValues)
(assertValueOneOf "IPv6ProxyNDP" boolValues) (assertValueOneOf "IPv6ProxyNDP" boolValues)
(assertValueOneOf "IPv6PrefixDelegation" boolValues) (assertValueOneOf "IPv6PrefixDelegation" (boolValues ++ [ "dhcpv6" "static" ]))
(assertValueOneOf "ActiveSlave" boolValues) (assertValueOneOf "ActiveSlave" boolValues)
(assertValueOneOf "PrimarySlave" boolValues) (assertValueOneOf "PrimarySlave" boolValues)
(assertValueOneOf "ConfigureWithoutCarrier" boolValues) (assertValueOneOf "ConfigureWithoutCarrier" boolValues)
@ -924,6 +924,8 @@ in
config = mkIf config.systemd.network.enable { config = mkIf config.systemd.network.enable {
users.users.systemd-network.group = "systemd-network";
systemd.additionalUpstreamSystemUnits = [ systemd.additionalUpstreamSystemUnits = [
"systemd-networkd.service" "systemd-networkd-wait-online.service" "systemd-networkd.service" "systemd-networkd-wait-online.service"
]; ];

View file

@ -136,6 +136,8 @@ in
} }
]; ];
users.users.resolved.group = "systemd-resolve";
systemd.additionalUpstreamSystemUnits = [ systemd.additionalUpstreamSystemUnits = [
"systemd-resolved.service" "systemd-resolved.service"
]; ];

View file

@ -50,7 +50,10 @@ with lib;
${config.services.timesyncd.extraConfig} ${config.services.timesyncd.extraConfig}
''; '';
users.users.systemd-timesync.uid = config.ids.uids.systemd-timesync; users.users.systemd-timesync = {
uid = config.ids.uids.systemd-timesync;
group = "systemd-timesync";
};
users.groups.systemd-timesync.gid = config.ids.gids.systemd-timesync; users.groups.systemd-timesync.gid = config.ids.gids.systemd-timesync;
system.activationScripts.systemd-timesyncd-migration = mkIf (versionOlder config.system.stateVersion "19.09") '' system.activationScripts.systemd-timesyncd-migration = mkIf (versionOlder config.system.stateVersion "19.09") ''

View file

@ -149,7 +149,7 @@ let
--setenv PATH="$PATH" \ --setenv PATH="$PATH" \
${optionalString cfg.ephemeral "--ephemeral"} \ ${optionalString cfg.ephemeral "--ephemeral"} \
${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then ${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then
''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else "" ''--capability="${concatStringsSep "," cfg.additionalCapabilities}"'' else ""
} \ } \
${if cfg.tmpfs != null && cfg.tmpfs != [] then ${if cfg.tmpfs != null && cfg.tmpfs != [] then
''--tmpfs=${concatStringsSep " --tmpfs=" cfg.tmpfs}'' else "" ''--tmpfs=${concatStringsSep " --tmpfs=" cfg.tmpfs}'' else ""

View file

@ -0,0 +1,197 @@
{ config, pkgs, lib, modulesPath, ... }:
with lib;
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
(modulesPath + "/virtualisation/digital-ocean-init.nix")
];
options.virtualisation.digitalOcean = with types; {
setRootPassword = mkOption {
type = bool;
default = false;
example = true;
description = "Whether to set the root password from the Digital Ocean metadata";
};
setSshKeys = mkOption {
type = bool;
default = true;
example = true;
description = "Whether to fetch ssh keys from Digital Ocean";
};
seedEntropy = mkOption {
type = bool;
default = true;
example = true;
description = "Whether to run the kernel RNG entropy seeding script from the Digital Ocean vendor data";
};
};
config =
let
cfg = config.virtualisation.digitalOcean;
hostName = config.networking.hostName;
doMetadataFile = "/run/do-metadata/v1.json";
in mkMerge [{
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
autoResize = true;
fsType = "ext4";
};
boot = {
growPartition = true;
kernelParams = [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ];
initrd.kernelModules = [ "virtio_scsi" ];
kernelModules = [ "virtio_pci" "virtio_net" ];
loader = {
grub.device = "/dev/vda";
timeout = 0;
grub.configurationLimit = 0;
};
};
services.openssh = {
enable = mkDefault true;
passwordAuthentication = mkDefault false;
};
services.do-agent.enable = mkDefault true;
networking = {
hostName = mkDefault ""; # use Digital Ocean metadata server
};
/* Check for and wait for the metadata server to become reachable.
* This serves as a dependency for all the other metadata services. */
systemd.services.digitalocean-metadata = {
path = [ pkgs.curl ];
description = "Get host metadata provided by Digitalocean";
script = ''
set -eu
DO_DELAY_ATTEMPTS=0
while ! curl -fsSL -o $RUNTIME_DIRECTORY/v1.json http://169.254.169.254/metadata/v1.json; do
DO_DELAY_ATTEMPTS=$((DO_DELAY_ATTEMPTS + 1))
if (( $DO_DELAY_ATTEMPTS >= $DO_DELAY_ATTEMPTS_MAX )); then
echo "giving up"
exit 1
fi
echo "metadata unavailable, trying again in 1s..."
sleep 1
done
chmod 600 $RUNTIME_DIRECTORY/v1.json
'';
environment = {
DO_DELAY_ATTEMPTS_MAX = "10";
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
RuntimeDirectory = "do-metadata";
RuntimeDirectoryPreserve = "yes";
};
unitConfig = {
ConditionPathExists = "!${doMetadataFile}";
After = [ "network-pre.target" ] ++
optional config.networking.dhcpcd.enable "dhcpcd.service" ++
optional config.systemd.network.enable "systemd-networkd.service";
};
};
/* Fetch the root password from the digital ocean metadata.
* There is no specific route for this, so we use jq to get
* it from the One Big JSON metadata blob */
systemd.services.digitalocean-set-root-password = mkIf cfg.setRootPassword {
path = [ pkgs.shadow pkgs.jq ];
description = "Set root password provided by Digitalocean";
wantedBy = [ "multi-user.target" ];
script = ''
set -eo pipefail
ROOT_PASSWORD=$(jq -er '.auth_key' ${doMetadataFile})
echo "root:$ROOT_PASSWORD" | chpasswd
mkdir -p /etc/do-metadata/set-root-password
'';
unitConfig = {
ConditionPathExists = "!/etc/do-metadata/set-root-password";
Before = optional config.services.openssh.enable "sshd.service";
After = [ "digitalocean-metadata.service" ];
Requires = [ "digitalocean-metadata.service" ];
};
serviceConfig = {
Type = "oneshot";
};
};
/* Set the hostname from Digital Ocean, unless the user configured it in
* the NixOS configuration. The cached metadata file isn't used here
* because the hostname is a mutable part of the droplet. */
systemd.services.digitalocean-set-hostname = mkIf (hostName == "") {
path = [ pkgs.curl pkgs.nettools ];
description = "Set hostname provided by Digitalocean";
wantedBy = [ "network.target" ];
script = ''
set -e
DIGITALOCEAN_HOSTNAME=$(curl -fsSL http://169.254.169.254/metadata/v1/hostname)
hostname "$DIGITALOCEAN_HOSTNAME"
if [[ ! -e /etc/hostname || -w /etc/hostname ]]; then
printf "%s\n" "$DIGITALOCEAN_HOSTNAME" > /etc/hostname
fi
'';
unitConfig = {
Before = [ "network.target" ];
After = [ "digitalocean-metadata.service" ];
Wants = [ "digitalocean-metadata.service" ];
};
serviceConfig = {
Type = "oneshot";
};
};
/* Fetch the ssh keys for root from Digital Ocean */
systemd.services.digitalocean-ssh-keys = mkIf cfg.setSshKeys {
description = "Set root ssh keys provided by Digital Ocean";
wantedBy = [ "multi-user.target" ];
path = [ pkgs.jq ];
script = ''
set -e
mkdir -m 0700 -p /root/.ssh
jq -er '.public_keys[]' ${doMetadataFile} > /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
unitConfig = {
ConditionPathExists = "!/root/.ssh/authorized_keys";
Before = optional config.services.openssh.enable "sshd.service";
After = [ "digitalocean-metadata.service" ];
Requires = [ "digitalocean-metadata.service" ];
};
};
/* Initialize the RNG by running the entropy-seed script from the
* Digital Ocean metadata
*/
systemd.services.digitalocean-entropy-seed = mkIf cfg.seedEntropy {
description = "Run the kernel RNG entropy seeding script from the Digital Ocean vendor data";
wantedBy = [ "network.target" ];
path = [ pkgs.jq pkgs.mpack ];
script = ''
set -eo pipefail
TEMPDIR=$(mktemp -d)
jq -er '.vendor_data' ${doMetadataFile} | munpack -tC $TEMPDIR
ENTROPY_SEED=$(grep -rl "DigitalOcean Entropy Seed script" $TEMPDIR)
${pkgs.runtimeShell} $ENTROPY_SEED
rm -rf $TEMPDIR
'';
unitConfig = {
Before = [ "network.target" ];
After = [ "digitalocean-metadata.service" ];
Requires = [ "digitalocean-metadata.service" ];
};
serviceConfig = {
Type = "oneshot";
};
};
}
];
meta.maintainers = with maintainers; [ arianvp eamsden ];
}

View file

@ -0,0 +1,69 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.virtualisation.digitalOceanImage;
in
{
imports = [ ./digital-ocean-config.nix ];
options = {
virtualisation.digitalOceanImage.diskSize = mkOption {
type = with types; int;
default = 4096;
description = ''
Size of disk image. Unit is MB.
'';
};
virtualisation.digitalOceanImage.configFile = mkOption {
type = with types; nullOr path;
default = null;
description = ''
A path to a configuration file which will be placed at
<literal>/etc/nixos/configuration.nix</literal> and be used when switching
to a new configuration. If set to <literal>null</literal>, a default
configuration is used that imports
<literal>(modulesPath + "/virtualisation/digital-ocean-config.nix")</literal>.
'';
};
virtualisation.digitalOceanImage.compressionMethod = mkOption {
type = types.enum [ "gzip" "bzip2" ];
default = "gzip";
example = "bzip2";
description = ''
Disk image compression method. Choose bzip2 to generate smaller images that
take longer to generate but will consume less metered storage space on your
Digital Ocean account.
'';
};
};
#### implementation
config = {
system.build.digitalOceanImage = import ../../lib/make-disk-image.nix {
name = "digital-ocean-image";
format = "qcow2";
postVM = let
compress = {
"gzip" = "${pkgs.gzip}/bin/gzip";
"bzip2" = "${pkgs.bzip2}/bin/bzip2";
}.${cfg.compressionMethod};
in ''
${compress} $diskImage
'';
configFile = if cfg.configFile == null
then config.virtualisation.digitalOcean.defaultConfigFile
else cfg.configFile;
inherit (cfg) diskSize;
inherit config lib pkgs;
};
};
meta.maintainers = with maintainers; [ arianvp eamsden ];
}

View file

@ -0,0 +1,95 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.virtualisation.digitalOcean;
defaultConfigFile = pkgs.writeText "digitalocean-configuration.nix" ''
{ modulesPath, lib, ... }:
{
imports = lib.optional (builtins.pathExists ./do-userdata.nix) ./do-userdata.nix ++ [
(modulesPath + "/virtualisation/digital-ocean-config.nix")
];
}
'';
in {
options.virtualisation.digitalOcean.rebuildFromUserData = mkOption {
type = types.bool;
default = true;
example = true;
description = "Whether to reconfigure the system from Digital Ocean user data";
};
options.virtualisation.digitalOcean.defaultConfigFile = mkOption {
type = types.path;
default = defaultConfigFile;
defaultText = ''
The default configuration imports user-data if applicable and
<literal>(modulesPath + "/virtualisation/digital-ocean-config.nix")</literal>.
'';
description = ''
A path to a configuration file which will be placed at
<literal>/etc/nixos/configuration.nix</literal> and be used when switching to
a new configuration.
'';
};
config = {
systemd.services.digitalocean-init = mkIf cfg.rebuildFromUserData {
description = "Reconfigure the system from Digital Ocean userdata on startup";
wantedBy = [ "network-online.target" ];
unitConfig = {
ConditionPathExists = "!/etc/nixos/do-userdata.nix";
After = [ "digitalocean-metadata.service" "network-online.target" ];
Requires = [ "digitalocean-metadata.service" ];
X-StopOnRemoval = false;
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
restartIfChanged = false;
path = [ pkgs.jq pkgs.gnused pkgs.gnugrep pkgs.systemd config.nix.package config.system.build.nixos-rebuild ];
environment = {
HOME = "/root";
NIX_PATH = concatStringsSep ":" [
"/nix/var/nix/profiles/per-user/root/channels/nixos"
"nixos-config=/etc/nixos/configuration.nix"
"/nix/var/nix/profiles/per-user/root/channels"
];
};
script = ''
set -e
echo "attempting to fetch configuration from Digital Ocean user data..."
userData=$(mktemp)
if jq -er '.user_data' /run/do-metadata/v1.json > $userData; then
# If the user-data looks like it could be a nix expression,
# copy it over. Also, look for a magic three-hash comment and set
# that as the channel.
if nix-instantiate --parse $userData > /dev/null; then
channels="$(grep '^###' "$userData" | sed 's|###\s*||')"
printf "%s" "$channels" | while read channel; do
echo "writing channel: $channel"
done
if [[ -n "$channels" ]]; then
printf "%s" "$channels" > /root/.nix-channels
nix-channel --update
fi
echo "setting configuration from Digital Ocean user data"
cp "$userData" /etc/nixos/do-userdata.nix
if [[ ! -e /etc/nixos/configuration.nix ]]; then
install -m0644 ${cfg.defaultConfigFile} /etc/nixos/configuration.nix
fi
else
echo "user data does not appear to be a Nix expression; ignoring"
exit
fi
nixos-rebuild switch
else
echo "no user data is available"
fi
'';
};
};
meta.maintainers = with maintainers; [ arianvp eamsden ];
}

View file

@ -42,6 +42,9 @@ in {
default = false; default = false;
description = '' description = ''
Whether to start racoon service for openvswitch. Whether to start racoon service for openvswitch.
Supported only if openvswitch version is less than 2.6.0.
Use <literal>virtualisation.vswitch.package = pkgs.openvswitch-lts</literal>
for a version that supports ipsec over GRE.
''; '';
}; };
}; };
@ -89,6 +92,13 @@ in {
"${cfg.package}/share/openvswitch/vswitch.ovsschema" "${cfg.package}/share/openvswitch/vswitch.ovsschema"
fi fi
chmod -R +w /var/db/openvswitch chmod -R +w /var/db/openvswitch
if ${cfg.package}/bin/ovsdb-tool needs-conversion /var/db/openvswitch/conf.db | grep -q "yes"
then
echo "Performing database upgrade"
${cfg.package}/bin/ovsdb-tool convert /var/db/openvswitch/conf.db
else
echo "Database already up to date"
fi
''; '';
serviceConfig = { serviceConfig = {
ExecStart = ExecStart =
@ -133,7 +143,7 @@ in {
}; };
} }
(mkIf cfg.ipsec { (mkIf (cfg.ipsec && (versionOlder cfg.package.version "2.6.0")) {
services.racoon.enable = true; services.racoon.enable = true;
services.racoon.configPath = "${runDir}/ipsec/etc/racoon/racoon.conf"; services.racoon.configPath = "${runDir}/ipsec/etc/racoon/racoon.conf";
@ -172,5 +182,4 @@ in {
''; '';
}; };
})])); })]));
} }

View file

@ -620,7 +620,7 @@ in
# Wireless won't work in the VM. # Wireless won't work in the VM.
networking.wireless.enable = mkVMOverride false; networking.wireless.enable = mkVMOverride false;
networking.connman.enable = mkVMOverride false; services.connman.enable = mkVMOverride false;
# Speed up booting by not waiting for ARP. # Speed up booting by not waiting for ARP.
networking.dhcpcd.extraConfig = "noarp"; networking.dhcpcd.extraConfig = "noarp";

View file

@ -63,8 +63,7 @@ in rec {
#(all nixos.tests.containers) #(all nixos.tests.containers)
(all nixos.tests.containers-imperative) (all nixos.tests.containers-imperative)
(all nixos.tests.containers-ipv4) (all nixos.tests.containers-ip)
(all nixos.tests.containers-ipv6)
nixos.tests.chromium.x86_64-linux or [] nixos.tests.chromium.x86_64-linux or []
(all nixos.tests.firefox) (all nixos.tests.firefox)
(all nixos.tests.firewall) (all nixos.tests.firewall)

View file

@ -32,8 +32,7 @@ in rec {
tests = { tests = {
inherit (nixos'.tests) inherit (nixos'.tests)
containers-imperative containers-imperative
containers-ipv4 containers-ip
containers-ipv6
firewall firewall
ipv6 ipv6
login login

View file

@ -28,7 +28,7 @@ in
babeld = handleTest ./babeld.nix {}; babeld = handleTest ./babeld.nix {};
bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64 bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64
beanstalkd = handleTest ./beanstalkd.nix {}; beanstalkd = handleTest ./beanstalkd.nix {};
beegfs = handleTestOn ["x86_64-linux"] ./beegfs.nix {}; # beegfs is unsupported on aarch64 bees = handleTest ./bees.nix {};
bind = handleTest ./bind.nix {}; bind = handleTest ./bind.nix {};
bittorrent = handleTest ./bittorrent.nix {}; bittorrent = handleTest ./bittorrent.nix {};
#blivet = handleTest ./blivet.nix {}; # broken since 2017-07024 #blivet = handleTest ./blivet.nix {}; # broken since 2017-07024
@ -53,8 +53,7 @@ in
containers-extra_veth = handleTest ./containers-extra_veth.nix {}; containers-extra_veth = handleTest ./containers-extra_veth.nix {};
containers-hosts = handleTest ./containers-hosts.nix {}; containers-hosts = handleTest ./containers-hosts.nix {};
containers-imperative = handleTest ./containers-imperative.nix {}; containers-imperative = handleTest ./containers-imperative.nix {};
containers-ipv4 = handleTest ./containers-ipv4.nix {}; containers-ip = handleTest ./containers-ip.nix {};
containers-ipv6 = handleTest ./containers-ipv6.nix {};
containers-macvlans = handleTest ./containers-macvlans.nix {}; containers-macvlans = handleTest ./containers-macvlans.nix {};
containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {}; containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {};
containers-restart_networking = handleTest ./containers-restart_networking.nix {}; containers-restart_networking = handleTest ./containers-restart_networking.nix {};
@ -206,7 +205,6 @@ in
openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {}; openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
orangefs = handleTest ./orangefs.nix {}; orangefs = handleTest ./orangefs.nix {};
os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {}; os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
osquery = handleTest ./osquery.nix {};
osrm-backend = handleTest ./osrm-backend.nix {}; osrm-backend = handleTest ./osrm-backend.nix {};
overlayfs = handleTest ./overlayfs.nix {}; overlayfs = handleTest ./overlayfs.nix {};
packagekit = handleTest ./packagekit.nix {}; packagekit = handleTest ./packagekit.nix {};

View file

@ -1,115 +0,0 @@
import ./make-test.nix ({ ... } :
let
connAuthFile="beegfs/auth-def.key";
client = { pkgs, ... } : {
networking.firewall.enable = false;
services.beegfsEnable = true;
services.beegfs.default = {
mgmtdHost = "mgmt";
connAuthFile = "/etc/${connAuthFile}";
client = {
mount = false;
enable = true;
};
};
fileSystems = pkgs.lib.mkVMOverride # FIXME: this should be creatd by the module
[ { mountPoint = "/beegfs";
device = "default";
fsType = "beegfs";
options = [ "cfgFile=/etc/beegfs/client-default.conf" "_netdev" ];
}
];
environment.etc.${connAuthFile} = {
enable = true;
text = "ThisIsALousySecret";
mode = "0600";
};
};
server = service : { pkgs, ... } : {
networking.firewall.enable = false;
boot.initrd.postDeviceCommands = ''
${pkgs.e2fsprogs}/bin/mkfs.ext4 -L data /dev/vdb
'';
virtualisation.emptyDiskImages = [ 4096 ];
fileSystems = pkgs.lib.mkVMOverride
[ { mountPoint = "/data";
device = "/dev/disk/by-label/data";
fsType = "ext4";
}
];
environment.systemPackages = with pkgs; [ beegfs ];
environment.etc.${connAuthFile} = {
enable = true;
text = "ThisIsALousySecret";
mode = "0600";
};
services.beegfsEnable = true;
services.beegfs.default = {
mgmtdHost = "mgmt";
connAuthFile = "/etc/${connAuthFile}";
${service} = {
enable = true;
storeDir = "/data";
};
};
};
in
{
name = "beegfs";
nodes = {
meta = server "meta";
mgmt = server "mgmtd";
storage1 = server "storage";
storage2 = server "storage";
client1 = client;
client2 = client;
};
testScript = ''
# Initalize the data directories
$mgmt->waitForUnit("default.target");
$mgmt->succeed("beegfs-setup-mgmtd -C -f -p /data");
$mgmt->succeed("systemctl start beegfs-mgmtd-default");
$meta->waitForUnit("default.target");
$meta->succeed("beegfs-setup-meta -C -f -s 1 -p /data");
$meta->succeed("systemctl start beegfs-meta-default");
$storage1->waitForUnit("default.target");
$storage1->succeed("beegfs-setup-storage -C -f -s 1 -i 1 -p /data");
$storage1->succeed("systemctl start beegfs-storage-default");
$storage2->waitForUnit("default.target");
$storage2->succeed("beegfs-setup-storage -C -f -s 2 -i 2 -p /data");
$storage2->succeed("systemctl start beegfs-storage-default");
#
# Basic test
$client1->waitForUnit("beegfs.mount");
$client1->succeed("beegfs-check-servers-default");
$client1->succeed("echo test > /beegfs/test");
$client2->waitForUnit("beegfs.mount");
$client2->succeed("test -e /beegfs/test");
$client2->succeed("cat /beegfs/test | grep test");
# test raid0/stripping
$client1->succeed("dd if=/dev/urandom bs=1M count=10 of=/beegfs/striped");
$client2->succeed("cat /beegfs/striped > /dev/null");
# check if fs is still healthy
$client1->succeed("beegfs-fsck-default --checkfs");
'';
})

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ lib, ... }: import ./make-test-python.nix ({ lib, pkgs, ... }:
{ {
name = "bees"; name = "bees";
@ -29,27 +29,34 @@ import ./make-test.nix ({ lib, ... }:
testScript = testScript =
let let
withRetry = content: maxTests: sleepTime: '' someContentIsShared = loc: pkgs.writeShellScript "some-content-is-shared" ''
max_tests=${lib.escapeShellArg maxTests}; sleep_time=${lib.escapeShellArg sleepTime}; for ((i=0; i<max_tests; i++)); do ${content} && exit 0; sleep "$sleep_time"; done; exit 1; [[ $(btrfs fi du -s --raw ${lib.escapeShellArg loc}/dedup-me-{1,2} | awk 'BEGIN { count=0; } NR>1 && $3 == 0 { count++ } END { print count }') -eq 0 ]]
''; '';
someContentIsShared = loc: ''[[ $(btrfs fi du -s --raw ${lib.escapeShellArg loc}/dedup-me-{1,2} | awk 'BEGIN { count=0; } NR>1 && $3 == 0 { count++ } END { print count }') -eq 0 ]]'';
in '' in ''
# shut down the instance started by systemd at boot, so we can test our test procedure # shut down the instance started by systemd at boot, so we can test our test procedure
$machine->succeed("systemctl stop beesd\@aux1.service"); machine.succeed("systemctl stop beesd@aux1.service")
$machine->succeed("dd if=/dev/urandom of=/aux1/dedup-me-1 bs=1M count=8"); machine.succeed(
$machine->succeed("cp --reflink=never /aux1/dedup-me-1 /aux1/dedup-me-2"); "dd if=/dev/urandom of=/aux1/dedup-me-1 bs=1M count=8",
$machine->succeed("cp --reflink=never /aux1/* /aux2/"); "cp --reflink=never /aux1/dedup-me-1 /aux1/dedup-me-2",
$machine->succeed("sync"); "cp --reflink=never /aux1/* /aux2/",
$machine->fail(q(${someContentIsShared "/aux1"})); "sync",
$machine->fail(q(${someContentIsShared "/aux2"})); )
$machine->succeed("systemctl start beesd\@aux1.service"); machine.fail(
"${someContentIsShared "/aux1"}",
"${someContentIsShared "/aux2"}",
)
machine.succeed("systemctl start beesd@aux1.service")
# assert that "Set Shared" column is nonzero # assert that "Set Shared" column is nonzero
$machine->succeed(q(${withRetry (someContentIsShared "/aux1") 20 2})); machine.wait_until_succeeds(
$machine->fail(q(${someContentIsShared "/aux2"})); "${someContentIsShared "/aux1"}",
)
machine.fail("${someContentIsShared "/aux2"}")
# assert that 16MB hash table size requested was honored # assert that 16MB hash table size requested was honored
$machine->succeed(q([[ $(stat -c %s /aux1/.beeshome/beeshash.dat) = $(( 16 * 1024 * 1024)) ]])) machine.succeed(
"[[ $(stat -c %s /aux1/.beeshome/beeshash.dat) = $(( 16 * 1024 * 1024)) ]]"
)
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... }: { import ./make-test-python.nix ({ pkgs, ... }: {
name = "clickhouse"; name = "clickhouse";
meta.maintainers = with pkgs.stdenv.lib.maintainers; [ ma27 ]; meta.maintainers = with pkgs.stdenv.lib.maintainers; [ ma27 ];
@ -14,12 +14,18 @@ import ./make-test.nix ({ pkgs, ... }: {
selectQuery = pkgs.writeText "select.sql" "SELECT * from `demo`"; selectQuery = pkgs.writeText "select.sql" "SELECT * from `demo`";
in in
'' ''
$machine->start(); machine.start()
$machine->waitForUnit("clickhouse.service"); machine.wait_for_unit("clickhouse.service")
$machine->waitForOpenPort(9000); machine.wait_for_open_port(9000)
$machine->succeed("cat ${tableDDL} | clickhouse-client"); machine.succeed(
$machine->succeed("cat ${insertQuery} | clickhouse-client"); "cat ${tableDDL} | clickhouse-client"
$machine->succeed("cat ${selectQuery} | clickhouse-client | grep foo"); )
machine.succeed(
"cat ${insertQuery} | clickhouse-client"
)
machine.succeed(
"cat ${selectQuery} | clickhouse-client | grep foo"
)
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ... }: import ./make-test-python.nix ({ pkgs, lib, ... }:
{ {
name = "codimd"; name = "codimd";
@ -35,20 +35,18 @@ import ./make-test.nix ({ pkgs, lib, ... }:
}; };
testScript = '' testScript = ''
startAll(); start_all()
subtest "CodiMD sqlite", sub { with subtest("CodiMD sqlite"):
$codimdSqlite->waitForUnit("codimd.service"); codimdSqlite.wait_for_unit("codimd.service")
$codimdSqlite->waitForOpenPort(3000); codimdSqlite.wait_for_open_port(3000)
$codimdSqlite->waitUntilSucceeds("curl -sSf http://localhost:3000/new"); codimdSqlite.wait_until_succeeds("curl -sSf http://localhost:3000/new")
};
subtest "CodiMD postgres", sub { with subtest("CodiMD postgres"):
$codimdPostgres->waitForUnit("postgresql.service"); codimdPostgres.wait_for_unit("postgresql.service")
$codimdPostgres->waitForUnit("codimd.service"); codimdPostgres.wait_for_unit("codimd.service")
$codimdPostgres->waitForOpenPort(5432); codimdPostgres.wait_for_open_port(5432)
$codimdPostgres->waitForOpenPort(3000); codimdPostgres.wait_for_open_port(3000)
$codimdPostgres->waitUntilSucceeds("curl -sSf http://localhost:3000/new"); codimdPostgres.wait_until_succeeds("curl -sSf http://localhost:3000/new")
};
''; '';
}) })

View file

@ -7,7 +7,7 @@ let
containerIp6 = "fc00::2/7"; containerIp6 = "fc00::2/7";
in in
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-bridge"; name = "containers-bridge";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ aristid aszlig eelco kampfschlaefer ]; maintainers = [ aristid aszlig eelco kampfschlaefer ];
@ -61,43 +61,42 @@ import ./make-test.nix ({ pkgs, ...} : {
virtualisation.pathsInNixDB = [ pkgs.stdenv ]; virtualisation.pathsInNixDB = [ pkgs.stdenv ];
}; };
testScript = testScript = ''
'' machine.wait_for_unit("default.target")
$machine->waitForUnit("default.target"); assert "webserver" in machine.succeed("nixos-container list")
$machine->succeed("nixos-container list") =~ /webserver/ or die;
# Start the webserver container. with subtest("Start the webserver container"):
$machine->succeed("nixos-container status webserver") =~ /up/ or die; assert "up" in machine.succeed("nixos-container status webserver")
# Check if bridges exist inside containers with subtest("Bridges exist inside containers"):
$machine->succeed("nixos-container run webserver -- ip link show eth0"); machine.succeed(
$machine->succeed("nixos-container run web-noip -- ip link show eth0"); "nixos-container run webserver -- ip link show eth0",
"nixos-container run web-noip -- ip link show eth0",
)
"${containerIp}" =~ /([^\/]+)\/([0-9+])/; ip = "${containerIp}".split("/")[0]
my $ip = $1; machine.succeed(f"ping -n -c 1 {ip}")
chomp $ip; machine.succeed(f"curl --fail http://{ip}/ > /dev/null")
$machine->succeed("ping -n -c 1 $ip");
$machine->succeed("curl --fail http://$ip/ > /dev/null");
"${containerIp6}" =~ /([^\/]+)\/([0-9+])/; ip6 = "${containerIp6}".split("/")[0]
my $ip6 = $1; machine.succeed(f"ping -n -c 1 {ip6}")
chomp $ip6; machine.succeed(f"curl --fail http://[{ip6}]/ > /dev/null")
$machine->succeed("ping -n -c 1 $ip6");
$machine->succeed("curl --fail http://[$ip6]/ > /dev/null");
# Check that nixos-container show-ip works in case of an ipv4 address with with subtest(
# subnetmask in CIDR notation. "nixos-container show-ip works in case of an ipv4 address "
my $result = $machine->succeed("nixos-container show-ip webserver"); + "with subnetmask in CIDR notation."
chomp $result; ):
$result eq $ip or die; result = machine.succeed("nixos-container show-ip webserver").rstrip()
assert result == ip
# Stop the container. with subtest("Stop the container"):
$machine->succeed("nixos-container stop webserver"); machine.succeed("nixos-container stop webserver")
$machine->fail("curl --fail --connect-timeout 2 http://$ip/ > /dev/null"); machine.fail(
$machine->fail("curl --fail --connect-timeout 2 http://[$ip6]/ > /dev/null"); f"curl --fail --connect-timeout 2 http://{ip}/ > /dev/null",
f"curl --fail --connect-timeout 2 http://[{ip6}]/ > /dev/null",
# Destroying a declarative container should fail. )
$machine->fail("nixos-container destroy webserver");
'';
# Destroying a declarative container should fail.
machine.fail("nixos-container destroy webserver")
'';
}) })

View file

@ -1,6 +1,6 @@
# Test for NixOS' container support. # Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-ephemeral"; name = "containers-ephemeral";
machine = { pkgs, ... }: { machine = { pkgs, ... }: {
@ -16,10 +16,10 @@ import ./make-test.nix ({ pkgs, ...} : {
services.nginx = { services.nginx = {
enable = true; enable = true;
virtualHosts.localhost = { virtualHosts.localhost = {
root = (pkgs.runCommand "localhost" {} '' root = pkgs.runCommand "localhost" {} ''
mkdir "$out" mkdir "$out"
echo hello world > "$out/index.html" echo hello world > "$out/index.html"
''); '';
}; };
}; };
networking.firewall.allowedTCPPorts = [ 80 ]; networking.firewall.allowedTCPPorts = [ 80 ];
@ -28,29 +28,27 @@ import ./make-test.nix ({ pkgs, ...} : {
}; };
testScript = '' testScript = ''
$machine->succeed("nixos-container list") =~ /webserver/ or die; assert "webserver" in machine.succeed("nixos-container list")
# Start the webserver container. machine.succeed("nixos-container start webserver")
$machine->succeed("nixos-container start webserver");
# Check that container got its own root folder with subtest("Container got its own root folder"):
$machine->succeed("ls /run/containers/webserver"); machine.succeed("ls /run/containers/webserver")
# Check that container persistent directory is not created with subtest("Container persistent directory is not created"):
$machine->fail("ls /var/lib/containers/webserver"); machine.fail("ls /var/lib/containers/webserver")
# Since "start" returns after the container has reached # Since "start" returns after the container has reached
# multi-user.target, we should now be able to access it. # multi-user.target, we should now be able to access it.
my $ip = $machine->succeed("nixos-container show-ip webserver"); ip = machine.succeed("nixos-container show-ip webserver").rstrip()
chomp $ip; machine.succeed(f"ping -n -c1 {ip}")
$machine->succeed("ping -n -c1 $ip"); machine.succeed(f"curl --fail http://{ip}/ > /dev/null")
$machine->succeed("curl --fail http://$ip/ > /dev/null");
# Stop the container. with subtest("Stop the container"):
$machine->succeed("nixos-container stop webserver"); machine.succeed("nixos-container stop webserver")
$machine->fail("curl --fail --connect-timeout 2 http://$ip/ > /dev/null"); machine.fail(f"curl --fail --connect-timeout 2 http://{ip}/ > /dev/null")
# Check that container's root folder was removed with subtest("Container's root folder was removed"):
$machine->fail("ls /run/containers/webserver"); machine.fail("ls /run/containers/webserver")
''; '';
}) })

View file

@ -1,6 +1,6 @@
# Test for NixOS' container support. # Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-hosts"; name = "containers-hosts";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ montag451 ]; maintainers = [ montag451 ];
@ -42,11 +42,11 @@ import ./make-test.nix ({ pkgs, ...} : {
}; };
testScript = '' testScript = ''
startAll; start_all()
$machine->waitForUnit("default.target"); machine.wait_for_unit("default.target")
# Ping the containers using the entries added in /etc/hosts with subtest("Ping the containers using the entries added in /etc/hosts"):
$machine->succeed("ping -n -c 1 simple.containers"); for host in "simple.containers", "netmask.containers":
$machine->succeed("ping -n -c 1 netmask.containers"); machine.succeed(f"ping -n -c 1 {host}")
''; '';
}) })

View file

@ -1,6 +1,6 @@
# Test for NixOS' container support. # Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-imperative"; name = "containers-imperative";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ aristid aszlig eelco kampfschlaefer ]; maintainers = [ aristid aszlig eelco kampfschlaefer ];
@ -36,95 +36,99 @@ import ./make-test.nix ({ pkgs, ...} : {
}; };
testScript = let testScript = let
tmpfilesContainerConfig = pkgs.writeText "container-config-tmpfiles" '' tmpfilesContainerConfig = pkgs.writeText "container-config-tmpfiles" ''
{ {
systemd.tmpfiles.rules = [ "d /foo - - - - -" ]; systemd.tmpfiles.rules = [ "d /foo - - - - -" ];
systemd.services.foo = { systemd.services.foo = {
serviceConfig.Type = "oneshot"; serviceConfig.Type = "oneshot";
script = "ls -al /foo"; script = "ls -al /foo";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
}; };
} }
''; in '';
'' in ''
# Make sure we have a NixOS tree (required by nixos-container create). with subtest("Make sure we have a NixOS tree (required by nixos-container create)"):
$machine->succeed("PAGER=cat nix-env -qa -A nixos.hello >&2"); machine.succeed("PAGER=cat nix-env -qa -A nixos.hello >&2")
# Create some containers imperatively. id1, id2 = None, None
my $id1 = $machine->succeed("nixos-container create foo --ensure-unique-name");
chomp $id1;
$machine->log("created container $id1");
my $id2 = $machine->succeed("nixos-container create foo --ensure-unique-name"); with subtest("Create some containers imperatively"):
chomp $id2; id1 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
$machine->log("created container $id2"); machine.log(f"created container {id1}")
die if $id1 eq $id2; id2 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
machine.log(f"created container {id2}")
# Put the root of $id2 into a bind mount. assert id1 != id2
$machine->succeed(
"mv /var/lib/containers/$id2 /id2-bindmount",
"mount --bind /id2-bindmount /var/lib/containers/$id1"
);
my $ip1 = $machine->succeed("nixos-container show-ip $id1"); with subtest(f"Put the root of {id2} into a bind mount"):
chomp $ip1; machine.succeed(
my $ip2 = $machine->succeed("nixos-container show-ip $id2"); f"mv /var/lib/containers/{id2} /id2-bindmount",
chomp $ip2; f"mount --bind /id2-bindmount /var/lib/containers/{id1}",
die if $ip1 eq $ip2; )
# Create a directory and a file we can later check if it still exists ip1 = machine.succeed(f"nixos-container show-ip {id1}").rstrip()
# after destruction of the container. ip2 = machine.succeed(f"nixos-container show-ip {id2}").rstrip()
$machine->succeed( assert ip1 != ip2
"mkdir /nested-bindmount",
"echo important data > /nested-bindmount/dummy",
);
# Create a directory with a dummy file and bind-mount it into both with subtest(
# containers. "Create a directory and a file we can later check if it still exists "
foreach ($id1, $id2) { + "after destruction of the container"
my $importantPath = "/var/lib/containers/$_/very/important/data"; ):
$machine->succeed( machine.succeed("mkdir /nested-bindmount")
"mkdir -p $importantPath", machine.succeed("echo important data > /nested-bindmount/dummy")
"mount --bind /nested-bindmount $importantPath"
);
}
# Start one of them. with subtest(
$machine->succeed("nixos-container start $id1"); "Create a directory with a dummy file and bind-mount it into both containers."
):
for id in id1, id2:
important_path = f"/var/lib/containers/{id}/very/important/data"
machine.succeed(
f"mkdir -p {important_path}",
f"mount --bind /nested-bindmount {important_path}",
)
# Execute commands via the root shell. with subtest("Start one of them"):
$machine->succeed("nixos-container run $id1 -- uname") =~ /Linux/ or die; machine.succeed(f"nixos-container start {id1}")
# Execute a nix command via the root shell. (regression test for #40355) with subtest("Execute commands via the root shell"):
$machine->succeed("nixos-container run $id1 -- nix-instantiate -E 'derivation { name = \"empty\"; builder = \"false\"; system = \"false\"; }'"); assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")
# Stop and start (regression test for #4989) with subtest("Execute a nix command via the root shell. (regression test for #40355)"):
$machine->succeed("nixos-container stop $id1"); machine.succeed(
$machine->succeed("nixos-container start $id1"); f"nixos-container run {id1} -- nix-instantiate -E "
+ '\'derivation { name = "empty"; builder = "false"; system = "false"; }\' '
)
# Ensure tmpfiles are present with subtest("Stop and start (regression test for #4989)"):
$machine->log("creating container tmpfiles"); machine.succeed(f"nixos-container stop {id1}")
$machine->succeed("nixos-container create tmpfiles --config-file ${tmpfilesContainerConfig}"); machine.succeed(f"nixos-container start {id1}")
$machine->log("created, starting");
$machine->succeed("nixos-container start tmpfiles");
$machine->log("done starting, investigating");
$machine->succeed("echo \$(nixos-container run tmpfiles -- systemctl is-active foo.service) | grep -q active;");
$machine->succeed("nixos-container destroy tmpfiles");
# Execute commands via the root shell. with subtest("tmpfiles are present"):
$machine->succeed("nixos-container run $id1 -- uname") =~ /Linux/ or die; machine.log("creating container tmpfiles")
machine.succeed(
"nixos-container create tmpfiles --config-file ${tmpfilesContainerConfig}"
)
machine.log("created, starting")
machine.succeed("nixos-container start tmpfiles")
machine.log("done starting, investigating")
machine.succeed(
"echo $(nixos-container run tmpfiles -- systemctl is-active foo.service) | grep -q active;"
)
machine.succeed("nixos-container destroy tmpfiles")
# Destroy the containers. with subtest("Execute commands via the root shell"):
$machine->succeed("nixos-container destroy $id1"); assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")
$machine->succeed("nixos-container destroy $id2");
$machine->succeed( with subtest("Destroy the containers"):
# Check whether destruction of any container has killed important data for id in id1, id2:
"grep -qF 'important data' /nested-bindmount/dummy", machine.succeed(f"nixos-container destroy {id}")
# Ensure that the container path is gone
"test ! -e /var/lib/containers/$id1" with subtest("Check whether destruction of any container has killed important data"):
); machine.succeed("grep -qF 'important data' /nested-bindmount/dummy")
with subtest("Ensure that the container path is gone"):
print(machine.succeed("ls -lsa /var/lib/containers"))
machine.succeed(f"test ! -e /var/lib/containers/{id1}")
''; '';
}) })

View file

@ -0,0 +1,77 @@
# Test for NixOS' container support.
let
webserverFor = hostAddress: localAddress: {
inherit hostAddress localAddress;
privateNetwork = true;
config = {
services.httpd = {
enable = true;
adminAddr = "foo@example.org";
};
networking.firewall.allowedTCPPorts = [ 80 ];
};
};
in import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-ipv4-ipv6";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ aristid aszlig eelco kampfschlaefer ];
};
machine =
{ pkgs, ... }: {
imports = [ ../modules/installer/cd-dvd/channel.nix ];
virtualisation = {
writableStore = true;
memorySize = 768;
};
containers.webserver4 = webserverFor "10.231.136.1" "10.231.136.2";
containers.webserver6 = webserverFor "fc00::2" "fc00::1";
virtualisation.pathsInNixDB = [ pkgs.stdenv ];
};
testScript = { nodes, ... }: ''
import time
def curl_host(ip):
# put [] around ipv6 addresses for curl
host = ip if ":" not in ip else f"[{ip}]"
return f"curl --fail --connect-timeout 2 http://{host}/ > /dev/null"
def get_ip(container):
# need to distinguish because show-ip won't work for ipv6
if container == "webserver4":
ip = machine.succeed(f"nixos-container show-ip {container}").rstrip()
assert ip == "${nodes.machine.config.containers.webserver4.localAddress}"
return ip
return "${nodes.machine.config.containers.webserver6.localAddress}"
for container in "webserver4", "webserver6":
assert container in machine.succeed("nixos-container list")
with subtest(f"Start container {container}"):
machine.succeed(f"nixos-container start {container}")
# wait 2s for container to start and network to be up
time.sleep(2)
# Since "start" returns after the container has reached
# multi-user.target, we should now be able to access it.
ip = get_ip(container)
with subtest(f"{container} reacts to pings and HTTP requests"):
machine.succeed(f"ping -n -c1 {ip}")
machine.succeed(curl_host(ip))
with subtest(f"Stop container {container}"):
machine.succeed(f"nixos-container stop {container}")
machine.fail(curl_host(ip))
# Destroying a declarative container should fail.
machine.fail(f"nixos-container destroy {container}")
'';
})

View file

@ -1,55 +0,0 @@
# Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : {
name = "containers-ipv4";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ aristid aszlig eelco kampfschlaefer ];
};
machine =
{ pkgs, ... }:
{ imports = [ ../modules/installer/cd-dvd/channel.nix ];
virtualisation.writableStore = true;
virtualisation.memorySize = 768;
containers.webserver =
{ privateNetwork = true;
hostAddress = "10.231.136.1";
localAddress = "10.231.136.2";
config =
{ services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
networking.firewall.allowedTCPPorts = [ 80 ];
system.stateVersion = "18.03";
};
};
virtualisation.pathsInNixDB = [ pkgs.stdenv ];
};
testScript =
''
$machine->succeed("nixos-container list") =~ /webserver/ or die;
# Start the webserver container.
$machine->succeed("nixos-container start webserver");
# wait two seconds for the container to start and the network to be up
sleep 2;
# Since "start" returns after the container has reached
# multi-user.target, we should now be able to access it.
my $ip = $machine->succeed("nixos-container show-ip webserver");
chomp $ip;
$machine->succeed("ping -n -c1 $ip");
$machine->succeed("curl --fail http://$ip/ > /dev/null");
# Stop the container.
$machine->succeed("nixos-container stop webserver");
$machine->fail("curl --fail --connect-timeout 2 http://$ip/ > /dev/null");
# Destroying a declarative container should fail.
$machine->fail("nixos-container destroy webserver");
'';
})

View file

@ -1,60 +0,0 @@
# Test for NixOS' container support.
let
hostIp = "fc00::2";
localIp = "fc00::1";
in
import ./make-test.nix ({ pkgs, ...} : {
name = "containers-ipv6";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ aristid aszlig eelco kampfschlaefer ];
};
machine =
{ pkgs, ... }:
{ imports = [ ../modules/installer/cd-dvd/channel.nix ];
virtualisation.writableStore = true;
virtualisation.memorySize = 768;
containers.webserver =
{ privateNetwork = true;
hostAddress6 = hostIp;
localAddress6 = localIp;
config =
{ services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
networking.firewall.allowedTCPPorts = [ 80 ];
};
};
virtualisation.pathsInNixDB = [ pkgs.stdenv ];
};
testScript =
''
$machine->waitForUnit("default.target");
$machine->succeed("nixos-container list") =~ /webserver/ or die;
# Start the webserver container.
$machine->succeed("nixos-container start webserver");
# wait two seconds for the container to start and the network to be up
sleep 2;
# Since "start" returns after the container has reached
# multi-user.target, we should now be able to access it.
my $ip = "${localIp}";
chomp $ip;
$machine->succeed("ping -n -c 1 $ip");
$machine->succeed("curl --fail http://[$ip]/ > /dev/null");
# Stop the container.
$machine->succeed("nixos-container stop webserver");
$machine->fail("curl --fail --connect-timeout 2 http://[$ip]/ > /dev/null");
# Destroying a declarative container should fail.
$machine->fail("nixos-container destroy webserver");
'';
})

View file

@ -1,7 +1,7 @@
import ./make-test.nix ({ pkgs, lib, ...} : import ./make-test-python.nix ({ pkgs, lib, ...} :
let let
client_base = { client_base = {
containers.test1 = { containers.test1 = {
autoStart = true; autoStart = true;
config = { config = {
@ -48,18 +48,25 @@ in {
c1System = nodes.client_c1.config.system.build.toplevel; c1System = nodes.client_c1.config.system.build.toplevel;
c2System = nodes.client_c2.config.system.build.toplevel; c2System = nodes.client_c2.config.system.build.toplevel;
in '' in ''
$client->start(); client.start()
$client->waitForUnit("default.target"); client.wait_for_unit("default.target")
$client->succeed("[[ \$(nixos-container run test1 cat /etc/check) == client_base ]] >&2");
$client->succeed("${c1System}/bin/switch-to-configuration test >&2"); assert "client_base" in client.succeed("nixos-container run test1 cat /etc/check")
$client->succeed("[[ \$(nixos-container run test1 cat /etc/check) == client_c1 ]] >&2");
$client->succeed("systemctl status httpd -M test1 >&2");
$client->succeed("${c2System}/bin/switch-to-configuration test >&2"); with subtest("httpd is available after activating config1"):
$client->succeed("[[ \$(nixos-container run test1 cat /etc/check) == client_c2 ]] >&2"); client.succeed(
$client->fail("systemctl status httpd -M test1 >&2"); "${c1System}/bin/switch-to-configuration test >&2",
$client->succeed("systemctl status nginx -M test1 >&2"); "[[ $(nixos-container run test1 cat /etc/check) == client_c1 ]] >&2",
"systemctl status httpd -M test1 >&2",
)
with subtest("httpd is not available any longer after switching to config2"):
client.succeed(
"${c2System}/bin/switch-to-configuration test >&2",
"[[ $(nixos-container run test1 cat /etc/check) == client_c2 ]] >&2",
"systemctl status nginx -M test1 >&2",
)
client.fail("systemctl status httpd -M test1 >&2")
''; '';
}) })

View file

@ -1,6 +1,6 @@
# Test for NixOS' container support. # Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-tmpfs"; name = "containers-tmpfs";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ kampka ]; maintainers = [ kampka ];
@ -31,49 +31,63 @@ import ./make-test.nix ({ pkgs, ...} : {
virtualisation.pathsInNixDB = [ pkgs.stdenv ]; virtualisation.pathsInNixDB = [ pkgs.stdenv ];
}; };
testScript = testScript = ''
'' machine.wait_for_unit("default.target")
$machine->waitForUnit("default.target"); assert "tmpfs" in machine.succeed("nixos-container list")
$machine->succeed("nixos-container list") =~ /tmpfs/ or die;
# Start the tmpfs container. with subtest("tmpfs container is up"):
#$machine->succeed("nixos-container status tmpfs") =~ /up/ or die; assert "up" in machine.succeed("nixos-container status tmpfs")
# Verify that /var is mounted as a tmpfs
#$machine->succeed("nixos-container run tmpfs -- systemctl status var.mount --no-pager 2>/dev/null") =~ /What: tmpfs/ or die;
$machine->succeed("nixos-container run tmpfs -- mountpoint -q /var 2>/dev/null");
# Verify that /var/log is mounted as a tmpfs
$machine->succeed("nixos-container run tmpfs -- systemctl status var-log.mount --no-pager 2>/dev/null") =~ /What: tmpfs/ or die;
$machine->succeed("nixos-container run tmpfs -- mountpoint -q /var/log 2>/dev/null");
# Verify that /some/random/path is mounted as a tmpfs
$machine->succeed("nixos-container run tmpfs -- systemctl status some-random-path.mount --no-pager 2>/dev/null") =~ /What: tmpfs/ or die;
$machine->succeed("nixos-container run tmpfs -- mountpoint -q /some/random/path 2>/dev/null");
# Verify that files created in the container in a non-tmpfs directory are visible on the host.
# This establishes legitimacy for the following tests
$machine->succeed("nixos-container run tmpfs -- touch /root/test.file 2>/dev/null");
$machine->succeed("nixos-container run tmpfs -- ls -l /root | grep -q test.file 2>/dev/null");
$machine->succeed("test -e /var/lib/containers/tmpfs/root/test.file");
# Verify that /some/random/path is writable and that files created there def tmpfs_cmd(command):
# are not in the hosts container dir but in the tmpfs return f"nixos-container run tmpfs -- {command} 2>/dev/null"
$machine->succeed("nixos-container run tmpfs -- touch /some/random/path/test.file 2>/dev/null");
$machine->succeed("nixos-container run tmpfs -- test -e /some/random/path/test.file 2>/dev/null");
$machine->fail("test -e /var/lib/containers/tmpfs/some/random/path/test.file");
# Verify that files created in the hosts container dir in a path where a tmpfs file system has been mounted with subtest("/var is mounted as a tmpfs"):
# are not visible to the container as the do not exist in the tmpfs machine.succeed(tmpfs_cmd("mountpoint -q /var"))
$machine->succeed("touch /var/lib/containers/tmpfs/var/test.file");
$machine->succeed("test -e /var/lib/containers/tmpfs/var/test.file"); with subtest("/var/log is mounted as a tmpfs"):
$machine->succeed("ls -l /var/lib/containers/tmpfs/var/ | grep -q test.file 2>/dev/null"); assert "What: tmpfs" in machine.succeed(
tmpfs_cmd("systemctl status var-log.mount --no-pager")
)
machine.succeed(tmpfs_cmd("mountpoint -q /var/log"))
$machine->fail("nixos-container run tmpfs -- ls -l /var | grep -q test.file 2>/dev/null"); with subtest("/some/random/path is mounted as a tmpfs"):
assert "What: tmpfs" in machine.succeed(
tmpfs_cmd("systemctl status some-random-path.mount --no-pager")
)
machine.succeed(tmpfs_cmd("mountpoint -q /some/random/path"))
with subtest(
"files created in the container in a non-tmpfs directory are visible on the host."
):
# This establishes legitimacy for the following tests
machine.succeed(
tmpfs_cmd("touch /root/test.file"),
tmpfs_cmd("ls -l /root | grep -q test.file"),
"test -e /var/lib/containers/tmpfs/root/test.file",
)
with subtest(
"/some/random/path is writable and that files created there are not "
+ "in the hosts container dir but in the tmpfs"
):
machine.succeed(
tmpfs_cmd("touch /some/random/path/test.file"),
tmpfs_cmd("test -e /some/random/path/test.file"),
)
machine.fail("test -e /var/lib/containers/tmpfs/some/random/path/test.file")
with subtest(
"files created in the hosts container dir in a path where a tmpfs "
+ "file system has been mounted are not visible to the container as "
+ "the do not exist in the tmpfs"
):
machine.succeed(
"touch /var/lib/containers/tmpfs/var/test.file",
"test -e /var/lib/containers/tmpfs/var/test.file",
"ls -l /var/lib/containers/tmpfs/var/ | grep -q test.file 2>/dev/null",
)
machine.fail(tmpfs_cmd("ls -l /var | grep -q test.file"))
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "deluge"; name = "deluge";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ flokli ]; maintainers = [ flokli ];
@ -45,18 +45,20 @@ import ./make-test.nix ({ pkgs, ...} : {
}; };
testScript = '' testScript = ''
startAll; start_all()
$simple->waitForUnit("deluged"); simple.wait_for_unit("deluged")
$simple->waitForUnit("delugeweb"); simple.wait_for_unit("delugeweb")
$simple->waitForOpenPort("8112"); simple.wait_for_open_port("8112")
$declarative->waitForUnit("network.target"); declarative.wait_for_unit("network.target")
$declarative->waitUntilSucceeds("curl --fail http://simple:8112"); declarative.wait_until_succeeds("curl --fail http://simple:8112")
$declarative->waitForUnit("deluged"); declarative.wait_for_unit("deluged")
$declarative->waitForUnit("delugeweb"); declarative.wait_for_unit("delugeweb")
$declarative->waitUntilSucceeds("curl --fail http://declarative:3142"); declarative.wait_until_succeeds("curl --fail http://declarative:3142")
$declarative->succeed("deluge-console 'help' | grep -q 'rm - Remove a torrent'"); declarative.succeed("deluge-console 'help' | grep -q 'rm - Remove a torrent'")
$declarative->succeed("deluge-console 'connect 127.0.0.1:58846 andrew password; help' | grep -q 'rm - Remove a torrent'"); declarative.succeed(
"deluge-console 'connect 127.0.0.1:58846 andrew password; help' | grep -q 'rm - Remove a torrent'"
)
''; '';
}) })

View file

@ -1,6 +1,6 @@
# This test runs docker-registry and check if it works # This test runs docker-registry and check if it works
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "docker-registry"; name = "docker-registry";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ globin ma27 ironpinguin ]; maintainers = [ globin ma27 ironpinguin ];
@ -28,36 +28,34 @@ import ./make-test.nix ({ pkgs, ...} : {
}; };
testScript = '' testScript = ''
$client1->start(); client1.start()
$client1->waitForUnit("docker.service"); client1.wait_for_unit("docker.service")
$client1->succeed("tar cv --files-from /dev/null | docker import - scratch"); client1.succeed("tar cv --files-from /dev/null | docker import - scratch")
$client1->succeed("docker tag scratch registry:8080/scratch"); client1.succeed("docker tag scratch registry:8080/scratch")
$registry->start(); registry.start()
$registry->waitForUnit("docker-registry.service"); registry.wait_for_unit("docker-registry.service")
$registry->waitForOpenPort("8080"); registry.wait_for_open_port("8080")
$client1->succeed("docker push registry:8080/scratch"); client1.succeed("docker push registry:8080/scratch")
$client2->start(); client2.start()
$client2->waitForUnit("docker.service"); client2.wait_for_unit("docker.service")
$client2->succeed("docker pull registry:8080/scratch"); client2.succeed("docker pull registry:8080/scratch")
$client2->succeed("docker images | grep scratch"); client2.succeed("docker images | grep scratch")
$client2->succeed( client2.succeed(
'curl -fsS -X DELETE registry:8080/v2/scratch/manifests/$(curl -fsS -I -H"Accept: application/vnd.docker.distribution.manifest.v2+json" registry:8080/v2/scratch/manifests/latest | grep Docker-Content-Digest | sed -e \'s/Docker-Content-Digest: //\' | tr -d \'\r\')' "curl -fsS -X DELETE registry:8080/v2/scratch/manifests/$(curl -fsS -I -H\"Accept: application/vnd.docker.distribution.manifest.v2+json\" registry:8080/v2/scratch/manifests/latest | grep Docker-Content-Digest | sed -e 's/Docker-Content-Digest: //' | tr -d '\\r')"
); )
$registry->systemctl("start docker-registry-garbage-collect.service"); registry.systemctl("start docker-registry-garbage-collect.service")
$registry->waitUntilFails("systemctl status docker-registry-garbage-collect.service"); registry.wait_until_fails("systemctl status docker-registry-garbage-collect.service")
$registry->waitForUnit("docker-registry.service"); registry.wait_for_unit("docker-registry.service")
$registry->fail( registry.fail("ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data")
'ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data'
);
$client1->succeed("docker push registry:8080/scratch"); client1.succeed("docker push registry:8080/scratch")
$registry->succeed( registry.succeed(
'ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data' "ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data"
); )
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix { import ./make-test-python.nix {
name = "dovecot"; name = "dovecot";
machine = { pkgs, ... }: { machine = { pkgs, ... }: {
@ -66,12 +66,12 @@ import ./make-test.nix {
}; };
testScript = '' testScript = ''
$machine->waitForUnit('postfix.service'); machine.wait_for_unit("postfix.service")
$machine->waitForUnit('dovecot2.service'); machine.wait_for_unit("dovecot2.service")
$machine->succeed('send-testmail'); machine.succeed("send-testmail")
$machine->succeed('send-lda'); machine.succeed("send-lda")
$machine->waitUntilFails('[ "$(postqueue -p)" != "Mail queue is empty" ]'); machine.wait_until_fails('[ "$(postqueue -p)" != "Mail queue is empty" ]')
$machine->succeed('test-imap'); machine.succeed("test-imap")
$machine->succeed('test-pop'); machine.succeed("test-pop")
''; '';
} }

View file

@ -1,6 +1,6 @@
# This test runs simple etcd cluster # This test runs simple etcd cluster
import ./make-test.nix ({ pkgs, ... } : let import ./make-test-python.nix ({ pkgs, ... } : let
runWithOpenSSL = file: cmd: pkgs.runCommand file { runWithOpenSSL = file: cmd: pkgs.runCommand file {
buildInputs = [ pkgs.openssl ]; buildInputs = [ pkgs.openssl ];
@ -129,29 +129,26 @@ in {
}; };
testScript = '' testScript = ''
subtest "should start etcd cluster", sub { with subtest("should start etcd cluster"):
$node1->start(); node1.start()
$node2->start(); node2.start()
$node1->waitForUnit("etcd.service"); node1.wait_for_unit("etcd.service")
$node2->waitForUnit("etcd.service"); node2.wait_for_unit("etcd.service")
$node2->waitUntilSucceeds("etcdctl cluster-health"); node2.wait_until_succeeds("etcdctl cluster-health")
$node1->succeed("etcdctl set /foo/bar 'Hello world'"); node1.succeed("etcdctl set /foo/bar 'Hello world'")
$node2->succeed("etcdctl get /foo/bar | grep 'Hello world'"); node2.succeed("etcdctl get /foo/bar | grep 'Hello world'")
};
subtest "should add another member", sub { with subtest("should add another member"):
$node1->waitUntilSucceeds("etcdctl member add node3 https://node3:2380"); node1.wait_until_succeeds("etcdctl member add node3 https://node3:2380")
$node3->start(); node3.start()
$node3->waitForUnit("etcd.service"); node3.wait_for_unit("etcd.service")
$node3->waitUntilSucceeds("etcdctl member list | grep 'node3'"); node3.wait_until_succeeds("etcdctl member list | grep 'node3'")
$node3->succeed("etcdctl cluster-health"); node3.succeed("etcdctl cluster-health")
};
subtest "should survive member crash", sub { with subtest("should survive member crash"):
$node3->crash; node3.crash()
$node1->succeed("etcdctl cluster-health"); node1.succeed("etcdctl cluster-health")
$node1->succeed("etcdctl set /foo/bar 'Hello degraded world'"); node1.succeed("etcdctl set /foo/bar 'Hello degraded world'")
$node1->succeed("etcdctl get /foo/bar | grep 'Hello degraded world'"); node1.succeed("etcdctl get /foo/bar | grep 'Hello degraded world'")
};
''; '';
}) })

View file

@ -1,6 +1,6 @@
# This test runs simple etcd node # This test runs simple etcd node
import ./make-test.nix ({ pkgs, ... } : { import ./make-test-python.nix ({ pkgs, ... } : {
name = "etcd"; name = "etcd";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
@ -14,14 +14,12 @@ import ./make-test.nix ({ pkgs, ... } : {
}; };
testScript = '' testScript = ''
subtest "should start etcd node", sub { with subtest("should start etcd node"):
$node->start(); node.start()
$node->waitForUnit("etcd.service"); node.wait_for_unit("etcd.service")
};
subtest "should write and read some values to etcd", sub { with subtest("should write and read some values to etcd"):
$node->succeed("etcdctl set /foo/bar 'Hello world'"); node.succeed("etcdctl set /foo/bar 'Hello world'")
$node->succeed("etcdctl get /foo/bar | grep 'Hello world'"); node.succeed("etcdctl get /foo/bar | grep 'Hello world'")
}
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... } : { import ./make-test-python.nix ({ pkgs, ... } : {
name = "fancontrol"; name = "fancontrol";
machine = machine =
@ -19,7 +19,10 @@ import ./make-test.nix ({ pkgs, ... } : {
# This configuration cannot be valid for the test VM, so it's expected to get an 'outdated' error. # This configuration cannot be valid for the test VM, so it's expected to get an 'outdated' error.
testScript = '' testScript = ''
$machine->waitForUnit("fancontrol.service"); start_all()
$machine->waitUntilSucceeds("journalctl -eu fancontrol | grep 'Configuration appears to be outdated'"); machine.wait_for_unit("fancontrol.service")
machine.wait_until_succeeds(
"journalctl -eu fancontrol | grep 'Configuration appears to be outdated'"
)
''; '';
}) })

View file

@ -1,5 +1,5 @@
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "ferm"; name = "ferm";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ mic92 ]; maintainers = [ mic92 ];
@ -53,24 +53,22 @@ import ./make-test.nix ({ pkgs, ...} : {
testScript = testScript =
'' ''
startAll; start_all()
$client->waitForUnit("network-online.target"); client.wait_for_unit("network-online.target")
$server->waitForUnit("ferm.service"); server.wait_for_unit("ferm.service")
$server->waitForUnit("nginx.service"); server.wait_for_unit("nginx.service")
$server->waitUntilSucceeds("ss -ntl | grep -q 80"); server.wait_until_succeeds("ss -ntl | grep -q 80")
subtest "port 80 is allowed", sub { with subtest("port 80 is allowed"):
$client->succeed("curl --fail -g http://192.168.1.1:80/status"); client.succeed("curl --fail -g http://192.168.1.1:80/status")
$client->succeed("curl --fail -g http://[fd00::1]:80/status"); client.succeed("curl --fail -g http://[fd00::1]:80/status")
};
subtest "port 8080 is not allowed", sub { with subtest("port 8080 is not allowed"):
$server->succeed("curl --fail -g http://192.168.1.1:8080/status"); server.succeed("curl --fail -g http://192.168.1.1:8080/status")
$server->succeed("curl --fail -g http://[fd00::1]:8080/status"); server.succeed("curl --fail -g http://[fd00::1]:8080/status")
$client->fail("curl --fail -g http://192.168.1.1:8080/status"); client.fail("curl --fail -g http://192.168.1.1:8080/status")
$client->fail("curl --fail -g http://[fd00::1]:8080/status"); client.fail("curl --fail -g http://[fd00::1]:8080/status")
};
''; '';
}) })

View file

@ -1,6 +1,6 @@
# Test the firewall module. # Test the firewall module.
import ./make-test.nix ( { pkgs, ... } : { import ./make-test-python.nix ( { pkgs, ... } : {
name = "firewall"; name = "firewall";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ eelco ]; maintainers = [ eelco ];
@ -36,30 +36,30 @@ import ./make-test.nix ( { pkgs, ... } : {
testScript = { nodes, ... }: let testScript = { nodes, ... }: let
newSystem = nodes.walled2.config.system.build.toplevel; newSystem = nodes.walled2.config.system.build.toplevel;
in '' in ''
$walled->start; start_all()
$attacker->start;
$walled->waitForUnit("firewall"); walled.wait_for_unit("firewall")
$walled->waitForUnit("httpd"); walled.wait_for_unit("httpd")
$attacker->waitForUnit("network.target"); attacker.wait_for_unit("network.target")
# Local connections should still work. # Local connections should still work.
$walled->succeed("curl -v http://localhost/ >&2"); walled.succeed("curl -v http://localhost/ >&2")
# Connections to the firewalled machine should fail, but ping should succeed. # Connections to the firewalled machine should fail, but ping should succeed.
$attacker->fail("curl --fail --connect-timeout 2 http://walled/ >&2"); attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
$attacker->succeed("ping -c 1 walled >&2"); attacker.succeed("ping -c 1 walled >&2")
# Outgoing connections/pings should still work. # Outgoing connections/pings should still work.
$walled->succeed("curl -v http://attacker/ >&2"); walled.succeed("curl -v http://attacker/ >&2")
$walled->succeed("ping -c 1 attacker >&2"); walled.succeed("ping -c 1 attacker >&2")
# If we stop the firewall, then connections should succeed. # If we stop the firewall, then connections should succeed.
$walled->stopJob("firewall"); walled.stop_job("firewall")
$attacker->succeed("curl -v http://walled/ >&2"); attacker.succeed("curl -v http://walled/ >&2")
# Check whether activation of a new configuration reloads the firewall. # Check whether activation of a new configuration reloads the firewall.
$walled->succeed("${newSystem}/bin/switch-to-configuration test 2>&1" . walled.succeed(
" | grep -qF firewall.service"); "${newSystem}/bin/switch-to-configuration test 2>&1 | grep -qF firewall.service"
)
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... }: { import ./make-test-python.nix ({ pkgs, ... }: {
name = "fish"; name = "fish";
machine = machine =
@ -14,8 +14,11 @@ import ./make-test.nix ({ pkgs, ... }: {
testScript = testScript =
'' ''
$machine->waitForFile("/etc/fish/generated_completions/coreutils.fish"); start_all()
$machine->waitForFile("/etc/fish/generated_completions/kill.fish"); machine.wait_for_file("/etc/fish/generated_completions/coreutils.fish")
$machine->succeed("fish -ic 'echo \$fish_complete_path' | grep -q '/share/fish/completions /etc/fish/generated_completions /root/.local/share/fish/generated_completions\$'"); machine.wait_for_file("/etc/fish/generated_completions/kill.fish")
machine.succeed(
"fish -ic 'echo $fish_complete_path' | grep -q '/share/fish/completions /etc/fish/generated_completions /root/.local/share/fish/generated_completions$'"
)
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ... }: { import ./make-test-python.nix ({ pkgs, lib, ... }: {
name = "fluentd"; name = "fluentd";
machine = { pkgs, ... }: { machine = { pkgs, ... }: {
@ -33,14 +33,17 @@ import ./make-test.nix ({ pkgs, lib, ... }: {
inherit testMessage; inherit testMessage;
}); });
in '' in ''
$machine->start; machine.start()
$machine->waitForUnit('fluentd.service'); machine.wait_for_unit("fluentd.service")
$machine->waitForOpenPort(9880); machine.wait_for_open_port(9880)
$machine->succeed("curl -fsSL -X POST -H 'Content-type: application/json' -d @${payload} http://localhost:9880/test.tag"); machine.succeed(
"curl -fsSL -X POST -H 'Content-type: application/json' -d @${payload} http://localhost:9880/test.tag"
)
$machine->succeed("systemctl stop fluentd"); # blocking flush # blocking flush
machine.succeed("systemctl stop fluentd")
$machine->succeed("grep '${testMessage}' /tmp/current-log"); machine.succeed("grep '${testMessage}' /tmp/current-log")
''; '';
}) })

View file

@ -3,7 +3,7 @@
let let
initialRootPassword = "notproduction"; initialRootPassword = "notproduction";
in in
import ./make-test.nix ({ pkgs, lib, ...} : with lib; { import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
name = "gitlab"; name = "gitlab";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ globin ]; maintainers = [ globin ];
@ -63,21 +63,35 @@ import ./make-test.nix ({ pkgs, lib, ...} : with lib; {
}); });
in in
'' ''
$gitlab->start(); gitlab.start()
$gitlab->waitForUnit("gitaly.service"); gitlab.wait_for_unit("gitaly.service")
$gitlab->waitForUnit("gitlab-workhorse.service"); gitlab.wait_for_unit("gitlab-workhorse.service")
$gitlab->waitForUnit("gitlab.service"); gitlab.wait_for_unit("gitlab.service")
$gitlab->waitForUnit("gitlab-sidekiq.service"); gitlab.wait_for_unit("gitlab-sidekiq.service")
$gitlab->waitForFile("/var/gitlab/state/tmp/sockets/gitlab.socket"); gitlab.wait_for_file("/var/gitlab/state/tmp/sockets/gitlab.socket")
$gitlab->waitUntilSucceeds("curl -sSf http://gitlab/users/sign_in"); gitlab.wait_until_succeeds("curl -sSf http://gitlab/users/sign_in")
$gitlab->succeed("curl -isSf http://gitlab | grep -i location | grep -q http://gitlab/users/sign_in"); gitlab.succeed(
$gitlab->succeed("${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2"); "curl -isSf http://gitlab | grep -i location | grep -q http://gitlab/users/sign_in"
$gitlab->succeed("echo \"Authorization: Bearer \$(curl -X POST -H 'Content-Type: application/json' -d @${auth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers"); )
$gitlab->succeed("curl -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createProject} http://gitlab/api/v4/projects"); gitlab.succeed(
$gitlab->succeed("curl -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${putFile} http://gitlab/api/v4/projects/1/repository/files/some-file.txt"); "${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2"
$gitlab->succeed("curl -H @/tmp/headers http://gitlab/api/v4/projects/1/repository/archive.tar.gz > /tmp/archive.tar.gz"); )
$gitlab->succeed("curl -H @/tmp/headers http://gitlab/api/v4/projects/1/repository/archive.tar.bz2 > /tmp/archive.tar.bz2"); gitlab.succeed(
$gitlab->succeed("test -s /tmp/archive.tar.gz"); "echo \"Authorization: Bearer \$(curl -X POST -H 'Content-Type: application/json' -d @${auth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers"
$gitlab->succeed("test -s /tmp/archive.tar.bz2"); )
gitlab.succeed(
"curl -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createProject} http://gitlab/api/v4/projects"
)
gitlab.succeed(
"curl -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${putFile} http://gitlab/api/v4/projects/1/repository/files/some-file.txt"
)
gitlab.succeed(
"curl -H @/tmp/headers http://gitlab/api/v4/projects/1/repository/archive.tar.gz > /tmp/archive.tar.gz"
)
gitlab.succeed(
"curl -H @/tmp/headers http://gitlab/api/v4/projects/1/repository/archive.tar.bz2 > /tmp/archive.tar.bz2"
)
gitlab.succeed("test -s /tmp/archive.tar.gz")
gitlab.succeed("test -s /tmp/archive.tar.bz2")
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ...}: import ./make-test-python.nix ({ pkgs, ...}:
let let
adminPrivateKey = pkgs.writeText "id_ed25519" '' adminPrivateKey = pkgs.writeText "id_ed25519" ''
@ -43,7 +43,7 @@ let
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZNonUP1ePHLrvn0W9D2hdN6zWWZYFyJc+QR6pOKQEw bob@client ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZNonUP1ePHLrvn0W9D2hdN6zWWZYFyJc+QR6pOKQEw bob@client
''; '';
gitoliteAdminConfSnippet = '' gitoliteAdminConfSnippet = pkgs.writeText "gitolite-admin-conf-snippet" ''
repo alice-project repo alice-project
RW+ = alice RW+ = alice
''; '';
@ -85,55 +85,54 @@ in
}; };
testScript = '' testScript = ''
startAll; start_all()
subtest "can setup ssh keys on system", sub { with subtest("can setup ssh keys on system"):
$client->mustSucceed("mkdir -p ~root/.ssh"); client.succeed(
$client->mustSucceed("cp ${adminPrivateKey} ~root/.ssh/id_ed25519"); "mkdir -p ~root/.ssh",
$client->mustSucceed("chmod 600 ~root/.ssh/id_ed25519"); "cp ${adminPrivateKey} ~root/.ssh/id_ed25519",
"chmod 600 ~root/.ssh/id_ed25519",
)
client.succeed(
"sudo -u alice mkdir -p ~alice/.ssh",
"sudo -u alice cp ${alicePrivateKey} ~alice/.ssh/id_ed25519",
"sudo -u alice chmod 600 ~alice/.ssh/id_ed25519",
)
client.succeed(
"sudo -u bob mkdir -p ~bob/.ssh",
"sudo -u bob cp ${bobPrivateKey} ~bob/.ssh/id_ed25519",
"sudo -u bob chmod 600 ~bob/.ssh/id_ed25519",
)
$client->mustSucceed("sudo -u alice mkdir -p ~alice/.ssh"); with subtest("gitolite server starts"):
$client->mustSucceed("sudo -u alice cp ${alicePrivateKey} ~alice/.ssh/id_ed25519"); server.wait_for_unit("gitolite-init.service")
$client->mustSucceed("sudo -u alice chmod 600 ~alice/.ssh/id_ed25519"); server.wait_for_unit("sshd.service")
client.succeed("ssh gitolite@server info")
$client->mustSucceed("sudo -u bob mkdir -p ~bob/.ssh"); with subtest("admin can clone and configure gitolite-admin.git"):
$client->mustSucceed("sudo -u bob cp ${bobPrivateKey} ~bob/.ssh/id_ed25519"); client.succeed(
$client->mustSucceed("sudo -u bob chmod 600 ~bob/.ssh/id_ed25519"); "git clone gitolite@server:gitolite-admin.git",
}; "git config --global user.name 'System Administrator'",
"git config --global user.email root\@domain.example",
"cp ${alicePublicKey} gitolite-admin/keydir/alice.pub",
"cp ${bobPublicKey} gitolite-admin/keydir/bob.pub",
"(cd gitolite-admin && git add . && git commit -m 'Add keys for alice, bob' && git push)",
"cat ${gitoliteAdminConfSnippet} >> gitolite-admin/conf/gitolite.conf",
"(cd gitolite-admin && git add . && git commit -m 'Add repo for alice' && git push)",
)
subtest "gitolite server starts", sub { with subtest("non-admins cannot clone gitolite-admin.git"):
$server->waitForUnit("gitolite-init.service"); client.fail("sudo -i -u alice git clone gitolite@server:gitolite-admin.git")
$server->waitForUnit("sshd.service"); client.fail("sudo -i -u bob git clone gitolite@server:gitolite-admin.git")
$client->mustSucceed('ssh gitolite@server info');
};
subtest "admin can clone and configure gitolite-admin.git", sub { with subtest("non-admins can clone testing.git"):
$client->mustSucceed('git clone gitolite@server:gitolite-admin.git'); client.succeed("sudo -i -u alice git clone gitolite@server:testing.git")
$client->mustSucceed("git config --global user.name 'System Administrator'"); client.succeed("sudo -i -u bob git clone gitolite@server:testing.git")
$client->mustSucceed("git config --global user.email root\@domain.example");
$client->mustSucceed("cp ${alicePublicKey} gitolite-admin/keydir/alice.pub");
$client->mustSucceed("cp ${bobPublicKey} gitolite-admin/keydir/bob.pub");
$client->mustSucceed('(cd gitolite-admin && git add . && git commit -m "Add keys for alice, bob" && git push)');
$client->mustSucceed("printf '${gitoliteAdminConfSnippet}' >> gitolite-admin/conf/gitolite.conf");
$client->mustSucceed('(cd gitolite-admin && git add . && git commit -m "Add repo for alice" && git push)');
};
subtest "non-admins cannot clone gitolite-admin.git", sub { with subtest("alice can clone alice-project.git"):
$client->mustFail('sudo -i -u alice git clone gitolite@server:gitolite-admin.git'); client.succeed("sudo -i -u alice git clone gitolite@server:alice-project.git")
$client->mustFail('sudo -i -u bob git clone gitolite@server:gitolite-admin.git');
};
subtest "non-admins can clone testing.git", sub { with subtest("bob cannot clone alice-project.git"):
$client->mustSucceed('sudo -i -u alice git clone gitolite@server:testing.git'); client.fail("sudo -i -u bob git clone gitolite@server:alice-project.git")
$client->mustSucceed('sudo -i -u bob git clone gitolite@server:testing.git');
};
subtest "alice can clone alice-project.git", sub {
$client->mustSucceed('sudo -i -u alice git clone gitolite@server:alice-project.git');
};
subtest "bob cannot clone alice-project.git", sub {
$client->mustFail('sudo -i -u bob git clone gitolite@server:alice-project.git');
};
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ ... } : import ./make-test-python.nix ({pkgs, lib, ...}:
let let
client = { pkgs, ... } : { client = { pkgs, ... } : {
@ -39,27 +39,29 @@ in {
}; };
testScript = '' testScript = ''
$server1->waitForUnit("glusterd.service"); server1.wait_for_unit("glusterd.service")
$server2->waitForUnit("glusterd.service"); server2.wait_for_unit("glusterd.service")
server1.wait_until_succeeds("gluster peer status")
server2.wait_until_succeeds("gluster peer status")
# establish initial contact # establish initial contact
$server1->succeed("sleep 2"); server1.succeed("gluster peer probe server2")
$server1->succeed("gluster peer probe server2"); server1.succeed("gluster peer probe server1")
$server1->succeed("gluster peer probe server1");
$server1->succeed("gluster peer status | grep Connected"); server1.succeed("gluster peer status | grep Connected")
# create volumes # create volumes
$server1->succeed("mkdir -p /data/vg0"); server1.succeed("mkdir -p /data/vg0")
$server2->succeed("mkdir -p /data/vg0"); server2.succeed("mkdir -p /data/vg0")
$server1->succeed("gluster volume create gv0 server1:/data/vg0 server2:/data/vg0"); server1.succeed("gluster volume create gv0 server1:/data/vg0 server2:/data/vg0")
$server1->succeed("gluster volume start gv0"); server1.succeed("gluster volume start gv0")
# test clients # test clients
$client1->waitForUnit("gluster.mount"); client1.wait_for_unit("gluster.mount")
$client2->waitForUnit("gluster.mount"); client2.wait_for_unit("gluster.mount")
$client1->succeed("echo test > /gluster/file1"); client1.succeed("echo test > /gluster/file1")
$client2->succeed("grep test /gluster/file1"); client2.succeed("grep test /gluster/file1")
''; '';
}) })

View file

@ -1,7 +1,14 @@
import ../make-test.nix ({ pkgs, ... } : import ../make-test-python.nix ({ pkgs, ... } :
let let
inherit (import ./../ssh-keys.nix pkgs) inherit (import ./../ssh-keys.nix pkgs)
snakeOilPrivateKey snakeOilPublicKey; snakeOilPrivateKey snakeOilPublicKey;
# don't check host keys or known hosts, use the snakeoil ssh key
ssh-config = builtins.toFile "ssh.conf" ''
UserKnownHostsFile=/dev/null
StrictHostKeyChecking=no
IdentityFile=~/.ssh/id_snakeoil
'';
in { in {
name = "google-oslogin"; name = "google-oslogin";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
@ -15,38 +22,49 @@ in {
client = { ... }: {}; client = { ... }: {};
}; };
testScript = '' testScript = ''
startAll; start_all()
$server->waitForUnit("mock-google-metadata.service"); server.wait_for_unit("mock-google-metadata.service")
$server->waitForOpenPort(80); server.wait_for_open_port(80)
# mockserver should return a non-expired ssh key for both mockuser and mockadmin # mockserver should return a non-expired ssh key for both mockuser and mockadmin
$server->succeed('${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockuser | grep -q "${snakeOilPublicKey}"'); server.succeed(
$server->succeed('${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockadmin | grep -q "${snakeOilPublicKey}"'); '${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockuser | grep -q "${snakeOilPublicKey}"'
)
server.succeed(
'${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockadmin | grep -q "${snakeOilPublicKey}"'
)
# install snakeoil ssh key on the client # install snakeoil ssh key on the client, and provision .ssh/config file
$client->succeed("mkdir -p ~/.ssh"); client.succeed("mkdir -p ~/.ssh")
$client->succeed("cat ${snakeOilPrivateKey} > ~/.ssh/id_snakeoil"); client.succeed(
$client->succeed("chmod 600 ~/.ssh/id_snakeoil"); "cat ${snakeOilPrivateKey} > ~/.ssh/id_snakeoil"
)
client.succeed("chmod 600 ~/.ssh/id_snakeoil")
client.succeed("cp ${ssh-config} ~/.ssh/config")
$client->waitForUnit("network.target"); client.wait_for_unit("network.target")
$server->waitForUnit("sshd.service"); server.wait_for_unit("sshd.service")
# we should not be able to connect as non-existing user # we should not be able to connect as non-existing user
$client->fail("ssh -o User=ghost -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server -i ~/.ssh/id_snakeoil 'true'"); client.fail("ssh ghost@server 'true'")
# we should be able to connect as mockuser # we should be able to connect as mockuser
$client->succeed("ssh -o User=mockuser -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server -i ~/.ssh/id_snakeoil 'true'"); client.succeed("ssh mockuser@server 'true'")
# but we shouldn't be able to sudo # but we shouldn't be able to sudo
$client->fail("ssh -o User=mockuser -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server -i ~/.ssh/id_snakeoil '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"); client.fail(
"ssh mockuser@server '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"
)
# we should also be able to log in as mockadmin # we should also be able to log in as mockadmin
$client->succeed("ssh -o User=mockadmin -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server -i ~/.ssh/id_snakeoil 'true'"); client.succeed("ssh mockadmin@server 'true'")
# pam_oslogin_admin.so should now have generated a sudoers file # pam_oslogin_admin.so should now have generated a sudoers file
$server->succeed("find /run/google-sudoers.d | grep -q '/run/google-sudoers.d/mockadmin'"); server.succeed("find /run/google-sudoers.d | grep -q '/run/google-sudoers.d/mockadmin'")
# and we should be able to sudo # and we should be able to sudo
$client->succeed("ssh -o User=mockadmin -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server -i ~/.ssh/id_snakeoil '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"); client.succeed(
"ssh mockadmin@server '/run/wrappers/bin/sudo /run/current-system/sw/bin/id' | grep -q 'root'"
)
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ...} : { import ./make-test-python.nix ({ pkgs, lib, ...} : {
name = "gotify-server"; name = "gotify-server";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ ma27 ]; maintainers = [ ma27 ];
@ -14,32 +14,32 @@ import ./make-test.nix ({ pkgs, lib, ...} : {
}; };
testScript = '' testScript = ''
startAll; machine.start()
$machine->waitForUnit("gotify-server"); machine.wait_for_unit("gotify-server.service")
$machine->waitForOpenPort(3000); machine.wait_for_open_port(3000)
my $token = $machine->succeed( token = machine.succeed(
"curl --fail -sS -X POST localhost:3000/application -F name=nixos " . "curl --fail -sS -X POST localhost:3000/application -F name=nixos "
'-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" ' . + '-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" '
'| jq .token | xargs echo -n' + "| jq .token | xargs echo -n"
); )
my $usertoken = $machine->succeed( usertoken = machine.succeed(
"curl --fail -sS -X POST localhost:3000/client -F name=nixos " . "curl --fail -sS -X POST localhost:3000/client -F name=nixos "
'-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" ' . + '-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" '
'| jq .token | xargs echo -n' + "| jq .token | xargs echo -n"
); )
$machine->succeed( machine.succeed(
"curl --fail -sS -X POST 'localhost:3000/message?token=$token' -H 'Accept: application/json' " . f"curl --fail -sS -X POST 'localhost:3000/message?token={token}' -H 'Accept: application/json' "
'-F title=Gotify -F message=Works' + "-F title=Gotify -F message=Works"
); )
my $title = $machine->succeed( title = machine.succeed(
"curl --fail -sS 'localhost:3000/message?since=0&token=$usertoken' | jq '.messages|.[0]|.title' | xargs echo -n" f"curl --fail -sS 'localhost:3000/message?since=0&token={usertoken}' | jq '.messages|.[0]|.title' | xargs echo -n"
); )
$title eq "Gotify" or die "Wrong title ($title), expected 'Gotify'!"; assert title == "Gotify"
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ... }: { import ./make-test-python.nix ({ pkgs, lib, ... }: {
name = "graylog"; name = "graylog";
meta.maintainers = with lib.maintainers; [ ma27 ]; meta.maintainers = with lib.maintainers; [ ma27 ];
@ -64,48 +64,52 @@ import ./make-test.nix ({ pkgs, lib, ... }: {
facility = "Test"; facility = "Test";
}); });
in '' in ''
$machine->start; machine.start()
$machine->waitForUnit("graylog.service"); machine.wait_for_unit("graylog.service")
$machine->waitForOpenPort(9000); machine.wait_for_open_port(9000)
$machine->succeed("curl -sSfL http://127.0.0.1:9000/"); machine.succeed("curl -sSfL http://127.0.0.1:9000/")
my $session = $machine->succeed("curl -X POST " session = machine.succeed(
. "-sSfL http://127.0.0.1:9000/api/system/sessions " "curl -X POST "
. "-d \$(cat ${payloads.login}) " + "-sSfL http://127.0.0.1:9000/api/system/sessions "
. "-H 'Content-Type: application/json' " + "-d $(cat ${payloads.login}) "
. "-H 'Accept: application/json' " + "-H 'Content-Type: application/json' "
. "-H 'x-requested-by: cli' " + "-H 'Accept: application/json' "
. "| jq .session_id | xargs echo" + "-H 'x-requested-by: cli' "
); + "| jq .session_id | xargs echo"
).rstrip()
chomp($session); machine.succeed(
"curl -X POST "
+ f"-sSfL http://127.0.0.1:9000/api/system/inputs -u {session}:session "
+ '-d $(cat ${payloads.input} | sed -e "s,@node@,$(cat /var/lib/graylog/server/node-id),") '
+ "-H 'Accept: application/json' "
+ "-H 'Content-Type: application/json' "
+ "-H 'x-requested-by: cli' "
)
$machine->succeed("curl -X POST " machine.wait_until_succeeds(
. "-sSfL http://127.0.0.1:9000/api/system/inputs -u $session:session " "test \"$(curl -sSfL 'http://127.0.0.1:9000/api/cluster/inputstates' "
. "-d \$(cat ${payloads.input} | sed -e \"s,\@node\@,\$(cat /var/lib/graylog/server/node-id),\") " + f"-u {session}:session "
. "-H 'Accept: application/json' " + "-H 'Accept: application/json' "
. "-H 'Content-Type: application/json' " + "-H 'Content-Type: application/json' "
. "-H 'x-requested-by: cli' " + "-H 'x-requested-by: cli'"
); + "| jq 'to_entries[]|.value|.[0]|.state' | xargs echo"
+ ')" = "RUNNING"'
)
$machine->waitUntilSucceeds("test \"\$(curl -sSfL 'http://127.0.0.1:9000/api/cluster/inputstates' " machine.succeed(
. "-u $session:session " "echo -n $(cat ${payloads.gelf_message}) | nc -w10 -u 127.0.0.1 12201"
. "-H 'Accept: application/json' " )
. "-H 'Content-Type: application/json' "
. "-H 'x-requested-by: cli'"
. "| jq 'to_entries[]|.value|.[0]|.state' | xargs echo"
. ")\" = \"RUNNING\""
);
$machine->succeed("echo -n \$(cat ${payloads.gelf_message}) | nc -w10 -u 127.0.0.1 12201"); machine.succeed(
'test "$(curl -X GET '
$machine->succeed("test \"\$(curl -X GET " + "-sSfL 'http://127.0.0.1:9000/api/search/universal/relative?query=*' "
. "-sSfL 'http://127.0.0.1:9000/api/search/universal/relative?query=*' " + f"-u {session}:session "
. "-u $session:session " + "-H 'Accept: application/json' "
. "-H 'Accept: application/json' " + "-H 'Content-Type: application/json' "
. "-H 'Content-Type: application/json' " + "-H 'x-requested-by: cli'"
. "-H 'x-requested-by: cli'" + ' | jq \'.total_results\' | xargs echo)" = "1"'
. " | jq '.total_results' | xargs echo)\" = \"1\"" )
);
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... }: import ./make-test-python.nix ({ pkgs, ... }:
let let
# Download Big Buck Bunny example, licensed under CC Attribution 3.0. # Download Big Buck Bunny example, licensed under CC Attribution 3.0.
testMkv = pkgs.fetchurl { testMkv = pkgs.fetchurl {
@ -19,7 +19,13 @@ in {
testScript = '' testScript = ''
# Test MP4 and MKV transcoding. Since this is a short clip, transcoding typically # Test MP4 and MKV transcoding. Since this is a short clip, transcoding typically
# only takes a few seconds. # only takes a few seconds.
$machine->succeed("HandBrakeCLI -i ${testMkv} -o test.mp4 -e x264 -q 20 -B 160"); start_all()
$machine->succeed("HandBrakeCLI -i ${testMkv} -o test.mkv -e x264 -q 20 -B 160");
machine.succeed(
"HandBrakeCLI -i ${testMkv} -o test.mp4 -e x264 -q 20 -B 160"
)
machine.succeed(
"HandBrakeCLI -i ${testMkv} -o test.mkv -e x264 -q 20 -B 160"
)
''; '';
}) })

View file

@ -1,6 +1,6 @@
# Test whether hibernation from partition works. # Test whether hibernation from partition works.
import ./make-test.nix (pkgs: { import ./make-test-python.nix (pkgs: {
name = "hibernate"; name = "hibernate";
nodes = { nodes = {
@ -28,16 +28,17 @@ import ./make-test.nix (pkgs: {
testScript = testScript =
'' ''
$machine->waitForUnit("multi-user.target"); machine.start()
$machine->succeed("mkswap /dev/vdb"); machine.wait_for_unit("multi-user.target")
$machine->succeed("swapon -a"); machine.succeed("mkswap /dev/vdb")
$machine->startJob("listener"); machine.succeed("swapon -a")
$machine->waitForOpenPort(4444); machine.start_job("listener")
$machine->succeed("systemctl hibernate &"); machine.wait_for_open_port(4444)
$machine->waitForShutdown; machine.succeed("systemctl hibernate &")
$probe->waitForUnit("multi-user.target"); machine.wait_for_shutdown()
$machine->start; probe.wait_for_unit("multi-user.target")
$probe->waitUntilSucceeds("echo test | nc machine 4444 -N"); machine.start()
probe.wait_until_succeeds("echo test | nc machine 4444 -N")
''; '';
}) })

View file

@ -1,5 +1,5 @@
# Test whether `houndd` indexes nixpkgs # Test whether `houndd` indexes nixpkgs
import ./make-test.nix ({ pkgs, ... } : { import ./make-test-python.nix ({ pkgs, ... } : {
name = "hound"; name = "hound";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ grahamc ]; maintainers = [ grahamc ];
@ -46,13 +46,14 @@ import ./make-test.nix ({ pkgs, ... } : {
}; };
}; };
testScript = testScript = ''
'' startAll; start_all()
$machine->waitForUnit("network.target"); machine.wait_for_unit("network.target")
$machine->waitForUnit("hound.service"); machine.wait_for_unit("hound.service")
$machine->waitForOpenPort(6080); machine.wait_for_open_port(6080)
$machine->waitUntilSucceeds('curl http://127.0.0.1:6080/api/v1/search\?stats\=fosho\&repos\=\*\&rng=%3A20\&q\=hi\&files\=\&i=nope | grep "Filename" | grep "hello"'); machine.wait_until_succeeds(
"curl http://127.0.0.1:6080/api/v1/search\?stats\=fosho\&repos\=\*\&rng=%3A20\&q\=hi\&files\=\&i=nope | grep 'Filename' | grep 'hello'"
''; )
'';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... }: { import ./make-test-python.nix ({ pkgs, ... }: {
name = "icingaweb2"; name = "icingaweb2";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ das_j ]; maintainers = [ das_j ];
@ -64,8 +64,8 @@ import ./make-test.nix ({ pkgs, ... }: {
}; };
testScript = '' testScript = ''
startAll(); start_all()
$icingaweb2->waitForUnit("multi-user.target"); icingaweb2.wait_for_unit("multi-user.target")
$icingaweb2->succeed("curl -sSf http://icingaweb2/authentication/login"); icingaweb2.succeed("curl -sSf http://icingaweb2/authentication/login")
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ... }: import ./make-test-python.nix ({ pkgs, lib, ... }:
with lib; with lib;
@ -18,17 +18,16 @@ with lib;
}; };
testScript = '' testScript = ''
subtest "machine with iftop enabled", sub { with subtest("machine with iftop enabled"):
$withIftop->waitForUnit("default.target"); withIftop.wait_for_unit("default.target")
# limit to eth1 (eth0 is the test driver's control interface) # limit to eth1 (eth0 is the test driver's control interface)
# and don't try name lookups # and don't try name lookups
$withIftop->succeed("su -l alice -c 'iftop -t -s 1 -n -i eth1'"); withIftop.succeed("su -l alice -c 'iftop -t -s 1 -n -i eth1'")
};
subtest "machine without iftop", sub { with subtest("machine without iftop"):
$withoutIftop->waitForUnit("default.target"); withoutIftop.wait_for_unit("default.target")
# check that iftop is there but user alice lacks capabilities # check that iftop is there but user alice lacks capabilitie
$withoutIftop->succeed("iftop -t -s 1 -n -i eth1"); withoutIftop.succeed("iftop -t -s 1 -n -i eth1")
$withoutIftop->fail("su -l alice -c 'iftop -t -s 1 -n -i eth1'"); withoutIftop.fail("su -l alice -c 'iftop -t -s 1 -n -i eth1'")
};
''; '';
}) })

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ... }: import ./make-test-python.nix ({ pkgs, lib, ... }:
{ {
name = "incron"; name = "incron";
@ -19,34 +19,34 @@ import ./make-test.nix ({ pkgs, lib, ... }:
}; };
testScript = '' testScript = ''
startAll; start_all()
$machine->waitForUnit("multi-user.target"); machine.wait_for_unit("multi-user.target")
$machine->waitForUnit("incron.service"); machine.wait_for_unit("incron.service")
$machine->succeed("test -d /test"); machine.succeed("test -d /test")
# create some activity for incron to monitor # create some activity for incron to monitor
$machine->succeed("touch /test/file"); machine.succeed("touch /test/file")
$machine->succeed("echo foo >> /test/file"); machine.succeed("echo foo >> /test/file")
$machine->succeed("mv /test/file /root"); machine.succeed("mv /test/file /root")
$machine->succeed("mv /root/file /test"); machine.succeed("mv /root/file /test")
$machine->sleep(1); machine.sleep(1)
# touch /test/file # touch /test/file
$machine->succeed("grep '/test/file IN_CREATE' /root/incron.log"); machine.succeed("grep '/test/file IN_CREATE' /root/incron.log")
# echo foo >> /test/file # echo foo >> /test/file
$machine->succeed("grep '/test/file IN_MODIFY' /root/incron.log"); machine.succeed("grep '/test/file IN_MODIFY' /root/incron.log")
$machine->succeed("grep '/test/file IN_CLOSE_WRITE' /root/incron.log"); machine.succeed("grep '/test/file IN_CLOSE_WRITE' /root/incron.log")
# mv /test/file /root # mv /test/file /root
$machine->succeed("grep '/test/file IN_MOVED_FROM' /root/incron.log"); machine.succeed("grep '/test/file IN_MOVED_FROM' /root/incron.log")
# mv /root/file /test # mv /root/file /test
$machine->succeed("grep '/test/file IN_MOVED_TO' /root/incron.log"); machine.succeed("grep '/test/file IN_MOVED_TO' /root/incron.log")
# ensure something unexpected is not present # ensure something unexpected is not present
$machine->fail("grep 'IN_OPEN' /root/incron.log"); machine.fail("grep 'IN_OPEN' /root/incron.log")
''; '';
}) })

View file

@ -1,6 +1,6 @@
# This test runs influxdb and checks if influxdb is up and running # This test runs influxdb and checks if influxdb is up and running
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "influxdb"; name = "influxdb";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ offline ]; maintainers = [ offline ];
@ -9,25 +9,32 @@ import ./make-test.nix ({ pkgs, ...} : {
nodes = { nodes = {
one = { ... }: { one = { ... }: {
services.influxdb.enable = true; services.influxdb.enable = true;
environment.systemPackages = [ pkgs.httpie ];
}; };
}; };
testScript = '' testScript = ''
startAll; import shlex
$one->waitForUnit("influxdb.service"); start_all()
one.wait_for_unit("influxdb.service")
# create database # create database
$one->succeed(q~ one.succeed(
curl -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE test" "curl -XPOST http://localhost:8086/query --data-urlencode 'q=CREATE DATABASE test'"
~); )
# write some points and run simple query # write some points and run simple query
$one->succeed(q~ out = one.succeed(
curl -XPOST 'http://localhost:8086/write?db=test' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000' "curl -XPOST 'http://localhost:8086/write?db=test' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'"
~); )
$one->succeed(q~
curl -GET 'http://localhost:8086/query' --data-urlencode "db=test" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west'" | grep "0\.64" qv = "SELECT value FROM cpu_load_short WHERE region='us-west'"
~); cmd = f'curl -GET "http://localhost:8086/query?db=test" --data-urlencode {shlex.quote("q="+ qv)}'
out = one.succeed(cmd)
assert "2015-06-11T20:46:02Z" in out
assert "0.64" in out
''; '';
}) })

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