Merge commit a2a66180ba into haskell-updates
This commit is contained in:
@@ -102,6 +102,7 @@ body:
|
||||
Please mention the people who are in the **Maintainers** list of the offending package. This is done by by searching for the package on the [NixOS Package Search](https://search.nixos.org/packages) and mentioning the people listed under **Maintainers** by prefixing their GitHub usernames with an '@' character. Please add the mentions above the `---` characters in the template below.
|
||||
value: |
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Note for maintainers:** Please tag this issue in your pull request description. (i.e. `Resolves #ISSUE`.)
|
||||
|
||||
@@ -116,6 +116,7 @@ body:
|
||||
If this issue is related to the Darwin packaging architecture as a whole, or is related to the core Darwin frameworks, consider mentioning the `@NixOS/darwin-core` team.
|
||||
value: |
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Note for maintainers:** Please tag this issue in your pull request description. (i.e. `Resolves #ISSUE`.)
|
||||
|
||||
@@ -106,6 +106,7 @@ body:
|
||||
If in doubt, check `git blame` for whoever last touched the module, or check the associated package's maintainers. Please add the mentions above the `---` characters.
|
||||
value: |
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Note for maintainers:** Please tag this issue in your pull request description. (i.e. `Resolves #ISSUE`.)
|
||||
|
||||
@@ -109,6 +109,7 @@ body:
|
||||
Please mention the people who are in the **Maintainers** list of the offending package. This is done by by searching for the package on the [NixOS Package Search](https://search.nixos.org/packages) and mentioning the people listed under **Maintainers** by prefixing their GitHub usernames with an '@' character. Please add the mentions above the `---` characters in the template below.
|
||||
value: |
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Note for maintainers:** Please tag this issue in your pull request description. (i.e. `Resolves #ISSUE`.)
|
||||
|
||||
@@ -48,6 +48,7 @@ body:
|
||||
Please mention the people who are in the **Maintainers** list of the offending package. This is done by by searching for the package on the [NixOS Package Search](https://search.nixos.org/packages) and mentioning the people listed under **Maintainers** by prefixing their GitHub usernames with an '@' character. Please add the mentions above the `---` characters in the template below.
|
||||
value: |
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Note for maintainers:** Please tag this issue in your pull request description. (i.e. `Resolves #ISSUE`.)
|
||||
|
||||
@@ -121,6 +121,7 @@ body:
|
||||
Please mention the people who are in the **Maintainers** list of the offending package. This is done by by searching for the package on the [NixOS Package Search](https://search.nixos.org/packages) and mentioning the people listed under **Maintainers** by prefixing their GitHub usernames with an '@' character. Please add the mentions above the `---` characters in the template below.
|
||||
value: |
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Note for maintainers:** Please tag this issue in your pull request description. (i.e. `Resolves #ISSUE`.)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"rev": "5757bbb8bd7c0630a0cc4bb19c47e588db30b97c",
|
||||
"sha256": "0px0lr7ad2zrws400507c9w5nnaffz9mp9hqssm64icdm6f6h0fz"
|
||||
"rev": "573c650e8a14b2faa0041645ab18aed7e60f0c9a",
|
||||
"sha256": "0qg99zj0gb0pc6sjlkmwhk1c1xz14qxmk6gamgfmcxpsfdp5vn72"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ The NixOS desktop or other non-headless configurations are the primary target fo
|
||||
|
||||
## Nix on GNU/Linux {#nix-on-gnulinux}
|
||||
|
||||
If you are using a non-NixOS GNU/Linux/X11 desktop with free software video drivers, consider launching OpenGL-dependent programs from Nixpkgs with Nixpkgs versions of `libglvnd` and `mesa.drivers` in `LD_LIBRARY_PATH`. For Mesa drivers, the Linux kernel version doesn't have to match nixpkgs.
|
||||
If you are using a non-NixOS GNU/Linux/X11 desktop with free software video drivers, consider launching OpenGL-dependent programs from Nixpkgs with Nixpkgs versions of `libglvnd` and `mesa` in `LD_LIBRARY_PATH`. For Mesa drivers, the Linux kernel version doesn't have to match nixpkgs.
|
||||
|
||||
For proprietary video drivers, you might have luck with also adding the corresponding video driver package.
|
||||
|
||||
@@ -220,6 +220,11 @@ lib.mapAttrs mkLicense ({
|
||||
fullName = "Lawrence Berkeley National Labs BSD variant license";
|
||||
};
|
||||
|
||||
bsdAxisNoDisclaimerUnmodified = {
|
||||
fullName = "BSD-Axis without Warranty Disclaimer with Unmodified requirement";
|
||||
url = "https://scancode-licensedb.aboutcode.org/bsd-no-disclaimer-unmodified.html";
|
||||
};
|
||||
|
||||
bsdOriginal = {
|
||||
spdxId = "BSD-4-Clause";
|
||||
fullName = ''BSD 4-clause "Original" or "Old" License'';
|
||||
|
||||
@@ -2235,6 +2235,13 @@
|
||||
name = "tali auster";
|
||||
matrix = "@atalii:matrix.org";
|
||||
};
|
||||
atar13 = {
|
||||
name = "Anthony Tarbinian";
|
||||
email = "atar137h@gmail.com";
|
||||
github = "atar13";
|
||||
githubId = 42757207;
|
||||
matrix = "@atar13:matrix.org";
|
||||
};
|
||||
ataraxiasjel = {
|
||||
email = "nix@ataraxiadev.com";
|
||||
github = "AtaraxiaSjel";
|
||||
@@ -2451,6 +2458,12 @@
|
||||
githubId = 206242;
|
||||
name = "Andreas Wiese";
|
||||
};
|
||||
awwpotato = {
|
||||
email = "awwpotato@voidq.com";
|
||||
github = "awwpotato";
|
||||
githubId = 153149335;
|
||||
name = "awwpotato";
|
||||
};
|
||||
axertheaxe = {
|
||||
email = "axertheaxe@proton.me";
|
||||
github = "AxerTheAxe";
|
||||
@@ -3188,6 +3201,12 @@
|
||||
githubId = 77934086;
|
||||
keys = [ { fingerprint = "4CA3 48F6 8FE1 1777 8EDA 3860 B9A2 C1B0 25EC 2C55"; } ];
|
||||
};
|
||||
blenderfreaky = {
|
||||
name = "blenderfreaky";
|
||||
email = "nix@blenderfreaky.de";
|
||||
github = "blenderfreaky";
|
||||
githubId = 14351657;
|
||||
};
|
||||
blinry = {
|
||||
name = "blinry";
|
||||
email = "mail@blinry.org";
|
||||
@@ -4461,6 +4480,12 @@
|
||||
githubId = 71959829;
|
||||
name = "Cleeyv";
|
||||
};
|
||||
clementpoiret = {
|
||||
email = "poiret.clement@outlook.fr";
|
||||
github = "clementpoiret";
|
||||
githubId = 10899984;
|
||||
name = "Clement POIRET";
|
||||
};
|
||||
clemjvdm = {
|
||||
email = "clement.jvdm@gmail.com";
|
||||
github = "clemjvdm";
|
||||
@@ -5297,7 +5322,7 @@
|
||||
};
|
||||
danth = {
|
||||
name = "Daniel Thwaites";
|
||||
email = "danthwaites30@btinternet.com";
|
||||
email = "danth@danth.me";
|
||||
matrix = "@danth:danth.me";
|
||||
github = "danth";
|
||||
githubId = 28959268;
|
||||
@@ -9176,6 +9201,12 @@
|
||||
githubId = 1498782;
|
||||
name = "Jesse Haber-Kucharsky";
|
||||
};
|
||||
hakujin = {
|
||||
email = "colin@hakuj.in";
|
||||
github = "hakujin";
|
||||
githubId = 2192042;
|
||||
name = "Colin King";
|
||||
};
|
||||
hamburger1984 = {
|
||||
email = "hamburger1984@gmail.com";
|
||||
github = "hamburger1984";
|
||||
@@ -9456,6 +9487,12 @@
|
||||
githubId = 49935860;
|
||||
name = "Henri Rosten";
|
||||
};
|
||||
henrispriet = {
|
||||
email = "henri.spriet@gmail.com";
|
||||
github = "henrispriet";
|
||||
githubId = 36509362;
|
||||
name = "Henri Spriet";
|
||||
};
|
||||
henrytill = {
|
||||
email = "henrytill@gmail.com";
|
||||
github = "henrytill";
|
||||
@@ -9732,6 +9769,12 @@
|
||||
githubId = 39689;
|
||||
name = "Hugo Tavares Reis";
|
||||
};
|
||||
httprafa = {
|
||||
email = "rafael.kienitz@gmail.com";
|
||||
github = "HttpRafa";
|
||||
githubId = 60099368;
|
||||
name = "Rafael Kienitz";
|
||||
};
|
||||
huantian = {
|
||||
name = "David Li";
|
||||
email = "davidtianli@gmail.com";
|
||||
@@ -14304,6 +14347,12 @@
|
||||
}
|
||||
];
|
||||
};
|
||||
mahyarmirrashed = {
|
||||
email = "mah.mirr@gmail.com";
|
||||
github = "mahyarmirrashed";
|
||||
githubId = 59240843;
|
||||
name = "Mahyar Mirrashed";
|
||||
};
|
||||
majesticmullet = {
|
||||
email = "hoccthomas@gmail.com.au";
|
||||
github = "MajesticMullet";
|
||||
@@ -16498,6 +16547,13 @@
|
||||
githubId = 56316606;
|
||||
name = "Amneesh Singh";
|
||||
};
|
||||
naufik = {
|
||||
email = "naufal@naufik.net";
|
||||
github = "naufik";
|
||||
githubId = 8577904;
|
||||
name = "Naufal Fikri";
|
||||
keys = [ { fingerprint = "1575 D651 E31EC 6117A CF0AA C1A3B 8BBC A515 8835"; } ];
|
||||
};
|
||||
naxdy = {
|
||||
name = "Naxdy";
|
||||
email = "naxdy@naxdy.org";
|
||||
@@ -16506,11 +16562,6 @@
|
||||
githubId = 4532582;
|
||||
keys = [ { fingerprint = "BDEA AB07 909D B96F 4106 85F1 CC15 0758 46BC E91B"; } ];
|
||||
};
|
||||
nayeko = {
|
||||
name = "nayeko";
|
||||
github = "nayeko";
|
||||
githubId = 196556004;
|
||||
};
|
||||
nazarewk = {
|
||||
name = "Krzysztof Nazarewski";
|
||||
email = "nixpkgs@kdn.im";
|
||||
@@ -17700,6 +17751,12 @@
|
||||
githubId = 34910574;
|
||||
keys = [ { fingerprint = "D055 8A23 3947 B7A0 F966 B07F 0B41 0348 9833 7273"; } ];
|
||||
};
|
||||
Oops418 = {
|
||||
email = "oooopsxxx@gmail.com";
|
||||
github = "Oops418";
|
||||
name = "Oops418";
|
||||
githubId = 93655215;
|
||||
};
|
||||
oosquare = {
|
||||
name = "Justin Chen";
|
||||
email = "oosquare@outlook.com";
|
||||
@@ -20098,6 +20155,12 @@
|
||||
githubId = 10631029;
|
||||
name = "Richard Ipsum";
|
||||
};
|
||||
richiejp = {
|
||||
email = "io@richiejp.com";
|
||||
github = "richiejp";
|
||||
githubId = 988098;
|
||||
name = "Richard Palethorpe";
|
||||
};
|
||||
rick68 = {
|
||||
email = "rick68@gmail.com";
|
||||
github = "rick68";
|
||||
@@ -20483,6 +20546,12 @@
|
||||
githubId = 19699320;
|
||||
keys = [ { fingerprint = "FD5D F7A8 85BB 378A 0157 5356 B09C 4220 3566 9AF8"; } ];
|
||||
};
|
||||
RossSmyth = {
|
||||
name = "Ross Smyth";
|
||||
matrix = "@rosssmyth:matrix.org";
|
||||
github = "RossSmyth";
|
||||
githubId = 18294397;
|
||||
};
|
||||
rostan-t = {
|
||||
name = "Rostan Tabet";
|
||||
email = "rostan.tabet@gmail.com";
|
||||
@@ -21387,6 +21456,12 @@
|
||||
githubId = 33031;
|
||||
name = "Greg Pfeil";
|
||||
};
|
||||
semtexerror = {
|
||||
email = "github@spampert.com";
|
||||
github = "SemtexError";
|
||||
githubId = 8776314;
|
||||
name = "Robin";
|
||||
};
|
||||
sengaya = {
|
||||
email = "tlo@sengaya.de";
|
||||
github = "sengaya";
|
||||
@@ -23726,6 +23801,12 @@
|
||||
githubId = 678511;
|
||||
name = "Thomas Mader";
|
||||
};
|
||||
thornoar = {
|
||||
email = "r.a.maksimovich@gmail.com";
|
||||
github = "thornoar";
|
||||
githubId = 84677666;
|
||||
name = "Roman Maksimovich";
|
||||
};
|
||||
thornycrackers = {
|
||||
email = "codyfh@gmail.com";
|
||||
github = "thornycrackers";
|
||||
@@ -23893,6 +23974,12 @@
|
||||
matrix = "@titaniumtown:envs.net";
|
||||
keys = [ { fingerprint = "D15E 4754 FE1A EDA1 5A6D 4702 9AB2 8AC1 0ECE 533D"; } ];
|
||||
};
|
||||
tjkeller = {
|
||||
email = "tjk@tjkeller.xyz";
|
||||
github = "tjkeller-xyz";
|
||||
githubId = 36288711;
|
||||
name = "Tim Keller";
|
||||
};
|
||||
tjni = {
|
||||
email = "43ngvg@masqt.com";
|
||||
matrix = "@tni:matrix.org";
|
||||
@@ -26409,6 +26496,11 @@
|
||||
github = "zfnmxt";
|
||||
githubId = 37446532;
|
||||
};
|
||||
zh4ngx = {
|
||||
github = "zh4ngx";
|
||||
githubId = 1329212;
|
||||
name = "Andy Zhang";
|
||||
};
|
||||
zhaofengli = {
|
||||
email = "hello@zhaofeng.li";
|
||||
matrix = "@zhaofeng:zhaofeng.li";
|
||||
|
||||
@@ -444,6 +444,7 @@ with lib.maintainers;
|
||||
members = [
|
||||
globin
|
||||
krav
|
||||
leona
|
||||
talyz
|
||||
yayayayaka
|
||||
];
|
||||
@@ -548,7 +549,10 @@ with lib.maintainers;
|
||||
};
|
||||
|
||||
infisical = {
|
||||
members = [ akhilmhdh ];
|
||||
members = [
|
||||
akhilmhdh
|
||||
mahyarmirrashed
|
||||
];
|
||||
scope = "Maintain Infisical";
|
||||
shortName = "Infisical";
|
||||
};
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
- LLVM has been updated from LLVM 16 (on Darwin) and LLVM 18 (on other platforms) to LLVM 19.
|
||||
This introduces some backwards‐incompatible changes; see the [upstream release notes](https://releases.llvm.org/) for details.
|
||||
|
||||
- Emacs has been updated to 30.1.
|
||||
This introduces some backwards‐incompatible changes; see the NEWS for details.
|
||||
NEWS can been viewed from Emacs by typing `C-h n`, or by clicking `Help->Emacs News` from the menu bar.
|
||||
It can also be browsed [online](https://git.savannah.gnu.org/cgit/emacs.git/tree/etc/NEWS?h=emacs-30).
|
||||
|
||||
- The default PHP version has been updated to 8.3.
|
||||
|
||||
- The default Erlang OTP version has been updated to 27.
|
||||
@@ -176,6 +181,8 @@
|
||||
|
||||
- [echoip](https://github.com/mpolden/echoip), a simple service for looking up your IP address. Available as [services.echoip](#opt-services.echoip.enable).
|
||||
|
||||
- [LiteLLM](https://github.com/BerriAI/litellm), a LLM Gateway to provide model access, fallbacks and spend tracking across 100+ LLMs. All in the OpenAI format. Available as [services.litellm](#opt-services.litellm.enable).
|
||||
|
||||
- [Buffyboard](https://gitlab.postmarketos.org/postmarketOS/buffybox/-/tree/master/buffyboard), a framebuffer on-screen keyboard. Available as [services.buffyboard](option.html#opt-services.buffyboard).
|
||||
|
||||
- [KanBoard](https://github.com/kanboard/kanboard), a project management tool that focuses on the Kanban methodology. Available as [services.kanboard](#opt-services.kanboard.enable).
|
||||
@@ -190,6 +197,8 @@
|
||||
|
||||
- [Limine](https://github.com/limine-bootloader/limine) a modern, advanced, portable, multiprotocol bootloader and boot manager. Available as [boot.loader.limine](#opt-boot.loader.limine.enable)
|
||||
|
||||
- [Orthanc](https://orthanc.uclouvain.be/) a lightweight, RESTful DICOM server for healthcare and medical research. Available as [services.orthanc](#opt-services.orthanc.enable).
|
||||
|
||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||
|
||||
## Backward Incompatibilities {#sec-release-25.05-incompatibilities}
|
||||
@@ -237,6 +246,8 @@
|
||||
|
||||
- `pytestFlagsArray` and `unittestFlagsArray` are kept for compatibility purposes. They continue to be Bash-expanded before concatenated. This compatibility layer will be removed in future releases.
|
||||
|
||||
- The `haka` package and module has been removed because the package was broken and unmaintained for 9 years.
|
||||
|
||||
- `strawberry` has been updated to 1.2, which drops support for the VLC backend and Qt 5. The `strawberry-qt5` package
|
||||
and `withGstreamer`/`withVlc` override options have been removed due to this.
|
||||
|
||||
@@ -264,6 +275,8 @@
|
||||
|
||||
- `isd` was updated from 0.2.0 to 0.5.1, the new version may crash with a previously generated config, try moving or deleting `~/.config/isd/schema.json`.
|
||||
|
||||
- `uwsgi` no longer supports Python 2 plugins.
|
||||
|
||||
- `asusd` has been upgraded to version 6 which supports multiple aura devices. To account for this, the single `auraConfig` configuration option has been replaced with `auraConfigs` which is an attribute set of config options per each device. The config files may also be now specified as either source files or text strings; to account for this you will need to specify that `text` is used for your existing configs, e.g.:
|
||||
```diff
|
||||
-services.asusd.asusdConfig = '''file contents'''
|
||||
@@ -443,6 +456,8 @@
|
||||
|
||||
- `docker_24` has been removed, as it was EOL with vulnerabilities since June 08, 2024.
|
||||
|
||||
- Emacs 28 and 29 have been removed.
|
||||
|
||||
- `containerd` has been updated to v2, which contains breaking changes. See the [containerd
|
||||
2.0](https://github.com/containerd/containerd/blob/main/docs/containerd-2.0.md) documentation for more
|
||||
details.
|
||||
@@ -481,6 +496,8 @@
|
||||
|
||||
- `security.apparmor.policies.<name>.enforce` and `security.apparmor.policies.<name>.enable` were removed.
|
||||
Configuring the state of apparmor policies must now be done using `security.apparmor.policies.<name>.state` tristate option.
|
||||
- `services.graylog.package` now defaults to `graylog-6_0` as previous default `graylog-5_1` is EOL and therefore removed.
|
||||
Check the migration guides on [5.1→5.2](https://go2docs.graylog.org/5-2/upgrading_graylog/upgrading_to_graylog_5.2.x.htm) and [5.2→6.0](https://go2docs.graylog.org/6-0/upgrading_graylog/upgrading_to_graylog_6.0.x.html) for breaking changes.
|
||||
|
||||
- the notmuch vim plugin now lives in a separate output of the `notmuch`
|
||||
package. Installing `notmuch` will not bring the notmuch vim package anymore,
|
||||
@@ -503,6 +520,8 @@
|
||||
|
||||
- `programs.clash-verge.tunMode` was deprecated and removed because now service mode is necessary to start program. Without `programs.clash-verge.enable`, clash-verge-rev will refuse to start.
|
||||
|
||||
- `confluent-cli` was updated from 3.60.0 to 4.16.0, which includes several breaking changes as detailed in [Confluent's release notes](https://docs.confluent.io/confluent-cli/current/release-notes.html).
|
||||
|
||||
- `siduck76-st` has been renamed to `st-snazzy`, like the project's [flake](https://github.com/siduck/st/blob/main/flake.nix).
|
||||
|
||||
- `python3Packages.jax` now directly depends on `python3Packages.jaxlib`.
|
||||
@@ -573,6 +592,8 @@
|
||||
|
||||
- `services.kmonad` now creates a determinate symlink (in `/dev/input/by-id/`) to each of KMonad virtual devices.
|
||||
|
||||
- `services.searx` now supports configuration of the favicons cache and other options available in SearXNG's `favicons.toml` file
|
||||
|
||||
- `services.gitea` now supports CAPTCHA usage through the `services.gitea.captcha` variable.
|
||||
|
||||
- `services.soft-serve` now restarts upon config change.
|
||||
@@ -587,6 +608,8 @@
|
||||
- New options for the declarative configuration of the user space part of ALSA have been introduced under [hardware.alsa](options.html#opt-hardware.alsa.enable), including setting the default capture and playback device, defining sound card aliases and volume controls.
|
||||
Note: these are intended for users not running a sound server like PulseAudio or PipeWire, but having ALSA as their only sound system.
|
||||
|
||||
- `services.k3s` now provides the `autoDeployCharts` option that allows to automatically deploy Helm charts via the k3s Helm controller.
|
||||
|
||||
- Caddy can now be built with plugins by using `caddy.withPlugins`, a `passthru` function that accepts an attribute set as a parameter. The `plugins` argument represents a list of Caddy plugins, with each Caddy plugin being a versioned module. The `hash` argument represents the `vendorHash` of the resulting Caddy source code with the plugins added.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -120,7 +120,7 @@ in
|
||||
{ "r" = {}; };
|
||||
};
|
||||
|
||||
hardware.graphics.package = lib.mkDefault pkgs.mesa.drivers;
|
||||
hardware.graphics.package32 = lib.mkDefault pkgs.pkgsi686Linux.mesa.drivers;
|
||||
hardware.graphics.package = lib.mkDefault pkgs.mesa;
|
||||
hardware.graphics.package32 = lib.mkDefault pkgs.pkgsi686Linux.mesa;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.hddtemp = {
|
||||
description = "HDD/SSD temperature";
|
||||
documentation = [ "man:hddtemp(8)" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "forking";
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
# compression tools
|
||||
, zstd
|
||||
, xz
|
||||
, zeekstd
|
||||
|
||||
# arguments
|
||||
, name
|
||||
@@ -89,11 +90,13 @@ let
|
||||
compressionPkg = {
|
||||
"zstd" = zstd;
|
||||
"xz" = xz;
|
||||
"zstd-seekable" = zeekstd;
|
||||
}."${compression.algorithm}";
|
||||
|
||||
compressionCommand = {
|
||||
"zstd" = "zstd --no-progress --threads=$NIX_BUILD_CORES -${toString compression.level}";
|
||||
"xz" = "xz --keep --verbose --threads=$NIX_BUILD_CORES -${toString compression.level}";
|
||||
"zstd-seekable" = "zeekstd --quiet --max-frame-size 2M --compression-level ${toString compression.level}";
|
||||
}."${compression.algorithm}";
|
||||
in
|
||||
stdenvNoCC.mkDerivation (finalAttrs:
|
||||
|
||||
@@ -48,7 +48,7 @@ let
|
||||
};
|
||||
|
||||
repartConfig = lib.mkOption {
|
||||
type = with lib.types; attrsOf (oneOf [ str int bool ]);
|
||||
type = with lib.types; attrsOf (oneOf [ str int bool (listOf str) ]);
|
||||
example = {
|
||||
Type = "home";
|
||||
SizeMinBytes = "512M";
|
||||
@@ -113,7 +113,7 @@ in
|
||||
enable = lib.mkEnableOption "Image compression";
|
||||
|
||||
algorithm = lib.mkOption {
|
||||
type = lib.types.enum [ "zstd" "xz" ];
|
||||
type = lib.types.enum [ "zstd" "xz" "zstd-seekable" ];
|
||||
default = "zstd";
|
||||
description = "Compression algorithm";
|
||||
};
|
||||
@@ -274,6 +274,7 @@ in
|
||||
{
|
||||
"zstd" = ".zst";
|
||||
"xz" = ".xz";
|
||||
"zstd-seekable" = ".zst";
|
||||
}."${cfg.compression.algorithm}";
|
||||
|
||||
makeClosure = paths: pkgs.closureInfo { rootPaths = paths; };
|
||||
@@ -298,6 +299,7 @@ in
|
||||
level = lib.mkOptionDefault {
|
||||
"zstd" = 3;
|
||||
"xz" = 3;
|
||||
"zstd-seekable" = 3;
|
||||
}."${cfg.compression.algorithm}";
|
||||
};
|
||||
|
||||
@@ -311,7 +313,7 @@ in
|
||||
(lib.mapAttrsToList (_n: v: v.repartConfig.Format or null) cfg.partitions);
|
||||
|
||||
|
||||
format = pkgs.formats.ini { };
|
||||
format = pkgs.formats.ini { listsAsDuplicateKeys = true; };
|
||||
|
||||
definitionsDirectory = utils.systemdUtils.lib.definitions
|
||||
"repart.d"
|
||||
|
||||
@@ -825,6 +825,7 @@
|
||||
./services/misc/languagetool.nix
|
||||
./services/misc/leaps.nix
|
||||
./services/misc/lifecycled.nix
|
||||
./services/misc/litellm.nix
|
||||
./services/misc/llama-cpp.nix
|
||||
./services/misc/logkeys.nix
|
||||
./services/misc/mame.nix
|
||||
@@ -848,6 +849,7 @@
|
||||
./services/misc/ombi.nix
|
||||
./services/misc/omnom.nix
|
||||
./services/misc/open-webui.nix
|
||||
./services/misc/orthanc.nix
|
||||
./services/misc/osrm.nix
|
||||
./services/misc/owncast.nix
|
||||
./services/misc/packagekit.nix
|
||||
@@ -1385,7 +1387,6 @@
|
||||
./services/security/esdm.nix
|
||||
./services/security/fail2ban.nix
|
||||
./services/security/fprintd.nix
|
||||
./services/security/haka.nix
|
||||
./services/security/haveged.nix
|
||||
./services/security/hockeypuck.nix
|
||||
./services/security/hologram-agent.nix
|
||||
|
||||
@@ -127,8 +127,6 @@ in
|
||||
system.disableInstallerTools = true;
|
||||
|
||||
nix.settings = {
|
||||
auto-optimise-store = true;
|
||||
|
||||
min-free = cfg.min-free;
|
||||
|
||||
max-free = cfg.max-free;
|
||||
|
||||
@@ -13,11 +13,19 @@ in
|
||||
programs.bash.enableLsColors = lib.mkEnableOption "extra colors in directory listings" // {
|
||||
default = true;
|
||||
};
|
||||
programs.bash.lsColorsFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = lib.literalExpression "\${pkgs.dircolors-solarized}/ansi-dark";
|
||||
description = "Alternative colorscheme for ls colors";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf enable {
|
||||
programs.bash.promptPluginInit = ''
|
||||
eval "$(${pkgs.coreutils}/bin/dircolors -b)"
|
||||
eval "$(${pkgs.coreutils}/bin/dircolors -b ${
|
||||
lib.optionalString (config.programs.bash.lsColorsFile != null) config.programs.bash.lsColorsFile
|
||||
})"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ let
|
||||
shell:
|
||||
if (shell != "fish") then
|
||||
''
|
||||
eval $(${getExe finalPackage} ${shell} --alias ${cfg.alias})
|
||||
eval "$(${getExe finalPackage} ${shell} --alias ${cfg.alias})"
|
||||
''
|
||||
else
|
||||
''
|
||||
|
||||
@@ -292,6 +292,9 @@ in
|
||||
See https://www.isc.org/blogs/isc-dhcp-eol/ for details.
|
||||
Please switch to a different implementation like kea or dnsmasq.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "services" "haka" ] ''
|
||||
The corresponding package was broken and removed from nixpkgs.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "services" "tedicross" ] ''
|
||||
The corresponding package was broken and removed from nixpkgs.
|
||||
'')
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
systemd.services.auditd = {
|
||||
description = "Linux Audit daemon";
|
||||
documentation = [ "man:auditd(8)" ];
|
||||
wantedBy = [ "sysinit.target" ];
|
||||
after = [
|
||||
"local-fs.target"
|
||||
|
||||
@@ -128,6 +128,7 @@ in
|
||||
systemd.services.isolate = {
|
||||
description = "Isolate control group hierarchy daemon";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
documentation = [ "man:isolate(1)" ];
|
||||
serviceConfig = {
|
||||
Type = "notify";
|
||||
ExecStart = "${isolate}/bin/isolate-cg-keeper";
|
||||
|
||||
@@ -20,110 +20,355 @@ let
|
||||
chartDir = "/var/lib/rancher/k3s/server/static/charts";
|
||||
imageDir = "/var/lib/rancher/k3s/agent/images";
|
||||
containerdConfigTemplateFile = "/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl";
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
yamlDocSeparator = builtins.toFile "yaml-doc-separator" "\n---\n";
|
||||
# Manifests need a valid YAML suffix to be respected by k3s
|
||||
mkManifestTarget =
|
||||
name: if (lib.hasSuffix ".yaml" name || lib.hasSuffix ".yml" name) then name else name + ".yaml";
|
||||
# Produces a list containing all duplicate manifest names
|
||||
duplicateManifests =
|
||||
with builtins;
|
||||
lib.intersectLists (attrNames cfg.autoDeployCharts) (attrNames cfg.manifests);
|
||||
# Produces a list containing all duplicate chart names
|
||||
duplicateCharts =
|
||||
with builtins;
|
||||
lib.intersectLists (attrNames cfg.autoDeployCharts) (attrNames cfg.charts);
|
||||
|
||||
manifestModule =
|
||||
let
|
||||
mkTarget =
|
||||
name: if (lib.hasSuffix ".yaml" name || lib.hasSuffix ".yml" name) then name else name + ".yaml";
|
||||
in
|
||||
lib.types.submodule (
|
||||
{
|
||||
name,
|
||||
config,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Whether this manifest file should be generated.";
|
||||
};
|
||||
|
||||
target = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
example = lib.literalExpression "manifest.yaml";
|
||||
description = ''
|
||||
Name of the symlink (relative to {file}`${manifestDir}`).
|
||||
Defaults to the attribute name.
|
||||
'';
|
||||
};
|
||||
|
||||
content = lib.mkOption {
|
||||
type = with lib.types; nullOr (either attrs (listOf attrs));
|
||||
default = null;
|
||||
description = ''
|
||||
Content of the manifest file. A single attribute set will
|
||||
generate a single document YAML file. A list of attribute sets
|
||||
will generate multiple documents separated by `---` in a single
|
||||
YAML file.
|
||||
'';
|
||||
};
|
||||
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
example = lib.literalExpression "./manifests/app.yaml";
|
||||
description = ''
|
||||
Path of the source `.yaml` file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
target = lib.mkDefault (mkTarget name);
|
||||
source = lib.mkIf (config.content != null) (
|
||||
let
|
||||
name' = "k3s-manifest-" + builtins.baseNameOf name;
|
||||
docName = "k3s-manifest-doc-" + builtins.baseNameOf name;
|
||||
yamlDocSeparator = builtins.toFile "yaml-doc-separator" "\n---\n";
|
||||
mkYaml = name: x: (pkgs.formats.yaml { }).generate name x;
|
||||
mkSource =
|
||||
value:
|
||||
if builtins.isList value then
|
||||
pkgs.concatText name' (
|
||||
lib.concatMap (x: [
|
||||
yamlDocSeparator
|
||||
(mkYaml docName x)
|
||||
]) value
|
||||
)
|
||||
else
|
||||
mkYaml name' value;
|
||||
in
|
||||
lib.mkDerivedConfig options.content mkSource
|
||||
);
|
||||
};
|
||||
}
|
||||
# Converts YAML -> JSON -> Nix
|
||||
fromYaml =
|
||||
path:
|
||||
with builtins;
|
||||
fromJSON (
|
||||
readFile (
|
||||
pkgs.runCommand "${path}-converted.json" { nativeBuildInputs = [ yq-go ]; } ''
|
||||
yq --no-colors --output-format json ${path} > $out
|
||||
''
|
||||
)
|
||||
);
|
||||
|
||||
enabledManifests = lib.filter (m: m.enable) (lib.attrValues cfg.manifests);
|
||||
linkManifestEntry = m: "${pkgs.coreutils-full}/bin/ln -sfn ${m.source} ${manifestDir}/${m.target}";
|
||||
linkImageEntry = image: "${pkgs.coreutils-full}/bin/ln -sfn ${image} ${imageDir}/${image.name}";
|
||||
linkChartEntry =
|
||||
let
|
||||
mkTarget = name: if (lib.hasSuffix ".tgz" name) then name else name + ".tgz";
|
||||
in
|
||||
# Replace characters that are problematic in file names
|
||||
cleanHelmChartName =
|
||||
lib.replaceStrings
|
||||
[
|
||||
"/"
|
||||
":"
|
||||
]
|
||||
[
|
||||
"-"
|
||||
"-"
|
||||
];
|
||||
|
||||
# Fetch a Helm chart from a public registry. This only supports a basic Helm pull.
|
||||
fetchHelm =
|
||||
{
|
||||
name,
|
||||
repo,
|
||||
version,
|
||||
hash ? lib.fakeHash,
|
||||
}:
|
||||
pkgs.runCommand (cleanHelmChartName "${lib.removePrefix "https://" repo}-${name}-${version}.tgz")
|
||||
{
|
||||
inherit (lib.fetchers.normalizeHash { } { inherit hash; }) outputHash outputHashAlgo;
|
||||
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
|
||||
nativeBuildInputs = with pkgs; [
|
||||
kubernetes-helm
|
||||
cacert
|
||||
];
|
||||
}
|
||||
''
|
||||
export HOME="$PWD"
|
||||
helm repo add repository ${repo}
|
||||
helm pull repository/${name} --version ${version}
|
||||
mv ./*.tgz $out
|
||||
'';
|
||||
|
||||
# Returns the path to a YAML manifest file
|
||||
mkExtraDeployManifest =
|
||||
x:
|
||||
# x is a derivation that provides a YAML file
|
||||
if lib.isDerivation x then
|
||||
x.outPath
|
||||
# x is an attribute set that needs to be converted to a YAML file
|
||||
else if builtins.isAttrs x then
|
||||
(yamlFormat.generate "extra-deploy-chart-manifest" x)
|
||||
# assume x is a path to a YAML file
|
||||
else
|
||||
x;
|
||||
|
||||
# Generate a HelmChart custom resource.
|
||||
mkHelmChartCR =
|
||||
name: value:
|
||||
"${pkgs.coreutils-full}/bin/ln -sfn ${value} ${chartDir}/${mkTarget (builtins.baseNameOf name)}";
|
||||
let
|
||||
chartValues = if (lib.isPath value.values) then fromYaml value.values else value.values;
|
||||
# use JSON for values as it's a subset of YAML and understood by the k3s Helm controller
|
||||
valuesContent = builtins.toJSON chartValues;
|
||||
in
|
||||
# merge with extraFieldDefinitions to allow setting advanced values and overwrite generated
|
||||
# values
|
||||
lib.recursiveUpdate {
|
||||
apiVersion = "helm.cattle.io/v1";
|
||||
kind = "HelmChart";
|
||||
metadata = {
|
||||
inherit name;
|
||||
namespace = "kube-system";
|
||||
};
|
||||
spec = {
|
||||
inherit valuesContent;
|
||||
inherit (value) targetNamespace createNamespace;
|
||||
chart = "https://%{KUBERNETES_API}%/static/charts/${name}.tgz";
|
||||
};
|
||||
} value.extraFieldDefinitions;
|
||||
|
||||
activateK3sContent = pkgs.writeShellScript "activate-k3s-content" ''
|
||||
${lib.optionalString (
|
||||
builtins.length enabledManifests > 0
|
||||
) "${pkgs.coreutils-full}/bin/mkdir -p ${manifestDir}"}
|
||||
${lib.optionalString (cfg.charts != { }) "${pkgs.coreutils-full}/bin/mkdir -p ${chartDir}"}
|
||||
${lib.optionalString (
|
||||
builtins.length cfg.images > 0
|
||||
) "${pkgs.coreutils-full}/bin/mkdir -p ${imageDir}"}
|
||||
# Generate a HelmChart custom resource together with extraDeploy manifests. This
|
||||
# generates possibly a multi document YAML file that the auto deploy mechanism of k3s
|
||||
# deploys.
|
||||
mkAutoDeployChartManifest = name: value: {
|
||||
# target is the final name of the link created for the manifest file
|
||||
target = mkManifestTarget name;
|
||||
inherit (value) enable package;
|
||||
# source is a store path containing the complete manifest file
|
||||
source = pkgs.concatText "auto-deploy-chart-${name}.yaml" (
|
||||
[
|
||||
(yamlFormat.generate "helm-chart-manifest-${name}.yaml" (mkHelmChartCR name value))
|
||||
]
|
||||
# alternate the YAML doc seperator (---) and extraDeploy manifests to create
|
||||
# multi document YAMLs
|
||||
++ (lib.concatMap (x: [
|
||||
yamlDocSeparator
|
||||
(mkExtraDeployManifest x)
|
||||
]) value.extraDeploy)
|
||||
);
|
||||
};
|
||||
|
||||
${builtins.concatStringsSep "\n" (map linkManifestEntry enabledManifests)}
|
||||
${builtins.concatStringsSep "\n" (lib.mapAttrsToList linkChartEntry cfg.charts)}
|
||||
${builtins.concatStringsSep "\n" (map linkImageEntry cfg.images)}
|
||||
autoDeployChartsModule = lib.types.submodule (
|
||||
{ config, ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = ''
|
||||
Whether to enable the installation of this Helm chart. Note that setting
|
||||
this option to `false` will not uninstall the chart from the cluster, if
|
||||
it was previously installed. Please use the the `--disable` flag or `.skip`
|
||||
files to delete/disable Helm charts, as mentioned in the
|
||||
[docs](https://docs.k3s.io/installation/packaged-components#disabling-manifests).
|
||||
'';
|
||||
};
|
||||
|
||||
${lib.optionalString (cfg.containerdConfigTemplate != null) ''
|
||||
mkdir -p $(dirname ${containerdConfigTemplateFile})
|
||||
${pkgs.coreutils-full}/bin/ln -sfn ${pkgs.writeText "config.toml.tmpl" cfg.containerdConfigTemplate} ${containerdConfigTemplateFile}
|
||||
''}
|
||||
'';
|
||||
repo = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
example = "https://kubernetes.github.io/ingress-nginx";
|
||||
description = ''
|
||||
The repo of the Helm chart. Only has an effect if `package` is not set.
|
||||
The Helm chart is fetched during build time and placed as a `.tgz` archive on the
|
||||
filesystem.
|
||||
'';
|
||||
};
|
||||
|
||||
name = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
example = "ingress-nginx";
|
||||
description = ''
|
||||
The name of the Helm chart. Only has an effect if `package` is not set.
|
||||
The Helm chart is fetched during build time and placed as a `.tgz` archive on the
|
||||
filesystem.
|
||||
'';
|
||||
};
|
||||
|
||||
version = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
example = "4.7.0";
|
||||
description = ''
|
||||
The version of the Helm chart. Only has an effect if `package` is not set.
|
||||
The Helm chart is fetched during build time and placed as a `.tgz` archive on the
|
||||
filesystem.
|
||||
'';
|
||||
};
|
||||
|
||||
hash = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "sha256-ej+vpPNdiOoXsaj1jyRpWLisJgWo8EqX+Z5VbpSjsPA=";
|
||||
description = ''
|
||||
The hash of the packaged Helm chart. Only has an effect if `package` is not set.
|
||||
The Helm chart is fetched during build time and placed as a `.tgz` archive on the
|
||||
filesystem.
|
||||
'';
|
||||
};
|
||||
|
||||
package = lib.mkOption {
|
||||
type = with lib.types; either path package;
|
||||
example = lib.literalExpression "../my-helm-chart.tgz";
|
||||
description = ''
|
||||
The packaged Helm chart. Overwrites the options `repo`, `name`, `version`
|
||||
and `hash` in case of conflicts.
|
||||
'';
|
||||
};
|
||||
|
||||
targetNamespace = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = "default";
|
||||
example = "kube-system";
|
||||
description = "The namespace in which the Helm chart gets installed.";
|
||||
};
|
||||
|
||||
createNamespace = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether to create the target namespace if not present.";
|
||||
};
|
||||
|
||||
values = lib.mkOption {
|
||||
type = with lib.types; either path attrs;
|
||||
default = { };
|
||||
example = {
|
||||
replicaCount = 3;
|
||||
hostName = "my-host";
|
||||
server = {
|
||||
name = "nginx";
|
||||
port = 80;
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Override default chart values via Nix expressions. This is equivalent to setting
|
||||
values in a `values.yaml` file.
|
||||
|
||||
WARNING: The values (including secrets!) specified here are exposed unencrypted
|
||||
in the world-readable nix store.
|
||||
'';
|
||||
};
|
||||
|
||||
extraDeploy = lib.mkOption {
|
||||
type = with lib.types; listOf (either path attrs);
|
||||
default = [ ];
|
||||
example = lib.literalExpression ''
|
||||
[
|
||||
../manifests/my-extra-deployment.yaml
|
||||
{
|
||||
apiVersion = "v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
name = "app-service";
|
||||
};
|
||||
spec = {
|
||||
selector = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
};
|
||||
ports = [
|
||||
{
|
||||
name = "name-of-service-port";
|
||||
protocol = "TCP";
|
||||
port = 80;
|
||||
targetPort = "http-web-svc";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
'';
|
||||
description = "List of extra Kubernetes manifests to deploy with this Helm chart.";
|
||||
};
|
||||
|
||||
extraFieldDefinitions = lib.mkOption {
|
||||
inherit (yamlFormat) type;
|
||||
default = { };
|
||||
example = {
|
||||
spec = {
|
||||
bootstrap = true;
|
||||
helmVersion = "v2";
|
||||
backOffLimit = 3;
|
||||
jobImage = "custom-helm-controller:v0.0.1";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Extra HelmChart field definitions that are merged with the rest of the HelmChart
|
||||
custom resource. This can be used to set advanced fields or to overwrite
|
||||
generated fields. See https://docs.k3s.io/helm#helmchart-field-definitions
|
||||
for possible fields.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config.package = lib.mkDefault (fetchHelm {
|
||||
inherit (config)
|
||||
repo
|
||||
name
|
||||
version
|
||||
hash
|
||||
;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
manifestModule = lib.types.submodule (
|
||||
{
|
||||
name,
|
||||
config,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Whether this manifest file should be generated.";
|
||||
};
|
||||
|
||||
target = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
example = "manifest.yaml";
|
||||
description = ''
|
||||
Name of the symlink (relative to {file}`${manifestDir}`).
|
||||
Defaults to the attribute name.
|
||||
'';
|
||||
};
|
||||
|
||||
content = lib.mkOption {
|
||||
type = with lib.types; nullOr (either attrs (listOf attrs));
|
||||
default = null;
|
||||
description = ''
|
||||
Content of the manifest file. A single attribute set will
|
||||
generate a single document YAML file. A list of attribute sets
|
||||
will generate multiple documents separated by `---` in a single
|
||||
YAML file.
|
||||
'';
|
||||
};
|
||||
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
example = lib.literalExpression "./manifests/app.yaml";
|
||||
description = ''
|
||||
Path of the source `.yaml` file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
target = lib.mkDefault (mkManifestTarget name);
|
||||
source = lib.mkIf (config.content != null) (
|
||||
let
|
||||
name' = "k3s-manifest-" + builtins.baseNameOf name;
|
||||
docName = "k3s-manifest-doc-" + builtins.baseNameOf name;
|
||||
mkSource =
|
||||
value:
|
||||
if builtins.isList value then
|
||||
pkgs.concatText name' (
|
||||
lib.concatMap (x: [
|
||||
yamlDocSeparator
|
||||
(yamlFormat.generate docName x)
|
||||
]) value
|
||||
)
|
||||
else
|
||||
yamlFormat.generate name' value;
|
||||
in
|
||||
lib.mkDerivedConfig options.content mkSource
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
imports = [ (removeOption [ "docker" ] "k3s docker option is no longer supported.") ];
|
||||
@@ -242,78 +487,80 @@ in
|
||||
type = lib.types.attrsOf manifestModule;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
deployment.source = ../manifests/deployment.yaml;
|
||||
my-service = {
|
||||
enable = false;
|
||||
target = "app-service.yaml";
|
||||
content = {
|
||||
apiVersion = "v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
name = "app-service";
|
||||
};
|
||||
spec = {
|
||||
selector = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
{
|
||||
deployment.source = ../manifests/deployment.yaml;
|
||||
my-service = {
|
||||
enable = false;
|
||||
target = "app-service.yaml";
|
||||
content = {
|
||||
apiVersion = "v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
name = "app-service";
|
||||
};
|
||||
spec = {
|
||||
selector = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
};
|
||||
ports = [
|
||||
{
|
||||
name = "name-of-service-port";
|
||||
protocol = "TCP";
|
||||
port = 80;
|
||||
targetPort = "http-web-svc";
|
||||
}
|
||||
];
|
||||
};
|
||||
ports = [
|
||||
{
|
||||
name = "name-of-service-port";
|
||||
protocol = "TCP";
|
||||
port = 80;
|
||||
targetPort = "http-web-svc";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
nginx.content = [
|
||||
{
|
||||
apiVersion = "v1";
|
||||
kind = "Pod";
|
||||
metadata = {
|
||||
name = "nginx";
|
||||
labels = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
nginx.content = [
|
||||
{
|
||||
apiVersion = "v1";
|
||||
kind = "Pod";
|
||||
metadata = {
|
||||
name = "nginx";
|
||||
labels = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
};
|
||||
};
|
||||
};
|
||||
spec = {
|
||||
containers = [
|
||||
{
|
||||
name = "nginx";
|
||||
image = "nginx:1.14.2";
|
||||
ports = [
|
||||
{
|
||||
containerPort = 80;
|
||||
name = "http-web-svc";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
{
|
||||
apiVersion = "v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
name = "nginx-service";
|
||||
};
|
||||
spec = {
|
||||
selector = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
spec = {
|
||||
containers = [
|
||||
{
|
||||
name = "nginx";
|
||||
image = "nginx:1.14.2";
|
||||
ports = [
|
||||
{
|
||||
containerPort = 80;
|
||||
name = "http-web-svc";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
ports = [
|
||||
{
|
||||
name = "name-of-service-port";
|
||||
protocol = "TCP";
|
||||
port = 80;
|
||||
targetPort = "http-web-svc";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
apiVersion = "v1";
|
||||
kind = "Service";
|
||||
metadata = {
|
||||
name = "nginx-service";
|
||||
};
|
||||
spec = {
|
||||
selector = {
|
||||
"app.kubernetes.io/name" = "MyApp";
|
||||
};
|
||||
ports = [
|
||||
{
|
||||
name = "name-of-service-port";
|
||||
protocol = "TCP";
|
||||
port = 80;
|
||||
targetPort = "http-web-svc";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Auto-deploying manifests that are linked to {file}`${manifestDir}` before k3s starts.
|
||||
@@ -337,10 +584,9 @@ in
|
||||
Packaged Helm charts that are linked to {file}`${chartDir}` before k3s starts.
|
||||
The attribute name will be used as the link target (relative to {file}`${chartDir}`).
|
||||
The specified charts will only be placed on the file system and made available to the
|
||||
Kubernetes APIServer from within the cluster, you may use the
|
||||
[k3s Helm controller](https://docs.k3s.io/helm#using-the-helm-controller)
|
||||
to deploy the charts. This option only makes sense on server nodes
|
||||
(`role = server`).
|
||||
Kubernetes APIServer from within the cluster. See the [](#opt-services.k3s.autoDeployCharts)
|
||||
option and the [k3s Helm controller docs](https://docs.k3s.io/helm#using-the-helm-controller)
|
||||
to deploy Helm charts. This option only makes sense on server nodes (`role = server`).
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -450,6 +696,53 @@ in
|
||||
set the `clientConnection.kubeconfig` if you want to use `extraKubeProxyConfig`.
|
||||
'';
|
||||
};
|
||||
|
||||
autoDeployCharts = lib.mkOption {
|
||||
type = lib.types.attrsOf autoDeployChartsModule;
|
||||
apply = lib.mapAttrs mkAutoDeployChartManifest;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
harbor = {
|
||||
name = "harbor";
|
||||
repo = "https://helm.goharbor.io";
|
||||
version = "1.14.0";
|
||||
hash = "sha256-fMP7q1MIbvzPGS9My91vbQ1d3OJMjwc+o8YE/BXZaYU=";
|
||||
values = {
|
||||
existingSecretAdminPassword = "harbor-admin";
|
||||
expose = {
|
||||
tls = {
|
||||
enabled = true;
|
||||
certSource = "secret";
|
||||
secret.secretName = "my-tls-secret";
|
||||
};
|
||||
ingress = {
|
||||
hosts.core = "example.com";
|
||||
className = "nginx";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
custom-chart = {
|
||||
package = ../charts/my-chart.tgz;
|
||||
values = ../values/my-values.yaml;
|
||||
extraFieldDefinitions = {
|
||||
spec.timeout = "60s";
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Auto deploying Helm charts that are installed by the k3s Helm controller. Avoid to use
|
||||
attribute names that are also used in the [](#opt-services.k3s.manifests) and
|
||||
[](#opt-services.k3s.charts) options. Manifests with the same name will override
|
||||
auto deploying charts with the same name. Similiarly, charts with the same name will
|
||||
overwrite the Helm chart contained in auto deploying charts. This option only makes
|
||||
sense on server nodes (`role = server`). See the
|
||||
[k3s Helm documentation](https://docs.k3s.io/helm) for further information.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# implementation
|
||||
@@ -462,6 +755,15 @@ in
|
||||
++ (lib.optional (cfg.role != "server" && cfg.charts != { })
|
||||
"k3s: Helm charts are only made available to the cluster on server nodes (role == server), they will be ignored by this node."
|
||||
)
|
||||
++ (lib.optional (cfg.role != "server" && cfg.autoDeployCharts != { })
|
||||
"k3s: Auto deploying Helm charts are only installed on server nodes (role == server), they will be ignored by this node."
|
||||
)
|
||||
++ (lib.optional (duplicateManifests != [ ])
|
||||
"k3s: The following auto deploying charts are overriden by manifests of the same name: ${toString duplicateManifests}."
|
||||
)
|
||||
++ (lib.optional (duplicateCharts != [ ])
|
||||
"k3s: The following auto deploying charts are overriden by charts of the same name: ${toString duplicateCharts}."
|
||||
)
|
||||
++ (lib.optional (
|
||||
cfg.disableAgent && cfg.images != [ ]
|
||||
) "k3s: Images are only imported on nodes with an enabled agent, they will be ignored by this node")
|
||||
@@ -486,6 +788,50 @@ in
|
||||
|
||||
environment.systemPackages = [ config.services.k3s.package ];
|
||||
|
||||
# Use systemd-tmpfiles to activate k3s content
|
||||
systemd.tmpfiles.settings."10-k3s" =
|
||||
let
|
||||
# Merge manifest with manifests generated from auto deploying charts, keep only enabled manifests
|
||||
enabledManifests = lib.filterAttrs (_: v: v.enable) (cfg.autoDeployCharts // cfg.manifests);
|
||||
# Merge charts with charts contained in enabled auto deploying charts
|
||||
helmCharts =
|
||||
(lib.concatMapAttrs (n: v: { ${n} = v.package; }) (
|
||||
lib.filterAttrs (_: v: v.enable) cfg.autoDeployCharts
|
||||
))
|
||||
// cfg.charts;
|
||||
# Make a systemd-tmpfiles rule for a manifest
|
||||
mkManifestRule = manifest: {
|
||||
name = "${manifestDir}/${manifest.target}";
|
||||
value = {
|
||||
"L+".argument = "${manifest.source}";
|
||||
};
|
||||
};
|
||||
# Ensure that all chart targets have a .tgz suffix
|
||||
mkChartTarget = name: if (lib.hasSuffix ".tgz" name) then name else name + ".tgz";
|
||||
# Make a systemd-tmpfiles rule for a chart
|
||||
mkChartRule = target: source: {
|
||||
name = "${chartDir}/${mkChartTarget target}";
|
||||
value = {
|
||||
"L+".argument = "${source}";
|
||||
};
|
||||
};
|
||||
# Make a systemd-tmpfiles rule for a container image
|
||||
mkImageRule = image: {
|
||||
name = "${imageDir}/${image.name}";
|
||||
value = {
|
||||
"L+".argument = "${image}";
|
||||
};
|
||||
};
|
||||
in
|
||||
(lib.mapAttrs' (_: v: mkManifestRule v) enabledManifests)
|
||||
// (lib.mapAttrs' (n: v: mkChartRule n v) helmCharts)
|
||||
// (builtins.listToAttrs (map mkImageRule cfg.images))
|
||||
// (lib.optionalAttrs (cfg.containerdConfigTemplate != null) {
|
||||
${containerdConfigTemplateFile} = {
|
||||
"L+".argument = "${pkgs.writeText "config.toml.tmpl" cfg.containerdConfigTemplate}";
|
||||
};
|
||||
});
|
||||
|
||||
systemd.services.k3s =
|
||||
let
|
||||
kubeletParams =
|
||||
@@ -533,7 +879,6 @@ in
|
||||
LimitCORE = "infinity";
|
||||
TasksMax = "infinity";
|
||||
EnvironmentFile = cfg.environmentFile;
|
||||
ExecStartPre = activateK3sContent;
|
||||
ExecStart = lib.concatStringsSep " \\\n " (
|
||||
[ "${cfg.package}/bin/k3s ${cfg.role}" ]
|
||||
++ (lib.optional cfg.clusterInit "--cluster-init")
|
||||
|
||||
@@ -70,6 +70,7 @@ in
|
||||
};
|
||||
|
||||
systemd.services.torque-server = {
|
||||
documentation = [ "man:pbs_server(8)" ];
|
||||
path = [ torque ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
@@ -93,6 +94,7 @@ in
|
||||
};
|
||||
|
||||
systemd.services.torque-scheduler = {
|
||||
documentation = [ "man:pbs_sched(8)" ];
|
||||
path = [ torque ];
|
||||
|
||||
requires = [ "torque-server-init.service" ];
|
||||
|
||||
@@ -93,11 +93,7 @@ let
|
||||
};
|
||||
} cfg.extraConfig;
|
||||
|
||||
configFile = pkgs.runCommandLocal "config.toml" { } ''
|
||||
${pkgs.buildPackages.remarshal}/bin/remarshal -if json -of toml \
|
||||
< ${pkgs.writeText "config.json" (builtins.toJSON configOptions)} \
|
||||
> $out
|
||||
'';
|
||||
configFile = (pkgs.formats.toml {}).generate "config.toml" configOptions;
|
||||
in
|
||||
{
|
||||
|
||||
|
||||
@@ -372,10 +372,13 @@ in
|
||||
) "${lv2Plugins}/lib/lv2";
|
||||
|
||||
# Mask pw-pulse if it's not wanted
|
||||
systemd.user.services.pipewire-pulse.enable = cfg.pulse.enable;
|
||||
systemd.user.sockets.pipewire-pulse.enable = cfg.pulse.enable;
|
||||
systemd.services.pipewire-pulse.enable = cfg.pulse.enable && cfg.systemWide;
|
||||
systemd.sockets.pipewire-pulse.enable = cfg.pulse.enable && cfg.systemWide;
|
||||
systemd.user.services.pipewire-pulse.enable = cfg.pulse.enable && !cfg.systemWide;
|
||||
systemd.user.sockets.pipewire-pulse.enable = cfg.pulse.enable && !cfg.systemWide;
|
||||
|
||||
systemd.sockets.pipewire.wantedBy = mkIf cfg.socketActivation [ "sockets.target" ];
|
||||
systemd.sockets.pipewire-pulse.wantedBy = mkIf cfg.socketActivation [ "sockets.target" ];
|
||||
systemd.user.sockets.pipewire.wantedBy = mkIf cfg.socketActivation [ "sockets.target" ];
|
||||
systemd.user.sockets.pipewire-pulse.wantedBy = mkIf cfg.socketActivation [ "sockets.target" ];
|
||||
|
||||
|
||||
@@ -140,12 +140,10 @@ let
|
||||
}
|
||||
);
|
||||
|
||||
configFile = pkgs.runCommandLocal "config.toml" { } ''
|
||||
${pkgs.buildPackages.jq}/bin/jq 'del(..|nulls)' \
|
||||
< ${pkgs.writeText "config.json" (builtins.toJSON athensConfig)} | \
|
||||
${pkgs.buildPackages.remarshal}/bin/remarshal -if json -of toml \
|
||||
> $out
|
||||
'';
|
||||
configFile = lib.pipe athensConfig [
|
||||
(lib.filterAttrsRecursive (_k: v: v != null))
|
||||
((pkgs.formats.toml {}).generate "config.toml")
|
||||
];
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
|
||||
@@ -127,5 +127,7 @@
|
||||
services.libeufin.nexus.settings.libeufin-nexusdb-postgres.CONFIG = lib.mkIf (
|
||||
cfgMain.bank.enable && cfgMain.bank.createLocalDatabase
|
||||
) "postgresql:///libeufin-bank";
|
||||
|
||||
systemd.services.libeufin-nexus.documentation = [ "man:libeufin-nexus(1)" ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,11 +68,19 @@ in
|
||||
requires = [ "taler-${talerComponent}-dbinit.service" ];
|
||||
after = [ "taler-${talerComponent}-dbinit.service" ];
|
||||
wantedBy = [ "multi-user.target" ]; # TODO slice?
|
||||
documentation = [
|
||||
"man:taler-${talerComponent}-${name}(1)"
|
||||
"info:taler-${talerComponent}"
|
||||
];
|
||||
}))
|
||||
# Database Initialisation
|
||||
{
|
||||
"taler-${talerComponent}-dbinit" = {
|
||||
path = [ config.services.postgresql.package ];
|
||||
documentation = [
|
||||
"man:taler-${talerComponent}-dbinit(1)"
|
||||
"info:taler-${talerComponent}"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
DynamicUser = true;
|
||||
|
||||
@@ -148,7 +148,7 @@ in {
|
||||
};
|
||||
|
||||
package = lib.mkPackageOption pkgs "minecraft-server" {
|
||||
example = "minecraft-server_1_12_2";
|
||||
example = "pkgs.minecraft-server_1_12_2";
|
||||
};
|
||||
|
||||
jvmOpts = lib.mkOption {
|
||||
|
||||
@@ -49,6 +49,7 @@ in
|
||||
|
||||
systemd.services.thermald = {
|
||||
description = "Thermal Daemon Service";
|
||||
documentation = [ "man:thermald(8)" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
PrivateNetwork = true;
|
||||
|
||||
@@ -122,6 +122,7 @@ in
|
||||
systemd.services.triggerhappy = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description = "Global hotkey daemon";
|
||||
documentation = [ "man:thd(1)" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.triggerhappy}/bin/thd ${
|
||||
lib.optionalString (cfg.user != "root") "--user ${cfg.user}"
|
||||
|
||||
@@ -38,17 +38,8 @@ in
|
||||
|
||||
enable = lib.mkEnableOption "Graylog, a log management solution";
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default =
|
||||
if lib.versionOlder config.system.stateVersion "23.05" then pkgs.graylog-3_3 else pkgs.graylog-5_1;
|
||||
defaultText = lib.literalExpression (
|
||||
if lib.versionOlder config.system.stateVersion "23.05" then
|
||||
"pkgs.graylog-3_3"
|
||||
else
|
||||
"pkgs.graylog-5_1"
|
||||
);
|
||||
description = "Graylog package to use.";
|
||||
package = lib.mkPackageOption pkgs "graylog" {
|
||||
example = "graylog-6_0";
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
@@ -139,6 +130,22 @@ in
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
# Note: when changing the default, make it conditional on
|
||||
# ‘system.stateVersion’ to maintain compatibility with existing
|
||||
# systems!
|
||||
services.graylog.package =
|
||||
let
|
||||
mkThrow = ver: throw "graylog-${ver} was removed, please upgrade your graylog version.";
|
||||
base =
|
||||
if lib.versionAtLeast config.system.stateVersion "25.05" then
|
||||
pkgs.graylog-6_0
|
||||
else if lib.versionAtLeast config.system.stateVersion "23.05" then
|
||||
mkThrow "5_1"
|
||||
else
|
||||
mkThrow "3_3";
|
||||
in
|
||||
lib.mkDefault base;
|
||||
|
||||
users.users = lib.mkIf (cfg.user == "graylog") {
|
||||
graylog = {
|
||||
isSystemUser = true;
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
let
|
||||
cfg = config.services.promtail;
|
||||
|
||||
prettyJSON = conf: pkgs.runCommandLocal "promtail-config.json" {} ''
|
||||
echo '${builtins.toJSON conf}' | ${pkgs.buildPackages.jq}/bin/jq 'del(._module)' > $out
|
||||
'';
|
||||
format = pkgs.formats.json {};
|
||||
prettyJSON = conf: with lib; pipe conf [
|
||||
(flip removeAttrs [ "_module" ])
|
||||
(format.generate "promtail-config.json")
|
||||
];
|
||||
|
||||
allowSystemdJournal = cfg.configuration ? scrape_configs && lib.any (v: v ? journal) cfg.configuration.scrape_configs;
|
||||
|
||||
@@ -20,7 +22,7 @@ in {
|
||||
enable = mkEnableOption "the Promtail ingresser";
|
||||
|
||||
configuration = mkOption {
|
||||
type = (pkgs.formats.json {}).type;
|
||||
type = format.type;
|
||||
description = ''
|
||||
Specify the configuration for Promtail in Nix.
|
||||
This option will be ignored if `services.promtail.configFile` is defined.
|
||||
|
||||
@@ -871,6 +871,7 @@ in
|
||||
systemd.services.postfix = {
|
||||
description = "Postfix mail server";
|
||||
|
||||
documentation = [ "man:postfix(1)" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [
|
||||
"network.target"
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) types;
|
||||
|
||||
cfg = config.services.litellm;
|
||||
settingsFormat = pkgs.formats.yaml { };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.litellm = {
|
||||
enable = lib.mkEnableOption "LiteLLM server";
|
||||
package = lib.mkPackageOption pkgs "litellm" { };
|
||||
|
||||
stateDir = lib.mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/litellm";
|
||||
example = "/home/foo";
|
||||
description = "State directory of LiteLLM.";
|
||||
};
|
||||
|
||||
host = lib.mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
example = "0.0.0.0";
|
||||
description = ''
|
||||
The host address which the LiteLLM server HTTP interface listens to.
|
||||
'';
|
||||
};
|
||||
|
||||
port = lib.mkOption {
|
||||
type = types.port;
|
||||
default = 8080;
|
||||
example = 11111;
|
||||
description = ''
|
||||
Which port the LiteLLM server listens to.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
options = {
|
||||
model_list = lib.mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = ''
|
||||
List of supported models on the server, with model-specific configs.
|
||||
'';
|
||||
default = [ ];
|
||||
};
|
||||
router_settings = lib.mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = ''
|
||||
LiteLLM Router settings
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
|
||||
litellm_settings = lib.mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = ''
|
||||
LiteLLM Module settings
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
|
||||
general_settings = lib.mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = ''
|
||||
LiteLLM Server settings
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
|
||||
environment_variables = lib.mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = ''
|
||||
Environment variables to pass to the Lite
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
Configuration for LiteLLM.
|
||||
See <https://docs.litellm.ai/docs/proxy/configs> for more.
|
||||
'';
|
||||
};
|
||||
|
||||
environment = lib.mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {
|
||||
SCARF_NO_ANALYTICS = "True";
|
||||
DO_NOT_TRACK = "True";
|
||||
ANONYMIZED_TELEMETRY = "False";
|
||||
};
|
||||
example = ''
|
||||
{
|
||||
NO_DOCS="True";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Extra environment variables for LiteLLM.
|
||||
'';
|
||||
};
|
||||
|
||||
environmentFile = lib.mkOption {
|
||||
description = ''
|
||||
Environment file to be passed to the systemd service.
|
||||
Useful for passing secrets to the service to prevent them from being
|
||||
world-readable in the Nix store.
|
||||
'';
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/var/lib/secrets/liteLLMSecrets";
|
||||
};
|
||||
|
||||
openFirewall = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to open the firewall for LiteLLM.
|
||||
This adds `services.litellm.port` to `networking.firewall.allowedTCPPorts`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.litellm = {
|
||||
description = "LLM Gateway to provide model access, fallbacks and spend tracking across 100+ LLMs.";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
environment = cfg.environment;
|
||||
|
||||
serviceConfig =
|
||||
let
|
||||
configFile = settingsFormat.generate "config.yaml" cfg.settings;
|
||||
in
|
||||
{
|
||||
ExecStart = "${lib.getExe cfg.package} --host \"${cfg.host}\" --port ${toString cfg.port} --config ${configFile}";
|
||||
EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile;
|
||||
WorkingDirectory = cfg.stateDir;
|
||||
StateDirectory = "litellm";
|
||||
RuntimeDirectory = "litellm";
|
||||
RuntimeDirectoryMode = "0755";
|
||||
PrivateTmp = true;
|
||||
DynamicUser = true;
|
||||
DevicePolicy = "closed";
|
||||
LockPersonality = true;
|
||||
PrivateUsers = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
UMask = "0077";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
ProtectClock = true;
|
||||
ProtectProc = "invisible";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; };
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ drupol ];
|
||||
}
|
||||
@@ -120,6 +120,18 @@ in
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
UMask = "0077";
|
||||
CapabilityBoundingSet = "";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
ProtectClock = true;
|
||||
ProtectProc = "invisible";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
{
|
||||
config,
|
||||
options,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) types;
|
||||
|
||||
cfg = config.services.orthanc;
|
||||
opt = options.services.orthanc;
|
||||
|
||||
settingsFormat = pkgs.formats.json { };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.orthanc = {
|
||||
enable = lib.mkEnableOption "Orthanc server";
|
||||
package = lib.mkPackageOption pkgs "orthanc" { };
|
||||
|
||||
stateDir = lib.mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/orthanc";
|
||||
example = "/home/foo";
|
||||
description = "State directory of Orthanc.";
|
||||
};
|
||||
|
||||
environment = lib.mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {
|
||||
};
|
||||
example = ''
|
||||
{
|
||||
ORTHANC_NAME = "Orthanc server";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Extra environment variables
|
||||
For more details see <https://orthanc.uclouvain.be/book/users/configuration.html>
|
||||
'';
|
||||
};
|
||||
|
||||
environmentFile = lib.mkOption {
|
||||
description = ''
|
||||
Environment file to be passed to the systemd service.
|
||||
Useful for passing secrets to the service to prevent them from being
|
||||
world-readable in the Nix store.
|
||||
'';
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
example = "/var/lib/secrets/orthancSecrets";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
};
|
||||
default = {
|
||||
HttpPort = lib.mkDefault 8042;
|
||||
IndexDirectory = lib.mkDefault "/var/lib/orthanc/";
|
||||
StorageDirectory = lib.mkDefault "/var/lib/orthanc/";
|
||||
};
|
||||
example = {
|
||||
Name = "My Orthanc Server";
|
||||
HttpPort = 12345;
|
||||
};
|
||||
description = ''
|
||||
Configuration written to a json file that is read by orthanc.
|
||||
See <https://orthanc.uclouvain.be/book/index.html> for more.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to open the firewall for Orthanc.
|
||||
This adds `services.orthanc.settings.HttpPort` to `networking.firewall.allowedTCPPorts`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.orthanc.settings = options.services.orthanc.settings.default;
|
||||
|
||||
systemd.services.orthanc = {
|
||||
description = "Orthanc is a lightweight, RESTful DICOM server for healthcare and medical research";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
environment = cfg.environment;
|
||||
|
||||
serviceConfig =
|
||||
let
|
||||
config-json = settingsFormat.generate "orthanc-config.json" (cfg.settings);
|
||||
in
|
||||
{
|
||||
ExecStart = "${lib.getExe cfg.package} ${config-json}";
|
||||
EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile;
|
||||
WorkingDirectory = cfg.stateDir;
|
||||
BindReadOnlyPaths = [
|
||||
"-/etc/localtime"
|
||||
];
|
||||
StateDirectory = "orthanc";
|
||||
RuntimeDirectory = "orthanc";
|
||||
RuntimeDirectoryMode = "0755";
|
||||
PrivateTmp = true;
|
||||
DynamicUser = true;
|
||||
DevicePolicy = "closed";
|
||||
LockPersonality = true;
|
||||
PrivateUsers = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.settings.HttpPort ]; };
|
||||
|
||||
# Orthanc requires /etc/localtime to be present
|
||||
time.timeZone = lib.mkDefault "UTC";
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ drupol ];
|
||||
}
|
||||
@@ -69,7 +69,7 @@ in
|
||||
validateSettings = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Weither to run renovate's config validator on the built configuration.";
|
||||
description = "Whether to run renovate's config validator on the built configuration.";
|
||||
};
|
||||
settings = mkOption {
|
||||
type = json.type;
|
||||
|
||||
@@ -68,6 +68,7 @@ in
|
||||
|
||||
systemd.services."glances" = {
|
||||
description = "Glances";
|
||||
documentation = [ "man:glances(1)" ];
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
|
||||
@@ -603,9 +603,10 @@ in
|
||||
''
|
||||
)
|
||||
+ ''
|
||||
# clear cache after update (before migrations)
|
||||
OLD_VERSION=$(cat ${cfg.dataDir}/version)
|
||||
if [[ $OLD_VERSION != "${package.version}" ]]; then
|
||||
# clear cache if package has changed (cache may contain cached paths
|
||||
# to the old package)
|
||||
OLD_PACKAGE=$(cat ${cfg.dataDir}/package)
|
||||
if [[ $OLD_PACKAGE != "${package}" ]]; then
|
||||
rm -r ${cfg.dataDir}/cache/*
|
||||
fi
|
||||
|
||||
@@ -616,16 +617,21 @@ in
|
||||
echo "${lib.boolToString cfg.enableOneMinutePolling}" > ${cfg.dataDir}/one_minute_enabled
|
||||
fi
|
||||
|
||||
# migrate db
|
||||
${artisanWrapper}/bin/librenms-artisan migrate --force --no-interaction
|
||||
|
||||
# regenerate cache after migrations after update
|
||||
# migrate db if package version has changed
|
||||
# not necessary for every package change
|
||||
OLD_VERSION=$(cat ${cfg.dataDir}/version)
|
||||
if [[ $OLD_VERSION != "${package.version}" ]]; then
|
||||
${artisanWrapper}/bin/librenms-artisan migrate --force --no-interaction
|
||||
echo "${package.version}" > ${cfg.dataDir}/version
|
||||
fi
|
||||
|
||||
# regenerate cache if package has changed
|
||||
if [[ $OLD_PACKAGE != "${package}" ]]; then
|
||||
${artisanWrapper}/bin/librenms-artisan view:clear
|
||||
${artisanWrapper}/bin/librenms-artisan optimize:clear
|
||||
${artisanWrapper}/bin/librenms-artisan view:cache
|
||||
${artisanWrapper}/bin/librenms-artisan optimize
|
||||
echo "${package.version}" > ${cfg.dataDir}/version
|
||||
echo "${package}" > ${cfg.dataDir}/package
|
||||
fi
|
||||
'';
|
||||
};
|
||||
@@ -693,6 +699,7 @@ in
|
||||
"d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
"f ${cfg.dataDir}/.env 0600 ${cfg.user} ${cfg.group} - -"
|
||||
"f ${cfg.dataDir}/version 0600 ${cfg.user} ${cfg.group} - -"
|
||||
"f ${cfg.dataDir}/package 0600 ${cfg.user} ${cfg.group} - -"
|
||||
"f ${cfg.dataDir}/one_minute_enabled 0600 ${cfg.user} ${cfg.group} - -"
|
||||
"f ${cfg.dataDir}/config.json 0600 ${cfg.user} ${cfg.group} - -"
|
||||
"d ${cfg.dataDir}/storage 0700 ${cfg.user} ${cfg.group} - -"
|
||||
|
||||
@@ -28,7 +28,7 @@ let
|
||||
cfg = config.services.thanos;
|
||||
|
||||
nullOpt = type: description: mkOption {
|
||||
type = types.nullOr type;
|
||||
type = if type.check null then type else types.nullOr type;
|
||||
default = null;
|
||||
description = description;
|
||||
};
|
||||
@@ -85,11 +85,7 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
toYAML = name: attrs: pkgs.runCommand name {
|
||||
preferLocalBuild = true;
|
||||
json = builtins.toFile "${name}.json" (builtins.toJSON attrs);
|
||||
nativeBuildInputs = [ pkgs.remarshal ];
|
||||
} "json2yaml -i $json -o $out";
|
||||
format = pkgs.formats.yaml {};
|
||||
|
||||
thanos = cmd: "${cfg.package}/bin/thanos ${cmd}" +
|
||||
(let args = cfg.${cmd}.arguments;
|
||||
@@ -144,10 +140,10 @@ let
|
||||
option = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = if cfg.tracing.config == null then null
|
||||
else toString (toYAML "tracing.yaml" cfg.tracing.config);
|
||||
else toString (format.generate "tracing.yaml" cfg.tracing.config);
|
||||
defaultText = literalExpression ''
|
||||
if config.services.thanos.<cmd>.tracing.config == null then null
|
||||
else toString (toYAML "tracing.yaml" config.services.thanos.<cmd>.tracing.config);
|
||||
else toString (format.generate "tracing.yaml" config.services.thanos.<cmd>.tracing.config);
|
||||
'';
|
||||
description = ''
|
||||
Path to YAML file that contains tracing configuration.
|
||||
@@ -160,7 +156,7 @@ let
|
||||
tracing.config =
|
||||
{
|
||||
toArgs = _opt: _attrs: [];
|
||||
option = nullOpt types.attrs ''
|
||||
option = nullOpt format.type ''
|
||||
Tracing configuration.
|
||||
|
||||
When not `null` the attribute set gets converted to
|
||||
@@ -209,10 +205,10 @@ let
|
||||
option = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = if cfg.objstore.config == null then null
|
||||
else toString (toYAML "objstore.yaml" cfg.objstore.config);
|
||||
else toString (format.generate "objstore.yaml" cfg.objstore.config);
|
||||
defaultText = literalExpression ''
|
||||
if config.services.thanos.<cmd>.objstore.config == null then null
|
||||
else toString (toYAML "objstore.yaml" config.services.thanos.<cmd>.objstore.config);
|
||||
else toString (format.generate "objstore.yaml" config.services.thanos.<cmd>.objstore.config);
|
||||
'';
|
||||
description = ''
|
||||
Path to YAML file that contains object store configuration.
|
||||
@@ -225,7 +221,7 @@ let
|
||||
objstore.config =
|
||||
{
|
||||
toArgs = _opt: _attrs: [];
|
||||
option = nullOpt types.attrs ''
|
||||
option = nullOpt format.type ''
|
||||
Object store configuration.
|
||||
|
||||
When not `null` the attribute set gets converted to
|
||||
|
||||
@@ -218,6 +218,7 @@ in
|
||||
in
|
||||
lib.nameValuePair "tahoe.introducer-${node}" {
|
||||
description = "Tahoe LAFS node ${node}";
|
||||
documentation = [ "info:tahoe-lafs" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ settings.package ];
|
||||
restartTriggers = [
|
||||
@@ -329,6 +330,7 @@ in
|
||||
in
|
||||
lib.nameValuePair "tahoe.${node}" {
|
||||
description = "Tahoe LAFS node ${node}";
|
||||
documentation = [ "info:tahoe-lafs" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ settings.package ];
|
||||
restartTriggers = [
|
||||
|
||||
@@ -305,6 +305,12 @@ in
|
||||
description = "Avahi mDNS/DNS-SD Stack";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
requires = [ "avahi-daemon.socket" ];
|
||||
documentation = [
|
||||
"man:avahi-daemon(8)"
|
||||
"man:avahi-daemon.conf(5)"
|
||||
"man:avahi.hosts(5)"
|
||||
"man:avahi.service(5)"
|
||||
];
|
||||
|
||||
# Make NSS modules visible so that `avahi_nss_support ()' can
|
||||
# return a sensible value.
|
||||
|
||||
@@ -10,9 +10,11 @@ let
|
||||
certificateFile = lib.mkOption {
|
||||
type = with lib.types; nullOr path;
|
||||
description = ''
|
||||
Cert.pem file.
|
||||
Account certificate file, necessary to create, delete and manage tunnels. It can be obtained by running `cloudflared login`.
|
||||
|
||||
See [Cert.pem](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-useful-terms/#certpem).
|
||||
Note that this is **necessary** for a fully declarative set up, as routes can not otherwise be created outside of the Cloudflare interface.
|
||||
|
||||
See [Cert.pem](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-useful-terms/#certpem) for information about the file, and [Tunnel permissions](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/local-management/tunnel-permissions/) for a comparison between the account certificate and the tunnel credentials file.
|
||||
'';
|
||||
default = null;
|
||||
};
|
||||
@@ -301,12 +303,6 @@ in
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = lib.mapAttrsToList (name: tunnel: {
|
||||
assertion =
|
||||
tunnel.ingress == { } || (cfg.certificateFile != null || tunnel.certificateFile != null);
|
||||
message = "Cloudflare Tunnel ${name} has a declarative configuration, but no certificate file was defined.";
|
||||
}) cfg.tunnels;
|
||||
|
||||
systemd.targets = lib.mapAttrs' (
|
||||
name: tunnel:
|
||||
lib.nameValuePair "cloudflared-tunnel-${name}" {
|
||||
|
||||
@@ -209,6 +209,8 @@ in
|
||||
in
|
||||
{ description = "DHCP Client";
|
||||
|
||||
documentation = [ "man:dhcpcd(8)" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ] ++ lib.optional (!hasDefaultGatewaySet) "network-online.target";
|
||||
wants = [ "network.target" "resolvconf.service" ];
|
||||
after = [ "resolvconf.service" ];
|
||||
|
||||
@@ -149,6 +149,7 @@ in
|
||||
|
||||
systemd.services.gnunet = {
|
||||
description = "GNUnet";
|
||||
documentation = [ "info:gnunet" ];
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
restartTriggers = [ config.environment.etc."gnunet.conf".source ];
|
||||
|
||||
@@ -114,6 +114,10 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.gvpe = {
|
||||
description = "GNU Virtual Private Ethernet node";
|
||||
documentation = [
|
||||
"info:gvpe"
|
||||
"man:gvpe(8)"
|
||||
];
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ let
|
||||
nativeBuildInputs = [ nats-server ];
|
||||
}
|
||||
''
|
||||
nats-server --config "${configFile}" -t
|
||||
ln -s "${configFile}" "$out"
|
||||
nats-server --config "${file}" -t
|
||||
ln -s "${file}" "$out"
|
||||
''
|
||||
) { };
|
||||
|
||||
|
||||
@@ -4,25 +4,8 @@ let
|
||||
cfg = cfgs.ncdns;
|
||||
|
||||
dataDir = "/var/lib/ncdns";
|
||||
username = "ncdns";
|
||||
|
||||
valueType = with lib.types; oneOf [ int str bool path ]
|
||||
// { description = "setting type (integer, string, bool or path)"; };
|
||||
|
||||
configType = with lib.types; attrsOf (nullOr (either valueType configType))
|
||||
// { description = ''
|
||||
ncdns.conf configuration type. The format consists of an
|
||||
attribute set of settings. Each setting can be either `null`,
|
||||
a value or an attribute set. The allowed values are integers,
|
||||
strings, booleans or paths.
|
||||
'';
|
||||
};
|
||||
|
||||
configFile = pkgs.runCommand "ncdns.conf"
|
||||
{ json = builtins.toJSON cfg.settings;
|
||||
passAsFile = [ "json" ];
|
||||
}
|
||||
"${pkgs.remarshal}/bin/json2toml < $jsonPath > $out";
|
||||
format = pkgs.formats.toml {};
|
||||
|
||||
defaultFiles = {
|
||||
public = "${dataDir}/bit.key";
|
||||
@@ -35,7 +18,7 @@ let
|
||||
needsKeygen = lib.all lib.id (lib.flip lib.mapAttrsToList cfg.dnssec.keys
|
||||
(n: v: v == lib.getAttr n defaultFiles));
|
||||
|
||||
mkDefaultAttrs = lib.mapAttrs (n: v: lib.mkDefault v);
|
||||
mkDefaultAttrs = lib.mapAttrs (_n: v: lib.mkDefault v);
|
||||
|
||||
in
|
||||
|
||||
@@ -160,7 +143,7 @@ in
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = configType;
|
||||
type = format.type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{ # enable webserver
|
||||
@@ -257,7 +240,7 @@ in
|
||||
User = "ncdns";
|
||||
StateDirectory = "ncdns";
|
||||
Restart = "on-failure";
|
||||
ExecStart = "${pkgs.ncdns}/bin/ncdns -conf=${configFile}";
|
||||
ExecStart = "${pkgs.ncdns}/bin/ncdns -conf=${format.generate "ncdns.conf" cfg.settings}";
|
||||
};
|
||||
|
||||
preStart = lib.optionalString (cfg.dnssec.enable && needsKeygen) ''
|
||||
|
||||
@@ -229,6 +229,7 @@ in
|
||||
|
||||
systemd.services.privoxy = {
|
||||
description = "Filtering web proxy";
|
||||
documentation = [ "man:privoxy(8)" ];
|
||||
after = [
|
||||
"network.target"
|
||||
"nss-lookup.target"
|
||||
|
||||
@@ -11,6 +11,7 @@ let
|
||||
(builtins.toJSON cfg.settings);
|
||||
|
||||
limiterSettingsFile = (pkgs.formats.toml { }).generate "limiter.toml" cfg.limiterSettings;
|
||||
faviconsSettingsFile = (pkgs.formats.toml { }).generate "favicons.toml" cfg.faviconsSettings;
|
||||
|
||||
generateConfig = ''
|
||||
cd ${runDir}
|
||||
@@ -143,6 +144,35 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
faviconsSettings = mkOption {
|
||||
type = types.attrsOf settingType;
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
favicons = {
|
||||
cfg_schema = 1;
|
||||
cache = {
|
||||
db_url = "/run/searx/faviconcache.db";
|
||||
HOLD_TIME = 5184000;
|
||||
LIMIT_TOTAL_BYTES = 2147483648;
|
||||
BLOB_MAX_BYTES = 40960;
|
||||
MAINTENANCE_MODE = "auto";
|
||||
MAINTENANCE_PERIOD = 600;
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Favicons settings for SearXNG.
|
||||
|
||||
::: {.note}
|
||||
For available settings, see the SearXNG
|
||||
[schema file](https://github.com/searxng/searxng/blob/master/searx/favicons/favicons.toml).
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
package = mkPackageOption pkgs "searxng" { };
|
||||
|
||||
runInUwsgi = mkOption {
|
||||
@@ -263,8 +293,13 @@ in
|
||||
port = 0;
|
||||
};
|
||||
|
||||
environment.etc."searxng/limiter.toml" = lib.mkIf (cfg.limiterSettings != { }) {
|
||||
source = limiterSettingsFile;
|
||||
environment.etc = {
|
||||
"searxng/limiter.toml" = lib.mkIf (cfg.limiterSettings != { }) {
|
||||
source = limiterSettingsFile;
|
||||
};
|
||||
"searxng/favicons.toml" = lib.mkIf (cfg.faviconsSettings != { }) {
|
||||
source = faviconsSettingsFile;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ in
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
documentation = [ "man:soju(1)" ];
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
Restart = "always";
|
||||
|
||||
@@ -366,6 +366,10 @@ in
|
||||
("tinc.${network}")
|
||||
(let version = getVersion data.package; in {
|
||||
description = "Tinc Daemon - ${network}";
|
||||
documentation = [
|
||||
"info:tinc"
|
||||
"man:tincd(8)"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ data.package ];
|
||||
reloadTriggers = mkIf (versionAtLeast version "1.1pre") [ (builtins.toJSON etcConfig) ];
|
||||
|
||||
@@ -82,6 +82,7 @@ in
|
||||
|
||||
systemd.services.atd = {
|
||||
description = "Job Execution Daemon (atd)";
|
||||
documentation = [ "man:atd(8)" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = [ at ];
|
||||
|
||||
@@ -169,6 +169,7 @@ in
|
||||
|
||||
systemd.services.clamav-daemon = lib.mkIf cfg.daemon.enable {
|
||||
description = "ClamAV daemon (clamd)";
|
||||
documentation = [ "man:clamd(8)" ];
|
||||
after = lib.optionals cfg.updater.enable [ "clamav-freshclam.service" ];
|
||||
wants = lib.optionals cfg.updater.enable [ "clamav-freshclam.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
@@ -199,6 +200,7 @@ in
|
||||
|
||||
systemd.services.clamav-freshclam = lib.mkIf cfg.updater.enable {
|
||||
description = "ClamAV virus database updater (freshclam)";
|
||||
documentation = [ "man:freshclam(1)" ];
|
||||
restartTriggers = [ freshclamConfigFile ];
|
||||
requires = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
@@ -276,6 +278,7 @@ in
|
||||
|
||||
systemd.services.clamdscan = lib.mkIf cfg.scanner.enable {
|
||||
description = "ClamAV virus scanner";
|
||||
documentation = [ "man:clamdscan(1)" ];
|
||||
after = lib.optionals cfg.updater.enable [ "clamav-freshclam.service" ];
|
||||
wants = lib.optionals cfg.updater.enable [ "clamav-freshclam.service" ];
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.endlessh = {
|
||||
description = "SSH tarpit";
|
||||
documentation = [ "man:endlessh(1)" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig =
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
# This module defines global configuration for Haka.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
|
||||
cfg = config.services.haka;
|
||||
|
||||
haka = cfg.package;
|
||||
|
||||
hakaConf = pkgs.writeText "haka.conf" ''
|
||||
[general]
|
||||
configuration = ${
|
||||
if lib.strings.hasPrefix "/" cfg.configFile then
|
||||
"${cfg.configFile}"
|
||||
else
|
||||
"${haka}/share/haka/sample/${cfg.configFile}"
|
||||
}
|
||||
${lib.optionalString (builtins.lessThan 0 cfg.threads) "thread = ${cfg.threads}"}
|
||||
|
||||
[packet]
|
||||
${lib.optionalString cfg.pcap ''module = "packet/pcap"''}
|
||||
${lib.optionalString cfg.nfqueue ''module = "packet/nqueue"''}
|
||||
${lib.optionalString cfg.dump.enable ''dump = "yes"''}
|
||||
${lib.optionalString cfg.dump.enable ''dump_input = "${cfg.dump.input}"''}
|
||||
${lib.optionalString cfg.dump.enable ''dump_output = "${cfg.dump.output}"''}
|
||||
|
||||
interfaces = "${lib.strings.concatStringsSep "," cfg.interfaces}"
|
||||
|
||||
[log]
|
||||
# Select the log module
|
||||
module = "log/syslog"
|
||||
|
||||
# Set the default logging level
|
||||
#level = "info,packet=debug"
|
||||
|
||||
[alert]
|
||||
# Select the alert module
|
||||
module = "alert/syslog"
|
||||
|
||||
# Disable alert on standard output
|
||||
#alert_on_stdout = no
|
||||
|
||||
# alert/file module option
|
||||
#file = "/dev/null"
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.haka = {
|
||||
|
||||
enable = lib.mkEnableOption "Haka";
|
||||
|
||||
package = lib.mkPackageOption pkgs "haka" { };
|
||||
|
||||
configFile = lib.mkOption {
|
||||
default = "empty.lua";
|
||||
example = "/srv/haka/myfilter.lua";
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Specify which configuration file Haka uses.
|
||||
It can be absolute path or a path relative to the sample directory of
|
||||
the haka git repo.
|
||||
'';
|
||||
};
|
||||
|
||||
interfaces = lib.mkOption {
|
||||
default = [ "eth0" ];
|
||||
example = [ "any" ];
|
||||
type = with lib.types; listOf str;
|
||||
description = ''
|
||||
Specify which interface(s) Haka listens to.
|
||||
Use 'any' to listen to all interfaces.
|
||||
'';
|
||||
};
|
||||
|
||||
threads = lib.mkOption {
|
||||
default = 0;
|
||||
example = 4;
|
||||
type = lib.types.int;
|
||||
description = ''
|
||||
The number of threads that will be used.
|
||||
All system threads are used by default.
|
||||
'';
|
||||
};
|
||||
|
||||
pcap = lib.mkOption {
|
||||
default = true;
|
||||
type = lib.types.bool;
|
||||
description = "Whether to enable pcap";
|
||||
};
|
||||
|
||||
nfqueue = lib.mkEnableOption "nfqueue";
|
||||
|
||||
dump.enable = lib.mkEnableOption "dump";
|
||||
dump.input = lib.mkOption {
|
||||
default = "/tmp/input.pcap";
|
||||
example = "/path/to/file.pcap";
|
||||
type = lib.types.path;
|
||||
description = "Path to file where incoming packets are dumped";
|
||||
};
|
||||
|
||||
dump.output = lib.mkOption {
|
||||
default = "/tmp/output.pcap";
|
||||
example = "/path/to/file.pcap";
|
||||
type = lib.types.path;
|
||||
description = "Path to file where outgoing packets are dumped";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
###### implementation
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.pcap != cfg.nfqueue;
|
||||
message = "either pcap or nfqueue can be enabled, not both.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.nfqueue -> !cfg.dump.enable;
|
||||
message = "dump can only be used with nfqueue.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.interfaces != [ ];
|
||||
message = "at least one interface must be specified.";
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = [ haka ];
|
||||
|
||||
systemd.services.haka = {
|
||||
description = "Haka";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${haka}/bin/haka -c ${hakaConf}";
|
||||
ExecStop = "${haka}/bin/hakactl stop";
|
||||
User = "root";
|
||||
Type = "forking";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -790,12 +790,12 @@ in
|
||||
++ concatLists (
|
||||
flip mapAttrsToList (filterPresent cfg.provision.systems.oauth2) (
|
||||
oauth2: oauth2Cfg:
|
||||
(optionals (cfg.provision.extraJsonFile == null) (
|
||||
(optional (cfg.provision.extraJsonFile == null) (
|
||||
assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.scopeMaps" (
|
||||
attrNames oauth2Cfg.scopeMaps
|
||||
)
|
||||
))
|
||||
++ (optionals (cfg.provision.extraJsonFile == null) (
|
||||
++ (optional (cfg.provision.extraJsonFile == null) (
|
||||
assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.supplementaryScopeMaps" (
|
||||
attrNames oauth2Cfg.supplementaryScopeMaps
|
||||
)
|
||||
|
||||
@@ -46,6 +46,10 @@ in
|
||||
users.groups.munge = { };
|
||||
|
||||
systemd.services.munged = {
|
||||
documentation = [
|
||||
"man:munged(8)"
|
||||
"man:mungekey(8)"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [
|
||||
"network-online.target"
|
||||
|
||||
@@ -116,6 +116,7 @@ in
|
||||
|
||||
systemd.services.physlock = {
|
||||
enable = true;
|
||||
documentation = [ "man:physlock(1)" ];
|
||||
description = "Physlock";
|
||||
wantedBy =
|
||||
lib.optional cfg.lockOn.suspend "suspend.target"
|
||||
|
||||
@@ -119,6 +119,7 @@ in
|
||||
{
|
||||
sks-db = {
|
||||
description = "SKS database server";
|
||||
documentation = [ "man:sks(8)" ];
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
preStart = ''
|
||||
|
||||
@@ -1324,6 +1324,7 @@ in
|
||||
|
||||
systemd.services.tor = {
|
||||
description = "Tor Daemon";
|
||||
documentation = [ "man:tor(8)" ];
|
||||
path = [ pkgs.tor ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
@@ -95,7 +95,7 @@ let
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
description = "Akkoma frontend package.";
|
||||
example = literalExpression "pkgs.akkoma-frontends.akkoma-fe";
|
||||
example = literalExpression "pkgs.akkoma-fe";
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
@@ -520,12 +520,12 @@ in {
|
||||
type = with types; attrsOf (submodule frontend);
|
||||
default = {
|
||||
primary = {
|
||||
package = pkgs.akkoma-frontends.akkoma-fe;
|
||||
package = pkgs.akkoma-fe;
|
||||
name = "akkoma-fe";
|
||||
ref = "stable";
|
||||
};
|
||||
admin = {
|
||||
package = pkgs.akkoma-frontends.admin-fe;
|
||||
package = pkgs.akkoma-admin-fe;
|
||||
name = "admin-fe";
|
||||
ref = "stable";
|
||||
};
|
||||
@@ -533,12 +533,12 @@ in {
|
||||
defaultText = literalExpression ''
|
||||
{
|
||||
primary = {
|
||||
package = pkgs.akkoma-frontends.akkoma-fe;
|
||||
package = pkgs.akkoma-fe;
|
||||
name = "akkoma-fe";
|
||||
ref = "stable";
|
||||
};
|
||||
admin = {
|
||||
package = pkgs.akkoma-frontends.admin-fe;
|
||||
package = pkgs.akkoma-admin-fe;
|
||||
name = "admin-fe";
|
||||
ref = "stable";
|
||||
};
|
||||
@@ -557,7 +557,7 @@ in {
|
||||
default = null;
|
||||
example = literalExpression ''
|
||||
{
|
||||
"emoji/blobs.gg" = pkgs.akkoma-emoji.blobs_gg;
|
||||
"emoji/blobs.gg" = pkgs.blobs_gg;
|
||||
"static/terms-of-service.html" = pkgs.writeText "terms-of-service.html" '''
|
||||
…
|
||||
''';
|
||||
|
||||
@@ -73,7 +73,7 @@ in
|
||||
default = null;
|
||||
example = "/run/secrets/changedetection-io.env";
|
||||
description = ''
|
||||
Securely pass environment variabels to changedetection-io.
|
||||
Securely pass environment variables to changedetection-io.
|
||||
|
||||
This can be used to set for example a frontend password reproducible via `SALTED_PASS`
|
||||
which convinetly also deactivates nags about the hosted version.
|
||||
|
||||
@@ -196,6 +196,10 @@ in
|
||||
}
|
||||
];
|
||||
|
||||
systemd.services."phpfpm-flarum" = {
|
||||
restartTriggers = [ cfg.package ];
|
||||
};
|
||||
|
||||
systemd.services.flarum-install = {
|
||||
description = "Flarum installation";
|
||||
requiredBy = [ "phpfpm-flarum.service" ];
|
||||
|
||||
@@ -128,7 +128,11 @@ in
|
||||
in
|
||||
{
|
||||
description = "hledger-web - web-app for the hledger accounting tool.";
|
||||
documentation = [ "https://hledger.org/hledger-web.html" ];
|
||||
documentation = [
|
||||
"info:hledger-web"
|
||||
"man:hledger-web(1)"
|
||||
"https://hledger.org/hledger-web.html"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "networking.target" ];
|
||||
serviceConfig = mkMerge [
|
||||
|
||||
@@ -195,7 +195,7 @@ in {
|
||||
affect other virtualHosts running on your nginx instance, if any.
|
||||
Alternatively you can configure a reverse-proxy of your choice to serve these paths:
|
||||
|
||||
`/ -> $(nix-instantiate --eval '<nixpkgs>' -A mastodon.outPath)/public`
|
||||
`/ -> ''${pkgs.mastodon}/public`
|
||||
|
||||
`/ -> 127.0.0.1:{{ webPort }} `(If there was no file in the directory above.)
|
||||
|
||||
@@ -324,6 +324,21 @@ in {
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
vapidPrivateKeyFile = lib.mkOption {
|
||||
description = ''
|
||||
Path to file containing the private key used for Web Push
|
||||
Voluntary Application Server Identification. A new keypair can
|
||||
be generated by running:
|
||||
|
||||
`nix build -f '<nixpkgs>' mastodon; cd result; bin/rake webpush:generate_keys`
|
||||
|
||||
If this file does not exist, it will be created with a new
|
||||
private key.
|
||||
'';
|
||||
default = "/var/lib/mastodon/secrets/vapid-private-key";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
localDomain = lib.mkOption {
|
||||
description = "The domain serving your Mastodon instance.";
|
||||
example = "social.example.org";
|
||||
@@ -401,21 +416,6 @@ in {
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
vapidPrivateKeyFile = lib.mkOption {
|
||||
description = ''
|
||||
Path to file containing the private key used for Web Push
|
||||
Voluntary Application Server Identification. A new keypair can
|
||||
be generated by running:
|
||||
|
||||
`nix build -f '<nixpkgs>' mastodon; cd result; bin/rake webpush:generate_keys`
|
||||
|
||||
If this file does not exist, it will be created with a new
|
||||
private key.
|
||||
'';
|
||||
default = "/var/lib/mastodon/secrets/vapid-private-key";
|
||||
type = lib.types.str;
|
||||
};
|
||||
|
||||
trustedProxy = lib.mkOption {
|
||||
description = ''
|
||||
You need to set it to the IP from which your reverse proxy sends requests to Mastodon's web process,
|
||||
@@ -945,6 +945,7 @@ in {
|
||||
enable = true;
|
||||
hostname = lib.mkDefault "${cfg.localDomain}";
|
||||
};
|
||||
|
||||
services.redis.servers.mastodon = lib.mkIf redisActuallyCreateLocally (lib.mkMerge [
|
||||
{
|
||||
enable = true;
|
||||
@@ -953,6 +954,7 @@ in {
|
||||
port = cfg.redis.port;
|
||||
})
|
||||
]);
|
||||
|
||||
services.postgresql = lib.mkIf databaseActuallyCreateLocally {
|
||||
enable = true;
|
||||
ensureUsers = [
|
||||
|
||||
@@ -282,6 +282,7 @@ in {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
Environment = ["DOTNET_USE_POLLING_FILE_WATCHER=1"];
|
||||
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
|
||||
StateDirectory = "slskd"; # Creates /var/lib/slskd and manages permissions
|
||||
ExecStart = "${cfg.package}/bin/slskd --app-dir /var/lib/slskd --config ${configurationYaml}";
|
||||
|
||||
@@ -254,6 +254,7 @@ in {
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "phpfpm.target" ];
|
||||
partOf = [ "phpfpm.target" ];
|
||||
documentation = [ "man:php-fpm(8)" ];
|
||||
serviceConfig = let
|
||||
cfgFile = fpmCfgFile pool poolOpts;
|
||||
iniFile = phpIni poolOpts;
|
||||
|
||||
@@ -4,48 +4,18 @@ with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.traefik;
|
||||
jsonValue = with types;
|
||||
let
|
||||
valueType = nullOr (oneOf [
|
||||
bool
|
||||
int
|
||||
float
|
||||
str
|
||||
(lazyAttrsOf valueType)
|
||||
(listOf valueType)
|
||||
]) // {
|
||||
description = "JSON value";
|
||||
emptyValue.value = { };
|
||||
};
|
||||
in valueType;
|
||||
|
||||
format = pkgs.formats.toml {};
|
||||
|
||||
dynamicConfigFile = if cfg.dynamicConfigFile == null then
|
||||
pkgs.runCommand "config.toml" {
|
||||
buildInputs = [ pkgs.remarshal ];
|
||||
preferLocalBuild = true;
|
||||
} ''
|
||||
remarshal -if json -of toml \
|
||||
< ${
|
||||
pkgs.writeText "dynamic_config.json"
|
||||
(builtins.toJSON cfg.dynamicConfigOptions)
|
||||
} \
|
||||
> $out
|
||||
''
|
||||
format.generate "config.toml" cfg.dynamicConfigOptions
|
||||
else
|
||||
cfg.dynamicConfigFile;
|
||||
|
||||
staticConfigFile = if cfg.staticConfigFile == null then
|
||||
pkgs.runCommand "config.toml" {
|
||||
buildInputs = [ pkgs.yj ];
|
||||
preferLocalBuild = true;
|
||||
} ''
|
||||
yj -jt -i \
|
||||
< ${
|
||||
pkgs.writeText "static_config.json" (builtins.toJSON
|
||||
(recursiveUpdate cfg.staticConfigOptions {
|
||||
providers.file.filename = "${dynamicConfigFile}";
|
||||
}))
|
||||
} \
|
||||
> $out
|
||||
''
|
||||
format.generate "config.toml" (recursiveUpdate cfg.staticConfigOptions {
|
||||
providers.file.filename = "${dynamicConfigFile}";
|
||||
})
|
||||
else
|
||||
cfg.staticConfigFile;
|
||||
|
||||
@@ -71,7 +41,7 @@ in {
|
||||
description = ''
|
||||
Static configuration for Traefik.
|
||||
'';
|
||||
type = jsonValue;
|
||||
type = format.type;
|
||||
default = { entryPoints.http.address = ":80"; };
|
||||
example = {
|
||||
entryPoints.web.address = ":8080";
|
||||
@@ -95,7 +65,7 @@ in {
|
||||
description = ''
|
||||
Dynamic configuration for Traefik.
|
||||
'';
|
||||
type = jsonValue;
|
||||
type = format.type;
|
||||
default = { };
|
||||
example = {
|
||||
http.routers.router1 = {
|
||||
|
||||
@@ -33,19 +33,8 @@ let
|
||||
c.plugins or cfg.plugins;
|
||||
plugins = unique plugins';
|
||||
|
||||
hasPython = v: filter (n: n == "python${v}") plugins != [ ];
|
||||
hasPython2 = hasPython "2";
|
||||
hasPython3 = hasPython "3";
|
||||
|
||||
python =
|
||||
if hasPython2 && hasPython3 then
|
||||
throw "`plugins` attribute in uWSGI configuration shouldn't contain both python2 and python3"
|
||||
else if hasPython2 then
|
||||
cfg.package.python2
|
||||
else if hasPython3 then
|
||||
cfg.package.python3
|
||||
else
|
||||
null;
|
||||
hasPython3 = filter (n: n == "python3") plugins != [ ];
|
||||
python = if hasPython3 then cfg.package.python3 else null;
|
||||
|
||||
pythonEnv = python.withPackages (c.pythonPackages or (self: [ ]));
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ let
|
||||
cfg = config.systemd.repart;
|
||||
initrdCfg = config.boot.initrd.systemd.repart;
|
||||
|
||||
format = pkgs.formats.ini { };
|
||||
format = pkgs.formats.ini { listsAsDuplicateKeys = true; };
|
||||
|
||||
definitionsDirectory = utils.systemdUtils.lib.definitions "repart.d" format (
|
||||
lib.mapAttrs (_n: v: { Partition = v; }) cfg.partitions
|
||||
@@ -93,6 +93,7 @@ in
|
||||
str
|
||||
int
|
||||
bool
|
||||
(listOf str)
|
||||
])
|
||||
);
|
||||
default = { };
|
||||
|
||||
@@ -166,6 +166,7 @@ in
|
||||
in
|
||||
nameValuePair "btrfs-scrub-${fs'}" {
|
||||
description = "btrfs scrub on ${fs}";
|
||||
documentation = [ "man:btrfs-scrub(8)" ];
|
||||
# scrub prevents suspend2ram or proper shutdown
|
||||
conflicts = [
|
||||
"shutdown.target"
|
||||
|
||||
@@ -51,6 +51,7 @@ in
|
||||
config = mkIf (cfg.enable) {
|
||||
systemd.services = {
|
||||
powertop = {
|
||||
documentation = [ "man:powertop(8)" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "multi-user.target" ];
|
||||
description = "Powertop tunings";
|
||||
|
||||
@@ -159,6 +159,34 @@ in
|
||||
which the prune will occur.
|
||||
'';
|
||||
};
|
||||
|
||||
randomizedDelaySec = mkOption {
|
||||
default = "0";
|
||||
type = types.singleLineStr;
|
||||
example = "45min";
|
||||
description = ''
|
||||
Add a randomized delay before each auto prune.
|
||||
The delay will be chosen between zero and this value.
|
||||
This value must be a time span in the format specified by
|
||||
{manpage}`systemd.time(7)`
|
||||
'';
|
||||
};
|
||||
|
||||
persistent = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
example = false;
|
||||
description = ''
|
||||
Takes a boolean argument. If true, the time when the service
|
||||
unit was last triggered is stored on disk. When the timer is
|
||||
activated, the service unit is triggered immediately if it
|
||||
would have been triggered at least once during the time when
|
||||
the timer was inactive. Such triggering is nonetheless
|
||||
subject to the delay imposed by RandomizedDelaySec=. This is
|
||||
useful to catch up on missed runs of the service when the
|
||||
system was powered down.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
package = mkPackageOption pkgs "docker" { };
|
||||
@@ -254,6 +282,13 @@ in
|
||||
requires = [ "docker.service" ];
|
||||
};
|
||||
|
||||
systemd.timers.docker-prune = mkIf cfg.autoPrune.enable {
|
||||
timerConfig = {
|
||||
RandomizedDelaySec = cfg.autoPrune.randomizedDelaySec;
|
||||
Persistent = cfg.autoPrune.persistent;
|
||||
};
|
||||
};
|
||||
|
||||
assertions = [
|
||||
{ assertion = cfg.enableNvidia && pkgs.stdenv.hostPlatform.isx86_64 -> config.hardware.graphics.enable32Bit or false;
|
||||
message = "Option enableNvidia on x86_64 requires 32-bit support libraries";
|
||||
|
||||
@@ -87,7 +87,7 @@ with lib;
|
||||
# ec2-get-console-output.
|
||||
echo "-----BEGIN SSH HOST KEY FINGERPRINTS-----" > /dev/console
|
||||
for i in /etc/ssh/ssh_host_*_key.pub; do
|
||||
${config.programs.ssh.package}/bin/ssh-keygen -l -f "$i" || true > /dev/console
|
||||
${config.programs.ssh.package}/bin/ssh-keygen -l -f "$i" > /dev/console || true
|
||||
done
|
||||
echo "-----END SSH HOST KEY FINGERPRINTS-----" > /dev/console
|
||||
'';
|
||||
|
||||
@@ -363,7 +363,7 @@ in
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Weither to configure OpenSSH to use the [SSH Proxy](https://libvirt.org/ssh-proxy.html).
|
||||
Whether to configure OpenSSH to use the [SSH Proxy](https://libvirt.org/ssh-proxy.html).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
+43
-46
@@ -1,58 +1,55 @@
|
||||
import ./make-test-python.nix (
|
||||
{ ... }:
|
||||
{
|
||||
name = "acme-dns";
|
||||
{
|
||||
name = "acme-dns";
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.acme-dns = {
|
||||
enable = true;
|
||||
settings = {
|
||||
general = rec {
|
||||
domain = "acme-dns.home.arpa";
|
||||
nsname = domain;
|
||||
nsadmin = "admin.home.arpa";
|
||||
records = [
|
||||
"${domain}. A 127.0.0.1"
|
||||
"${domain}. AAAA ::1"
|
||||
"${domain}. NS ${domain}."
|
||||
];
|
||||
};
|
||||
logconfig.loglevel = "debug";
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.acme-dns = {
|
||||
enable = true;
|
||||
settings = {
|
||||
general = rec {
|
||||
domain = "acme-dns.home.arpa";
|
||||
nsname = domain;
|
||||
nsadmin = "admin.home.arpa";
|
||||
records = [
|
||||
"${domain}. A 127.0.0.1"
|
||||
"${domain}. AAAA ::1"
|
||||
"${domain}. NS ${domain}."
|
||||
];
|
||||
};
|
||||
logconfig.loglevel = "debug";
|
||||
};
|
||||
environment.systemPackages = with pkgs; [
|
||||
curl
|
||||
bind
|
||||
];
|
||||
};
|
||||
environment.systemPackages = with pkgs; [
|
||||
curl
|
||||
bind
|
||||
];
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import json
|
||||
testScript = ''
|
||||
import json
|
||||
|
||||
machine.wait_for_unit("acme-dns.service")
|
||||
machine.wait_for_open_port(53) # dns
|
||||
machine.wait_for_open_port(8080) # http api
|
||||
machine.wait_for_unit("acme-dns.service")
|
||||
machine.wait_for_open_port(53) # dns
|
||||
machine.wait_for_open_port(8080) # http api
|
||||
|
||||
result = machine.succeed("curl --fail -X POST http://localhost:8080/register")
|
||||
print(result)
|
||||
result = machine.succeed("curl --fail -X POST http://localhost:8080/register")
|
||||
print(result)
|
||||
|
||||
registration = json.loads(result)
|
||||
registration = json.loads(result)
|
||||
|
||||
machine.succeed(f'dig -t TXT @localhost {registration["fulldomain"]} | grep "SOA" | grep "admin.home.arpa"')
|
||||
machine.succeed(f'dig -t TXT @localhost {registration["fulldomain"]} | grep "SOA" | grep "admin.home.arpa"')
|
||||
|
||||
# acme-dns exspects a TXT value string length of exactly 43 chars
|
||||
txt = "___dummy_validation_token_for_txt_record___"
|
||||
# acme-dns exspects a TXT value string length of exactly 43 chars
|
||||
txt = "___dummy_validation_token_for_txt_record___"
|
||||
|
||||
machine.succeed(
|
||||
"curl --fail -X POST http://localhost:8080/update "
|
||||
+ f' -H "X-Api-User: {registration["username"]}"'
|
||||
+ f' -H "X-Api-Key: {registration["password"]}"'
|
||||
+ f' -d \'{{"subdomain":"{registration["subdomain"]}", "txt":"{txt}"}}\'''
|
||||
)
|
||||
machine.succeed(
|
||||
"curl --fail -X POST http://localhost:8080/update "
|
||||
+ f' -H "X-Api-User: {registration["username"]}"'
|
||||
+ f' -H "X-Api-Key: {registration["password"]}"'
|
||||
+ f' -d \'{{"subdomain":"{registration["subdomain"]}", "txt":"{txt}"}}\'''
|
||||
)
|
||||
|
||||
assert txt in machine.succeed(f'dig -t TXT +short @localhost {registration["fulldomain"]}')
|
||||
'';
|
||||
}
|
||||
)
|
||||
assert txt in machine.succeed(f'dig -t TXT +short @localhost {registration["fulldomain"]}')
|
||||
'';
|
||||
}
|
||||
|
||||
+14
-16
@@ -1,18 +1,16 @@
|
||||
import ./make-test-python.nix (
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "actual";
|
||||
meta.maintainers = [ lib.maintainers.oddlama ];
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "actual";
|
||||
meta.maintainers = [ lib.maintainers.oddlama ];
|
||||
|
||||
nodes.machine =
|
||||
{ ... }:
|
||||
{
|
||||
services.actual.enable = true;
|
||||
};
|
||||
nodes.machine =
|
||||
{ ... }:
|
||||
{
|
||||
services.actual.enable = true;
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_open_port(3000)
|
||||
machine.succeed("curl -fvvv -Ls http://localhost:3000/ | grep 'Actual'")
|
||||
'';
|
||||
}
|
||||
)
|
||||
testScript = ''
|
||||
machine.wait_for_open_port(3000)
|
||||
machine.succeed("curl -fvvv -Ls http://localhost:3000/ | grep 'Actual'")
|
||||
'';
|
||||
}
|
||||
|
||||
+41
-43
@@ -1,49 +1,47 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
hello-world = pkgs.writeText "hello-world" ''
|
||||
{-# OPTIONS --guardedness #-}
|
||||
open import IO
|
||||
open import Level
|
||||
let
|
||||
hello-world = pkgs.writeText "hello-world" ''
|
||||
{-# OPTIONS --guardedness #-}
|
||||
open import IO
|
||||
open import Level
|
||||
|
||||
main = run {0ℓ} (putStrLn "Hello World!")
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "agda";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [
|
||||
alexarice
|
||||
turion
|
||||
main = run {0ℓ} (putStrLn "Hello World!")
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "agda";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [
|
||||
alexarice
|
||||
turion
|
||||
];
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [
|
||||
(pkgs.agda.withPackages {
|
||||
pkgs = p: [ p.standard-library ];
|
||||
})
|
||||
];
|
||||
virtualisation.memorySize = 2000; # Agda uses a lot of memory
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [
|
||||
(pkgs.agda.withPackages {
|
||||
pkgs = p: [ p.standard-library ];
|
||||
})
|
||||
];
|
||||
virtualisation.memorySize = 2000; # Agda uses a lot of memory
|
||||
};
|
||||
testScript = ''
|
||||
# Minimal script that typechecks
|
||||
machine.succeed("touch TestEmpty.agda")
|
||||
machine.succeed("agda TestEmpty.agda")
|
||||
|
||||
testScript = ''
|
||||
# Minimal script that typechecks
|
||||
machine.succeed("touch TestEmpty.agda")
|
||||
machine.succeed("agda TestEmpty.agda")
|
||||
|
||||
# Hello world
|
||||
machine.succeed(
|
||||
"cp ${hello-world} HelloWorld.agda"
|
||||
)
|
||||
machine.succeed("agda -l standard-library -i . -c HelloWorld.agda")
|
||||
# Check execution
|
||||
assert "Hello World!" in machine.succeed(
|
||||
"./HelloWorld"
|
||||
), "HelloWorld does not run properly"
|
||||
'';
|
||||
}
|
||||
)
|
||||
# Hello world
|
||||
machine.succeed(
|
||||
"cp ${hello-world} HelloWorld.agda"
|
||||
)
|
||||
machine.succeed("agda -l standard-library -i . -c HelloWorld.agda")
|
||||
# Check execution
|
||||
assert "Hello World!" in machine.succeed(
|
||||
"./HelloWorld"
|
||||
), "HelloWorld does not run properly"
|
||||
'';
|
||||
}
|
||||
|
||||
+25
-27
@@ -1,32 +1,30 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "airsonic";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ sumnerevans ];
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "airsonic";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ sumnerevans ];
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.airsonic = {
|
||||
enable = true;
|
||||
maxMemory = 800;
|
||||
};
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.airsonic = {
|
||||
enable = true;
|
||||
maxMemory = 800;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
def airsonic_is_up(_) -> bool:
|
||||
status, _ = machine.execute("curl --fail http://localhost:4040/login")
|
||||
return status == 0
|
||||
testScript = ''
|
||||
def airsonic_is_up(_) -> bool:
|
||||
status, _ = machine.execute("curl --fail http://localhost:4040/login")
|
||||
return status == 0
|
||||
|
||||
|
||||
machine.start()
|
||||
machine.wait_for_unit("airsonic.service")
|
||||
machine.wait_for_open_port(4040)
|
||||
machine.start()
|
||||
machine.wait_for_unit("airsonic.service")
|
||||
machine.wait_for_open_port(4040)
|
||||
|
||||
with machine.nested("Waiting for UI to work"):
|
||||
retry(airsonic_is_up)
|
||||
'';
|
||||
}
|
||||
)
|
||||
with machine.nested("Waiting for UI to work"):
|
||||
retry(airsonic_is_up)
|
||||
'';
|
||||
}
|
||||
|
||||
+228
-132
@@ -1,149 +1,245 @@
|
||||
/*
|
||||
End-to-end test for Akkoma.
|
||||
# end‐to‐end test for Akkoma
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
confined ? false,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit ((pkgs.formats.elixirConf { }).lib) mkRaw;
|
||||
|
||||
Based in part on nixos/tests/pleroma.
|
||||
package = pkgs.akkoma;
|
||||
|
||||
TODO: Test federation.
|
||||
*/
|
||||
import ./make-test-python.nix (
|
||||
{
|
||||
pkgs,
|
||||
package ? pkgs.akkoma,
|
||||
confined ? false,
|
||||
...
|
||||
}:
|
||||
let
|
||||
userPassword = "4LKOrGo8SgbPm1a6NclVU5Wb";
|
||||
tlsCert =
|
||||
names:
|
||||
pkgs.runCommand "certificates-${lib.head names}"
|
||||
{
|
||||
nativeBuildInputs = with pkgs; [ openssl ];
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
openssl req -x509 \
|
||||
-subj '/CN=${lib.head names}/' -days 49710 \
|
||||
-addext 'subjectAltName = ${lib.concatStringsSep ", " (map (name: "DNS:${name}") names)}' \
|
||||
-keyout "$out/key.pem" -newkey ed25519 \
|
||||
-out "$out/cert.pem" -noenc
|
||||
'';
|
||||
|
||||
provisionUser = pkgs.writers.writeBashBin "provisionUser" ''
|
||||
set -eu -o errtrace -o pipefail
|
||||
tlsCertA = tlsCert [
|
||||
"akkoma-a.nixos.test"
|
||||
"media.akkoma-a.nixos.test"
|
||||
];
|
||||
|
||||
pleroma_ctl user new jamy jamy@nixos.test --password '${userPassword}' --moderator --admin -y
|
||||
'';
|
||||
tlsCertB = tlsCert [
|
||||
"akkoma-b.nixos.test"
|
||||
"media.akkoma-b.nixos.test"
|
||||
];
|
||||
|
||||
tlsCert =
|
||||
pkgs.runCommand "selfSignedCerts"
|
||||
{
|
||||
nativeBuildInputs = with pkgs; [ openssl ];
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
openssl req -x509 \
|
||||
-subj '/CN=akkoma.nixos.test/' -days 49710 \
|
||||
-addext 'subjectAltName = DNS:akkoma.nixos.test' \
|
||||
-keyout "$out/key.pem" -newkey ed25519 \
|
||||
-out "$out/cert.pem" -noenc
|
||||
'';
|
||||
|
||||
sendToot = pkgs.writers.writeBashBin "sendToot" ''
|
||||
set -eu -o errtrace -o pipefail
|
||||
|
||||
export REQUESTS_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
${pkgs.toot}/bin/toot login_cli -i "akkoma.nixos.test" -e "jamy@nixos.test" -p '${userPassword}'
|
||||
${pkgs.toot}/bin/toot post "hello world Jamy here"
|
||||
${pkgs.toot}/bin/toot timeline -1 | grep -F -q "hello world Jamy here"
|
||||
|
||||
# Test file upload
|
||||
echo "y" | ${pkgs.toot}/bin/toot upload <(dd if=/dev/zero bs=1024 count=1024 status=none) \
|
||||
| grep -F -q "https://akkoma.nixos.test:443/media"
|
||||
'';
|
||||
|
||||
checkFe = pkgs.writers.writeBashBin "checkFe" ''
|
||||
set -eu -o errtrace -o pipefail
|
||||
testMedia = pkgs.runCommand "blank.png" { nativeBuildInputs = with pkgs; [ imagemagick ]; } ''
|
||||
magick -size 640x480 canvas:transparent "PNG8:$out"
|
||||
'';
|
||||
|
||||
checkFe = pkgs.writeShellApplication {
|
||||
name = "checkFe";
|
||||
runtimeInputs = with pkgs; [ curl ];
|
||||
text = ''
|
||||
paths=( / /static/{config,styles}.json /pleroma/admin/ )
|
||||
|
||||
for path in "''${paths[@]}"; do
|
||||
diff \
|
||||
<(${pkgs.curl}/bin/curl -f -S -s -o /dev/null -w '%{response_code}' "https://akkoma.nixos.test$path") \
|
||||
<(curl -f -S -s -o /dev/null -w '%{response_code}' "https://$1$path") \
|
||||
<(echo -n 200)
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
hosts = nodes: ''
|
||||
${nodes.akkoma.networking.primaryIPAddress} akkoma.nixos.test
|
||||
${nodes.client.networking.primaryIPAddress} client.nixos.test
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "akkoma";
|
||||
nodes = {
|
||||
client =
|
||||
{
|
||||
nodes,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
security.pki.certificateFiles = [ "${tlsCert}/cert.pem" ];
|
||||
networking.extraHosts = hosts nodes;
|
||||
};
|
||||
commonConfig =
|
||||
{ nodes, ... }:
|
||||
{
|
||||
security.pki.certificateFiles = [
|
||||
"${tlsCertA}/cert.pem"
|
||||
"${tlsCertB}/cert.pem"
|
||||
];
|
||||
|
||||
akkoma =
|
||||
{
|
||||
nodes,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
networking.extraHosts = hosts nodes;
|
||||
networking.firewall.allowedTCPPorts = [ 443 ];
|
||||
environment.systemPackages = with pkgs; [ provisionUser ];
|
||||
systemd.services.akkoma.confinement.enable = confined;
|
||||
|
||||
services.akkoma = {
|
||||
enable = true;
|
||||
package = package;
|
||||
config = {
|
||||
":pleroma" = {
|
||||
":instance" = {
|
||||
name = "NixOS test Akkoma server";
|
||||
description = "NixOS test Akkoma server";
|
||||
email = "akkoma@nixos.test";
|
||||
notify_email = "akkoma@nixos.test";
|
||||
registration_open = true;
|
||||
};
|
||||
|
||||
":media_proxy" = {
|
||||
enabled = false;
|
||||
};
|
||||
|
||||
"Pleroma.Web.Endpoint" = {
|
||||
url.host = "akkoma.nixos.test";
|
||||
};
|
||||
"Pleroma.Upload" = {
|
||||
base_url = "https://akkoma.nixos.test:443/media/";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nginx = {
|
||||
addSSL = true;
|
||||
sslCertificate = "${tlsCert}/cert.pem";
|
||||
sslCertificateKey = "${tlsCert}/key.pem";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.postgresql.enable = true;
|
||||
};
|
||||
networking.extraHosts = ''
|
||||
${nodes.akkoma-a.networking.primaryIPAddress} akkoma-a.nixos.test media.akkoma-a.nixos.test
|
||||
${nodes.akkoma-b.networking.primaryIPAddress} akkoma-b.nixos.test media.akkoma-b.nixos.test
|
||||
${nodes.client-a.networking.primaryIPAddress} client-a.nixos.test
|
||||
${nodes.client-b.networking.primaryIPAddress} client-b.nixos.test
|
||||
'';
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
start_all()
|
||||
akkoma.wait_for_unit('akkoma-initdb.service')
|
||||
akkoma.systemctl('restart akkoma-initdb.service') # test repeated initialisation
|
||||
akkoma.wait_for_unit('akkoma.service')
|
||||
akkoma.wait_for_file('/run/akkoma/socket');
|
||||
akkoma.succeed('${provisionUser}/bin/provisionUser')
|
||||
akkoma.wait_for_unit('nginx.service')
|
||||
client.succeed('${sendToot}/bin/sendToot')
|
||||
client.succeed('${checkFe}/bin/checkFe')
|
||||
'';
|
||||
}
|
||||
)
|
||||
clientConfig =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment = {
|
||||
sessionVariables = {
|
||||
REQUESTS_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
|
||||
};
|
||||
systemPackages = with pkgs; [ toot ];
|
||||
};
|
||||
};
|
||||
|
||||
serverConfig =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
networking = {
|
||||
domain = "nixos.test";
|
||||
firewall.allowedTCPPorts = [ 443 ];
|
||||
};
|
||||
|
||||
systemd.services.akkoma.confinement.enable = confined;
|
||||
|
||||
services.akkoma = {
|
||||
enable = true;
|
||||
inherit package;
|
||||
config = {
|
||||
":pleroma" = {
|
||||
":instance" = {
|
||||
name = "NixOS test Akkoma server";
|
||||
description = "NixOS test Akkoma server";
|
||||
email = "akkoma@nixos.test";
|
||||
notify_email = "akkoma@nixos.test";
|
||||
registration_open = true;
|
||||
};
|
||||
|
||||
":media_proxy" = {
|
||||
enabled = false;
|
||||
};
|
||||
|
||||
"Pleroma.Web.Endpoint" = {
|
||||
url.host = config.networking.fqdn;
|
||||
};
|
||||
|
||||
"Pleroma.Upload" = {
|
||||
base_url = "https://media.${config.networking.fqdn}/media/";
|
||||
};
|
||||
|
||||
# disable certificate verification until we figure out how to
|
||||
# supply our own certificates
|
||||
":http".adapter.pools = mkRaw "%{default: [conn_opts: [transport_opts: [verify: :verify_none]]]}";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.addSSL = true;
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.postgresql.enable = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "akkoma";
|
||||
nodes = {
|
||||
client-a =
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
clientConfig
|
||||
commonConfig
|
||||
];
|
||||
};
|
||||
|
||||
client-b =
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
clientConfig
|
||||
commonConfig
|
||||
];
|
||||
};
|
||||
|
||||
akkoma-a =
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
commonConfig
|
||||
serverConfig
|
||||
];
|
||||
|
||||
services.akkoma.nginx = {
|
||||
sslCertificate = "${tlsCertA}/cert.pem";
|
||||
sslCertificateKey = "${tlsCertA}/key.pem";
|
||||
};
|
||||
};
|
||||
|
||||
akkoma-b =
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
commonConfig
|
||||
serverConfig
|
||||
];
|
||||
|
||||
services.akkoma.nginx = {
|
||||
sslCertificate = "${tlsCertB}/cert.pem";
|
||||
sslCertificateKey = "${tlsCertB}/key.pem";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
from shlex import quote
|
||||
|
||||
def randomString(len):
|
||||
return "".join(random.choice(string.ascii_letters + string.digits) for _ in range(len))
|
||||
|
||||
def registerUser(user, password):
|
||||
return 'pleroma_ctl user new {0} {0}@nixos.test --password {1} -y'.format(
|
||||
quote(user), quote(password))
|
||||
|
||||
def loginUser(instance, user, password):
|
||||
return 'toot login_cli -i {}.nixos.test -e {}@nixos.test -p {}'.format(
|
||||
quote(instance), quote(user), quote(password))
|
||||
|
||||
userAName = randomString(11)
|
||||
userBName = randomString(11)
|
||||
userAPassword = randomString(22)
|
||||
userBPassword = randomString(22)
|
||||
|
||||
testMessage = randomString(22)
|
||||
testMedia = '${testMedia}'
|
||||
|
||||
start_all()
|
||||
akkoma_a.wait_for_unit('akkoma-initdb.service')
|
||||
akkoma_b.wait_for_unit('akkoma-initdb.service')
|
||||
|
||||
# test repeated initialisation
|
||||
akkoma_a.systemctl('restart akkoma-initdb.service')
|
||||
|
||||
akkoma_a.wait_for_unit('akkoma.service')
|
||||
akkoma_b.wait_for_unit('akkoma.service')
|
||||
akkoma_a.wait_for_file('/run/akkoma/socket');
|
||||
akkoma_b.wait_for_file('/run/akkoma/socket');
|
||||
|
||||
akkoma_a.succeed(registerUser(userAName, userAPassword))
|
||||
akkoma_b.succeed(registerUser(userBName, userBPassword))
|
||||
|
||||
akkoma_a.wait_for_unit('nginx.service')
|
||||
akkoma_b.wait_for_unit('nginx.service')
|
||||
|
||||
client_a.succeed(loginUser('akkoma-a', userAName, userAPassword))
|
||||
client_b.succeed(loginUser('akkoma-b', userBName, userBPassword))
|
||||
|
||||
client_b.succeed('toot follow {}@akkoma-a.nixos.test'.format(userAName))
|
||||
client_a.wait_until_succeeds('toot followers | grep -F -q {}'.format(quote(userBName)))
|
||||
|
||||
client_a.succeed('toot post {} --media {} --description "nothing to see here"'.format(
|
||||
quote(testMessage), quote(testMedia)))
|
||||
|
||||
# verify test message
|
||||
status = json.loads(client_b.wait_until_succeeds(
|
||||
'toot status --json "$(toot timeline -1 | grep -E -o \'^ID [^ ]+\' | cut -d \' \' -f 2)"'))
|
||||
assert status['content'] == testMessage
|
||||
|
||||
# compare attachment to original
|
||||
client_b.succeed('cmp {} <(curl -f -S -s {})'.format(quote(testMedia),
|
||||
quote(status['media_attachments'][0]['url'])))
|
||||
|
||||
client_a.succeed('${lib.getExe checkFe} akkoma-a.nixos.test')
|
||||
client_b.succeed('${lib.getExe checkFe} akkoma-b.nixos.test')
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
# This test does a basic functionality check for alice-lg
|
||||
|
||||
{
|
||||
system ? builtins.currentSystem,
|
||||
pkgs ? import ../.. {
|
||||
inherit system;
|
||||
config = { };
|
||||
},
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
|
||||
inherit (pkgs.lib) optionalString;
|
||||
in
|
||||
makeTest {
|
||||
{
|
||||
name = "alice-lg";
|
||||
nodes = {
|
||||
host1 = {
|
||||
|
||||
@@ -1,48 +1,46 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
rec {
|
||||
name = "all-terminfo";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ jkarlson ];
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "all-terminfo";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ jkarlson ];
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
infoFilter =
|
||||
name: drv:
|
||||
let
|
||||
o = builtins.tryEval drv;
|
||||
in
|
||||
o.success
|
||||
&& lib.isDerivation o.value
|
||||
&& o.value ? outputs
|
||||
&& builtins.elem "terminfo" o.value.outputs
|
||||
&& !o.value.meta.broken;
|
||||
terminfos = lib.filterAttrs infoFilter pkgs;
|
||||
excludedTerminfos = lib.filterAttrs (
|
||||
_: drv: !(builtins.elem drv.terminfo config.environment.systemPackages)
|
||||
) terminfos;
|
||||
includedOuts = lib.filterAttrs (
|
||||
_: drv: builtins.elem drv.out config.environment.systemPackages
|
||||
) terminfos;
|
||||
in
|
||||
{
|
||||
environment = {
|
||||
enableAllTerminfo = true;
|
||||
etc."terminfo-missing".text = builtins.concatStringsSep "\n" (builtins.attrNames excludedTerminfos);
|
||||
etc."terminfo-extra-outs".text = builtins.concatStringsSep "\n" (builtins.attrNames includedOuts);
|
||||
};
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
infoFilter =
|
||||
name: drv:
|
||||
let
|
||||
o = builtins.tryEval drv;
|
||||
in
|
||||
o.success
|
||||
&& lib.isDerivation o.value
|
||||
&& o.value ? outputs
|
||||
&& builtins.elem "terminfo" o.value.outputs
|
||||
&& !o.value.meta.broken;
|
||||
terminfos = lib.filterAttrs infoFilter pkgs;
|
||||
excludedTerminfos = lib.filterAttrs (
|
||||
_: drv: !(builtins.elem drv.terminfo config.environment.systemPackages)
|
||||
) terminfos;
|
||||
includedOuts = lib.filterAttrs (
|
||||
_: drv: builtins.elem drv.out config.environment.systemPackages
|
||||
) terminfos;
|
||||
in
|
||||
{
|
||||
environment = {
|
||||
enableAllTerminfo = true;
|
||||
etc."terminfo-missing".text = builtins.concatStringsSep "\n" (builtins.attrNames excludedTerminfos);
|
||||
etc."terminfo-extra-outs".text = builtins.concatStringsSep "\n" (builtins.attrNames includedOuts);
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.fail("grep . /etc/terminfo-missing >&2")
|
||||
machine.fail("grep . /etc/terminfo-extra-outs >&2")
|
||||
'';
|
||||
}
|
||||
)
|
||||
testScript = ''
|
||||
machine.fail("grep . /etc/terminfo-missing >&2")
|
||||
machine.fail("grep . /etc/terminfo-extra-outs >&2")
|
||||
'';
|
||||
}
|
||||
|
||||
+97
-62
@@ -147,48 +147,60 @@ in {
|
||||
_3proxy = runTest ./3proxy.nix;
|
||||
aaaaxy = runTest ./aaaaxy.nix;
|
||||
acme = import ./acme/default.nix { inherit runTest; };
|
||||
acme-dns = handleTest ./acme-dns.nix {};
|
||||
actual = handleTest ./actual.nix {};
|
||||
acme-dns = runTest ./acme-dns.nix;
|
||||
actual = runTest ./actual.nix;
|
||||
adguardhome = runTest ./adguardhome.nix;
|
||||
aesmd = runTestOn ["x86_64-linux"] ./aesmd.nix;
|
||||
agate = runTest ./web-servers/agate.nix;
|
||||
agda = handleTest ./agda.nix {};
|
||||
agda = runTest ./agda.nix;
|
||||
age-plugin-tpm-decrypt = runTest ./age-plugin-tpm-decrypt.nix;
|
||||
agorakit = runTest ./web-apps/agorakit.nix;
|
||||
airsonic = handleTest ./airsonic.nix {};
|
||||
akkoma = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./akkoma.nix {};
|
||||
akkoma-confined = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./akkoma.nix { confined = true; };
|
||||
alice-lg = handleTest ./alice-lg.nix {};
|
||||
alloy = handleTest ./alloy.nix {};
|
||||
allTerminfo = handleTest ./all-terminfo.nix {};
|
||||
alps = handleTest ./alps.nix {};
|
||||
amazon-cloudwatch-agent = handleTest ./amazon-cloudwatch-agent.nix {};
|
||||
amazon-init-shell = handleTest ./amazon-init-shell.nix {};
|
||||
amazon-ssm-agent = handleTest ./amazon-ssm-agent.nix {};
|
||||
airsonic = runTest ./airsonic.nix;
|
||||
akkoma = runTestOn [ "x86_64-linux" "aarch64-linux" ] {
|
||||
imports = [ ./akkoma.nix ];
|
||||
_module.args.confined = false;
|
||||
};
|
||||
akkoma-confined = runTestOn [ "x86_64-linux" "aarch64-linux" ] {
|
||||
imports = [ ./akkoma.nix ];
|
||||
_module.args.confined = true;
|
||||
};
|
||||
alice-lg = runTest ./alice-lg.nix;
|
||||
alloy = runTest ./alloy.nix;
|
||||
allTerminfo = runTest ./all-terminfo.nix;
|
||||
alps = runTest ./alps.nix;
|
||||
amazon-cloudwatch-agent = runTest ./amazon-cloudwatch-agent.nix;
|
||||
amazon-init-shell = runTest ./amazon-init-shell.nix;
|
||||
amazon-ssm-agent = runTest ./amazon-ssm-agent.nix;
|
||||
amd-sev = runTest ./amd-sev.nix;
|
||||
angie-api = handleTest ./angie-api.nix {};
|
||||
anki-sync-server = handleTest ./anki-sync-server.nix {};
|
||||
anuko-time-tracker = handleTest ./anuko-time-tracker.nix {};
|
||||
apcupsd = handleTest ./apcupsd.nix {};
|
||||
angie-api = runTest ./angie-api.nix;
|
||||
anki-sync-server = runTest ./anki-sync-server.nix;
|
||||
anuko-time-tracker = runTest ./anuko-time-tracker.nix;
|
||||
apcupsd = runTest ./apcupsd.nix;
|
||||
apfs = runTest ./apfs.nix;
|
||||
appliance-repart-image = runTest ./appliance-repart-image.nix;
|
||||
appliance-repart-image-verity-store = runTest ./appliance-repart-image-verity-store.nix;
|
||||
apparmor = handleTest ./apparmor {};
|
||||
archi = handleTest ./archi.nix {};
|
||||
aria2 = handleTest ./aria2.nix {};
|
||||
armagetronad = handleTest ./armagetronad.nix {};
|
||||
apparmor = runTest ./apparmor;
|
||||
archi = runTest ./archi.nix;
|
||||
aria2 = runTest ./aria2.nix;
|
||||
armagetronad = runTest ./armagetronad.nix;
|
||||
artalk = runTest ./artalk.nix;
|
||||
atd = handleTest ./atd.nix {};
|
||||
atd = runTest ./atd.nix;
|
||||
atop = handleTest ./atop.nix {};
|
||||
atticd = runTest ./atticd.nix;
|
||||
atuin = runTest ./atuin.nix;
|
||||
audiobookshelf = handleTest ./audiobookshelf.nix {};
|
||||
auth-mysql = handleTest ./auth-mysql.nix {};
|
||||
authelia = handleTest ./authelia.nix {};
|
||||
auto-cpufreq = handleTest ./auto-cpufreq.nix {};
|
||||
autobrr = handleTest ./autobrr.nix {};
|
||||
avahi = handleTest ./avahi.nix {};
|
||||
avahi-with-resolved = handleTest ./avahi.nix { networkd = true; };
|
||||
audiobookshelf = runTest ./audiobookshelf.nix;
|
||||
auth-mysql = runTest ./auth-mysql.nix;
|
||||
authelia = runTest ./authelia.nix;
|
||||
auto-cpufreq = runTest ./auto-cpufreq.nix;
|
||||
autobrr = runTest ./autobrr.nix;
|
||||
avahi = runTest {
|
||||
imports = [ ./avahi.nix ];
|
||||
_module.args.networkd = false;
|
||||
};
|
||||
avahi-with-resolved = runTest {
|
||||
imports = [ ./avahi.nix ];
|
||||
_module.args.networkd = true;
|
||||
};
|
||||
ayatana-indicators = runTest ./ayatana-indicators.nix;
|
||||
babeld = runTest ./babeld.nix;
|
||||
bazarr = handleTest ./bazarr.nix {};
|
||||
@@ -416,7 +428,10 @@ in {
|
||||
flannel = handleTestOn ["x86_64-linux"] ./flannel.nix {};
|
||||
flaresolverr = handleTest ./flaresolverr.nix {};
|
||||
flood = handleTest ./flood.nix {};
|
||||
floorp = handleTest ./firefox.nix { firefoxPackage = pkgs.floorp; };
|
||||
floorp = runTest {
|
||||
imports = [ ./firefox.nix ] ;
|
||||
_module.args.firefoxPackage = pkgs.floorp;
|
||||
};
|
||||
fluentd = handleTest ./fluentd.nix {};
|
||||
fluidd = handleTest ./fluidd.nix {};
|
||||
fontconfig-default-fonts = handleTest ./fontconfig-default-fonts.nix {};
|
||||
@@ -607,7 +622,10 @@ in {
|
||||
libresprite = handleTest ./libresprite.nix {};
|
||||
libreswan = runTest ./libreswan.nix;
|
||||
libreswan-nat = runTest ./libreswan-nat.nix;
|
||||
librewolf = handleTest ./firefox.nix { firefoxPackage = pkgs.librewolf; };
|
||||
librewolf = runTest {
|
||||
imports = [ ./firefox.nix ];
|
||||
_module.args.firefoxPackage = pkgs.librewolf;
|
||||
};
|
||||
libuiohook = handleTest ./libuiohook.nix {};
|
||||
libvirtd = handleTest ./libvirtd.nix {};
|
||||
lidarr = handleTest ./lidarr.nix {};
|
||||
@@ -616,6 +634,7 @@ in {
|
||||
limesurvey = handleTest ./limesurvey.nix {};
|
||||
limine = import ./limine { inherit runTest; };
|
||||
listmonk = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./listmonk.nix {};
|
||||
litellm = runTest ./litellm.nix;
|
||||
litestream = handleTest ./litestream.nix {};
|
||||
lldap = handleTest ./lldap.nix {};
|
||||
localsend = handleTest ./localsend.nix {};
|
||||
@@ -856,6 +875,7 @@ in {
|
||||
opentelemetry-collector = handleTest ./opentelemetry-collector.nix {};
|
||||
open-web-calendar = handleTest ./web-apps/open-web-calendar.nix {};
|
||||
ocsinventory-agent = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./ocsinventory-agent.nix {};
|
||||
orthanc = runTest ./orthanc.nix;
|
||||
owncast = handleTest ./owncast.nix {};
|
||||
outline = handleTest ./outline.nix {};
|
||||
image-contents = handleTest ./image-contents.nix {};
|
||||
@@ -896,11 +916,26 @@ in {
|
||||
phosh = handleTest ./phosh.nix {};
|
||||
photonvision = handleTest ./photonvision.nix {};
|
||||
photoprism = handleTest ./photoprism.nix {};
|
||||
php = handleTest ./php {};
|
||||
php81 = handleTest ./php { php = pkgs.php81; };
|
||||
php82 = handleTest ./php { php = pkgs.php82; };
|
||||
php83 = handleTest ./php { php = pkgs.php83; };
|
||||
php84 = handleTest ./php { php = pkgs.php84; };
|
||||
php = import ./php/default.nix {
|
||||
inherit runTest;
|
||||
php = pkgs.php;
|
||||
};
|
||||
php81 = import ./php/default.nix {
|
||||
inherit runTest;
|
||||
php = pkgs.php81;
|
||||
};
|
||||
php82 = import ./php/default.nix {
|
||||
inherit runTest;
|
||||
php = pkgs.php82;
|
||||
};
|
||||
php83 = import ./php/default.nix {
|
||||
inherit runTest;
|
||||
php = pkgs.php83;
|
||||
};
|
||||
php84 = import ./php/default.nix {
|
||||
inherit runTest;
|
||||
php = pkgs.php84;
|
||||
};
|
||||
phylactery = handleTest ./web-apps/phylactery.nix {};
|
||||
pict-rs = handleTest ./pict-rs.nix {};
|
||||
pingvin-share = handleTest ./pingvin-share.nix {} ;
|
||||
@@ -1267,26 +1302,26 @@ in {
|
||||
wrappers = handleTest ./wrappers.nix {};
|
||||
writefreely = handleTest ./web-apps/writefreely.nix {};
|
||||
wstunnel = runTest ./wstunnel.nix;
|
||||
xandikos = handleTest ./xandikos.nix {};
|
||||
xautolock = handleTest ./xautolock.nix {};
|
||||
xfce = handleTest ./xfce.nix {};
|
||||
xfce-wayland = handleTest ./xfce-wayland.nix {};
|
||||
xmonad = handleTest ./xmonad.nix {};
|
||||
xmonad-xdg-autostart = handleTest ./xmonad-xdg-autostart.nix {};
|
||||
xpadneo = handleTest ./xpadneo.nix {};
|
||||
xrdp = handleTest ./xrdp.nix {};
|
||||
xrdp-with-audio-pulseaudio = handleTest ./xrdp-with-audio-pulseaudio.nix {};
|
||||
xandikos = runTest ./xandikos.nix;
|
||||
xautolock = runTest ./xautolock.nix;
|
||||
xfce = runTest ./xfce.nix;
|
||||
xfce-wayland = runTest ./xfce-wayland.nix;
|
||||
xmonad = runTest ./xmonad.nix;
|
||||
xmonad-xdg-autostart = runTest ./xmonad-xdg-autostart.nix;
|
||||
xpadneo = runTest ./xpadneo.nix;
|
||||
xrdp = runTest ./xrdp.nix;
|
||||
xrdp-with-audio-pulseaudio = runTest ./xrdp-with-audio-pulseaudio.nix;
|
||||
xscreensaver = handleTest ./xscreensaver.nix {};
|
||||
xss-lock = handleTest ./xss-lock.nix {};
|
||||
xterm = handleTest ./xterm.nix {};
|
||||
xxh = handleTest ./xxh.nix {};
|
||||
yabar = handleTest ./yabar.nix {};
|
||||
xss-lock = runTest ./xss-lock.nix;
|
||||
xterm = runTest ./xterm.nix;
|
||||
xxh = runTest ./xxh.nix;
|
||||
yabar = runTest ./yabar.nix;
|
||||
ydotool = handleTest ./ydotool.nix {};
|
||||
yggdrasil = handleTest ./yggdrasil.nix {};
|
||||
your_spotify = handleTest ./your_spotify.nix {};
|
||||
zammad = handleTest ./zammad.nix {};
|
||||
zenohd = handleTest ./zenohd.nix {};
|
||||
zeronet-conservancy = handleTest ./zeronet-conservancy.nix {};
|
||||
yggdrasil = runTest ./yggdrasil.nix;
|
||||
your_spotify = runTest ./your_spotify.nix;
|
||||
zammad = runTest ./zammad.nix;
|
||||
zenohd = runTest ./zenohd.nix;
|
||||
zeronet-conservancy = runTest ./zeronet-conservancy.nix;
|
||||
zfs = handleTest ./zfs.nix {};
|
||||
zigbee2mqtt_1 = runTest {
|
||||
imports = [ ./zigbee2mqtt.nix ];
|
||||
@@ -1296,12 +1331,12 @@ in {
|
||||
imports = [ ./zigbee2mqtt.nix ];
|
||||
_module.args.package = pkgs.zigbee2mqtt_2;
|
||||
};
|
||||
zipline = handleTest ./zipline.nix {};
|
||||
zoneminder = handleTest ./zoneminder.nix {};
|
||||
zookeeper = handleTest ./zookeeper.nix {};
|
||||
zram-generator = handleTest ./zram-generator.nix {};
|
||||
zrepl = handleTest ./zrepl.nix {};
|
||||
zsh-history = handleTest ./zsh-history.nix {};
|
||||
zwave-js = handleTest ./zwave-js.nix {};
|
||||
zwave-js-ui = handleTest ./zwave-js-ui.nix {};
|
||||
zipline = runTest ./zipline.nix;
|
||||
zoneminder = runTest ./zoneminder.nix;
|
||||
zookeeper = runTest ./zookeeper.nix;
|
||||
zram-generator = runTest ./zram-generator.nix;
|
||||
zrepl = runTest ./zrepl.nix;
|
||||
zsh-history = runTest ./zsh-history.nix;
|
||||
zwave-js = runTest ./zwave-js.nix;
|
||||
zwave-js-ui = runTest ./zwave-js-ui.nix;
|
||||
}
|
||||
|
||||
+28
-30
@@ -1,37 +1,35 @@
|
||||
import ./make-test-python.nix (
|
||||
{ lib, pkgs, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
nodes = {
|
||||
machine = {
|
||||
services.alloy = {
|
||||
enable = true;
|
||||
};
|
||||
environment.etc."alloy/config.alloy".text = "";
|
||||
let
|
||||
nodes = {
|
||||
machine = {
|
||||
services.alloy = {
|
||||
enable = true;
|
||||
};
|
||||
environment.etc."alloy/config.alloy".text = "";
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "alloy";
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "alloy";
|
||||
|
||||
meta = with lib.maintainers; {
|
||||
maintainers = [
|
||||
flokli
|
||||
hbjydev
|
||||
];
|
||||
};
|
||||
meta = with lib.maintainers; {
|
||||
maintainers = [
|
||||
flokli
|
||||
hbjydev
|
||||
];
|
||||
};
|
||||
|
||||
inherit nodes;
|
||||
inherit nodes;
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machine.wait_for_unit("alloy.service")
|
||||
machine.wait_for_open_port(12345)
|
||||
machine.succeed(
|
||||
"curl -sSfN http://127.0.0.1:12345/-/healthy"
|
||||
)
|
||||
machine.shutdown()
|
||||
'';
|
||||
}
|
||||
)
|
||||
machine.wait_for_unit("alloy.service")
|
||||
machine.wait_for_open_port(12345)
|
||||
machine.succeed(
|
||||
"curl -sSfN http://127.0.0.1:12345/-/healthy"
|
||||
)
|
||||
machine.shutdown()
|
||||
'';
|
||||
}
|
||||
|
||||
+101
-103
@@ -2,118 +2,116 @@ let
|
||||
certs = import ./common/acme/server/snakeoil-certs.nix;
|
||||
domain = certs.domain;
|
||||
in
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "alps";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ hmenke ];
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "alps";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ hmenke ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
server = {
|
||||
imports = [ ./common/user-account.nix ];
|
||||
security.pki.certificateFiles = [
|
||||
certs.ca.cert
|
||||
];
|
||||
networking.extraHosts = ''
|
||||
127.0.0.1 ${domain}
|
||||
'';
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
25
|
||||
465
|
||||
993
|
||||
];
|
||||
services.postfix = {
|
||||
enable = true;
|
||||
enableSubmission = true;
|
||||
enableSubmissions = true;
|
||||
tlsTrustedAuthorities = "${certs.ca.cert}";
|
||||
sslCert = "${certs.${domain}.cert}";
|
||||
sslKey = "${certs.${domain}.key}";
|
||||
};
|
||||
services.dovecot2 = {
|
||||
enable = true;
|
||||
enableImap = true;
|
||||
sslCACert = "${certs.ca.cert}";
|
||||
sslServerCert = "${certs.${domain}.cert}";
|
||||
sslServerKey = "${certs.${domain}.key}";
|
||||
};
|
||||
};
|
||||
|
||||
nodes = {
|
||||
server = {
|
||||
imports = [ ./common/user-account.nix ];
|
||||
client =
|
||||
{ nodes, config, ... }:
|
||||
{
|
||||
security.pki.certificateFiles = [
|
||||
certs.ca.cert
|
||||
];
|
||||
networking.extraHosts = ''
|
||||
127.0.0.1 ${domain}
|
||||
${nodes.server.config.networking.primaryIPAddress} ${domain}
|
||||
'';
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
25
|
||||
465
|
||||
993
|
||||
];
|
||||
services.postfix = {
|
||||
services.alps = {
|
||||
enable = true;
|
||||
enableSubmission = true;
|
||||
enableSubmissions = true;
|
||||
tlsTrustedAuthorities = "${certs.ca.cert}";
|
||||
sslCert = "${certs.${domain}.cert}";
|
||||
sslKey = "${certs.${domain}.key}";
|
||||
};
|
||||
services.dovecot2 = {
|
||||
enable = true;
|
||||
enableImap = true;
|
||||
sslCACert = "${certs.ca.cert}";
|
||||
sslServerCert = "${certs.${domain}.cert}";
|
||||
sslServerKey = "${certs.${domain}.key}";
|
||||
};
|
||||
};
|
||||
|
||||
client =
|
||||
{ nodes, config, ... }:
|
||||
{
|
||||
security.pki.certificateFiles = [
|
||||
certs.ca.cert
|
||||
];
|
||||
networking.extraHosts = ''
|
||||
${nodes.server.config.networking.primaryIPAddress} ${domain}
|
||||
'';
|
||||
services.alps = {
|
||||
enable = true;
|
||||
theme = "alps";
|
||||
imaps = {
|
||||
host = domain;
|
||||
port = 993;
|
||||
};
|
||||
smtps = {
|
||||
host = domain;
|
||||
port = 465;
|
||||
};
|
||||
theme = "alps";
|
||||
imaps = {
|
||||
host = domain;
|
||||
port = 993;
|
||||
};
|
||||
smtps = {
|
||||
host = domain;
|
||||
port = 465;
|
||||
};
|
||||
environment.systemPackages = [
|
||||
(pkgs.writers.writePython3Bin "test-alps-login" { } ''
|
||||
from urllib.request import build_opener, HTTPCookieProcessor, Request
|
||||
from urllib.parse import urlencode, urljoin
|
||||
from http.cookiejar import CookieJar
|
||||
|
||||
baseurl = "http://localhost:${toString config.services.alps.port}"
|
||||
username = "alice"
|
||||
password = "${nodes.server.config.users.users.alice.password}"
|
||||
cookiejar = CookieJar()
|
||||
cookieprocessor = HTTPCookieProcessor(cookiejar)
|
||||
opener = build_opener(cookieprocessor)
|
||||
|
||||
data = urlencode({"username": username, "password": password}).encode()
|
||||
req = Request(urljoin(baseurl, "login"), data=data, method="POST")
|
||||
with opener.open(req) as ret:
|
||||
# Check that the alps_session cookie is set
|
||||
print(cookiejar)
|
||||
assert any(cookie.name == "alps_session" for cookie in cookiejar)
|
||||
|
||||
req = Request(baseurl)
|
||||
with opener.open(req) as ret:
|
||||
# Check that the alps_session cookie is still there...
|
||||
print(cookiejar)
|
||||
assert any(cookie.name == "alps_session" for cookie in cookiejar)
|
||||
# ...and that we have not been redirected back to the login page
|
||||
print(ret.url)
|
||||
assert ret.url == urljoin(baseurl, "mailbox/INBOX")
|
||||
|
||||
req = Request(urljoin(baseurl, "logout"))
|
||||
with opener.open(req) as ret:
|
||||
# Check that the alps_session cookie is now gone
|
||||
print(cookiejar)
|
||||
assert all(cookie.name != "alps_session" for cookie in cookiejar)
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
environment.systemPackages = [
|
||||
(pkgs.writers.writePython3Bin "test-alps-login" { } ''
|
||||
from urllib.request import build_opener, HTTPCookieProcessor, Request
|
||||
from urllib.parse import urlencode, urljoin
|
||||
from http.cookiejar import CookieJar
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
server.start()
|
||||
server.wait_for_unit("postfix.service")
|
||||
server.wait_for_unit("dovecot2.service")
|
||||
server.wait_for_open_port(465)
|
||||
server.wait_for_open_port(993)
|
||||
baseurl = "http://localhost:${toString config.services.alps.port}"
|
||||
username = "alice"
|
||||
password = "${nodes.server.config.users.users.alice.password}"
|
||||
cookiejar = CookieJar()
|
||||
cookieprocessor = HTTPCookieProcessor(cookiejar)
|
||||
opener = build_opener(cookieprocessor)
|
||||
|
||||
client.start()
|
||||
client.wait_for_unit("alps.service")
|
||||
client.wait_for_open_port(${toString nodes.client.config.services.alps.port})
|
||||
client.succeed("test-alps-login")
|
||||
'';
|
||||
}
|
||||
)
|
||||
data = urlencode({"username": username, "password": password}).encode()
|
||||
req = Request(urljoin(baseurl, "login"), data=data, method="POST")
|
||||
with opener.open(req) as ret:
|
||||
# Check that the alps_session cookie is set
|
||||
print(cookiejar)
|
||||
assert any(cookie.name == "alps_session" for cookie in cookiejar)
|
||||
|
||||
req = Request(baseurl)
|
||||
with opener.open(req) as ret:
|
||||
# Check that the alps_session cookie is still there...
|
||||
print(cookiejar)
|
||||
assert any(cookie.name == "alps_session" for cookie in cookiejar)
|
||||
# ...and that we have not been redirected back to the login page
|
||||
print(ret.url)
|
||||
assert ret.url == urljoin(baseurl, "mailbox/INBOX")
|
||||
|
||||
req = Request(urljoin(baseurl, "logout"))
|
||||
with opener.open(req) as ret:
|
||||
# Check that the alps_session cookie is now gone
|
||||
print(cookiejar)
|
||||
assert all(cookie.name != "alps_session" for cookie in cookiejar)
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ nodes, ... }:
|
||||
''
|
||||
server.start()
|
||||
server.wait_for_unit("postfix.service")
|
||||
server.wait_for_unit("dovecot2.service")
|
||||
server.wait_for_open_port(465)
|
||||
server.wait_for_open_port(993)
|
||||
|
||||
client.start()
|
||||
client.wait_for_unit("alps.service")
|
||||
client.wait_for_open_port(${toString nodes.client.config.services.alps.port})
|
||||
client.succeed("test-alps-login")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,92 +1,90 @@
|
||||
import ./make-test-python.nix (
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
# See https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
|
||||
iniFormat = pkgs.formats.ini { };
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
# See https://docs.aws.amazon.com/sdkref/latest/guide/file-format.html.
|
||||
iniFormat = pkgs.formats.ini { };
|
||||
|
||||
region = "ap-northeast-1";
|
||||
sharedConfigurationDefaultProfile = "default";
|
||||
sharedConfigurationFile = iniFormat.generate "config" {
|
||||
"${sharedConfigurationDefaultProfile}" = {
|
||||
region = region;
|
||||
};
|
||||
region = "ap-northeast-1";
|
||||
sharedConfigurationDefaultProfile = "default";
|
||||
sharedConfigurationFile = iniFormat.generate "config" {
|
||||
"${sharedConfigurationDefaultProfile}" = {
|
||||
region = region;
|
||||
};
|
||||
sharedCredentialsFile = iniFormat.generate "credentials" {
|
||||
"${sharedConfigurationDefaultProfile}" = {
|
||||
aws_access_key_id = "placeholder";
|
||||
aws_secret_access_key = "placeholder";
|
||||
aws_session_token = "placeholder";
|
||||
};
|
||||
};
|
||||
sharedCredentialsFile = iniFormat.generate "credentials" {
|
||||
"${sharedConfigurationDefaultProfile}" = {
|
||||
aws_access_key_id = "placeholder";
|
||||
aws_secret_access_key = "placeholder";
|
||||
aws_session_token = "placeholder";
|
||||
};
|
||||
sharedConfigurationDirectory = pkgs.runCommand ".aws" { } ''
|
||||
mkdir $out
|
||||
};
|
||||
sharedConfigurationDirectory = pkgs.runCommand ".aws" { } ''
|
||||
mkdir $out
|
||||
|
||||
cp ${sharedConfigurationFile} $out/config
|
||||
cp ${sharedCredentialsFile} $out/credentials
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "amazon-cloudwatch-agent";
|
||||
cp ${sharedConfigurationFile} $out/config
|
||||
cp ${sharedCredentialsFile} $out/credentials
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "amazon-cloudwatch-agent";
|
||||
|
||||
nodes.machine =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.amazon-cloudwatch-agent = {
|
||||
enable = true;
|
||||
commonConfiguration = {
|
||||
credentials = {
|
||||
shared_credential_profile = sharedConfigurationDefaultProfile;
|
||||
shared_credential_file = "${sharedConfigurationDirectory}/credentials";
|
||||
};
|
||||
nodes.machine =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.amazon-cloudwatch-agent = {
|
||||
enable = true;
|
||||
commonConfiguration = {
|
||||
credentials = {
|
||||
shared_credential_profile = sharedConfigurationDefaultProfile;
|
||||
shared_credential_file = "${sharedConfigurationDirectory}/credentials";
|
||||
};
|
||||
configuration = {
|
||||
agent = {
|
||||
# Required despite documentation saying the agent ignores it in "onPremise" mode.
|
||||
region = region;
|
||||
|
||||
# Show debug logs and write to a file for interactive debugging.
|
||||
debug = true;
|
||||
logfile = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
|
||||
};
|
||||
logs = {
|
||||
logs_collected = {
|
||||
files = {
|
||||
collect_list = [
|
||||
{
|
||||
file_path = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
|
||||
log_group_name = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
|
||||
log_stream_name = "{local_hostname}";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
traces = {
|
||||
local_mode = true;
|
||||
traces_collected = {
|
||||
xray = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
mode = "onPremise";
|
||||
};
|
||||
configuration = {
|
||||
agent = {
|
||||
# Required despite documentation saying the agent ignores it in "onPremise" mode.
|
||||
region = region;
|
||||
|
||||
# Keep the runtime directory for interactive debugging.
|
||||
systemd.services.amazon-cloudwatch-agent.serviceConfig.RuntimeDirectoryPreserve = true;
|
||||
# Show debug logs and write to a file for interactive debugging.
|
||||
debug = true;
|
||||
logfile = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
|
||||
};
|
||||
logs = {
|
||||
logs_collected = {
|
||||
files = {
|
||||
collect_list = [
|
||||
{
|
||||
file_path = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
|
||||
log_group_name = "/var/log/amazon-cloudwatch-agent/amazon-cloudwatch-agent.log";
|
||||
log_stream_name = "{local_hostname}";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
traces = {
|
||||
local_mode = true;
|
||||
traces_collected = {
|
||||
xray = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
mode = "onPremise";
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
# Keep the runtime directory for interactive debugging.
|
||||
systemd.services.amazon-cloudwatch-agent.serviceConfig.RuntimeDirectoryPreserve = true;
|
||||
};
|
||||
|
||||
machine.wait_for_unit("amazon-cloudwatch-agent.service")
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.pid")
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.toml")
|
||||
# "config-translator" omits this file if no trace configurations are specified.
|
||||
#
|
||||
# See https://github.com/aws/amazon-cloudwatch-agent/issues/1320.
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.yaml")
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/env-config.json")
|
||||
'';
|
||||
}
|
||||
)
|
||||
machine.wait_for_unit("amazon-cloudwatch-agent.service")
|
||||
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.pid")
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.toml")
|
||||
# "config-translator" omits this file if no trace configurations are specified.
|
||||
#
|
||||
# See https://github.com/aws/amazon-cloudwatch-agent/issues/1320.
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/amazon-cloudwatch-agent.yaml")
|
||||
machine.wait_for_file("/run/amazon-cloudwatch-agent/env-config.json")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -6,41 +6,35 @@
|
||||
# configuration expression.
|
||||
|
||||
{
|
||||
system ? builtins.currentSystem,
|
||||
config ? { },
|
||||
pkgs ? import ../.. { inherit system config; },
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
with pkgs.lib;
|
||||
|
||||
makeTest {
|
||||
{
|
||||
name = "amazon-init";
|
||||
meta = with maintainers; {
|
||||
meta = with lib.maintainers; {
|
||||
maintainers = [ urbas ];
|
||||
};
|
||||
nodes.machine =
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
../modules/profiles/headless.nix
|
||||
../modules/virtualisation/amazon-init.nix
|
||||
];
|
||||
services.openssh.enable = true;
|
||||
system.switch.enable = true;
|
||||
networking.hostName = "";
|
||||
environment.etc."ec2-metadata/user-data" = {
|
||||
text = ''
|
||||
#!/usr/bin/bash
|
||||
nodes.machine = {
|
||||
imports = [
|
||||
../modules/profiles/headless.nix
|
||||
../modules/virtualisation/amazon-init.nix
|
||||
];
|
||||
services.openssh.enable = true;
|
||||
system.switch.enable = true;
|
||||
networking.hostName = "";
|
||||
environment.etc."ec2-metadata/user-data" = {
|
||||
text = ''
|
||||
#!/usr/bin/bash
|
||||
|
||||
echo successful > /tmp/evidence
|
||||
echo successful > /tmp/evidence
|
||||
|
||||
# Emulate running nixos-rebuild switch, just without any building.
|
||||
# https://github.com/nixos/nixpkgs/blob/4c62505847d88f16df11eff3c81bf9a453a4979e/nixos/modules/virtualisation/amazon-init.nix#L55
|
||||
/run/current-system/bin/switch-to-configuration test
|
||||
'';
|
||||
};
|
||||
# Emulate running nixos-rebuild switch, just without any building.
|
||||
# https://github.com/nixos/nixpkgs/blob/4c62505847d88f16df11eff3c81bf9a453a4979e/nixos/modules/virtualisation/amazon-init.nix#L55
|
||||
/run/current-system/bin/switch-to-configuration test
|
||||
'';
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
# To wait until amazon-init terminates its run
|
||||
unnamed.wait_for_unit("amazon-init.service")
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import ./make-test-python.nix (
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
name = "amazon-ssm-agent";
|
||||
meta.maintainers = [ lib.maintainers.anthonyroussel ];
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "amazon-ssm-agent";
|
||||
meta.maintainers = [ lib.maintainers.anthonyroussel ];
|
||||
|
||||
nodes.machine =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.amazon-ssm-agent.enable = true;
|
||||
};
|
||||
nodes.machine = {
|
||||
services.amazon-ssm-agent.enable = true;
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machine.wait_for_file("/etc/amazon/ssm/seelog.xml")
|
||||
machine.wait_for_file("/etc/amazon/ssm/amazon-ssm-agent.json")
|
||||
machine.wait_for_file("/etc/amazon/ssm/seelog.xml")
|
||||
machine.wait_for_file("/etc/amazon/ssm/amazon-ssm-agent.json")
|
||||
|
||||
machine.wait_for_unit("amazon-ssm-agent.service")
|
||||
'';
|
||||
}
|
||||
)
|
||||
machine.wait_for_unit("amazon-ssm-agent.service")
|
||||
'';
|
||||
}
|
||||
|
||||
+143
-145
@@ -1,170 +1,168 @@
|
||||
import ./make-test-python.nix (
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
hosts = ''
|
||||
192.168.2.101 example.com
|
||||
192.168.2.101 api.example.com
|
||||
192.168.2.101 backend.example.com
|
||||
'';
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
hosts = ''
|
||||
192.168.2.101 example.com
|
||||
192.168.2.101 api.example.com
|
||||
192.168.2.101 backend.example.com
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
name = "angie-api";
|
||||
meta.maintainers = with pkgs.lib.maintainers; [ izorkin ];
|
||||
in
|
||||
{
|
||||
name = "angie-api";
|
||||
meta.maintainers = with pkgs.lib.maintainers; [ izorkin ];
|
||||
|
||||
nodes = {
|
||||
server =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
networking = {
|
||||
interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.2.101";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
nodes = {
|
||||
server =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
networking = {
|
||||
interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.2.101";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
extraHosts = hosts;
|
||||
firewall.allowedTCPPorts = [ 80 ];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
package = pkgs.angie;
|
||||
|
||||
upstreams = {
|
||||
"backend-http" = {
|
||||
servers = {
|
||||
"backend.example.com:8080" = {
|
||||
fail_timeout = "0";
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
zone upstream 256k;
|
||||
'';
|
||||
};
|
||||
"backend-socket" = {
|
||||
servers = {
|
||||
"unix:/run/example.sock" = {
|
||||
fail_timeout = "0";
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
zone upstream 256k;
|
||||
'';
|
||||
};
|
||||
extraHosts = hosts;
|
||||
firewall.allowedTCPPorts = [ 80 ];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
package = pkgs.angie;
|
||||
virtualHosts."api.example.com" = {
|
||||
locations."/console/" = {
|
||||
extraConfig = ''
|
||||
api /status/;
|
||||
|
||||
upstreams = {
|
||||
"backend-http" = {
|
||||
servers = {
|
||||
"backend.example.com:8080" = {
|
||||
fail_timeout = "0";
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
zone upstream 256k;
|
||||
'';
|
||||
};
|
||||
"backend-socket" = {
|
||||
servers = {
|
||||
"unix:/run/example.sock" = {
|
||||
fail_timeout = "0";
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
zone upstream 256k;
|
||||
'';
|
||||
};
|
||||
allow 192.168.2.201;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
virtualHosts."api.example.com" = {
|
||||
locations."/console/" = {
|
||||
extraConfig = ''
|
||||
api /status/;
|
||||
virtualHosts."example.com" = {
|
||||
locations."/test/" = {
|
||||
root = lib.mkForce (
|
||||
pkgs.runCommandLocal "testdir" { } ''
|
||||
mkdir -p "$out/test"
|
||||
cat > "$out/test/index.html" <<EOF
|
||||
<html><body>Hello World!</body></html>
|
||||
EOF
|
||||
''
|
||||
);
|
||||
extraConfig = ''
|
||||
status_zone test_zone;
|
||||
|
||||
allow 192.168.2.201;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
allow 192.168.2.201;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
locations."/test/locked/" = {
|
||||
extraConfig = ''
|
||||
status_zone test_zone;
|
||||
|
||||
virtualHosts."example.com" = {
|
||||
locations."/test/" = {
|
||||
root = lib.mkForce (
|
||||
pkgs.runCommandLocal "testdir" { } ''
|
||||
mkdir -p "$out/test"
|
||||
cat > "$out/test/index.html" <<EOF
|
||||
<html><body>Hello World!</body></html>
|
||||
EOF
|
||||
''
|
||||
);
|
||||
extraConfig = ''
|
||||
status_zone test_zone;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
locations."/test/error/" = {
|
||||
extraConfig = ''
|
||||
status_zone test_zone;
|
||||
|
||||
allow 192.168.2.201;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
locations."/test/locked/" = {
|
||||
extraConfig = ''
|
||||
status_zone test_zone;
|
||||
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
locations."/test/error/" = {
|
||||
extraConfig = ''
|
||||
status_zone test_zone;
|
||||
|
||||
allow all;
|
||||
'';
|
||||
};
|
||||
locations."/upstream-http/" = {
|
||||
proxyPass = "http://backend-http";
|
||||
};
|
||||
locations."/upstream-socket/" = {
|
||||
proxyPass = "http://backend-socket";
|
||||
};
|
||||
allow all;
|
||||
'';
|
||||
};
|
||||
locations."/upstream-http/" = {
|
||||
proxyPass = "http://backend-http";
|
||||
};
|
||||
locations."/upstream-socket/" = {
|
||||
proxyPass = "http://backend-socket";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
client =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
networking = {
|
||||
interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.2.201";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
extraHosts = hosts;
|
||||
client =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
networking = {
|
||||
interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = "192.168.2.201";
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
extraHosts = hosts;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
server.wait_for_unit("nginx")
|
||||
server.wait_for_open_port(80)
|
||||
server.wait_for_unit("nginx")
|
||||
server.wait_for_open_port(80)
|
||||
|
||||
# Check Angie version
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.angie.version' | grep '${pkgs.angie.version}'")
|
||||
# Check Angie version
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.angie.version' | grep '${pkgs.angie.version}'")
|
||||
|
||||
# Check access
|
||||
client.succeed("curl --verbose --head http://api.example.com/console/ | grep 'HTTP/1.1 200'")
|
||||
server.succeed("curl --verbose --head http://api.example.com/console/ | grep 'HTTP/1.1 403 Forbidden'")
|
||||
# Check access
|
||||
client.succeed("curl --verbose --head http://api.example.com/console/ | grep 'HTTP/1.1 200'")
|
||||
server.succeed("curl --verbose --head http://api.example.com/console/ | grep 'HTTP/1.1 403 Forbidden'")
|
||||
|
||||
# Check responses and requests
|
||||
client.succeed("curl --verbose http://example.com/test/")
|
||||
client.succeed("curl --verbose http://example.com/test/locked/")
|
||||
client.succeed("curl --verbose http://example.com/test/locked/")
|
||||
client.succeed("curl --verbose http://example.com/test/error/")
|
||||
client.succeed("curl --verbose http://example.com/test/error/")
|
||||
client.succeed("curl --verbose http://example.com/test/error/")
|
||||
server.succeed("curl --verbose http://example.com/test/")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"200\"' | grep '1'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"403\"' | grep '3'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"404\"' | grep '3'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.requests.total' | grep '7'")
|
||||
# Check responses and requests
|
||||
client.succeed("curl --verbose http://example.com/test/")
|
||||
client.succeed("curl --verbose http://example.com/test/locked/")
|
||||
client.succeed("curl --verbose http://example.com/test/locked/")
|
||||
client.succeed("curl --verbose http://example.com/test/error/")
|
||||
client.succeed("curl --verbose http://example.com/test/error/")
|
||||
client.succeed("curl --verbose http://example.com/test/error/")
|
||||
server.succeed("curl --verbose http://example.com/test/")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"200\"' | grep '1'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"403\"' | grep '3'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.responses.\"404\"' | grep '3'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.location_zones.test_zone.requests.total' | grep '7'")
|
||||
|
||||
# Check upstreams
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".state' | grep 'up'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".health.fails' | grep '0'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".state' | grep 'up'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".health.fails' | grep '0'")
|
||||
client.succeed("curl --verbose http://example.com/upstream-http/")
|
||||
client.succeed("curl --verbose http://example.com/upstream-socket/")
|
||||
client.succeed("curl --verbose http://example.com/upstream-socket/")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".health.fails' | grep '1'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".health.fails' | grep '2'")
|
||||
# Check upstreams
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".state' | grep 'up'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".health.fails' | grep '0'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".state' | grep 'up'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".health.fails' | grep '0'")
|
||||
client.succeed("curl --verbose http://example.com/upstream-http/")
|
||||
client.succeed("curl --verbose http://example.com/upstream-socket/")
|
||||
client.succeed("curl --verbose http://example.com/upstream-socket/")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-http\".peers.\"192.168.2.101:8080\".health.fails' | grep '1'")
|
||||
client.succeed("curl --verbose http://api.example.com/console/ | jq -e '.http.upstreams.\"backend-socket\".peers.\"unix:/run/example.sock\".health.fails' | grep '2'")
|
||||
|
||||
server.shutdown()
|
||||
client.shutdown()
|
||||
'';
|
||||
}
|
||||
)
|
||||
server.shutdown()
|
||||
client.shutdown()
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,75 +1,71 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
ankiSyncTest = pkgs.writeScript "anki-sync-test.py" ''
|
||||
#!${pkgs.python3}/bin/python
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
ankiSyncTest = pkgs.writeScript "anki-sync-test.py" ''
|
||||
#!${pkgs.python3}/bin/python
|
||||
|
||||
import sys
|
||||
import sys
|
||||
|
||||
# get site paths from anki itself
|
||||
from runpy import run_path
|
||||
run_path("${pkgs.anki}/bin/.anki-wrapped")
|
||||
import anki
|
||||
# get site paths from anki itself
|
||||
from runpy import run_path
|
||||
run_path("${pkgs.anki}/bin/.anki-wrapped")
|
||||
import anki
|
||||
|
||||
col = anki.collection.Collection('test_collection')
|
||||
endpoint = 'http://localhost:27701'
|
||||
col = anki.collection.Collection('test_collection')
|
||||
endpoint = 'http://localhost:27701'
|
||||
|
||||
# Sanity check: verify bad login fails
|
||||
try:
|
||||
col.sync_login('baduser', 'badpass', endpoint)
|
||||
print("bad user login worked?!")
|
||||
sys.exit(1)
|
||||
except anki.errors.SyncError:
|
||||
pass
|
||||
# Sanity check: verify bad login fails
|
||||
try:
|
||||
col.sync_login('baduser', 'badpass', endpoint)
|
||||
print("bad user login worked?!")
|
||||
sys.exit(1)
|
||||
except anki.errors.SyncError:
|
||||
pass
|
||||
|
||||
# test logging in to users
|
||||
col.sync_login('user', 'password', endpoint)
|
||||
col.sync_login('passfileuser', 'passfilepassword', endpoint)
|
||||
# test logging in to users
|
||||
col.sync_login('user', 'password', endpoint)
|
||||
col.sync_login('passfileuser', 'passfilepassword', endpoint)
|
||||
|
||||
# Test actual sync. login apparently doesn't remember the endpoint...
|
||||
login = col.sync_login('user', 'password', endpoint)
|
||||
login.endpoint = endpoint
|
||||
sync = col.sync_collection(login, False)
|
||||
assert sync.required == sync.NO_CHANGES
|
||||
# TODO: create an archive with server content including a test card
|
||||
# and check we got it?
|
||||
'';
|
||||
testPasswordFile = pkgs.writeText "anki-password" "passfilepassword";
|
||||
in
|
||||
{
|
||||
name = "anki-sync-server";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ martinetd ];
|
||||
# Test actual sync. login apparently doesn't remember the endpoint...
|
||||
login = col.sync_login('user', 'password', endpoint)
|
||||
login.endpoint = endpoint
|
||||
sync = col.sync_collection(login, False)
|
||||
assert sync.required == sync.NO_CHANGES
|
||||
# TODO: create an archive with server content including a test card
|
||||
# and check we got it?
|
||||
'';
|
||||
testPasswordFile = pkgs.writeText "anki-password" "passfilepassword";
|
||||
in
|
||||
{
|
||||
name = "anki-sync-server";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ martinetd ];
|
||||
};
|
||||
|
||||
nodes.machine = {
|
||||
services.anki-sync-server = {
|
||||
enable = true;
|
||||
users = [
|
||||
{
|
||||
username = "user";
|
||||
password = "password";
|
||||
}
|
||||
{
|
||||
username = "passfileuser";
|
||||
passwordFile = testPasswordFile;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.anki-sync-server = {
|
||||
enable = true;
|
||||
users = [
|
||||
{
|
||||
username = "user";
|
||||
password = "password";
|
||||
}
|
||||
{
|
||||
username = "passfileuser";
|
||||
passwordFile = testPasswordFile;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
with subtest("Server starts successfully"):
|
||||
# service won't start without users
|
||||
machine.wait_for_unit("anki-sync-server.service")
|
||||
machine.wait_for_open_port(27701)
|
||||
|
||||
with subtest("Server starts successfully"):
|
||||
# service won't start without users
|
||||
machine.wait_for_unit("anki-sync-server.service")
|
||||
machine.wait_for_open_port(27701)
|
||||
|
||||
with subtest("Can sync"):
|
||||
machine.succeed("${ankiSyncTest}")
|
||||
'';
|
||||
}
|
||||
)
|
||||
with subtest("Can sync"):
|
||||
machine.succeed("${ankiSyncTest}")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "anuko-time-tracker";
|
||||
meta = {
|
||||
maintainers = with pkgs.lib.maintainers; [ michaelshmitty ];
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
name = "anuko-time-tracker";
|
||||
meta = {
|
||||
maintainers = with pkgs.lib.maintainers; [ michaelshmitty ];
|
||||
};
|
||||
nodes = {
|
||||
machine = {
|
||||
services.anuko-time-tracker.enable = true;
|
||||
};
|
||||
nodes = {
|
||||
machine = {
|
||||
services.anuko-time-tracker.enable = true;
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("phpfpm-anuko-time-tracker")
|
||||
machine.wait_for_open_port(80);
|
||||
machine.wait_until_succeeds("curl -s --fail -L http://localhost/time.php | grep 'Anuko Time Tracker'")
|
||||
'';
|
||||
}
|
||||
)
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("phpfpm-anuko-time-tracker")
|
||||
machine.wait_for_open_port(80);
|
||||
machine.wait_until_succeeds("curl -s --fail -L http://localhost/time.php | grep 'Anuko Time Tracker'")
|
||||
'';
|
||||
}
|
||||
|
||||
+36
-38
@@ -2,45 +2,43 @@ let
|
||||
# arbitrary address
|
||||
ipAddr = "192.168.42.42";
|
||||
in
|
||||
import ./make-test-python.nix (
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
name = "apcupsd";
|
||||
meta.maintainers = with lib.maintainers; [ bjornfor ];
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "apcupsd";
|
||||
meta.maintainers = with lib.maintainers; [ bjornfor ];
|
||||
|
||||
nodes = {
|
||||
machine = {
|
||||
services.apcupsd = {
|
||||
enable = true;
|
||||
configText = ''
|
||||
UPSTYPE usb
|
||||
BATTERYLEVEL 42
|
||||
# Configure NISIP so that the only way apcaccess can work is to read
|
||||
# this config.
|
||||
NISIP ${ipAddr}
|
||||
'';
|
||||
};
|
||||
networking.interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = ipAddr;
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
nodes = {
|
||||
machine = {
|
||||
services.apcupsd = {
|
||||
enable = true;
|
||||
configText = ''
|
||||
UPSTYPE usb
|
||||
BATTERYLEVEL 42
|
||||
# Configure NISIP so that the only way apcaccess can work is to read
|
||||
# this config.
|
||||
NISIP ${ipAddr}
|
||||
'';
|
||||
};
|
||||
networking.interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = ipAddr;
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Check that the service starts, that the CLI (apcaccess) works and that it
|
||||
# uses the config (ipAddr) defined in the service config.
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("apcupsd.service")
|
||||
machine.wait_for_open_port(3551, "${ipAddr}")
|
||||
res = machine.succeed("apcaccess")
|
||||
expect_line="MBATTCHG : 42 Percent"
|
||||
assert "MBATTCHG : 42 Percent" in res, f"expected apcaccess output to contain '{expect_line}' but got '{res}'"
|
||||
machine.shutdown()
|
||||
'';
|
||||
}
|
||||
)
|
||||
# Check that the service starts, that the CLI (apcaccess) works and that it
|
||||
# uses the config (ipAddr) defined in the service config.
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("apcupsd.service")
|
||||
machine.wait_for_open_port(3551, "${ipAddr}")
|
||||
res = machine.succeed("apcaccess")
|
||||
expect_line="MBATTCHG : 42 Percent"
|
||||
assert "MBATTCHG : 42 Percent" in res, f"expected apcaccess output to contain '{expect_line}' but got '{res}'"
|
||||
machine.shutdown()
|
||||
'';
|
||||
}
|
||||
|
||||
+111
-115
@@ -1,130 +1,126 @@
|
||||
import ../make-test-python.nix (
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
helloProfileContents = ''
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
profile hello ${lib.getExe pkgs.hello} {
|
||||
include <abstractions/base>
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "apparmor";
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
julm
|
||||
grimmauld
|
||||
];
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
helloProfileContents = ''
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
profile hello ${lib.getExe pkgs.hello} {
|
||||
include <abstractions/base>
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
name = "apparmor";
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
julm
|
||||
grimmauld
|
||||
];
|
||||
|
||||
nodes.machine =
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
security.apparmor = {
|
||||
enable = lib.mkDefault true;
|
||||
nodes.machine =
|
||||
{
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
security.apparmor = {
|
||||
enable = lib.mkDefault true;
|
||||
|
||||
policies.hello = {
|
||||
# test profile enforce and content definition
|
||||
state = "enforce";
|
||||
profile = helloProfileContents;
|
||||
};
|
||||
policies.hello = {
|
||||
# test profile enforce and content definition
|
||||
state = "enforce";
|
||||
profile = helloProfileContents;
|
||||
};
|
||||
|
||||
policies.sl = {
|
||||
# test profile complain and path definition
|
||||
state = "complain";
|
||||
path = ./sl_profile;
|
||||
};
|
||||
policies.sl = {
|
||||
# test profile complain and path definition
|
||||
state = "complain";
|
||||
path = ./sl_profile;
|
||||
};
|
||||
|
||||
policies.hexdump = {
|
||||
# test profile complain and path definition
|
||||
state = "enforce";
|
||||
profile = ''
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
profile hexdump /nix/store/*/bin/hexdump {
|
||||
include <abstractions/base>
|
||||
deny /tmp/** r,
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
includes."abstractions/base" = ''
|
||||
/nix/store/*/bin/** mr,
|
||||
/nix/store/*/lib/** mr,
|
||||
/nix/store/** r,
|
||||
policies.hexdump = {
|
||||
# test profile complain and path definition
|
||||
state = "enforce";
|
||||
profile = ''
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
profile hexdump /nix/store/*/bin/hexdump {
|
||||
include <abstractions/base>
|
||||
deny /tmp/** r,
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
includes."abstractions/base" = ''
|
||||
/nix/store/*/bin/** mr,
|
||||
/nix/store/*/lib/** mr,
|
||||
/nix/store/** r,
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
let
|
||||
inherit (lib) getExe getExe';
|
||||
in
|
||||
''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
testScript =
|
||||
let
|
||||
inherit (lib) getExe getExe';
|
||||
in
|
||||
''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
with subtest("AppArmor profiles are loaded"):
|
||||
machine.succeed("systemctl status apparmor.service")
|
||||
with subtest("AppArmor profiles are loaded"):
|
||||
machine.succeed("systemctl status apparmor.service")
|
||||
|
||||
# AppArmor securityfs
|
||||
with subtest("AppArmor securityfs is mounted"):
|
||||
machine.succeed("mountpoint -q /sys/kernel/security")
|
||||
machine.succeed("cat /sys/kernel/security/apparmor/profiles")
|
||||
# AppArmor securityfs
|
||||
with subtest("AppArmor securityfs is mounted"):
|
||||
machine.succeed("mountpoint -q /sys/kernel/security")
|
||||
machine.succeed("cat /sys/kernel/security/apparmor/profiles")
|
||||
|
||||
# Test apparmorRulesFromClosure by:
|
||||
# 1. Prepending a string of the relevant packages' name and version on each line.
|
||||
# 2. Sorting according to those strings.
|
||||
# 3. Removing those prepended strings.
|
||||
# 4. Using `diff` against the expected output.
|
||||
with subtest("apparmorRulesFromClosure"):
|
||||
machine.succeed(
|
||||
"${getExe' pkgs.diffutils "diff"} -u ${
|
||||
pkgs.writeText "expected.rules" (import ./makeExpectedPolicies.nix { inherit pkgs; })
|
||||
} ${
|
||||
pkgs.runCommand "actual.rules" { preferLocalBuild = true; } ''
|
||||
${getExe pkgs.gnused} -e 's:^[^ ]* ${builtins.storeDir}/[^,/-]*-\([^/,]*\):\1 \0:' ${
|
||||
pkgs.apparmorRulesFromClosure {
|
||||
name = "ping";
|
||||
additionalRules = [ "x $path/foo/**" ];
|
||||
} [ pkgs.libcap ]
|
||||
} |
|
||||
${getExe' pkgs.coreutils "sort"} -n -k1 |
|
||||
${getExe pkgs.gnused} -e 's:^[^ ]* ::' >$out
|
||||
''
|
||||
}"
|
||||
)
|
||||
# Test apparmorRulesFromClosure by:
|
||||
# 1. Prepending a string of the relevant packages' name and version on each line.
|
||||
# 2. Sorting according to those strings.
|
||||
# 3. Removing those prepended strings.
|
||||
# 4. Using `diff` against the expected output.
|
||||
with subtest("apparmorRulesFromClosure"):
|
||||
machine.succeed(
|
||||
"${getExe' pkgs.diffutils "diff"} -u ${
|
||||
pkgs.writeText "expected.rules" (import ./makeExpectedPolicies.nix { inherit pkgs; })
|
||||
} ${
|
||||
pkgs.runCommand "actual.rules" { preferLocalBuild = true; } ''
|
||||
${getExe pkgs.gnused} -e 's:^[^ ]* ${builtins.storeDir}/[^,/-]*-\([^/,]*\):\1 \0:' ${
|
||||
pkgs.apparmorRulesFromClosure {
|
||||
name = "ping";
|
||||
additionalRules = [ "x $path/foo/**" ];
|
||||
} [ pkgs.libcap ]
|
||||
} |
|
||||
${getExe' pkgs.coreutils "sort"} -n -k1 |
|
||||
${getExe pkgs.gnused} -e 's:^[^ ]* ::' >$out
|
||||
''
|
||||
}"
|
||||
)
|
||||
|
||||
# Test apparmor profile states by using `diff` against `aa-status`
|
||||
with subtest("apparmorProfileStates"):
|
||||
machine.succeed("${getExe' pkgs.diffutils "diff"} -u \
|
||||
<(${getExe' pkgs.apparmor-bin-utils "aa-status"} --json | ${getExe pkgs.jq} --sort-keys . ) \
|
||||
<(${getExe pkgs.jq} --sort-keys . ${
|
||||
pkgs.writers.writeJSON "expectedStates.json" {
|
||||
version = "2";
|
||||
processes = { };
|
||||
profiles = {
|
||||
hexdump = "enforce";
|
||||
hello = "enforce";
|
||||
sl = "complain";
|
||||
};
|
||||
}
|
||||
})")
|
||||
# Test apparmor profile states by using `diff` against `aa-status`
|
||||
with subtest("apparmorProfileStates"):
|
||||
machine.succeed("${getExe' pkgs.diffutils "diff"} -u \
|
||||
<(${getExe' pkgs.apparmor-bin-utils "aa-status"} --json | ${getExe pkgs.jq} --sort-keys . ) \
|
||||
<(${getExe pkgs.jq} --sort-keys . ${
|
||||
pkgs.writers.writeJSON "expectedStates.json" {
|
||||
version = "2";
|
||||
processes = { };
|
||||
profiles = {
|
||||
hexdump = "enforce";
|
||||
hello = "enforce";
|
||||
sl = "complain";
|
||||
};
|
||||
}
|
||||
})")
|
||||
|
||||
# Test apparmor profile files in /etc/apparmor.d/<name> to be either a correct symlink (sl) or have the right file contents (hello)
|
||||
with subtest("apparmorProfileTargets"):
|
||||
machine.succeed("${getExe' pkgs.diffutils "diff"} -u <(${getExe pkgs.file} /etc/static/apparmor.d/sl) ${pkgs.writeText "expected.link" ''
|
||||
/etc/static/apparmor.d/sl: symbolic link to ${./sl_profile}
|
||||
''}")
|
||||
machine.succeed("${getExe' pkgs.diffutils "diff"} -u /etc/static/apparmor.d/hello ${pkgs.writeText "expected.content" helloProfileContents}")
|
||||
# Test apparmor profile files in /etc/apparmor.d/<name> to be either a correct symlink (sl) or have the right file contents (hello)
|
||||
with subtest("apparmorProfileTargets"):
|
||||
machine.succeed("${getExe' pkgs.diffutils "diff"} -u <(${getExe pkgs.file} /etc/static/apparmor.d/sl) ${pkgs.writeText "expected.link" ''
|
||||
/etc/static/apparmor.d/sl: symbolic link to ${./sl_profile}
|
||||
''}")
|
||||
machine.succeed("${getExe' pkgs.diffutils "diff"} -u /etc/static/apparmor.d/hello ${pkgs.writeText "expected.content" helloProfileContents}")
|
||||
|
||||
|
||||
with subtest("apparmorProfileEnforce"):
|
||||
machine.succeed("${getExe pkgs.hello} 1> /tmp/test-file")
|
||||
machine.fail("${lib.getExe' pkgs.util-linux "hexdump"} /tmp/test-file") # no access to /tmp/test-file granted by apparmor
|
||||
'';
|
||||
}
|
||||
)
|
||||
with subtest("apparmorProfileEnforce"):
|
||||
machine.succeed("${getExe pkgs.hello} 1> /tmp/test-file")
|
||||
machine.fail("${lib.getExe' pkgs.util-linux "hexdump"} /tmp/test-file") # no access to /tmp/test-file granted by apparmor
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{ pkgs }:
|
||||
''
|
||||
ixr ${pkgs.bash}/libexec/**,
|
||||
mr ${pkgs.bash}/lib/**.so*,
|
||||
mr ${pkgs.bash}/lib64/**.so*,
|
||||
mr ${pkgs.bash}/share/**,
|
||||
r ${pkgs.bash},
|
||||
r ${pkgs.bash}/etc/**,
|
||||
r ${pkgs.bash}/lib/**,
|
||||
r ${pkgs.bash}/lib64/**,
|
||||
x ${pkgs.bash}/foo/**,
|
||||
ixr ${pkgs.bashNonInteractive}/libexec/**,
|
||||
mr ${pkgs.bashNonInteractive}/lib/**.so*,
|
||||
mr ${pkgs.bashNonInteractive}/lib64/**.so*,
|
||||
mr ${pkgs.bashNonInteractive}/share/**,
|
||||
r ${pkgs.bashNonInteractive},
|
||||
r ${pkgs.bashNonInteractive}/etc/**,
|
||||
r ${pkgs.bashNonInteractive}/lib/**,
|
||||
r ${pkgs.bashNonInteractive}/lib64/**,
|
||||
x ${pkgs.bashNonInteractive}/foo/**,
|
||||
ixr ${pkgs.glibc}/libexec/**,
|
||||
mr ${pkgs.glibc}/lib/**.so*,
|
||||
mr ${pkgs.glibc}/lib64/**.so*,
|
||||
@@ -54,6 +54,15 @@
|
||||
r ${pkgs.libunistring}/lib/**,
|
||||
r ${pkgs.libunistring}/lib64/**,
|
||||
x ${pkgs.libunistring}/foo/**,
|
||||
ixr ${pkgs.tzdata}/libexec/**,
|
||||
mr ${pkgs.tzdata}/lib/**.so*,
|
||||
mr ${pkgs.tzdata}/lib64/**.so*,
|
||||
mr ${pkgs.tzdata}/share/**,
|
||||
r ${pkgs.tzdata},
|
||||
r ${pkgs.tzdata}/etc/**,
|
||||
r ${pkgs.tzdata}/lib/**,
|
||||
r ${pkgs.tzdata}/lib64/**,
|
||||
x ${pkgs.tzdata}/foo/**,
|
||||
ixr ${pkgs.glibc.libgcc}/libexec/**,
|
||||
mr ${pkgs.glibc.libgcc}/lib/**.so*,
|
||||
mr ${pkgs.glibc.libgcc}/lib64/**.so*,
|
||||
|
||||
+28
-30
@@ -1,38 +1,36 @@
|
||||
import ./make-test-python.nix (
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "archi";
|
||||
meta.maintainers = with lib.maintainers; [ paumr ];
|
||||
{ lib, ... }:
|
||||
{
|
||||
name = "archi";
|
||||
meta.maintainers = with lib.maintainers; [ paumr ];
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./common/x11.nix
|
||||
];
|
||||
nodes.machine =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./common/x11.nix
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [ archi ];
|
||||
};
|
||||
environment.systemPackages = with pkgs; [ archi ];
|
||||
};
|
||||
|
||||
enableOCR = true;
|
||||
enableOCR = true;
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_x()
|
||||
testScript = ''
|
||||
machine.wait_for_x()
|
||||
|
||||
with subtest("createEmptyModel via CLI"):
|
||||
machine.succeed("Archi -application com.archimatetool.commandline.app -consoleLog -nosplash --createEmptyModel --saveModel smoke.archimate")
|
||||
machine.copy_from_vm("smoke.archimate", "")
|
||||
with subtest("createEmptyModel via CLI"):
|
||||
machine.succeed("Archi -application com.archimatetool.commandline.app -consoleLog -nosplash --createEmptyModel --saveModel smoke.archimate")
|
||||
machine.copy_from_vm("smoke.archimate", "")
|
||||
|
||||
with subtest("UI smoketest"):
|
||||
machine.succeed("DISPLAY=:0 Archi --createEmptyModel >&2 &")
|
||||
machine.wait_for_window("Archi")
|
||||
with subtest("UI smoketest"):
|
||||
machine.succeed("DISPLAY=:0 Archi --createEmptyModel >&2 &")
|
||||
machine.wait_for_window("Archi")
|
||||
|
||||
# wait till main UI is open
|
||||
# since OCR seems to be buggy wait_for_text was replaced by sleep, issue: #302965
|
||||
# machine.wait_for_text("Welcome to Archi")
|
||||
machine.sleep(20)
|
||||
# wait till main UI is open
|
||||
# since OCR seems to be buggy wait_for_text was replaced by sleep, issue: #302965
|
||||
# machine.wait_for_text("Welcome to Archi")
|
||||
machine.sleep(20)
|
||||
|
||||
machine.screenshot("welcome-screen")
|
||||
'';
|
||||
}
|
||||
)
|
||||
machine.screenshot("welcome-screen")
|
||||
'';
|
||||
}
|
||||
|
||||
+47
-49
@@ -1,54 +1,52 @@
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
rpcSecret = "supersecret";
|
||||
rpc-listen-port = 6800;
|
||||
curlBody = {
|
||||
jsonrpc = 2.0;
|
||||
id = 1;
|
||||
method = "aria2.getVersion";
|
||||
params = [ "token:${rpcSecret}" ];
|
||||
};
|
||||
in
|
||||
rec {
|
||||
name = "aria2";
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
rpcSecret = "supersecret";
|
||||
rpc-listen-port = 6800;
|
||||
curlBody = {
|
||||
jsonrpc = 2.0;
|
||||
id = 1;
|
||||
method = "aria2.getVersion";
|
||||
params = [ "token:${rpcSecret}" ];
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "aria2";
|
||||
|
||||
nodes.machine = {
|
||||
environment.etc."aria2Rpc".text = rpcSecret;
|
||||
services.aria2 = {
|
||||
enable = true;
|
||||
rpcSecretFile = "/etc/aria2Rpc";
|
||||
settings = {
|
||||
inherit rpc-listen-port;
|
||||
allow-overwrite = false;
|
||||
check-integrity = true;
|
||||
console-log-level = "warn";
|
||||
listen-port = [
|
||||
{
|
||||
from = 20000;
|
||||
to = 20010;
|
||||
}
|
||||
{
|
||||
from = 22222;
|
||||
to = 22222;
|
||||
}
|
||||
];
|
||||
max-concurrent-downloads = 50;
|
||||
seed-ratio = 1.2;
|
||||
summary-interval = 0;
|
||||
};
|
||||
nodes.machine = {
|
||||
environment.etc."aria2Rpc".text = rpcSecret;
|
||||
services.aria2 = {
|
||||
enable = true;
|
||||
rpcSecretFile = "/etc/aria2Rpc";
|
||||
settings = {
|
||||
inherit rpc-listen-port;
|
||||
allow-overwrite = false;
|
||||
check-integrity = true;
|
||||
console-log-level = "warn";
|
||||
listen-port = [
|
||||
{
|
||||
from = 20000;
|
||||
to = 20010;
|
||||
}
|
||||
{
|
||||
from = 22222;
|
||||
to = 22222;
|
||||
}
|
||||
];
|
||||
max-concurrent-downloads = 50;
|
||||
seed-ratio = 1.2;
|
||||
summary-interval = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.start()
|
||||
machine.wait_for_unit("aria2.service")
|
||||
curl_cmd = 'curl --fail-with-body -X POST -H "Content-Type: application/json" \
|
||||
-d \'${builtins.toJSON curlBody}\' http://localhost:${toString rpc-listen-port}/jsonrpc'
|
||||
print(machine.wait_until_succeeds(curl_cmd, timeout=10))
|
||||
machine.shutdown()
|
||||
'';
|
||||
testScript = ''
|
||||
machine.start()
|
||||
machine.wait_for_unit("aria2.service")
|
||||
curl_cmd = 'curl --fail-with-body -X POST -H "Content-Type: application/json" \
|
||||
-d \'${builtins.toJSON curlBody}\' http://localhost:${toString rpc-listen-port}/jsonrpc'
|
||||
print(machine.wait_until_succeeds(curl_cmd, timeout=10))
|
||||
machine.shutdown()
|
||||
'';
|
||||
|
||||
meta.maintainers = [ pkgs.lib.maintainers.timhae ];
|
||||
}
|
||||
)
|
||||
meta.maintainers = [ pkgs.lib.maintainers.timhae ];
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user