Merge branch 'master' into feature/plasma-5-18
This commit is contained in:
commit
5091d358b8
@ -57,10 +57,13 @@ indent_size = unset
|
||||
[deps.nix]
|
||||
insert_final_newline = unset
|
||||
|
||||
[eggs.nix]
|
||||
trim_trailing_whitespace = unset
|
||||
|
||||
[gemset.nix]
|
||||
insert_final_newline = unset
|
||||
|
||||
[node-packages.nix]
|
||||
[node-{composition,packages}.nix]
|
||||
insert_final_newline = unset
|
||||
|
||||
[nixos/modules/services/networking/ircd-hybrid/*.{conf,in}]
|
||||
@ -102,5 +105,8 @@ insert_final_newline = unset
|
||||
indent_size = unset
|
||||
trim_trailing_whitespace = unset
|
||||
|
||||
[pkgs/top-level/emscripten-packages.nix]
|
||||
trim_trailing_whitespace = unset
|
||||
|
||||
[pkgs/top-level/perl-packages.nix]
|
||||
indent_size = unset
|
||||
|
9
.github/CODEOWNERS
vendored
9
.github/CODEOWNERS
vendored
@ -195,10 +195,11 @@
|
||||
/pkgs/top-level/php-packages.nix @NixOS/php
|
||||
|
||||
# Podman, CRI-O modules and related
|
||||
/nixos/modules/virtualisation/containers.nix @NixOS/podman
|
||||
/nixos/modules/virtualisation/cri-o.nix @NixOS/podman
|
||||
/nixos/modules/virtualisation/podman.nix @NixOS/podman
|
||||
/nixos/tests/podman.nix @NixOS/podman
|
||||
/nixos/modules/virtualisation/containers.nix @NixOS/podman @zowoq
|
||||
/nixos/modules/virtualisation/cri-o.nix @NixOS/podman @zowoq
|
||||
/nixos/modules/virtualisation/podman.nix @NixOS/podman @zowoq
|
||||
/nixos/tests/cri-o.nix @NixOS/podman @zowoq
|
||||
/nixos/tests/podman.nix @NixOS/podman @zowoq
|
||||
|
||||
# Blockchains
|
||||
/pkgs/applications/blockchains @mmahut
|
||||
|
27
.github/workflows/editorconfig.yml
vendored
Normal file
27
.github/workflows/editorconfig.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: "Checking EditorConfig"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: technote-space/get-diff-action@v3.1.0
|
||||
- name: Fetch editorconfig-checker
|
||||
if: env.GIT_DIFF
|
||||
env:
|
||||
ECC_VERSION: "2.1.0"
|
||||
ECC_URL: "https://github.com/editorconfig-checker/editorconfig-checker/releases/download"
|
||||
run: |
|
||||
curl -sSf -O -L -C - "$ECC_URL/$ECC_VERSION/ec-linux-amd64.tar.gz" && \
|
||||
tar xzf ec-linux-amd64.tar.gz && \
|
||||
mv ./bin/ec-linux-amd64 ./bin/editorconfig-checker
|
||||
- name: Checking EditorConfig
|
||||
if: env.GIT_DIFF
|
||||
run: |
|
||||
./bin/editorconfig-checker -disable-indentation \
|
||||
${{ env.GIT_DIFF }}
|
21
.github/workflows/pending-clear.yml
vendored
Normal file
21
.github/workflows/pending-clear.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: "clear pending status"
|
||||
|
||||
on:
|
||||
check_suite:
|
||||
types: [ completed ]
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: clear pending status
|
||||
if: github.repository_owner == 'NixOS' && github.event.check_suite.app.name == 'OfBorg'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-d '{"state": "success", "target_url": " ", "description": " ", "context": "Wait for ofborg"}' \
|
||||
"https://api.github.com/repos/NixOS/nixpkgs/statuses/${{ github.event.check_suite.head_sha }}"
|
20
.github/workflows/pending-set.yml
vendored
Normal file
20
.github/workflows/pending-set.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: "set pending status"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: set pending status
|
||||
if: github.repository_owner == 'NixOS'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-d '{"state": "failure", "target_url": " ", "description": "This failed status will be cleared when ofborg finishes eval.", "context": "Wait for ofborg"}' \
|
||||
"https://api.github.com/repos/NixOS/nixpkgs/statuses/${{ github.event.pull_request.head.sha }}"
|
@ -436,6 +436,12 @@ lib.mapAttrs (n: v: v // { shortName = n; }) {
|
||||
};
|
||||
|
||||
# Proprietary binaries; free to redistribute without modification.
|
||||
databricks = {
|
||||
fullName = "Databricks Proprietary License";
|
||||
url = "https://pypi.org/project/databricks-connect";
|
||||
free = false;
|
||||
};
|
||||
|
||||
issl = {
|
||||
fullName = "Intel Simplified Software License";
|
||||
url = "https://software.intel.com/en-us/license/intel-simplified-software-license";
|
||||
|
@ -76,6 +76,7 @@ rec {
|
||||
# uname -r
|
||||
release = null;
|
||||
};
|
||||
isStatic = final.isWasm || final.isRedox;
|
||||
|
||||
kernelArch =
|
||||
if final.isAarch32 then "arm"
|
||||
|
@ -46,7 +46,7 @@ rec {
|
||||
|
||||
armv7a-android-prebuilt = {
|
||||
config = "armv7a-unknown-linux-androideabi";
|
||||
sdkVer = "24";
|
||||
sdkVer = "29";
|
||||
ndkVer = "18b";
|
||||
platform = platforms.armv7a-android;
|
||||
useAndroidPrebuilt = true;
|
||||
@ -54,7 +54,7 @@ rec {
|
||||
|
||||
aarch64-android-prebuilt = {
|
||||
config = "aarch64-unknown-linux-android";
|
||||
sdkVer = "24";
|
||||
sdkVer = "29";
|
||||
ndkVer = "18b";
|
||||
platform = platforms.aarch64-multiplatform;
|
||||
useAndroidPrebuilt = true;
|
||||
|
@ -17,7 +17,6 @@ pkgs.runCommandNoCC "nixpkgs-lib-tests" {
|
||||
export TEST_ROOT=$(pwd)/test-tmp
|
||||
export NIX_BUILD_HOOK=
|
||||
export NIX_CONF_DIR=$TEST_ROOT/etc
|
||||
export NIX_DB_DIR=$TEST_ROOT/db
|
||||
export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
|
||||
export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
|
||||
export NIX_STATE_DIR=$TEST_ROOT/var/nix
|
||||
|
@ -254,6 +254,12 @@
|
||||
githubId = 732652;
|
||||
name = "Andreas Herrmann";
|
||||
};
|
||||
ahrzb = {
|
||||
email = "ahrzb5@gmail.com";
|
||||
github = "ahrzb";
|
||||
githubId = 5220438;
|
||||
name = "AmirHossein Roozbahani";
|
||||
};
|
||||
ahuzik = {
|
||||
email = "ales.guzik@gmail.com";
|
||||
github = "alesguzik";
|
||||
@ -466,6 +472,12 @@
|
||||
githubId = 858965;
|
||||
name = "Andrew Morsillo";
|
||||
};
|
||||
andehen = {
|
||||
email = "git@andehen.net";
|
||||
github = "andehen";
|
||||
githubId = 754494;
|
||||
name = "Anders Asheim Hennum";
|
||||
};
|
||||
andersk = {
|
||||
email = "andersk@mit.edu";
|
||||
github = "andersk";
|
||||
@ -2705,6 +2717,12 @@
|
||||
githubId = 857308;
|
||||
name = "Joe Hermaszewski";
|
||||
};
|
||||
extends = {
|
||||
email = "sharosari@gmail.com";
|
||||
github = "ImExtends";
|
||||
githubId = 55919390;
|
||||
name = "Vincent VILLIAUMEY";
|
||||
};
|
||||
eyjhb = {
|
||||
email = "eyjhbb@gmail.com";
|
||||
github = "eyJhb";
|
||||
@ -2861,6 +2879,12 @@
|
||||
githubId = 5918766;
|
||||
name = "Franz Thoma";
|
||||
};
|
||||
fooker = {
|
||||
email = "fooker@lab.sh";
|
||||
github = "fooker";
|
||||
githubId = 405105;
|
||||
name = "Dustin Frisch";
|
||||
};
|
||||
forkk = {
|
||||
email = "forkk@forkk.net";
|
||||
github = "forkk";
|
||||
@ -3343,6 +3367,12 @@
|
||||
githubId = 131599;
|
||||
name = "Martin Weinelt";
|
||||
};
|
||||
hh = {
|
||||
email = "hh@m-labs.hk";
|
||||
github = "HarryMakes";
|
||||
githubId = 66358631;
|
||||
name = "Harry Ho";
|
||||
};
|
||||
hhm = {
|
||||
email = "heehooman+nixpkgs@gmail.com";
|
||||
github = "hhm0";
|
||||
@ -3370,10 +3400,14 @@
|
||||
name = "Hlodver Sigurdsson";
|
||||
};
|
||||
hugoreeves = {
|
||||
email = "hugolreeves@gmail.com";
|
||||
email = "hugo@hugoreeves.com";
|
||||
github = "hugoreeves";
|
||||
githubId = 20039091;
|
||||
name = "Hugo Reeves";
|
||||
keys = [{
|
||||
longkeyid = "rsa4096/0x49FA39F8A7F735F9";
|
||||
fingerprint = "78C2 E81C 828A 420B 269A EBC1 49FA 39F8 A7F7 35F9";
|
||||
}];
|
||||
};
|
||||
hodapp = {
|
||||
email = "hodapp87@gmail.com";
|
||||
@ -3715,6 +3749,12 @@
|
||||
}];
|
||||
name = "Jiri Daněk";
|
||||
};
|
||||
jdbaldry = {
|
||||
email = "jack.baldry@grafana.com";
|
||||
github = "jdbaldry";
|
||||
githubId = 4599384;
|
||||
name = "Jack Baldry";
|
||||
};
|
||||
jdehaas = {
|
||||
email = "qqlq@nullptr.club";
|
||||
github = "jeroendehaas";
|
||||
@ -3835,6 +3875,12 @@
|
||||
githubId = 51518420;
|
||||
name = "jitwit";
|
||||
};
|
||||
jjjollyjim = {
|
||||
email = "jamie@kwiius.com";
|
||||
github = "JJJollyjim";
|
||||
githubId = 691552;
|
||||
name = "Jamie McClymont";
|
||||
};
|
||||
jk = {
|
||||
email = "hello+nixpkgs@j-k.io";
|
||||
github = "06kellyjac";
|
||||
@ -4264,6 +4310,12 @@
|
||||
githubId = 494012;
|
||||
name = "Kevin Cox";
|
||||
};
|
||||
kfollesdal = {
|
||||
email = "kfollesdal@gmail.com";
|
||||
github = "kfollesdal";
|
||||
githubId = 546087;
|
||||
name = "Kristoffer K. Føllesdal";
|
||||
};
|
||||
khumba = {
|
||||
email = "bog@khumba.net";
|
||||
github = "khumba";
|
||||
@ -6365,6 +6417,12 @@
|
||||
githubId = 157610;
|
||||
name = "Piotr Bogdan";
|
||||
};
|
||||
pblkt = {
|
||||
email = "pebblekite@gmail.com";
|
||||
github = "pblkt";
|
||||
githubId = 6498458;
|
||||
name = "pebble kite";
|
||||
};
|
||||
pcarrier = {
|
||||
email = "pc@rrier.ca";
|
||||
github = "pcarrier";
|
||||
@ -6713,6 +6771,12 @@
|
||||
githubId = 37715;
|
||||
name = "Brian McKenna";
|
||||
};
|
||||
purcell = {
|
||||
email = "steve@sanityinc.com";
|
||||
github = "purcell";
|
||||
githubId = 5636;
|
||||
name = "Steve Purcell";
|
||||
};
|
||||
puzzlewolf = {
|
||||
email = "nixos@nora.pink";
|
||||
github = "puzzlewolf";
|
||||
@ -6749,6 +6813,12 @@
|
||||
githubId = 115877;
|
||||
name = "Kenny Shen";
|
||||
};
|
||||
quentini = {
|
||||
email = "quentini@airmail.cc";
|
||||
github = "QuentinI";
|
||||
githubId = 18196237;
|
||||
name = "Quentin Inkling";
|
||||
};
|
||||
qyliss = {
|
||||
email = "hi@alyssa.is";
|
||||
github = "alyssais";
|
||||
@ -7297,6 +7367,12 @@
|
||||
githubId = 1153271;
|
||||
name = "Sander van der Burg";
|
||||
};
|
||||
sarcasticadmin = {
|
||||
email = "rob@sarcasticadmin.com";
|
||||
github = "sarcasticadmin";
|
||||
githubId = 30531572;
|
||||
name = "Robert James Hernandez";
|
||||
};
|
||||
sargon = {
|
||||
email = "danielehlers@mindeye.net";
|
||||
github = "sargon";
|
||||
@ -7931,6 +8007,12 @@
|
||||
githubId = 65870;
|
||||
name = "Сухарик";
|
||||
};
|
||||
SuperSandro2000 = {
|
||||
email = "sandro.jaeckel@gmail.com";
|
||||
github = "SuperSandro2000";
|
||||
githubId = 7258858;
|
||||
name = "Sandro Jäckel";
|
||||
};
|
||||
SuprDewd = {
|
||||
email = "suprdewd@gmail.com";
|
||||
github = "SuprDewd";
|
||||
@ -8127,6 +8209,12 @@
|
||||
githubId = 863327;
|
||||
name = "Tyler Benster";
|
||||
};
|
||||
tcbravo = {
|
||||
email = "tomas.bravo@protonmail.ch";
|
||||
github = "tcbravo";
|
||||
githubId = 66133083;
|
||||
name = "Tomas Bravo";
|
||||
};
|
||||
tckmn = {
|
||||
email = "andy@tck.mn";
|
||||
github = "tckmn";
|
||||
@ -8517,6 +8605,12 @@
|
||||
githubId = 699403;
|
||||
name = "Tomas Vestelind";
|
||||
};
|
||||
tviti = {
|
||||
email = "tviti@hawaii.edu";
|
||||
github = "tviti";
|
||||
githubId = 2251912;
|
||||
name = "Taylor Viti";
|
||||
};
|
||||
tvorog = {
|
||||
email = "marszaripov@gmail.com";
|
||||
github = "tvorog";
|
||||
@ -8732,6 +8826,16 @@
|
||||
fingerprint = "B3C0 DA1A C18B 82E8 CA8B B1D1 4F62 CD07 CE64 796A";
|
||||
}];
|
||||
};
|
||||
vincentbernat = {
|
||||
email = "vincent@bernat.ch";
|
||||
github = "vincentbernat";
|
||||
githubId = 631446;
|
||||
name = "Vincent Bernat";
|
||||
keys = [{
|
||||
longkeyid = "rsa4096/0x95A42FE8353525F9";
|
||||
fingerprint = "AEF2 3487 66F3 71C6 89A7 3600 95A4 2FE8 3535 25F9";
|
||||
}];
|
||||
};
|
||||
vinymeuh = {
|
||||
email = "vinymeuh@gmail.com";
|
||||
github = "vinymeuh";
|
||||
@ -9126,6 +9230,16 @@
|
||||
fingerprint = "85F8 E850 F8F2 F823 F934 535B EC50 6589 9AEA AF4C";
|
||||
}];
|
||||
};
|
||||
yusdacra = {
|
||||
email = "y.bera003.06@protonmail.com";
|
||||
github = "yusdacra";
|
||||
githubId = 19897088;
|
||||
name = "Yusuf Bera Ertan";
|
||||
keys = [{
|
||||
longkeyid = "rsa2048/0x61807181F60EFCB2";
|
||||
fingerprint = "9270 66BD 8125 A45B 4AC4 0326 6180 7181 F60E FCB2";
|
||||
}];
|
||||
};
|
||||
yvesf = {
|
||||
email = "yvesf+nix@xapek.org";
|
||||
github = "yvesf";
|
||||
@ -9398,4 +9512,26 @@
|
||||
github = "fzakaria";
|
||||
githubId = 605070;
|
||||
};
|
||||
nagisa = {
|
||||
name = "Simonas Kazlauskas";
|
||||
email = "nixpkgs@kazlauskas.me";
|
||||
github = "nagisa";
|
||||
githubId = 679122;
|
||||
};
|
||||
yevhenshymotiuk = {
|
||||
name = "Yevhen Shymotiuk";
|
||||
email = "yevhenshymotiuk@gmail.com";
|
||||
github = "yevhenshymotiuk";
|
||||
githubId = 44244245;
|
||||
};
|
||||
hmenke = {
|
||||
name = "Henri Menke";
|
||||
email = "henri@henrimenke.de";
|
||||
github = "hmenke";
|
||||
githubId = 1903556;
|
||||
keys = [{
|
||||
longkeyid = "rsa4096/0xD65C9AFB4C224DA3";
|
||||
fingerprint = "F1C5 760E 45B9 9A44 72E9 6BFB D65C 9AFB 4C22 4DA3";
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ lua-cmsgpack,,,,,
|
||||
lua-iconv,,,,,
|
||||
lua-lsp,,http://luarocks.org/dev,,,
|
||||
lua-messagepack,,,,,
|
||||
lua-resty-http,,,,,
|
||||
lua-resty-jwt,,,,,
|
||||
lua-resty-openidc,,,,,
|
||||
lua-resty-session,,,,,
|
||||
lua-term,,,,,
|
||||
lua-toml,,,,,
|
||||
lua-zlib,,,,,koral
|
||||
|
|
@ -70,35 +70,12 @@ Platform Vendor Advanced Micro Devices, Inc.</screen>
|
||||
Core Next</link> (GCN) GPUs are supported through the
|
||||
<package>rocm-opencl-icd</package> package. Adding this package to
|
||||
<xref linkend="opt-hardware.opengl.extraPackages"/> enables OpenCL
|
||||
support. However, OpenCL Image support is provided through the
|
||||
non-free <package>rocm-runtime-ext</package> package. This package can
|
||||
be added to the same configuration option, but requires that
|
||||
<varname>allowUnfree</varname> option is is enabled for nixpkgs. Full
|
||||
OpenCL support on supported AMD GPUs is thus enabled as follows:
|
||||
support:
|
||||
|
||||
<programlisting><xref linkend="opt-hardware.opengl.extraPackages"/> = [
|
||||
rocm-opencl-icd
|
||||
rocm-runtime-ext
|
||||
];</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It is also possible to use the OpenCL Image extension without a
|
||||
system-wide installation of the <package>rocm-runtime-ext</package>
|
||||
package by setting the <varname>ROCR_EXT_DIR</varname> environment
|
||||
variable to the directory that contains the extension:
|
||||
|
||||
<screen><prompt>$</prompt> export \
|
||||
ROCR_EXT_DIR=`nix-build '<nixpkgs>' --no-out-link -A rocm-runtime-ext`/lib/rocm-runtime-ext</screen>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
With either approach, you can verify that OpenCL Image support
|
||||
is indeed working with the <command>clinfo</command> command:
|
||||
|
||||
<screen><prompt>$</prompt> clinfo | grep Image
|
||||
Image support Yes</screen>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="sec-gpu-accel-opencl-intel">
|
||||
|
@ -136,7 +136,7 @@
|
||||
<filename>/mnt</filename>:
|
||||
</para>
|
||||
<screen>
|
||||
# nixos-enter /mnt
|
||||
# nixos-enter --root /mnt
|
||||
</screen>
|
||||
<para>
|
||||
Run a shell command:
|
||||
|
@ -128,7 +128,7 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Two new option <link linkend="opt-documentation.man.generateCaches">documentation.man.generateCaches</link>
|
||||
The new option <link linkend="opt-documentation.man.generateCaches">documentation.man.generateCaches</link>
|
||||
has been added to automatically generate the <literal>man-db</literal> caches, which are needed by utilities
|
||||
like <command>whatis</command> and <command>apropos</command>. The caches are generated during the build of
|
||||
the NixOS configuration: since this can be expensive when a large number of packages are installed, the
|
||||
@ -137,7 +137,7 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>services.postfix.sslCACert</varname> was replaced by <varname>services.postfix.tlsTrustedAuthorities</varname> which now defaults to system certifcate authorities.
|
||||
<varname>services.postfix.sslCACert</varname> was replaced by <varname>services.postfix.tlsTrustedAuthorities</varname> which now defaults to system certificate authorities.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@ -156,6 +156,64 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
Support for built-in LCDs in various pieces of Logitech hardware (keyboards and USB speakers). <varname>hardware.logitech.lcd.enable</varname> enables support for all hardware supported by the g15daemon project.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Zabbix now defaults to 5.0, updated from 4.4. Please carefully read through
|
||||
<link xlink:href="https://www.zabbix.com/documentation/current/manual/installation/upgrade/sources">the upgrade guide</link>
|
||||
and apply any changes required. Be sure to take special note of the section on
|
||||
<link xlink:href="https://www.zabbix.com/documentation/current/manual/installation/upgrade_notes_500#enabling_extended_range_of_numeric_float_values">enabling extended range of numeric (float) values</link>
|
||||
as you will need to apply this database migration manually.
|
||||
</para>
|
||||
<para>
|
||||
If you are using Zabbix Server with a MySQL or MariaDB database you should note that using a character set of <literal>utf8</literal> and a collate of <literal>utf8_bin</literal> has become mandatory with
|
||||
this release. See the upstream <link xlink:href="https://support.zabbix.com/browse/ZBX-17357">issue</link> for further discussion. Before upgrading you should check the character set and collation used by
|
||||
your database and ensure they are correct:
|
||||
<programlisting>
|
||||
SELECT
|
||||
default_character_set_name,
|
||||
default_collation_name
|
||||
FROM
|
||||
information_schema.schemata
|
||||
WHERE
|
||||
schema_name = 'zabbix';
|
||||
</programlisting>
|
||||
If these values are not correct you should take a backup of your database and convert the character set and collation as required. Here is an
|
||||
<link xlink:href="https://www.zabbix.com/forum/zabbix-help/396573-reinstall-after-upgrade?p=396891#post396891">example</link> of how to do so, taken from
|
||||
the Zabbix forums:
|
||||
<programlisting>
|
||||
ALTER DATABASE `zabbix` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
-- the following will produce a list of SQL commands you should subsequently execute
|
||||
SELECT CONCAT("ALTER TABLE ", TABLE_NAME," CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;") AS ExecuteTheString
|
||||
FROM information_schema.`COLUMNS`
|
||||
WHERE table_schema = "zabbix" AND COLLATION_NAME = "utf8_general_ci";
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The NixOS module system now supports freeform modules as a mix between <literal>types.attrsOf</literal> and <literal>types.submodule</literal>. These allow you to explicitly declare a subset of options while still permitting definitions without an associated option. See <xref linkend='sec-freeform-modules'/> for how to use them.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The GRUB module gained support for basic password protection, which
|
||||
allows to restrict non-default entries in the boot menu to one or more
|
||||
users. The users and passwords are defined via the option
|
||||
<option>boot.loader.grub.users</option>.
|
||||
Note: Password support is only avaiable in GRUB version 2.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Following its deprecation in 20.03, the Perl NixOS test driver has been removed.
|
||||
All remaining tests have been ported to the Python test framework.
|
||||
Code outside nixpkgs using <filename>make-test.nix</filename> or
|
||||
<filename>testing.nix</filename> needs to be ported to
|
||||
<filename>make-test-python.nix</filename> and
|
||||
<filename>testing-python.nix</filename> respectively.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
@ -175,6 +233,11 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
<para>
|
||||
There is a new <xref linkend="opt-security.doas.enable"/> module that provides <command>doas</command>, a lighter alternative to <command>sudo</command> with many of the same features.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xlink:href="https://hercules-ci.com">Hercules CI</link> Agent is a specialized build agent for projects built with Nix. See the <link xlink:href="https://nixos.org/nixos/options.html#services.hercules-ci-agent">options</link> and <link xlink:href="https://docs.hercules-ci.com/hercules-ci/getting-started/#deploy-agent">setup</link>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
@ -199,7 +262,7 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
in the source tree for downloaded modules instead of using go's <link
|
||||
xlink:href="https://golang.org/cmd/go/#hdr-Module_proxy_protocol">module
|
||||
proxy protocol</link>. This storage format is simpler and therefore less
|
||||
likekly to break with future versions of go. As a result
|
||||
likely to break with future versions of go. As a result
|
||||
<literal>buildGoModule</literal> switched from
|
||||
<literal>modSha256</literal> to the <literal>vendorSha256</literal>
|
||||
attribute to pin fetched version data.
|
||||
@ -211,7 +274,7 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
<link xlink:href="https://grafana.com/docs/grafana/latest/guides/whats-new-in-v6-4/">deprecated in Grafana</link>
|
||||
and the <package>phantomjs</package> project is
|
||||
<link xlink:href="https://github.com/ariya/phantomjs/issues/15344#issue-302015362">currently unmaintained</link>.
|
||||
It can still be enabled by providing <literal>phantomJsSupport = true</literal> to the package instanciation:
|
||||
It can still be enabled by providing <literal>phantomJsSupport = true</literal> to the package instantiation:
|
||||
<programlisting>{
|
||||
services.grafana.package = pkgs.grafana.overrideAttrs (oldAttrs: rec {
|
||||
phantomJsSupport = false;
|
||||
@ -223,7 +286,7 @@ GRANT ALL PRIVILEGES ON *.* TO 'mysql'@'localhost' WITH GRANT OPTION;
|
||||
<para>
|
||||
The <link linkend="opt-services.supybot.enable">supybot</link> module now uses <literal>/var/lib/supybot</literal>
|
||||
as its default <link linkend="opt-services.supybot.stateDir">stateDir</link> path if <literal>stateVersion</literal>
|
||||
is 20.09 or higher. It also enables number of
|
||||
is 20.09 or higher. It also enables a number of
|
||||
<link xlink:href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Sandboxing">systemd sandboxing options</link>
|
||||
which may possibly interfere with some plugins. If this is the case you can disable the options through attributes in
|
||||
<option>systemd.services.supybot.serviceConfig</option>.
|
||||
@ -697,6 +760,13 @@ CREATE ROLE postgres LOGIN SUPERUSER;
|
||||
The USBGuard module now removes options and instead hardcodes values for <literal>IPCAccessControlFiles</literal>, <literal>ruleFiles</literal>, and <literal>auditFilePath</literal>. Audit logs can be found in the journal.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The NixOS module system now evaluates option definitions more strictly, allowing it to detect a larger set of problems.
|
||||
As a result, what previously evaluated may not do so anymore.
|
||||
See <link xlink:href="https://github.com/NixOS/nixpkgs/pull/82743#issuecomment-674520472">the PR that changed this</link> for more info.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
@ -915,9 +985,18 @@ services.transmission.settings.rpc-bind-address = "0.0.0.0";
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Nginx module <literal>nginxModules.fastcgi-cache-purge</literal> renamed to official name <literal>nginxModules.cache-purge</literal>.
|
||||
Nginx module <literal>nginxModules.ngx_aws_auth</literal> renamed to official name <literal>nginxModules.aws-auth</literal>.
|
||||
The packages <package>perl</package>, <package>rsync</package> and <package>strace</package> were removed from <option>systemPackages</option>. If you need them, install them again with <code><xref linkend="opt-environment.systemPackages"/> = with pkgs; [ perl rsync strace ];</code> in your <filename>configuration.nix</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The <literal>undervolt</literal> option no longer needs to apply its
|
||||
settings every 30s. If they still become undone, open an issue and restore
|
||||
the previous behaviour using <literal>undervolt.useTimer</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
|
@ -24,11 +24,11 @@
|
||||
check ? true
|
||||
, prefix ? []
|
||||
, lib ? import ../../lib
|
||||
, extraModules ? let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH";
|
||||
in if e == "" then [] else [(import e)]
|
||||
}:
|
||||
|
||||
let extraArgs_ = extraArgs; pkgs_ = pkgs;
|
||||
extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH";
|
||||
in if e == "" then [] else [(import e)];
|
||||
in
|
||||
|
||||
let
|
||||
|
@ -22,9 +22,9 @@ rec {
|
||||
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
|
||||
|
||||
qemuBinary = qemuPkg: {
|
||||
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu host";
|
||||
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu max";
|
||||
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -enable-kvm -machine virt -cpu host";
|
||||
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -enable-kvm -machine virt,gic-version=host -cpu host";
|
||||
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu host";
|
||||
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu max";
|
||||
}.${pkgs.stdenv.hostPlatform.system} or "${qemuPkg}/bin/qemu-kvm";
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
package Logger;
|
||||
|
||||
use strict;
|
||||
use Thread::Queue;
|
||||
use XML::Writer;
|
||||
use Encode qw(decode encode);
|
||||
use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
|
||||
|
||||
sub new {
|
||||
my ($class) = @_;
|
||||
|
||||
my $logFile = defined $ENV{LOGFILE} ? "$ENV{LOGFILE}" : "/dev/null";
|
||||
my $log = new XML::Writer(OUTPUT => new IO::File(">$logFile"));
|
||||
|
||||
my $self = {
|
||||
log => $log,
|
||||
logQueue => Thread::Queue->new()
|
||||
};
|
||||
|
||||
$self->{log}->startTag("logfile");
|
||||
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub close {
|
||||
my ($self) = @_;
|
||||
$self->{log}->endTag("logfile");
|
||||
$self->{log}->end;
|
||||
}
|
||||
|
||||
sub drainLogQueue {
|
||||
my ($self) = @_;
|
||||
while (defined (my $item = $self->{logQueue}->dequeue_nb())) {
|
||||
$self->{log}->dataElement("line", sanitise($item->{msg}), 'machine' => $item->{machine}, 'type' => 'serial');
|
||||
}
|
||||
}
|
||||
|
||||
sub maybePrefix {
|
||||
my ($msg, $attrs) = @_;
|
||||
$msg = $attrs->{machine} . ": " . $msg if defined $attrs->{machine};
|
||||
return $msg;
|
||||
}
|
||||
|
||||
sub nest {
|
||||
my ($self, $msg, $coderef, $attrs) = @_;
|
||||
print STDERR maybePrefix("$msg\n", $attrs);
|
||||
$self->{log}->startTag("nest");
|
||||
$self->{log}->dataElement("head", $msg, %{$attrs});
|
||||
my $now = clock_gettime(CLOCK_MONOTONIC);
|
||||
$self->drainLogQueue();
|
||||
eval { &$coderef };
|
||||
my $res = $@;
|
||||
$self->drainLogQueue();
|
||||
$self->log(sprintf("(%.2f seconds)", clock_gettime(CLOCK_MONOTONIC) - $now));
|
||||
$self->{log}->endTag("nest");
|
||||
die $@ if $@;
|
||||
}
|
||||
|
||||
sub sanitise {
|
||||
my ($s) = @_;
|
||||
$s =~ s/[[:cntrl:]\xff]//g;
|
||||
$s = decode('UTF-8', $s, Encode::FB_DEFAULT);
|
||||
return encode('UTF-8', $s, Encode::FB_CROAK);
|
||||
}
|
||||
|
||||
sub log {
|
||||
my ($self, $msg, $attrs) = @_;
|
||||
chomp $msg;
|
||||
print STDERR maybePrefix("$msg\n", $attrs);
|
||||
$self->drainLogQueue();
|
||||
$self->{log}->dataElement("line", $msg, %{$attrs});
|
||||
}
|
||||
|
||||
1;
|
@ -1,734 +0,0 @@
|
||||
package Machine;
|
||||
|
||||
use strict;
|
||||
use threads;
|
||||
use Socket;
|
||||
use IO::Handle;
|
||||
use POSIX qw(dup2);
|
||||
use FileHandle;
|
||||
use Cwd;
|
||||
use File::Basename;
|
||||
use File::Path qw(make_path);
|
||||
use File::Slurp;
|
||||
use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
|
||||
|
||||
|
||||
my $showGraphics = defined $ENV{'DISPLAY'};
|
||||
|
||||
my $sharedDir;
|
||||
|
||||
|
||||
sub new {
|
||||
my ($class, $args) = @_;
|
||||
|
||||
my $startCommand = $args->{startCommand};
|
||||
|
||||
my $name = $args->{name};
|
||||
if (!$name) {
|
||||
$startCommand =~ /run-(.*)-vm$/ if defined $startCommand;
|
||||
$name = $1 || "machine";
|
||||
}
|
||||
|
||||
if (!$startCommand) {
|
||||
# !!! merge with qemu-vm.nix.
|
||||
my $netBackend = "-netdev user,id=net0";
|
||||
my $netFrontend = "-device virtio-net-pci,netdev=net0";
|
||||
|
||||
$netBackend .= "," . $args->{netBackendArgs}
|
||||
if defined $args->{netBackendArgs};
|
||||
|
||||
$netFrontend .= "," . $args->{netFrontendArgs}
|
||||
if defined $args->{netFrontendArgs};
|
||||
|
||||
$startCommand =
|
||||
"qemu-kvm -m 384 $netBackend $netFrontend \$QEMU_OPTS ";
|
||||
|
||||
if (defined $args->{hda}) {
|
||||
if ($args->{hdaInterface} eq "scsi") {
|
||||
$startCommand .= "-drive id=hda,file="
|
||||
. Cwd::abs_path($args->{hda})
|
||||
. ",werror=report,if=none "
|
||||
. "-device scsi-hd,drive=hda ";
|
||||
} else {
|
||||
$startCommand .= "-drive file=" . Cwd::abs_path($args->{hda})
|
||||
. ",if=" . $args->{hdaInterface}
|
||||
. ",werror=report ";
|
||||
}
|
||||
}
|
||||
|
||||
$startCommand .= "-cdrom $args->{cdrom} "
|
||||
if defined $args->{cdrom};
|
||||
$startCommand .= "-device piix3-usb-uhci -drive id=usbdisk,file=$args->{usb},if=none,readonly -device usb-storage,drive=usbdisk "
|
||||
if defined $args->{usb};
|
||||
$startCommand .= "-bios $args->{bios} "
|
||||
if defined $args->{bios};
|
||||
$startCommand .= $args->{qemuFlags} || "";
|
||||
}
|
||||
|
||||
my $tmpDir = $ENV{'TMPDIR'} || "/tmp";
|
||||
unless (defined $sharedDir) {
|
||||
$sharedDir = $tmpDir . "/xchg-shared";
|
||||
make_path($sharedDir, { mode => 0700, owner => $< });
|
||||
}
|
||||
|
||||
my $allowReboot = 0;
|
||||
$allowReboot = $args->{allowReboot} if defined $args->{allowReboot};
|
||||
|
||||
my $self = {
|
||||
startCommand => $startCommand,
|
||||
name => $name,
|
||||
allowReboot => $allowReboot,
|
||||
booted => 0,
|
||||
pid => 0,
|
||||
connected => 0,
|
||||
socket => undef,
|
||||
stateDir => "$tmpDir/vm-state-$name",
|
||||
monitor => undef,
|
||||
log => $args->{log},
|
||||
redirectSerial => $args->{redirectSerial} // 1,
|
||||
};
|
||||
|
||||
mkdir $self->{stateDir}, 0700;
|
||||
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub log {
|
||||
my ($self, $msg) = @_;
|
||||
$self->{log}->log($msg, { machine => $self->{name} });
|
||||
}
|
||||
|
||||
|
||||
sub nest {
|
||||
my ($self, $msg, $coderef, $attrs) = @_;
|
||||
$self->{log}->nest($msg, $coderef, { %{$attrs || {}}, machine => $self->{name} });
|
||||
}
|
||||
|
||||
|
||||
sub name {
|
||||
my ($self) = @_;
|
||||
return $self->{name};
|
||||
}
|
||||
|
||||
|
||||
sub stateDir {
|
||||
my ($self) = @_;
|
||||
return $self->{stateDir};
|
||||
}
|
||||
|
||||
|
||||
sub start {
|
||||
my ($self) = @_;
|
||||
return if $self->{booted};
|
||||
|
||||
$self->log("starting vm");
|
||||
|
||||
# Create a socket pair for the serial line input/output of the VM.
|
||||
my ($serialP, $serialC);
|
||||
socketpair($serialP, $serialC, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
|
||||
# Create a Unix domain socket to which QEMU's monitor will connect.
|
||||
my $monitorPath = $self->{stateDir} . "/monitor";
|
||||
unlink $monitorPath;
|
||||
my $monitorS;
|
||||
socket($monitorS, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
bind($monitorS, sockaddr_un($monitorPath)) or die "cannot bind monitor socket: $!";
|
||||
listen($monitorS, 1) or die;
|
||||
|
||||
# Create a Unix domain socket to which the root shell in the guest will connect.
|
||||
my $shellPath = $self->{stateDir} . "/shell";
|
||||
unlink $shellPath;
|
||||
my $shellS;
|
||||
socket($shellS, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
bind($shellS, sockaddr_un($shellPath)) or die "cannot bind shell socket: $!";
|
||||
listen($shellS, 1) or die;
|
||||
|
||||
# Start the VM.
|
||||
my $pid = fork();
|
||||
die if $pid == -1;
|
||||
|
||||
if ($pid == 0) {
|
||||
close $serialP;
|
||||
close $monitorS;
|
||||
close $shellS;
|
||||
if ($self->{redirectSerial}) {
|
||||
open NUL, "</dev/null" or die;
|
||||
dup2(fileno(NUL), fileno(STDIN));
|
||||
dup2(fileno($serialC), fileno(STDOUT));
|
||||
dup2(fileno($serialC), fileno(STDERR));
|
||||
}
|
||||
$ENV{TMPDIR} = $self->{stateDir};
|
||||
$ENV{SHARED_DIR} = $sharedDir;
|
||||
$ENV{USE_TMPDIR} = 1;
|
||||
$ENV{QEMU_OPTS} =
|
||||
($self->{allowReboot} ? "" : "-no-reboot ") .
|
||||
"-monitor unix:./monitor -chardev socket,id=shell,path=./shell " .
|
||||
"-device virtio-serial -device virtconsole,chardev=shell " .
|
||||
"-device virtio-rng-pci " .
|
||||
($showGraphics ? "-serial stdio" : "-nographic") . " " . ($ENV{QEMU_OPTS} || "");
|
||||
chdir $self->{stateDir} or die;
|
||||
exec $self->{startCommand};
|
||||
die "running VM script: $!";
|
||||
}
|
||||
|
||||
# Process serial line output.
|
||||
close $serialC;
|
||||
|
||||
threads->create(\&processSerialOutput, $self, $serialP)->detach;
|
||||
|
||||
sub processSerialOutput {
|
||||
my ($self, $serialP) = @_;
|
||||
while (<$serialP>) {
|
||||
chomp;
|
||||
s/\r$//;
|
||||
print STDERR $self->{name}, "# $_\n";
|
||||
$self->{log}->{logQueue}->enqueue({msg => $_, machine => $self->{name}}); # !!!
|
||||
}
|
||||
}
|
||||
|
||||
eval {
|
||||
local $SIG{CHLD} = sub { die "QEMU died prematurely\n"; };
|
||||
|
||||
# Wait until QEMU connects to the monitor.
|
||||
accept($self->{monitor}, $monitorS) or die;
|
||||
|
||||
# Wait until QEMU connects to the root shell socket. QEMU
|
||||
# does so immediately; this doesn't mean that the root shell
|
||||
# has connected yet inside the guest.
|
||||
accept($self->{socket}, $shellS) or die;
|
||||
$self->{socket}->autoflush(1);
|
||||
};
|
||||
die "$@" if $@;
|
||||
|
||||
$self->waitForMonitorPrompt;
|
||||
|
||||
$self->log("QEMU running (pid $pid)");
|
||||
|
||||
$self->{pid} = $pid;
|
||||
$self->{booted} = 1;
|
||||
}
|
||||
|
||||
|
||||
# Send a command to the monitor and wait for it to finish. TODO: QEMU
|
||||
# also has a JSON-based monitor interface now, but it doesn't support
|
||||
# all commands yet. We should use it once it does.
|
||||
sub sendMonitorCommand {
|
||||
my ($self, $command) = @_;
|
||||
$self->log("sending monitor command: $command");
|
||||
syswrite $self->{monitor}, "$command\n";
|
||||
return $self->waitForMonitorPrompt;
|
||||
}
|
||||
|
||||
|
||||
# Wait until the monitor sends "(qemu) ".
|
||||
sub waitForMonitorPrompt {
|
||||
my ($self) = @_;
|
||||
my $res = "";
|
||||
my $s;
|
||||
while (sysread($self->{monitor}, $s, 1024)) {
|
||||
$res .= $s;
|
||||
last if $res =~ s/\(qemu\) $//;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
# Call the given code reference repeatedly, with 1 second intervals,
|
||||
# until it returns 1 or a timeout is reached.
|
||||
sub retry {
|
||||
my ($coderef) = @_;
|
||||
my $n;
|
||||
for ($n = 899; $n >=0; $n--) {
|
||||
return if &$coderef($n);
|
||||
sleep 1;
|
||||
}
|
||||
die "action timed out after $n seconds";
|
||||
}
|
||||
|
||||
|
||||
sub connect {
|
||||
my ($self) = @_;
|
||||
return if $self->{connected};
|
||||
|
||||
$self->nest("waiting for the VM to finish booting", sub {
|
||||
|
||||
$self->start;
|
||||
|
||||
my $now = clock_gettime(CLOCK_MONOTONIC);
|
||||
local $SIG{ALRM} = sub { die "timed out waiting for the VM to connect\n"; };
|
||||
alarm 600;
|
||||
readline $self->{socket} or die "the VM quit before connecting\n";
|
||||
alarm 0;
|
||||
|
||||
$self->log("connected to guest root shell");
|
||||
# We're interested in tracking how close we are to `alarm`.
|
||||
$self->log(sprintf("(connecting took %.2f seconds)", clock_gettime(CLOCK_MONOTONIC) - $now));
|
||||
$self->{connected} = 1;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub waitForShutdown {
|
||||
my ($self) = @_;
|
||||
return unless $self->{booted};
|
||||
|
||||
$self->nest("waiting for the VM to power off", sub {
|
||||
waitpid $self->{pid}, 0;
|
||||
$self->{pid} = 0;
|
||||
$self->{booted} = 0;
|
||||
$self->{connected} = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub isUp {
|
||||
my ($self) = @_;
|
||||
return $self->{booted} && $self->{connected};
|
||||
}
|
||||
|
||||
|
||||
sub execute_ {
|
||||
my ($self, $command) = @_;
|
||||
|
||||
$self->connect;
|
||||
|
||||
print { $self->{socket} } ("( $command ); echo '|!=EOF' \$?\n");
|
||||
|
||||
my $out = "";
|
||||
|
||||
while (1) {
|
||||
my $line = readline($self->{socket});
|
||||
die "connection to VM lost unexpectedly" unless defined $line;
|
||||
#$self->log("got line: $line");
|
||||
if ($line =~ /^(.*)\|\!\=EOF\s+(\d+)$/) {
|
||||
$out .= $1;
|
||||
$self->log("exit status $2");
|
||||
return ($2, $out);
|
||||
}
|
||||
$out .= $line;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub execute {
|
||||
my ($self, $command) = @_;
|
||||
my @res;
|
||||
$self->nest("running command: $command", sub {
|
||||
@res = $self->execute_($command);
|
||||
});
|
||||
return @res;
|
||||
}
|
||||
|
||||
|
||||
sub succeed {
|
||||
my ($self, @commands) = @_;
|
||||
|
||||
my $res;
|
||||
foreach my $command (@commands) {
|
||||
$self->nest("must succeed: $command", sub {
|
||||
my ($status, $out) = $self->execute_($command);
|
||||
if ($status != 0) {
|
||||
$self->log("output: $out");
|
||||
die "command `$command' did not succeed (exit code $status)\n";
|
||||
}
|
||||
$res .= $out;
|
||||
});
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
sub mustSucceed {
|
||||
succeed @_;
|
||||
}
|
||||
|
||||
|
||||
sub waitUntilSucceeds {
|
||||
my ($self, $command) = @_;
|
||||
$self->nest("waiting for success: $command", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute($command);
|
||||
return 1 if $status == 0;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub waitUntilFails {
|
||||
my ($self, $command) = @_;
|
||||
$self->nest("waiting for failure: $command", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute($command);
|
||||
return 1 if $status != 0;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub fail {
|
||||
my ($self, $command) = @_;
|
||||
$self->nest("must fail: $command", sub {
|
||||
my ($status, $out) = $self->execute_($command);
|
||||
die "command `$command' unexpectedly succeeded"
|
||||
if $status == 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub mustFail {
|
||||
fail @_;
|
||||
}
|
||||
|
||||
|
||||
sub getUnitInfo {
|
||||
my ($self, $unit, $user) = @_;
|
||||
my ($status, $lines) = $self->systemctl("--no-pager show \"$unit\"", $user);
|
||||
return undef if $status != 0;
|
||||
my $info = {};
|
||||
foreach my $line (split '\n', $lines) {
|
||||
$line =~ /^([^=]+)=(.*)$/ or next;
|
||||
$info->{$1} = $2;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
sub systemctl {
|
||||
my ($self, $q, $user) = @_;
|
||||
if ($user) {
|
||||
$q =~ s/'/\\'/g;
|
||||
return $self->execute("su -l $user -c \$'XDG_RUNTIME_DIR=/run/user/`id -u` systemctl --user $q'");
|
||||
}
|
||||
|
||||
return $self->execute("systemctl $q");
|
||||
}
|
||||
|
||||
# Fail if the given systemd unit is not in the "active" state.
|
||||
sub requireActiveUnit {
|
||||
my ($self, $unit) = @_;
|
||||
$self->nest("checking if unit ‘$unit’ has reached state 'active'", sub {
|
||||
my $info = $self->getUnitInfo($unit);
|
||||
my $state = $info->{ActiveState};
|
||||
if ($state ne "active") {
|
||||
die "Expected unit ‘$unit’ to to be in state 'active' but it is in state ‘$state’\n";
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
# Wait for a systemd unit to reach the "active" state.
|
||||
sub waitForUnit {
|
||||
my ($self, $unit, $user) = @_;
|
||||
$self->nest("waiting for unit ‘$unit’", sub {
|
||||
retry sub {
|
||||
my $info = $self->getUnitInfo($unit, $user);
|
||||
my $state = $info->{ActiveState};
|
||||
die "unit ‘$unit’ reached state ‘$state’\n" if $state eq "failed";
|
||||
if ($state eq "inactive") {
|
||||
# If there are no pending jobs, then assume this unit
|
||||
# will never reach active state.
|
||||
my ($status, $jobs) = $self->systemctl("list-jobs --full 2>&1", $user);
|
||||
if ($jobs =~ /No jobs/) { # FIXME: fragile
|
||||
# Handle the case where the unit may have started
|
||||
# between the previous getUnitInfo() and
|
||||
# list-jobs.
|
||||
my $info2 = $self->getUnitInfo($unit);
|
||||
die "unit ‘$unit’ is inactive and there are no pending jobs\n"
|
||||
if $info2->{ActiveState} eq $state;
|
||||
}
|
||||
}
|
||||
return 1 if $state eq "active";
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub waitForJob {
|
||||
my ($self, $jobName) = @_;
|
||||
return $self->waitForUnit($jobName);
|
||||
}
|
||||
|
||||
|
||||
# Wait until the specified file exists.
|
||||
sub waitForFile {
|
||||
my ($self, $fileName) = @_;
|
||||
$self->nest("waiting for file ‘$fileName’", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("test -e $fileName");
|
||||
return 1 if $status == 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sub startJob {
|
||||
my ($self, $jobName, $user) = @_;
|
||||
$self->systemctl("start $jobName", $user);
|
||||
# FIXME: check result
|
||||
}
|
||||
|
||||
sub stopJob {
|
||||
my ($self, $jobName, $user) = @_;
|
||||
$self->systemctl("stop $jobName", $user);
|
||||
}
|
||||
|
||||
|
||||
# Wait until the machine is listening on the given TCP port.
|
||||
sub waitForOpenPort {
|
||||
my ($self, $port) = @_;
|
||||
$self->nest("waiting for TCP port $port", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("nc -z localhost $port");
|
||||
return 1 if $status == 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Wait until the machine is not listening on the given TCP port.
|
||||
sub waitForClosedPort {
|
||||
my ($self, $port) = @_;
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("nc -z localhost $port");
|
||||
return 1 if $status != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub shutdown {
|
||||
my ($self) = @_;
|
||||
return unless $self->{booted};
|
||||
|
||||
print { $self->{socket} } ("poweroff\n");
|
||||
|
||||
$self->waitForShutdown;
|
||||
}
|
||||
|
||||
|
||||
sub crash {
|
||||
my ($self) = @_;
|
||||
return unless $self->{booted};
|
||||
|
||||
$self->log("forced crash");
|
||||
|
||||
$self->sendMonitorCommand("quit");
|
||||
|
||||
$self->waitForShutdown;
|
||||
}
|
||||
|
||||
|
||||
# Make the machine unreachable by shutting down eth1 (the multicast
|
||||
# interface used to talk to the other VMs). We keep eth0 up so that
|
||||
# the test driver can continue to talk to the machine.
|
||||
sub block {
|
||||
my ($self) = @_;
|
||||
$self->sendMonitorCommand("set_link virtio-net-pci.1 off");
|
||||
}
|
||||
|
||||
|
||||
# Make the machine reachable.
|
||||
sub unblock {
|
||||
my ($self) = @_;
|
||||
$self->sendMonitorCommand("set_link virtio-net-pci.1 on");
|
||||
}
|
||||
|
||||
|
||||
# Take a screenshot of the X server on :0.0.
|
||||
sub screenshot {
|
||||
my ($self, $filename) = @_;
|
||||
my $dir = $ENV{'out'} || Cwd::abs_path(".");
|
||||
$filename = "$dir/${filename}.png" if $filename =~ /^\w+$/;
|
||||
my $tmp = "${filename}.ppm";
|
||||
my $name = basename($filename);
|
||||
$self->nest("making screenshot ‘$name’", sub {
|
||||
$self->sendMonitorCommand("screendump $tmp");
|
||||
system("pnmtopng $tmp > ${filename}") == 0
|
||||
or die "cannot convert screenshot";
|
||||
unlink $tmp;
|
||||
}, { image => $name } );
|
||||
}
|
||||
|
||||
# Get the text of TTY<n>
|
||||
sub getTTYText {
|
||||
my ($self, $tty) = @_;
|
||||
|
||||
my ($status, $out) = $self->execute("fold -w\$(stty -F /dev/tty${tty} size | awk '{print \$2}') /dev/vcs${tty}");
|
||||
return $out;
|
||||
}
|
||||
|
||||
# Wait until TTY<n>'s text matches a particular regular expression
|
||||
sub waitUntilTTYMatches {
|
||||
my ($self, $tty, $regexp) = @_;
|
||||
|
||||
$self->nest("waiting for $regexp to appear on tty $tty", sub {
|
||||
retry sub {
|
||||
my ($retries_remaining) = @_;
|
||||
if ($retries_remaining == 0) {
|
||||
$self->log("Last chance to match /$regexp/ on TTY$tty, which currently contains:");
|
||||
$self->log($self->getTTYText($tty));
|
||||
}
|
||||
|
||||
return 1 if $self->getTTYText($tty) =~ /$regexp/;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
# Debugging: Dump the contents of the TTY<n>
|
||||
sub dumpTTYContents {
|
||||
my ($self, $tty) = @_;
|
||||
|
||||
$self->execute("fold -w 80 /dev/vcs${tty} | systemd-cat");
|
||||
}
|
||||
|
||||
# Take a screenshot and return the result as text using optical character
|
||||
# recognition.
|
||||
sub getScreenText {
|
||||
my ($self) = @_;
|
||||
|
||||
system("command -v tesseract &> /dev/null") == 0
|
||||
or die "getScreenText used but enableOCR is false";
|
||||
|
||||
my $text;
|
||||
$self->nest("performing optical character recognition", sub {
|
||||
my $tmpbase = Cwd::abs_path(".")."/ocr";
|
||||
my $tmpin = $tmpbase."in.ppm";
|
||||
|
||||
$self->sendMonitorCommand("screendump $tmpin");
|
||||
|
||||
my $magickArgs = "-filter Catrom -density 72 -resample 300 "
|
||||
. "-contrast -normalize -despeckle -type grayscale "
|
||||
. "-sharpen 1 -posterize 3 -negate -gamma 100 "
|
||||
. "-blur 1x65535";
|
||||
my $tessArgs = "-c debug_file=/dev/null --psm 11 --oem 2";
|
||||
|
||||
$text = `convert $magickArgs $tmpin tiff:- | tesseract - - $tessArgs`;
|
||||
my $status = $? >> 8;
|
||||
unlink $tmpin;
|
||||
|
||||
die "OCR failed with exit code $status" if $status != 0;
|
||||
});
|
||||
return $text;
|
||||
}
|
||||
|
||||
|
||||
# Wait until a specific regexp matches the textual contents of the screen.
|
||||
sub waitForText {
|
||||
my ($self, $regexp) = @_;
|
||||
$self->nest("waiting for $regexp to appear on the screen", sub {
|
||||
retry sub {
|
||||
my ($retries_remaining) = @_;
|
||||
if ($retries_remaining == 0) {
|
||||
$self->log("Last chance to match /$regexp/ on the screen, which currently contains:");
|
||||
$self->log($self->getScreenText);
|
||||
}
|
||||
|
||||
return 1 if $self->getScreenText =~ /$regexp/;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Wait until it is possible to connect to the X server. Note that
|
||||
# testing the existence of /tmp/.X11-unix/X0 is insufficient.
|
||||
sub waitForX {
|
||||
my ($self, $regexp) = @_;
|
||||
$self->nest("waiting for the X11 server", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("journalctl -b SYSLOG_IDENTIFIER=systemd | grep 'Reached target Current graphical'");
|
||||
return 0 if $status != 0;
|
||||
($status, $out) = $self->execute("[ -e /tmp/.X11-unix/X0 ]");
|
||||
return 1 if $status == 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub getWindowNames {
|
||||
my ($self) = @_;
|
||||
my $res = $self->mustSucceed(
|
||||
q{xwininfo -root -tree | sed 's/.*0x[0-9a-f]* \"\([^\"]*\)\".*/\1/; t; d'});
|
||||
return split /\n/, $res;
|
||||
}
|
||||
|
||||
|
||||
sub waitForWindow {
|
||||
my ($self, $regexp) = @_;
|
||||
$self->nest("waiting for a window to appear", sub {
|
||||
retry sub {
|
||||
my @names = $self->getWindowNames;
|
||||
|
||||
my ($retries_remaining) = @_;
|
||||
if ($retries_remaining == 0) {
|
||||
$self->log("Last chance to match /$regexp/ on the the window list, which currently contains:");
|
||||
$self->log(join(", ", @names));
|
||||
}
|
||||
|
||||
foreach my $n (@names) {
|
||||
return 1 if $n =~ /$regexp/;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub copyFileFromHost {
|
||||
my ($self, $from, $to) = @_;
|
||||
my $s = `cat $from` or die;
|
||||
$s =~ s/'/'\\''/g;
|
||||
$self->mustSucceed("echo '$s' > $to");
|
||||
}
|
||||
|
||||
|
||||
my %charToKey = (
|
||||
'A' => "shift-a", 'N' => "shift-n", '-' => "0x0C", '_' => "shift-0x0C", '!' => "shift-0x02",
|
||||
'B' => "shift-b", 'O' => "shift-o", '=' => "0x0D", '+' => "shift-0x0D", '@' => "shift-0x03",
|
||||
'C' => "shift-c", 'P' => "shift-p", '[' => "0x1A", '{' => "shift-0x1A", '#' => "shift-0x04",
|
||||
'D' => "shift-d", 'Q' => "shift-q", ']' => "0x1B", '}' => "shift-0x1B", '$' => "shift-0x05",
|
||||
'E' => "shift-e", 'R' => "shift-r", ';' => "0x27", ':' => "shift-0x27", '%' => "shift-0x06",
|
||||
'F' => "shift-f", 'S' => "shift-s", '\'' => "0x28", '"' => "shift-0x28", '^' => "shift-0x07",
|
||||
'G' => "shift-g", 'T' => "shift-t", '`' => "0x29", '~' => "shift-0x29", '&' => "shift-0x08",
|
||||
'H' => "shift-h", 'U' => "shift-u", '\\' => "0x2B", '|' => "shift-0x2B", '*' => "shift-0x09",
|
||||
'I' => "shift-i", 'V' => "shift-v", ',' => "0x33", '<' => "shift-0x33", '(' => "shift-0x0A",
|
||||
'J' => "shift-j", 'W' => "shift-w", '.' => "0x34", '>' => "shift-0x34", ')' => "shift-0x0B",
|
||||
'K' => "shift-k", 'X' => "shift-x", '/' => "0x35", '?' => "shift-0x35",
|
||||
'L' => "shift-l", 'Y' => "shift-y", ' ' => "spc",
|
||||
'M' => "shift-m", 'Z' => "shift-z", "\n" => "ret",
|
||||
);
|
||||
|
||||
|
||||
sub sendKeys {
|
||||
my ($self, @keys) = @_;
|
||||
foreach my $key (@keys) {
|
||||
$key = $charToKey{$key} if exists $charToKey{$key};
|
||||
$self->sendMonitorCommand("sendkey $key");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub sendChars {
|
||||
my ($self, $chars) = @_;
|
||||
$self->nest("sending keys ‘$chars’", sub {
|
||||
$self->sendKeys(split //, $chars);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Sleep N seconds (in virtual guest time, not real time).
|
||||
sub sleep {
|
||||
my ($self, $time) = @_;
|
||||
$self->succeed("sleep $time");
|
||||
}
|
||||
|
||||
|
||||
# Forward a TCP port on the host to a TCP port on the guest. Useful
|
||||
# during interactive testing.
|
||||
sub forwardPort {
|
||||
my ($self, $hostPort, $guestPort) = @_;
|
||||
$hostPort = 8080 unless defined $hostPort;
|
||||
$guestPort = 80 unless defined $guestPort;
|
||||
$self->sendMonitorCommand("hostfwd_add tcp::$hostPort-:$guestPort");
|
||||
}
|
||||
|
||||
|
||||
1;
|
@ -1,191 +0,0 @@
|
||||
#! /somewhere/perl -w
|
||||
|
||||
use strict;
|
||||
use Machine;
|
||||
use Term::ReadLine;
|
||||
use IO::File;
|
||||
use IO::Pty;
|
||||
use Logger;
|
||||
use Cwd;
|
||||
use POSIX qw(_exit dup2);
|
||||
use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
|
||||
|
||||
$SIG{PIPE} = 'IGNORE'; # because Unix domain sockets may die unexpectedly
|
||||
|
||||
STDERR->autoflush(1);
|
||||
|
||||
my $log = new Logger;
|
||||
|
||||
|
||||
# Start vde_switch for each network required by the test.
|
||||
my %vlans;
|
||||
foreach my $vlan (split / /, $ENV{VLANS} || "") {
|
||||
next if defined $vlans{$vlan};
|
||||
# Start vde_switch as a child process. We don't run it in daemon
|
||||
# mode because we want the child process to be cleaned up when we
|
||||
# die. Since we have to make sure that the control socket is
|
||||
# ready, we send a dummy command to vde_switch (via stdin) and
|
||||
# wait for a reply. Note that vde_switch requires stdin to be a
|
||||
# TTY, so we create one.
|
||||
$log->log("starting VDE switch for network $vlan");
|
||||
my $socket = Cwd::abs_path "./vde$vlan.ctl";
|
||||
my $pty = new IO::Pty;
|
||||
my ($stdoutR, $stdoutW); pipe $stdoutR, $stdoutW;
|
||||
my $pid = fork(); die "cannot fork" unless defined $pid;
|
||||
if ($pid == 0) {
|
||||
dup2(fileno($pty->slave), 0);
|
||||
dup2(fileno($stdoutW), 1);
|
||||
exec "vde_switch -s $socket --dirmode 0700" or _exit(1);
|
||||
}
|
||||
close $stdoutW;
|
||||
print $pty "version\n";
|
||||
readline $stdoutR or die "cannot start vde_switch";
|
||||
$ENV{"QEMU_VDE_SOCKET_$vlan"} = $socket;
|
||||
$vlans{$vlan} = $pty;
|
||||
die unless -e "$socket/ctl";
|
||||
}
|
||||
|
||||
|
||||
my %vms;
|
||||
my $context = "";
|
||||
|
||||
sub createMachine {
|
||||
my ($args) = @_;
|
||||
my $vm = Machine->new({%{$args}, log => $log, redirectSerial => ($ENV{USE_SERIAL} // "0") ne "1"});
|
||||
$vms{$vm->name} = $vm;
|
||||
$context .= "my \$" . $vm->name . " = \$vms{'" . $vm->name . "'}; ";
|
||||
return $vm;
|
||||
}
|
||||
|
||||
foreach my $vmScript (@ARGV) {
|
||||
my $vm = createMachine({startCommand => $vmScript});
|
||||
}
|
||||
|
||||
|
||||
sub startAll {
|
||||
$log->nest("starting all VMs", sub {
|
||||
$_->start foreach values %vms;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Wait until all VMs have terminated.
|
||||
sub joinAll {
|
||||
$log->nest("waiting for all VMs to finish", sub {
|
||||
$_->waitForShutdown foreach values %vms;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# In interactive tests, this allows the non-interactive test script to
|
||||
# be executed conveniently.
|
||||
sub testScript {
|
||||
eval "$context $ENV{testScript};\n";
|
||||
warn $@ if $@;
|
||||
}
|
||||
|
||||
|
||||
my $nrTests = 0;
|
||||
my $nrSucceeded = 0;
|
||||
|
||||
|
||||
sub subtest {
|
||||
my ($name, $coderef) = @_;
|
||||
$log->nest("subtest: $name", sub {
|
||||
$nrTests++;
|
||||
eval { &$coderef };
|
||||
if ($@) {
|
||||
$log->log("error: $@", { error => 1 });
|
||||
} else {
|
||||
$nrSucceeded++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub runTests {
|
||||
if (defined $ENV{tests}) {
|
||||
$log->nest("running the VM test script", sub {
|
||||
eval "$context $ENV{tests}";
|
||||
if ($@) {
|
||||
$log->log("error: $@", { error => 1 });
|
||||
die $@;
|
||||
}
|
||||
}, { expanded => 1 });
|
||||
} else {
|
||||
my $term = Term::ReadLine->new('nixos-vm-test');
|
||||
$term->ReadHistory;
|
||||
while (defined ($_ = $term->readline("> "))) {
|
||||
eval "$context $_\n";
|
||||
warn $@ if $@;
|
||||
}
|
||||
$term->WriteHistory;
|
||||
}
|
||||
|
||||
# Copy the kernel coverage data for each machine, if the kernel
|
||||
# has been compiled with coverage instrumentation.
|
||||
$log->nest("collecting coverage data", sub {
|
||||
foreach my $vm (values %vms) {
|
||||
my $gcovDir = "/sys/kernel/debug/gcov";
|
||||
|
||||
next unless $vm->isUp();
|
||||
|
||||
my ($status, $out) = $vm->execute("test -e $gcovDir");
|
||||
next if $status != 0;
|
||||
|
||||
# Figure out where to put the *.gcda files so that the
|
||||
# report generator can find the corresponding kernel
|
||||
# sources.
|
||||
my $kernelDir = $vm->mustSucceed("echo \$(dirname \$(readlink -f /run/current-system/kernel))/.build/linux-*");
|
||||
chomp $kernelDir;
|
||||
my $coverageDir = "/tmp/xchg/coverage-data/$kernelDir";
|
||||
|
||||
# Copy all the *.gcda files.
|
||||
$vm->execute("for d in $gcovDir/nix/store/*/.build/linux-*; do for i in \$(cd \$d && find -name '*.gcda'); do echo \$i; mkdir -p $coverageDir/\$(dirname \$i); cp -v \$d/\$i $coverageDir/\$i; done; done");
|
||||
}
|
||||
});
|
||||
|
||||
$log->nest("syncing", sub {
|
||||
foreach my $vm (values %vms) {
|
||||
next unless $vm->isUp();
|
||||
$vm->execute("sync");
|
||||
}
|
||||
});
|
||||
|
||||
if ($nrTests != 0) {
|
||||
$log->log("$nrSucceeded out of $nrTests tests succeeded",
|
||||
($nrSucceeded < $nrTests ? { error => 1 } : { }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Create an empty raw virtual disk with the given name and size (in
|
||||
# MiB).
|
||||
sub createDisk {
|
||||
my ($name, $size) = @_;
|
||||
system("qemu-img create -f raw $name ${size}M") == 0
|
||||
or die "cannot create image of size $size";
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
$log->nest("cleaning up", sub {
|
||||
foreach my $vm (values %vms) {
|
||||
if ($vm->{pid}) {
|
||||
$log->log("killing " . $vm->{name} . " (pid " . $vm->{pid} . ")");
|
||||
kill 9, $vm->{pid};
|
||||
}
|
||||
}
|
||||
});
|
||||
$log->close();
|
||||
}
|
||||
|
||||
my $now1 = clock_gettime(CLOCK_MONOTONIC);
|
||||
|
||||
runTests;
|
||||
|
||||
my $now2 = clock_gettime(CLOCK_MONOTONIC);
|
||||
|
||||
printf STDERR "test script finished in %.2fs\n", $now2 - $now1;
|
||||
|
||||
exit ($nrSucceeded < $nrTests ? 1 : 0);
|
@ -424,15 +424,18 @@ class Machine:
|
||||
output += out
|
||||
return output
|
||||
|
||||
def fail(self, *commands: str) -> None:
|
||||
def fail(self, *commands: str) -> str:
|
||||
"""Execute each command and check that it fails."""
|
||||
output = ""
|
||||
for command in commands:
|
||||
with self.nested("must fail: {}".format(command)):
|
||||
status, output = self.execute(command)
|
||||
(status, out) = self.execute(command)
|
||||
if status == 0:
|
||||
raise Exception(
|
||||
"command `{}` unexpectedly succeeded".format(command)
|
||||
)
|
||||
output += out
|
||||
return output
|
||||
|
||||
def wait_until_succeeds(self, command: str) -> str:
|
||||
"""Wait until a command returns success and return its output.
|
||||
@ -837,7 +840,8 @@ class Machine:
|
||||
retry(window_is_visible)
|
||||
|
||||
def sleep(self, secs: int) -> None:
|
||||
time.sleep(secs)
|
||||
# We want to sleep in *guest* time, not *host* time.
|
||||
self.succeed(f"sleep {secs}")
|
||||
|
||||
def forward_port(self, host_port: int = 8080, guest_port: int = 80) -> None:
|
||||
"""Forward a TCP port on the host to a TCP port on the guest.
|
||||
|
@ -1,258 +0,0 @@
|
||||
{ system
|
||||
, pkgs ? import ../.. { inherit system config; }
|
||||
# Use a minimal kernel?
|
||||
, minimal ? false
|
||||
# Ignored
|
||||
, config ? {}
|
||||
# Modules to add to each VM
|
||||
, extraConfigurations ? [] }:
|
||||
|
||||
with import ./build-vms.nix { inherit system pkgs minimal extraConfigurations; };
|
||||
with pkgs;
|
||||
|
||||
rec {
|
||||
|
||||
inherit pkgs;
|
||||
|
||||
|
||||
testDriver = lib.warn ''
|
||||
Perl VM tests are deprecated and will be removed for 20.09.
|
||||
Please update your tests to use the python test driver.
|
||||
See https://github.com/NixOS/nixpkgs/pull/71684 for details.
|
||||
'' stdenv.mkDerivation {
|
||||
name = "nixos-test-driver";
|
||||
|
||||
buildInputs = [ makeWrapper perl ];
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
preferLocalBuild = true;
|
||||
|
||||
installPhase =
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
cp ${./test-driver/test-driver.pl} $out/bin/nixos-test-driver
|
||||
chmod u+x $out/bin/nixos-test-driver
|
||||
|
||||
libDir=$out/${perl.libPrefix}
|
||||
mkdir -p $libDir
|
||||
cp ${./test-driver/Machine.pm} $libDir/Machine.pm
|
||||
cp ${./test-driver/Logger.pm} $libDir/Logger.pm
|
||||
|
||||
wrapProgram $out/bin/nixos-test-driver \
|
||||
--prefix PATH : "${lib.makeBinPath [ qemu_test vde2 netpbm coreutils ]}" \
|
||||
--prefix PERL5LIB : "${with perlPackages; makePerlPath [ TermReadLineGnu XMLWriter IOTty FileSlurp ]}:$out/${perl.libPrefix}"
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
# Run an automated test suite in the given virtual network.
|
||||
# `driver' is the script that runs the network.
|
||||
runTests = driver:
|
||||
stdenv.mkDerivation {
|
||||
name = "vm-test-run-${driver.testName}";
|
||||
|
||||
requiredSystemFeatures = [ "kvm" "nixos-test" ];
|
||||
|
||||
buildCommand =
|
||||
''
|
||||
mkdir -p $out
|
||||
|
||||
LOGFILE=/dev/null tests='eval $ENV{testScript}; die $@ if $@;' ${driver}/bin/nixos-test-driver
|
||||
|
||||
for i in */xchg/coverage-data; do
|
||||
mkdir -p $out/coverage-data
|
||||
mv $i $out/coverage-data/$(dirname $(dirname $i))
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
makeTest =
|
||||
{ testScript
|
||||
, makeCoverageReport ? false
|
||||
, enableOCR ? false
|
||||
, name ? "unnamed"
|
||||
, ...
|
||||
} @ t:
|
||||
|
||||
let
|
||||
# A standard store path to the vm monitor is built like this:
|
||||
# /tmp/nix-build-vm-test-run-$name.drv-0/vm-state-machine/monitor
|
||||
# The max filename length of a unix domain socket is 108 bytes.
|
||||
# This means $name can at most be 50 bytes long.
|
||||
maxTestNameLen = 50;
|
||||
testNameLen = builtins.stringLength name;
|
||||
|
||||
testDriverName = with builtins;
|
||||
if testNameLen > maxTestNameLen then
|
||||
abort ("The name of the test '${name}' must not be longer than ${toString maxTestNameLen} " +
|
||||
"it's currently ${toString testNameLen} characters long.")
|
||||
else
|
||||
"nixos-test-driver-${name}";
|
||||
|
||||
nodes = buildVirtualNetwork (
|
||||
t.nodes or (if t ? machine then { machine = t.machine; } else { }));
|
||||
|
||||
testScript' =
|
||||
# Call the test script with the computed nodes.
|
||||
if lib.isFunction testScript
|
||||
then testScript { inherit nodes; }
|
||||
else testScript;
|
||||
|
||||
vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes);
|
||||
|
||||
vms = map (m: m.config.system.build.vm) (lib.attrValues nodes);
|
||||
|
||||
ocrProg = tesseract4.override { enableLanguages = [ "eng" ]; };
|
||||
|
||||
imagemagick_tiff = imagemagick_light.override { inherit libtiff; };
|
||||
|
||||
# Generate onvenience wrappers for running the test driver
|
||||
# interactively with the specified network, and for starting the
|
||||
# VMs from the command line.
|
||||
driver = runCommand testDriverName
|
||||
{ buildInputs = [ makeWrapper];
|
||||
testScript = testScript';
|
||||
preferLocalBuild = true;
|
||||
testName = name;
|
||||
}
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
echo "$testScript" > $out/test-script
|
||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/
|
||||
vms=($(for i in ${toString vms}; do echo $i/bin/run-*-vm; done))
|
||||
wrapProgram $out/bin/nixos-test-driver \
|
||||
--add-flags "''${vms[*]}" \
|
||||
${lib.optionalString enableOCR
|
||||
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
|
||||
--run "export testScript=\"\$(cat $out/test-script)\"" \
|
||||
--set VLANS '${toString vlans}'
|
||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
|
||||
wrapProgram $out/bin/nixos-run-vms \
|
||||
--add-flags "''${vms[*]}" \
|
||||
${lib.optionalString enableOCR "--prefix PATH : '${ocrProg}/bin'"} \
|
||||
--set tests 'startAll; joinAll;' \
|
||||
--set VLANS '${toString vlans}' \
|
||||
${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
|
||||
''; # "
|
||||
|
||||
passMeta = drv: drv // lib.optionalAttrs (t ? meta) {
|
||||
meta = (drv.meta or {}) // t.meta;
|
||||
};
|
||||
|
||||
test = passMeta (runTests driver);
|
||||
report = passMeta (releaseTools.gcovReport { coverageRuns = [ test ]; });
|
||||
|
||||
nodeNames = builtins.attrNames nodes;
|
||||
invalidNodeNames = lib.filter
|
||||
(node: builtins.match "^[A-z_][A-z0-9_]+$" node == null) nodeNames;
|
||||
|
||||
in
|
||||
if lib.length invalidNodeNames > 0 then
|
||||
throw ''
|
||||
Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
|
||||
All machines are referenced as perl variables in the testing framework which will break the
|
||||
script when special characters are used.
|
||||
|
||||
Please stick to alphanumeric chars and underscores as separation.
|
||||
''
|
||||
else
|
||||
(if makeCoverageReport then report else test) // {
|
||||
inherit nodes driver test;
|
||||
};
|
||||
|
||||
runInMachine =
|
||||
{ drv
|
||||
, machine
|
||||
, preBuild ? ""
|
||||
, postBuild ? ""
|
||||
, ... # ???
|
||||
}:
|
||||
let
|
||||
vm = buildVM { }
|
||||
[ machine
|
||||
{ key = "run-in-machine";
|
||||
networking.hostName = "client";
|
||||
nix.readOnlyStore = false;
|
||||
virtualisation.writableStore = false;
|
||||
}
|
||||
];
|
||||
|
||||
buildrunner = writeText "vm-build" ''
|
||||
source $1
|
||||
|
||||
${coreutils}/bin/mkdir -p $TMPDIR
|
||||
cd $TMPDIR
|
||||
|
||||
exec $origBuilder $origArgs
|
||||
'';
|
||||
|
||||
testScript = ''
|
||||
startAll;
|
||||
$client->waitForUnit("multi-user.target");
|
||||
${preBuild}
|
||||
$client->succeed("env -i ${bash}/bin/bash ${buildrunner} /tmp/xchg/saved-env >&2");
|
||||
${postBuild}
|
||||
$client->succeed("sync"); # flush all data before pulling the plug
|
||||
'';
|
||||
|
||||
vmRunCommand = writeText "vm-run" ''
|
||||
xchg=vm-state-client/xchg
|
||||
${coreutils}/bin/mkdir $out
|
||||
${coreutils}/bin/mkdir -p $xchg
|
||||
|
||||
for i in $passAsFile; do
|
||||
i2=''${i}Path
|
||||
_basename=$(${coreutils}/bin/basename ''${!i2})
|
||||
${coreutils}/bin/cp ''${!i2} $xchg/$_basename
|
||||
eval $i2=/tmp/xchg/$_basename
|
||||
${coreutils}/bin/ls -la $xchg
|
||||
done
|
||||
|
||||
unset i i2 _basename
|
||||
export | ${gnugrep}/bin/grep -v '^xchg=' > $xchg/saved-env
|
||||
unset xchg
|
||||
|
||||
export tests='${testScript}'
|
||||
${testDriver}/bin/nixos-test-driver ${vm.config.system.build.vm}/bin/run-*-vm
|
||||
''; # */
|
||||
|
||||
in
|
||||
lib.overrideDerivation drv (attrs: {
|
||||
requiredSystemFeatures = [ "kvm" ];
|
||||
builder = "${bash}/bin/sh";
|
||||
args = ["-e" vmRunCommand];
|
||||
origArgs = attrs.args;
|
||||
origBuilder = attrs.builder;
|
||||
});
|
||||
|
||||
|
||||
runInMachineWithX = { require ? [], ... } @ args:
|
||||
let
|
||||
client =
|
||||
{ ... }:
|
||||
{
|
||||
inherit require;
|
||||
imports = [
|
||||
../tests/common/auto.nix
|
||||
];
|
||||
virtualisation.memorySize = 1024;
|
||||
services.xserver.enable = true;
|
||||
test-support.displayManager.auto.enable = true;
|
||||
services.xserver.displayManager.defaultSession = "none+icewm";
|
||||
services.xserver.windowManager.icewm.enable = true;
|
||||
};
|
||||
in
|
||||
runInMachine ({
|
||||
machine = client;
|
||||
preBuild =
|
||||
''
|
||||
$client->waitForX;
|
||||
'';
|
||||
} // args);
|
||||
|
||||
|
||||
simpleTest = as: (makeTest as).test;
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ log() {
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
if [ "$#" -ne 1 ]; then
|
||||
log "Usage: ./upload-amazon-image.sh IMAGE_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -108,6 +108,15 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
postBuildCommands = mkOption {
|
||||
example = literalExample "'' dd if=\${pkgs.myBootLoader}/SPL of=$img bs=1024 seek=1 conv=notrunc ''";
|
||||
default = "";
|
||||
description = ''
|
||||
Shell commands to run after the image is built.
|
||||
Can be used for boards requiring to dd u-boot SPL before actual partitions.
|
||||
'';
|
||||
};
|
||||
|
||||
compressImage = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@ -197,6 +206,9 @@ in
|
||||
# Verify the FAT partition before copying it.
|
||||
fsck.vfat -vn firmware_part.img
|
||||
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
|
||||
|
||||
${config.sdImage.postBuildCommands}
|
||||
|
||||
if test -n "$compressImage"; then
|
||||
zstd -T$NIX_BUILD_CORES --rm $img
|
||||
fi
|
||||
|
@ -288,7 +288,10 @@ fi
|
||||
if [ "$action" = edit ]; then
|
||||
if [[ -z $flake ]]; then
|
||||
NIXOS_CONFIG=${NIXOS_CONFIG:-$(nix-instantiate --find-file nixos-config)}
|
||||
exec "${EDITOR:-nano}" "$NIXOS_CONFIG"
|
||||
if [[ -d $NIXOS_CONFIG ]]; then
|
||||
NIXOS_CONFIG=$NIXOS_CONFIG/default.nix
|
||||
fi
|
||||
exec ${EDITOR:-nano} "$NIXOS_CONFIG"
|
||||
else
|
||||
exec nix edit "${lockFlags[@]}" -- "$flake#$flakeAttr"
|
||||
fi
|
||||
|
@ -321,7 +321,7 @@ in
|
||||
monetdb = 290;
|
||||
restic = 291;
|
||||
openvpn = 292;
|
||||
meguca = 293;
|
||||
# meguca = 293; # removed 2020-08-21
|
||||
yarn = 294;
|
||||
hdfs = 295;
|
||||
mapred = 296;
|
||||
@ -622,7 +622,7 @@ in
|
||||
monetdb = 290;
|
||||
restic = 291;
|
||||
openvpn = 292;
|
||||
meguca = 293;
|
||||
# meguca = 293; # removed 2020-08-21
|
||||
yarn = 294;
|
||||
hdfs = 295;
|
||||
mapred = 296;
|
||||
|
@ -127,7 +127,7 @@ in {
|
||||
{ LOCATE_PATH = cfg.output;
|
||||
};
|
||||
|
||||
warnings = optional (isMLocate && cfg.localuser != null) "mlocate does not support searching as user other than root"
|
||||
warnings = optional (isMLocate && cfg.localuser != null) "mlocate does not support the services.locate.localuser option; updatedb will run as root. (Silence with services.locate.localuser = null.)"
|
||||
++ optional (isFindutils && cfg.pruneNames != []) "findutils locate does not support pruning by directory component"
|
||||
++ optional (isFindutils && cfg.pruneBindMounts) "findutils locate does not support skipping bind mounts";
|
||||
|
||||
|
@ -178,8 +178,6 @@ in
|
||||
type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform
|
||||
default = null;
|
||||
example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
|
||||
defaultText = literalExample
|
||||
''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
|
||||
description = ''
|
||||
Specifies the platform for which NixOS should be
|
||||
built. Specify this only if it is different from
|
||||
|
@ -262,6 +262,7 @@
|
||||
./services/continuous-integration/buildbot/worker.nix
|
||||
./services/continuous-integration/buildkite-agents.nix
|
||||
./services/continuous-integration/hail.nix
|
||||
./services/continuous-integration/hercules-ci-agent/default.nix
|
||||
./services/continuous-integration/hydra/default.nix
|
||||
./services/continuous-integration/gitlab-runner.nix
|
||||
./services/continuous-integration/gocd-agent/default.nix
|
||||
@ -296,10 +297,10 @@
|
||||
./services/desktops/accountsservice.nix
|
||||
./services/desktops/bamf.nix
|
||||
./services/desktops/blueman.nix
|
||||
./services/desktops/deepin/deepin.nix
|
||||
./services/desktops/dleyna-renderer.nix
|
||||
./services/desktops/dleyna-server.nix
|
||||
./services/desktops/pantheon/files.nix
|
||||
./services/desktops/espanso.nix
|
||||
./services/desktops/flatpak.nix
|
||||
./services/desktops/geoclue2.nix
|
||||
./services/desktops/gsignond.nix
|
||||
@ -717,6 +718,7 @@
|
||||
./services/networking/rdnssd.nix
|
||||
./services/networking/redsocks.nix
|
||||
./services/networking/resilio.nix
|
||||
./services/networking/robustirc-bridge.nix
|
||||
./services/networking/rpcbind.nix
|
||||
./services/networking/rxe.nix
|
||||
./services/networking/sabnzbd.nix
|
||||
@ -886,7 +888,6 @@
|
||||
./services/web-servers/lighttpd/collectd.nix
|
||||
./services/web-servers/lighttpd/default.nix
|
||||
./services/web-servers/lighttpd/gitweb.nix
|
||||
./services/web-servers/meguca.nix
|
||||
./services/web-servers/mighttpd2.nix
|
||||
./services/web-servers/minio.nix
|
||||
./services/web-servers/molly-brown.nix
|
||||
|
@ -1,7 +1,7 @@
|
||||
# A profile with most (vanilla) hardening options enabled by default,
|
||||
# potentially at the cost of features and performance.
|
||||
|
||||
{ lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
@ -27,6 +27,9 @@ with lib;
|
||||
|
||||
security.forcePageTableIsolation = mkDefault true;
|
||||
|
||||
# This is required by podman to run containers in rootless mode.
|
||||
security.unprivilegedUsernsClone = mkDefault config.virtualisation.containers.enable;
|
||||
|
||||
security.virtualisation.flushL1DataCache = mkDefault "always";
|
||||
|
||||
security.apparmor.enable = mkDefault true;
|
||||
|
@ -48,6 +48,7 @@ with lib;
|
||||
instead, or any other display manager in NixOS as they all support auto-login.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead")
|
||||
(mkRemovedOptionModule [ "services" "meguca" ] "Use meguca has been removed from nixpkgs")
|
||||
(mkRemovedOptionModule ["hardware" "brightnessctl" ] ''
|
||||
The brightnessctl module was removed because newer versions of
|
||||
brightnessctl don't require the udev rules anymore (they can use the
|
||||
|
@ -150,6 +150,14 @@ let
|
||||
'';
|
||||
};
|
||||
|
||||
extraLegoFlags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
Additional global flags to pass to all lego commands.
|
||||
'';
|
||||
};
|
||||
|
||||
extraLegoRenewFlags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
@ -157,6 +165,14 @@ let
|
||||
Additional flags to pass to lego renew.
|
||||
'';
|
||||
};
|
||||
|
||||
extraLegoRunFlags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
Additional flags to pass to lego run.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -313,9 +329,10 @@ in
|
||||
++ optionals (data.dnsProvider != null && !data.dnsPropagationCheck) [ "--dns.disable-cp" ]
|
||||
++ concatLists (mapAttrsToList (name: root: [ "-d" name ]) data.extraDomains)
|
||||
++ (if data.dnsProvider != null then [ "--dns" data.dnsProvider ] else [ "--http" "--http.webroot" data.webroot ])
|
||||
++ optionals (cfg.server != null || data.server != null) ["--server" (if data.server == null then cfg.server else data.server)];
|
||||
++ optionals (cfg.server != null || data.server != null) ["--server" (if data.server == null then cfg.server else data.server)]
|
||||
++ data.extraLegoFlags;
|
||||
certOpts = optionals data.ocspMustStaple [ "--must-staple" ];
|
||||
runOpts = escapeShellArgs (globalOpts ++ [ "run" ] ++ certOpts);
|
||||
runOpts = escapeShellArgs (globalOpts ++ [ "run" ] ++ certOpts ++ data.extraLegoRunFlags);
|
||||
renewOpts = escapeShellArgs (globalOpts ++
|
||||
[ "renew" "--days" (toString cfg.validMinDays) ] ++
|
||||
certOpts ++ data.extraLegoRenewFlags);
|
||||
|
@ -23,11 +23,17 @@ in
|
||||
default = [];
|
||||
description = "List of packages to be added to apparmor's include path";
|
||||
};
|
||||
parserConfig = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "AppArmor parser configuration file content";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ pkgs.apparmor-utils ];
|
||||
environment.etc."apparmor/parser.conf".text = cfg.parserConfig;
|
||||
|
||||
boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
|
||||
|
||||
|
@ -51,7 +51,7 @@ in
|
||||
};
|
||||
|
||||
secretKeyFile = mkOption {
|
||||
type = types.path;
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
A file containing your secret key. The security of your Duo application is tied to the security of your secret key.
|
||||
|
@ -27,6 +27,16 @@ with lib;
|
||||
'';
|
||||
};
|
||||
|
||||
security.unprivilegedUsernsClone = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
When disabled, unprivileged users will not be able to create new namespaces.
|
||||
By default unprivileged user namespaces are disabled.
|
||||
This option only works in a hardened profile.
|
||||
'';
|
||||
};
|
||||
|
||||
security.protectKernelImage = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@ -115,6 +125,10 @@ with lib;
|
||||
];
|
||||
})
|
||||
|
||||
(mkIf config.security.unprivilegedUsernsClone {
|
||||
boot.kernel.sysctl."kernel.unprivileged_userns_clone" = mkDefault true;
|
||||
})
|
||||
|
||||
(mkIf config.security.protectKernelImage {
|
||||
# Disable hibernation (allows replacing the running kernel)
|
||||
boot.kernelParams = [ "nohibernate" ];
|
||||
|
@ -47,7 +47,7 @@ in {
|
||||
enable = mkEnableOption "Icecast server";
|
||||
|
||||
hostname = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
description = "DNS name or IP address that will be used for the stream directory lookups or possibily the playlist generation if a Host header is not provided.";
|
||||
default = config.networking.domain;
|
||||
};
|
||||
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
|
||||
This file is for options that NixOS and nix-darwin have in common.
|
||||
|
||||
Platform-specific code is in the respective default.nix files.
|
||||
|
||||
*/
|
||||
|
||||
{ config, lib, options, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption mkIf types filterAttrs literalExample mkRenamedOptionModule;
|
||||
|
||||
cfg =
|
||||
config.services.hercules-ci-agent;
|
||||
|
||||
format = pkgs.formats.toml {};
|
||||
|
||||
settingsModule = { config, ... }: {
|
||||
freeformType = format.type;
|
||||
options = {
|
||||
baseDirectory = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/hercules-ci-agent";
|
||||
description = ''
|
||||
State directory (secrets, work directory, etc) for agent
|
||||
'';
|
||||
};
|
||||
concurrentTasks = mkOption {
|
||||
description = ''
|
||||
Number of tasks to perform simultaneously, such as evaluations, derivations.
|
||||
|
||||
You must have a total capacity across agents of at least 2 concurrent tasks on <literal>x86_64-linux</literal>
|
||||
to allow for import from derivation.
|
||||
'';
|
||||
type = types.int;
|
||||
default = 4;
|
||||
};
|
||||
workDirectory = mkOption {
|
||||
description = ''
|
||||
The directory in which temporary subdirectories are created for task state. This includes sources for Nix evaluation.
|
||||
'';
|
||||
type = types.path;
|
||||
default = config.baseDirectory + "/work";
|
||||
defaultText = literalExample ''baseDirectory + "/work"'';
|
||||
};
|
||||
staticSecretsDirectory = mkOption {
|
||||
description = ''
|
||||
This is the default directory to look for statically configured secrets like <literal>cluster-join-token.key</literal>.
|
||||
'';
|
||||
type = types.path;
|
||||
default = config.baseDirectory + "/secrets";
|
||||
defaultText = literalExample ''baseDirectory + "/secrets"'';
|
||||
};
|
||||
clusterJoinTokenPath = mkOption {
|
||||
description = ''
|
||||
Location of the cluster-join-token.key file.
|
||||
'';
|
||||
type = types.path;
|
||||
default = config.staticSecretsDirectory + "/cluster-join-token.key";
|
||||
defaultText = literalExample ''staticSecretsDirectory + "/cluster-join-token.key"'';
|
||||
# internal: It's a bit too detailed to show by default in the docs,
|
||||
# but useful to define explicitly to allow reuse by other modules.
|
||||
internal = true;
|
||||
};
|
||||
binaryCachesPath = mkOption {
|
||||
description = ''
|
||||
Location of the binary-caches.json file.
|
||||
'';
|
||||
type = types.path;
|
||||
default = config.staticSecretsDirectory + "/binary-caches.json";
|
||||
defaultText = literalExample ''staticSecretsDirectory + "/binary-caches.json"'';
|
||||
# internal: It's a bit too detailed to show by default in the docs,
|
||||
# but useful to define explicitly to allow reuse by other modules.
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
checkNix =
|
||||
if !cfg.checkNix
|
||||
then ""
|
||||
else if lib.versionAtLeast config.nix.package.version "2.4.0"
|
||||
then ""
|
||||
else pkgs.stdenv.mkDerivation {
|
||||
name = "hercules-ci-check-system-nix-src";
|
||||
inherit (config.nix.package) src patches;
|
||||
configurePhase = ":";
|
||||
buildPhase = ''
|
||||
echo "Checking in-memory pathInfoCache expiry"
|
||||
if ! grep 'struct PathInfoCacheValue' src/libstore/store-api.hh >/dev/null; then
|
||||
cat 1>&2 <<EOF
|
||||
|
||||
You are deploying Hercules CI Agent on a system with an incompatible
|
||||
nix-daemon. Please
|
||||
- either upgrade Nix to version 2.4.0 (when released),
|
||||
- or set option services.hercules-ci-agent.patchNix = true;
|
||||
- or set option nix.package to a build of Nix 2.3 with this patch applied:
|
||||
https://github.com/NixOS/nix/pull/3405
|
||||
|
||||
The patch is required for Nix-daemon clients that expect a change in binary
|
||||
cache contents while running, like the agent's evaluator. Without it, import
|
||||
from derivation will fail if your cluster has more than one machine.
|
||||
We are conservative with changes to the overall system, which is why we
|
||||
keep changes to a minimum and why we ask for confirmation in the form of
|
||||
services.hercules-ci-agent.patchNix = true before applying.
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
installPhase = "touch $out";
|
||||
};
|
||||
|
||||
patchedNix = lib.mkIf (!lib.versionAtLeast pkgs.nix.version "2.4.0") (
|
||||
if lib.versionAtLeast pkgs.nix.version "2.4pre"
|
||||
then lib.warn "Hercules CI Agent module will not patch 2.4 pre-release. Make sure it includes (equivalently) PR #3043, commit d048577909 or is no older than 2020-03-13." pkgs.nix
|
||||
else pkgs.nix.overrideAttrs (
|
||||
o: {
|
||||
patches = (o.patches or []) ++ [ backportNix3398 ];
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
backportNix3398 = pkgs.fetchurl {
|
||||
url = "https://raw.githubusercontent.com/hercules-ci/hercules-ci-agent/hercules-ci-agent-0.7.3/for-upstream/issue-3398-path-info-cache-ttls-backport-2.3.patch";
|
||||
sha256 = "0jfckqjir9il2il7904yc1qyadw366y7xqzg81sp9sl3f1pw70ib";
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(mkRenamedOptionModule ["services" "hercules-ci-agent" "extraOptions"] ["services" "hercules-ci-agent" "settings"])
|
||||
(mkRenamedOptionModule ["services" "hercules-ci-agent" "baseDirectory"] ["services" "hercules-ci-agent" "settings" "baseDirectory"])
|
||||
(mkRenamedOptionModule ["services" "hercules-ci-agent" "concurrentTasks"] ["services" "hercules-ci-agent" "settings" "concurrentTasks"])
|
||||
];
|
||||
|
||||
options.services.hercules-ci-agent = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable to run Hercules CI Agent as a system service.
|
||||
|
||||
<link xlink:href="https://hercules-ci.com">Hercules CI</link> is a
|
||||
continuous integation service that is centered around Nix.
|
||||
|
||||
Support is available at <link xlink:href="mailto:help@hercules-ci.com">help@hercules-ci.com</link>.
|
||||
'';
|
||||
};
|
||||
patchNix = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Fix Nix 2.3 cache path metadata caching behavior. Has the effect of <literal>nix.package = patch pkgs.nix;</literal>
|
||||
|
||||
This option will be removed when Hercules CI Agent moves to Nix 2.4 (upcoming Nix release).
|
||||
'';
|
||||
};
|
||||
checkNix = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to make sure that the system's Nix (nix-daemon) is compatible.
|
||||
|
||||
If you set this to false, please keep up with the change log.
|
||||
'';
|
||||
};
|
||||
package = mkOption {
|
||||
description = ''
|
||||
Package containing the bin/hercules-ci-agent executable.
|
||||
'';
|
||||
type = types.package;
|
||||
default = pkgs.hercules-ci-agent;
|
||||
defaultText = literalExample "pkgs.hercules-ci-agent";
|
||||
};
|
||||
settings = mkOption {
|
||||
description = ''
|
||||
These settings are written to the <literal>agent.toml</literal> file.
|
||||
|
||||
Not all settings are listed as options, can be set nonetheless.
|
||||
|
||||
For the exhaustive list of settings, see <link xlink:href="https://docs.hercules-ci.com/hercules-ci/reference/agent-config/"/>.
|
||||
'';
|
||||
type = types.submoduleWith { modules = [ settingsModule ]; };
|
||||
};
|
||||
|
||||
/*
|
||||
Internal and/or computed values.
|
||||
|
||||
These are written as options instead of let binding to allow sharing with
|
||||
default.nix on both NixOS and nix-darwin.
|
||||
*/
|
||||
tomlFile = mkOption {
|
||||
type = types.path;
|
||||
internal = true;
|
||||
defaultText = "generated hercules-ci-agent.toml";
|
||||
description = ''
|
||||
The fully assembled config file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
nix.extraOptions = lib.addContextFrom checkNix ''
|
||||
# A store path that was missing at first may well have finished building,
|
||||
# even shortly after the previous lookup. This *also* applies to the daemon.
|
||||
narinfo-cache-negative-ttl = 0
|
||||
'';
|
||||
nix.package = mkIf cfg.patchNix patchedNix;
|
||||
services.hercules-ci-agent.tomlFile =
|
||||
format.generate "hercules-ci-agent.toml" cfg.settings;
|
||||
};
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
|
||||
This file is for NixOS-specific options and configs.
|
||||
|
||||
Code that is shared with nix-darwin goes in common.nix.
|
||||
|
||||
*/
|
||||
|
||||
{ pkgs, config, lib, ... }:
|
||||
|
||||
let
|
||||
|
||||
inherit (lib) mkIf mkDefault;
|
||||
|
||||
cfg = config.services.hercules-ci-agent;
|
||||
|
||||
command = "${cfg.package}/bin/hercules-ci-agent --config ${cfg.tomlFile}";
|
||||
testCommand = "${command} --test-configuration";
|
||||
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./common.nix
|
||||
(lib.mkRenamedOptionModule ["services" "hercules-ci-agent" "user"] ["systemd" "services" "hercules-ci-agent" "serviceConfig" "User"])
|
||||
];
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
systemd.services.hercules-ci-agent = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
path = [ config.nix.package ];
|
||||
serviceConfig = {
|
||||
User = "hercules-ci-agent";
|
||||
ExecStart = command;
|
||||
ExecStartPre = testCommand;
|
||||
Restart = "on-failure";
|
||||
RestartSec = 120;
|
||||
StartLimitBurst = 30 * 1000000; # practically infinite
|
||||
};
|
||||
};
|
||||
|
||||
# Changes in the secrets do not affect the unit in any way that would cause
|
||||
# a restart, which is currently necessary to reload the secrets.
|
||||
systemd.paths.hercules-ci-agent-restart-files = {
|
||||
wantedBy = [ "hercules-ci-agent.service" ];
|
||||
pathConfig = {
|
||||
Unit = "hercules-ci-agent-restarter.service";
|
||||
PathChanged = [ cfg.settings.clusterJoinTokenPath cfg.settings.binaryCachesPath ];
|
||||
};
|
||||
};
|
||||
systemd.services.hercules-ci-agent-restarter = {
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
# Wait a bit, with the effect of bundling up file changes into a single
|
||||
# run of this script and hopefully a single restart.
|
||||
sleep 10
|
||||
if systemctl is-active --quiet hercules-ci-agent.service; then
|
||||
if ${testCommand}; then
|
||||
systemctl restart hercules-ci-agent.service
|
||||
else
|
||||
echo 1>&2 "WARNING: Not restarting agent because config is not valid at this time."
|
||||
fi
|
||||
else
|
||||
echo 1>&2 "Not restarting hercules-ci-agent despite config file update, because it is not already active."
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Trusted user allows simplified configuration and better performance
|
||||
# when operating in a cluster.
|
||||
nix.trustedUsers = [ config.systemd.services.hercules-ci-agent.serviceConfig.User ];
|
||||
services.hercules-ci-agent.settings.nixUserIsTrusted = true;
|
||||
|
||||
users.users.hercules-ci-agent = {
|
||||
home = cfg.settings.baseDirectory;
|
||||
createHome = true;
|
||||
group = "hercules-ci-agent";
|
||||
description = "Hercules CI Agent system user";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
users.groups.hercules-ci-agent = {};
|
||||
};
|
||||
}
|
@ -11,23 +11,23 @@ let
|
||||
then cfg.package
|
||||
else cfg.package.withPackages (_: cfg.extraPlugins);
|
||||
|
||||
toStr = value:
|
||||
if true == value then "yes"
|
||||
else if false == value then "no"
|
||||
else if isString value then "'${lib.replaceStrings ["'"] ["''"] value}'"
|
||||
else toString value;
|
||||
|
||||
# The main PostgreSQL configuration file.
|
||||
configFile = pkgs.writeText "postgresql.conf"
|
||||
''
|
||||
hba_file = '${pkgs.writeText "pg_hba.conf" cfg.authentication}'
|
||||
ident_file = '${pkgs.writeText "pg_ident.conf" cfg.identMap}'
|
||||
log_destination = 'stderr'
|
||||
log_line_prefix = '${cfg.logLinePrefix}'
|
||||
listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}'
|
||||
port = ${toString cfg.port}
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
configFile = pkgs.writeText "postgresql.conf" (concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${toStr v}") cfg.settings));
|
||||
|
||||
groupAccessAvailable = versionAtLeast postgresql.version "11.0";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "services" "postgresql" "extraConfig" ] "Use services.postgresql.settings instead.")
|
||||
];
|
||||
|
||||
###### interface
|
||||
|
||||
@ -212,10 +212,28 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Additional text to be appended to <filename>postgresql.conf</filename>.";
|
||||
settings = mkOption {
|
||||
type = with types; attrsOf (oneOf [ bool float int str ]);
|
||||
default = {};
|
||||
description = ''
|
||||
PostgreSQL configuration. Refer to
|
||||
<link xlink:href="https://www.postgresql.org/docs/11/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE"/>
|
||||
for an overview of <literal>postgresql.conf</literal>.
|
||||
|
||||
<note><para>
|
||||
String values will automatically be enclosed in single quotes. Single quotes will be
|
||||
escaped with two single quotes as described by the upstream documentation linked above.
|
||||
</para></note>
|
||||
'';
|
||||
example = literalExample ''
|
||||
{
|
||||
log_connections = true;
|
||||
log_statement = "all";
|
||||
logging_collector = true
|
||||
log_disconnections = true
|
||||
log_destination = lib.mkForce "syslog";
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
recoveryConfig = mkOption {
|
||||
@ -245,6 +263,16 @@ in
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
services.postgresql.settings =
|
||||
{
|
||||
hba_file = "${pkgs.writeText "pg_hba.conf" cfg.authentication}";
|
||||
ident_file = "${pkgs.writeText "pg_ident.conf" cfg.identMap}";
|
||||
log_destination = "stderr";
|
||||
log_line_prefix = cfg.logLinePrefix;
|
||||
listen_addresses = if cfg.enableTCPIP then "*" else "localhost";
|
||||
port = cfg.port;
|
||||
};
|
||||
|
||||
services.postgresql.package =
|
||||
# Note: when changing the default, make it conditional on
|
||||
# ‘system.stateVersion’ to maintain compatibility with existing
|
||||
|
@ -1,123 +0,0 @@
|
||||
# deepin
|
||||
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.deepin.core.enable = lib.mkEnableOption "
|
||||
Basic dbus and systemd services, groups and users needed by the
|
||||
Deepin Desktop Environment.
|
||||
";
|
||||
|
||||
services.deepin.deepin-menu.enable = lib.mkEnableOption "
|
||||
DBus service for unified menus in Deepin Desktop Environment.
|
||||
";
|
||||
|
||||
services.deepin.deepin-turbo.enable = lib.mkEnableOption "
|
||||
Turbo service for the Deepin Desktop Environment. It is a daemon
|
||||
that helps to launch applications faster.
|
||||
";
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = lib.mkMerge [
|
||||
|
||||
(lib.mkIf config.services.deepin.core.enable {
|
||||
environment.systemPackages = [
|
||||
pkgs.deepin.dde-api
|
||||
pkgs.deepin.dde-calendar
|
||||
pkgs.deepin.dde-control-center
|
||||
pkgs.deepin.dde-daemon
|
||||
pkgs.deepin.dde-dock
|
||||
pkgs.deepin.dde-launcher
|
||||
pkgs.deepin.dde-file-manager
|
||||
pkgs.deepin.dde-session-ui
|
||||
pkgs.deepin.deepin-anything
|
||||
pkgs.deepin.deepin-image-viewer
|
||||
];
|
||||
|
||||
services.dbus.packages = [
|
||||
pkgs.deepin.dde-api
|
||||
pkgs.deepin.dde-calendar
|
||||
pkgs.deepin.dde-control-center
|
||||
pkgs.deepin.dde-daemon
|
||||
pkgs.deepin.dde-dock
|
||||
pkgs.deepin.dde-launcher
|
||||
pkgs.deepin.dde-file-manager
|
||||
pkgs.deepin.dde-session-ui
|
||||
pkgs.deepin.deepin-anything
|
||||
pkgs.deepin.deepin-image-viewer
|
||||
];
|
||||
|
||||
systemd.packages = [
|
||||
pkgs.deepin.dde-api
|
||||
pkgs.deepin.dde-daemon
|
||||
pkgs.deepin.dde-file-manager
|
||||
pkgs.deepin.deepin-anything
|
||||
];
|
||||
|
||||
boot.extraModulePackages = [ config.boot.kernelPackages.deepin-anything ];
|
||||
|
||||
boot.kernelModules = [ "vfs_monitor" ];
|
||||
|
||||
users.groups.deepin-sound-player = { };
|
||||
|
||||
users.users.deepin-sound-player = {
|
||||
description = "Deepin sound player";
|
||||
group = "deepin-sound-player";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
users.groups.deepin-daemon = { };
|
||||
|
||||
users.users.deepin-daemon = {
|
||||
description = "Deepin daemon user";
|
||||
group = "deepin-daemon";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
users.groups.deepin_anything_server = { };
|
||||
|
||||
users.users.deepin_anything_server = {
|
||||
description = "Deepin Anything Server";
|
||||
group = "deepin_anything_server";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
security.pam.services.deepin-auth-keyboard.text = ''
|
||||
# original at ${pkgs.deepin.dde-daemon}/etc/pam.d/deepin-auth-keyboard
|
||||
auth [success=2 default=ignore] pam_lsass.so
|
||||
auth [success=1 default=ignore] pam_unix.so nullok_secure try_first_pass
|
||||
auth requisite pam_deny.so
|
||||
auth required pam_permit.so
|
||||
'';
|
||||
|
||||
environment.etc = {
|
||||
"polkit-1/localauthority/10-vendor.d/com.deepin.api.device.pkla".source = "${pkgs.deepin.dde-api}/etc/polkit-1/localauthority/10-vendor.d/com.deepin.api.device.pkla";
|
||||
"polkit-1/localauthority/10-vendor.d/com.deepin.daemon.Accounts.pkla".source = "${pkgs.deepin.dde-daemon}/etc/polkit-1/localauthority/10-vendor.d/com.deepin.daemon.Accounts.pkla";
|
||||
"polkit-1/localauthority/10-vendor.d/com.deepin.daemon.Grub2.pkla".source = "${pkgs.deepin.dde-daemon}/etc/polkit-1/localauthority/10-vendor.d/com.deepin.daemon.Grub2.pkla";
|
||||
};
|
||||
|
||||
services.deepin.deepin-menu.enable = true;
|
||||
services.deepin.deepin-turbo.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf config.services.deepin.deepin-menu.enable {
|
||||
services.dbus.packages = [ pkgs.deepin.deepin-menu ];
|
||||
})
|
||||
|
||||
(lib.mkIf config.services.deepin.deepin-turbo.enable {
|
||||
environment.systemPackages = [ pkgs.deepin.deepin-turbo ];
|
||||
systemd.packages = [ pkgs.deepin.deepin-turbo ];
|
||||
})
|
||||
|
||||
];
|
||||
|
||||
}
|
25
nixos/modules/services/desktops/espanso.nix
Normal file
25
nixos/modules/services/desktops/espanso.nix
Normal file
@ -0,0 +1,25 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
let cfg = config.services.espanso;
|
||||
in {
|
||||
meta = { maintainers = with lib.maintainers; [ numkem ]; };
|
||||
|
||||
options = {
|
||||
services.espanso = { enable = options.mkEnableOption "Espanso"; };
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.user.services.espanso = {
|
||||
description = "Espanso daemon";
|
||||
path = with pkgs; [ espanso libnotify xclip ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.espanso}/bin/espanso daemon";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
wantedBy = [ "default.target" ];
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.espanso ];
|
||||
};
|
||||
}
|
@ -15,7 +15,7 @@ let
|
||||
jupyterhubConfig = pkgs.writeText "jupyterhub_config.py" ''
|
||||
c.JupyterHub.bind_url = "http://${cfg.host}:${toString cfg.port}"
|
||||
|
||||
c.JupyterHub.authentication_class = "${cfg.authentication}"
|
||||
c.JupyterHub.authenticator_class = "${cfg.authentication}"
|
||||
c.JupyterHub.spawner_class = "${cfg.spawner}"
|
||||
|
||||
c.SystemdSpawner.default_url = '/lab'
|
||||
|
@ -322,7 +322,7 @@ https://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides
|
||||
If you want, you can tweak the Emacs package itself from your
|
||||
<filename>emacs.nix</filename>. For example, if you want to have a
|
||||
GTK 3-based Emacs instead of the default GTK 2-based binary and remove the
|
||||
automatically generated <filename>emacs.desktop</filename> (useful is you
|
||||
automatically generated <filename>emacs.desktop</filename> (useful if you
|
||||
only use <command>emacsclient</command>), you can change your file
|
||||
<filename>emacs.nix</filename> in this way:
|
||||
</para>
|
||||
|
@ -12,7 +12,7 @@ in{
|
||||
|
||||
config = mkOption {
|
||||
default = null;
|
||||
type = types.lines;
|
||||
type = types.nullOr types.lines;
|
||||
description = "Fancontrol configuration file content. See <citerefentry><refentrytitle>pwmconfig</refentrytitle><manvolnum>8</manvolnum></citerefentry> from the lm_sensors package.";
|
||||
example = ''
|
||||
# Configuration file generated by pwmconfig
|
||||
|
@ -103,6 +103,17 @@ in
|
||||
The temperature target on battery power in Celsius degrees.
|
||||
'';
|
||||
};
|
||||
|
||||
useTimer = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to set a timer that applies the undervolt settings every 30s.
|
||||
This will cause spam in the journal but might be required for some
|
||||
hardware under specific conditions.
|
||||
Enable this if your undervolt settings don't hold.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
@ -114,6 +125,11 @@ in
|
||||
path = [ pkgs.undervolt ];
|
||||
|
||||
description = "Intel Undervolting Service";
|
||||
|
||||
# Apply undervolt on boot, nixos generation switch and resume
|
||||
wantedBy = [ "multi-user.target" "post-resume.target" ];
|
||||
after = [ "post-resume.target" ]; # Not sure why but it won't work without this
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
Restart = "no";
|
||||
@ -121,7 +137,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.undervolt = {
|
||||
systemd.timers.undervolt = mkIf cfg.useTimer {
|
||||
description = "Undervolt timer to ensure voltage settings are always applied";
|
||||
partOf = [ "undervolt.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
@ -5,54 +5,93 @@ with lib;
|
||||
let
|
||||
cfg = config.services.logrotate;
|
||||
|
||||
pathOptions = {
|
||||
pathOpts = {
|
||||
options = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable log rotation for this path. This can be used to explicitly disable
|
||||
logging that has been configured by NixOS.
|
||||
'';
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
description = "The path to log files to be rotated";
|
||||
description = ''
|
||||
The path to log files to be rotated.
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
description = "The user account to use for rotation";
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
The user account to use for rotation.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
description = "The group to use for rotation";
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
The group to use for rotation.
|
||||
'';
|
||||
};
|
||||
|
||||
frequency = mkOption {
|
||||
type = types.enum [
|
||||
"daily" "weekly" "monthly" "yearly"
|
||||
];
|
||||
type = types.enum [ "daily" "weekly" "monthly" "yearly" ];
|
||||
default = "daily";
|
||||
description = "How often to rotate the logs";
|
||||
description = ''
|
||||
How often to rotate the logs.
|
||||
'';
|
||||
};
|
||||
|
||||
keep = mkOption {
|
||||
type = types.int;
|
||||
default = 20;
|
||||
description = "How many rotations to keep";
|
||||
description = ''
|
||||
How many rotations to keep.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Extra logrotate config options for this path";
|
||||
description = ''
|
||||
Extra logrotate config options for this path. Refer to
|
||||
<link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
|
||||
'';
|
||||
};
|
||||
|
||||
priority = mkOption {
|
||||
type = types.int;
|
||||
default = 1000;
|
||||
description = ''
|
||||
Order of this logrotate block in relation to the others. The semantics are
|
||||
the same as with `lib.mkOrder`. Smaller values have a greater priority.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pathConfig = options: ''
|
||||
"${options.path}" {
|
||||
su ${options.user} ${options.group}
|
||||
${options.frequency}
|
||||
config.extraConfig = ''
|
||||
missingok
|
||||
notifempty
|
||||
rotate ${toString options.keep}
|
||||
${options.extraConfig}
|
||||
'';
|
||||
};
|
||||
|
||||
mkConf = pathOpts: ''
|
||||
# generated by NixOS using the `services.logrotate.paths.${pathOpts.name}` attribute set
|
||||
"${pathOpts.path}" {
|
||||
${optionalString (pathOpts.user != null || pathOpts.group != null) "su ${pathOpts.user} ${pathOpts.group}"}
|
||||
${pathOpts.frequency}
|
||||
rotate ${toString pathOpts.keep}
|
||||
${pathOpts.extraConfig}
|
||||
}
|
||||
'';
|
||||
|
||||
configFile = pkgs.writeText "logrotate.conf" (
|
||||
(concatStringsSep "\n" ((map pathConfig cfg.paths) ++ [cfg.extraConfig]))
|
||||
);
|
||||
paths = sortProperties (mapAttrsToList (name: pathOpts: pathOpts // { name = name; }) (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths));
|
||||
configFile = pkgs.writeText "logrotate.conf" (concatStringsSep "\n" ((map mkConf paths) ++ [ cfg.extraConfig ]));
|
||||
|
||||
in
|
||||
{
|
||||
@ -65,41 +104,66 @@ in
|
||||
enable = mkEnableOption "the logrotate systemd service";
|
||||
|
||||
paths = mkOption {
|
||||
type = types.listOf (types.submodule pathOptions);
|
||||
default = [];
|
||||
description = "List of attribute sets with paths to rotate";
|
||||
example = {
|
||||
"/var/log/myapp/*.log" = {
|
||||
user = "myuser";
|
||||
group = "mygroup";
|
||||
rotate = "weekly";
|
||||
keep = 5;
|
||||
};
|
||||
};
|
||||
type = with types; attrsOf (submodule pathOpts);
|
||||
default = {};
|
||||
description = ''
|
||||
Attribute set of paths to rotate. The order each block appears in the generated configuration file
|
||||
can be controlled by the <link linkend="opt-services.logrotate.paths._name_.priority">priority</link> option
|
||||
using the same semantics as `lib.mkOrder`. Smaller values have a greater priority.
|
||||
'';
|
||||
example = literalExample ''
|
||||
{
|
||||
httpd = {
|
||||
path = "/var/log/httpd/*.log";
|
||||
user = config.services.httpd.user;
|
||||
group = config.services.httpd.group;
|
||||
keep = 7;
|
||||
};
|
||||
|
||||
myapp = {
|
||||
path = "/var/log/myapp/*.log";
|
||||
user = "myuser";
|
||||
group = "mygroup";
|
||||
frequency = "weekly";
|
||||
keep = 5;
|
||||
priority = 1;
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Extra contents to add to the logrotate config file.
|
||||
See https://linux.die.net/man/8/logrotate
|
||||
Extra contents to append to the logrotate configuration file. Refer to
|
||||
<link xlink:href="https://linux.die.net/man/8/logrotate"/> for details.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.logrotate = {
|
||||
description = "Logrotate Service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
startAt = "*-*-* *:05:00";
|
||||
assertions = mapAttrsToList (name: pathOpts:
|
||||
{ assertion = (pathOpts.user != null) == (pathOpts.group != null);
|
||||
message = ''
|
||||
If either of `services.logrotate.paths.${name}.user` or `services.logrotate.paths.${name}.group` are specified then *both* must be specified.
|
||||
'';
|
||||
}
|
||||
) cfg.paths;
|
||||
|
||||
serviceConfig.Restart = "no";
|
||||
serviceConfig.User = "root";
|
||||
systemd.services.logrotate = {
|
||||
description = "Logrotate Service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
startAt = "*-*-* *:05:00";
|
||||
script = ''
|
||||
exec ${pkgs.logrotate}/sbin/logrotate ${configFile}
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Restart = "no";
|
||||
User = "root";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -4,13 +4,9 @@ with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.logstash;
|
||||
pluginPath = lib.concatStringsSep ":" cfg.plugins;
|
||||
havePluginPath = lib.length cfg.plugins > 0;
|
||||
ops = lib.optionalString;
|
||||
verbosityFlag = "--log.level " + cfg.logLevel;
|
||||
|
||||
pluginsPath = "--path.plugins ${pluginPath}";
|
||||
|
||||
logstashConf = pkgs.writeText "logstash.conf" ''
|
||||
input {
|
||||
${cfg.inputConfig}
|
||||
@ -173,7 +169,7 @@ in
|
||||
ExecStart = concatStringsSep " " (filter (s: stringLength s != 0) [
|
||||
"${cfg.package}/bin/logstash"
|
||||
"-w ${toString cfg.filterWorkers}"
|
||||
(ops havePluginPath pluginsPath)
|
||||
(concatMapStringsSep " " (x: "--path.plugins ${x}") cfg.plugins)
|
||||
"${verbosityFlag}"
|
||||
"-f ${logstashConf}"
|
||||
"--path.settings ${logstashSettingsDir}"
|
||||
|
@ -1,4 +1,4 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ options, config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
@ -83,11 +83,11 @@ let
|
||||
)
|
||||
|
||||
(
|
||||
optionalString (cfg.mailboxes != []) ''
|
||||
optionalString (cfg.mailboxes != {}) ''
|
||||
protocol imap {
|
||||
namespace inbox {
|
||||
inbox=yes
|
||||
${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)}
|
||||
${concatStringsSep "\n" (map mailboxConfig (attrValues cfg.mailboxes))}
|
||||
}
|
||||
}
|
||||
''
|
||||
@ -131,12 +131,13 @@ let
|
||||
special_use = \${toString mailbox.specialUse}
|
||||
'' + "}";
|
||||
|
||||
mailboxes = { ... }: {
|
||||
mailboxes = { name, ... }: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.nullOr (types.strMatching ''[^"]+'');
|
||||
type = types.strMatching ''[^"]+'';
|
||||
example = "Spam";
|
||||
default = null;
|
||||
default = name;
|
||||
readOnly = true;
|
||||
description = "The name of the mailbox.";
|
||||
};
|
||||
auto = mkOption {
|
||||
@ -335,19 +336,11 @@ in
|
||||
};
|
||||
|
||||
mailboxes = mkOption {
|
||||
type = with types; let m = submodule mailboxes; in either (listOf m) (attrsOf m);
|
||||
type = with types; coercedTo
|
||||
(listOf unspecified)
|
||||
(list: listToAttrs (map (entry: { name = entry.name; value = removeAttrs entry ["name"]; }) list))
|
||||
(attrsOf (submodule mailboxes));
|
||||
default = {};
|
||||
apply = x:
|
||||
if isList x then warn "Declaring `services.dovecot2.mailboxes' as a list is deprecated and will break eval in 21.03!" x
|
||||
else mapAttrsToList (name: value:
|
||||
if value.name != null
|
||||
then throw ''
|
||||
When specifying dovecot2 mailboxes as attributes, declaring
|
||||
a `name'-attribute is prohibited! The name ${value.name} should
|
||||
be the attribute key!
|
||||
''
|
||||
else value // { inherit name; }
|
||||
) x;
|
||||
example = literalExample ''
|
||||
{
|
||||
Spam = { specialUse = "Junk"; auto = "create"; };
|
||||
@ -471,6 +464,10 @@ in
|
||||
|
||||
environment.systemPackages = [ dovecotPkg ];
|
||||
|
||||
warnings = mkIf (any isList options.services.dovecot2.mailboxes.definitions) [
|
||||
"Declaring `services.dovecot2.mailboxes' as a list is deprecated and will break eval in 21.03! See the release notes for more info for migration."
|
||||
];
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion = intersectLists cfg.protocols [ "pop3" "imap" ] != [];
|
||||
|
@ -172,7 +172,7 @@ in {
|
||||
};
|
||||
|
||||
database = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Database name to store sms data";
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ let
|
||||
'') gitlabConfig.production.repositories.storages))}
|
||||
'';
|
||||
|
||||
gitlabShellConfig = {
|
||||
gitlabShellConfig = flip recursiveUpdate cfg.extraShellConfig {
|
||||
user = cfg.user;
|
||||
gitlab_url = "http+unix://${pathUrlQuote gitlabSocket}";
|
||||
http_settings.self_signed_cert = false;
|
||||
@ -517,6 +517,12 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
extraShellConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Extra configuration to merge into shell-config.yml";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
|
@ -50,6 +50,12 @@ in
|
||||
description = "Parse and interpret emoji tags";
|
||||
};
|
||||
|
||||
h1-title = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Use the first h1 as page title";
|
||||
};
|
||||
|
||||
branch = mkOption {
|
||||
type = types.str;
|
||||
default = "master";
|
||||
@ -102,6 +108,7 @@ in
|
||||
--ref ${cfg.branch} \
|
||||
${optionalString cfg.mathjax "--mathjax"} \
|
||||
${optionalString cfg.emoji "--emoji"} \
|
||||
${optionalString cfg.h1-title "--h1-title"} \
|
||||
${optionalString (cfg.allowUploads != null) "--allow-uploads ${cfg.allowUploads}"} \
|
||||
${cfg.stateDir}
|
||||
'';
|
||||
|
@ -500,13 +500,6 @@ in
|
||||
|
||||
config = {
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.nix.distributedBuilds || config.nix.buildMachines == [];
|
||||
message = "You must set `nix.distributedBuilds = true` to use nix.buildMachines";
|
||||
}
|
||||
];
|
||||
|
||||
nix.binaryCachePublicKeys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
|
||||
nix.binaryCaches = [ "https://cache.nixos.org/" ];
|
||||
|
||||
|
@ -68,8 +68,8 @@ in
|
||||
plugins = mkOption {
|
||||
default = plugins: [];
|
||||
defaultText = "plugins: []";
|
||||
example = literalExample "plugins: [ m3d-fio ]";
|
||||
description = "Additional plugins.";
|
||||
example = literalExample "plugins: with plugins; [ m33-fio stlviewer ]";
|
||||
description = "Additional plugins to be used. Available plugins are passed through the plugins input.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
|
@ -1,12 +1,12 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkDefault mkEnableOption mkIf mkOption types;
|
||||
inherit (lib) mkBefore mkDefault mkEnableOption mkIf mkOption mkRemovedOptionModule types;
|
||||
inherit (lib) concatStringsSep literalExample mapAttrsToList;
|
||||
inherit (lib) optional optionalAttrs optionalString singleton versionAtLeast;
|
||||
inherit (lib) optional optionalAttrs optionalString;
|
||||
|
||||
cfg = config.services.redmine;
|
||||
|
||||
format = pkgs.formats.yaml {};
|
||||
bundle = "${cfg.package}/share/redmine/bin/bundle";
|
||||
|
||||
databaseYml = pkgs.writeText "database.yml" ''
|
||||
@ -20,24 +20,8 @@ let
|
||||
${optionalString (cfg.database.type == "mysql2" && cfg.database.socket != null) "socket: ${cfg.database.socket}"}
|
||||
'';
|
||||
|
||||
configurationYml = pkgs.writeText "configuration.yml" ''
|
||||
default:
|
||||
scm_subversion_command: ${pkgs.subversion}/bin/svn
|
||||
scm_mercurial_command: ${pkgs.mercurial}/bin/hg
|
||||
scm_git_command: ${pkgs.gitAndTools.git}/bin/git
|
||||
scm_cvs_command: ${pkgs.cvs}/bin/cvs
|
||||
scm_bazaar_command: ${pkgs.breezy}/bin/bzr
|
||||
scm_darcs_command: ${pkgs.darcs}/bin/darcs
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
|
||||
additionalEnvironment = pkgs.writeText "additional_environment.rb" ''
|
||||
config.logger = Logger.new("${cfg.stateDir}/log/production.log", 14, 1048576)
|
||||
config.logger.level = Logger::INFO
|
||||
|
||||
${cfg.extraEnv}
|
||||
'';
|
||||
configurationYml = format.generate "configuration.yml" cfg.settings;
|
||||
additionalEnvironment = pkgs.writeText "additional_environment.rb" cfg.extraEnv;
|
||||
|
||||
unpackTheme = unpack "theme";
|
||||
unpackPlugin = unpack "plugin";
|
||||
@ -56,8 +40,13 @@ let
|
||||
pgsqlLocal = cfg.database.createLocally && cfg.database.type == "postgresql";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "services" "redmine" "extraConfig" ] "Use services.redmine.settings instead.")
|
||||
(mkRemovedOptionModule [ "services" "redmine" "database" "password" ] "Use services.redmine.database.passwordFile instead.")
|
||||
];
|
||||
|
||||
# interface
|
||||
options = {
|
||||
services.redmine = {
|
||||
enable = mkEnableOption "Redmine";
|
||||
@ -93,21 +82,24 @@ in
|
||||
description = "The state directory, logs and plugins are stored here.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
settings = mkOption {
|
||||
type = format.type;
|
||||
default = {};
|
||||
description = ''
|
||||
Extra configuration in configuration.yml.
|
||||
|
||||
See <link xlink:href="https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration"/>
|
||||
Redmine configuration (<filename>configuration.yml</filename>). Refer to
|
||||
<link xlink:href="https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration"/>
|
||||
for details.
|
||||
'';
|
||||
example = literalExample ''
|
||||
email_delivery:
|
||||
delivery_method: smtp
|
||||
smtp_settings:
|
||||
address: mail.example.com
|
||||
port: 25
|
||||
{
|
||||
email_delivery = {
|
||||
delivery_method = "smtp";
|
||||
smtp_settings = {
|
||||
address = "mail.example.com";
|
||||
port = 25;
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
@ -186,16 +178,6 @@ in
|
||||
description = "Database user.";
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
The password corresponding to <option>database.user</option>.
|
||||
Warning: this is stored in cleartext in the Nix store!
|
||||
Use <option>database.passwordFile</option> instead.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
@ -226,11 +208,12 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
# implementation
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
assertions = [
|
||||
{ assertion = cfg.database.passwordFile != null || cfg.database.password != "" || cfg.database.socket != null;
|
||||
message = "one of services.redmine.database.socket, services.redmine.database.passwordFile, or services.redmine.database.password must be set";
|
||||
{ assertion = cfg.database.passwordFile != null || cfg.database.socket != null;
|
||||
message = "one of services.redmine.database.socket or services.redmine.database.passwordFile must be set";
|
||||
}
|
||||
{ assertion = cfg.database.createLocally -> cfg.database.user == cfg.user;
|
||||
message = "services.redmine.database.user must be set to ${cfg.user} if services.redmine.database.createLocally is set true";
|
||||
@ -243,6 +226,22 @@ in
|
||||
}
|
||||
];
|
||||
|
||||
services.redmine.settings = {
|
||||
production = {
|
||||
scm_subversion_command = "${pkgs.subversion}/bin/svn";
|
||||
scm_mercurial_command = "${pkgs.mercurial}/bin/hg";
|
||||
scm_git_command = "${pkgs.gitAndTools.git}/bin/git";
|
||||
scm_cvs_command = "${pkgs.cvs}/bin/cvs";
|
||||
scm_bazaar_command = "${pkgs.breezy}/bin/bzr";
|
||||
scm_darcs_command = "${pkgs.darcs}/bin/darcs";
|
||||
};
|
||||
};
|
||||
|
||||
services.redmine.extraEnv = mkBefore ''
|
||||
config.logger = Logger.new("${cfg.stateDir}/log/production.log", 14, 1048576)
|
||||
config.logger.level = Logger::INFO
|
||||
'';
|
||||
|
||||
services.mysql = mkIf mysqlLocal {
|
||||
enable = true;
|
||||
package = mkDefault pkgs.mariadb;
|
||||
@ -338,7 +337,7 @@ in
|
||||
|
||||
|
||||
# handle database.passwordFile & permissions
|
||||
DBPASS=$(head -n1 ${cfg.database.passwordFile})
|
||||
DBPASS=${optionalString (cfg.database.passwordFile != null) "$(head -n1 ${cfg.database.passwordFile})"}
|
||||
cp -f ${databaseYml} "${cfg.stateDir}/config/database.yml"
|
||||
sed -e "s,#dbpass#,$DBPASS,g" -i "${cfg.stateDir}/config/database.yml"
|
||||
chmod 440 "${cfg.stateDir}/config/database.yml"
|
||||
@ -379,17 +378,6 @@ in
|
||||
redmine.gid = config.ids.gids.redmine;
|
||||
};
|
||||
|
||||
warnings = optional (cfg.database.password != "")
|
||||
''config.services.redmine.database.password will be stored as plaintext
|
||||
in the Nix store. Use database.passwordFile instead.'';
|
||||
|
||||
# Create database passwordFile default when password is configured.
|
||||
services.redmine.database.passwordFile =
|
||||
(mkDefault (toString (pkgs.writeTextFile {
|
||||
name = "redmine-database-password";
|
||||
text = cfg.database.password;
|
||||
})));
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -29,13 +29,15 @@ in {
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.ssm-agent = {
|
||||
users.extraUsers.ssm-user = {};
|
||||
|
||||
inherit (cfg.package.meta) description;
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = [ fake-lsb-release ];
|
||||
path = [ fake-lsb-release pkgs.coreutils ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/agent";
|
||||
ExecStart = "${cfg.package}/bin/amazon-ssm-agent";
|
||||
KillMode = "process";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "15min";
|
||||
|
@ -69,7 +69,7 @@ in {
|
||||
mode = "0400";
|
||||
};
|
||||
|
||||
system.nssModules = pkgs.sssd;
|
||||
system.nssModules = [ pkgs.sssd ];
|
||||
system.nssDatabases = {
|
||||
group = [ "sss" ];
|
||||
passwd = [ "sss" ];
|
||||
@ -92,4 +92,6 @@ in {
|
||||
services.openssh.authorizedKeysCommand = "/etc/ssh/authorized_keys_command";
|
||||
services.openssh.authorizedKeysCommandUser = "nobody";
|
||||
})];
|
||||
|
||||
meta.maintainers = with maintainers; [ bbigras ];
|
||||
}
|
||||
|
@ -4,19 +4,29 @@ with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.monit;
|
||||
extraConfig = pkgs.writeText "monitConfig" cfg.extraConfig;
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
(mkRenamedOptionModule [ "services" "monit" "config" ] ["services" "monit" "extraConfig" ])
|
||||
];
|
||||
|
||||
options.services.monit = {
|
||||
|
||||
enable = mkEnableOption "Monit";
|
||||
|
||||
config = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "monitrc content";
|
||||
configFiles = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
description = "List of paths to be included in the monitrc file";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Additional monit config as string";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
@ -24,7 +34,7 @@ in
|
||||
environment.systemPackages = [ pkgs.monit ];
|
||||
|
||||
environment.etc.monitrc = {
|
||||
text = cfg.config;
|
||||
text = concatMapStringsSep "\n" (path: "include ${path}") (cfg.configFiles ++ [extraConfig]);
|
||||
mode = "0400";
|
||||
};
|
||||
|
||||
|
@ -46,7 +46,7 @@ let
|
||||
cmdlineArgs = cfg.extraFlags ++ [
|
||||
"--storage.tsdb.path=${workingDir}/data/"
|
||||
"--config.file=${prometheusYml}"
|
||||
"--web.listen-address=${cfg.listenAddress}"
|
||||
"--web.listen-address=${cfg.listenAddress}:${builtins.toString cfg.port}"
|
||||
"--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
|
||||
"--alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
|
||||
] ++
|
||||
@ -489,9 +489,17 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 9090;
|
||||
description = ''
|
||||
Port to listen on.
|
||||
'';
|
||||
};
|
||||
|
||||
listenAddress = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0:9090";
|
||||
default = "0.0.0.0";
|
||||
description = ''
|
||||
Address to listen on for the web interface, API, and telemetry.
|
||||
'';
|
||||
@ -619,6 +627,21 @@ in {
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
( let
|
||||
legacy = builtins.match "(.*):(.*)" cfg.listenAddress;
|
||||
in {
|
||||
assertion = legacy == null;
|
||||
message = ''
|
||||
Do not specify the port for Prometheus to listen on in the
|
||||
listenAddress option; use the port option instead:
|
||||
services.prometheus.listenAddress = ${builtins.elemAt legacy 0};
|
||||
services.prometheus.port = ${builtins.elemAt legacy 1};
|
||||
'';
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
users.groups.prometheus.gid = config.ids.gids.prometheus;
|
||||
users.users.prometheus = {
|
||||
description = "Prometheus daemon user";
|
||||
|
@ -20,7 +20,7 @@ let
|
||||
${pkgs.coreutils}/bin/cat << EOF
|
||||
From: smartd on ${host} <${nm.sender}>
|
||||
To: undisclosed-recipients:;
|
||||
Subject: SMART error on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE
|
||||
Subject: $SMARTD_SUBJECT
|
||||
|
||||
$SMARTD_FULLMESSAGE
|
||||
EOF
|
||||
@ -239,11 +239,7 @@ in
|
||||
|
||||
systemd.services.smartd = {
|
||||
description = "S.M.A.R.T. Daemon";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = [ pkgs.nettools ]; # for hostname and dnsdomanname calls in smartd
|
||||
|
||||
serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}";
|
||||
};
|
||||
|
||||
|
@ -5,8 +5,8 @@ let
|
||||
pgsql = config.services.postgresql;
|
||||
mysql = config.services.mysql;
|
||||
|
||||
inherit (lib) mkDefault mkEnableOption mkIf mkMerge mkOption;
|
||||
inherit (lib) attrValues concatMapStringsSep literalExample optional optionalAttrs optionalString types;
|
||||
inherit (lib) mkAfter mkDefault mkEnableOption mkIf mkMerge mkOption;
|
||||
inherit (lib) attrValues concatMapStringsSep getName literalExample optional optionalAttrs optionalString types;
|
||||
inherit (lib.generators) toKeyValue;
|
||||
|
||||
user = "zabbix";
|
||||
@ -232,14 +232,15 @@ in
|
||||
services.mysql = optionalAttrs mysqlLocal {
|
||||
enable = true;
|
||||
package = mkDefault pkgs.mariadb;
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
ensureUsers = [
|
||||
{ name = cfg.database.user;
|
||||
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services.mysql.postStart = mkAfter (optionalString mysqlLocal ''
|
||||
( echo "CREATE DATABASE IF NOT EXISTS \`${cfg.database.name}\` CHARACTER SET utf8 COLLATE utf8_bin;"
|
||||
echo "CREATE USER IF NOT EXISTS '${cfg.database.user}'@'localhost' IDENTIFIED WITH ${if (getName config.services.mysql.package == getName pkgs.mariadb) then "unix_socket" else "auth_socket"};"
|
||||
echo "GRANT ALL PRIVILEGES ON \`${cfg.database.name}\`.* TO '${cfg.database.user}'@'localhost';"
|
||||
) | ${config.services.mysql.package}/bin/mysql -N
|
||||
'');
|
||||
|
||||
services.postgresql = optionalAttrs pgsqlLocal {
|
||||
enable = true;
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
|
@ -5,8 +5,8 @@ let
|
||||
pgsql = config.services.postgresql;
|
||||
mysql = config.services.mysql;
|
||||
|
||||
inherit (lib) mkDefault mkEnableOption mkIf mkMerge mkOption;
|
||||
inherit (lib) attrValues concatMapStringsSep literalExample optional optionalAttrs optionalString types;
|
||||
inherit (lib) mkAfter mkDefault mkEnableOption mkIf mkMerge mkOption;
|
||||
inherit (lib) attrValues concatMapStringsSep getName literalExample optional optionalAttrs optionalString types;
|
||||
inherit (lib.generators) toKeyValue;
|
||||
|
||||
user = "zabbix";
|
||||
@ -220,14 +220,15 @@ in
|
||||
services.mysql = optionalAttrs mysqlLocal {
|
||||
enable = true;
|
||||
package = mkDefault pkgs.mariadb;
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
ensureUsers = [
|
||||
{ name = cfg.database.user;
|
||||
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services.mysql.postStart = mkAfter (optionalString mysqlLocal ''
|
||||
( echo "CREATE DATABASE IF NOT EXISTS \`${cfg.database.name}\` CHARACTER SET utf8 COLLATE utf8_bin;"
|
||||
echo "CREATE USER IF NOT EXISTS '${cfg.database.user}'@'localhost' IDENTIFIED WITH ${if (getName config.services.mysql.package == getName pkgs.mariadb) then "unix_socket" else "auth_socket"};"
|
||||
echo "GRANT ALL PRIVILEGES ON \`${cfg.database.name}\`.* TO '${cfg.database.user}'@'localhost';"
|
||||
) | ${config.services.mysql.package}/bin/mysql -N
|
||||
'');
|
||||
|
||||
services.postgresql = optionalAttrs pgsqlLocal {
|
||||
enable = true;
|
||||
ensureDatabases = [ cfg.database.name ];
|
||||
|
@ -83,14 +83,14 @@ in {
|
||||
};
|
||||
|
||||
dataStorageSpace = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "/data/storage";
|
||||
description = "Directory for data storage.";
|
||||
};
|
||||
|
||||
metadataStorageSpace = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "/data/meta";
|
||||
description = "Directory for meta data storage.";
|
||||
|
@ -87,7 +87,7 @@ in
|
||||
};
|
||||
|
||||
rpc.password = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Password for RPC connections.
|
||||
|
@ -89,7 +89,7 @@ in
|
||||
};
|
||||
|
||||
rpc.password = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Password for RPC connections.
|
||||
|
@ -458,7 +458,7 @@ in {
|
||||
|
||||
systemd.services.NetworkManager-dispatcher = {
|
||||
wantedBy = [ "network.target" ];
|
||||
restartTriggers = [ configFile ];
|
||||
restartTriggers = [ configFile overrideNameserversScript ];
|
||||
|
||||
# useful binaries for user-specified hooks
|
||||
path = [ pkgs.iproute pkgs.utillinux pkgs.coreutils ];
|
||||
|
47
nixos/modules/services/networking/robustirc-bridge.nix
Normal file
47
nixos/modules/services/networking/robustirc-bridge.nix
Normal file
@ -0,0 +1,47 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.robustirc-bridge;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.robustirc-bridge = {
|
||||
enable = mkEnableOption "RobustIRC bridge";
|
||||
|
||||
extraFlags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''Extra flags passed to the <command>robustirc-bridge</command> command. See <link xlink:href="https://robustirc.net/docs/adminguide.html#_bridge">RobustIRC Documentation</link> or robustirc-bridge(1) for details.'';
|
||||
example = [
|
||||
"-network robustirc.net"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.robustirc-bridge = {
|
||||
description = "RobustIRC bridge";
|
||||
documentation = [
|
||||
"man:robustirc-bridge(1)"
|
||||
"https://robustirc.net/"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
ExecStart = "${pkgs.robustirc-bridge}/bin/robustirc-bridge ${concatStringsSep " " cfg.extraFlags}";
|
||||
Restart = "on-failure";
|
||||
|
||||
# Hardening
|
||||
PrivateDevices = true;
|
||||
ProtectSystem = true;
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -11,8 +11,13 @@ let
|
||||
method = cfg.encryptionMethod;
|
||||
mode = cfg.mode;
|
||||
user = "nobody";
|
||||
fast_open = true;
|
||||
} // optionalAttrs (cfg.password != null) { password = cfg.password; };
|
||||
fast_open = cfg.fastOpen;
|
||||
} // optionalAttrs (cfg.plugin != null) {
|
||||
plugin = cfg.plugin;
|
||||
plugin_opts = cfg.pluginOpts;
|
||||
} // optionalAttrs (cfg.password != null) {
|
||||
password = cfg.password;
|
||||
};
|
||||
|
||||
configFile = pkgs.writeText "shadowsocks.json" (builtins.toJSON opts);
|
||||
|
||||
@ -74,6 +79,14 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
fastOpen = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
use TCP fast-open
|
||||
'';
|
||||
};
|
||||
|
||||
encryptionMethod = mkOption {
|
||||
type = types.str;
|
||||
default = "chacha20-ietf-poly1305";
|
||||
@ -82,6 +95,23 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
plugin = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "\${pkgs.shadowsocks-v2ray-plugin}/bin/v2ray-plugin";
|
||||
description = ''
|
||||
SIP003 plugin for shadowsocks
|
||||
'';
|
||||
};
|
||||
|
||||
pluginOpts = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "server;host=example.com";
|
||||
description = ''
|
||||
Options to pass to the plugin if one was specified
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
@ -99,7 +129,7 @@ in
|
||||
description = "shadowsocks-libev Daemon";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.shadowsocks-libev ] ++ optional (cfg.passwordFile != null) pkgs.jq;
|
||||
path = [ pkgs.shadowsocks-libev cfg.plugin ] ++ optional (cfg.passwordFile != null) pkgs.jq;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
script = ''
|
||||
${optionalString (cfg.passwordFile != null) ''
|
||||
|
@ -233,6 +233,9 @@ in {
|
||||
path = [ pkgs.wpa_supplicant ];
|
||||
|
||||
script = ''
|
||||
if [ -f /etc/wpa_supplicant.conf -a "/etc/wpa_supplicant.conf" != "${configFile}" ]
|
||||
then echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead."
|
||||
fi
|
||||
iface_args="-s -u -D${cfg.driver} -c ${configFile}"
|
||||
${if ifaces == [] then ''
|
||||
for i in $(cd /sys/class/net && echo *); do
|
||||
|
@ -52,6 +52,14 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
lockMessage = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Message to show on physlock login terminal.
|
||||
'';
|
||||
};
|
||||
|
||||
lockOn = {
|
||||
|
||||
suspend = mkOption {
|
||||
@ -111,7 +119,7 @@ in
|
||||
++ cfg.lockOn.extraTargets;
|
||||
serviceConfig = {
|
||||
Type = "forking";
|
||||
ExecStart = "${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}";
|
||||
ExecStart = "${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}${optionalString (cfg.lockMessage != "") " -p \"${cfg.lockMessage}\""}";
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -34,8 +34,8 @@ let
|
||||
User tor
|
||||
DataDirectory ${torDirectory}
|
||||
${optionalString cfg.enableGeoIP ''
|
||||
GeoIPFile ${pkgs.tor.geoip}/share/tor/geoip
|
||||
GeoIPv6File ${pkgs.tor.geoip}/share/tor/geoip6
|
||||
GeoIPFile ${cfg.package.geoip}/share/tor/geoip
|
||||
GeoIPv6File ${cfg.package.geoip}/share/tor/geoip6
|
||||
''}
|
||||
|
||||
${optint "ControlPort" cfg.controlPort}
|
||||
@ -123,6 +123,16 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.tor;
|
||||
defaultText = "pkgs.tor";
|
||||
example = literalExample "pkgs.tor";
|
||||
description = ''
|
||||
Tor package to use
|
||||
'';
|
||||
};
|
||||
|
||||
enableGeoIP = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@ -749,8 +759,8 @@ in
|
||||
serviceConfig =
|
||||
{ Type = "simple";
|
||||
# Translated from the upstream contrib/dist/tor.service.in
|
||||
ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config";
|
||||
ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile}";
|
||||
ExecStartPre = "${cfg.package}/bin/tor -f ${torRcFile} --verify-config";
|
||||
ExecStart = "${cfg.package}/bin/tor -f ${torRcFile}";
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||
KillSignal = "SIGINT";
|
||||
TimeoutSec = 30;
|
||||
@ -773,7 +783,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.tor ];
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
services.privoxy = mkIf (cfg.client.enable && cfg.client.privoxy.enable) {
|
||||
enable = true;
|
||||
|
@ -82,6 +82,7 @@ in {
|
||||
auth required pam_unix.so nullok
|
||||
account required pam_unix.so
|
||||
session required pam_unix.so
|
||||
session required pam_env.so conffile=${config.system.build.pamEnvironment} readenv=0
|
||||
session required ${pkgs.systemd}/lib/security/pam_systemd.so
|
||||
'';
|
||||
|
||||
|
@ -77,7 +77,6 @@ in {
|
||||
// Paths
|
||||
WOSendMail = "/run/wrappers/bin/sendmail";
|
||||
SOGoMailSpoolPath = "/var/lib/sogo/spool";
|
||||
SOGoZipPath = "${pkgs.zip}/bin/zip";
|
||||
// Enable CSRF protection
|
||||
SOGoXSRFValidationEnabled = YES;
|
||||
// Remove dates from log (jornald does that)
|
||||
|
@ -661,6 +661,25 @@ in
|
||||
pkg
|
||||
];
|
||||
|
||||
services.logrotate = optionalAttrs (cfg.logFormat != "none") {
|
||||
enable = mkDefault true;
|
||||
paths.httpd = {
|
||||
path = "${cfg.logDir}/*.log";
|
||||
user = cfg.user;
|
||||
group = cfg.group;
|
||||
frequency = "daily";
|
||||
keep = 28;
|
||||
extraConfig = ''
|
||||
sharedscripts
|
||||
compress
|
||||
delaycompress
|
||||
postrotate
|
||||
systemctl reload httpd.service > /dev/null 2>/dev/null || true
|
||||
endscript
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
services.httpd.phpOptions =
|
||||
''
|
||||
; Needed for PHP's mail() function.
|
||||
|
@ -1,174 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.meguca;
|
||||
postgres = config.services.postgresql;
|
||||
in with lib; {
|
||||
options.services.meguca = {
|
||||
enable = mkEnableOption "meguca";
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/meguca";
|
||||
example = "/home/okina/meguca";
|
||||
description = "Location where meguca stores it's database and links.";
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
type = types.str;
|
||||
default = "meguca";
|
||||
example = "dumbpass";
|
||||
description = "Password for the meguca database.";
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = types.path;
|
||||
default = "/run/keys/meguca-password-file";
|
||||
example = "/home/okina/meguca/keys/pass";
|
||||
description = "Password file for the meguca database.";
|
||||
};
|
||||
|
||||
reverseProxy = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "192.168.1.5";
|
||||
description = "Reverse proxy IP.";
|
||||
};
|
||||
|
||||
sslCertificate = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "/home/okina/meguca/ssl.cert";
|
||||
description = "Path to the SSL certificate.";
|
||||
};
|
||||
|
||||
listenAddress = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "127.0.0.1:8000";
|
||||
description = "Listen on a specific IP address and port.";
|
||||
};
|
||||
|
||||
cacheSize = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = null;
|
||||
example = 256;
|
||||
description = "Cache size in MB.";
|
||||
};
|
||||
|
||||
postgresArgs = mkOption {
|
||||
type = types.str;
|
||||
example = "user=meguca password=dumbpass dbname=meguca sslmode=disable";
|
||||
description = "Postgresql connection arguments.";
|
||||
};
|
||||
|
||||
postgresArgsFile = mkOption {
|
||||
type = types.path;
|
||||
default = "/run/keys/meguca-postgres-args";
|
||||
example = "/home/okina/meguca/keys/postgres";
|
||||
description = "Postgresql connection arguments file.";
|
||||
};
|
||||
|
||||
compressTraffic = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Compress all traffic with gzip.";
|
||||
};
|
||||
|
||||
assumeReverseProxy = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Assume the server is behind a reverse proxy, when resolving client IPs.";
|
||||
};
|
||||
|
||||
httpsOnly = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Serve and listen only through HTTPS.";
|
||||
};
|
||||
|
||||
videoPaths = mkOption {
|
||||
type = types.listOf types.path;
|
||||
default = [];
|
||||
example = [ "/home/okina/Videos/tehe_pero.webm" ];
|
||||
description = "Videos that will be symlinked into www/videos.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
security.sudo.enable = cfg.enable;
|
||||
services.postgresql.enable = cfg.enable;
|
||||
services.postgresql.package = pkgs.postgresql_11;
|
||||
services.meguca.passwordFile = mkDefault (pkgs.writeText "meguca-password-file" cfg.password);
|
||||
services.meguca.postgresArgsFile = mkDefault (pkgs.writeText "meguca-postgres-args" cfg.postgresArgs);
|
||||
services.meguca.postgresArgs = mkDefault "user=meguca password=${cfg.password} dbname=meguca sslmode=disable";
|
||||
|
||||
systemd.services.meguca = {
|
||||
description = "meguca";
|
||||
after = [ "network.target" "postgresql.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
preStart = ''
|
||||
# Ensure folder exists or create it and links and permissions are correct
|
||||
mkdir -p ${escapeShellArg cfg.dataDir}/www
|
||||
rm -rf ${escapeShellArg cfg.dataDir}/www/videos
|
||||
ln -sf ${pkgs.meguca}/share/meguca/www/* ${escapeShellArg cfg.dataDir}/www
|
||||
unlink ${escapeShellArg cfg.dataDir}/www/videos
|
||||
mkdir -p ${escapeShellArg cfg.dataDir}/www/videos
|
||||
|
||||
for vid in ${escapeShellArg cfg.videoPaths}; do
|
||||
ln -sf $vid ${escapeShellArg cfg.dataDir}/www/videos
|
||||
done
|
||||
|
||||
chmod 750 ${escapeShellArg cfg.dataDir}
|
||||
chown -R meguca:meguca ${escapeShellArg cfg.dataDir}
|
||||
|
||||
# Ensure the database is correct or create it
|
||||
${pkgs.sudo}/bin/sudo -u ${postgres.superUser} ${postgres.package}/bin/createuser \
|
||||
-SDR meguca || true
|
||||
${pkgs.sudo}/bin/sudo -u ${postgres.superUser} ${postgres.package}/bin/createdb \
|
||||
-T template0 -E UTF8 -O meguca meguca || true
|
||||
${pkgs.sudo}/bin/sudo -u meguca ${postgres.package}/bin/psql \
|
||||
-c "ALTER ROLE meguca WITH PASSWORD '$(cat ${escapeShellArg cfg.passwordFile})';" || true
|
||||
'';
|
||||
|
||||
script = ''
|
||||
cd ${escapeShellArg cfg.dataDir}
|
||||
|
||||
${pkgs.meguca}/bin/meguca -d "$(cat ${escapeShellArg cfg.postgresArgsFile})"''
|
||||
+ optionalString (cfg.reverseProxy != null) " -R ${cfg.reverseProxy}"
|
||||
+ optionalString (cfg.sslCertificate != null) " -S ${cfg.sslCertificate}"
|
||||
+ optionalString (cfg.listenAddress != null) " -a ${cfg.listenAddress}"
|
||||
+ optionalString (cfg.cacheSize != null) " -c ${toString cfg.cacheSize}"
|
||||
+ optionalString (cfg.compressTraffic) " -g"
|
||||
+ optionalString (cfg.assumeReverseProxy) " -r"
|
||||
+ optionalString (cfg.httpsOnly) " -s" + " start";
|
||||
|
||||
serviceConfig = {
|
||||
PermissionsStartOnly = true;
|
||||
Type = "forking";
|
||||
User = "meguca";
|
||||
Group = "meguca";
|
||||
ExecStop = "${pkgs.meguca}/bin/meguca stop";
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
groups.meguca.gid = config.ids.gids.meguca;
|
||||
|
||||
users.meguca = {
|
||||
description = "meguca server service user";
|
||||
home = cfg.dataDir;
|
||||
createHome = true;
|
||||
group = "meguca";
|
||||
uid = config.ids.uids.meguca;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(mkRenamedOptionModule [ "services" "meguca" "baseDir" ] [ "services" "meguca" "dataDir" ])
|
||||
];
|
||||
|
||||
meta.maintainers = with maintainers; [ chiiruno ];
|
||||
}
|
@ -61,7 +61,8 @@ in
|
||||
"--kill"
|
||||
] ++ cfg.extraOptions);
|
||||
ExecStop = "${pkgs.procps}/bin/pkill imwheel";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 3;
|
||||
Restart = "always";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -641,7 +641,7 @@ in
|
||||
credential = mkOption {
|
||||
default = null;
|
||||
example = "f1d00200d8dc783f7fb1e10ace8da27f8312d72692abfca2f7e4960a73f48e82e1f7571f6ebfcee9fb434f9886ccc8fcc52a6614d8d2";
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
description = "The FIDO2 credential ID.";
|
||||
};
|
||||
|
||||
|
@ -378,12 +378,14 @@ mountFS() {
|
||||
|
||||
mkdir -p "/mnt-root$mountPoint"
|
||||
|
||||
# For CIFS mounts, retry a few times before giving up.
|
||||
# For ZFS and CIFS mounts, retry a few times before giving up.
|
||||
# We do this for ZFS as a workaround for issue NixOS/nixpkgs#25383.
|
||||
local n=0
|
||||
while true; do
|
||||
mount "/mnt-root$mountPoint" && break
|
||||
if [ "$fsType" != cifs -o "$n" -ge 10 ]; then fail; break; fi
|
||||
if [ \( "$fsType" != cifs -a "$fsType" != zfs \) -o "$n" -ge 10 ]; then fail; break; fi
|
||||
echo "retrying..."
|
||||
sleep 1
|
||||
n=$((n + 1))
|
||||
done
|
||||
|
||||
|
@ -36,7 +36,7 @@ let
|
||||
set -euo pipefail
|
||||
|
||||
declare -A seen
|
||||
declare -a left
|
||||
left=()
|
||||
|
||||
patchelf="${pkgs.buildPackages.patchelf}/bin/patchelf"
|
||||
|
||||
@ -48,7 +48,7 @@ let
|
||||
done
|
||||
}
|
||||
|
||||
add_needed $1
|
||||
add_needed "$1"
|
||||
|
||||
while [ ''${#left[@]} -ne 0 ]; do
|
||||
next=''${left[0]}
|
||||
@ -87,7 +87,9 @@ let
|
||||
# copy what we need. Instead of using statically linked binaries,
|
||||
# we just copy what we need from Glibc and use patchelf to make it
|
||||
# work.
|
||||
extraUtils = pkgs.runCommandCC "extra-utils"
|
||||
extraUtils = let
|
||||
# Use lvm2 without udev support, which is the same lvm2 we already have in the closure anyways
|
||||
lvm2 = pkgs.lvm2.override { udev = null; }; in pkgs.runCommandCC "extra-utils"
|
||||
{ nativeBuildInputs = [pkgs.buildPackages.nukeReferences];
|
||||
allowedReferences = [ "out" ]; # prevent accidents like glibc being included in the initrd
|
||||
}
|
||||
@ -111,20 +113,21 @@ let
|
||||
copy_bin_and_libs ${pkgs.utillinux}/sbin/blkid
|
||||
|
||||
# Copy dmsetup and lvm.
|
||||
copy_bin_and_libs ${getBin pkgs.lvm2}/bin/dmsetup
|
||||
copy_bin_and_libs ${getBin pkgs.lvm2}/bin/lvm
|
||||
copy_bin_and_libs ${getBin lvm2}/bin/dmsetup
|
||||
copy_bin_and_libs ${getBin lvm2}/bin/lvm
|
||||
|
||||
# Add RAID mdadm tool.
|
||||
copy_bin_and_libs ${pkgs.mdadm}/sbin/mdadm
|
||||
copy_bin_and_libs ${pkgs.mdadm}/sbin/mdmon
|
||||
|
||||
# Copy udev.
|
||||
copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd
|
||||
copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl
|
||||
copy_bin_and_libs ${udev}/bin/udevadm
|
||||
copy_bin_and_libs ${udev}/lib/systemd/systemd-sysctl
|
||||
for BIN in ${udev}/lib/udev/*_id; do
|
||||
copy_bin_and_libs $BIN
|
||||
done
|
||||
# systemd-udevd is only a symlink to udevadm these days
|
||||
ln -sf udevadm $out/bin/systemd-udevd
|
||||
|
||||
# Copy modprobe.
|
||||
copy_bin_and_libs ${pkgs.kmod}/bin/kmod
|
||||
|
@ -25,7 +25,7 @@ let
|
||||
"nss-lookup.target"
|
||||
"nss-user-lookup.target"
|
||||
"time-sync.target"
|
||||
#"cryptsetup.target"
|
||||
"cryptsetup.target"
|
||||
"sigpwr.target"
|
||||
"timers.target"
|
||||
"paths.target"
|
||||
@ -903,11 +903,9 @@ in
|
||||
)
|
||||
]);
|
||||
passwd = (mkMerge [
|
||||
[ "mymachines" ]
|
||||
(mkAfter [ "systemd" ])
|
||||
]);
|
||||
group = (mkMerge [
|
||||
[ "mymachines" ]
|
||||
(mkAfter [ "systemd" ])
|
||||
]);
|
||||
};
|
||||
|
@ -1129,7 +1129,6 @@ in
|
||||
++ optionals config.networking.wireless.enable [
|
||||
pkgs.wirelesstools # FIXME: obsolete?
|
||||
pkgs.iw
|
||||
pkgs.rfkill
|
||||
]
|
||||
++ bridgeStp;
|
||||
|
||||
|
@ -110,6 +110,7 @@ in
|
||||
'';
|
||||
|
||||
environment.etc."cni/net.d/10-crio-bridge.conf".source = copyFile "${pkgs.cri-o-unwrapped.src}/contrib/cni/10-crio-bridge.conf";
|
||||
environment.etc."cni/net.d/99-loopback.conf".source = copyFile "${pkgs.cri-o-unwrapped.src}/contrib/cni/99-loopback.conf";
|
||||
|
||||
# Enable common /etc/containers configuration
|
||||
virtualisation.containers.enable = true;
|
||||
|
@ -1,134 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with builtins;
|
||||
|
||||
let
|
||||
cfg = config.virtualisation;
|
||||
|
||||
sanitizeImageName = image: replaceStrings ["/"] ["-"] image.imageName;
|
||||
hash = drv: head (split "-" (baseNameOf drv.outPath));
|
||||
# The label of an ext4 FS is limited to 16 bytes
|
||||
labelFromImage = image: substring 0 16 (hash image);
|
||||
|
||||
# The Docker image is loaded and some files from /var/lib/docker/
|
||||
# are written into a qcow image.
|
||||
preload = image: pkgs.vmTools.runInLinuxVM (
|
||||
pkgs.runCommand "docker-preload-image-${sanitizeImageName image}" {
|
||||
buildInputs = with pkgs; [ docker e2fsprogs utillinux curl kmod ];
|
||||
preVM = pkgs.vmTools.createEmptyImage {
|
||||
size = cfg.dockerPreloader.qcowSize;
|
||||
fullName = "docker-deamon-image.qcow2";
|
||||
};
|
||||
}
|
||||
''
|
||||
mkfs.ext4 /dev/vda
|
||||
e2label /dev/vda ${labelFromImage image}
|
||||
mkdir -p /var/lib/docker
|
||||
mount -t ext4 /dev/vda /var/lib/docker
|
||||
|
||||
modprobe overlay
|
||||
|
||||
# from https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount
|
||||
mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
|
||||
cd /sys/fs/cgroup
|
||||
for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do
|
||||
mkdir -p $sys
|
||||
if ! mountpoint -q $sys; then
|
||||
if ! mount -n -t cgroup -o $sys cgroup $sys; then
|
||||
rmdir $sys || true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
dockerd -H tcp://127.0.0.1:5555 -H unix:///var/run/docker.sock &
|
||||
|
||||
until $(curl --output /dev/null --silent --connect-timeout 2 http://127.0.0.1:5555); do
|
||||
printf '.'
|
||||
sleep 1
|
||||
done
|
||||
|
||||
docker load -i ${image}
|
||||
|
||||
kill %1
|
||||
find /var/lib/docker/ -maxdepth 1 -mindepth 1 -not -name "image" -not -name "overlay2" | xargs rm -rf
|
||||
'');
|
||||
|
||||
preloadedImages = map preload cfg.dockerPreloader.images;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.virtualisation.dockerPreloader = {
|
||||
images = mkOption {
|
||||
default = [ ];
|
||||
type = types.listOf types.package;
|
||||
description =
|
||||
''
|
||||
A list of Docker images to preload (in the /var/lib/docker directory).
|
||||
'';
|
||||
};
|
||||
qcowSize = mkOption {
|
||||
default = 1024;
|
||||
type = types.int;
|
||||
description =
|
||||
''
|
||||
The size (MB) of qcow files.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.dockerPreloader.images != []) {
|
||||
assertions = [{
|
||||
# If docker.storageDriver is null, Docker choose the storage
|
||||
# driver. So, in this case, we cannot be sure overlay2 is used.
|
||||
assertion = cfg.docker.storageDriver == "overlay2"
|
||||
|| cfg.docker.storageDriver == "overlay"
|
||||
|| cfg.docker.storageDriver == null;
|
||||
message = "The Docker image Preloader only works with overlay2 storage driver!";
|
||||
}];
|
||||
|
||||
virtualisation.qemu.options =
|
||||
map (path: "-drive if=virtio,file=${path}/disk-image.qcow2,readonly,media=cdrom,format=qcow2")
|
||||
preloadedImages;
|
||||
|
||||
|
||||
# All attached QCOW files are mounted and their contents are linked
|
||||
# to /var/lib/docker/ in order to make image available.
|
||||
systemd.services.docker-preloader = {
|
||||
description = "Preloaded Docker images";
|
||||
wantedBy = ["docker.service"];
|
||||
after = ["network.target"];
|
||||
path = with pkgs; [ mount rsync jq ];
|
||||
script = ''
|
||||
mkdir -p /var/lib/docker/overlay2/l /var/lib/docker/image/overlay2
|
||||
echo '{}' > /tmp/repositories.json
|
||||
|
||||
for i in ${concatStringsSep " " (map labelFromImage cfg.dockerPreloader.images)}; do
|
||||
mkdir -p /mnt/docker-images/$i
|
||||
|
||||
# The ext4 label is limited to 16 bytes
|
||||
mount /dev/disk/by-label/$(echo $i | cut -c1-16) -o ro,noload /mnt/docker-images/$i
|
||||
|
||||
find /mnt/docker-images/$i/overlay2/ -maxdepth 1 -mindepth 1 -not -name l\
|
||||
-exec ln -s '{}' /var/lib/docker/overlay2/ \;
|
||||
cp -P /mnt/docker-images/$i/overlay2/l/* /var/lib/docker/overlay2/l/
|
||||
|
||||
rsync -a /mnt/docker-images/$i/image/ /var/lib/docker/image/
|
||||
|
||||
# Accumulate image definitions
|
||||
cp /tmp/repositories.json /tmp/repositories.json.tmp
|
||||
jq -s '.[0] * .[1]' \
|
||||
/tmp/repositories.json.tmp \
|
||||
/mnt/docker-images/$i/image/overlay2/repositories.json \
|
||||
> /tmp/repositories.json
|
||||
done
|
||||
|
||||
mv /tmp/repositories.json /var/lib/docker/image/overlay2/repositories.json
|
||||
'';
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -32,7 +32,7 @@ in
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
type = types.nullOr types.package;
|
||||
default = config.boot.kernelPackages.prl-tools;
|
||||
defaultText = "config.boot.kernelPackages.prl-tools";
|
||||
example = literalExample "config.boot.kernelPackages.prl-tools";
|
||||
|
@ -264,7 +264,6 @@ in
|
||||
{
|
||||
imports = [
|
||||
../profiles/qemu-guest.nix
|
||||
./docker-preloader.nix
|
||||
];
|
||||
|
||||
options = {
|
||||
|
@ -106,11 +106,29 @@ in rec {
|
||||
(onFullSupported "nixos.tests.networking.scripted.bridge")
|
||||
(onFullSupported "nixos.tests.networking.scripted.dhcpOneIf")
|
||||
(onFullSupported "nixos.tests.networking.scripted.dhcpSimple")
|
||||
(onFullSupported "nixos.tests.networking.scripted.link")
|
||||
(onFullSupported "nixos.tests.networking.scripted.loopback")
|
||||
(onFullSupported "nixos.tests.networking.scripted.macvlan")
|
||||
(onFullSupported "nixos.tests.networking.scripted.privacy")
|
||||
(onFullSupported "nixos.tests.networking.scripted.routes")
|
||||
(onFullSupported "nixos.tests.networking.scripted.sit")
|
||||
(onFullSupported "nixos.tests.networking.scripted.static")
|
||||
(onFullSupported "nixos.tests.networking.scripted.virtual")
|
||||
(onFullSupported "nixos.tests.networking.scripted.vlan")
|
||||
(onFullSupported "nixos.tests.networking.networkd.bond")
|
||||
(onFullSupported "nixos.tests.networking.networkd.bridge")
|
||||
(onFullSupported "nixos.tests.networking.networkd.dhcpOneIf")
|
||||
(onFullSupported "nixos.tests.networking.networkd.dhcpSimple")
|
||||
(onFullSupported "nixos.tests.networking.networkd.link")
|
||||
(onFullSupported "nixos.tests.networking.networkd.loopback")
|
||||
# Fails nondeterministically (https://github.com/NixOS/nixpkgs/issues/96709)
|
||||
#(onFullSupported "nixos.tests.networking.networkd.macvlan")
|
||||
(onFullSupported "nixos.tests.networking.networkd.privacy")
|
||||
(onFullSupported "nixos.tests.networking.networkd.routes")
|
||||
(onFullSupported "nixos.tests.networking.networkd.sit")
|
||||
(onFullSupported "nixos.tests.networking.networkd.static")
|
||||
(onFullSupported "nixos.tests.networking.networkd.virtual")
|
||||
(onFullSupported "nixos.tests.networking.networkd.vlan")
|
||||
(onFullSupported "nixos.tests.systemd-networkd-ipv6-prefix-delegation")
|
||||
(onFullSupported "nixos.tests.nfs3.simple")
|
||||
(onFullSupported "nixos.tests.nfs4.simple")
|
||||
|
@ -34,6 +34,7 @@ in
|
||||
bind = handleTest ./bind.nix {};
|
||||
bitcoind = handleTest ./bitcoind.nix {};
|
||||
bittorrent = handleTest ./bittorrent.nix {};
|
||||
bitwarden = handleTest ./bitwarden.nix {};
|
||||
blockbook-frontend = handleTest ./blockbook-frontend.nix {};
|
||||
buildkite-agents = handleTest ./buildkite-agents.nix {};
|
||||
boot = handleTestOn ["x86_64-linux"] ./boot.nix {}; # syslinux is unsupported on aarch64
|
||||
@ -48,6 +49,7 @@ in
|
||||
ceph-multi-node = handleTestOn ["x86_64-linux"] ./ceph-multi-node.nix {};
|
||||
certmgr = handleTest ./certmgr.nix {};
|
||||
cfssl = handleTestOn ["x86_64-linux"] ./cfssl.nix {};
|
||||
charliecloud = handleTest ./charliecloud.nix {};
|
||||
chromium = (handleTestOn ["x86_64-linux"] ./chromium.nix {}).stable or {};
|
||||
cjdns = handleTest ./cjdns.nix {};
|
||||
clickhouse = handleTest ./clickhouse.nix {};
|
||||
@ -65,11 +67,13 @@ in
|
||||
containers-macvlans = handleTest ./containers-macvlans.nix {};
|
||||
containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {};
|
||||
containers-portforward = handleTest ./containers-portforward.nix {};
|
||||
containers-reloadable = handleTest ./containers-reloadable.nix {};
|
||||
containers-restart_networking = handleTest ./containers-restart_networking.nix {};
|
||||
containers-tmpfs = handleTest ./containers-tmpfs.nix {};
|
||||
convos = handleTest ./convos.nix {};
|
||||
corerad = handleTest ./corerad.nix {};
|
||||
couchdb = handleTest ./couchdb.nix {};
|
||||
cri-o = handleTestOn ["x86_64-linux"] ./cri-o.nix {};
|
||||
deluge = handleTest ./deluge.nix {};
|
||||
dhparams = handleTest ./dhparams.nix {};
|
||||
dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {};
|
||||
@ -78,15 +82,13 @@ in
|
||||
docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
|
||||
oci-containers = handleTestOn ["x86_64-linux"] ./oci-containers.nix {};
|
||||
docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
|
||||
docker-preloader = handleTestOn ["x86_64-linux"] ./docker-preloader.nix {};
|
||||
docker-registry = handleTest ./docker-registry.nix {};
|
||||
docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
|
||||
docker-tools-overlay = handleTestOn ["x86_64-linux"] ./docker-tools-overlay.nix {};
|
||||
documize = handleTest ./documize.nix {};
|
||||
dokuwiki = handleTest ./dokuwiki.nix {};
|
||||
dovecot = handleTest ./dovecot.nix {};
|
||||
# ec2-config doesn't work in a sandbox as the simulated ec2 instance needs network access
|
||||
#ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
|
||||
ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
|
||||
ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
|
||||
ecryptfs = handleTest ./ecryptfs.nix {};
|
||||
ejabberd = handleTest ./xmpp/ejabberd.nix {};
|
||||
@ -296,6 +298,7 @@ in
|
||||
redis = handleTest ./redis.nix {};
|
||||
redmine = handleTest ./redmine.nix {};
|
||||
restic = handleTest ./restic.nix {};
|
||||
robustirc-bridge = handleTest ./robustirc-bridge.nix {};
|
||||
roundcube = handleTest ./roundcube.nix {};
|
||||
rspamd = handleTest ./rspamd.nix {};
|
||||
rss2email = handleTest ./rss2email.nix {};
|
||||
@ -306,6 +309,7 @@ in
|
||||
sanoid = handleTest ./sanoid.nix {};
|
||||
sddm = handleTest ./sddm.nix {};
|
||||
service-runner = handleTest ./service-runner.nix {};
|
||||
shadowsocks = handleTest ./shadowsocks.nix {};
|
||||
shattered-pixel-dungeon = handleTest ./shattered-pixel-dungeon.nix {};
|
||||
shiori = handleTest ./shiori.nix {};
|
||||
signal-desktop = handleTest ./signal-desktop.nix {};
|
||||
@ -320,6 +324,7 @@ in
|
||||
spike = handleTest ./spike.nix {};
|
||||
sonarr = handleTest ./sonarr.nix {};
|
||||
sslh = handleTest ./sslh.nix {};
|
||||
sssd = handleTestOn ["x86_64-linux"] ./sssd.nix {};
|
||||
strongswan-swanctl = handleTest ./strongswan-swanctl.nix {};
|
||||
sudo = handleTest ./sudo.nix {};
|
||||
switchTest = handleTest ./switch-test.nix {};
|
||||
|
188
nixos/tests/bitwarden.nix
Normal file
188
nixos/tests/bitwarden.nix
Normal file
@ -0,0 +1,188 @@
|
||||
{ system ? builtins.currentSystem
|
||||
, config ? { }
|
||||
, pkgs ? import ../.. { inherit system config; }
|
||||
}:
|
||||
|
||||
# These tests will:
|
||||
# * Set up a bitwarden-rs server
|
||||
# * Have Firefox use the web vault to create an account, log in, and save a password to the valut
|
||||
# * Have the bw cli log in and read that password from the vault
|
||||
#
|
||||
# Note that Firefox must be on the same machine as the server for WebCrypto APIs to be available (or HTTPS must be configured)
|
||||
#
|
||||
# The same tests should work without modification on the official bitwarden server, if we ever package that.
|
||||
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
with pkgs.lib;
|
||||
let
|
||||
backends = [ "sqlite" "mysql" "postgresql" ];
|
||||
|
||||
dbPassword = "please_dont_hack";
|
||||
|
||||
userEmail = "meow@example.com";
|
||||
userPassword = "also_super_secret_ZJWpBKZi668QGt"; # Must be complex to avoid interstitial warning on the signup page
|
||||
|
||||
storedPassword = "seeeecret";
|
||||
|
||||
makeBitwardenTest = backend: makeTest {
|
||||
name = "bitwarden_rs-${backend}";
|
||||
meta = {
|
||||
maintainers = with pkgs.stdenv.lib.maintainers; [ jjjollyjim ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
server = { pkgs, ... }:
|
||||
let backendConfig = {
|
||||
mysql = {
|
||||
services.mysql = {
|
||||
enable = true;
|
||||
initialScript = pkgs.writeText "mysql-init.sql" ''
|
||||
CREATE DATABASE bitwarden;
|
||||
CREATE USER 'bitwardenuser'@'localhost' IDENTIFIED BY '${dbPassword}';
|
||||
GRANT ALL ON `bitwarden`.* TO 'bitwardenuser'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
'';
|
||||
package = pkgs.mysql;
|
||||
};
|
||||
|
||||
services.bitwarden_rs.config.databaseUrl = "mysql://bitwardenuser:${dbPassword}@localhost/bitwarden";
|
||||
|
||||
systemd.services.bitwarden_rs.after = [ "mysql.service" ];
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
initialScript = pkgs.writeText "postgresql-init.sql" ''
|
||||
CREATE DATABASE bitwarden;
|
||||
CREATE USER bitwardenuser WITH PASSWORD '${dbPassword}';
|
||||
GRANT ALL PRIVILEGES ON DATABASE bitwarden TO bitwardenuser;
|
||||
'';
|
||||
};
|
||||
|
||||
services.bitwarden_rs.config.databaseUrl = "postgresql://bitwardenuser:${dbPassword}@localhost/bitwarden";
|
||||
|
||||
systemd.services.bitwarden_rs.after = [ "postgresql.service" ];
|
||||
};
|
||||
|
||||
sqlite = { };
|
||||
};
|
||||
in
|
||||
mkMerge [
|
||||
backendConfig.${backend}
|
||||
{
|
||||
services.bitwarden_rs = {
|
||||
enable = true;
|
||||
dbBackend = backend;
|
||||
config.rocketPort = 80;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
|
||||
environment.systemPackages =
|
||||
let
|
||||
testRunner = pkgs.writers.writePython3Bin "test-runner"
|
||||
{
|
||||
libraries = [ pkgs.python3Packages.selenium ];
|
||||
} ''
|
||||
from selenium.webdriver import Firefox
|
||||
from selenium.webdriver.firefox.options import Options
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
options = Options()
|
||||
options.add_argument('--headless')
|
||||
driver = Firefox(options=options)
|
||||
|
||||
driver.implicitly_wait(20)
|
||||
driver.get('http://localhost/#/register')
|
||||
|
||||
wait = WebDriverWait(driver, 10)
|
||||
|
||||
wait.until(EC.title_contains("Create Account"))
|
||||
|
||||
driver.find_element_by_css_selector('input#email').send_keys(
|
||||
'${userEmail}'
|
||||
)
|
||||
driver.find_element_by_css_selector('input#name').send_keys(
|
||||
'A Cat'
|
||||
)
|
||||
driver.find_element_by_css_selector('input#masterPassword').send_keys(
|
||||
'${userPassword}'
|
||||
)
|
||||
driver.find_element_by_css_selector('input#masterPasswordRetype').send_keys(
|
||||
'${userPassword}'
|
||||
)
|
||||
|
||||
driver.find_element_by_xpath("//button[contains(., 'Submit')]").click()
|
||||
|
||||
wait.until_not(EC.title_contains("Create Account"))
|
||||
|
||||
driver.find_element_by_css_selector('input#masterPassword').send_keys(
|
||||
'${userPassword}'
|
||||
)
|
||||
driver.find_element_by_xpath("//button[contains(., 'Log In')]").click()
|
||||
|
||||
wait.until(EC.title_contains("My Vault"))
|
||||
|
||||
driver.find_element_by_xpath("//button[contains(., 'Add Item')]").click()
|
||||
|
||||
driver.find_element_by_css_selector('input#name').send_keys(
|
||||
'secrets'
|
||||
)
|
||||
driver.find_element_by_css_selector('input#loginPassword').send_keys(
|
||||
'${storedPassword}'
|
||||
)
|
||||
|
||||
driver.find_element_by_xpath("//button[contains(., 'Save')]").click()
|
||||
'';
|
||||
in
|
||||
[ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];
|
||||
|
||||
virtualisation.memorySize = 768;
|
||||
}
|
||||
];
|
||||
|
||||
client = { pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.bitwarden-cli ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
server.wait_for_unit("bitwarden_rs.service")
|
||||
server.wait_for_open_port(80)
|
||||
|
||||
with subtest("configure the cli"):
|
||||
client.succeed("bw --nointeraction config server http://server")
|
||||
|
||||
with subtest("can't login to nonexistant account"):
|
||||
client.fail(
|
||||
"bw --nointeraction --raw login ${userEmail} ${userPassword}"
|
||||
)
|
||||
|
||||
with subtest("use the web interface to sign up, log in, and save a password"):
|
||||
server.succeed("PYTHONUNBUFFERED=1 test-runner | systemd-cat -t test-runner")
|
||||
|
||||
with subtest("log in with the cli"):
|
||||
key = client.succeed(
|
||||
"bw --nointeraction --raw login ${userEmail} ${userPassword}"
|
||||
).strip()
|
||||
|
||||
with subtest("sync with the cli"):
|
||||
client.succeed(f"bw --nointeraction --raw --session {key} sync -f")
|
||||
|
||||
with subtest("get the password with the cli"):
|
||||
password = client.succeed(
|
||||
f"bw --nointeraction --raw --session {key} list items | ${pkgs.jq}/bin/jq -r .[].login.password"
|
||||
)
|
||||
assert password.strip() == "${storedPassword}"
|
||||
'';
|
||||
};
|
||||
in
|
||||
builtins.listToAttrs (
|
||||
map
|
||||
(backend: { name = backend; value = makeBitwardenTest backend; })
|
||||
backends
|
||||
)
|
43
nixos/tests/charliecloud.nix
Normal file
43
nixos/tests/charliecloud.nix
Normal file
@ -0,0 +1,43 @@
|
||||
# This test checks charliecloud image construction and run
|
||||
|
||||
import ./make-test-python.nix ({ pkgs, ...} : let
|
||||
|
||||
dockerfile = pkgs.writeText "Dockerfile" ''
|
||||
FROM nix
|
||||
RUN mkdir /home /tmp
|
||||
RUN touch /etc/passwd /etc/group
|
||||
CMD ["true"]
|
||||
'';
|
||||
|
||||
in {
|
||||
name = "charliecloud";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ bzizou ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
host = { ... }: {
|
||||
environment.systemPackages = [ pkgs.charliecloud ];
|
||||
virtualisation.docker.enable = true;
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "docker" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
host.start()
|
||||
host.wait_for_unit("docker.service")
|
||||
host.succeed(
|
||||
'su - alice -c "docker load --input=${pkgs.dockerTools.examples.nix}"'
|
||||
)
|
||||
host.succeed(
|
||||
"cp ${dockerfile} /home/alice/Dockerfile"
|
||||
)
|
||||
host.succeed('su - alice -c "ch-build -t hello ."')
|
||||
host.succeed('su - alice -c "ch-builder2tar hello /var/tmp"')
|
||||
host.succeed('su - alice -c "ch-tar2dir /var/tmp/hello.tar.gz /var/tmp"')
|
||||
host.succeed('su - alice -c "ch-run /var/tmp/hello -- echo Running_From_Container_OK"')
|
||||
'';
|
||||
})
|
@ -59,7 +59,8 @@ pkgs.runCommand "acme-snakeoil-ca" {
|
||||
openssl genrsa -out snakeoil.key 4096
|
||||
openssl req -new -key snakeoil.key -out snakeoil.csr
|
||||
openssl x509 -req -in snakeoil.csr -sha256 -set_serial 666 \
|
||||
-CA ca.pem -CAkey ca.key -out snakeoil.pem -days 36500
|
||||
-CA ca.pem -CAkey ca.key -out snakeoil.pem -days 36500 \
|
||||
-extfile "$OPENSSL_CONF" -extensions req_ext
|
||||
addpem snakeoil.key ${lib.escapeShellArg fqdn} key
|
||||
addpem snakeoil.pem ${lib.escapeShellArg fqdn} cert
|
||||
'') domains}
|
||||
|
@ -2,170 +2,171 @@
|
||||
{
|
||||
ca.key = builtins.toFile "ca.key" ''
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
JUsBXFNz132nP4iIr3UKrPedQZijSi4=
|
||||
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDd1G7OFpXIoHnr
|
||||
rxdw+hiJVDY6nQDDKFt9FBKwlv7x2hCvX7bnyvHaL7H61c+80McGPISrQn3+MjuR
|
||||
Zuqwax49DddNXbGt4WqGlx4LAeI37OgNUUz9foNr2rDDV744vwp14/PD1f3nqpWf
|
||||
Ogzzsh8rxac0mZ5Se9HxOIpI7NRNuHJjj7HWZ4YxeOvi289rmpu0JPcp25njw7h6
|
||||
FNfHu8GGp34Uj6wAxubdRyfViV8z9FMfbglLuA9i1OiSy3NQpq8VwBG+u/0iC7PQ
|
||||
sQjxSragQu25sfATYIrFJQ4ZCvh0nxqKMeyPPBi6dAcMpa2AZAqtqv+CwWdo36Bt
|
||||
S5XiC7rApgYn+yteKQHSbnCiG2W/boSbfg9lRk3w41dESENCADVajLb3Eovvp0tB
|
||||
O/BALudvWjzAPbpXleVNr6ngWtGlsZTC7LXDgBqdW2KlzpZGcz+PW3ATlwip/ZFR
|
||||
t7A15u5dVkWPVoPuQ0w1Tw+g9dxWFTNk3h+2d7K87IxQbcvqxeIDSEVFMrxo0e4C
|
||||
G2udMcelZwARl6iNTAETa2zJW0XtAdGVM+HY1S/kU6U9J3nubDttAkAMABjPwyjL
|
||||
G7hfyWqUHf9yPs49GsftAVvIy8XIeu0shD1BG11/VzvwpUCiRc+btuWi2erZ4ZfP
|
||||
oQ5YoS9gt4S+Ipz7TPGBl+AUk9HO2QIDAQABAoICAGW+aLAXxc2GZUVHQp4r55Md
|
||||
T94kYtQgL4435bafGwH8vchiQzcfazxiweRFqwl0TMS8fzE5xyYPDilLpfsStoTU
|
||||
U1sFzVfuWviuWTY9P+/ctjZdgs2F+GtAm/CMzw+h9/9IdWbuQI3APO4SJxyjJw7h
|
||||
kiZbCzXT2uAjybFXBq07GyQ1JSEszGzmhHLB1OoKuL2wcrj9IyFHhNZhtvLCWCoV
|
||||
qotttjuI/xyg5VFYt5TRzEpPIu5a1pvDAYVK0XI9cXKtbLYp7RlveqMOgAaD+S2a
|
||||
ZQTV60JH9n4j18p+sKR00SxvZ4vuyXzDePRBDUolGIy9MIJdiLueTiuzDmTmclnM
|
||||
8Yy7oliawW2Bn+1gaWpqmgzEUw9bXRSqIp2zGZ7HaQ+5c/MhS002+/i8WQyssfeg
|
||||
9EfI+Vl0D2avTxCECmsfjUxtkhzMYPVNbRPjt0QBEM+s8lDoNsP2zhMO441+TKpe
|
||||
/5KZHIW+Y0US6GMIUs1o1byKfNz8Nj5HjEKO9CMyK6SBMJnCMroPD4H6opqk3lw9
|
||||
4mk04BdN556EzyJDT0a5/VpXG2DUYwFaNwE1ZPMu3Yx6IBoM1xx8mR80vHQCddmF
|
||||
NP+BzkpUiHf0Txyy0YQWECZ/anTt0Bo0XqY5tirIM2dkG0ngNl9tGlw6gVAY1ky8
|
||||
+cr7qKmhhwMWojaX/L+9AoIBAQD/BZAeF3l9I5RBh6ktWA+opzVyd6ejdLpc2Q1z
|
||||
fmSmtUKRsEe51sWaIf6Sez408UaCMT2IQuppPgMnV8xfMM1/og75Cs8aPyAohwKo
|
||||
IbOenXhLfFZiYB4y/Pac3F+FzNKsTT6n+fsE+82UHafY5ZI2FlPb2L0lfyx09zXv
|
||||
fBYhcXgwSx5ymJLJSl8zFaEGn9qi3UB5ss44SaNM0n8SFGUQUk3PR7SFWSWgNxtl
|
||||
CP7LWTsjXYoC/qBMe7b8JieK5aFk1EkkG1EkJvdiMnulMcMJzl+kj6LqVPmVDoZS
|
||||
mMGvgKGJPpFgrbJ5wlA7uOhucGmMpFWP9RCav66DY4GHrLJPAoIBAQDerkZQ03AN
|
||||
i2iJVjtL97TvDjrE8vtNFS/Auh8JyDIW4GGK3Y/ZoMedQpuu3e6NYM9aMjh+QJoA
|
||||
kqhaiZ/tMXjEXJByglpc3a43g2ceWtJg5yLgexGgRtegbA57PRCo35Vhc6WycD1l
|
||||
6FZNxpTkd2BXX/69KWZ6PpSiLYPvdzxP5ZkYqoWRQIa4ee4orHfz/lUXJm1XwmyG
|
||||
mx3hN9Z9m8Q/PGMGfwrorcp4DK53lmmhTZyPh+X5T5/KkVmrw/v5HEEB3JsknStR
|
||||
3DAqp2XZcRHsGQef9R7H+PINJm9nebjCraataaE4gr76znXKT23P80Ce5Lw6OQUW
|
||||
XHhoL16gS+pXAoIBADTuz6ofTz01PFmZsfjSdXWZN1PKGEaqPOB2wP7+9h9QMkAR
|
||||
KeId/Sfv9GotII1Woz70v4Pf983ebEMnSyla9NyQI7F3l+MnxSIEW/3P+PtsTgLF
|
||||
DR0gPERzEzEd4Mnh6LyQz/eHwJ2ZMmOTADrZ8848Ni3EwAXfbrfcdBqAVAufBMZp
|
||||
YSmCF72mLTpqO+EnHvd9GxvnjDxMtJOGgY+cIhoQK0xh4stm5JNrvMjs5A4LOGYv
|
||||
zSyv80/Mwf92X/DJlwVZttDCxsXNPL3qIpX4TTZk2p9KnRMsjh1tRV4xjMpD1cOp
|
||||
8/zwMMJrHcI3sC70MERb+9KEmGy2ap+k8MbbhqsCggEAUAqqocDupR+4Kq2BUPQv
|
||||
6EHgJA0HAZUc/hSotXZtcsWiqiyr2Vkuhzt7BGcnqU/kGJK2tcL42D3fH/QaNUM0
|
||||
Grj+/voWCw1v4uprtYCF4GkUo0X5dvgf570Pk4LGqzz6z/Wm2LX5i9jwtLItsNWs
|
||||
HpwVz97CxCwcdxMPOpNMbZek6TXaHvTnuAWz8pDT6TNBWLnqUcJECjpVii/s/Gdy
|
||||
KhzFp38g57QYdABy8e9x9pYUMY9yvaO+VyzZ46DlwIxEXavzZDzOZnVUJvDW7krz
|
||||
Wz8/+2I7dzvnnYx0POiG3gtXPzwZxFtS1IpD0r2sRjQ0xSiI9BCs4HXKngBw7gN7
|
||||
rwKCAQEAloJOFw4bafVXZVXuQVnLDm0/MNTfqxUzFE6V2WkMVkJqcpKt+ndApM8P
|
||||
MJvojHWw1fmxDzIAwqZ9rXgnwWKydjSZBDYNjhGFUACVywHe5AjC4PPMUdltGptU
|
||||
lY0BjC7qtwkVugr65goQkEzU61y9JgTqKpYsr3D+qXcoiDvWRuqk5Q0WfYJrUlE0
|
||||
APWaqbxmkqUVDRrXXrifiluupk+BCV7cFSnnknSYbd9FZd9DuKaoNBlkp2J9LZE+
|
||||
Ux74Cfro8SHINHmvqL+YLFUPVDWNeuXh5Kl6AaJ7yclCLXLxAIix3/rIf6mJeIGc
|
||||
s9o9Sr49cibZ3CbMjCSNE3AOeVE1/Q==
|
||||
-----END PRIVATE KEY-----
|
||||
'';
|
||||
ca.cert = builtins.toFile "ca.cert" ''
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFDzCCAvegAwIBAgIUTRDYSWJvmlhwIR3pzVrIQfnboLEwDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAwwLU25ha2VvaWwgQ0EwIBcNMjAwMzIyMjI1NjE3WhgPMjEy
|
||||
MDAyMjcyMjU2MTdaMBYxFDASBgNVBAMMC1NuYWtlb2lsIENBMIICIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAg8AMIICCgKCAgEAwp1WRhJ+vHs15Q1hOYI7Aj6rrUeJ8cP8LyGw
|
||||
MQdlZNlnkOhxr7diXa8+anq9iF3e+mLaUHqnfn33rWi7THhU6/l8vcqhKcdgH75h
|
||||
BHC57olm7FBmc7B8Fu/+JD4ABQcvU8CZ/5PPdpUerkGGtEEt/Ql/OZCzGfy2V1Mg
|
||||
pSAWviMU9TqL5hqjDq+JxgEkUD+nf558p+NSp2rf3bacmmuc4H2MAOmFulMXMsLw
|
||||
UqTDlzNP/NgRWRsgC7d50Pn35q7SnLzI7DSwRWrJVfs2DtTzGy20wlvEpiU44c7m
|
||||
qV7QR67r6HtuNd911pb3D9cpWk8dGpcIkFia9VxDlFixBU4Dk3kcolQ8Q7p6c/u6
|
||||
BnMM3HThvJwoHesNGmGhAs9c70txWE0M/jIqphJMerOG49VPdCNJMFCW3lo46xju
|
||||
2PUKuItfRmnw4O3ADJ/XhwojWzaz4+rf4H2lWwq25Jt2VY5Ly00Npm9pb+/rVYou
|
||||
Odtu4jT7jUupcdhVZa/w14kazlX4IT76DsVH186ICYWS1eGZIvsnGxkGucPGDA2A
|
||||
r+HNPHSgOwGrVYTUutHNc4EDY7lhdwb6HEskshlKJ1U+odQ2JSfWAKoKjaXnYDUf
|
||||
ZKadN+EjIQe3Y/ZXgei0TAPnNXxv0/tZQ25APr6KXqbePt9KA3Ak2HxIn5dR8Kjc
|
||||
P21w5tcCAwEAAaNTMFEwHQYDVR0OBBYEFCIoeYSYjtMiPrmxfHmcrsZkyTpvMB8G
|
||||
A1UdIwQYMBaAFCIoeYSYjtMiPrmxfHmcrsZkyTpvMA8GA1UdEwEB/wQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQELBQADggIBAHPdwOgAxyhIhbqFObNftW8K3sptorB/Fj6jwYCm
|
||||
mHleFueqQnjTHMWsflOjREvQp1M307FWooGj+KQkjwvAyDc/Hmy7WgJxBg9p3vc+
|
||||
/Xf/e7ZfBl8rv7vH8VXW/BC1vVsILdFncrgTrP8/4psV50/cl1F4+nPBiekvvxwZ
|
||||
k+R7SgeSvcWT7YlOG8tm1M3al4F4mWzSRkYjkrXmwRCKAiya9xcGSt0Bob+LoM/O
|
||||
mpDGV/PMC1WAoDc1mMuXN2hSc0n68xMcuFs+dj/nQYn8uL5pzOxpX9560ynKyLDv
|
||||
yOzQlM2VuZ7H2hSIeYOFgrtHJJwhDtzjmUNDQpQdp9Fx+LONQTS1VLCTXND2i/3F
|
||||
10X6PkdnLEn09RiPt5qy20pQkICxoEydmlwpFs32musYfJPdBPkZqZWrwINBv2Wb
|
||||
HfOmEB4xUvXufZ5Ju5icgggBkyNA3PCLo0GZFRrMtvA7i9IXOcXNR+njhKa9246V
|
||||
QQfeWiz05RmIvgShJYVsnZWtael8ni366d+UXypBYncohimyNlAD1n+Bh3z0PvBB
|
||||
+FK4JgOSeouM4SuBHdwmlZ/H0mvfUG81Y8Jbrw0yuRHtuCtX5HpN5GKpZPHDE7aQ
|
||||
fEShVB/GElC3n3DvgK9OJBeVVhYQgUEfJi4rsSxt3cdEI0NrdckUoZbApWVJ3CBc
|
||||
F8Y7
|
||||
MIIFDzCCAvegAwIBAgIUX0P6NfX4gRUpFz+TNV/f26GHokgwDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAwwLU25ha2VvaWwgQ0EwIBcNMjAwODI0MDc0MjEyWhgPMjEy
|
||||
MDA3MzEwNzQyMTJaMBYxFDASBgNVBAMMC1NuYWtlb2lsIENBMIICIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAg8AMIICCgKCAgEA3dRuzhaVyKB5668XcPoYiVQ2Op0AwyhbfRQS
|
||||
sJb+8doQr1+258rx2i+x+tXPvNDHBjyEq0J9/jI7kWbqsGsePQ3XTV2xreFqhpce
|
||||
CwHiN+zoDVFM/X6Da9qww1e+OL8KdePzw9X956qVnzoM87IfK8WnNJmeUnvR8TiK
|
||||
SOzUTbhyY4+x1meGMXjr4tvPa5qbtCT3KduZ48O4ehTXx7vBhqd+FI+sAMbm3Ucn
|
||||
1YlfM/RTH24JS7gPYtTokstzUKavFcARvrv9Iguz0LEI8Uq2oELtubHwE2CKxSUO
|
||||
GQr4dJ8aijHsjzwYunQHDKWtgGQKrar/gsFnaN+gbUuV4gu6wKYGJ/srXikB0m5w
|
||||
ohtlv26Em34PZUZN8ONXREhDQgA1Woy29xKL76dLQTvwQC7nb1o8wD26V5XlTa+p
|
||||
4FrRpbGUwuy1w4AanVtipc6WRnM/j1twE5cIqf2RUbewNebuXVZFj1aD7kNMNU8P
|
||||
oPXcVhUzZN4ftneyvOyMUG3L6sXiA0hFRTK8aNHuAhtrnTHHpWcAEZeojUwBE2ts
|
||||
yVtF7QHRlTPh2NUv5FOlPSd57mw7bQJADAAYz8Moyxu4X8lqlB3/cj7OPRrH7QFb
|
||||
yMvFyHrtLIQ9QRtdf1c78KVAokXPm7blotnq2eGXz6EOWKEvYLeEviKc+0zxgZfg
|
||||
FJPRztkCAwEAAaNTMFEwHQYDVR0OBBYEFNhBZxryvykCjfPO85xB3wof2enAMB8G
|
||||
A1UdIwQYMBaAFNhBZxryvykCjfPO85xB3wof2enAMA8GA1UdEwEB/wQFMAMBAf8w
|
||||
DQYJKoZIhvcNAQELBQADggIBAEZwlsQ+3yd1MVxLRy9RjoA8hI7iWBNmvPUyNjlb
|
||||
l/L9N+dZgdx9G5h/KPRUyzvUc/uk/ZxTWVPIOp13WI65qwsBKrwvYKiXiwzjt+9V
|
||||
CKDRc1sOghTSXk4FD3L5UcKvTQ2lRcFsqxbkopEwQWhoCuhe4vFyt3Nx8ZGLCBUD
|
||||
3I5zMHtO8FtpZWKJPw46Yc1kasv0nlfly/vUbnErYfgjWX1hgWUcRgYdKwO4sOZ7
|
||||
KbNma0WUsX5mWhXo4Kk7D15wATHO+j9s+j8m86duBL3A4HzpTo1DhHvBi0dkg0CO
|
||||
XuSdByIzVLIPh3yhCHN1loRCP2rbzKM8IQeU/X5Q4UJeC/x9ew8Kk+RKXoHc8Y2C
|
||||
JQO1DxuidyDJRhbb98wZo2YfIsdWQGjYZBe1XQRwBD28JnB+Rb9shml6lORWQn9y
|
||||
P/STo9uWm5zvOCfqwbnCoetljDweItINx622G9SafBwPZc3o79oL7QSl8DgCtN6g
|
||||
p0wGIlIBx+25w/96PqZcrYb8B7/uBHJviiKjBXDoIJWNiNRhW5HaFjeJdSKq7KIL
|
||||
I/PO9KuHafif36ksG69X02Rio2/cTjgjEW1hGHcDRyyJWWaj7bd2eWuouh6FF22b
|
||||
PA6FGY4vewDPnbLKLaix2ZIKxtedUDOH/qru3Mv58IFXmQ4iyM8oC8aOxYSQLZDn
|
||||
1yJD
|
||||
-----END CERTIFICATE-----
|
||||
'';
|
||||
"acme.test".key = builtins.toFile "acme.test.key" ''
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
'';
|
||||
"acme.test".cert = builtins.toFile "acme.test.cert" ''
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
NbjvWnP8lDU8j2l3eSG58S14iGs=
|
||||
-----END CERTIFICATE-----
|
||||
'';
|
||||
}
|
||||
|
@ -20,30 +20,44 @@ with pkgs.lib;
|
||||
in makeTest {
|
||||
name = "ec2-" + name;
|
||||
nodes = {};
|
||||
testScript =
|
||||
''
|
||||
my $imageDir = ($ENV{'TMPDIR'} // "/tmp") . "/vm-state-machine";
|
||||
mkdir $imageDir, 0700;
|
||||
my $diskImage = "$imageDir/machine.qcow2";
|
||||
system("qemu-img create -f qcow2 -o backing_file=${image} $diskImage") == 0 or die;
|
||||
system("qemu-img resize $diskImage 10G") == 0 or die;
|
||||
testScript = ''
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
# Note: we use net=169.0.0.0/8 rather than
|
||||
# net=169.254.0.0/16 to prevent dhcpcd from getting horribly
|
||||
# confused. (It would get a DHCP lease in the 169.254.*
|
||||
# range, which it would then configure and prompty delete
|
||||
# again when it deletes link-local addresses.) Ideally we'd
|
||||
# turn off the DHCP server, but qemu does not have an option
|
||||
# to do that.
|
||||
my $startCommand = "qemu-kvm -m 1024";
|
||||
$startCommand .= " -device virtio-net-pci,netdev=vlan0";
|
||||
$startCommand .= " -netdev 'user,id=vlan0,net=169.0.0.0/8,guestfwd=tcp:169.254.169.254:80-cmd:${pkgs.micro-httpd}/bin/micro_httpd ${metaData}'";
|
||||
$startCommand .= " -drive file=$diskImage,if=virtio,werror=report";
|
||||
$startCommand .= " \$QEMU_OPTS";
|
||||
image_dir = os.path.join(
|
||||
os.environ.get("TMPDIR", tempfile.gettempdir()), "tmp", "vm-state-machine"
|
||||
)
|
||||
os.makedirs(image_dir, mode=0o700, exist_ok=True)
|
||||
disk_image = os.path.join(image_dir, "machine.qcow2")
|
||||
subprocess.check_call(
|
||||
[
|
||||
"qemu-img",
|
||||
"create",
|
||||
"-f",
|
||||
"qcow2",
|
||||
"-o",
|
||||
"backing_file=${image}",
|
||||
disk_image,
|
||||
]
|
||||
)
|
||||
subprocess.check_call(["qemu-img", "resize", disk_image, "10G"])
|
||||
|
||||
my $machine = createMachine({ startCommand => $startCommand });
|
||||
# Note: we use net=169.0.0.0/8 rather than
|
||||
# net=169.254.0.0/16 to prevent dhcpcd from getting horribly
|
||||
# confused. (It would get a DHCP lease in the 169.254.*
|
||||
# range, which it would then configure and prompty delete
|
||||
# again when it deletes link-local addresses.) Ideally we'd
|
||||
# turn off the DHCP server, but qemu does not have an option
|
||||
# to do that.
|
||||
start_command = (
|
||||
"qemu-kvm -m 1024"
|
||||
+ " -device virtio-net-pci,netdev=vlan0"
|
||||
+ " -netdev 'user,id=vlan0,net=169.0.0.0/8,guestfwd=tcp:169.254.169.254:80-cmd:${pkgs.micro-httpd}/bin/micro_httpd ${metaData}'"
|
||||
+ f" -drive file={disk_image},if=virtio,werror=report"
|
||||
+ " $QEMU_OPTS"
|
||||
)
|
||||
|
||||
${script}
|
||||
'';
|
||||
machine = create_machine({"startCommand": start_command})
|
||||
'' + script;
|
||||
};
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
# prevent make-test.nix to change IP
|
||||
# prevent make-test-python.nix to change IP
|
||||
networking.interfaces = {
|
||||
eth1.ipv4.addresses = lib.mkOverride 0 [ ];
|
||||
};
|
||||
};
|
||||
in {
|
||||
name = "cotnainers-reloadable";
|
||||
name = "containers-reloadable";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ danbst ];
|
||||
};
|
||||
|
19
nixos/tests/cri-o.nix
Normal file
19
nixos/tests/cri-o.nix
Normal file
@ -0,0 +1,19 @@
|
||||
# This test runs CRI-O and verifies via critest
|
||||
import ./make-test-python.nix ({ pkgs, ... }: {
|
||||
name = "cri-o";
|
||||
maintainers = with pkgs.stdenv.lib.maintainers; teams.podman.members;
|
||||
|
||||
nodes = {
|
||||
crio = {
|
||||
virtualisation.cri-o.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
crio.wait_for_unit("crio.service")
|
||||
crio.succeed(
|
||||
"critest --ginkgo.focus='Runtime info' --runtime-endpoint unix:///var/run/crio/crio.sock"
|
||||
)
|
||||
'';
|
||||
})
|
@ -1,27 +0,0 @@
|
||||
import ./make-test.nix ({ pkgs, ...} : {
|
||||
name = "docker-preloader";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ lewo ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
docker =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
virtualisation.docker.enable = true;
|
||||
virtualisation.dockerPreloader.images = [ pkgs.dockerTools.examples.nix pkgs.dockerTools.examples.bash ];
|
||||
|
||||
services.openssh.enable = true;
|
||||
services.openssh.permitRootLogin = "yes";
|
||||
services.openssh.extraConfig = "PermitEmptyPasswords yes";
|
||||
users.extraUsers.root.password = "";
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
startAll;
|
||||
|
||||
$docker->waitForUnit("sockets.target");
|
||||
$docker->succeed("docker run nix nix-store --version");
|
||||
$docker->succeed("docker run bash bash --version");
|
||||
'';
|
||||
})
|
@ -3,58 +3,58 @@
|
||||
pkgs ? import ../.. { inherit system config; }
|
||||
}:
|
||||
|
||||
with import ../lib/testing.nix { inherit system pkgs; };
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
with pkgs.lib;
|
||||
|
||||
with import common/ec2.nix { inherit makeTest pkgs; };
|
||||
|
||||
let
|
||||
imageCfg =
|
||||
(import ../lib/eval-config.nix {
|
||||
inherit system;
|
||||
modules = [
|
||||
../maintainers/scripts/ec2/amazon-image.nix
|
||||
../modules/testing/test-instrumentation.nix
|
||||
../modules/profiles/qemu-guest.nix
|
||||
{ ec2.hvm = true;
|
||||
imageCfg = (import ../lib/eval-config.nix {
|
||||
inherit system;
|
||||
modules = [
|
||||
../maintainers/scripts/ec2/amazon-image.nix
|
||||
../modules/testing/test-instrumentation.nix
|
||||
../modules/profiles/qemu-guest.nix
|
||||
{
|
||||
ec2.hvm = true;
|
||||
|
||||
# Hack to make the partition resizing work in QEMU.
|
||||
boot.initrd.postDeviceCommands = mkBefore
|
||||
''
|
||||
ln -s vda /dev/xvda
|
||||
ln -s vda1 /dev/xvda1
|
||||
'';
|
||||
# Hack to make the partition resizing work in QEMU.
|
||||
boot.initrd.postDeviceCommands = mkBefore ''
|
||||
ln -s vda /dev/xvda
|
||||
ln -s vda1 /dev/xvda1
|
||||
'';
|
||||
|
||||
# Needed by nixos-rebuild due to the lack of network
|
||||
# access. Determined by trial and error.
|
||||
system.extraDependencies =
|
||||
with pkgs; (
|
||||
[
|
||||
# Needed for a nixos-rebuild.
|
||||
busybox
|
||||
stdenv
|
||||
stdenvNoCC
|
||||
mkinitcpio-nfs-utils
|
||||
unionfs-fuse
|
||||
cloud-utils
|
||||
desktop-file-utils
|
||||
texinfo
|
||||
libxslt.bin
|
||||
xorg.lndir
|
||||
# Needed by nixos-rebuild due to the lack of network
|
||||
# access. Determined by trial and error.
|
||||
system.extraDependencies = with pkgs; ( [
|
||||
# Needed for a nixos-rebuild.
|
||||
busybox
|
||||
cloud-utils
|
||||
desktop-file-utils
|
||||
libxslt.bin
|
||||
mkinitcpio-nfs-utils
|
||||
stdenv
|
||||
stdenvNoCC
|
||||
texinfo
|
||||
unionfs-fuse
|
||||
xorg.lndir
|
||||
|
||||
# These are used in the configure-from-userdata tests
|
||||
# for EC2. Httpd and valgrind are requested by the
|
||||
# configuration.
|
||||
apacheHttpd apacheHttpd.doc apacheHttpd.man valgrind.doc
|
||||
]
|
||||
);
|
||||
}
|
||||
];
|
||||
}).config;
|
||||
# These are used in the configure-from-userdata tests
|
||||
# for EC2. Httpd and valgrind are requested by the
|
||||
# configuration.
|
||||
apacheHttpd
|
||||
apacheHttpd.doc
|
||||
apacheHttpd.man
|
||||
valgrind.doc
|
||||
]);
|
||||
}
|
||||
];
|
||||
}).config;
|
||||
image = "${imageCfg.system.build.amazonImage}/${imageCfg.amazonImage.name}.vhd";
|
||||
|
||||
sshKeys = import ./ssh-keys.nix pkgs;
|
||||
snakeOilPrivateKey = sshKeys.snakeOilPrivateKey.text;
|
||||
snakeOilPrivateKeyFile = pkgs.writeText "private-key" snakeOilPrivateKey;
|
||||
snakeOilPublicKey = sshKeys.snakeOilPublicKey;
|
||||
|
||||
in {
|
||||
@ -68,43 +68,47 @@ in {
|
||||
SSH_HOST_ED25519_KEY:${replaceStrings ["\n"] ["|"] snakeOilPrivateKey}
|
||||
'';
|
||||
script = ''
|
||||
$machine->start;
|
||||
$machine->waitForFile("/etc/ec2-metadata/user-data");
|
||||
$machine->waitForUnit("sshd.service");
|
||||
machine.start()
|
||||
machine.wait_for_file("/etc/ec2-metadata/user-data")
|
||||
machine.wait_for_unit("sshd.service")
|
||||
|
||||
$machine->succeed("grep unknown /etc/ec2-metadata/ami-manifest-path");
|
||||
machine.succeed("grep unknown /etc/ec2-metadata/ami-manifest-path")
|
||||
|
||||
# We have no keys configured on the client side yet, so this should fail
|
||||
$machine->fail("ssh -o BatchMode=yes localhost exit");
|
||||
machine.fail("ssh -o BatchMode=yes localhost exit")
|
||||
|
||||
# Let's install our client private key
|
||||
$machine->succeed("mkdir -p ~/.ssh");
|
||||
machine.succeed("mkdir -p ~/.ssh")
|
||||
|
||||
$machine->succeed("echo '${snakeOilPrivateKey}' > ~/.ssh/id_ed25519");
|
||||
$machine->succeed("chmod 600 ~/.ssh/id_ed25519");
|
||||
machine.copy_from_host_via_shell(
|
||||
"${snakeOilPrivateKeyFile}", "~/.ssh/id_ed25519"
|
||||
)
|
||||
machine.succeed("chmod 600 ~/.ssh/id_ed25519")
|
||||
|
||||
# We haven't configured the host key yet, so this should still fail
|
||||
$machine->fail("ssh -o BatchMode=yes localhost exit");
|
||||
machine.fail("ssh -o BatchMode=yes localhost exit")
|
||||
|
||||
# Add the host key; ssh should finally succeed
|
||||
$machine->succeed("echo localhost,127.0.0.1 ${snakeOilPublicKey} > ~/.ssh/known_hosts");
|
||||
$machine->succeed("ssh -o BatchMode=yes localhost exit");
|
||||
machine.succeed(
|
||||
"echo localhost,127.0.0.1 ${snakeOilPublicKey} > ~/.ssh/known_hosts"
|
||||
)
|
||||
machine.succeed("ssh -o BatchMode=yes localhost exit")
|
||||
|
||||
# Test whether the root disk was resized.
|
||||
my $blocks = $machine->succeed("stat -c %b -f /");
|
||||
my $bsize = $machine->succeed("stat -c %S -f /");
|
||||
my $size = $blocks * $bsize;
|
||||
die "wrong free space $size" if $size < 9.7 * 1024 * 1024 * 1024 || $size > 10 * 1024 * 1024 * 1024;
|
||||
blocks, block_size = map(int, machine.succeed("stat -c %b:%S -f /").split(":"))
|
||||
GB = 1024 ** 3
|
||||
assert 9.7 * GB <= blocks * block_size <= 10 * GB
|
||||
|
||||
# Just to make sure resizing is idempotent.
|
||||
$machine->shutdown;
|
||||
$machine->start;
|
||||
$machine->waitForFile("/etc/ec2-metadata/user-data");
|
||||
machine.shutdown()
|
||||
machine.start()
|
||||
machine.wait_for_file("/etc/ec2-metadata/user-data")
|
||||
'';
|
||||
};
|
||||
|
||||
boot-ec2-config = makeEc2Test {
|
||||
name = "config-userdata";
|
||||
meta.broken = true; # amazon-init wants to download from the internet while building the system
|
||||
inherit image;
|
||||
sshPublicKey = snakeOilPublicKey;
|
||||
|
||||
@ -133,17 +137,17 @@ in {
|
||||
}
|
||||
'';
|
||||
script = ''
|
||||
$machine->start;
|
||||
machine.start()
|
||||
|
||||
# amazon-init must succeed. if it fails, make the test fail
|
||||
# immediately instead of timing out in waitForFile.
|
||||
$machine->waitForUnit('amazon-init.service');
|
||||
# immediately instead of timing out in wait_for_file.
|
||||
machine.wait_for_unit("amazon-init.service")
|
||||
|
||||
$machine->waitForFile("/etc/testFile");
|
||||
$machine->succeed("cat /etc/testFile | grep -q 'whoa'");
|
||||
machine.wait_for_file("/etc/testFile")
|
||||
assert "whoa" in machine.succeed("cat /etc/testFile")
|
||||
|
||||
$machine->waitForUnit("httpd.service");
|
||||
$machine->succeed("curl http://localhost | grep Valgrind");
|
||||
machine.wait_for_unit("httpd.service")
|
||||
assert "Valgrind" in machine.succeed("curl http://localhost")
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@ -23,6 +23,13 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
|
||||
services.xserver.desktopManager.gnome3.enable = true;
|
||||
services.xserver.desktopManager.gnome3.debug = true;
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.makeAutostartItem {
|
||||
name = "org.gnome.Terminal";
|
||||
package = pkgs.gnome3.gnome-terminal;
|
||||
})
|
||||
];
|
||||
|
||||
virtualisation.memorySize = 1024;
|
||||
};
|
||||
|
||||
@ -65,9 +72,6 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
|
||||
)
|
||||
|
||||
with subtest("Open Gnome Terminal"):
|
||||
machine.succeed(
|
||||
"${gnomeTerminalCommand}"
|
||||
)
|
||||
# correct output should be (true, '"gnome-terminal-server"')
|
||||
machine.wait_until_succeeds(
|
||||
"${wmClass} | grep -q 'gnome-terminal-server'"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import ./make-test.nix ({ pkgs, latestKernel ? false, ... } : {
|
||||
import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... } : {
|
||||
name = "hardened";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ joachifm ];
|
||||
@ -47,84 +47,88 @@ import ./make-test.nix ({ pkgs, latestKernel ? false, ... } : {
|
||||
};
|
||||
in
|
||||
''
|
||||
$machine->waitForUnit("multi-user.target");
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
|
||||
with subtest("AppArmor profiles are loaded"):
|
||||
machine.succeed("systemctl status apparmor.service")
|
||||
|
||||
subtest "apparmor-loaded", sub {
|
||||
$machine->succeed("systemctl status apparmor.service");
|
||||
};
|
||||
|
||||
# AppArmor securityfs
|
||||
subtest "apparmor-securityfs", sub {
|
||||
$machine->succeed("mountpoint -q /sys/kernel/security");
|
||||
$machine->succeed("cat /sys/kernel/security/apparmor/profiles");
|
||||
};
|
||||
with subtest("AppArmor securityfs is mounted"):
|
||||
machine.succeed("mountpoint -q /sys/kernel/security")
|
||||
machine.succeed("cat /sys/kernel/security/apparmor/profiles")
|
||||
|
||||
|
||||
# Test loading out-of-tree modules
|
||||
subtest "extra-module-packages", sub {
|
||||
$machine->succeed("grep -Fq wireguard /proc/modules");
|
||||
};
|
||||
with subtest("Out-of-tree modules can be loaded"):
|
||||
machine.succeed("grep -Fq wireguard /proc/modules")
|
||||
|
||||
|
||||
# Test hidepid
|
||||
subtest "hidepid", sub {
|
||||
$machine->succeed("grep -Fq hidepid=2 /proc/mounts");
|
||||
with subtest("hidepid=2 option is applied and works"):
|
||||
machine.succeed("grep -Fq hidepid=2 /proc/mounts")
|
||||
# cannot use pgrep -u here, it segfaults when access to process info is denied
|
||||
$machine->succeed("[ `su - sybil -c 'ps --no-headers --user root | wc -l'` = 0 ]");
|
||||
$machine->succeed("[ `su - alice -c 'ps --no-headers --user root | wc -l'` != 0 ]");
|
||||
};
|
||||
machine.succeed("[ `su - sybil -c 'ps --no-headers --user root | wc -l'` = 0 ]")
|
||||
machine.succeed("[ `su - alice -c 'ps --no-headers --user root | wc -l'` != 0 ]")
|
||||
|
||||
|
||||
# Test kernel module hardening
|
||||
subtest "lock-modules", sub {
|
||||
with subtest("No more kernel modules can be loaded"):
|
||||
# note: this better a be module we normally wouldn't load ...
|
||||
$machine->fail("modprobe dccp");
|
||||
};
|
||||
machine.fail("modprobe dccp")
|
||||
|
||||
|
||||
# Test userns
|
||||
subtest "userns", sub {
|
||||
$machine->succeed("unshare --user true");
|
||||
$machine->fail("su -l alice -c 'unshare --user true'");
|
||||
};
|
||||
with subtest("User namespaces are restricted"):
|
||||
machine.succeed("unshare --user true")
|
||||
machine.fail("su -l alice -c 'unshare --user true'")
|
||||
|
||||
|
||||
# Test dmesg restriction
|
||||
subtest "dmesg", sub {
|
||||
$machine->fail("su -l alice -c dmesg");
|
||||
};
|
||||
with subtest("Regular users cannot access dmesg"):
|
||||
machine.fail("su -l alice -c dmesg")
|
||||
|
||||
|
||||
# Test access to kcore
|
||||
subtest "kcore", sub {
|
||||
$machine->fail("cat /proc/kcore");
|
||||
};
|
||||
with subtest("Kcore is inaccessible as root"):
|
||||
machine.fail("cat /proc/kcore")
|
||||
|
||||
|
||||
# Test deferred mount
|
||||
subtest "mount", sub {
|
||||
$machine->fail("mountpoint -q /efi"); # was deferred
|
||||
$machine->execute("mkdir -p /efi");
|
||||
$machine->succeed("mount /dev/disk/by-label/EFISYS /efi");
|
||||
$machine->succeed("mountpoint -q /efi"); # now mounted
|
||||
};
|
||||
with subtest("Deferred mounts work"):
|
||||
machine.fail("mountpoint -q /efi") # was deferred
|
||||
machine.execute("mkdir -p /efi")
|
||||
machine.succeed("mount /dev/disk/by-label/EFISYS /efi")
|
||||
machine.succeed("mountpoint -q /efi") # now mounted
|
||||
|
||||
|
||||
# Test Nix dæmon usage
|
||||
subtest "nix-daemon", sub {
|
||||
$machine->fail("su -l nobody -s /bin/sh -c 'nix ping-store'");
|
||||
$machine->succeed("su -l alice -c 'nix ping-store'") =~ "OK";
|
||||
};
|
||||
with subtest("nix-daemon cannot be used by all users"):
|
||||
machine.fail("su -l nobody -s /bin/sh -c 'nix ping-store'")
|
||||
machine.succeed("su -l alice -c 'nix ping-store'")
|
||||
|
||||
|
||||
# Test kernel image protection
|
||||
subtest "kernelimage", sub {
|
||||
$machine->fail("systemctl hibernate");
|
||||
$machine->fail("systemctl kexec");
|
||||
};
|
||||
with subtest("The kernel image is protected"):
|
||||
machine.fail("systemctl hibernate")
|
||||
machine.fail("systemctl kexec")
|
||||
|
||||
|
||||
# Test hardened memory allocator
|
||||
sub runMallocTestProg {
|
||||
my ($progName, $errorText) = @_;
|
||||
my $text = "fatal allocator error: " . $errorText;
|
||||
$machine->fail("${hardened-malloc-tests}/bin/" . $progName) =~ $text;
|
||||
};
|
||||
def runMallocTestProg(prog_name, error_text):
|
||||
text = "fatal allocator error: " + error_text
|
||||
if not text in machine.fail(
|
||||
"${hardened-malloc-tests}/bin/"
|
||||
+ prog_name
|
||||
+ " 2>&1"
|
||||
):
|
||||
raise Exception("Hardened malloc does not work for {}".format(error_text))
|
||||
|
||||
subtest "hardenedmalloc", sub {
|
||||
runMallocTestProg("double_free_large", "invalid free");
|
||||
runMallocTestProg("unaligned_free_small", "invalid unaligned free");
|
||||
runMallocTestProg("write_after_free_small", "detected write after free");
|
||||
};
|
||||
|
||||
with subtest("The hardened memory allocator works"):
|
||||
runMallocTestProg("double_free_large", "invalid free")
|
||||
runMallocTestProg("unaligned_free_small", "invalid unaligned free")
|
||||
runMallocTestProg("write_after_free_small", "detected write after free")
|
||||
'';
|
||||
})
|
||||
|
@ -1,15 +1,16 @@
|
||||
import ../make-test.nix ({ pkgs, ...} : {
|
||||
import ../make-test-python.nix ({ pkgs, ...} : {
|
||||
name = "test-hocker-fetchdocker";
|
||||
meta = with pkgs.stdenv.lib.maintainers; {
|
||||
maintainers = [ ixmatus ];
|
||||
broken = true; # tries to download from registry-1.docker.io - how did this ever work?
|
||||
};
|
||||
|
||||
machine = import ./machine.nix;
|
||||
|
||||
testScript = ''
|
||||
startAll;
|
||||
start_all()
|
||||
|
||||
$machine->waitForUnit("sockets.target");
|
||||
$machine->waitUntilSucceeds("docker run registry-1.docker.io/v2/library/hello-world:latest");
|
||||
machine.wait_for_unit("sockets.target")
|
||||
machine.wait_until_succeeds("docker run registry-1.docker.io/v2/library/hello-world:latest")
|
||||
'';
|
||||
})
|
||||
|
@ -74,7 +74,7 @@ let
|
||||
throw "Non-EFI boot methods are only supported on i686 / x86_64"
|
||||
else ''
|
||||
def assemble_qemu_flags():
|
||||
flags = "-cpu host"
|
||||
flags = "-cpu max"
|
||||
${if system == "x86_64-linux"
|
||||
then ''flags += " -m 768"''
|
||||
else ''flags += " -m 512 -enable-kvm -machine virt,gic-version=host"''
|
||||
@ -317,6 +317,7 @@ let
|
||||
texinfo
|
||||
unionfs-fuse
|
||||
xorg.lndir
|
||||
(lvm2.override { udev = null; }) # for initrd (extra-utils)
|
||||
|
||||
# add curl so that rather than seeing the test attempt to download
|
||||
# curl's tarball, we see what it's trying to download
|
||||
@ -799,7 +800,7 @@ in {
|
||||
"btrfs subvol create /mnt/badpath/boot",
|
||||
"btrfs subvol create /mnt/nixos",
|
||||
"btrfs subvol set-default "
|
||||
+ "$(btrfs subvol list /mnt | grep 'nixos' | awk '{print \$2}') /mnt",
|
||||
+ "$(btrfs subvol list /mnt | grep 'nixos' | awk '{print $2}') /mnt",
|
||||
"umount /mnt",
|
||||
"mount -o defaults LABEL=root /mnt",
|
||||
"mkdir -p /mnt/badpath/boot", # Help ensure the detection mechanism
|
||||
|
@ -1,9 +0,0 @@
|
||||
f: {
|
||||
system ? builtins.currentSystem,
|
||||
pkgs ? import ../.. { inherit system; config = {}; },
|
||||
...
|
||||
} @ args:
|
||||
|
||||
with import ../lib/testing.nix { inherit system pkgs; };
|
||||
|
||||
makeTest (if pkgs.lib.isFunction f then f (args // { inherit pkgs; inherit (pkgs) lib; }) else f)
|
@ -3,30 +3,30 @@
|
||||
pkgs ? import ../.. { inherit system config; }
|
||||
}:
|
||||
|
||||
with import ../lib/testing.nix { inherit system pkgs; };
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
with pkgs.lib;
|
||||
|
||||
with import common/ec2.nix { inherit makeTest pkgs; };
|
||||
|
||||
let
|
||||
image =
|
||||
(import ../lib/eval-config.nix {
|
||||
inherit system;
|
||||
modules = [
|
||||
../maintainers/scripts/openstack/openstack-image.nix
|
||||
../modules/testing/test-instrumentation.nix
|
||||
../modules/profiles/qemu-guest.nix
|
||||
{
|
||||
# Needed by nixos-rebuild due to lack of network access.
|
||||
system.extraDependencies = with pkgs; [
|
||||
stdenv
|
||||
];
|
||||
}
|
||||
];
|
||||
}).config.system.build.openstackImage + "/nixos.qcow2";
|
||||
image = (import ../lib/eval-config.nix {
|
||||
inherit system;
|
||||
modules = [
|
||||
../maintainers/scripts/openstack/openstack-image.nix
|
||||
../modules/testing/test-instrumentation.nix
|
||||
../modules/profiles/qemu-guest.nix
|
||||
{
|
||||
# Needed by nixos-rebuild due to lack of network access.
|
||||
system.extraDependencies = with pkgs; [
|
||||
stdenv
|
||||
];
|
||||
}
|
||||
];
|
||||
}).config.system.build.openstackImage + "/nixos.qcow2";
|
||||
|
||||
sshKeys = import ./ssh-keys.nix pkgs;
|
||||
snakeOilPrivateKey = sshKeys.snakeOilPrivateKey.text;
|
||||
snakeOilPrivateKeyFile = pkgs.writeText "private-key" snakeOilPrivateKey;
|
||||
snakeOilPublicKey = sshKeys.snakeOilPublicKey;
|
||||
|
||||
in {
|
||||
@ -39,32 +39,36 @@ in {
|
||||
SSH_HOST_ED25519_KEY:${replaceStrings ["\n"] ["|"] snakeOilPrivateKey}
|
||||
'';
|
||||
script = ''
|
||||
$machine->start;
|
||||
$machine->waitForFile("/etc/ec2-metadata/user-data");
|
||||
$machine->waitForUnit("sshd.service");
|
||||
machine.start()
|
||||
machine.wait_for_file("/etc/ec2-metadata/user-data")
|
||||
machine.wait_for_unit("sshd.service")
|
||||
|
||||
$machine->succeed("grep unknown /etc/ec2-metadata/ami-manifest-path");
|
||||
machine.succeed("grep unknown /etc/ec2-metadata/ami-manifest-path")
|
||||
|
||||
# We have no keys configured on the client side yet, so this should fail
|
||||
$machine->fail("ssh -o BatchMode=yes localhost exit");
|
||||
machine.fail("ssh -o BatchMode=yes localhost exit")
|
||||
|
||||
# Let's install our client private key
|
||||
$machine->succeed("mkdir -p ~/.ssh");
|
||||
machine.succeed("mkdir -p ~/.ssh")
|
||||
|
||||
$machine->succeed("echo '${snakeOilPrivateKey}' > ~/.ssh/id_ed25519");
|
||||
$machine->succeed("chmod 600 ~/.ssh/id_ed25519");
|
||||
machine.copy_from_host_via_shell(
|
||||
"${snakeOilPrivateKeyFile}", "~/.ssh/id_ed25519"
|
||||
)
|
||||
machine.succeed("chmod 600 ~/.ssh/id_ed25519")
|
||||
|
||||
# We haven't configured the host key yet, so this should still fail
|
||||
$machine->fail("ssh -o BatchMode=yes localhost exit");
|
||||
machine.fail("ssh -o BatchMode=yes localhost exit")
|
||||
|
||||
# Add the host key; ssh should finally succeed
|
||||
$machine->succeed("echo localhost,127.0.0.1 ${snakeOilPublicKey} > ~/.ssh/known_hosts");
|
||||
$machine->succeed("ssh -o BatchMode=yes localhost exit");
|
||||
machine.succeed(
|
||||
"echo localhost,127.0.0.1 ${snakeOilPublicKey} > ~/.ssh/known_hosts"
|
||||
)
|
||||
machine.succeed("ssh -o BatchMode=yes localhost exit")
|
||||
|
||||
# Just to make sure resizing is idempotent.
|
||||
$machine->shutdown;
|
||||
$machine->start;
|
||||
$machine->waitForFile("/etc/ec2-metadata/user-data");
|
||||
machine.shutdown()
|
||||
machine.start()
|
||||
machine.wait_for_file("/etc/ec2-metadata/user-data")
|
||||
'';
|
||||
};
|
||||
|
||||
@ -86,9 +90,9 @@ in {
|
||||
}
|
||||
'';
|
||||
script = ''
|
||||
$machine->start;
|
||||
$machine->waitForFile("/etc/testFile");
|
||||
$machine->succeed("cat /etc/testFile | grep -q 'whoa'");
|
||||
machine.start()
|
||||
machine.wait_for_file("/etc/testFile")
|
||||
assert "whoa" in machine.succeed("cat /etc/testFile")
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user