Merge remote-tracking branch 'origin/staging' into dnicponski/scratch/update_darwin_cctools

This commit is contained in:
Matthew Bauer 2019-11-25 22:00:13 -05:00
commit 08d6c4019d
893 changed files with 10352 additions and 7435 deletions

8
.github/CODEOWNERS vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1780,6 +1780,12 @@
githubId = 875324; githubId = 875324;
name = "David Johnson"; name = "David Johnson";
}; };
dmrauh = {
email = "dmrauh@posteo.de";
github = "dmrauh";
githubId = 37698547;
name = "Dominik Michael Rauh";
};
dmvianna = { dmvianna = {
email = "dmlvianna@gmail.com"; email = "dmlvianna@gmail.com";
github = "dmvianna"; github = "dmvianna";
@ -2515,6 +2521,7 @@
gazally = { gazally = {
email = "gazally@runbox.com"; email = "gazally@runbox.com";
github = "gazally"; github = "gazally";
githubId = 16470252;
name = "Gemini Lasswell"; name = "Gemini Lasswell";
}; };
gebner = { gebner = {
@ -3594,6 +3601,12 @@
github = "klntsky"; github = "klntsky";
githubId = 18447310; githubId = 18447310;
}; };
kmcopper = {
email = "kmcopper@danwin1210.me";
name = "Kyle Copperfield";
github = "kmcopper";
githubId = 57132115;
};
kmeakin = { kmeakin = {
email = "karlwfmeakin@gmail.com"; email = "karlwfmeakin@gmail.com";
name = "Karl Meakin"; name = "Karl Meakin";
@ -3700,6 +3713,18 @@
githubId = 449813; githubId = 449813;
name = "Roman Kuznetsov"; name = "Roman Kuznetsov";
}; };
kylesferrazza = {
name = "Kyle Sferrazza";
email = "kyle.sferrazza@gmail.com";
github = "kylesferrazza";
githubId = 6677292;
keys = [{
longkeyid = "rsa4096/81A1540948162372";
fingerprint = "5A9A 1C9B 2369 8049 3B48 CF5B 81A1 5409 4816 2372";
}];
};
kylewlacy = { kylewlacy = {
email = "kylelacy+nix@pm.me"; email = "kylelacy+nix@pm.me";
github = "kylewlacy"; github = "kylewlacy";
@ -4505,6 +4530,12 @@
githubId = 117842; githubId = 117842;
name = "Henri Bourcereau"; name = "Henri Bourcereau";
}; };
mmilata = {
email = "martin@martinmilata.cz";
github = "mmilata";
gitHubId = 85857;
name = "Martin Milata";
};
mmlb = { mmlb = {
email = "me.mmlb@mmlb.me"; email = "me.mmlb@mmlb.me";
github = "mmlb"; github = "mmlb";
@ -6087,7 +6118,7 @@
name = "Shahrukh Khan"; name = "Shahrukh Khan";
}; };
shanemikel = { shanemikel = {
email = "shanemikel1@gmail.com"; email = "shanepearlman@pm.me";
github = "shanemikel"; github = "shanemikel";
githubId = 6720672; githubId = 6720672;
name = "Shane Pearlman"; name = "Shane Pearlman";
@ -6708,6 +6739,12 @@
githubId = 42933; githubId = 42933;
name = "Andrew Childs"; name = "Andrew Childs";
}; };
thefenriswolf = {
email = "stefan.rohrbacher97@gmail.com";
github = "thefenriswolf";
githubId = "8547242";
name = "Stefan Rohrbacher";
};
thesola10 = { thesola10 = {
email = "thesola10@bobile.fr"; email = "thesola10@bobile.fr";
github = "thesola10"; github = "thesola10";

View File

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

View File

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

View File

@ -45,12 +45,12 @@
<listitem> <listitem>
<para> <para>
<literal>git tag -a -s -m &quot;Release 17.09-beta&quot; 17.09-beta <literal>git tag -a -s -m &quot;Release 17.09-beta&quot; 17.09-beta
&amp;&amp; git push --tags</literal> &amp;&amp; git push origin 17.09-beta</literal>
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
From the master branch run <literal>git checkout -B From the master branch run <literal>git checkout -b
release-17.09</literal>. release-17.09</literal>.
</para> </para>
</listitem> </listitem>
@ -157,7 +157,7 @@
<listitem> <listitem>
<para> <para>
Release Nix (currently only Eelco Dolstra can do that). Release Nix (currently only Eelco Dolstra can do that).
<link xlink:href="https://github.com/NixOS/nixpkgs/commit/53710c752a85f00658882531bc90a23a3d1287e4"> <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/tools/nix-fallback-paths.nix">
Make sure fallback is updated. </link> Make sure fallback is updated. </link>
</para> </para>
</listitem> </listitem>
@ -169,8 +169,8 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Change <literal>stableBranch</literal> to true and wait for channel to Change <literal>stableBranch</literal> to <literal>true</literal> in Hydra and wait for
update. the channel to update.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -193,9 +193,11 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Update http://nixos.org/nixos/download.html and Update the
http://nixos.org/nixos/manual in <link xlink:href="https://github.com/NixOS/nixos-homepage/commit/2a37975d5a617ecdfca94696242b6f32ffcba9f1"><code>NIXOS_SERIES</code></link>
https://github.com/NixOS/nixos-org-configurations in the
<link xlink:href="https://github.com/NixOS/nixos-homepage">nixos-homepage</link>
repository.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -212,7 +214,8 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Send an email to nix-dev to announce the release with above information. Create a new topic on <link xlink:href="https://discourse.nixos.org/">the
Discourse instance</link> to announce the release with the above information.
Best to check how previous email was formulated to see what needs to be Best to check how previous email was formulated to see what needs to be
included. included.
</para> </para>

View File

@ -418,11 +418,11 @@
Do the installation: Do the installation:
<screen> <screen>
<prompt># </prompt>nixos-install</screen> <prompt># </prompt>nixos-install</screen>
Cross fingers. If this fails due to a temporary problem (such as a network This will install your system based on the configuration you provided.
issue while downloading binaries from the NixOS binary cache), you can If anything fails due to a configuration problem or any other issue
just re-run <command>nixos-install</command>. Otherwise, fix your (such as a network outage while downloading binaries from the NixOS
<filename>configuration.nix</filename> and then re-run binary cache), you can re-run <command>nixos-install</command> after
<command>nixos-install</command>. fixing your <filename>configuration.nix</filename>.
</para> </para>
<para> <para>
As the last step, <command>nixos-install</command> will ask you to set the As the last step, <command>nixos-install</command> will ask you to set the

View File

@ -155,6 +155,37 @@
You should now use the different build tools coming with the languages with sandbox mode disabled. You should now use the different build tools coming with the languages with sandbox mode disabled.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
There is now only one Xfce package-set and module. This means attributes, <literal>xfce4-14</literal>
<literal>xfce4-12</literal>, and <literal>xfceUnstable</literal> all now point to the latest Xfce 4.14
packages. And in future NixOS releases will be the latest released version of Xfce available at the
time during the releases development (if viable).
</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>
</itemizedlist> </itemizedlist>
</section> </section>

View File

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

View File

@ -3,7 +3,6 @@ from contextlib import contextmanager, _GeneratorContextManager
from xml.sax.saxutils import XMLGenerator from xml.sax.saxutils import XMLGenerator
import _thread import _thread
import atexit import atexit
import json
import os import os
import ptpython.repl import ptpython.repl
import pty import pty
@ -16,7 +15,7 @@ import sys
import tempfile import tempfile
import time import time
import unicodedata import unicodedata
from typing import Tuple, TextIO, Any, Callable, Dict, Iterator, Optional, List from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List
CHAR_TO_KEY = { CHAR_TO_KEY = {
"A": "shift-a", "A": "shift-a",
@ -290,9 +289,14 @@ class Machine:
def wait_for_monitor_prompt(self) -> str: def wait_for_monitor_prompt(self) -> str:
assert self.monitor is not None assert self.monitor is not None
answer = ""
while True: while True:
answer = self.monitor.recv(1024).decode() undecoded_answer = self.monitor.recv(1024)
if not undecoded_answer:
break
answer += undecoded_answer.decode()
if answer.endswith("(qemu) "): if answer.endswith("(qemu) "):
break
return answer return answer
def send_monitor_command(self, command: str) -> str: def send_monitor_command(self, command: str) -> str:
@ -606,12 +610,15 @@ class Machine:
+ os.environ.get("QEMU_OPTS", "") + os.environ.get("QEMU_OPTS", "")
) )
environment = { environment = dict(os.environ)
"QEMU_OPTS": qemu_options, environment.update(
{
"TMPDIR": self.state_dir,
"SHARED_DIR": self.shared_dir, "SHARED_DIR": self.shared_dir,
"USE_TMPDIR": "1", "USE_TMPDIR": "1",
"QEMU_OPTS": qemu_options,
} }
environment.update(dict(os.environ)) )
self.process = subprocess.Popen( self.process = subprocess.Popen(
self.script, self.script,
@ -749,7 +756,7 @@ def run_tests() -> None:
if tests is not None: if tests is not None:
with log.nested("running the VM test script"): with log.nested("running the VM test script"):
try: try:
exec(tests) exec(tests, globals())
except Exception as e: except Exception as e:
eprint("error: {}".format(str(e))) eprint("error: {}".format(str(e)))
sys.exit(1) sys.exit(1)
@ -763,7 +770,9 @@ def run_tests() -> None:
machine.execute("sync") machine.execute("sync")
if nr_tests != 0: if nr_tests != 0:
log.log("{} out of {} tests succeeded".format(nr_succeeded, nr_tests)) eprint("{} out of {} tests succeeded".format(nr_succeeded, nr_tests))
if nr_tests > nr_succeeded:
sys.exit(1)
@contextmanager @contextmanager

View File

@ -211,11 +211,11 @@ upload_image() {
log "Registering snapshot $snapshot_id as AMI" log "Registering snapshot $snapshot_id as AMI"
local block_device_mappings=( local block_device_mappings=(
"DeviceName=/dev/sda1,Ebs={SnapshotId=$snapshot_id,VolumeSize=$image_logical_gigabytes,DeleteOnTermination=true,VolumeType=gp2}" "DeviceName=/dev/xvda,Ebs={SnapshotId=$snapshot_id,VolumeSize=$image_logical_gigabytes,DeleteOnTermination=true,VolumeType=gp2}"
) )
local extra_flags=( local extra_flags=(
--root-device-name /dev/sda1 --root-device-name /dev/xvda
--sriov-net-support simple --sriov-net-support simple
--ena-support --ena-support
--virtualization-type hvm --virtualization-type hvm

View File

@ -10,7 +10,7 @@ let
isQtStyle = cfg.platformTheme == "gtk2" && cfg.style != "adwaita"; isQtStyle = cfg.platformTheme == "gtk2" && cfg.style != "adwaita";
packages = if isQGnome then [ pkgs.qgnomeplatform pkgs.adwaita-qt ] packages = if isQGnome then [ pkgs.qgnomeplatform pkgs.adwaita-qt ]
else if isQtStyle then [ pkgs.qtstyleplugins ] else if isQtStyle then [ pkgs.libsForQt5.qtstyleplugins ]
else throw "`qt5.platformTheme` ${cfg.platformTheme} and `qt5.style` ${cfg.style} are not compatible."; else throw "`qt5.platformTheme` ${cfg.platformTheme} and `qt5.style` ${cfg.style} are not compatible.";
in in

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

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

View File

@ -11,6 +11,9 @@
{ lib, ... }: { lib, ... }:
let
inherit (lib) types;
in
{ {
options = { options = {
@ -19,6 +22,7 @@
description = '' description = ''
The user IDs used in NixOS. The user IDs used in NixOS.
''; '';
type = types.attrsOf types.int;
}; };
ids.gids = lib.mkOption { ids.gids = lib.mkOption {
@ -26,6 +30,7 @@
description = '' description = ''
The group IDs used in NixOS. The group IDs used in NixOS.
''; '';
type = types.attrsOf types.int;
}; };
}; };

View File

@ -35,7 +35,6 @@
./config/terminfo.nix ./config/terminfo.nix
./config/unix-odbc-drivers.nix ./config/unix-odbc-drivers.nix
./config/users-groups.nix ./config/users-groups.nix
./config/vpnc.nix
./config/vte.nix ./config/vte.nix
./config/zram.nix ./config/zram.nix
./hardware/acpilight.nix ./hardware/acpilight.nix
@ -519,7 +518,6 @@
./services/monitoring/munin.nix ./services/monitoring/munin.nix
./services/monitoring/nagios.nix ./services/monitoring/nagios.nix
./services/monitoring/netdata.nix ./services/monitoring/netdata.nix
./services/monitoring/osquery.nix
./services/monitoring/prometheus/default.nix ./services/monitoring/prometheus/default.nix
./services/monitoring/prometheus/alertmanager.nix ./services/monitoring/prometheus/alertmanager.nix
./services/monitoring/prometheus/exporters.nix ./services/monitoring/prometheus/exporters.nix
@ -539,7 +537,6 @@
./services/monitoring/zabbix-agent.nix ./services/monitoring/zabbix-agent.nix
./services/monitoring/zabbix-proxy.nix ./services/monitoring/zabbix-proxy.nix
./services/monitoring/zabbix-server.nix ./services/monitoring/zabbix-server.nix
./services/network-filesystems/beegfs.nix
./services/network-filesystems/cachefilesd.nix ./services/network-filesystems/cachefilesd.nix
./services/network-filesystems/davfs2.nix ./services/network-filesystems/davfs2.nix
./services/network-filesystems/drbd.nix ./services/network-filesystems/drbd.nix

View File

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

View File

@ -23,7 +23,8 @@ with lib;
###### implementation ###### implementation
config = mkIf config.programs.adb.enable { config = mkIf config.programs.adb.enable {
services.udev.packages = [ pkgs.android-udev-rules ]; services.udev.packages = [ pkgs.android-udev-rules ];
environment.systemPackages = [ pkgs.androidenv.androidPkgs_9_0.platform-tools ]; # Give platform-tools lower priority so mke2fs+friends are taken from other packages first
environment.systemPackages = [ (lowPrio pkgs.androidenv.androidPkgs_9_0.platform-tools) ];
users.groups.adbusers = {}; users.groups.adbusers = {};
}; };
} }

View File

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

View File

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

View File

@ -7,12 +7,17 @@ with lib;
let let
cfg = config.services.tumbler; cfg = config.services.tumbler;
tumbler = cfg.package;
in in
{ {
imports = [
(mkRemovedOptionModule
[ "services" "tumbler" "package" ]
"")
];
###### interface ###### interface
options = { options = {
@ -21,13 +26,6 @@ in
enable = mkEnableOption "Tumbler, A D-Bus thumbnailer service"; enable = mkEnableOption "Tumbler, A D-Bus thumbnailer service";
package = mkOption {
type = types.package;
default = pkgs.xfce4-14.tumbler;
description = "Which tumbler package to use";
example = pkgs.xfce4-12.tumbler;
};
}; };
}; };
@ -37,11 +35,11 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [ environment.systemPackages = with pkgs.xfce; [
tumbler tumbler
]; ];
services.dbus.packages = [ services.dbus.packages = with pkgs.xfce; [
tumbler tumbler
]; ];

View File

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

View File

@ -74,7 +74,7 @@ in {
default = false; default = false;
description = '' description = ''
Whether to enable test remote. This is used by Whether to enable test remote. This is used by
<link xlink:href="https://github.com/hughsie/fwupd/blob/master/data/installed-tests/README.md">installed tests</link>. <link xlink:href="https://github.com/fwupd/fwupd/blob/master/data/installed-tests/README.md">installed tests</link>.
''; '';
}; };
@ -115,10 +115,6 @@ in {
services.udev.packages = [ cfg.package ]; services.udev.packages = [ cfg.package ];
systemd.packages = [ cfg.package ]; systemd.packages = [ cfg.package ];
systemd.tmpfiles.rules = [
"d /var/lib/fwupd 0755 root root -"
];
}; };
meta = { meta = {

View File

@ -37,7 +37,7 @@ in
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Whether to enable the TLP daemon."; description = "Whether to enable the TLP power management daemon.";
}; };
extraConfig = mkOption { extraConfig = mkOption {

View File

@ -25,6 +25,13 @@ in
description = "The port address of the http server."; description = "The port address of the http server.";
}; };
http.path = mkOption {
type = with types; nullOr str;
default = null;
description = "Prefix to all HTTP paths.";
example = "/mailcatcher";
};
smtp.ip = mkOption { smtp.ip = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
@ -53,7 +60,7 @@ in
serviceConfig = { serviceConfig = {
DynamicUser = true; DynamicUser = true;
Restart = "always"; Restart = "always";
ExecStart = "${pkgs.mailcatcher}/bin/mailcatcher --foreground --no-quit --http-ip ${cfg.http.ip} --http-port ${toString cfg.http.port} --smtp-ip ${cfg.smtp.ip} --smtp-port ${toString cfg.smtp.port}"; ExecStart = "${pkgs.mailcatcher}/bin/mailcatcher --foreground --no-quit --http-ip ${cfg.http.ip} --http-port ${toString cfg.http.port} --smtp-ip ${cfg.smtp.ip} --smtp-port ${toString cfg.smtp.port}" + optionalString (cfg.http.path != null) " --http-path ${cfg.http.path}";
AmbientCapabilities = optionalString (cfg.http.port < 1024 || cfg.smtp.port < 1024) "cap_net_bind_service"; AmbientCapabilities = optionalString (cfg.http.port < 1024 || cfg.smtp.port < 1024) "cap_net_bind_service";
}; };
}; };

View File

@ -160,7 +160,7 @@ in
${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create role ${cfg.database.username} with login password '${cfg.database.password}'"; ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create role ${cfg.database.username} with login password '${cfg.database.password}'";
${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create database ${cfg.database.dbname} with owner ${cfg.database.username}"; ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create database ${cfg.database.dbname} with owner ${cfg.database.username}";
fi fi
PGPASSWORD=${cfg.database.password} ${pkgs.postgresql}/bin/psql -U ${cfg.database.username} \ PGPASSWORD="${cfg.database.password}" ${pkgs.postgresql}/bin/psql -U ${cfg.database.username} \
-f ${cfg.package}/SQL/postgres.initial.sql \ -f ${cfg.package}/SQL/postgres.initial.sql \
-h ${cfg.database.host} ${cfg.database.dbname} -h ${cfg.database.host} ${cfg.database.dbname}
touch /var/lib/roundcube/db-created touch /var/lib/roundcube/db-created

View File

@ -60,7 +60,7 @@ let
}; };
type = mkOption { type = mkOption {
type = types.nullOr (types.enum [ type = types.nullOr (types.enum [
"normal" "controller" "fuzzy_storage" "rspamd_proxy" "lua" "proxy" "normal" "controller" "fuzzy" "rspamd_proxy" "lua" "proxy"
]); ]);
description = '' description = ''
The type of this worker. The type <literal>proxy</literal> is The type of this worker. The type <literal>proxy</literal> is

View File

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

View File

@ -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

@ -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

@ -78,7 +78,11 @@ in
cacheNetworks = mkOption { cacheNetworks = mkOption {
default = ["127.0.0.0/24"]; default = ["127.0.0.0/24"];
description = " description = "
What networks are allowed to use us as a resolver. What networks are allowed to use us as a resolver. Note
that this is for recursive queries -- all networks are
allowed to query zones configured with the `zones` option.
It is recommended that you limit cacheNetworks to avoid your
server being used for DNS amplification attacks.
"; ";
}; };

View File

@ -177,9 +177,6 @@ in {
NoNewPrivileges = "true"; NoNewPrivileges = "true";
PrivateDevices = "true"; PrivateDevices = "true";
MemoryDenyWriteExecute = "true"; MemoryDenyWriteExecute = "true";
# Permission for preStart
PermissionsStartOnly = "true";
}; };
}; };
users.users.${cfg.user} = { users.users.${cfg.user} = {

View File

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

View File

@ -23,6 +23,8 @@ in
type = types.int; type = types.int;
description = '' description = ''
The port the server should listen on. Will use the server's default (2022) if not specified. The port the server should listen on. Will use the server's default (2022) if not specified.
Make sure to open this port in the firewall if necessary.
''; '';
}; };
@ -86,4 +88,8 @@ in
}; };
}; };
}; };
meta = {
maintainers = with lib.maintainers; [ pingiun ];
};
} }

