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/modules/installer/tools/nixos-option.sh @nbp
# NixOS integration test driver
/nixos/lib/test-driver @tfc
# New NixOS modules
/nixos/modules/module-list.nix @Infinisil
@ -167,3 +170,8 @@
/nixos/modules/services/monitoring/prometheus/exporters.nix @WilliButz
/nixos/modules/services/monitoring/prometheus/exporters.xml @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 = ''
for f in $(find $out/bin/ $out/libexec/ -type f -executable); do
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/gsettings-schemas/${name}" \
--prefix XDG_DATA_DIRS : "${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" \
@ -102,7 +102,7 @@ preFixup = ''
</listitem>
<listitem xml:id="ssec-gnome-hooks-dconf">
<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>
</listitem>
<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:
```
$ nix-env -f "<nixpkgs>" -qaP -A haskellPackages
haskellPackages.a50 a50-0.5
haskellPackages.abacate haskell-abacate-0.0.0.0
haskellPackages.abcBridge haskell-abcBridge-0.12
haskellPackages.afv afv-0.1.1
haskellPackages.alex alex-3.1.4
haskellPackages.Allure Allure-0.4.101.1
haskellPackages.alms alms-0.6.7
[... some 8000 entries omitted ...]
haskellPackages.a50 a50-0.5
haskellPackages.AAI AAI-0.2.0.1
haskellPackages.abacate abacate-0.0.0.0
haskellPackages.abc-puzzle abc-puzzle-0.2.1
haskellPackages.abcBridge abcBridge-0.15
haskellPackages.abcnotation abcnotation-1.9.0
haskellPackages.abeson abeson-0.1.0.1
[... some 14000 entries omitted ...]
```
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:
```
$ nix-env -f "<nixpkgs>" -qaP -A haskell.compiler
haskell.compiler.ghc6104 ghc-6.10.4
haskell.compiler.ghc6123 ghc-6.12.3
haskell.compiler.ghc704 ghc-7.0.4
haskell.compiler.ghc722 ghc-7.2.2
haskell.compiler.ghc742 ghc-7.4.2
haskell.compiler.ghc763 ghc-7.6.3
haskell.compiler.ghc784 ghc-7.8.4
haskell.compiler.ghc7102 ghc-7.10.2
haskell.compiler.ghcHEAD ghc-7.11.20150402
haskell.compiler.ghcNokinds ghc-nokinds-7.11.20150704
haskell.compiler.ghcjs ghcjs-0.1.0
haskell.compiler.jhc jhc-0.8.2
haskell.compiler.uhc uhc-1.1.9.0
haskell.compiler.ghc822 ghc-8.2.2
haskell.compiler.integer-simple.ghc822 ghc-8.2.2
haskell.compiler.ghc822Binary ghc-8.2.2-binary
haskell.compiler.ghc844 ghc-8.4.4
haskell.compiler.ghc863Binary ghc-8.6.3-binary
haskell.compiler.ghc864 ghc-8.6.4
haskell.compiler.integer-simple.ghc864 ghc-8.6.4
haskell.compiler.ghc865 ghc-8.6.5
haskell.compiler.integer-simple.ghc865 ghc-8.6.5
haskell.compiler.ghc881 ghc-8.8.1
haskell.compiler.integer-simple.ghc881 ghc-8.8.1
haskell.compiler.ghcHEAD ghc-8.9.20190601
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

View file

@ -244,7 +244,7 @@
</question>
<answer>
<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>
</answer>
</qandaentry>

View file

@ -1717,7 +1717,7 @@ someVar=$(stripHash $name)
</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>

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:
<programlisting>
{
allowUnfreePredicate = (pkg: builtins.elem
(pkg.pname or (builtins.parseDrvName pkg.name).name) [
"flashplayer"
"vscode"
]);
allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"flashplayer"
"vscode"
];
}
</programlisting>
</para>
@ -217,7 +216,7 @@
The following configuration example only allows insecure packages with very short names:
<programlisting>
{
allowInsecurePredicate = (pkg: (builtins.stringLength (builtins.parseDrvName pkg.name).name) &lt;= 5);
allowInsecurePredicate = pkg: builtins.stringLength (lib.getName pkg) &lt;= 5;
}
</programlisting>
</para>

View file

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

View file

@ -472,6 +472,23 @@ rec {
*/
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
derivation's "name" attribute and extracts the version part from that
argument.

View file

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

View file

@ -26,7 +26,7 @@ let
"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;
@ -45,6 +45,7 @@ in {
x86_64 = filterDoubles predicates.isx86_64;
mips = filterDoubles predicates.isMips;
riscv = filterDoubles predicates.isRiscV;
vc4 = filterDoubles predicates.isVc4;
cygwin = filterDoubles predicates.isCygwin;
darwin = filterDoubles predicates.isDarwin;

View file

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

View file

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

View file

@ -112,6 +112,8 @@ rec {
msp430 = { bits = 16; significantByte = littleEndian; family = "msp430"; };
avr = { bits = 8; family = "avr"; };
vc4 = { bits = 32; significantByte = littleEndian; family = "vc4"; };
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 = {
name = "dadada";
email = "dadada@dadada.li";
@ -1780,6 +1790,12 @@
githubId = 875324;
name = "David Johnson";
};
dmrauh = {
email = "dmrauh@posteo.de";
github = "dmrauh";
githubId = 37698547;
name = "Dominik Michael Rauh";
};
dmvianna = {
email = "dmlvianna@gmail.com";
github = "dmvianna";
@ -2515,6 +2531,7 @@
gazally = {
email = "gazally@runbox.com";
github = "gazally";
githubId = 16470252;
name = "Gemini Lasswell";
};
gebner = {
@ -3594,6 +3611,12 @@
github = "klntsky";
githubId = 18447310;
};
kmcopper = {
email = "kmcopper@danwin1210.me";
name = "Kyle Copperfield";
github = "kmcopper";
githubId = 57132115;
};
kmeakin = {
email = "karlwfmeakin@gmail.com";
name = "Karl Meakin";
@ -4139,6 +4162,12 @@
github = "marcweber";
githubId = 34086;
name = "Marc Weber";
};
marcus7070 = {
email = "marcus@geosol.com.au";
github = "marcus7070";
githubId = 50230945;
name = "Marcus Boyd";
};
marenz = {
email = "marenz@arkom.men";
@ -4478,6 +4507,12 @@
githubId = 16974598;
name = "Mike Playle";
};
mkaito = {
email = "chris@mkaito.net";
github = "mkaito";
githubId = 20434;
name = "Christian Höppner";
};
mkazulak = {
email = "kazulakm@gmail.com";
github = "mulderr";
@ -4517,6 +4552,12 @@
githubId = 117842;
name = "Henri Bourcereau";
};
mmilata = {
email = "martin@martinmilata.cz";
github = "mmilata";
gitHubId = 85857;
name = "Martin Milata";
};
mmlb = {
email = "me.mmlb@mmlb.me";
github = "mmlb";
@ -4631,6 +4672,12 @@
githubId = 2881922;
name = "Francis St-Amour";
};
mtrsk = {
email = "marcos.schonfinkel@protonmail.com";
github = "mtrsk";
githubId = 16356569;
name = "Marcos Benevides";
};
mredaelli = {
email = "massimo@typish.io";
github = "mredaelli";
@ -6099,7 +6146,7 @@
name = "Shahrukh Khan";
};
shanemikel = {
email = "shanemikel1@gmail.com";
email = "shanepearlman@pm.me";
github = "shanemikel";
githubId = 6720672;
name = "Shane Pearlman";
@ -6720,6 +6767,12 @@
githubId = 42933;
name = "Andrew Childs";
};
thefenriswolf = {
email = "stefan.rohrbacher97@gmail.com";
github = "thefenriswolf";
githubId = "8547242";
name = "Stefan Rohrbacher";
};
thesola10 = {
email = "thesola10@bobile.fr";
github = "thesola10";
@ -7611,4 +7664,16 @@
githubId = 50867187;
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: {
name = package.name;
pname = (builtins.parseDrvName package.name).name;
pname = pkgs.lib.getName package;
updateScript = map builtins.toString (pkgs.lib.toList package.updateScript);
};

View file

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

View file

@ -163,6 +163,57 @@
time during the releases development (if viable).
</para>
</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>
</section>

View file

@ -86,7 +86,7 @@ let
optionsList = lib.sort optionLess optionsListDesc;
# 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);

View file

@ -3,7 +3,6 @@ from contextlib import contextmanager, _GeneratorContextManager
from xml.sax.saxutils import XMLGenerator
import _thread
import atexit
import json
import os
import ptpython.repl
import pty
@ -16,7 +15,9 @@ import sys
import tempfile
import time
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 = {
"A": "shift-a",
@ -92,6 +93,10 @@ def eprint(*args: object, **kwargs: Any) -> None:
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]:
global log
log.log("starting VDE switch for network {}".format(vlan_nr))
@ -216,7 +221,7 @@ class Machine:
return path
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.connected = False
@ -525,6 +530,33 @@ class Machine:
if ret.returncode != 0:
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:
"""Debugging: Dump the contents of the TTY<n>
"""
@ -771,7 +803,9 @@ def run_tests() -> None:
machine.execute("sync")
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

View file

@ -122,7 +122,7 @@ in
description = ''
Include ~/bin/ in $PATH.
'';
default = true;
default = false;
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 {
assertions = [
{
assertion = with config.services.xserver.displayManager; gdm.enable -> !gdm.wayland;
message = "NVIDIA drivers don't support wayland, set services.xserver.displayManager.gdm.wayland=false";
assertion = with config.services.xserver.displayManager; gdm.nvidiaWayland -> cfg.modesetting.enable;
message = "You cannot use wayland with GDM without modesetting enabled for NVIDIA drivers, set `hardware.nvidia.modesetting.enable = true`";
}
{
assertion = !optimusCfg.enable ||
(optimusCfg.nvidiaBusId != "" && optimusCfg.intelBusId != "");

View file

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

View file

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

View file

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

View file

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

View file

@ -32,13 +32,13 @@ in
environment.etc = optionals (cfg.profiles != {})
(mapAttrsToList mkDconfProfile cfg.profiles);
services.dbus.packages = [ pkgs.gnome3.dconf ];
services.dbus.packages = [ pkgs.dconf ];
# For dconf executable
environment.systemPackages = [ pkgs.gnome3.dconf ];
environment.systemPackages = [ pkgs.dconf ];
# 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;
let
cfg = config.networking.defaultMailServer;
cfg = config.services.ssmtp;
in
{
options = {
networking.defaultMailServer = {
services.ssmtp = {
directDelivery = mkOption {
enable = mkOption {
type = types.bool;
default = false;
description = ''
@ -29,7 +27,7 @@ in
<command>sendmail</command> or <command>postfix</command> on
your machine, set this option to <literal>true</literal>, and
set the option
<option>networking.defaultMailServer.hostName</option> to the
<option>services.ssmtp.hostName</option> to the
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 {
name = "ssmtp-authpass";
text = cfg.authPass;

View file

@ -10,6 +10,9 @@ with lib;
(mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
(mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ])
(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" ]
(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 [ "systemd" "generator-packages" ] "Use systemd.packages instead.")
(mkRemovedOptionModule [ "fonts" "enableCoreFonts" ] "Use fonts.fonts = [ pkgs.corefonts ]; instead.")
(mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.")
# ZSH
(mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ])
@ -279,6 +283,13 @@ with lib;
# BLCR
(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
(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.")

View file

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

View file

@ -8,15 +8,11 @@ let
mysql = cfg.package;
isMariaDB =
let
pName = _p: (builtins.parseDrvName (_p.name)).name;
in pName mysql == pName pkgs.mariadb;
isMariaDB = lib.getName mysql == lib.getName pkgs.mariadb;
isMysqlAtLeast57 =
let
pName = _p: (builtins.parseDrvName (_p.name)).name;
in (pName mysql == pName pkgs.mysql57)
&& ((builtins.compareVersions mysql.version "5.7") >= 0);
(lib.getName mysql == lib.getName pkgs.mysql57)
&& (builtins.compareVersions mysql.version "5.7" >= 0);
mysqldOptions =
"--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 = {
DynamicUser = true;
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";
# 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 {
type = types.lines;
default = "";
type = with types; nullOr lines;
default = null;
example = ''
[General]
ControllerMode = bredr
'';
description = ''
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
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 {
source = pkgs.writeText "main.conf" ''
[Policy]
AutoEnable=${lib.boolToString cfg.powerOnBoot}
${cfg.extraConfig}
'';
source = pkgs.writeText "main.conf" (generators.toINI { } cfg.config + optionalString (cfg.extraConfig != null) cfg.extraConfig);
target = "bluetooth/main.conf";
};

View file

@ -44,7 +44,8 @@ in
serviceConfig = {
DynamicUser = true;
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;
ExecStart = "${gitea.bin}/bin/gitea web";
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 = {

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;
})] ++ [(mkIf config.services.rspamd.enable {
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:
mkExporterConf {
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;
default = pkgs.samba;
defaultText = "pkgs.samba";
example = literalExample "pkgs.samba3";
example = literalExample "pkgs.samba4Full";
description = ''
Defines which package should be used for the samba server.
'';

View file

@ -4,7 +4,7 @@ with pkgs;
with lib;
let
cfg = config.networking.connman;
cfg = config.services.connman;
configFile = pkgs.writeText "connman.conf" ''
[General]
NetworkInterfaceBlacklist=${concatStringsSep "," cfg.networkInterfaceBlacklist}
@ -17,7 +17,7 @@ in {
options = {
networking.connman = {
services.connman = {
enable = mkOption {
type = types.bool;
@ -71,13 +71,13 @@ in {
assertions = [{
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;
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;
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 ];

View file

@ -137,7 +137,7 @@ in
];
services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveDNSChainQueries {
forwardZones =
forwardZonesRecurse =
{ bit = "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 {
type = types.attrs;
default = {};
description = ''
DNS zones to be forwarded to other authoritative servers.
'';
};
forwardZonesRecurse = mkOption {
type = types.attrs;
example = { eth = "127.0.0.1:5353"; };
default = {};
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-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;
dnssec = cfg.dnssecValidation;
serve-rfc1918 = cfg.serveRFC1918;

View file

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

View file

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

View file

@ -84,12 +84,6 @@ GRANT ALL PRIVILEGES ON matomo.* TO 'matomo'@'localhost';
<title>Issues</title>
<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>
<para>
Matomo will warn you that the JavaScript tracker is not writable. This is

View file

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

View file

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

View file

@ -27,20 +27,13 @@ in
example = "vlc";
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 [
(mkIf cfg.enable {
@ -173,12 +166,10 @@ in
# Phonon audio backend
++ 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" && cfg.enableQt4Support) pkgs.phonon-backend-vlc
# 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.hardware.pulseaudio.enable plasma-pa
++ lib.optional config.powerManagement.enable powerdevil

View file

@ -31,6 +31,44 @@ let
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
{
@ -88,11 +126,21 @@ in
wayland = mkOption {
default = true;
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;
};
nvidiaWayland = mkOption {
default = false;
description = ''
Whether to allow wayland to be used with the proprietary
NVidia graphics driver.
'';
};
autoSuspend = mkOption {
default = true;
description = ''
@ -156,6 +204,8 @@ in
cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF
yes
EOF
'' + optionalString hasDefaultUserSession ''
${setSessionScript}/bin/set-session ${defaultSessionName}
'';
};
@ -197,6 +247,19 @@ in
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" ];
programs.dconf.profiles.gdm =
@ -218,7 +281,7 @@ in
customDconfDb = pkgs.stdenv.mkDerivation {
name = "gdm-dconf-db";
buildCommand = ''
${pkgs.gnome3.dconf}/bin/dconf compile $out ${customDconf}/dconf
${pkgs.dconf}/bin/dconf compile $out ${customDconf}/dconf
'';
};
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;
grubTarget = f (grub.grubTarget or "");
shell = "${pkgs.runtimeShell}";
fullName = (builtins.parseDrvName realGrub.name).name;
fullVersion = (builtins.parseDrvName realGrub.name).version;
fullName = lib.getName realGrub;
fullVersion = lib.getVersion realGrub;
grubEfi = f grubEfi;
grubTargetEfi = if cfg.efiSupport && (cfg.version == 2) then f (grubEfi.grubTarget or "") else "";
bootPath = args.path;

View file

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

View file

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

View file

@ -50,7 +50,10 @@ with lib;
${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;
system.activationScripts.systemd-timesyncd-migration = mkIf (versionOlder config.system.stateVersion "19.09") ''

View file

@ -149,7 +149,7 @@ let
--setenv PATH="$PATH" \
${optionalString cfg.ephemeral "--ephemeral"} \
${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then
''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else ""
''--capability="${concatStringsSep "," cfg.additionalCapabilities}"'' else ""
} \
${if cfg.tmpfs != null && cfg.tmpfs != [] then
''--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;
description = ''
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"
fi
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 = {
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.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.
networking.wireless.enable = mkVMOverride false;
networking.connman.enable = mkVMOverride false;
services.connman.enable = mkVMOverride false;
# Speed up booting by not waiting for ARP.
networking.dhcpcd.extraConfig = "noarp";

View file

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

View file

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

View file

@ -28,7 +28,7 @@ in
babeld = handleTest ./babeld.nix {};
bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64
beanstalkd = handleTest ./beanstalkd.nix {};
beegfs = handleTestOn ["x86_64-linux"] ./beegfs.nix {}; # beegfs is unsupported on aarch64
bees = handleTest ./bees.nix {};
bind = handleTest ./bind.nix {};
bittorrent = handleTest ./bittorrent.nix {};
#blivet = handleTest ./blivet.nix {}; # broken since 2017-07024
@ -53,8 +53,7 @@ in
containers-extra_veth = handleTest ./containers-extra_veth.nix {};
containers-hosts = handleTest ./containers-hosts.nix {};
containers-imperative = handleTest ./containers-imperative.nix {};
containers-ipv4 = handleTest ./containers-ipv4.nix {};
containers-ipv6 = handleTest ./containers-ipv6.nix {};
containers-ip = handleTest ./containers-ip.nix {};
containers-macvlans = handleTest ./containers-macvlans.nix {};
containers-physical_interfaces = handleTest ./containers-physical_interfaces.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 {};
orangefs = handleTest ./orangefs.nix {};
os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
osquery = handleTest ./osquery.nix {};
osrm-backend = handleTest ./osrm-backend.nix {};
overlayfs = handleTest ./overlayfs.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";
@ -29,27 +29,34 @@ import ./make-test.nix ({ lib, ... }:
testScript =
let
withRetry = content: maxTests: sleepTime: ''
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;
someContentIsShared = loc: pkgs.writeShellScript "some-content-is-shared" ''
[[ $(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 ''
# 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("cp --reflink=never /aux1/dedup-me-1 /aux1/dedup-me-2");
$machine->succeed("cp --reflink=never /aux1/* /aux2/");
$machine->succeed("sync");
$machine->fail(q(${someContentIsShared "/aux1"}));
$machine->fail(q(${someContentIsShared "/aux2"}));
$machine->succeed("systemctl start beesd\@aux1.service");
machine.succeed(
"dd if=/dev/urandom of=/aux1/dedup-me-1 bs=1M count=8",
"cp --reflink=never /aux1/dedup-me-1 /aux1/dedup-me-2",
"cp --reflink=never /aux1/* /aux2/",
"sync",
)
machine.fail(
"${someContentIsShared "/aux1"}",
"${someContentIsShared "/aux2"}",
)
machine.succeed("systemctl start beesd@aux1.service")
# assert that "Set Shared" column is nonzero
$machine->succeed(q(${withRetry (someContentIsShared "/aux1") 20 2}));
$machine->fail(q(${someContentIsShared "/aux2"}));
machine.wait_until_succeeds(
"${someContentIsShared "/aux1"}",
)
machine.fail("${someContentIsShared "/aux2"}")
# 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";
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`";
in
''
$machine->start();
$machine->waitForUnit("clickhouse.service");
$machine->waitForOpenPort(9000);
machine.start()
machine.wait_for_unit("clickhouse.service")
machine.wait_for_open_port(9000)
$machine->succeed("cat ${tableDDL} | clickhouse-client");
$machine->succeed("cat ${insertQuery} | clickhouse-client");
$machine->succeed("cat ${selectQuery} | clickhouse-client | grep foo");
machine.succeed(
"cat ${tableDDL} | clickhouse-client"
)
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";
@ -35,20 +35,18 @@ import ./make-test.nix ({ pkgs, lib, ... }:
};
testScript = ''
startAll();
start_all()
subtest "CodiMD sqlite", sub {
$codimdSqlite->waitForUnit("codimd.service");
$codimdSqlite->waitForOpenPort(3000);
$codimdSqlite->waitUntilSucceeds("curl -sSf http://localhost:3000/new");
};
with subtest("CodiMD sqlite"):
codimdSqlite.wait_for_unit("codimd.service")
codimdSqlite.wait_for_open_port(3000)
codimdSqlite.wait_until_succeeds("curl -sSf http://localhost:3000/new")
subtest "CodiMD postgres", sub {
$codimdPostgres->waitForUnit("postgresql.service");
$codimdPostgres->waitForUnit("codimd.service");
$codimdPostgres->waitForOpenPort(5432);
$codimdPostgres->waitForOpenPort(3000);
$codimdPostgres->waitUntilSucceeds("curl -sSf http://localhost:3000/new");
};
with subtest("CodiMD postgres"):
codimdPostgres.wait_for_unit("postgresql.service")
codimdPostgres.wait_for_unit("codimd.service")
codimdPostgres.wait_for_open_port(5432)
codimdPostgres.wait_for_open_port(3000)
codimdPostgres.wait_until_succeeds("curl -sSf http://localhost:3000/new")
'';
})