View File

@ -18,6 +18,7 @@ let
fsWatcherEnabled = folder.watch; fsWatcherEnabled = folder.watch;
fsWatcherDelayS = folder.watchDelay; fsWatcherDelayS = folder.watchDelay;
ignorePerms = folder.ignorePerms; ignorePerms = folder.ignorePerms;
versioning = folder.versioning;
}) (filterAttrs ( }) (filterAttrs (
_: folder: _: folder:
folder.enable folder.enable
@ -220,6 +221,69 @@ in {
''; '';
}; };
versioning = mkOption {
default = null;
description = ''
How to keep changed/deleted files with syncthing.
There are 4 different types of versioning with different parameters.
See https://docs.syncthing.net/users/versioning.html
'';
example = [
{
versioning = {
type = "simple";
params.keep = "10";
};
}
{
versioning = {
type = "trashcan";
params.cleanoutDays = "1000";
};
}
{
versioning = {
type = "staggered";
params = {
cleanInterval = "3600";
maxAge = "31536000";
versionsPath = "/syncthing/backup";
};
};
}
{
versioning = {
type = "external";
params.versionsPath = pkgs.writers.writeBash "backup" ''
folderpath="$1"
filepath="$2"
rm -rf "$folderpath/$filepath"
'';
};
}
];
type = with types; nullOr (submodule {
options = {
type = mkOption {
type = enum [ "external" "simple" "staggered" "trashcan" ];
description = ''
Type of versioning.
See https://docs.syncthing.net/users/versioning.html
'';
};
params = mkOption {
type = attrsOf (either str path);
description = ''
Parameters for versioning. Structure depends on versioning.type.
See https://docs.syncthing.net/users/versioning.html
'';
};
};
});
};
rescanInterval = mkOption { rescanInterval = mkOption {
type = types.int; type = types.int;
default = 3600; default = 3600;

View File

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

View File

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

View File

@ -1,4 +1,4 @@
# This file defines the options that can be used both for the Apache # This file defines the options that can be used both for the Nginx
# main server configuration, and for the virtual hosts. (The latter # main server configuration, and for the virtual hosts. (The latter
# has additional options that affect the web server as a whole, like # has additional options that affect the web server as a whole, like
# the user/group to run under.) # the user/group to run under.)
@ -92,4 +92,3 @@ with lib;
}; };
}; };
} }

View File

@ -1,4 +1,4 @@
# This file defines the options that can be used both for the Apache # This file defines the options that can be used both for the Nginx
# main server configuration, and for the virtual hosts. (The latter # main server configuration, and for the virtual hosts. (The latter
# has additional options that affect the web server as a whole, like # has additional options that affect the web server as a whole, like
# the user/group to run under.) # the user/group to run under.)

View File

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

View File

@ -18,7 +18,7 @@ in
# determines the default: later modules (if enabled) are preferred. # determines the default: later modules (if enabled) are preferred.
# E.g., if Plasma 5 is enabled, it supersedes xterm. # E.g., if Plasma 5 is enabled, it supersedes xterm.
imports = [ imports = [
./none.nix ./xterm.nix ./xfce.nix ./xfce4-14.nix ./plasma5.nix ./lumina.nix ./none.nix ./xterm.nix ./xfce.nix ./plasma5.nix ./lumina.nix
./lxqt.nix ./enlightenment.nix ./gnome3.nix ./kodi.nix ./maxx.nix ./lxqt.nix ./enlightenment.nix ./gnome3.nix ./kodi.nix ./maxx.nix
./mate.nix ./pantheon.nix ./surf-display.nix ./mate.nix ./pantheon.nix ./surf-display.nix
]; ];

View File

@ -309,7 +309,7 @@ in
gnome-shell gnome-shell
gnome-shell-extensions gnome-shell-extensions
gnome-themes-extra gnome-themes-extra
gnome-user-docs pkgs.gnome-user-docs
pkgs.orca pkgs.orca
pkgs.glib # for gsettings pkgs.glib # for gsettings
pkgs.gnome-menus pkgs.gnome-menus

View File

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

View File