View file

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

View file

@ -1,6 +1,6 @@
# Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : {
import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-ephemeral";
machine = { pkgs, ... }: {
@ -16,10 +16,10 @@ import ./make-test.nix ({ pkgs, ...} : {
services.nginx = {
enable = true;
virtualHosts.localhost = {
root = (pkgs.runCommand "localhost" {} ''
root = pkgs.runCommand "localhost" {} ''
mkdir "$out"
echo hello world > "$out/index.html"
'');
'';
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
@ -28,29 +28,27 @@ import ./make-test.nix ({ pkgs, ...} : {
};
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
$machine->succeed("ls /run/containers/webserver");
with subtest("Container got its own root folder"):
machine.succeed("ls /run/containers/webserver")
# Check that container persistent directory is not created
$machine->fail("ls /var/lib/containers/webserver");
with subtest("Container persistent directory is not created"):
machine.fail("ls /var/lib/containers/webserver")
# 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");
ip = machine.succeed("nixos-container show-ip webserver").rstrip()
machine.succeed(f"ping -n -c1 {ip}")
machine.succeed(f"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");
with subtest("Stop the container"):
machine.succeed("nixos-container stop webserver")
machine.fail(f"curl --fail --connect-timeout 2 http://{ip}/ > /dev/null")
# Check that container's root folder was removed
$machine->fail("ls /run/containers/webserver");
with subtest("Container's root folder was removed"):
machine.fail("ls /run/containers/webserver")
'';
})

View file

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

View file

@ -1,6 +1,6 @@
# Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : {
import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-imperative";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ aristid aszlig eelco kampfschlaefer ];
@ -36,95 +36,99 @@ import ./make-test.nix ({ pkgs, ...} : {
};
testScript = let
tmpfilesContainerConfig = pkgs.writeText "container-config-tmpfiles" ''
{
systemd.tmpfiles.rules = [ "d /foo - - - - -" ];
systemd.services.foo = {
serviceConfig.Type = "oneshot";
script = "ls -al /foo";
wantedBy = [ "multi-user.target" ];
};
}
''; in
''
# Make sure we have a NixOS tree (required by nixos-container create).
$machine->succeed("PAGER=cat nix-env -qa -A nixos.hello >&2");
tmpfilesContainerConfig = pkgs.writeText "container-config-tmpfiles" ''
{
systemd.tmpfiles.rules = [ "d /foo - - - - -" ];
systemd.services.foo = {
serviceConfig.Type = "oneshot";
script = "ls -al /foo";
wantedBy = [ "multi-user.target" ];
};
}
'';
in ''
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")
# Create some containers imperatively.
my $id1 = $machine->succeed("nixos-container create foo --ensure-unique-name");
chomp $id1;
$machine->log("created container $id1");
id1, id2 = None, None
my $id2 = $machine->succeed("nixos-container create foo --ensure-unique-name");
chomp $id2;
$machine->log("created container $id2");
with subtest("Create some containers imperatively"):
id1 = machine.succeed("nixos-container create foo --ensure-unique-name").rstrip()
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.
$machine->succeed(
"mv /var/lib/containers/$id2 /id2-bindmount",
"mount --bind /id2-bindmount /var/lib/containers/$id1"
);
assert id1 != id2
my $ip1 = $machine->succeed("nixos-container show-ip $id1");
chomp $ip1;
my $ip2 = $machine->succeed("nixos-container show-ip $id2");
chomp $ip2;
die if $ip1 eq $ip2;
with subtest(f"Put the root of {id2} into a bind mount"):
machine.succeed(
f"mv /var/lib/containers/{id2} /id2-bindmount",
f"mount --bind /id2-bindmount /var/lib/containers/{id1}",
)
# Create a directory and a file we can later check if it still exists
# after destruction of the container.
$machine->succeed(
"mkdir /nested-bindmount",
"echo important data > /nested-bindmount/dummy",
);
ip1 = machine.succeed(f"nixos-container show-ip {id1}").rstrip()
ip2 = machine.succeed(f"nixos-container show-ip {id2}").rstrip()
assert ip1 != ip2
# Create a directory with a dummy file and bind-mount it into both
# containers.
foreach ($id1, $id2) {
my $importantPath = "/var/lib/containers/$_/very/important/data";
$machine->succeed(
"mkdir -p $importantPath",
"mount --bind /nested-bindmount $importantPath"
);
}
with subtest(
"Create a directory and a file we can later check if it still exists "
+ "after destruction of the container"
):
machine.succeed("mkdir /nested-bindmount")
machine.succeed("echo important data > /nested-bindmount/dummy")
# Start one of them.
$machine->succeed("nixos-container start $id1");
with subtest(
"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.
$machine->succeed("nixos-container run $id1 -- uname") =~ /Linux/ or die;
with subtest("Start one of them"):
machine.succeed(f"nixos-container start {id1}")
# Execute a nix command via the root shell. (regression test for #40355)
$machine->succeed("nixos-container run $id1 -- nix-instantiate -E 'derivation { name = \"empty\"; builder = \"false\"; system = \"false\"; }'");
with subtest("Execute commands via the root shell"):
assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")
# Stop and start (regression test for #4989)
$machine->succeed("nixos-container stop $id1");
$machine->succeed("nixos-container start $id1");
with subtest("Execute a nix command via the root shell. (regression test for #40355)"):
machine.succeed(
f"nixos-container run {id1} -- nix-instantiate -E "
+ '\'derivation { name = "empty"; builder = "false"; system = "false"; }\' '
)
# Ensure tmpfiles are present
$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");
with subtest("Stop and start (regression test for #4989)"):
machine.succeed(f"nixos-container stop {id1}")
machine.succeed(f"nixos-container start {id1}")
# Execute commands via the root shell.
$machine->succeed("nixos-container run $id1 -- uname") =~ /Linux/ or die;
with subtest("tmpfiles are present"):
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.
$machine->succeed("nixos-container destroy $id1");
$machine->succeed("nixos-container destroy $id2");
with subtest("Execute commands via the root shell"):
assert "Linux" in machine.succeed(f"nixos-container run {id1} -- uname")
$machine->succeed(
# Check whether destruction of any container has killed important data
"grep -qF 'important data' /nested-bindmount/dummy",
# Ensure that the container path is gone
"test ! -e /var/lib/containers/$id1"
);
with subtest("Destroy the containers"):
for id in id1, id2:
machine.succeed(f"nixos-container destroy {id}")
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
client_base = {
containers.test1 = {
autoStart = true;
config = {
@ -48,18 +48,25 @@ in {
c1System = nodes.client_c1.config.system.build.toplevel;
c2System = nodes.client_c2.config.system.build.toplevel;
in ''
$client->start();
$client->waitForUnit("default.target");
$client->succeed("[[ \$(nixos-container run test1 cat /etc/check) == client_base ]] >&2");
client.start()
client.wait_for_unit("default.target")
$client->succeed("${c1System}/bin/switch-to-configuration test >&2");
$client->succeed("[[ \$(nixos-container run test1 cat /etc/check) == client_c1 ]] >&2");
$client->succeed("systemctl status httpd -M test1 >&2");
assert "client_base" in client.succeed("nixos-container run test1 cat /etc/check")
$client->succeed("${c2System}/bin/switch-to-configuration test >&2");
$client->succeed("[[ \$(nixos-container run test1 cat /etc/check) == client_c2 ]] >&2");
$client->fail("systemctl status httpd -M test1 >&2");
$client->succeed("systemctl status nginx -M test1 >&2");
with subtest("httpd is available after activating config1"):
client.succeed(
"${c1System}/bin/switch-to-configuration test >&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.
import ./make-test.nix ({ pkgs, ...} : {
import ./make-test-python.nix ({ pkgs, ...} : {
name = "containers-tmpfs";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ kampka ];
@ -31,49 +31,63 @@ import ./make-test.nix ({ pkgs, ...} : {
virtualisation.pathsInNixDB = [ pkgs.stdenv ];
};
testScript =
''
$machine->waitForUnit("default.target");
$machine->succeed("nixos-container list") =~ /tmpfs/ or die;
testScript = ''
machine.wait_for_unit("default.target")
assert "tmpfs" in machine.succeed("nixos-container list")
# Start the tmpfs container.
#$machine->succeed("nixos-container status tmpfs") =~ /up/ or die;
# 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");
with subtest("tmpfs container is up"):
assert "up" in machine.succeed("nixos-container status tmpfs")
# Verify that /some/random/path is writable and that files created there
# are not in the hosts container dir but in the tmpfs
$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");
def tmpfs_cmd(command):
return f"nixos-container run tmpfs -- {command} 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
# are not visible to the container as the do not exist in the tmpfs
$machine->succeed("touch /var/lib/containers/tmpfs/var/test.file");
with subtest("/var is mounted as a tmpfs"):
machine.succeed(tmpfs_cmd("mountpoint -q /var"))
$machine->succeed("test -e /var/lib/containers/tmpfs/var/test.file");
$machine->succeed("ls -l /var/lib/containers/tmpfs/var/ | grep -q test.file 2>/dev/null");
with subtest("/var/log is mounted as a tmpfs"):
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";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ flokli ];
@ -45,18 +45,20 @@ import ./make-test.nix ({ pkgs, ...} : {
};
testScript = ''
startAll;
start_all()
$simple->waitForUnit("deluged");
$simple->waitForUnit("delugeweb");
$simple->waitForOpenPort("8112");
$declarative->waitForUnit("network.target");
$declarative->waitUntilSucceeds("curl --fail http://simple:8112");
simple.wait_for_unit("deluged")
simple.wait_for_unit("delugeweb")
simple.wait_for_open_port("8112")
declarative.wait_for_unit("network.target")
declarative.wait_until_succeeds("curl --fail http://simple:8112")
$declarative->waitForUnit("deluged");
$declarative->waitForUnit("delugeweb");
$declarative->waitUntilSucceeds("curl --fail http://declarative:3142");
$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.wait_for_unit("deluged")
declarative.wait_for_unit("delugeweb")
declarative.wait_until_succeeds("curl --fail http://declarative:3142")
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'"
)
'';
})

View file

@ -1,6 +1,6 @@
# This test runs docker-registry and check if it works
import ./make-test.nix ({ pkgs, ...} : {
import ./make-test-python.nix ({ pkgs, ...} : {
name = "docker-registry";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ globin ma27 ironpinguin ];
@ -28,36 +28,34 @@ import ./make-test.nix ({ pkgs, ...} : {
};
testScript = ''
$client1->start();
$client1->waitForUnit("docker.service");
$client1->succeed("tar cv --files-from /dev/null | docker import - scratch");
$client1->succeed("docker tag scratch registry:8080/scratch");
client1.start()
client1.wait_for_unit("docker.service")
client1.succeed("tar cv --files-from /dev/null | docker import - scratch")
client1.succeed("docker tag scratch registry:8080/scratch")
$registry->start();
$registry->waitForUnit("docker-registry.service");
$registry->waitForOpenPort("8080");
$client1->succeed("docker push registry:8080/scratch");
registry.start()
registry.wait_for_unit("docker-registry.service")
registry.wait_for_open_port("8080")
client1.succeed("docker push registry:8080/scratch")
$client2->start();
$client2->waitForUnit("docker.service");
$client2->succeed("docker pull registry:8080/scratch");
$client2->succeed("docker images | grep scratch");
client2.start()
client2.wait_for_unit("docker.service")
client2.succeed("docker pull registry:8080/scratch")
client2.succeed("docker images | grep scratch")
$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\')'
);
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')"
)
$registry->systemctl("start docker-registry-garbage-collect.service");
$registry->waitUntilFails("systemctl status docker-registry-garbage-collect.service");
$registry->waitForUnit("docker-registry.service");
registry.systemctl("start docker-registry-garbage-collect.service")
registry.wait_until_fails("systemctl status docker-registry-garbage-collect.service")
registry.wait_for_unit("docker-registry.service")
$registry->fail(
'ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data'
);
registry.fail("ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data")
$client1->succeed("docker push registry:8080/scratch");
$registry->succeed(
'ls -l /var/lib/docker-registry/docker/registry/v2/blobs/sha256/*/*/data'
);
client1.succeed("docker push registry:8080/scratch")
registry.succeed(
"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";
machine = { pkgs, ... }: {
@ -66,12 +66,12 @@ import ./make-test.nix {
};
testScript = ''
$machine->waitForUnit('postfix.service');
$machine->waitForUnit('dovecot2.service');
$machine->succeed('send-testmail');
$machine->succeed('send-lda');
$machine->waitUntilFails('[ "$(postqueue -p)" != "Mail queue is empty" ]');
$machine->succeed('test-imap');
$machine->succeed('test-pop');
machine.wait_for_unit("postfix.service")
machine.wait_for_unit("dovecot2.service")
machine.succeed("send-testmail")
machine.succeed("send-lda")
machine.wait_until_fails('[ "$(postqueue -p)" != "Mail queue is empty" ]')
machine.succeed("test-imap")
machine.succeed("test-pop")
'';
}

View file

@ -1,6 +1,6 @@
# 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 {
buildInputs = [ pkgs.openssl ];
@ -129,29 +129,26 @@ in {
};
testScript = ''
subtest "should start etcd cluster", sub {
$node1->start();
$node2->start();
$node1->waitForUnit("etcd.service");
$node2->waitForUnit("etcd.service");
$node2->waitUntilSucceeds("etcdctl cluster-health");
$node1->succeed("etcdctl set /foo/bar 'Hello world'");
$node2->succeed("etcdctl get /foo/bar | grep 'Hello world'");
};
with subtest("should start etcd cluster"):
node1.start()
node2.start()
node1.wait_for_unit("etcd.service")
node2.wait_for_unit("etcd.service")
node2.wait_until_succeeds("etcdctl cluster-health")
node1.succeed("etcdctl set /foo/bar 'Hello world'")
node2.succeed("etcdctl get /foo/bar | grep 'Hello world'")
subtest "should add another member", sub {
$node1->waitUntilSucceeds("etcdctl member add node3 https://node3:2380");
$node3->start();
$node3->waitForUnit("etcd.service");
$node3->waitUntilSucceeds("etcdctl member list | grep 'node3'");
$node3->succeed("etcdctl cluster-health");
};
with subtest("should add another member"):
node1.wait_until_succeeds("etcdctl member add node3 https://node3:2380")
node3.start()
node3.wait_for_unit("etcd.service")
node3.wait_until_succeeds("etcdctl member list | grep 'node3'")
node3.succeed("etcdctl cluster-health")
subtest "should survive member crash", sub {
$node3->crash;
$node1->succeed("etcdctl cluster-health");
$node1->succeed("etcdctl set /foo/bar 'Hello degraded world'");
$node1->succeed("etcdctl get /foo/bar | grep 'Hello degraded world'");
};
with subtest("should survive member crash"):
node3.crash()
node1.succeed("etcdctl cluster-health")
node1.succeed("etcdctl set /foo/bar '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
import ./make-test.nix ({ pkgs, ... } : {
import ./make-test-python.nix ({ pkgs, ... } : {
name = "etcd";
meta = with pkgs.stdenv.lib.maintainers; {
@ -14,14 +14,12 @@ import ./make-test.nix ({ pkgs, ... } : {
};
testScript = ''
subtest "should start etcd node", sub {
$node->start();
$node->waitForUnit("etcd.service");
};
with subtest("should start etcd node"):
node.start()
node.wait_for_unit("etcd.service")
subtest "should write and read some values to etcd", sub {
$node->succeed("etcdctl set /foo/bar 'Hello world'");
$node->succeed("etcdctl get /foo/bar | grep 'Hello world'");
}
with subtest("should write and read some values to etcd"):
node.succeed("etcdctl set /foo/bar '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";
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.
testScript = ''
$machine->waitForUnit("fancontrol.service");
$machine->waitUntilSucceeds("journalctl -eu fancontrol | grep 'Configuration appears to be outdated'");
start_all()
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";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ mic92 ];
@ -53,24 +53,22 @@ import ./make-test.nix ({ pkgs, ...} : {
testScript =
''
startAll;
start_all()
$client->waitForUnit("network-online.target");
$server->waitForUnit("ferm.service");
$server->waitForUnit("nginx.service");
$server->waitUntilSucceeds("ss -ntl | grep -q 80");
client.wait_for_unit("network-online.target")
server.wait_for_unit("ferm.service")
server.wait_for_unit("nginx.service")
server.wait_until_succeeds("ss -ntl | grep -q 80")
subtest "port 80 is allowed", sub {
$client->succeed("curl --fail -g http://192.168.1.1:80/status");
$client->succeed("curl --fail -g http://[fd00::1]:80/status");
};
with subtest("port 80 is allowed"):
client.succeed("curl --fail -g http://192.168.1.1:80/status")
client.succeed("curl --fail -g http://[fd00::1]:80/status")
subtest "port 8080 is not allowed", sub {
$server->succeed("curl --fail -g http://192.168.1.1:8080/status");
$server->succeed("curl --fail -g http://[fd00::1]:8080/status");
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://[fd00::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://192.168.1.1:8080/status")
client.fail("curl --fail -g http://[fd00::1]:8080/status")
'';
})

View file

@ -1,6 +1,6 @@
# Test the firewall module.
import ./make-test.nix ( { pkgs, ... } : {
import ./make-test-python.nix ( { pkgs, ... } : {
name = "firewall";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ eelco ];
@ -36,30 +36,30 @@ import ./make-test.nix ( { pkgs, ... } : {
testScript = { nodes, ... }: let
newSystem = nodes.walled2.config.system.build.toplevel;
in ''
$walled->start;
$attacker->start;
start_all()
$walled->waitForUnit("firewall");
$walled->waitForUnit("httpd");
$attacker->waitForUnit("network.target");
walled.wait_for_unit("firewall")
walled.wait_for_unit("httpd")
attacker.wait_for_unit("network.target")
# 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.
$attacker->fail("curl --fail --connect-timeout 2 http://walled/ >&2");
$attacker->succeed("ping -c 1 walled >&2");
attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
attacker.succeed("ping -c 1 walled >&2")
# Outgoing connections/pings should still work.
$walled->succeed("curl -v http://attacker/ >&2");
$walled->succeed("ping -c 1 attacker >&2");
walled.succeed("curl -v http://attacker/ >&2")
walled.succeed("ping -c 1 attacker >&2")
# If we stop the firewall, then connections should succeed.
$walled->stopJob("firewall");
$attacker->succeed("curl -v http://walled/ >&2");
walled.stop_job("firewall")
attacker.succeed("curl -v http://walled/ >&2")
# Check whether activation of a new configuration reloads the firewall.
$walled->succeed("${newSystem}/bin/switch-to-configuration test 2>&1" .
" | grep -qF firewall.service");
walled.succeed(
"${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";
machine =
@ -14,8 +14,11 @@ import ./make-test.nix ({ pkgs, ... }: {
testScript =
''
$machine->waitForFile("/etc/fish/generated_completions/coreutils.fish");
$machine->waitForFile("/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\$'");
start_all()
machine.wait_for_file("/etc/fish/generated_completions/coreutils.fish")
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";
machine = { pkgs, ... }: {
@ -33,14 +33,17 @@ import ./make-test.nix ({ pkgs, lib, ... }: {
inherit testMessage;
});
in ''
$machine->start;
$machine->waitForUnit('fluentd.service');
$machine->waitForOpenPort(9880);
machine.start()
machine.wait_for_unit("fluentd.service")
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
initialRootPassword = "notproduction";
in
import ./make-test.nix ({ pkgs, lib, ...} : with lib; {
import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
name = "gitlab";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ globin ];
@ -63,21 +63,35 @@ import ./make-test.nix ({ pkgs, lib, ...} : with lib; {
});
in
''
$gitlab->start();
$gitlab->waitForUnit("gitaly.service");
$gitlab->waitForUnit("gitlab-workhorse.service");
$gitlab->waitForUnit("gitlab.service");
$gitlab->waitForUnit("gitlab-sidekiq.service");
$gitlab->waitForFile("/var/gitlab/state/tmp/sockets/gitlab.socket");
$gitlab->waitUntilSucceeds("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("${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2");
$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("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");
gitlab.start()
gitlab.wait_for_unit("gitaly.service")
gitlab.wait_for_unit("gitlab-workhorse.service")
gitlab.wait_for_unit("gitlab.service")
gitlab.wait_for_unit("gitlab-sidekiq.service")
gitlab.wait_for_file("/var/gitlab/state/tmp/sockets/gitlab.socket")
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(
"${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2"
)
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(
"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
adminPrivateKey = pkgs.writeText "id_ed25519" ''
@ -43,7 +43,7 @@ let
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZNonUP1ePHLrvn0W9D2hdN6zWWZYFyJc+QR6pOKQEw bob@client
'';
gitoliteAdminConfSnippet = ''
gitoliteAdminConfSnippet = pkgs.writeText "gitolite-admin-conf-snippet" ''
repo alice-project
RW+ = alice
'';
@ -85,55 +85,54 @@ in
};
testScript = ''
startAll;
start_all()
subtest "can setup ssh keys on system", sub {
$client->mustSucceed("mkdir -p ~root/.ssh");
$client->mustSucceed("cp ${adminPrivateKey} ~root/.ssh/id_ed25519");
$client->mustSucceed("chmod 600 ~root/.ssh/id_ed25519");
with subtest("can setup ssh keys on system"):
client.succeed(
"mkdir -p ~root/.ssh",
"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");
$client->mustSucceed("sudo -u alice cp ${alicePrivateKey} ~alice/.ssh/id_ed25519");
$client->mustSucceed("sudo -u alice chmod 600 ~alice/.ssh/id_ed25519");
with subtest("gitolite server starts"):
server.wait_for_unit("gitolite-init.service")
server.wait_for_unit("sshd.service")
client.succeed("ssh gitolite@server info")
$client->mustSucceed("sudo -u bob mkdir -p ~bob/.ssh");
$client->mustSucceed("sudo -u bob cp ${bobPrivateKey} ~bob/.ssh/id_ed25519");
$client->mustSucceed("sudo -u bob chmod 600 ~bob/.ssh/id_ed25519");
};
with subtest("admin can clone and configure gitolite-admin.git"):
client.succeed(
"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 {
$server->waitForUnit("gitolite-init.service");
$server->waitForUnit("sshd.service");
$client->mustSucceed('ssh gitolite@server info');
};
with subtest("non-admins cannot clone gitolite-admin.git"):
client.fail("sudo -i -u alice git clone gitolite@server:gitolite-admin.git")
client.fail("sudo -i -u bob git clone gitolite@server:gitolite-admin.git")
subtest "admin can clone and configure gitolite-admin.git", sub {
$client->mustSucceed('git clone gitolite@server:gitolite-admin.git');
$client->mustSucceed("git config --global user.name 'System Administrator'");
$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)');
};
with subtest("non-admins can clone testing.git"):
client.succeed("sudo -i -u alice git clone gitolite@server:testing.git")
client.succeed("sudo -i -u bob git clone gitolite@server:testing.git")
subtest "non-admins cannot clone gitolite-admin.git", sub {
$client->mustFail('sudo -i -u alice git clone gitolite@server:gitolite-admin.git');
$client->mustFail('sudo -i -u bob git clone gitolite@server:gitolite-admin.git');
};
with subtest("alice can clone alice-project.git"):
client.succeed("sudo -i -u alice git clone gitolite@server:alice-project.git")
subtest "non-admins can clone testing.git", sub {
$client->mustSucceed('sudo -i -u alice git clone gitolite@server:testing.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');
};
with subtest("bob cannot clone alice-project.git"):
client.fail("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
client = { pkgs, ... } : {
@ -39,27 +39,29 @@ in {
};
testScript = ''
$server1->waitForUnit("glusterd.service");
$server2->waitForUnit("glusterd.service");
server1.wait_for_unit("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
$server1->succeed("sleep 2");
$server1->succeed("gluster peer probe server2");
$server1->succeed("gluster peer probe server1");
server1.succeed("gluster peer probe server2")
server1.succeed("gluster peer probe server1")
$server1->succeed("gluster peer status | grep Connected");
server1.succeed("gluster peer status | grep Connected")
# create volumes
$server1->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 start gv0");
server1.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 start gv0")
# test clients
$client1->waitForUnit("gluster.mount");
$client2->waitForUnit("gluster.mount");
client1.wait_for_unit("gluster.mount")
client2.wait_for_unit("gluster.mount")
$client1->succeed("echo test > /gluster/file1");
$client2->succeed("grep test /gluster/file1");
client1.succeed("echo 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
inherit (import ./../ssh-keys.nix pkgs)
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 {
name = "google-oslogin";
meta = with pkgs.stdenv.lib.maintainers; {
@ -15,38 +22,49 @@ in {
client = { ... }: {};
};
testScript = ''
startAll;
start_all()
$server->waitForUnit("mock-google-metadata.service");
$server->waitForOpenPort(80);
server.wait_for_unit("mock-google-metadata.service")
server.wait_for_open_port(80)
# 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('${pkgs.google-compute-engine-oslogin}/bin/google_authorized_keys mockadmin | grep -q "${snakeOilPublicKey}"');
server.succeed(
'${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
$client->succeed("mkdir -p ~/.ssh");
$client->succeed("cat ${snakeOilPrivateKey} > ~/.ssh/id_snakeoil");
$client->succeed("chmod 600 ~/.ssh/id_snakeoil");
# install snakeoil ssh key on the client, and provision .ssh/config file
client.succeed("mkdir -p ~/.ssh")
client.succeed(
"cat ${snakeOilPrivateKey} > ~/.ssh/id_snakeoil"
)
client.succeed("chmod 600 ~/.ssh/id_snakeoil")
client.succeed("cp ${ssh-config} ~/.ssh/config")
$client->waitForUnit("network.target");
$server->waitForUnit("sshd.service");
client.wait_for_unit("network.target")
server.wait_for_unit("sshd.service")
# 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
$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
$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
$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
$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
$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";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ ma27 ];
@ -14,32 +14,32 @@ import ./make-test.nix ({ pkgs, lib, ...} : {
};
testScript = ''
startAll;
machine.start()
$machine->waitForUnit("gotify-server");
$machine->waitForOpenPort(3000);
machine.wait_for_unit("gotify-server.service")
machine.wait_for_open_port(3000)
my $token = $machine->succeed(
"curl --fail -sS -X POST localhost:3000/application -F name=nixos " .
'-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" ' .
'| jq .token | xargs echo -n'
);
token = machine.succeed(
"curl --fail -sS -X POST localhost:3000/application -F name=nixos "
+ '-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" '
+ "| jq .token | xargs echo -n"
)
my $usertoken = $machine->succeed(
"curl --fail -sS -X POST localhost:3000/client -F name=nixos " .
'-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" ' .
'| jq .token | xargs echo -n'
);
usertoken = machine.succeed(
"curl --fail -sS -X POST localhost:3000/client -F name=nixos "
+ '-H "Authorization: Basic $(echo -ne "admin:admin" | base64 --wrap 0)" '
+ "| jq .token | xargs echo -n"
)
$machine->succeed(
"curl --fail -sS -X POST 'localhost:3000/message?token=$token' -H 'Accept: application/json' " .
'-F title=Gotify -F message=Works'
);
machine.succeed(
f"curl --fail -sS -X POST 'localhost:3000/message?token={token}' -H 'Accept: application/json' "
+ "-F title=Gotify -F message=Works"
)
my $title = $machine->succeed(
"curl --fail -sS 'localhost:3000/message?since=0&token=$usertoken' | jq '.messages|.[0]|.title' | xargs echo -n"
);
title = machine.succeed(
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";
meta.maintainers = with lib.maintainers; [ ma27 ];
@ -64,48 +64,52 @@ import ./make-test.nix ({ pkgs, lib, ... }: {
facility = "Test";
});
in ''
$machine->start;
$machine->waitForUnit("graylog.service");
$machine->waitForOpenPort(9000);
$machine->succeed("curl -sSfL http://127.0.0.1:9000/");
machine.start()
machine.wait_for_unit("graylog.service")
machine.wait_for_open_port(9000)
machine.succeed("curl -sSfL http://127.0.0.1:9000/")
my $session = $machine->succeed("curl -X POST "
. "-sSfL http://127.0.0.1:9000/api/system/sessions "
. "-d \$(cat ${payloads.login}) "
. "-H 'Content-Type: application/json' "
. "-H 'Accept: application/json' "
. "-H 'x-requested-by: cli' "
. "| jq .session_id | xargs echo"
);
session = machine.succeed(
"curl -X POST "
+ "-sSfL http://127.0.0.1:9000/api/system/sessions "
+ "-d $(cat ${payloads.login}) "
+ "-H 'Content-Type: application/json' "
+ "-H 'Accept: application/json' "
+ "-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 "
. "-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.wait_until_succeeds(
"test \"$(curl -sSfL 'http://127.0.0.1:9000/api/cluster/inputstates' "
+ f"-u {session}:session "
+ "-H 'Accept: application/json' "
+ "-H 'Content-Type: application/json' "
+ "-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' "
. "-u $session:session "
. "-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("echo -n \$(cat ${payloads.gelf_message}) | nc -w10 -u 127.0.0.1 12201");
$machine->succeed("test \"\$(curl -X GET "
. "-sSfL 'http://127.0.0.1:9000/api/search/universal/relative?query=*' "
. "-u $session:session "
. "-H 'Accept: application/json' "
. "-H 'Content-Type: application/json' "
. "-H 'x-requested-by: cli'"
. " | jq '.total_results' | xargs echo)\" = \"1\""
);
machine.succeed(
'test "$(curl -X GET '
+ "-sSfL 'http://127.0.0.1:9000/api/search/universal/relative?query=*' "
+ f"-u {session}:session "
+ "-H 'Accept: application/json' "
+ "-H 'Content-Type: application/json' "
+ "-H 'x-requested-by: cli'"
+ ' | jq \'.total_results\' | xargs echo)" = "1"'
)
'';
})

View file

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... }:
import ./make-test-python.nix ({ pkgs, ... }:
let
# Download Big Buck Bunny example, licensed under CC Attribution 3.0.
testMkv = pkgs.fetchurl {
@ -19,7 +19,13 @@ in {
testScript = ''
# Test MP4 and MKV transcoding. Since this is a short clip, transcoding typically
# only takes a few seconds.
$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");
start_all()
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.
import ./make-test.nix (pkgs: {
import ./make-test-python.nix (pkgs: {
name = "hibernate";
nodes = {
@ -28,16 +28,17 @@ import ./make-test.nix (pkgs: {
testScript =
''
$machine->waitForUnit("multi-user.target");
$machine->succeed("mkswap /dev/vdb");
$machine->succeed("swapon -a");
$machine->startJob("listener");
$machine->waitForOpenPort(4444);
$machine->succeed("systemctl hibernate &");
$machine->waitForShutdown;
$probe->waitForUnit("multi-user.target");
$machine->start;
$probe->waitUntilSucceeds("echo test | nc machine 4444 -N");
machine.start()
machine.wait_for_unit("multi-user.target")
machine.succeed("mkswap /dev/vdb")
machine.succeed("swapon -a")
machine.start_job("listener")
machine.wait_for_open_port(4444)
machine.succeed("systemctl hibernate &")
machine.wait_for_shutdown()
probe.wait_for_unit("multi-user.target")
machine.start()
probe.wait_until_succeeds("echo test | nc machine 4444 -N")
'';
})

View file

@ -1,5 +1,5 @@
# Test whether `houndd` indexes nixpkgs
import ./make-test.nix ({ pkgs, ... } : {
import ./make-test-python.nix ({ pkgs, ... } : {
name = "hound";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ grahamc ];
@ -46,13 +46,14 @@ import ./make-test.nix ({ pkgs, ... } : {
};
};
testScript =
'' startAll;
testScript = ''
start_all()
$machine->waitForUnit("network.target");
$machine->waitForUnit("hound.service");
$machine->waitForOpenPort(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_for_unit("network.target")
machine.wait_for_unit("hound.service")
machine.wait_for_open_port(6080)
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";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ das_j ];
@ -64,8 +64,8 @@ import ./make-test.nix ({ pkgs, ... }: {
};
testScript = ''
startAll();
$icingaweb2->waitForUnit("multi-user.target");
$icingaweb2->succeed("curl -sSf http://icingaweb2/authentication/login");
start_all()
icingaweb2.wait_for_unit("multi-user.target")
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;
@ -18,17 +18,16 @@ with lib;
};
testScript = ''
subtest "machine with iftop enabled", sub {
$withIftop->waitForUnit("default.target");
# limit to eth1 (eth0 is the test driver's control interface)
# and don't try name lookups
$withIftop->succeed("su -l alice -c 'iftop -t -s 1 -n -i eth1'");
};
subtest "machine without iftop", sub {
$withoutIftop->waitForUnit("default.target");
# check that iftop is there but user alice lacks capabilities
$withoutIftop->succeed("iftop -t -s 1 -n -i eth1");
$withoutIftop->fail("su -l alice -c 'iftop -t -s 1 -n -i eth1'");
};
with subtest("machine with iftop enabled"):
withIftop.wait_for_unit("default.target")
# limit to eth1 (eth0 is the test driver's control interface)
# and don't try name lookups
withIftop.succeed("su -l alice -c 'iftop -t -s 1 -n -i eth1'")
with subtest("machine without iftop"):
withoutIftop.wait_for_unit("default.target")
# check that iftop is there but user alice lacks capabilitie
withoutIftop.succeed("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";
@ -19,34 +19,34 @@ import ./make-test.nix ({ pkgs, lib, ... }:
};
testScript = ''
startAll;
start_all()
$machine->waitForUnit("multi-user.target");
$machine->waitForUnit("incron.service");
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("incron.service")
$machine->succeed("test -d /test");
machine.succeed("test -d /test")
# create some activity for incron to monitor
$machine->succeed("touch /test/file");
$machine->succeed("echo foo >> /test/file");
$machine->succeed("mv /test/file /root");
$machine->succeed("mv /root/file /test");
machine.succeed("touch /test/file")
machine.succeed("echo foo >> /test/file")
machine.succeed("mv /test/file /root")
machine.succeed("mv /root/file /test")
$machine->sleep(1);
machine.sleep(1)
# 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
$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_MODIFY' /root/incron.log")
machine.succeed("grep '/test/file IN_CLOSE_WRITE' /root/incron.log")
# 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
$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
$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
import ./make-test.nix ({ pkgs, ...} : {
import ./make-test-python.nix ({ pkgs, ...} : {
name = "influxdb";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ offline ];
@ -9,25 +9,32 @@ import ./make-test.nix ({ pkgs, ...} : {
nodes = {
one = { ... }: {
services.influxdb.enable = true;
environment.systemPackages = [ pkgs.httpie ];
};
};
testScript = ''
startAll;
$one->waitForUnit("influxdb.service");
import shlex
start_all()
one.wait_for_unit("influxdb.service")
# create database
$one->succeed(q~
curl -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE test"
~);
one.succeed(
"curl -XPOST http://localhost:8086/query --data-urlencode 'q=CREATE DATABASE test'"
)
# write some points and run simple query
$one->succeed(q~
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"
~);
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'"
)
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