@ -7,6 +7,32 @@ let
in in
{ {
imports = [
# added 2019-08-18
# needed to preserve some semblance of UI familarity
# with original XFCE module
(mkRenamedOptionModule
[ "services" "xserver" "desktopManager" "xfce4-14" "extraSessionCommands" ]
[ "services" "xserver" "displayManager" "sessionCommands" ])
# added 2019-11-04
# xfce4-14 module removed and promoted to xfce.
# Needed for configs that used xfce4-14 module to migrate to this one.
(mkRenamedOptionModule
[ "services" "xserver" "desktopManager" "xfce4-14" "enable" ]
[ "services" "xserver" "desktopManager" "xfce" "enable" ])
(mkRenamedOptionModule
[ "services" "xserver" "desktopManager" "xfce4-14" "noDesktop" ]
[ "services" "xserver" "desktopManager" "xfce" "noDesktop" ])
(mkRenamedOptionModule
[ "services" "xserver" "desktopManager" "xfce4-14" "enableXfwm" ]
[ "services" "xserver" "desktopManager" "xfce" "enableXfwm" ])
(mkRenamedOptionModule
[ "services" "xserver" "desktopManager" "xfce" "extraSessionCommands" ]
[ "services" "xserver" "displayManager" "sessionCommands" ])
];
options = { options = {
services.xserver.desktopManager.xfce = { services.xserver.desktopManager.xfce = {
enable = mkOption { enable = mkOption {
@ -30,14 +56,6 @@ in
description = "Don't install XFCE desktop components (xfdesktop, panel and notification daemon)."; description = "Don't install XFCE desktop components (xfdesktop, panel and notification daemon).";
}; };
extraSessionCommands = mkOption {
default = "";
type = types.lines;
description = ''
Shell commands executed just before XFCE is started.
'';
};
enableXfwm = mkOption { enableXfwm = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
@ -48,76 +66,101 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = with pkgs.xfce // pkgs; [ environment.systemPackages = with pkgs.xfce // pkgs; [
# Get GTK themes and gtk-update-icon-cache glib # for gsettings
gtk2.out gtk3.out # gtk-update-icon-cache
# Supplies some abstract icons such as: gnome3.gnome-themes-extra
# utilities-terminal, accessories-text-editor
gnome3.adwaita-icon-theme gnome3.adwaita-icon-theme
hicolor-icon-theme hicolor-icon-theme
tango-icon-theme tango-icon-theme
xfce4-icon-theme xfce4-icon-theme
desktop-file-utils
shared-mime-info # for update-mime-database
# For a polkit authentication agent
polkit_gnome
# Needed by Xfce's xinitrc script # Needed by Xfce's xinitrc script
# TODO: replace with command -v xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
which
exo exo
garcon garcon
gtk-xfce-engine
libxfce4ui libxfce4ui
tumbler
xfconf xfconf
mousepad mousepad
parole
ristretto ristretto
xfce4-appfinder xfce4-appfinder
xfce4-screenshooter xfce4-screenshooter
xfce4-session xfce4-session
xfce4-settings xfce4-settings
xfce4-taskmanager
xfce4-terminal xfce4-terminal
(thunar.override { thunarPlugins = cfg.thunarPlugins; }) (thunar.override { thunarPlugins = cfg.thunarPlugins; })
thunar-volman # TODO: drop ] # TODO: NetworkManager doesn't belong here
] ++ (if config.hardware.pulseaudio.enable ++ optional config.networking.networkmanager.enable networkmanagerapplet
then [ xfce4-mixer-pulse xfce4-volumed-pulse ] ++ optional config.powerManagement.enable xfce4-power-manager
else [ xfce4-mixer xfce4-volumed ]) ++ optionals config.hardware.pulseaudio.enable [
# TODO: NetworkManager doesn't belong here pavucontrol
++ optionals config.networking.networkmanager.enable [ networkmanagerapplet ] # volume up/down keys support:
++ optionals config.powerManagement.enable [ xfce4-power-manager ] # xfce4-pulseaudio-plugin includes all the functionalities of xfce4-volumed-pulse
++ optionals cfg.enableXfwm [ xfwm4 ] # but can only be used with xfce4-panel, so for no-desktop usage we still include
++ optionals (!cfg.noDesktop) [ # xfce4-volumed-pulse
xfce4-panel (if cfg.noDesktop then xfce4-volumed-pulse else xfce4-pulseaudio-plugin)
] ++ optionals cfg.enableXfwm [
xfwm4
xfwm4-themes
] ++ optionals (!cfg.noDesktop) [
xfce4-notifyd xfce4-notifyd
xfce4-panel
xfdesktop xfdesktop
]; ];
environment.pathsToLink = [ environment.pathsToLink = [
"/share/xfce4" "/share/xfce4"
"/share/themes" "/lib/xfce4"
"/share/gtksourceview-2.0" "/share/gtksourceview-3.0"
"/share/gtksourceview-4.0"
]; ];
services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
services.xserver.desktopManager.session = [{ services.xserver.desktopManager.session = [{
name = "xfce"; name = "xfce";
bgSupport = true; bgSupport = true;
start = '' start = ''
${cfg.extraSessionCommands} ${pkgs.runtimeShell} ${pkgs.xfce.xfce4-session.xinitrc} &
${pkgs.runtimeShell} ${pkgs.xfce.xinitrc} &
waitPID=$! waitPID=$!
''; '';
}]; }];
services.xserver.updateDbusEnvironment = true; services.xserver.updateDbusEnvironment = true;
services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
# Enable helpful DBus services. # Enable helpful DBus services.
services.udisks2.enable = true; services.udisks2.enable = true;
security.polkit.enable = true;
services.accounts-daemon.enable = true;
services.upower.enable = config.powerManagement.enable; services.upower.enable = config.powerManagement.enable;
services.gnome3.glib-networking.enable = true;
services.gvfs.enable = true; services.gvfs.enable = true;
services.gvfs.package = pkgs.xfce.gvfs; services.gvfs.package = pkgs.xfce.gvfs;
services.tumbler.enable = true;
services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
services.xserver.libinput.enable = mkDefault true; # used in xfce4-settings-manager
# Enable default programs
programs.dconf.enable = true;
# Shell integration for VTE terminals
programs.bash.vteIntegration = mkDefault true;
programs.zsh.vteIntegration = mkDefault true;
# Systemd services
systemd.packages = with pkgs.xfce; [
(thunar.override { thunarPlugins = cfg.thunarPlugins; })
] ++ optional (!cfg.noDesktop) xfce4-notifyd;
}; };
} }

View File

@ -1,152 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.xserver.desktopManager.xfce4-14;
in
{
# added 2019-08-18
# needed to preserve some semblance of UI familarity
# with original XFCE module
imports = [
(mkRenamedOptionModule
[ "services" "xserver" "desktopManager" "xfce4-14" "extraSessionCommands" ]
[ "services" "xserver" "displayManager" "sessionCommands" ])
];
options = {
services.xserver.desktopManager.xfce4-14 = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable the Xfce desktop environment.";
};
# TODO: support thunar plugins
# thunarPlugins = mkOption {
# default = [];
# type = types.listOf types.package;
# example = literalExample "[ pkgs.xfce4-14.thunar-archive-plugin ]";
# description = ''
# A list of plugin that should be installed with Thunar.
# '';
# };
noDesktop = mkOption {
type = types.bool;
default = false;
description = "Don't install XFCE desktop components (xfdesktop, panel and notification daemon).";
};
enableXfwm = mkOption {
type = types.bool;
default = true;
description = "Enable the XFWM (default) window manager.";
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = with pkgs.xfce4-14 // pkgs; [
glib # for gsettings
gtk3.out # gtk-update-icon-cache
gnome3.gnome-themes-extra
gnome3.adwaita-icon-theme
hicolor-icon-theme
tango-icon-theme
xfce4-icon-theme
desktop-file-utils
shared-mime-info # for update-mime-database
# For a polkit authentication agent
polkit_gnome
# Needed by Xfce's xinitrc script
xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
exo
garcon
libxfce4ui
xfconf
mousepad
parole
ristretto
xfce4-appfinder
xfce4-screenshooter
xfce4-session
xfce4-settings
xfce4-taskmanager
xfce4-terminal
# TODO: resync patch for plugins
#(thunar.override { thunarPlugins = cfg.thunarPlugins; })
thunar
] # TODO: NetworkManager doesn't belong here
++ optional config.networking.networkmanager.enable networkmanagerapplet
++ optional config.powerManagement.enable xfce4-power-manager
++ optionals config.hardware.pulseaudio.enable [
pavucontrol
# volume up/down keys support:
# xfce4-pulseaudio-plugin includes all the functionalities of xfce4-volumed-pulse
# but can only be used with xfce4-panel, so for no-desktop usage we still include
# xfce4-volumed-pulse
(if cfg.noDesktop then xfce4-volumed-pulse else xfce4-pulseaudio-plugin)
] ++ optionals cfg.enableXfwm [
xfwm4
xfwm4-themes
] ++ optionals (!cfg.noDesktop) [
xfce4-notifyd
xfce4-panel
xfdesktop
];
environment.pathsToLink = [
"/share/xfce4"
"/lib/xfce4"
"/share/gtksourceview-3.0"
"/share/gtksourceview-4.0"
];
services.xserver.desktopManager.session = [{
name = "xfce4-14";
bgSupport = true;
start = ''
${pkgs.runtimeShell} ${pkgs.xfce4-14.xinitrc} &
waitPID=$!
'';
}];
services.xserver.updateDbusEnvironment = true;
services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
# Enable helpful DBus services.
services.udisks2.enable = true;
security.polkit.enable = true;
services.accounts-daemon.enable = true;
services.upower.enable = config.powerManagement.enable;
services.gnome3.glib-networking.enable = true;
services.gvfs.enable = true;
services.gvfs.package = pkgs.xfce.gvfs;
services.tumbler.enable = true;
services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
services.xserver.libinput.enable = mkDefault true; # used in xfce4-settings-manager
# Enable default programs
programs.dconf.enable = true;
# Shell integration for VTE terminals
programs.bash.vteIntegration = mkDefault true;
programs.zsh.vteIntegration = mkDefault true;
# Systemd services
systemd.packages = with pkgs.xfce4-14; [
thunar
] ++ optional (!cfg.noDesktop) xfce4-notifyd;
};
}

View File

@ -31,6 +31,44 @@ let
load-module module-position-event-sounds load-module module-position-event-sounds
''; '';
dmDefault = config.services.xserver.desktopManager.default;
wmDefault = config.services.xserver.windowManager.default;
hasDefaultUserSession = dmDefault != "none" || wmDefault != "none";
defaultSessionName = dmDefault + optionalString (wmDefault != "none") ("+" + wmDefault);
setSessionScript = pkgs.python3.pkgs.buildPythonApplication {
name = "set-session";
format = "other";
src = ./set-session.py;
dontUnpack = true;
strictDeps = false;
nativeBuildInputs = with pkgs; [
wrapGAppsHook
gobject-introspection
];
buildInputs = with pkgs; [
accountsservice
glib
];
propagatedBuildInputs = with pkgs.python3.pkgs; [
pygobject3
ordered-set
];
installPhase = ''
mkdir -p $out/bin
cp $src $out/bin/set-session
chmod +x $out/bin/set-session
'';
};
in in
{ {
@ -156,6 +194,8 @@ in
cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF
yes yes
EOF EOF
'' + optionalString hasDefaultUserSession ''
${setSessionScript}/bin/set-session ${defaultSessionName}
''; '';
}; };

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

@ -209,12 +209,12 @@ in {
services.xserver.config = services.xserver.config =
'' ''
# Automatically enable the libinput driver for all touchpads. # General libinput configuration.
# See CONFIGURATION DETAILS section of man:libinput(4).
Section "InputClass" Section "InputClass"
Identifier "libinputConfiguration" Identifier "libinputConfiguration"
MatchIsTouchpad "on" MatchDriver "libinput"
${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''} ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''}
Driver "libinput"
Option "AccelProfile" "${cfg.accelProfile}" Option "AccelProfile" "${cfg.accelProfile}"
${optionalString (cfg.accelSpeed != null) ''Option "AccelSpeed" "${cfg.accelSpeed}"''} ${optionalString (cfg.accelSpeed != null) ''Option "AccelSpeed" "${cfg.accelSpeed}"''}
${optionalString (cfg.buttonMapping != null) ''Option "ButtonMapping" "${cfg.buttonMapping}"''} ${optionalString (cfg.buttonMapping != null) ''Option "ButtonMapping" "${cfg.buttonMapping}"''}

View File

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

View File

@ -10,7 +10,7 @@ let
checkLink = checkUnitConfig "Link" [ checkLink = checkUnitConfig "Link" [
(assertOnlyFields [ (assertOnlyFields [
"Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "OriginalName" "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name" "OriginalName"
"MTUBytes" "BitsPerSecond" "Duplex" "AutoNegotiation" "WakeOnLan" "Port" "MTUBytes" "BitsPerSecond" "Duplex" "AutoNegotiation" "WakeOnLan" "Port"
"TCPSegmentationOffload" "TCP6SegmentationOffload" "GenericSegmentationOffload" "TCPSegmentationOffload" "TCP6SegmentationOffload" "GenericSegmentationOffload"
"GenericReceiveOffload" "LargeReceiveOffload" "RxChannels" "TxChannels" "GenericReceiveOffload" "LargeReceiveOffload" "RxChannels" "TxChannels"
@ -201,7 +201,7 @@ let
(assertValueOneOf "IPv6AcceptRA" boolValues) (assertValueOneOf "IPv6AcceptRA" boolValues)
(assertValueOneOf "IPv4ProxyARP" boolValues) (assertValueOneOf "IPv4ProxyARP" boolValues)
(assertValueOneOf "IPv6ProxyNDP" boolValues) (assertValueOneOf "IPv6ProxyNDP" boolValues)
(assertValueOneOf "IPv6PrefixDelegation" boolValues) (assertValueOneOf "IPv6PrefixDelegation" (boolValues ++ [ "dhcpv6" "static" ]))
(assertValueOneOf "ActiveSlave" boolValues) (assertValueOneOf "ActiveSlave" boolValues)
(assertValueOneOf "PrimarySlave" boolValues) (assertValueOneOf "PrimarySlave" boolValues)
(assertValueOneOf "ConfigureWithoutCarrier" boolValues) (assertValueOneOf "ConfigureWithoutCarrier" boolValues)
@ -924,6 +924,8 @@ in
config = mkIf config.systemd.network.enable { config = mkIf config.systemd.network.enable {
users.users.systemd-network.group = "systemd-network";
systemd.additionalUpstreamSystemUnits = [ systemd.additionalUpstreamSystemUnits = [
"systemd-networkd.service" "systemd-networkd-wait-online.service" "systemd-networkd.service" "systemd-networkd-wait-online.service"
]; ];

View File

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

View File

@ -20,6 +20,18 @@ with lib;
The set of NTP servers from which to synchronise. The set of NTP servers from which to synchronise.
''; '';
}; };
extraConfig = mkOption {
default = "";
type = types.lines;
example = ''
PollIntervalMaxSec=180
'';
description = ''
Extra config options for systemd-timesyncd. See
<link xlink:href="https://www.freedesktop.org/software/systemd/man/timesyncd.conf.html">
timesyncd.conf(5)</link> for available options.
'';
};
}; };
}; };
@ -35,9 +47,13 @@ with lib;
environment.etc."systemd/timesyncd.conf".text = '' environment.etc."systemd/timesyncd.conf".text = ''
[Time] [Time]
NTP=${concatStringsSep " " config.services.timesyncd.servers} NTP=${concatStringsSep " " config.services.timesyncd.servers}
${config.services.timesyncd.extraConfig}
''; '';
users.users.systemd-timesync.uid = config.ids.uids.systemd-timesync; users.users.systemd-timesync = {
uid = config.ids.uids.systemd-timesync;
group = "systemd-timesync";
};
users.groups.systemd-timesync.gid = config.ids.gids.systemd-timesync; users.groups.systemd-timesync.gid = config.ids.gids.systemd-timesync;
system.activationScripts.systemd-timesyncd-migration = mkIf (versionOlder config.system.stateVersion "19.09") '' system.activationScripts.systemd-timesyncd-migration = mkIf (versionOlder config.system.stateVersion "19.09") ''

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -136,7 +136,6 @@ in rec {
(all nixos.tests.switchTest) (all nixos.tests.switchTest)
(all nixos.tests.udisks2) (all nixos.tests.udisks2)
(all nixos.tests.xfce) (all nixos.tests.xfce)
(all nixos.tests.xfce4-14)
nixpkgs.tarball nixpkgs.tarball
(all allSupportedNixpkgs.emacs) (all allSupportedNixpkgs.emacs)

View File

@ -28,7 +28,7 @@ in
babeld = handleTest ./babeld.nix {}; babeld = handleTest ./babeld.nix {};
bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64 bcachefs = handleTestOn ["x86_64-linux"] ./bcachefs.nix {}; # linux-4.18.2018.10.12 is unsupported on aarch64
beanstalkd = handleTest ./beanstalkd.nix {}; beanstalkd = handleTest ./beanstalkd.nix {};
beegfs = handleTestOn ["x86_64-linux"] ./beegfs.nix {}; # beegfs is unsupported on aarch64 bees = handleTest ./bees.nix {};
bind = handleTest ./bind.nix {}; bind = handleTest ./bind.nix {};
bittorrent = handleTest ./bittorrent.nix {}; bittorrent = handleTest ./bittorrent.nix {};
#blivet = handleTest ./blivet.nix {}; # broken since 2017-07024 #blivet = handleTest ./blivet.nix {}; # broken since 2017-07024
@ -206,7 +206,6 @@ in
openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {}; openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
orangefs = handleTest ./orangefs.nix {}; orangefs = handleTest ./orangefs.nix {};
os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {}; os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
osquery = handleTest ./osquery.nix {};
osrm-backend = handleTest ./osrm-backend.nix {}; osrm-backend = handleTest ./osrm-backend.nix {};
overlayfs = handleTest ./overlayfs.nix {}; overlayfs = handleTest ./overlayfs.nix {};
packagekit = handleTest ./packagekit.nix {}; packagekit = handleTest ./packagekit.nix {};
@ -285,7 +284,6 @@ in
wordpress = handleTest ./wordpress.nix {}; wordpress = handleTest ./wordpress.nix {};
xautolock = handleTest ./xautolock.nix {}; xautolock = handleTest ./xautolock.nix {};
xfce = handleTest ./xfce.nix {}; xfce = handleTest ./xfce.nix {};
xfce4-14 = handleTest ./xfce4-14.nix {};
xmonad = handleTest ./xmonad.nix {}; xmonad = handleTest ./xmonad.nix {};
xrdp = handleTest ./xrdp.nix {}; xrdp = handleTest ./xrdp.nix {};
xss-lock = handleTest ./xss-lock.nix {}; xss-lock = handleTest ./xss-lock.nix {};

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import ./make-test.nix ({pkgs, lib, ...}: import ./make-test-python.nix ({pkgs, lib, ...}:
let let
cfg = { cfg = {
@ -109,14 +109,14 @@ let
# For other ways to deploy a ceph cluster, look at the documentation at # For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/ # https://docs.ceph.com/docs/master/
testscript = { ... }: '' testscript = { ... }: ''
startAll; start_all()
$monA->waitForUnit("network.target"); monA.wait_for_unit("network.target")
$osd0->waitForUnit("network.target"); osd0.wait_for_unit("network.target")
$osd1->waitForUnit("network.target"); osd1.wait_for_unit("network.target")
# Bootstrap ceph-mon daemon # Bootstrap ceph-mon daemon
$monA->mustSucceed( monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'", "sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'", "sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring", "sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
@ -124,90 +124,90 @@ let
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring", "sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/", "sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done", "sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}" "systemctl start ceph-mon-${cfg.monA.name}",
); )
$monA->waitForUnit("ceph-mon-${cfg.monA.name}"); monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
$monA->mustSucceed("ceph mon enable-msgr2"); monA.succeed("ceph mon enable-msgr2")
# Can't check ceph status until a mon is up # Can't check ceph status until a mon is up
$monA->succeed("ceph -s | grep 'mon: 1 daemons'"); monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Start the ceph-mgr daemon, it has no deps and hardly any setup # Start the ceph-mgr daemon, it has no deps and hardly any setup
$monA->mustSucceed( monA.succeed(
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring", "ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}" "systemctl start ceph-mgr-${cfg.monA.name}",
); )
$monA->waitForUnit("ceph-mgr-a"); monA.wait_for_unit("ceph-mgr-a")
$monA->waitUntilSucceeds("ceph -s | grep 'quorum ${cfg.monA.name}'"); monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
$monA->waitUntilSucceeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'"); monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Send the admin keyring to the OSD machines # Send the admin keyring to the OSD machines
$monA->mustSucceed("cp /etc/ceph/ceph.client.admin.keyring /tmp/shared"); monA.succeed("cp /etc/ceph/ceph.client.admin.keyring /tmp/shared")
$osd0->mustSucceed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph"); osd0.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
$osd1->mustSucceed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph"); osd1.succeed("cp /tmp/shared/ceph.client.admin.keyring /etc/ceph")
# Bootstrap both OSDs # Bootstrap both OSDs
$osd0->mustSucceed( osd0.succeed(
"mkfs.xfs /dev/vdb", "mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}", "mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}", "mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}", "ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
"echo '{\"cephx_secret\": \"${cfg.osd0.key}\"}' | ceph osd new ${cfg.osd0.uuid} -i -", 'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
); )
$osd1->mustSucceed( osd1.succeed(
"mkfs.xfs /dev/vdb", "mkfs.xfs /dev/vdb",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}", "mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd1.name}", "mount /dev/vdb /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}", "ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
"echo '{\"cephx_secret\": \"${cfg.osd1.key}\"}' | ceph osd new ${cfg.osd1.uuid} -i -" 'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
); )
# Initialize the OSDs with regular filestore # Initialize the OSDs with regular filestore
$osd0->mustSucceed( osd0.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}", "ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd", "chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}", "systemctl start ceph-osd-${cfg.osd0.name}",
); )
$osd1->mustSucceed( osd1.succeed(
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}", "ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd", "chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd1.name}" "systemctl start ceph-osd-${cfg.osd1.name}",
); )
$monA->waitUntilSucceeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'"); monA.wait_until_succeeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'")
$monA->waitUntilSucceeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'"); monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
$monA->waitUntilSucceeds("ceph -s | grep 'HEALTH_OK'"); monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
$monA->mustSucceed( monA.succeed(
"ceph osd pool create multi-node-test 100 100", "ceph osd pool create multi-node-test 100 100",
"ceph osd pool ls | grep 'multi-node-test'", "ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool rename multi-node-test multi-node-other-test", "ceph osd pool rename multi-node-test multi-node-other-test",
"ceph osd pool ls | grep 'multi-node-other-test'" "ceph osd pool ls | grep 'multi-node-other-test'",
); )
$monA->waitUntilSucceeds("ceph -s | grep '1 pools, 100 pgs'"); monA.wait_until_succeeds("ceph -s | grep '1 pools, 100 pgs'")
$monA->mustSucceed("ceph osd pool set multi-node-other-test size 2"); monA.succeed("ceph osd pool set multi-node-other-test size 2")
$monA->waitUntilSucceeds("ceph -s | grep 'HEALTH_OK'"); monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
$monA->waitUntilSucceeds("ceph -s | grep '100 active+clean'"); monA.wait_until_succeeds("ceph -s | grep '100 active+clean'")
$monA->mustFail( monA.fail(
"ceph osd pool ls | grep 'multi-node-test'", "ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete multi-node-other-test multi-node-other-test --yes-i-really-really-mean-it" "ceph osd pool delete multi-node-other-test multi-node-other-test --yes-i-really-really-mean-it",
); )
# Shut down ceph on all machines in a very unpolite way # Shut down ceph on all machines in a very unpolite way
$monA->crash; monA.crash()
$osd0->crash; osd0.crash()
$osd1->crash; osd1.crash()
# Start it up # Start it up
$osd0->start; osd0.start()
$osd1->start; osd1.start()
$monA->start; monA.start()
# Ensure the cluster comes back up again # Ensure the cluster comes back up again
$monA->succeed("ceph -s | grep 'mon: 1 daemons'"); monA.succeed("ceph -s | grep 'mon: 1 daemons'")
$monA->waitUntilSucceeds("ceph -s | grep 'quorum ${cfg.monA.name}'"); monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
$monA->waitUntilSucceeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'"); monA.wait_until_succeeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'")
$monA->waitUntilSucceeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'"); monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
$monA->waitUntilSucceeds("ceph -s | grep 'HEALTH_OK'"); monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
''; '';
in { in {
name = "basic-multi-node-ceph-cluster"; name = "basic-multi-node-ceph-cluster";

View File

@ -1,4 +1,4 @@
import ./make-test.nix ({pkgs, lib, ...}: import ./make-test-python.nix ({pkgs, lib, ...}:
let let
cfg = { cfg = {
@ -74,38 +74,38 @@ let
# For other ways to deploy a ceph cluster, look at the documentation at # For other ways to deploy a ceph cluster, look at the documentation at
# https://docs.ceph.com/docs/master/ # https://docs.ceph.com/docs/master/
testscript = { ... }: '' testscript = { ... }: ''
startAll; start_all()
$monA->waitForUnit("network.target"); monA.wait_for_unit("network.target")
# Bootstrap ceph-mon daemon # Bootstrap ceph-mon daemon
$monA->mustSucceed( monA.succeed(
"sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'", "sudo -u ceph ceph-authtool --create-keyring /tmp/ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'",
"sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'", "sudo -u ceph ceph-authtool --create-keyring /etc/ceph/ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'",
"sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring", "sudo -u ceph ceph-authtool /tmp/ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring",
"monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap", "monmaptool --create --add ${cfg.monA.name} ${cfg.monA.ip} --fsid ${cfg.clusterId} /tmp/monmap",
"sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring", "sudo -u ceph ceph-mon --mkfs -i ${cfg.monA.name} --monmap /tmp/monmap --keyring /tmp/ceph.mon.keyring",
"sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done", "sudo -u ceph touch /var/lib/ceph/mon/ceph-${cfg.monA.name}/done",
"systemctl start ceph-mon-${cfg.monA.name}" "systemctl start ceph-mon-${cfg.monA.name}",
); )
$monA->waitForUnit("ceph-mon-${cfg.monA.name}"); monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
$monA->mustSucceed("ceph mon enable-msgr2"); monA.succeed("ceph mon enable-msgr2")
# Can't check ceph status until a mon is up # Can't check ceph status until a mon is up
$monA->succeed("ceph -s | grep 'mon: 1 daemons'"); monA.succeed("ceph -s | grep 'mon: 1 daemons'")
# Start the ceph-mgr daemon, after copying in the keyring # Start the ceph-mgr daemon, after copying in the keyring
$monA->mustSucceed( monA.succeed(
"sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/", "sudo -u ceph mkdir -p /var/lib/ceph/mgr/ceph-${cfg.monA.name}/",
"ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring", "ceph auth get-or-create mgr.${cfg.monA.name} mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-${cfg.monA.name}/keyring",
"systemctl start ceph-mgr-${cfg.monA.name}" "systemctl start ceph-mgr-${cfg.monA.name}",
); )
$monA->waitForUnit("ceph-mgr-a"); monA.wait_for_unit("ceph-mgr-a")
$monA->waitUntilSucceeds("ceph -s | grep 'quorum ${cfg.monA.name}'"); monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
$monA->waitUntilSucceeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'"); monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
# Bootstrap both OSDs # Bootstrap both OSDs
$monA->mustSucceed( monA.succeed(
"mkfs.xfs /dev/vdb", "mkfs.xfs /dev/vdb",
"mkfs.xfs /dev/vdc", "mkfs.xfs /dev/vdc",
"mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}", "mkdir -p /var/lib/ceph/osd/ceph-${cfg.osd0.name}",
@ -114,60 +114,60 @@ let
"mount /dev/vdc /var/lib/ceph/osd/ceph-${cfg.osd1.name}", "mount /dev/vdc /var/lib/ceph/osd/ceph-${cfg.osd1.name}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}", "ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd0.name}/keyring --name osd.${cfg.osd0.name} --add-key ${cfg.osd0.key}",
"ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}", "ceph-authtool --create-keyring /var/lib/ceph/osd/ceph-${cfg.osd1.name}/keyring --name osd.${cfg.osd1.name} --add-key ${cfg.osd1.key}",
"echo '{\"cephx_secret\": \"${cfg.osd0.key}\"}' | ceph osd new ${cfg.osd0.uuid} -i -", 'echo \'{"cephx_secret": "${cfg.osd0.key}"}\' | ceph osd new ${cfg.osd0.uuid} -i -',
"echo '{\"cephx_secret\": \"${cfg.osd1.key}\"}' | ceph osd new ${cfg.osd1.uuid} -i -" 'echo \'{"cephx_secret": "${cfg.osd1.key}"}\' | ceph osd new ${cfg.osd1.uuid} -i -',
); )
# Initialize the OSDs with regular filestore # Initialize the OSDs with regular filestore
$monA->mustSucceed( monA.succeed(
"ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}", "ceph-osd -i ${cfg.osd0.name} --mkfs --osd-uuid ${cfg.osd0.uuid}",
"ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}", "ceph-osd -i ${cfg.osd1.name} --mkfs --osd-uuid ${cfg.osd1.uuid}",
"chown -R ceph:ceph /var/lib/ceph/osd", "chown -R ceph:ceph /var/lib/ceph/osd",
"systemctl start ceph-osd-${cfg.osd0.name}", "systemctl start ceph-osd-${cfg.osd0.name}",
"systemctl start ceph-osd-${cfg.osd1.name}" "systemctl start ceph-osd-${cfg.osd1.name}",
); )
$monA->waitUntilSucceeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'"); monA.wait_until_succeeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'")
$monA->waitUntilSucceeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'"); monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
$monA->waitUntilSucceeds("ceph -s | grep 'HEALTH_OK'"); monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
$monA->mustSucceed( monA.succeed(
"ceph osd pool create single-node-test 100 100", "ceph osd pool create single-node-test 100 100",
"ceph osd pool ls | grep 'single-node-test'", "ceph osd pool ls | grep 'single-node-test'",
"ceph osd pool rename single-node-test single-node-other-test", "ceph osd pool rename single-node-test single-node-other-test",
"ceph osd pool ls | grep 'single-node-other-test'" "ceph osd pool ls | grep 'single-node-other-test'",
); )
$monA->waitUntilSucceeds("ceph -s | grep '1 pools, 100 pgs'"); monA.wait_until_succeeds("ceph -s | grep '1 pools, 100 pgs'")
$monA->mustSucceed( monA.succeed(
"ceph osd getcrushmap -o crush", "ceph osd getcrushmap -o crush",
"crushtool -d crush -o decrushed", "crushtool -d crush -o decrushed",
"sed 's/step chooseleaf firstn 0 type host/step chooseleaf firstn 0 type osd/' decrushed > modcrush", "sed 's/step chooseleaf firstn 0 type host/step chooseleaf firstn 0 type osd/' decrushed > modcrush",
"crushtool -c modcrush -o recrushed", "crushtool -c modcrush -o recrushed",
"ceph osd setcrushmap -i recrushed", "ceph osd setcrushmap -i recrushed",
"ceph osd pool set single-node-other-test size 2" "ceph osd pool set single-node-other-test size 2",
); )
$monA->waitUntilSucceeds("ceph -s | grep 'HEALTH_OK'"); monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
$monA->waitUntilSucceeds("ceph -s | grep '100 active+clean'"); monA.wait_until_succeeds("ceph -s | grep '100 active+clean'")
$monA->mustFail( monA.fail(
"ceph osd pool ls | grep 'multi-node-test'", "ceph osd pool ls | grep 'multi-node-test'",
"ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it" "ceph osd pool delete single-node-other-test single-node-other-test --yes-i-really-really-mean-it",
); )
# Shut down ceph by stopping ceph.target. # Shut down ceph by stopping ceph.target.
$monA->mustSucceed("systemctl stop ceph.target"); monA.succeed("systemctl stop ceph.target")
# Start it up # Start it up
$monA->succeed("systemctl start ceph.target"); monA.succeed("systemctl start ceph.target")
$monA->waitForUnit("ceph-mon-${cfg.monA.name}"); monA.wait_for_unit("ceph-mon-${cfg.monA.name}")
$monA->waitForUnit("ceph-mgr-${cfg.monA.name}"); monA.wait_for_unit("ceph-mgr-${cfg.monA.name}")
$monA->waitForUnit("ceph-osd-${cfg.osd0.name}"); monA.wait_for_unit("ceph-osd-${cfg.osd0.name}")
$monA->waitForUnit("ceph-osd-${cfg.osd1.name}"); monA.wait_for_unit("ceph-osd-${cfg.osd1.name}")
# Ensure the cluster comes back up again # Ensure the cluster comes back up again
$monA->succeed("ceph -s | grep 'mon: 1 daemons'"); monA.succeed("ceph -s | grep 'mon: 1 daemons'")
$monA->waitUntilSucceeds("ceph -s | grep 'quorum ${cfg.monA.name}'"); monA.wait_until_succeeds("ceph -s | grep 'quorum ${cfg.monA.name}'")
$monA->waitUntilSucceeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'"); monA.wait_until_succeeds("ceph osd stat | grep -e '2 osds: 2 up[^,]*, 2 in'")
$monA->waitUntilSucceeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'"); monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'")
$monA->waitUntilSucceeds("ceph -s | grep 'HEALTH_OK'"); monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'")
''; '';
in { in {
name = "basic-single-node-ceph-cluster"; name = "basic-single-node-ceph-cluster";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
# Test whether `houndd` indexes nixpkgs # Test whether `houndd` indexes nixpkgs
import ./make-test.nix ({ pkgs, ... } : { import ./make-test-python.nix ({ pkgs, ... } : {
name = "hound"; name = "hound";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ grahamc ]; maintainers = [ grahamc ];
@ -46,13 +46,14 @@ import ./make-test.nix ({ pkgs, ... } : {
}; };
}; };
testScript = testScript = ''
'' startAll; start_all()
$machine->waitForUnit("network.target");
$machine->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"; name = "icingaweb2";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ das_j ]; maintainers = [ das_j ];
@ -64,8 +64,8 @@ import ./make-test.nix ({ pkgs, ... }: {
}; };
testScript = '' testScript = ''
startAll(); start_all()
$icingaweb2->waitForUnit("multi-user.target"); icingaweb2.wait_for_unit("multi-user.target")
$icingaweb2->succeed("curl -sSf http://icingaweb2/authentication/login"); icingaweb2.succeed("curl -sSf http://icingaweb2/authentication/login")
''; '';
}) })

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import ./make-test.nix ({ lib, ... }: import ./make-test-python.nix ({ lib, ... }:
with lib; with lib;
@ -11,8 +11,9 @@ with lib;
{ services.jackett.enable = true; }; { services.jackett.enable = true; };
testScript = '' testScript = ''
$machine->waitForUnit('jackett.service'); machine.start()
$machine->waitForOpenPort('9117'); machine.wait_for_unit("jackett.service")
$machine->succeed("curl --fail http://localhost:9117/"); machine.wait_for_open_port(9117)
machine.succeed("curl --fail http://localhost:9117/")
''; '';
}) })

View File

@ -3,7 +3,7 @@
# 2. jenkins user can be extended on both master and slave # 2. jenkins user can be extended on both master and slave
# 3. jenkins service not started on slave node # 3. jenkins service not started on slave node
import ./make-test.nix ({ pkgs, ...} : { import ./make-test-python.nix ({ pkgs, ...} : {
name = "jenkins"; name = "jenkins";
meta = with pkgs.stdenv.lib.maintainers; { meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ bjornfor coconnor domenkozar eelco ]; maintainers = [ bjornfor coconnor domenkozar eelco ];
@ -33,18 +33,17 @@ import ./make-test.nix ({ pkgs, ...} : {
}; };
testScript = '' testScript = ''
startAll; start_all()
$master->waitForUnit("jenkins"); master.wait_for_unit("jenkins")
$master->mustSucceed("curl http://localhost:8080 | grep 'Authentication required'"); assert "Authentication required" in master.succeed("curl http://localhost:8080")
print $master->execute("sudo -u jenkins groups"); for host in master, slave:
$master->mustSucceed("sudo -u jenkins groups | grep jenkins | grep users"); groups = host.succeed("sudo -u jenkins groups")
assert "jenkins" in groups
assert "users" in groups
print $slave->execute("sudo -u jenkins groups"); slave.fail("systemctl is-enabled jenkins.service")
$slave->mustSucceed("sudo -u jenkins groups | grep jenkins | grep users");
$slave->mustFail("systemctl is-enabled jenkins.service");
''; '';
}) })

View File

@ -1,4 +1,4 @@
import ../make-test.nix ({pkgs, ...}: { import ../make-test-python.nix ({pkgs, ...}: {
name = "kerberos_server-heimdal"; name = "kerberos_server-heimdal";
machine = { config, libs, pkgs, ...}: machine = { config, libs, pkgs, ...}:
{ services.kerberos_server = { services.kerberos_server =
@ -23,31 +23,20 @@ import ../make-test.nix ({pkgs, ...}: {
}; };
testScript = '' testScript = ''
$machine->start; machine.succeed(
"kadmin -l init --realm-max-ticket-life='8 day' --realm-max-renewable-life='10 day' FOO.BAR",
"systemctl restart kadmind.service kdc.service",
)
$machine->succeed( for unit in ["kadmind", "kdc", "kpasswdd"]:
"kadmin -l init --realm-max-ticket-life='8 day' \\ machine.wait_for_unit(f"{unit}.service")
--realm-max-renewable-life='10 day' FOO.BAR"
);
$machine->succeed("systemctl restart kadmind.service kdc.service"); machine.succeed(
$machine->waitForUnit("kadmind.service"); "kadmin -l add --password=admin_pw --use-defaults admin",
$machine->waitForUnit("kdc.service"); "kadmin -l ext_keytab --keytab=admin.keytab admin",
$machine->waitForUnit("kpasswdd.service"); "kadmin -p admin -K admin.keytab add --password=alice_pw --use-defaults alice",
"kadmin -l ext_keytab --keytab=alice.keytab alice",
$machine->succeed( "kinit -kt alice.keytab alice",
"kadmin -l add --password=admin_pw --use-defaults admin" )
);
$machine->succeed(
"kadmin -l ext_keytab --keytab=admin.keytab admin"
);
$machine->succeed(
"kadmin -p admin -K admin.keytab add --password=alice_pw --use-defaults \\
alice"
);
$machine->succeed(
"kadmin -l ext_keytab --keytab=alice.keytab alice"
);
$machine->succeed("kinit -kt alice.keytab alice");
''; '';
}) })

View File

@ -1,4 +1,4 @@
import ../make-test.nix ({pkgs, ...}: { import ../make-test-python.nix ({pkgs, ...}: {
name = "kerberos_server-mit"; name = "kerberos_server-mit";
machine = { config, libs, pkgs, ...}: machine = { config, libs, pkgs, ...}:
{ services.kerberos_server = { services.kerberos_server =
@ -24,22 +24,18 @@ import ../make-test.nix ({pkgs, ...}: {
}; };
testScript = '' testScript = ''
$machine->start; machine.succeed(
"kdb5_util create -s -r FOO.BAR -P master_key",
"systemctl restart kadmind.service kdc.service",
)
$machine->succeed( for unit in ["kadmind", "kdc"]:
"kdb5_util create -s -r FOO.BAR -P master_key" machine.wait_for_unit(f"{unit}.service")
);
$machine->succeed("systemctl restart kadmind.service kdc.service"); machine.succeed(
$machine->waitForUnit("kadmind.service"); "kadmin.local add_principal -pw admin_pw admin",
$machine->waitForUnit("kdc.service"); "kadmin -p admin -w admin_pw addprinc -pw alice_pw alice",
"echo alice_pw | sudo -u alice kinit",
$machine->succeed( )
"kadmin.local add_principal -pw admin_pw admin"
);
$machine->succeed(
"kadmin -p admin -w admin_pw addprinc -pw alice_pw alice"
);
$machine->succeed("echo alice_pw | sudo -u alice kinit");
''; '';
}) })

View File

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, ... }: { import ./make-test-python.nix ({ pkgs, ... }: {
name = "minidlna"; name = "minidlna";
nodes = { nodes = {
@ -29,11 +29,11 @@ import ./make-test.nix ({ pkgs, ... }: {
testScript = testScript =
'' ''
startAll; start_all()
$server->succeed("mkdir -p /tmp/stuff && chown minidlna: /tmp/stuff"); server.succeed("mkdir -p /tmp/stuff && chown minidlna: /tmp/stuff")
$server->waitForUnit("minidlna"); server.wait_for_unit("minidlna")
$server->waitForOpenPort("8200"); server.wait_for_open_port("8200")
$server->succeed("curl --fail http://localhost:8200/"); server.succeed("curl --fail http://localhost:8200/")
$client->succeed("curl --fail http://server:8200/"); client.succeed("curl --fail http://server:8200/")
''; '';
}) })

View File

@ -1,4 +1,4 @@
import ./make-test.nix ({ pkgs, lib, ... }: import ./make-test-python.nix ({ pkgs, lib, ... }:
let let
port = 3142; port = 3142;
@ -37,16 +37,20 @@ with lib;
}; };
}; };
testScript = '' testScript = ''
startAll; start_all()
$default->waitForUnit('miniflux.service'); default.wait_for_unit("miniflux.service")
$default->waitForOpenPort(${toString defaultPort}); default.wait_for_open_port(${toString defaultPort})
$default->succeed("curl --fail 'http://localhost:${toString defaultPort}/healthcheck' | grep -q OK"); default.succeed("curl --fail 'http://localhost:${toString defaultPort}/healthcheck' | grep -q OK")
$default->succeed("curl 'http://localhost:${toString defaultPort}/v1/me' -u '${defaultUsername}:${defaultPassword}' -H Content-Type:application/json | grep -q '\"is_admin\":true'"); default.succeed(
"curl 'http://localhost:${toString defaultPort}/v1/me' -u '${defaultUsername}:${defaultPassword}' -H Content-Type:application/json | grep -q '\"is_admin\":true'"
)
$customized->waitForUnit('miniflux.service'); customized.wait_for_unit("miniflux.service")
$customized->waitForOpenPort(${toString port}); customized.wait_for_open_port(${toString port})
$customized->succeed("curl --fail 'http://localhost:${toString port}/healthcheck' | grep -q OK"); customized.succeed("curl --fail 'http://localhost:${toString port}/healthcheck' | grep -q OK")
$customized->succeed("curl 'http://localhost:${toString port}/v1/me' -u '${username}:${password}' -H Content-Type:application/json | grep -q '\"is_admin\":true'"); customized.succeed(
"curl 'http://localhost:${toString port}/v1/me' -u '${username}:${password}' -H Content-Type:application/json | grep -q '\"is_admin\":true'"
)
''; '';
}) })

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