diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 04f9ae0c7302..4714b843f203 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -154,14 +154,38 @@ bdfde18037f8d9f9b641a4016c8ada4dc4cbf856 # nixos/ollama: format with nixfmt-rfc-style (#329561) 246d1ee533810ac1946d863bbd9de9b525818d56 +# steam: cleanup (#216972) +ad815aebfbfe1415ff6436521d545029c803c3fb + # nixos/nvidia: apply nixfmt-rfc-style (#313440) fbdcdde04a7caa007e825a8b822c75fab9adb2d6 +# treewide: reformat files which need reformatting after (#341407) +e0464e47880a69896f0fb1810f00e0de469f770a + # step-cli: format package.nix with nixfmt (#331629) fc7a83f8b62e90de5679e993d4d49ca014ea013d +# ndn-cxx: format with nixfmt-rfc-style +160b2b769c3b8a6d1ae9947afa77520fa2887db7 + +# ndn-tools: format with nixfmt-rfc-style +4882ef721ce3d7bb3b5e48ff80125255db515013 + +# nfd: format with nixfmt-rfc-style +548c2377fa81e2abfc192fbf4f521e601251c468 + # darwin.stdenv: format with nixfmt-rfc-style (#333962) 93c10ac9e561c6594d3baaeaff2341907390d9b8 # nrr: format with nixfmt-rfc-style (#334578) cffc27daf06c77c0d76bc35d24b929cb9d68c3c9 + +# nixos/kanidm: inherit lib, nixfmt +8f18393d380079904d072007fb19dc64baef0a3a + +# fetchurl: nixfmt-rfc-style +ce21e97a1f20dee15da85c084f9d1148d84f853b + +# percona: apply nixfmt +8d14fa2886fec877690c6d28cfcdba4503dbbcea diff --git a/.gitattributes b/.gitattributes index 01d363cbb1c1..32cd96ef9e2c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,3 +16,5 @@ nixos/doc/default.nix linguist-documentation=false nixos/modules/module-list.nix merge=union # pkgs/top-level/all-packages.nix merge=union + +ci/OWNERS linguist-language=CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e138cd66152a..eb8b282c7b36 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,391 +1,4 @@ -# CODEOWNERS file +# Use ci/OWNERS instead # -# This file is used to describe who owns what in this repository. This file does not -# replace `meta.maintainers` but is instead used for other things than derivations -# and modules, like documentation, package sets, and other assets. -# -# For documentation on this file, see https://help.github.com/articles/about-codeowners/ -# Mentioned users will get code review requests. -# -# IMPORTANT NOTE: in order to actually get pinged, commit access is required. -# This also holds true for GitHub teams. Since almost none of our teams have write -# permissions, you need to list all members of the team with commit access individually. - -# CI -/.github/workflows @NixOS/Security @Mic92 @zowoq -/.github/workflows/check-nix-format.yml @infinisil -/ci @infinisil @NixOS/Security - -# Develompent support -/.editorconfig @Mic92 @zowoq -/shell.nix @infinisil @NixOS/Security - -# Libraries -/lib @infinisil -/lib/systems @alyssais @ericson2314 -/lib/generators.nix @infinisil @Profpatsch -/lib/cli.nix @infinisil @Profpatsch -/lib/debug.nix @infinisil @Profpatsch -/lib/asserts.nix @infinisil @Profpatsch -/lib/path.* @infinisil -/lib/fileset @infinisil -## Libraries / Module system -/lib/modules.nix @infinisil @roberth -/lib/types.nix @infinisil @roberth -/lib/options.nix @infinisil @roberth -/lib/tests/modules.sh @infinisil @roberth -/lib/tests/modules @infinisil @roberth - -# Nixpkgs Internals -/default.nix @Ericson2314 -/pkgs/top-level/default.nix @Ericson2314 -/pkgs/top-level/impure.nix @Ericson2314 -/pkgs/top-level/stage.nix @Ericson2314 -/pkgs/top-level/splice.nix @Ericson2314 -/pkgs/top-level/release-cross.nix @Ericson2314 -/pkgs/stdenv @philiptaron -/pkgs/stdenv/generic @Ericson2314 -/pkgs/stdenv/generic/check-meta.nix @Ericson2314 -/pkgs/stdenv/cross @Ericson2314 -/pkgs/build-support @philiptaron -/pkgs/build-support/cc-wrapper @Ericson2314 -/pkgs/build-support/bintools-wrapper @Ericson2314 -/pkgs/build-support/setup-hooks @Ericson2314 -/pkgs/build-support/setup-hooks/auto-patchelf.sh @layus -/pkgs/build-support/setup-hooks/auto-patchelf.py @layus -/pkgs/pkgs-lib @infinisil -## Format generators/serializers -/pkgs/pkgs-lib/formats/libconfig @h7x4 -/pkgs/pkgs-lib/formats/hocon @h7x4 - -# pkgs/by-name -/pkgs/test/check-by-name @infinisil -/pkgs/by-name/README.md @infinisil -/pkgs/top-level/by-name-overlay.nix @infinisil -/.github/workflows/check-by-name.yml @infinisil - -# Nixpkgs build-support -/pkgs/build-support/writers @lassulus @Profpatsch - -# Nixpkgs make-disk-image -/doc/build-helpers/images/makediskimage.section.md @raitobezarius -/nixos/lib/make-disk-image.nix @raitobezarius - -# Nix, the package manager -# @raitobezarius is not "code owner", but is listed here to be notified of changes -# pertaining to the Nix package manager. -# i.e. no authority over those files. -pkgs/tools/package-management/nix/ @NixOS/nix-team @raitobezarius -nixos/modules/installer/tools/nix-fallback-paths.nix @NixOS/nix-team @raitobezarius - -# Nixpkgs documentation -/maintainers/scripts/db-to-md.sh @jtojnar @ryantm -/maintainers/scripts/doc @jtojnar @ryantm - -# Contributor documentation -/CONTRIBUTING.md @infinisil -/.github/PULL_REQUEST_TEMPLATE.md @infinisil -/doc/contributing/ @infinisil -/doc/contributing/contributing-to-documentation.chapter.md @jtojnar @infinisil -/lib/README.md @infinisil -/doc/README.md @infinisil -/nixos/README.md @infinisil -/pkgs/README.md @infinisil -/maintainers/README.md @infinisil - -# User-facing development documentation -/doc/development.md @infinisil -/doc/development @infinisil - -# NixOS Internals -/nixos/default.nix @infinisil -/nixos/lib/from-env.nix @infinisil -/nixos/lib/eval-config.nix @infinisil -/nixos/modules/system/activation/bootspec.nix @grahamc @cole-h @raitobezarius -/nixos/modules/system/activation/bootspec.cue @grahamc @cole-h @raitobezarius - -# NixOS integration test driver -/nixos/lib/test-driver @tfc - -# NixOS QEMU virtualisation -/nixos/virtualisation/qemu-vm.nix @raitobezarius - -# ACME -/nixos/modules/security/acme @arianvp @flokli @aanderse @emilazy # no merge permission: @m1cr0man - -# Systemd -/nixos/modules/system/boot/systemd.nix @NixOS/systemd -/nixos/modules/system/boot/systemd @NixOS/systemd -/nixos/lib/systemd-*.nix @NixOS/systemd -/pkgs/os-specific/linux/systemd @NixOS/systemd - -# Systemd-boot -/nixos/modules/system/boot/loader/systemd-boot @JulienMalka - -# Images and installer media -/nixos/modules/installer/cd-dvd/ -/nixos/modules/installer/sd-card/ - -# Updaters -## update.nix -/maintainers/scripts/update.nix @jtojnar -/maintainers/scripts/update.py @jtojnar -## common-updater-scripts -/pkgs/common-updater/scripts/update-source-version @jtojnar - -# Python-related code and docs -/doc/languages-frameworks/python.section.md @mweinelt @natsukium -/maintainers/scripts/update-python-libraries @natsukium -/pkgs/development/interpreters/python @natsukium -/pkgs/top-level/python-packages.nix @natsukium -/pkgs/top-level/release-python.nix @natsukium - -# Haskell -/doc/languages-frameworks/haskell.section.md @sternenseemann @maralorn -/maintainers/scripts/haskell @sternenseemann @maralorn -/pkgs/development/compilers/ghc @sternenseemann @maralorn -/pkgs/development/haskell-modules @sternenseemann @maralorn -/pkgs/test/haskell @sternenseemann @maralorn -/pkgs/top-level/release-haskell.nix @sternenseemann @maralorn -/pkgs/top-level/haskell-packages.nix @sternenseemann @maralorn - -# Perl -/pkgs/development/interpreters/perl @stigtsp @zakame @marcusramberg -/pkgs/top-level/perl-packages.nix @stigtsp @zakame @marcusramberg -/pkgs/development/perl-modules @stigtsp @zakame @marcusramberg - -# R -/pkgs/applications/science/math/R @jbedo -/pkgs/development/r-modules @jbedo - -# Rust -/pkgs/development/compilers/rust @Mic92 @zowoq @winterqt @figsoda -/pkgs/build-support/rust @zowoq @winterqt @figsoda -/doc/languages-frameworks/rust.section.md @zowoq @winterqt @figsoda - -# C compilers -/pkgs/development/compilers/gcc -/pkgs/development/compilers/llvm @RossComputerGuy -/pkgs/development/compilers/emscripten @raitobezarius -/doc/languages-frameworks/emscripten.section.md @raitobezarius - -# Audio -/nixos/modules/services/audio/botamusique.nix @mweinelt -/nixos/modules/services/audio/snapserver.nix @mweinelt -/nixos/tests/modules/services/audio/botamusique.nix @mweinelt -/nixos/tests/snapcast.nix @mweinelt - -# Browsers -/pkgs/applications/networking/browsers/firefox @mweinelt -/pkgs/applications/networking/browsers/chromium @emilylange -/nixos/tests/chromium.nix @emilylange - -# Certificate Authorities -pkgs/data/misc/cacert/ @ajs124 @lukegb @mweinelt -pkgs/development/libraries/nss/ @ajs124 @lukegb @mweinelt -pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt - -# Jetbrains -/pkgs/applications/editors/jetbrains @edwtjo - -# Licenses -/lib/licenses.nix @alyssais - -# Qt -/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000 @ttuegel -/pkgs/development/libraries/qt-6 @K900 @NickCao @SuperSandro2000 @ttuegel - -# KDE / Plasma 5 -/pkgs/applications/kde @K900 @NickCao @SuperSandro2000 @ttuegel -/pkgs/desktops/plasma-5 @K900 @NickCao @SuperSandro2000 @ttuegel -/pkgs/development/libraries/kde-frameworks @K900 @NickCao @SuperSandro2000 @ttuegel - -# KDE / Plasma 6 -/pkgs/kde @K900 @NickCao @SuperSandro2000 @ttuegel -/maintainers/scripts/kde @K900 @NickCao @SuperSandro2000 @ttuegel - -# PostgreSQL and related stuff -/pkgs/servers/sql/postgresql @thoughtpolice -/nixos/modules/services/databases/postgresql.xml @thoughtpolice -/nixos/modules/services/databases/postgresql.nix @thoughtpolice -/nixos/tests/postgresql.nix @thoughtpolice - -# Hardened profile & related modules -/nixos/modules/profiles/hardened.nix @joachifm -/nixos/modules/security/hidepid.nix @joachifm -/nixos/modules/security/lock-kernel-modules.nix @joachifm -/nixos/modules/security/misc.nix @joachifm -/nixos/tests/hardened.nix @joachifm -/pkgs/os-specific/linux/kernel/hardened-config.nix @joachifm - -# Home Automation -/nixos/modules/services/misc/home-assistant.nix @mweinelt -/nixos/modules/services/misc/zigbee2mqtt.nix @mweinelt -/nixos/tests/home-assistant.nix @mweinelt -/nixos/tests/zigbee2mqtt.nix @mweinelt -/pkgs/servers/home-assistant @mweinelt -/pkgs/tools/misc/esphome @mweinelt - -# Network Time Daemons -/pkgs/tools/networking/chrony @thoughtpolice -/pkgs/tools/networking/ntp @thoughtpolice -/pkgs/tools/networking/openntpd @thoughtpolice -/nixos/modules/services/networking/ntp @thoughtpolice - -# Network -/pkgs/tools/networking/kea/default.nix @mweinelt -/pkgs/tools/networking/babeld/default.nix @mweinelt -/nixos/modules/services/networking/babeld.nix @mweinelt -/nixos/modules/services/networking/kea.nix @mweinelt -/nixos/modules/services/networking/knot.nix @mweinelt -/nixos/modules/services/monitoring/prometheus/exporters/kea.nix @mweinelt -/nixos/tests/babeld.nix @mweinelt -/nixos/tests/kea.nix @mweinelt -/nixos/tests/knot.nix @mweinelt - -# Web servers -/doc/packages/nginx.section.md @raitobezarius -/pkgs/servers/http/nginx/ @raitobezarius -/nixos/modules/services/web-servers/nginx/ @raitobezarius - -# Dhall -/pkgs/development/dhall-modules @Gabriella439 @Profpatsch @ehmry -/pkgs/development/interpreters/dhall @Gabriella439 @Profpatsch @ehmry - -# Idris -/pkgs/development/idris-modules @Infinisil - -# Bazel -/pkgs/development/tools/build-managers/bazel @Profpatsch - -# NixOS modules for e-mail and dns services -/nixos/modules/services/mail/mailman.nix @peti -/nixos/modules/services/mail/postfix.nix @peti -/nixos/modules/services/networking/bind.nix @peti -/nixos/modules/services/mail/rspamd.nix @peti - -# Emacs -/pkgs/applications/editors/emacs/elisp-packages @adisbladis -/pkgs/applications/editors/emacs @adisbladis -/pkgs/top-level/emacs-packages.nix @adisbladis - -# Kakoune -/pkgs/applications/editors/kakoune @philiptaron - -# Neovim -/pkgs/applications/editors/neovim @figsoda @teto - -# VimPlugins -/pkgs/applications/editors/vim/plugins @figsoda - -# VsCode Extensions -/pkgs/applications/editors/vscode/extensions - -# PHP interpreter, packages, extensions, tests and documentation -/doc/languages-frameworks/php.section.md @aanderse @drupol @globin @ma27 @talyz -/nixos/tests/php @aanderse @drupol @globin @ma27 @talyz -/pkgs/build-support/php/build-pecl.nix @aanderse @drupol @globin @ma27 @talyz -/pkgs/build-support/php @drupol -/pkgs/development/interpreters/php @jtojnar @aanderse @drupol @globin @ma27 @talyz -/pkgs/development/php-packages @aanderse @drupol @globin @ma27 @talyz -/pkgs/top-level/php-packages.nix @jtojnar @aanderse @drupol @globin @ma27 @talyz - -# Docker tools -/pkgs/build-support/docker @roberth -/nixos/tests/docker-tools* @roberth -/doc/build-helpers/images/dockertools.section.md @roberth - -# Blockchains -/pkgs/applications/blockchains @mmahut @RaghavSood - -# Go -/doc/languages-frameworks/go.section.md @kalbasit @katexochen @Mic92 @zowoq -/pkgs/build-support/go @kalbasit @katexochen @Mic92 @zowoq -/pkgs/development/compilers/go @kalbasit @katexochen @Mic92 @zowoq - -# GNOME -/pkgs/desktops/gnome @jtojnar -/pkgs/desktops/gnome/extensions @jtojnar -/pkgs/build-support/make-hardcode-gsettings-patch @jtojnar - -# Cinnamon -/pkgs/by-name/ci/cinnamon-* @mkg20001 -/pkgs/by-name/cj/cjs @mkg20001 -/pkgs/by-name/mu/muffin @mkg20001 -/pkgs/by-name/ne/nemo @mkg20001 -/pkgs/by-name/ne/nemo-* @mkg20001 - -# nim -/pkgs/development/compilers/nim @ehmry -/pkgs/development/nim-packages @ehmry -/pkgs/top-level/nim-packages.nix @ehmry - -# terraform providers -/pkgs/applications/networking/cluster/terraform-providers @zowoq - -# Forgejo -nixos/modules/services/misc/forgejo.nix @adamcstephens @bendlas @emilylange -pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange - -# Dotnet -/pkgs/build-support/dotnet @corngood -/pkgs/development/compilers/dotnet @corngood -/pkgs/test/dotnet @corngood -/doc/languages-frameworks/dotnet.section.md @corngood - -# Node.js -/pkgs/build-support/node/build-npm-package @winterqt -/pkgs/build-support/node/fetch-npm-deps @winterqt -/doc/languages-frameworks/javascript.section.md @winterqt - -# environment.noXlibs option aka NoX -/nixos/modules/config/no-x-libs.nix @SuperSandro2000 - -# OCaml -/pkgs/build-support/ocaml @ulrikstrid -/pkgs/development/compilers/ocaml @ulrikstrid -/pkgs/development/ocaml-modules @ulrikstrid - -# ZFS -pkgs/os-specific/linux/zfs/2_1.nix @raitobezarius -pkgs/os-specific/linux/zfs/generic.nix @raitobezarius -nixos/modules/tasks/filesystems/zfs.nix @raitobezarius -nixos/tests/zfs.nix @raitobezarius - -# Zig -/pkgs/development/compilers/zig @figsoda -/doc/hooks/zig.section.md @figsoda - -# Buildbot -nixos/modules/services/continuous-integration/buildbot @Mic92 @zowoq -nixos/tests/buildbot.nix @Mic92 @zowoq -pkgs/development/tools/continuous-integration/buildbot @Mic92 @zowoq - -# Pretix -pkgs/by-name/pr/pretix/ @mweinelt -pkgs/by-name/pr/pretalx/ @mweinelt -nixos/modules/services/web-apps/pretix.nix @mweinelt -nixos/modules/services/web-apps/pretalx.nix @mweinelt -nixos/tests/web-apps/pretix.nix @mweinelt -nixos/tests/web-apps/pretalx.nix @mweinelt - -# incus/lxc -nixos/maintainers/scripts/incus/ @adamcstephens -nixos/modules/virtualisation/incus.nix @adamcstephens -nixos/modules/virtualisation/lxc* @adamcstephens -nixos/tests/incus/ @adamcstephens -pkgs/by-name/in/incus/ @adamcstephens -pkgs/by-name/lx/lxc* @adamcstephens - -# ExpidusOS, Flutter -/pkgs/development/compilers/flutter @RossComputerGuy -/pkgs/desktops/expidus @RossComputerGuy - -# GNU Tar & Zip -/pkgs/tools/archivers/gnutar @RossComputerGuy -/pkgs/tools/archivers/zip @RossComputerGuy - -# SELinux -/pkgs/os-specific/linux/checkpolicy @RossComputerGuy -/pkgs/os-specific/linux/libselinux @RossComputerGuy -/pkgs/os-specific/linux/libsepol @RossComputerGuy +# This file would be for the native code owner feature of GitHub, +# but is not being used because of its problems, see ci/OWNERS diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c2351056bf8b..20e260b40894 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,7 @@ -## Description of changes diff --git a/.github/labeler.yml b/.github/labeler.yml index 9ef1ec30b6e9..485bcce6a8a4 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -270,6 +270,12 @@ - changed-files: - any-glob-to-any-file: - .github/**/* + - CONTRIBUTING.md + - pkgs/README.md + - nixos/README.md + - maintainers/README.md + - lib/README.md + - doc/README.md "6.topic: printing": - any: @@ -374,6 +380,19 @@ - any-glob-to-any-file: - pkgs/applications/editors/vscode/**/* +"6.topic: xen-project": + - any: + - changed-files: + - any-glob-to-any-file: + - nixos/modules/virtualisation/xen* + - pkgs/by-name/xe/xen/* + - pkgs/by-name/qe/qemu_xen/* + - pkgs/by-name/xe/xen-guest-agent/* + - pkgs/by-name/xt/xtf/* + - pkgs/build-support/xen/* + - pkgs/development/ocaml-modules/xen*/* + - pkgs/development/ocaml-modules/vchan/* + "6.topic: xfce": - any: - changed-files: diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 49ab3fefb64d..5ca7977fa902 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -20,7 +20,7 @@ jobs: if: github.repository_owner == 'NixOS' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs diff --git a/.github/workflows/basic-eval.yml b/.github/workflows/basic-eval.yml index fc7df3a1aa8d..5a8f20eb711d 100644 --- a/.github/workflows/basic-eval.yml +++ b/.github/workflows/basic-eval.yml @@ -19,8 +19,8 @@ jobs: runs-on: ubuntu-latest # we don't limit this action to only NixOS repo since the checks are cheap and useful developer feedback steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 - uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 with: # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. diff --git a/.github/workflows/check-by-name.yml b/.github/workflows/check-by-name.yml deleted file mode 100644 index 34c9e0632b5e..000000000000 --- a/.github/workflows/check-by-name.yml +++ /dev/null @@ -1,124 +0,0 @@ -# Checks pkgs/by-name (see pkgs/by-name/README.md) -# using the nixpkgs-check-by-name tool (see https://github.com/NixOS/nixpkgs-check-by-name) -# -# When you make changes to this workflow, also update pkgs/test/check-by-name/run-local.sh adequately -name: Check pkgs/by-name - -on: - # Using pull_request_target instead of pull_request avoids having to approve first time contributors - pull_request_target: - # This workflow depends on the base branch of the PR, - # but changing the base branch is not included in the default trigger events, - # which would be `opened`, `synchronize` or `reopened`. - # Instead it causes an `edited` event, so we need to add it explicitly here - # While `edited` is also triggered when the PR title/body is changed, - # this PR action is fairly quick, and PR's don't get edited that often, - # so it shouldn't be a problem - # There is a feature request for adding a `base_changed` event: - # https://github.com/orgs/community/discussions/35058 - types: [opened, synchronize, reopened, edited] - -permissions: {} - -# We don't use a concurrency group here, because the action is triggered quite often (due to the PR edit -# trigger), and contributers would get notified on any canceled run. -# There is a feature request for supressing notifications on concurrency-canceled runs: -# https://github.com/orgs/community/discussions/13015 - -jobs: - check: - name: pkgs-by-name-check - # This needs to be x86_64-linux, because we depend on the tooling being pre-built in the GitHub releases - runs-on: ubuntu-latest - # This should take 1 minute at most, but let's be generous. - # The default of 6 hours is definitely too long - timeout-minutes: 10 - steps: - # This step has to be in this file, - # because it's needed to determine which revision of the repository to fetch, - # and we can only use other files from the repository once it's fetched. - - name: Resolving the merge commit - env: - GH_TOKEN: ${{ github.token }} - run: | - # This checks for mergeability of a pull request as recommended in - # https://docs.github.com/en/rest/guides/using-the-rest-api-to-interact-with-your-git-database?apiVersion=2022-11-28#checking-mergeability-of-pull-requests - - # Retry the API query this many times - retryCount=5 - # Start with 5 seconds, but double every retry - retryInterval=5 - while true; do - echo "Checking whether the pull request can be merged" - prInfo=$(gh api \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/"$GITHUB_REPOSITORY"/pulls/${{ github.event.pull_request.number }}) - mergeable=$(jq -r .mergeable <<< "$prInfo") - mergedSha=$(jq -r .merge_commit_sha <<< "$prInfo") - - if [[ "$mergeable" == "null" ]]; then - if (( retryCount == 0 )); then - echo "Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com/" - exit 1 - else - (( retryCount -= 1 )) || true - - # null indicates that GitHub is still computing whether it's mergeable - # Wait a couple seconds before trying again - echo "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)" - sleep "$retryInterval" - - (( retryInterval *= 2 )) || true - fi - else - break - fi - done - - if [[ "$mergeable" == "true" ]]; then - echo "The PR can be merged, checking the merge commit $mergedSha" - echo "mergedSha=$mergedSha" >> "$GITHUB_ENV" - else - echo "The PR cannot be merged, it has a merge conflict, skipping the rest.." - fi - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - if: env.mergedSha - with: - # pull_request_target checks out the base branch by default - ref: ${{ env.mergedSha }} - # Fetches the merge commit and its parents - fetch-depth: 2 - - name: Checking out base branch - if: env.mergedSha - run: | - base=$(mktemp -d) - git worktree add "$base" "$(git rev-parse HEAD^1)" - echo "base=$base" >> "$GITHUB_ENV" - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - if: env.mergedSha - - name: Fetching the pinned tool - if: env.mergedSha - # Update the pinned version using pkgs/test/check-by-name/update-pinned-tool.sh - run: | - # The pinned version of the tooling to use - toolVersion=$(> "$GITHUB_ENV" - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: # explicitly enable sandbox extra_nix_config: sandbox = true diff --git a/.github/workflows/check-nixf-tidy.yml b/.github/workflows/check-nixf-tidy.yml index a3f37d8131c8..7facdeee7928 100644 --- a/.github/workflows/check-nixf-tidy.yml +++ b/.github/workflows/check-nixf-tidy.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.pull_request.title, '[skip treewide]')" steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge @@ -32,7 +32,7 @@ jobs: # This should not be a URL, because it would allow PRs to run arbitrary code in CI! rev=$(jq -r .rev ci/pinned-nixpkgs.json) echo "url=https://github.com/NixOS/nixpkgs/archive/$rev.tar.gz" >> "$GITHUB_ENV" - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: # explicitly enable sandbox extra_nix_config: sandbox = true diff --git a/.github/workflows/check-shell.yml b/.github/workflows/check-shell.yml index 0ecc3b0c7baf..0ece4946f6d8 100644 --- a/.github/workflows/check-shell.yml +++ b/.github/workflows/check-shell.yml @@ -10,11 +10,11 @@ jobs: name: shell-check-x86_64-linux runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 - name: Build shell run: nix-build shell.nix @@ -22,10 +22,10 @@ jobs: name: shell-check-aarch64-darwin runs-on: macos-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 - name: Build shell run: nix-build shell.nix diff --git a/.github/workflows/codeowners.yml b/.github/workflows/codeowners.yml new file mode 100644 index 000000000000..9d781c6ef080 --- /dev/null +++ b/.github/workflows/codeowners.yml @@ -0,0 +1,89 @@ +name: Codeowners + +# This workflow depends on a GitHub App with the following permissions: +# - Repository > Administration: read-only +# - Organization > Members: read-only +# - Repository > Pull Requests: read-write +# The App needs to be installed on this repository +# the OWNER_APP_ID repository variable needs to be set +# the OWNER_APP_PRIVATE_KEY repository secret needs to be set + +on: + pull_request_target: + types: [opened, ready_for_review, synchronize, reopened, edited] + +env: + OWNERS_FILE: ci/OWNERS + # Don't do anything on draft PRs + DRY_MODE: ${{ github.event.pull_request.draft && '1' || '' }} + +jobs: + # Check that code owners is valid + check: + name: Check + runs-on: ubuntu-latest + steps: + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 + + - uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 + if: github.repository_owner == 'NixOS' + with: + # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. + name: nixpkgs-ci + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + + # Important: Because we use pull_request_target, this checks out the base branch of the PR, not the PR itself. + # We later build and run code from the base branch with access to secrets, + # so it's important this is not the PRs code. + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + with: + path: base + + - name: Build codeowners validator + run: nix-build base/ci -A codeownersValidator + + - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + id: app-token + with: + app-id: ${{ vars.OWNER_APP_ID }} + private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} + + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + with: + ref: refs/pull/${{ github.event.number }}/merge + path: pr + + - name: Validate codeowners + run: result/bin/codeowners-validator + env: + OWNERS_FILE: pr/${{ env.OWNERS_FILE }} + GITHUB_ACCESS_TOKEN: ${{ steps.app-token.outputs.token }} + REPOSITORY_PATH: pr + OWNER_CHECKER_REPOSITORY: ${{ github.repository }} + # Set this to "notowned,avoid-shadowing" to check that all files are owned by somebody + EXPERIMENTAL_CHECKS: "avoid-shadowing" + + # Request reviews from code owners + request: + name: Request + runs-on: ubuntu-latest + steps: + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 + + # Important: Because we use pull_request_target, this checks out the base branch of the PR, not the PR head. + # This is intentional, because we need to request the review of owners as declared in the base branch. + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + + - uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0 + id: app-token + with: + app-id: ${{ vars.OWNER_APP_ID }} + private-key: ${{ secrets.OWNER_APP_PRIVATE_KEY }} + + - name: Build review request package + run: nix-build ci -A requestReviews + + - name: Request reviews + run: result/bin/request-reviews.sh ${{ github.repository }} ${{ github.event.number }} "$OWNERS_FILE" + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml index 26530f30f468..b4ef16a734b7 100644 --- a/.github/workflows/editorconfig.yml +++ b/.github/workflows/editorconfig.yml @@ -25,11 +25,11 @@ jobs: - name: print list of changed files run: | cat "$HOME/changed_files" - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: # nixpkgs commit is pinned so that it doesn't break # editorconfig-checker 2.4.0 diff --git a/.github/workflows/manual-nixos.yml b/.github/workflows/manual-nixos.yml index 002d44c8797d..2ae4d929c12d 100644 --- a/.github/workflows/manual-nixos.yml +++ b/.github/workflows/manual-nixos.yml @@ -15,11 +15,11 @@ jobs: runs-on: ubuntu-latest if: github.repository_owner == 'NixOS' steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: # explicitly enable sandbox extra_nix_config: sandbox = true diff --git a/.github/workflows/manual-nixpkgs.yml b/.github/workflows/manual-nixpkgs.yml index 00e84854495a..676a554107d5 100644 --- a/.github/workflows/manual-nixpkgs.yml +++ b/.github/workflows/manual-nixpkgs.yml @@ -17,11 +17,11 @@ jobs: runs-on: ubuntu-latest if: github.repository_owner == 'NixOS' steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: # explicitly enable sandbox extra_nix_config: sandbox = true diff --git a/.github/workflows/nix-parse.yml b/.github/workflows/nix-parse.yml index 7f55322d85e6..352cb81d87ed 100644 --- a/.github/workflows/nix-parse.yml +++ b/.github/workflows/nix-parse.yml @@ -25,12 +25,12 @@ jobs: if [[ -s "$HOME/changed_files" ]]; then echo "CHANGED_FILES=$HOME/changed_files" > "$GITHUB_ENV" fi - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: # pull_request_target checks out the base branch by default ref: refs/pull/${{ github.event.pull_request.number }}/merge if: ${{ env.CHANGED_FILES && env.CHANGED_FILES != '' }} - - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 with: nix_path: nixpkgs=channel:nixpkgs-unstable - name: Parse all changed or added nix files diff --git a/.github/workflows/nixpkgs-vet.yml b/.github/workflows/nixpkgs-vet.yml new file mode 100644 index 000000000000..2dc325b4c66c --- /dev/null +++ b/.github/workflows/nixpkgs-vet.yml @@ -0,0 +1,86 @@ +# `nixpkgs-vet` is a tool to vet Nixpkgs: its architecture, package structure, and more. +# Among other checks, it makes sure that `pkgs/by-name` (see `../../pkgs/by-name/README.md`) follows the validity rules outlined in [RFC 140](https://github.com/NixOS/rfcs/pull/140). +# When you make changes to this workflow, please also update `ci/nixpkgs-vet.sh` to reflect the impact of your work to the CI. +# See https://github.com/NixOS/nixpkgs-vet for details on the tool and its checks. +name: Vet nixpkgs + +on: + # Using pull_request_target instead of pull_request avoids having to approve first time contributors. + pull_request_target: + # This workflow depends on the base branch of the PR, but changing the base branch is not included in the default trigger events, which would be `opened`, `synchronize` or `reopened`. + # Instead it causes an `edited` event, so we need to add it explicitly here. + # While `edited` is also triggered when the PR title/body is changed, this PR action is fairly quick, and PRs don't get edited **that** often, so it shouldn't be a problem. + # There is a feature request for adding a `base_changed` event: https://github.com/orgs/community/discussions/35058 + types: [opened, synchronize, reopened, edited] + +permissions: {} + +# We don't use a concurrency group here, because the action is triggered quite often (due to the PR edit trigger), and contributors would get notified on any canceled run. +# There is a feature request for suppressing notifications on concurrency-canceled runs: https://github.com/orgs/community/discussions/13015 + +jobs: + check: + name: nixpkgs-vet + # This needs to be x86_64-linux, because we depend on the tooling being pre-built in the GitHub releases. + runs-on: ubuntu-latest + # This should take 1 minute at most, but let's be generous. The default of 6 hours is definitely too long. + timeout-minutes: 10 + steps: + # This checks out the base branch because of pull_request_target + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + with: + path: base + sparse-checkout: ci + - name: Resolving the merge commit + env: + GH_TOKEN: ${{ github.token }} + run: | + if mergedSha=$(base/ci/get-merge-commit.sh ${{ github.repository }} ${{ github.event.number }}); then + echo "Checking the merge commit $mergedSha" + echo "mergedSha=$mergedSha" >> "$GITHUB_ENV" + else + echo "Skipping the rest..." + fi + rm -rf base + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + if: env.mergedSha + with: + # pull_request_target checks out the base branch by default + ref: ${{ env.mergedSha }} + # Fetches the merge commit and its parents + fetch-depth: 2 + - name: Checking out base branch + if: env.mergedSha + run: | + base=$(mktemp -d) + git worktree add "$base" "$(git rev-parse HEAD^1)" + echo "base=$base" >> "$GITHUB_ENV" + - uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30 + if: env.mergedSha + - name: Fetching the pinned tool + if: env.mergedSha + # Update the pinned version using ci/nixpkgs-vet/update-pinned-tool.sh + run: | + # The pinned version of the tooling to use. + toolVersion=$(> $GITHUB_OUTPUT - - name: update terraform-providers - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config user.name "github-actions[bot]" - echo | nix-shell \ - maintainers/scripts/update.nix \ - --argstr commit true \ - --argstr keep-going true \ - --argstr max-workers 2 \ - --argstr path terraform-providers - - name: get failed updates - run: | - echo 'FAILED<> $GITHUB_ENV - git ls-files --others >> $GITHUB_ENV - echo 'EOF' >> $GITHUB_ENV - # cleanup logs of failed updates so they aren't included in the PR - - name: clean repo - run: | - git clean -f - - name: create PR - uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0 - with: - body: | - Automatic update by [update-terraform-providers](https://github.com/NixOS/nixpkgs/blob/master/.github/workflows/update-terraform-providers.yml) action. - - https://github.com/NixOS/nixpkgs/actions/runs/${{ github.run_id }} - - These providers failed to update: - ``` - ${{ env.FAILED }} - ``` - - Check that all providers build with: - ``` - @ofborg build opentofu.full - ``` - If there is more than ten commits in the PR `ofborg` won't build it automatically and you will need to use the above command. - branch: terraform-providers-update - delete-branch: false - title: ${{ steps.setup.outputs.title }} - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.mailmap b/.mailmap index d7e9caacea7e..12ba1f6ae442 100644 --- a/.mailmap +++ b/.mailmap @@ -1,11 +1,16 @@ ajs124 Anderson Torres Atemu +Christina Sørensen +Christina Sørensen +Christina Sørensen <89321978+cafkafk@users.noreply.github.com> Daniel Løvbrøtte Olsen Fabian Affolter -goatastronaut0212 +goatastronaut0212 Janne Heß Jörg Thalheim +Lin Jian +Lin Jian <75130626+jian-lin@users.noreply.github.com> Martin Weinelt R. RyanTM Robert Hensing diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8d99e465cc0e..bc9927fe10d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,6 +93,8 @@ This section describes in some detail how changes can be made and proposed with 7. Respond to review comments, potential CI failures and potential merge conflicts by updating the pull request. Always keep the pull request in a mergeable state. + This process is covered in more detail from the non-technical side in [I opened a PR, how do I get it merged?](#i-opened-a-pr-how-do-i-get-it-merged). + The custom [OfBorg](https://github.com/NixOS/ofborg) CI system will perform various checks to help ensure code quality, whose results you can see at the bottom of the pull request. See [the OfBorg Readme](https://github.com/NixOS/ofborg#readme) for more details. @@ -193,19 +195,12 @@ The last checkbox is about whether it fits the guidelines in this `CONTRIBUTING. [rebase]: #rebasing-between-branches-ie-from-master-to-staging From time to time, changes between branches must be rebased, for example, if the -number of new rebuilds they would cause is too large for the target branch. When -rebasing, care must be taken to include only the intended changes, otherwise -many CODEOWNERS will be inadvertently requested for review. To achieve this, -rebasing should not be performed directly on the target branch, but on the merge -base between the current and target branch. As an additional precautionary measure, -you should temporarily mark the PR as draft for the duration of the operation. -This reduces the probability of mass-pinging people. (OfBorg might still -request a couple of persons for reviews though.) +number of new rebuilds they would cause is too large for the target branch. In the following example, we assume that the current branch, called `feature`, is based on `master`, and we rebase it onto the merge base between -`master` and `staging` so that the PR can eventually be retargeted to -`staging` without causing a mess. The example uses `upstream` as the remote for `NixOS/nixpkgs.git` +`master` and `staging` so that the PR can be retargeted to +`staging`. The example uses `upstream` as the remote for `NixOS/nixpkgs.git` while `origin` is the remote you are pushing to. @@ -234,36 +229,6 @@ git status git push origin feature --force-with-lease ``` -#### Something went wrong and a lot of people were pinged - -It happens. Remember to be kind, especially to new contributors. -There is no way back, so the pull request should be closed and locked -(if possible). The changes should be re-submitted in a new PR, in which the people -originally involved in the conversation need to manually be pinged again. -No further discussion should happen on the original PR, as a lot of people -are now subscribed to it. - -The following message (or a version thereof) might be left when closing to -describe the situation, since closing and locking without any explanation -is kind of rude: - -```markdown -It looks like you accidentally mass-pinged a bunch of people, which are now subscribed -and getting notifications for everything in this pull request. Unfortunately, they -cannot be automatically unsubscribed from the issue (removing review request does not -unsubscribe), therefore development cannot continue in this pull request anymore. - -Please open a new pull request with your changes, link back to this one and ping the -people actually involved in here over there. - -In order to avoid this in the future, there are instructions for how to properly -rebase between branches in our [contribution guidelines](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#rebasing-between-branches-ie-from-master-to-staging). -Setting your pull request to draft prior to rebasing is strongly recommended. -In draft status, you can preview the list of people that are about to be requested -for review, which allows you to sidestep this issue. -This is not a bulletproof method though, as OfBorg still does review requests even on draft PRs. -``` - ## How to backport pull requests [pr-backport]: #how-to-backport-pull-requests @@ -315,6 +280,22 @@ When reviewing a pull request, please always be nice and polite. Controversial c GitHub provides reactions as a simple and quick way to provide feedback to pull requests or any comments. The thumb-down reaction should be used with care and if possible accompanied with some explanation so the submitter has directions to improve their contribution. +When doing a review: +- Aim to drive the proposal to a timely conclusion. +- Focus on the proposed changes to keep the scope of the discussion narrow. +- Help the contributor prioritise their efforts towards getting their change merged. + +If you find anything related that could be improved but is not immediately required for acceptance, consider +- Implementing the changes yourself in a follow-up pull request (and request review from the person who inspired you) +- Tracking your idea in an issue +- Offering the original contributor to review a follow-up pull request +- Making concrete [suggestions](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request) in the same pull request. + +For example, follow-up changes could involve refactoring code in the affected files. + +But please remember not to make such additional considerations a blocker, and communicate that to the contributor, for example by following the [conventional comments](https://conventionalcomments.org/) pattern. +If the related change is essential for the contribution at hand, make clear why you think it is important to address that first. + Pull request reviews should include a list of what has been reviewed in a comment, so other reviewers and mergers can know the state of the review. All the review template samples provided in this section are generic and meant as examples. Their usage is optional and the reviewer is free to adapt them to their liking. @@ -327,7 +308,7 @@ If you consider having enough knowledge and experience in a topic and would like Container system, boot system and library changes are some examples of the pull requests fitting this category. -## How to merge pull requests +## How to merge pull requests yourself [pr-merge]: #how-to-merge-pull-requests To streamline automated updates, leverage the nixpkgs-merge-bot by simply commenting `@NixOS/nixpkgs-merge-bot merge`. The bot will verify if the following conditions are met, refusing to merge otherwise: @@ -337,10 +318,7 @@ To streamline automated updates, leverage the nixpkgs-merge-bot by simply commen Further, nixpkgs-merge-bot will ensure all ofBorg checks (except the Darwin-related ones) are successfully completed before merging the pull request. Should the checks still be underway, the bot patiently waits for ofBorg to finish before attempting the merge again. -For other pull requests, the *Nixpkgs committers* are people who have been given -permission to merge. - -It is possible for community members that have enough knowledge and experience on a special topic to contribute by merging pull requests. +For other pull requests, please see [I opened a PR, how do I get it merged?](#i-opened-a-pr-how-do-i-get-it-merged). In case the PR is stuck waiting for the original author to apply a trivial change (a typo, capitalisation change, etc.) and the author allowed the members @@ -354,7 +332,7 @@ The following paragraphs about how to deal with unactive contributors is just a Please note that contributors with commit rights unactive for more than three months will have their commit rights revoked. --> -Please see the discussion in [GitHub nixpkgs issue #50105](https://github.com/NixOS/nixpkgs/issues/50105) for information on how to proceed to be granted this level of access. +Please see the discussion in [GitHub nixpkgs issue #321665](https://github.com/NixOS/nixpkgs/issues/321665) for information on how to proceed to be granted this level of access. In a case a contributor definitively leaves the Nix community, they should create an issue or post on [Discourse](https://discourse.nixos.org) with references of packages and modules they maintain so the maintainership can be taken over by other contributors. @@ -537,6 +515,7 @@ To get a sense for what changes are considered mass rebuilds, see [previously me - [Commit conventions](./doc/README.md#commit-conventions) for changes to `doc`, the Nixpkgs manual. ### Writing good commit messages +[writing-good-commit-messages]: #writing-good-commit-messages In addition to writing properly formatted commit messages, it's important to include relevant information so other developers can later understand *why* a change was made. While this information usually can be found by digging code, mailing list/Discourse archives, pull request discussions or upstream changes, it may require a lot of work. @@ -621,7 +600,7 @@ Names of files and directories should be in lowercase, with dashes between words ```nix { - buildInputs = lib.optional stdenv.isDarwin iconv; + buildInputs = lib.optional stdenv.hostPlatform.isDarwin iconv; } ``` @@ -629,9 +608,180 @@ Names of files and directories should be in lowercase, with dashes between words ```nix { - buildInputs = if stdenv.isDarwin then [ iconv ] else null; + buildInputs = if stdenv.hostPlatform.isDarwin then [ iconv ] else null; } ``` As an exception, an explicit conditional expression with null can be used when fixing a important bug without triggering a mass rebuild. If this is done a follow up pull request _should_ be created to change the code to `lib.optional(s)`. + +## I opened a PR, how do I get it merged? +[i-opened-a-pr-how-do-i-get-it-merged]:#i-opened-a-pr-how-do-i-get-it-merged + +In order for your PR to be merged, someone with merge permissions on the repository ("committer") needs to review and merge it. +Because the group of people with merge permissions is mostly a collection of independent unpaid volunteers who do this in their own free time, this can take some time to happen. +It is entirely normal for your PR to sit around without any feedback for days, weeks or sometimes even months. +We strive to avoid the latter cases of course but the reality of it is that this does happen quite frequently. +Even when you get feedback, follow-up feedback may take similarly long. +Don't be intimidated by this and kindly ask for feedback again every so often. +If your change is good it will eventually be merged at some point. + +There are some things you can do to help speed up the process of your PR being merged though. +In order to speed the process up, you need to know what needs to happen before a committer will actually hit the merge button. +This section intends to give a little overview and insight of what happens after you create your PR. + +### The committer's perspective + +PRs have varying quality and even the best people make mistakes. +It is the role of the committer team to assess whether any PR's changes are good changes or not. +In order for any PR to be merged, at least one committer needs to be convinced of its quality enough to merge it. + +Committers typically assess three aspects of your PR: + +1. Whether the change's intention is necessary and desirable +2. Whether the code quality of your changes is good +3. Whether the artefacts produced by the code are good + +If you want your PR to get merged quickly and smoothly, it is in your best interest to help convince committers in these three aspects. + +### How to help committers assess your PR + +For the committer to judge your intention, it's best to explain why you've made your change. +This does not apply to trivial changes like version updates because the intention is obvious (though linking the changelog is appreciated). +For any more nuanced changed or even major version upgrades, it helps if you explain the background behind your change a bit. +E.g. if you're adding a package, explain what it is and why it should be in Nixpkgs. +This goes hand in hand with [Writing good commit messages](#writing-good-commit-messages). + +For the code quality assessment, you cannot do anything yourself as only the committer can do this and they already have your code to look at. +In order to minimise the need for back and forth though, do take a look over your code changes yourself and try to put yourself into the shoes of someone who didn't just write that code. +Would you immediately know what the code does by glancing at it? +If not, reviewers will notice this and will ask you to clarify the code by refactoring it and/or adding a few explanations in code comments. +Doing this preemptively can save you and the committer a lot of time. + +The code artefacts are the hardest for committers to assess because PRs touch all sorts of components: applications, libraries, NixOS modules, editor plugins and many many other things. +Any individual committer can only really assess components that they themselves know how to use however and yet they must still be convinced somehow. +There isn't a good generic solution to this but there are some ways easing the committer's job here: + +- Provide smoke tests that the committer can run without much research or setup. + + Committers usually don't have the time or interest to learn how your component works and how they could test its functionality. + If you can provide a quick guide on how to use the component in a meaningful way or a ready-made command that demonstrates that the component works as expected, the committer can easily convince themselves that your change is good. + If it can be automated, you could even turn this smoke test into an automated NixOS test which reviewers could simply run via Nix. +- Invite other users of the component to try it out and report their findings. + + If a committer sees the testimonials of other users trying your change and it works as expected for them, that too can convince the committer of your PR's quality. +- Describe what you have done to test your PR. + + If you can convince the committer that you have done sufficient quality assurance on your changes and they trust your report, this too can convince them of your PR's quality, albeit not as strongly as the methods above. +- Become a maintainer of the component. + + This isn't something you can do on your first few PRs touching a component but listed maintainers generally receive more trust when it comes to changes to their maintained components and committers may opt to merge changes without deeper review when they see they're done by their respective maintainer. + +Even if you adhere to all of these recommendations, it is still quite possible for your PR to be forgotten or abandoned by any given committer. +Please remain mindful of the fact that they are doing this on their own volition and unpaid in their free time and therefore [owe you nothing](https://mikemcquaid.com/open-source-maintainers-owe-you-nothing/). +Causing a stink in such a situation is a surefire way to get any other potential committer to not want to look at your PR either. +Ask them nicely whether they still intend to review your PR and find yourself another committer to look at your PR if not. + +### How can I get a committer to look at my PR? + +- Simply wait. Reviewers frequently browse open PRs and may happen to run across yours and take a look. +- Get non-committers to review/approve. Many committers filter open PRs for low-hanging fruit that are already been reviewed. +- [@-mention](https://github.blog/news-insights/mention-somebody-they-re-notified/) someone and ask them nicely +- Post in one of the channels made for this purpose if there has been no activity for at least one week + - The current "PRs ready for review" or "PRs already reviewed" threads in the [NixOS Discourse](https://discourse.nixos.org/c/dev/14) (of course choose the one that applies to your situation) + - The [Nixpkgs Review Requests Matrix room](https://matrix.to/#/#review-requests:nixos.org). + +### CI failed or got stuck on my PR, what do I do? + +First ensure that the failure is actually related to your change. +Sometimes, the CI system simply has a hiccup or the check was broken by someone else before you made your changes. +Read through the error message; it's usually quite easy to tell whether it is caused by anything you did by checking whether it mentions the component you touched anywhere. +If it is indeed caused by your change, obviously try to fix it. +Don't be afraid of asking for advice if you're uncertain how to do that, others have likely fixed such issues dozens of times and can help you out. +Your PR is unlikely to be merged if it has a known issue and it is the purpose of CI to alert you aswell as reviewers to these issues. + +ofBorg builds can often get stuck, particularly in PRs targeting `staging` and in builders for the Darwin platform. Reviewers will know how to handle them or when to ignore them. +Don't worry about it. +If there is a build failure however and it happened due to a package related to your change, you need to investigate it of course. +If ofBorg reveals the build to be broken on some platform and you don't have access to that platform, you should set your package's `meta.broken` accordingly. + +When in any doubt, please simply ask via a comment in your PR or through one of the help channels. + +## I received a review on my PR, how do I get it over the finish line? + +In the review process, the committer will have left some sort of feedback on your PR. +They may have immediately approved of your PR or even merged it but the more likely case is that they want you to change a few things or that they require further input. + +A reviewer may have taken a look at the code and it looked good to them ("Diff LGTM") but they still need to be convinced of the artefact's quality. +They might also be waiting on input from other users of the component or its listed maintainer on whether the intention of your PR makes sense for the component. +If you know of people who could help clarify any of this, please bring the PR to their attention. +The current state of the PR is frequently not clearly communicated, so please don't hesitate to ask about it if it's unclear to you. + +It's also possible for the reviewer to not be convinced that your PR is necessary or that the method you've chose to achieve your intention is the right one. + +Please explain your intentions and reasoning to the committer in such a case. +There may be constraints you had to work with which they're not aware of or qualities of your approach that they didn't immediately notice. +(If these weren't clear to the reviewer, that's a good sign you should explain them in your commit message or code comments!) + +There are some further pitfalls and realities which this section intends to make you aware of. + +### A reviewer requested a bunch of insubstantial changes on my PR + +The people involved in Nixpkgs care about code quality because, once in Nixpkgs, it needs to be maintained for many years to come. +It is therefore likely that other people will ask you to do some things in another way or adhere to some standard. +Sometimes however, they also care a bit too much and may ask you to adhere to a personal preference of theirs. +It's not always easy to tell which is which and whether the requests are critically important to merging the PR. +Sometimes another reviewer may also come along with totally different opinions on some points too. + +It is convention to mark review comments that are not critical to the PR as nitpicks but this is not always followed. +As the PR author, you should still take a look at these as they will often reveal best practices and unwritten rules that usually have good reasons behind them and you may want to incorporate them into your modus operandi. + +Please keep in mind that reviewers almost always mean well here. +Their intent is not to denounce your code, they simply want your code to be as good as it can be. +Through their experience, they may also take notice of a seemingly insignificant issues that have caused significant burden before. + +Sometimes however, they can also get a bit carried away and become too perfectionistic. +If you feel some of the requests are unreasonable or merely a matter of personal preference, try to nicely remind the reviewers that you may not intend this code to be 100% perfect or that you have different taste in some regards and press them on whether they think that these requests are *critical* to the PR's success. + +While we do have a set of [official standards for the Nix community](https://github.com/NixOS/rfcs/), we don't have standards for everything and there are often multiple valid ways to achieve the same goal. +Unless there are standards forbidding the patterns used in your code or there are serious technical, maintainability or readability issues with your code, you can insist to keep the code the way you made it and disregard the requests. +Please communicate this clearly though; a simple "I prefer it this way and see no major issue with it" can save you a lot of arguing. + +If you are unsure about some change requests, please ask reviewers *why* they requested them. +This will usually reveal how important they deem it to be and will help educate you about standards, best practices, unwritten rules aswell as preferences people have and why. + +Some committers may have stronger opinions on some things and therefore (understandably) may not want to merge your PR if you don't follow their requests. +It is totally fine to get yourself a second or third opinion in such a case. + +### Committers work on a push-basis + +It's possible for you to get a review but nothing happens afterwards, even if you reply to review comments. +A committer not following up on your PR does not necessarily mean they're disinterested or unresponsive, they may have simply forgotten to follow up on it or had some other circumstances preventing them from doing so. + +Committers typically handle many other PRs besides yours and it is not realistic for them to keep up with all of them to a degree where they could reasonably remember to follow up on all PRs that they had intended following up upon. +If someone left an approving review on your PR and didn't merge a few days later, the most likely case is that they simply forgot. + +Please see it as your responsibility to actively remind reviewers of your open PRs. + +The easiest way to do so is to simply cause them a Github notification. +Github notifies people involved in the PR when you add a comment to your PR, push your PR or re-request their review. +Doing any of that will get you people's attention again. + +It may very well be the case that you have to do this every time you need the committer to follow up upon your PR. +Again, this is a community project so please be mindful of people's circumstances here; be nice when requesting reviews again. + +It may also be the case that the committer has lost interest or isn't familiar enough with the component you're touching to be comfortable merging your PR. +They will likely not immediately state that fact however, so please ask for clarification and don't hesitate to find yourself another committer to take a look at your PR. + +### Nothing helped + +If you followed these guidelines but still got no results or if you feel that you have been wronged in some way, please explicitly reach out to the greater community via its communication channels. + +The [NixOS Discourse](https://discourse.nixos.org/) is a great place to do this as it has historically been the asynchronous medium with the greatest concentration of committers and other people who are significantly involved in Nixpkgs. +There is a dedicated discourse thread [PRs in distress](https://discourse.nixos.org/t/prs-in-distress/3604) where you can link your PR if everything else fails. +The [Nixpkgs / NixOS contributions Matrix channel](https://matrix.to/#/#dev:nixos.org) is the best synchronous channel with the same qualities. + +Please reserve these for cases where you've made a serious effort in trying to get the attention of multiple active committers and provided realistic means for them to assess your PR's quality though. +As mentioned previously, it is unfortunately perfectly normal for a PR to sit around for weeks on end due to the realities of this being a community project. +Please don't blow up situations where progress is happening but is merely not going fast enough for your tastes. +Honking in a traffic jam will not make you go any faster. diff --git a/ci/OWNERS b/ci/OWNERS new file mode 100644 index 000000000000..8decab10834d --- /dev/null +++ b/ci/OWNERS @@ -0,0 +1,407 @@ +# This file is used to describe who owns what in this repository. +# Users/teams will get review requests for PRs that change their files. +# +# This file does not replace `meta.maintainers` +# but is instead used for other things than derivations and modules, +# like documentation, package sets, and other assets. +# +# This file uses the same syntax as the natively supported CODEOWNERS file, +# see https://help.github.com/articles/about-codeowners/ for documentation. +# However it comes with some notable differences: +# - There is no need for user/team listed here to have write access. +# - No reviews will be requested for PRs that target the wrong base branch. +# +# Processing of this file is implemented in workflows/codeowners.yml + +# CI +/.github/workflows @NixOS/Security @Mic92 @zowoq +/.github/workflows/check-nix-format.yml @infinisil +/.github/workflows/nixpkgs-vet.yml @infinisil @philiptaron +/.github/workflows/codeowners.yml @infinisil +/ci/OWNERS @infinisil +/ci @infinisil @philiptaron @NixOS/Security + +# Development support +/.editorconfig @Mic92 @zowoq +/shell.nix @infinisil @NixOS/Security + +# Libraries +/lib @infinisil +/lib/systems @alyssais @ericson2314 +/lib/generators.nix @infinisil @Profpatsch +/lib/cli.nix @infinisil @Profpatsch +/lib/debug.nix @infinisil @Profpatsch +/lib/asserts.nix @infinisil @Profpatsch +/lib/path/* @infinisil +/lib/fileset @infinisil +## Libraries / Module system +/lib/modules.nix @infinisil @roberth +/lib/types.nix @infinisil @roberth +/lib/options.nix @infinisil @roberth +/lib/tests/modules.sh @infinisil @roberth +/lib/tests/modules @infinisil @roberth + +# Nixpkgs Internals +/default.nix @Ericson2314 +/pkgs/top-level/default.nix @Ericson2314 +/pkgs/top-level/impure.nix @Ericson2314 +/pkgs/top-level/stage.nix @Ericson2314 +/pkgs/top-level/splice.nix @Ericson2314 +/pkgs/top-level/release-cross.nix @Ericson2314 +/pkgs/top-level/by-name-overlay.nix @infinisil @philiptaron +/pkgs/stdenv @philiptaron +/pkgs/stdenv/generic @Ericson2314 +/pkgs/stdenv/generic/check-meta.nix @Ericson2314 +/pkgs/stdenv/cross @Ericson2314 +/pkgs/build-support @philiptaron +/pkgs/build-support/cc-wrapper @Ericson2314 +/pkgs/build-support/bintools-wrapper @Ericson2314 +/pkgs/build-support/setup-hooks @Ericson2314 +/pkgs/build-support/setup-hooks/auto-patchelf.sh @layus +/pkgs/build-support/setup-hooks/auto-patchelf.py @layus +/pkgs/pkgs-lib @infinisil +## Format generators/serializers +/pkgs/pkgs-lib/formats/libconfig @h7x4 +/pkgs/pkgs-lib/formats/hocon @h7x4 + +# Nixpkgs build-support +/pkgs/build-support/writers @lassulus @Profpatsch + +# Nixpkgs make-disk-image +/doc/build-helpers/images/makediskimage.section.md @raitobezarius +/nixos/lib/make-disk-image.nix @raitobezarius + +# Nix, the package manager +# @raitobezarius is not "code owner", but is listed here to be notified of changes +# pertaining to the Nix package manager. +# i.e. no authority over those files. +pkgs/tools/package-management/nix/ @NixOS/nix-team @raitobezarius +nixos/modules/installer/tools/nix-fallback-paths.nix @NixOS/nix-team @raitobezarius + +# Nixpkgs documentation +/maintainers/scripts/db-to-md.sh @jtojnar @ryantm +/maintainers/scripts/doc @jtojnar @ryantm + +# Contributor documentation +/CONTRIBUTING.md @infinisil +/.github/PULL_REQUEST_TEMPLATE.md @infinisil +/doc/contributing/ @infinisil +/doc/contributing/contributing-to-documentation.chapter.md @jtojnar @infinisil +/lib/README.md @infinisil +/doc/README.md @infinisil +/nixos/README.md @infinisil +/pkgs/README.md @infinisil +/pkgs/by-name/README.md @infinisil +/maintainers/README.md @infinisil + +# User-facing development documentation +/doc/development.md @infinisil +/doc/development @infinisil + +# NixOS Internals +/nixos/default.nix @infinisil +/nixos/lib/from-env.nix @infinisil +/nixos/lib/eval-config.nix @infinisil +/nixos/modules/system/activation/bootspec.nix @grahamc @cole-h @raitobezarius +/nixos/modules/system/activation/bootspec.cue @grahamc @cole-h @raitobezarius + +# NixOS integration test driver +/nixos/lib/test-driver @tfc + +# NixOS QEMU virtualisation +/nixos/modules/virtualisation/qemu-vm.nix @raitobezarius + +# ACME +/nixos/modules/security/acme @NixOS/acme + +# Systemd +/nixos/modules/system/boot/systemd.nix @NixOS/systemd +/nixos/modules/system/boot/systemd @NixOS/systemd +/nixos/lib/systemd-*.nix @NixOS/systemd +/pkgs/os-specific/linux/systemd @NixOS/systemd + +# Systemd-boot +/nixos/modules/system/boot/loader/systemd-boot @JulienMalka + +# Images and installer media +/nixos/modules/profiles/installation-device.nix @ElvishJerricco +/nixos/modules/installer/cd-dvd/ @ElvishJerricco +/nixos/modules/installer/sd-card/ + +# Amazon +/nixos/modules/virtualisation/amazon-init.nix @arianvp +/nixos/modules/virtualisation/ec2-data.nix @arianvp +/nixos/modules/virtualisation/amazon-options.nix @arianvp +/nixos/modules/virtualisation/amazon-image.nix @arianvp +/nixos/maintainers/scripts/ec2/ @arianvp +/nixos/modules/services/misc/amazon-ssm-agent.nix @arianvp +/nixos/tests/amazon-ssm-agent.nix @arianvp +/nixos/modules/system/boot/grow-partition.nix @arianvp + + + +# Updaters +## update.nix +/maintainers/scripts/update.nix @jtojnar +/maintainers/scripts/update.py @jtojnar +## common-updater-scripts +/pkgs/common-updater/scripts/update-source-version @jtojnar + +# Python-related code and docs +/doc/languages-frameworks/python.section.md @mweinelt @natsukium +/maintainers/scripts/update-python-libraries @natsukium +/pkgs/development/interpreters/python @natsukium +/pkgs/top-level/python-packages.nix @natsukium +/pkgs/top-level/release-python.nix @natsukium + +# Haskell +/doc/languages-frameworks/haskell.section.md @sternenseemann @maralorn +/maintainers/scripts/haskell @sternenseemann @maralorn +/pkgs/development/compilers/ghc @sternenseemann @maralorn +/pkgs/development/haskell-modules @sternenseemann @maralorn +/pkgs/test/haskell @sternenseemann @maralorn +/pkgs/top-level/release-haskell.nix @sternenseemann @maralorn +/pkgs/top-level/haskell-packages.nix @sternenseemann @maralorn + +# Perl +/pkgs/development/interpreters/perl @stigtsp @zakame @marcusramberg +/pkgs/top-level/perl-packages.nix @stigtsp @zakame @marcusramberg +/pkgs/development/perl-modules @stigtsp @zakame @marcusramberg + +# R +/pkgs/applications/science/math/R @jbedo +/pkgs/development/r-modules @jbedo + +# Rust +/pkgs/development/compilers/rust @Mic92 @zowoq @winterqt @figsoda +/pkgs/build-support/rust @zowoq @winterqt @figsoda +/doc/languages-frameworks/rust.section.md @zowoq @winterqt @figsoda + +# C compilers +/pkgs/development/compilers/gcc +/pkgs/development/compilers/llvm @alyssais @RossComputerGuy +/pkgs/development/compilers/emscripten @raitobezarius +/doc/languages-frameworks/emscripten.section.md @raitobezarius + +# Audio +/nixos/modules/services/audio/botamusique.nix @mweinelt +/nixos/modules/services/audio/snapserver.nix @mweinelt +/nixos/tests/botamusique.nix @mweinelt +/nixos/tests/snapcast.nix @mweinelt + +# Browsers +/pkgs/applications/networking/browsers/firefox @mweinelt +/pkgs/applications/networking/browsers/chromium @emilylange +/nixos/tests/chromium.nix @emilylange + +# Certificate Authorities +pkgs/data/misc/cacert/ @ajs124 @lukegb @mweinelt +pkgs/development/libraries/nss/ @ajs124 @lukegb @mweinelt +pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt + +# Jetbrains +/pkgs/applications/editors/jetbrains @edwtjo + +# Licenses +/lib/licenses.nix @alyssais + +# Qt +/pkgs/development/libraries/qt-5 @K900 @NickCao @SuperSandro2000 @ttuegel +/pkgs/development/libraries/qt-6 @K900 @NickCao @SuperSandro2000 @ttuegel + +# KDE / Plasma 5 +/pkgs/applications/kde @K900 @NickCao @SuperSandro2000 @ttuegel +/pkgs/desktops/plasma-5 @K900 @NickCao @SuperSandro2000 @ttuegel +/pkgs/development/libraries/kde-frameworks @K900 @NickCao @SuperSandro2000 @ttuegel + +# KDE / Plasma 6 +/pkgs/kde @K900 @NickCao @SuperSandro2000 @ttuegel +/maintainers/scripts/kde @K900 @NickCao @SuperSandro2000 @ttuegel + +# PostgreSQL and related stuff +/pkgs/servers/sql/postgresql @thoughtpolice +/nixos/modules/services/databases/postgresql.md @thoughtpolice +/nixos/modules/services/databases/postgresql.nix @thoughtpolice +/nixos/tests/postgresql.nix @thoughtpolice + +# Hardened profile & related modules +/nixos/modules/profiles/hardened.nix @joachifm +/nixos/modules/security/lock-kernel-modules.nix @joachifm +/nixos/modules/security/misc.nix @joachifm +/nixos/tests/hardened.nix @joachifm +/pkgs/os-specific/linux/kernel/hardened/config.nix @joachifm + +# Home Automation +/nixos/modules/services/home-automation/home-assistant.nix @mweinelt +/nixos/modules/services/home-automation/zigbee2mqtt.nix @mweinelt +/nixos/tests/home-assistant.nix @mweinelt +/nixos/tests/zigbee2mqtt.nix @mweinelt +/pkgs/servers/home-assistant @mweinelt +/pkgs/tools/misc/esphome @mweinelt + +# Network Time Daemons +/pkgs/by-name/ch/chrony @thoughtpolice +/pkgs/tools/networking/ntp @thoughtpolice +/pkgs/tools/networking/openntpd @thoughtpolice +/nixos/modules/services/networking/ntp @thoughtpolice + +# Network +/pkgs/tools/networking/kea/default.nix @mweinelt +/pkgs/tools/networking/babeld/default.nix @mweinelt +/nixos/modules/services/networking/babeld.nix @mweinelt +/nixos/modules/services/networking/kea.nix @mweinelt +/nixos/modules/services/networking/knot.nix @mweinelt +/nixos/modules/services/monitoring/prometheus/exporters/kea.nix @mweinelt +/nixos/tests/babeld.nix @mweinelt +/nixos/tests/kea.nix @mweinelt +/nixos/tests/knot.nix @mweinelt + +# Web servers +/doc/packages/nginx.section.md @raitobezarius +/pkgs/servers/http/nginx/ @raitobezarius +/nixos/modules/services/web-servers/nginx/ @raitobezarius + +# Dhall +/pkgs/development/dhall-modules @Gabriella439 @Profpatsch @ehmry +/pkgs/development/interpreters/dhall @Gabriella439 @Profpatsch @ehmry + +# Idris +/pkgs/development/idris-modules @Infinisil +/pkgs/development/compilers/idris2 @mattpolzin + +# Bazel +/pkgs/development/tools/build-managers/bazel @Profpatsch + +# NixOS modules for e-mail and dns services +/nixos/modules/services/mail/mailman.nix @peti +/nixos/modules/services/mail/postfix.nix @peti +/nixos/modules/services/networking/bind.nix @peti +/nixos/modules/services/mail/rspamd.nix @peti + +# Emacs +/pkgs/applications/editors/emacs/elisp-packages @NixOS/emacs +/pkgs/applications/editors/emacs @NixOS/emacs +/pkgs/top-level/emacs-packages.nix @NixOS/emacs +/doc/packages/emacs.section.md @NixOS/emacs +/nixos/modules/services/editors/emacs.md @NixOS/emacs + +# Kakoune +/pkgs/applications/editors/kakoune @philiptaron + +# Neovim +/pkgs/applications/editors/neovim @figsoda @teto + +# VimPlugins +/pkgs/applications/editors/vim/plugins @figsoda + +# VsCode Extensions +/pkgs/applications/editors/vscode/extensions + +# PHP interpreter, packages, extensions, tests and documentation +/doc/languages-frameworks/php.section.md @aanderse @drupol @globin @ma27 @talyz +/nixos/tests/php @aanderse @drupol @globin @ma27 @talyz +/pkgs/build-support/php/build-pecl.nix @aanderse @drupol @globin @ma27 @talyz +/pkgs/build-support/php @drupol +/pkgs/development/interpreters/php @jtojnar @aanderse @drupol @globin @ma27 @talyz +/pkgs/development/php-packages @aanderse @drupol @globin @ma27 @talyz +/pkgs/top-level/php-packages.nix @jtojnar @aanderse @drupol @globin @ma27 @talyz + +# Docker tools +/pkgs/build-support/docker @roberth +/nixos/tests/docker-tools* @roberth +/doc/build-helpers/images/dockertools.section.md @roberth + +# Blockchains +/pkgs/applications/blockchains @mmahut @RaghavSood + +# Go +/doc/languages-frameworks/go.section.md @kalbasit @katexochen @Mic92 @zowoq +/pkgs/build-support/go @kalbasit @katexochen @Mic92 @zowoq +/pkgs/development/compilers/go @kalbasit @katexochen @Mic92 @zowoq + +# GNOME +/pkgs/desktops/gnome @jtojnar +/pkgs/desktops/gnome/extensions @jtojnar +/pkgs/build-support/make-hardcode-gsettings-patch @jtojnar + +# Cinnamon +/pkgs/by-name/ci/cinnamon-* @mkg20001 +/pkgs/by-name/cj/cjs @mkg20001 +/pkgs/by-name/mu/muffin @mkg20001 +/pkgs/by-name/ne/nemo @mkg20001 +/pkgs/by-name/ne/nemo-* @mkg20001 + +# nim +/pkgs/development/compilers/nim @ehmry + +# terraform providers +/pkgs/applications/networking/cluster/terraform-providers @zowoq + +# Forgejo +nixos/modules/services/misc/forgejo.nix @adamcstephens @bendlas @emilylange +pkgs/by-name/fo/forgejo/ @adamcstephens @bendlas @emilylange + +# Dotnet +/pkgs/build-support/dotnet @corngood +/pkgs/development/compilers/dotnet @corngood +/pkgs/test/dotnet @corngood +/doc/languages-frameworks/dotnet.section.md @corngood + +# Node.js +/pkgs/build-support/node/build-npm-package @winterqt +/pkgs/build-support/node/fetch-npm-deps @winterqt +/doc/languages-frameworks/javascript.section.md @winterqt + +# OCaml +/pkgs/build-support/ocaml @ulrikstrid +/pkgs/development/compilers/ocaml @ulrikstrid +/pkgs/development/ocaml-modules @ulrikstrid + +# ZFS +pkgs/os-specific/linux/zfs/2_1.nix @raitobezarius +pkgs/os-specific/linux/zfs/generic.nix @raitobezarius +nixos/modules/tasks/filesystems/zfs.nix @raitobezarius +nixos/tests/zfs.nix @raitobezarius + +# Zig +/pkgs/development/compilers/zig @figsoda +/doc/hooks/zig.section.md @figsoda + +# Buildbot +nixos/modules/services/continuous-integration/buildbot @Mic92 @zowoq +nixos/tests/buildbot.nix @Mic92 @zowoq +pkgs/development/tools/continuous-integration/buildbot @Mic92 @zowoq + +# Pretix +pkgs/by-name/pr/pretix/ @mweinelt +pkgs/by-name/pr/pretalx/ @mweinelt +nixos/modules/services/web-apps/pretix.nix @mweinelt +nixos/modules/services/web-apps/pretalx.nix @mweinelt +nixos/tests/web-apps/pretix.nix @mweinelt +nixos/tests/web-apps/pretalx.nix @mweinelt + +# incus/lxc +nixos/maintainers/scripts/incus/ @adamcstephens +nixos/modules/virtualisation/incus.nix @adamcstephens +nixos/modules/virtualisation/lxc* @adamcstephens +nixos/tests/incus/ @adamcstephens +pkgs/by-name/in/incus/ @adamcstephens +pkgs/by-name/lx/lxc* @adamcstephens + +# ExpidusOS, Flutter +/pkgs/development/compilers/flutter @RossComputerGuy +/pkgs/desktops/expidus @RossComputerGuy + +# GNU Tar & Zip +/pkgs/tools/archivers/gnutar @RossComputerGuy +/pkgs/tools/archivers/zip @RossComputerGuy + +# SELinux +/pkgs/os-specific/linux/checkpolicy @RossComputerGuy +/pkgs/os-specific/linux/libselinux @RossComputerGuy +/pkgs/os-specific/linux/libsepol @RossComputerGuy + +# installShellFiles +/pkgs/by-name/in/installShellFiles/* @Ericson2314 +/pkgs/test/install-shell-files/* @Ericson2314 +/doc/hooks/installShellFiles.section.md @Ericson2314 diff --git a/ci/README.md b/ci/README.md index 64cd8e5bcea9..11b53c6095e6 100644 --- a/ci/README.md +++ b/ci/README.md @@ -1,7 +1,7 @@ # CI support files This directory contains files to support CI, such as [GitHub Actions](https://github.com/NixOS/nixpkgs/tree/master/.github/workflows) and [Ofborg](https://github.com/nixos/ofborg). -This is in contrast with [`maintainers/scripts`](`../maintainers/scripts`) which is for human use instead. +This is in contrast with [`maintainers/scripts`](../maintainers/scripts) which is for human use instead. ## Pinned Nixpkgs @@ -10,3 +10,89 @@ In order to ensure that the needed packages are generally available without buil [`pinned-nixpkgs.json`](./pinned-nixpkgs.json) contains a pinned Nixpkgs version tested by Hydra. Run [`update-pinned-nixpkgs.sh`](./update-pinned-nixpkgs.sh) to update it. + +## `ci/nixpkgs-vet.sh BASE_BRANCH [REPOSITORY]` + +Runs the [`nixpkgs-vet` tool](https://github.com/NixOS/nixpkgs-vet) on the HEAD commit, closely matching what CI does. This can't do exactly the same as CI, because CI needs to rely on GitHub's server-side Git history to compute the mergeability of PRs before the check can be started. +In turn, when contributors are running this tool locally, we don't want to have to push commits to test them, and we can also rely on the local Git history to do the mergeability check. + +Arguments: + +- `BASE_BRANCH`: The base branch to use, e.g. master or release-24.05 +- `REPOSITORY`: The repository from which to fetch the base branch. Defaults to . + +## `ci/nixpkgs-vet` + +This directory contains scripts and files used and related to [`nixpkgs-vet`](https://github.com/NixOS/nixpkgs-vet/), which the CI uses to implement `pkgs/by-name` checks, along with many other Nixpkgs architecture rules. +See also the [CI GitHub Action](../.github/workflows/nixpkgs-vet.yml). + +## `ci/nixpkgs-vet/update-pinned-tool.sh` + +Updates the pinned [`nixpkgs-vet` tool](https://github.com/NixOS/nixpkgs-vet) in [`ci/nixpkgs-vet/pinned-version.txt`](./nixpkgs-vet/pinned-version.txt) to the latest [release](https://github.com/NixOS/nixpkgs-vet/releases). + +Each release contains a pre-built `x86_64-linux` version of the tool which is used by CI. + +This script currently needs to be called manually when the CI tooling needs to be updated. + +Why not just build the tooling right from the PRs Nixpkgs version? + +- Because it allows CI to check all PRs, even if they would break the CI tooling. +- Because it makes the CI check very fast, since no Nix builds need to be done, even for mass rebuilds. +- Because it improves security, since we don't have to build potentially untrusted code from PRs. + The tool only needs a very minimal Nix evaluation at runtime, which can work with [readonly-mode](https://nixos.org/manual/nix/stable/command-ref/opt-common.html#opt-readonly-mode) and [restrict-eval](https://nixos.org/manual/nix/stable/command-ref/conf-file.html#conf-restrict-eval). + +## `get-merge-commit.sh GITHUB_REPO PR_NUMBER` + +Check whether a PR is mergeable and return the test merge commit as +[computed by GitHub](https://docs.github.com/en/rest/guides/using-the-rest-api-to-interact-with-your-git-database?apiVersion=2022-11-28#checking-mergeability-of-pull-requests). + +Arguments: +- `GITHUB_REPO`: The repository of the PR, e.g. `NixOS/nixpkgs` +- `PR_NUMBER`: The PR number, e.g. `1234` + +Exit codes: +- 0: The PR can be merged, the test merge commit hash is returned on stdout +- 1: The PR cannot be merged because it's not open anymore +- 2: The PR cannot be merged because it has a merge conflict +- 3: The merge commit isn't being computed, GitHub is likely having internal issues, unknown if the PR is mergeable + +### Usage + +This script can be used in GitHub Actions workflows as follows: + +```yaml +on: pull_request_target + +# We need a token to query the API, but it doesn't need any special permissions +permissions: {} + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + # Important: Because of `pull_request_target`, this doesn't check out the PR, + # but rather the base branch of the PR, which is needed so we don't run untrusted code + - uses: actions/checkout@ + with: + path: base + sparse-checkout: ci + - name: Resolving the merge commit + env: + GH_TOKEN: ${{ github.token }} + run: | + if mergedSha=$(base/ci/get-merge-commit.sh ${{ github.repository }} ${{ github.event.number }}); then + echo "Checking the merge commit $mergedSha" + echo "mergedSha=$mergedSha" >> "$GITHUB_ENV" + else + # Skipping so that no notifications are sent + echo "Skipping the rest..." + fi + rm -rf base + - uses: actions/checkout@ + # Add this to _all_ subsequent steps to skip them + if: env.mergedSha + with: + ref: ${{ env.mergedSha }} + - ... +``` diff --git a/ci/codeowners-validator/default.nix b/ci/codeowners-validator/default.nix new file mode 100644 index 000000000000..5c2d5335c35e --- /dev/null +++ b/ci/codeowners-validator/default.nix @@ -0,0 +1,31 @@ +{ + buildGoModule, + fetchFromGitHub, + fetchpatch, +}: +buildGoModule { + name = "codeowners-validator"; + src = fetchFromGitHub { + owner = "mszostok"; + repo = "codeowners-validator"; + rev = "f3651e3810802a37bd965e6a9a7210728179d076"; + hash = "sha256-5aSmmRTsOuPcVLWfDF6EBz+6+/Qpbj66udAmi1CLmWQ="; + }; + patches = [ + # https://github.com/mszostok/codeowners-validator/pull/222 + (fetchpatch { + name = "user-write-access-check"; + url = "https://github.com/mszostok/codeowners-validator/compare/f3651e3810802a37bd965e6a9a7210728179d076...840eeb88b4da92bda3e13c838f67f6540b9e8529.patch"; + hash = "sha256-t3Dtt8SP9nbO3gBrM0nRE7+G6N/ZIaczDyVHYAG/6mU="; + }) + # Undoes part of the above PR: We don't want to require write access + # to the repository, that's only needed for GitHub's native CODEOWNERS. + # Furthermore, it removes an unneccessary check from the code + # that breaks tokens generated for GitHub Apps. + ./permissions.patch + # Allows setting a custom CODEOWNERS path using the OWNERS_FILE env var + ./owners-file-name.patch + ]; + postPatch = "rm -r docs/investigation"; + vendorHash = "sha256-R+pW3xcfpkTRqfS2ETVOwG8PZr0iH5ewroiF7u8hcYI="; +} diff --git a/ci/codeowners-validator/owners-file-name.patch b/ci/codeowners-validator/owners-file-name.patch new file mode 100644 index 000000000000..d8b87ba2f84a --- /dev/null +++ b/ci/codeowners-validator/owners-file-name.patch @@ -0,0 +1,15 @@ +diff --git a/pkg/codeowners/owners.go b/pkg/codeowners/owners.go +index 6910bd2..e0c95e9 100644 +--- a/pkg/codeowners/owners.go ++++ b/pkg/codeowners/owners.go +@@ -39,6 +39,10 @@ func NewFromPath(repoPath string) ([]Entry, error) { + // openCodeownersFile finds a CODEOWNERS file and returns content. + // see: https://help.github.com/articles/about-code-owners/#codeowners-file-location + func openCodeownersFile(dir string) (io.Reader, error) { ++ if file, ok := os.LookupEnv("OWNERS_FILE"); ok { ++ return fs.Open(file) ++ } ++ + var detectedFiles []string + for _, p := range []string{".", "docs", ".github"} { + pth := path.Join(dir, p) diff --git a/ci/codeowners-validator/permissions.patch b/ci/codeowners-validator/permissions.patch new file mode 100644 index 000000000000..38f42f483995 --- /dev/null +++ b/ci/codeowners-validator/permissions.patch @@ -0,0 +1,36 @@ +diff --git a/internal/check/valid_owner.go b/internal/check/valid_owner.go +index a264bcc..610eda8 100644 +--- a/internal/check/valid_owner.go ++++ b/internal/check/valid_owner.go +@@ -16,7 +16,6 @@ import ( + const scopeHeader = "X-OAuth-Scopes" + + var reqScopes = map[github.Scope]struct{}{ +- github.ScopeReadOrg: {}, + } + + type ValidOwnerConfig struct { +@@ -223,10 +222,7 @@ func (v *ValidOwner) validateTeam(ctx context.Context, name string) *validateErr + for _, t := range v.repoTeams { + // GitHub normalizes name before comparison + if strings.EqualFold(t.GetSlug(), team) { +- if t.Permissions["push"] { +- return nil +- } +- return newValidateError("Team %q cannot review PRs on %q as neither it nor any parent team has write permissions.", team, v.orgRepoName) ++ return nil + } + } + +@@ -245,10 +241,7 @@ func (v *ValidOwner) validateGitHubUser(ctx context.Context, name string) *valid + for _, u := range v.repoUsers { + // GitHub normalizes name before comparison + if strings.EqualFold(u.GetLogin(), userName) { +- if u.Permissions["push"] { +- return nil +- } +- return newValidateError("User %q cannot review PRs on %q as they don't have write permissions.", userName, v.orgRepoName) ++ return nil + } + } + diff --git a/ci/default.nix b/ci/default.nix new file mode 100644 index 000000000000..02b2e948d17b --- /dev/null +++ b/ci/default.nix @@ -0,0 +1,29 @@ +let + pinnedNixpkgs = builtins.fromJSON (builtins.readFile ./pinned-nixpkgs.json); +in +{ + system ? builtins.currentSystem, + + nixpkgs ? null, +}: +let + nixpkgs' = + if nixpkgs == null then + fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/${pinnedNixpkgs.rev}.tar.gz"; + sha256 = pinnedNixpkgs.sha256; + } + else + nixpkgs; + + pkgs = import nixpkgs' { + inherit system; + config = { }; + overlays = [ ]; + }; +in +{ + inherit pkgs; + requestReviews = pkgs.callPackage ./request-reviews { }; + codeownersValidator = pkgs.callPackage ./codeowners-validator { }; +} diff --git a/ci/get-merge-commit.sh b/ci/get-merge-commit.sh new file mode 100755 index 000000000000..c62bb56dd993 --- /dev/null +++ b/ci/get-merge-commit.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# See ./README.md for docs + +set -euo pipefail + +log() { + echo "$@" >&2 +} + +if (( $# < 2 )); then + log "Usage: $0 GITHUB_REPO PR_NUMBER" + exit 99 +fi +repo=$1 +prNumber=$2 + +# Retry the API query this many times +retryCount=5 +# Start with 5 seconds, but double every retry +retryInterval=5 + +while true; do + log "Checking whether the pull request can be merged" + prInfo=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$repo/pulls/$prNumber") + + # Non-open PRs won't have their mergeability computed no matter what + state=$(jq -r .state <<< "$prInfo") + if [[ "$state" != open ]]; then + log "PR is not open anymore" + exit 1 + fi + + mergeable=$(jq -r .mergeable <<< "$prInfo") + if [[ "$mergeable" == "null" ]]; then + if (( retryCount == 0 )); then + log "Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com/" + exit 3 + else + (( retryCount -= 1 )) || true + + # null indicates that GitHub is still computing whether it's mergeable + # Wait a couple seconds before trying again + log "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)" + sleep "$retryInterval" + + (( retryInterval *= 2 )) || true + fi + else + break + fi +done + +if [[ "$mergeable" == "true" ]]; then + log "The PR can be merged" + jq -r .merge_commit_sha <<< "$prInfo" +else + log "The PR has a merge conflict" + exit 2 +fi diff --git a/ci/nixpkgs-vet.sh b/ci/nixpkgs-vet.sh new file mode 100755 index 000000000000..7aabdfb6b8c5 --- /dev/null +++ b/ci/nixpkgs-vet.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p jq + +set -o pipefail -o errexit -o nounset + +trace() { echo >&2 "$@"; } + +tmp=$(mktemp -d) +cleanup() { + # Don't exit early if anything fails to cleanup + set +o errexit + + trace -n "Cleaning up.. " + + [[ -e "$tmp/base" ]] && git worktree remove --force "$tmp/base" + [[ -e "$tmp/merged" ]] && git worktree remove --force "$tmp/merged" + + rm -rf "$tmp" + + trace "Done" +} +trap cleanup exit + + +repo=https://github.com/NixOS/nixpkgs.git + +if (( $# != 0 )); then + baseBranch=$1 + shift +else + trace "Usage: $0 BASE_BRANCH [REPOSITORY]" + trace "BASE_BRANCH: The base branch to use, e.g. master or release-23.11" + trace "REPOSITORY: The repository to fetch the base branch from, defaults to $repo" + exit 1 +fi + +if (( $# != 0 )); then + repo=$1 + shift +fi + +if [[ -n "$(git status --porcelain)" ]]; then + trace -e "\e[33mWarning: Dirty tree, uncommitted changes won't be taken into account\e[0m" +fi +headSha=$(git rev-parse HEAD) +trace -e "Using HEAD commit \e[34m$headSha\e[0m" + +trace -n "Creating Git worktree for the HEAD commit in $tmp/merged.. " +git worktree add --detach -q "$tmp/merged" HEAD +trace "Done" + +trace -n "Fetching base branch $baseBranch to compare against.. " +git fetch -q "$repo" refs/heads/"$baseBranch" +baseSha=$(git rev-parse FETCH_HEAD) +trace -e "\e[34m$baseSha\e[0m" + +trace -n "Creating Git worktree for the base branch in $tmp/base.. " +git worktree add -q "$tmp/base" "$baseSha" +trace "Done" + +trace -n "Merging base branch into the HEAD commit in $tmp/merged.. " +git -C "$tmp/merged" merge -q --no-edit "$baseSha" +trace -e "\e[34m$(git -C "$tmp/merged" rev-parse HEAD)\e[0m" +trace -n "Reading pinned nixpkgs-vet version from pinned-version.txt.. " +toolVersion=$(<"$tmp/merged/ci/nixpkgs-vet/pinned-version.txt") +trace -e "\e[34m$toolVersion\e[0m" + +trace -n "Building tool.. " +nix-build https://github.com/NixOS/nixpkgs-vet/tarball/"$toolVersion" -o "$tmp/tool" -A build +trace "Running nixpkgs-vet.." +"$tmp/tool/bin/nixpkgs-vet" --base "$tmp/base" "$tmp/merged" diff --git a/ci/nixpkgs-vet/pinned-version.txt b/ci/nixpkgs-vet/pinned-version.txt new file mode 100644 index 000000000000..845639eef26c --- /dev/null +++ b/ci/nixpkgs-vet/pinned-version.txt @@ -0,0 +1 @@ +0.1.4 diff --git a/pkgs/test/check-by-name/update-pinned-tool.sh b/ci/nixpkgs-vet/update-pinned-tool.sh similarity index 94% rename from pkgs/test/check-by-name/update-pinned-tool.sh rename to ci/nixpkgs-vet/update-pinned-tool.sh index 7240bd597f13..78a9ae2411b8 100755 --- a/pkgs/test/check-by-name/update-pinned-tool.sh +++ b/ci/nixpkgs-vet/update-pinned-tool.sh @@ -7,7 +7,7 @@ trace() { echo >&2 "$@"; } SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -repository=NixOS/nixpkgs-check-by-name +repository=NixOS/nixpkgs-vet pin_file=$SCRIPT_DIR/pinned-version.txt trace -n "Fetching latest release of $repository.. " diff --git a/ci/request-reviews/default.nix b/ci/request-reviews/default.nix new file mode 100644 index 000000000000..b51d896539d8 --- /dev/null +++ b/ci/request-reviews/default.nix @@ -0,0 +1,43 @@ +{ + lib, + stdenvNoCC, + makeWrapper, + coreutils, + codeowners, + jq, + curl, + github-cli, + gitMinimal, +}: +stdenvNoCC.mkDerivation { + name = "request-reviews"; + src = lib.fileset.toSource { + root = ./.; + fileset = lib.fileset.unions [ + ./get-reviewers.sh + ./request-reviews.sh + ./verify-base-branch.sh + ./dev-branches.txt + ]; + }; + nativeBuildInputs = [ makeWrapper ]; + dontBuild = true; + installPhase = '' + mkdir -p $out/bin + mv dev-branches.txt $out/bin + for bin in *.sh; do + mv "$bin" "$out/bin" + wrapProgram "$out/bin/$bin" \ + --set PATH ${ + lib.makeBinPath [ + coreutils + codeowners + jq + curl + github-cli + gitMinimal + ] + } + done + ''; +} diff --git a/ci/request-reviews/dev-branches.txt b/ci/request-reviews/dev-branches.txt new file mode 100644 index 000000000000..2282529881ba --- /dev/null +++ b/ci/request-reviews/dev-branches.txt @@ -0,0 +1,7 @@ +# Trusted development branches: +# These generally require PRs to update and are built by Hydra. +master +staging +release-* +staging-* +haskell-updates diff --git a/ci/request-reviews/get-reviewers.sh b/ci/request-reviews/get-reviewers.sh new file mode 100755 index 000000000000..1107edd9e6f1 --- /dev/null +++ b/ci/request-reviews/get-reviewers.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash + +# Get the code owners of the files changed by a PR, +# suitable to be consumed by the API endpoint to request reviews: +# https://docs.github.com/en/rest/pulls/review-requests?apiVersion=2022-11-28#request-reviewers-for-a-pull-request + +set -euo pipefail + +log() { + echo "$@" >&2 +} + +if (( "$#" < 7 )); then + log "Usage: $0 GIT_REPO OWNERS_FILE BASE_REPO BASE_REF HEAD_REF PR_NUMBER PR_AUTHOR" + exit 1 +fi + +gitRepo=$1 +ownersFile=$2 +baseRepo=$3 +baseRef=$4 +headRef=$5 +prNumber=$6 +prAuthor=$7 + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' exit + +git -C "$gitRepo" diff --name-only --merge-base "$baseRef" "$headRef" > "$tmp/touched-files" +readarray -t touchedFiles < "$tmp/touched-files" +log "This PR touches ${#touchedFiles[@]} files" + +# Get the owners file from the base, because we don't want to allow PRs to +# remove code owners to avoid pinging them +git -C "$gitRepo" show "$baseRef":"$ownersFile" > "$tmp"/codeowners + +# Associative array with the user as the key for easy de-duplication +# Make sure to always lowercase keys to avoid duplicates with different casings +declare -A users=() + +for file in "${touchedFiles[@]}"; do + result=$(codeowners --file "$tmp"/codeowners "$file") + + read -r file owners <<< "$result" + if [[ "$owners" == "(unowned)" ]]; then + log "File $file is unowned" + continue + fi + log "File $file is owned by $owners" + + # Split up multiple owners, separated by arbitrary amounts of spaces + IFS=" " read -r -a entries <<< "$owners" + + for entry in "${entries[@]}"; do + # GitHub technically also supports Emails as code owners, + # but we can't easily support that, so let's not + if [[ ! "$entry" =~ @(.*) ]]; then + warn -e "\e[33mCodeowner \"$entry\" for file $file is not valid: Must start with \"@\"\e[0m" >&2 + # Don't fail, because the PR for which this script runs can't fix it, + # it has to be fixed in the base branch + continue + fi + # The first regex match is everything after the @ + entry=${BASH_REMATCH[1]} + + if [[ "$entry" =~ (.*)/(.*) ]]; then + # Teams look like $org/$team + org=${BASH_REMATCH[1]} + team=${BASH_REMATCH[2]} + + # Instead of requesting a review from the team itself, + # we request reviews from the individual users. + # This is because once somebody from a team reviewed the PR, + # the API doesn't expose that the team was already requested for a review, + # so we wouldn't be able to avoid rerequesting reviews + # without saving some some extra state somewhere + + # We could also consider implementing a more advanced heuristic + # in the future that e.g. only pings one team member, + # but escalates to somebody else if that member doesn't respond in time. + gh api \ + --cache=1h \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/orgs/$org/teams/$team/members" \ + --jq '.[].login' > "$tmp/team-members" + readarray -t members < "$tmp/team-members" + log "Team $entry has these members: ${members[*]}" + + for user in "${members[@]}"; do + users[${user,,}]= + done + else + # Everything else is a user + users[${entry,,}]= + fi + done + +done + +# Cannot request a review from the author +if [[ -v users[${prAuthor,,}] ]]; then + log "One or more files are owned by the PR author, ignoring" + unset 'users[${prAuthor,,}]' +fi + +gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$baseRepo/pulls/$prNumber/reviews" \ + --jq '.[].user.login' > "$tmp/already-reviewed-by" + +# And we don't want to rerequest reviews from people who already reviewed +while read -r user; do + if [[ -v users[${user,,}] ]]; then + log "User $user is a code owner but has already left a review, ignoring" + unset 'users[${user,,}]' + fi +done < "$tmp/already-reviewed-by" + +# Turn it into a JSON for the GitHub API call to request PR reviewers +jq -n \ + --arg users "${!users[*]}" \ + '{ + reviewers: $users | split(" "), + }' diff --git a/ci/request-reviews/request-reviews.sh b/ci/request-reviews/request-reviews.sh new file mode 100755 index 000000000000..b21354560242 --- /dev/null +++ b/ci/request-reviews/request-reviews.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# Requests reviews for a PR after verifying that the base branch is correct + +set -euo pipefail +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' exit +SCRIPT_DIR=$(dirname "$0") + +log() { + echo "$@" >&2 +} + +effect() { + if [[ -n "${DRY_MODE:-}" ]]; then + log "Skipping in dry mode:" "${@@Q}" + else + "$@" + fi +} + +if (( $# < 3 )); then + log "Usage: $0 GITHUB_REPO PR_NUMBER OWNERS_FILE" + exit 1 +fi +baseRepo=$1 +prNumber=$2 +ownersFile=$3 + +log "Fetching PR info" +prInfo=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$baseRepo/pulls/$prNumber") + +baseBranch=$(jq -r .base.ref <<< "$prInfo") +log "Base branch: $baseBranch" +prRepo=$(jq -r .head.repo.full_name <<< "$prInfo") +log "PR repo: $prRepo" +prBranch=$(jq -r .head.ref <<< "$prInfo") +log "PR branch: $prBranch" +prAuthor=$(jq -r .user.login <<< "$prInfo") +log "PR author: $prAuthor" + +extraArgs=() +if pwdRepo=$(git rev-parse --show-toplevel 2>/dev/null); then + # Speedup for local runs + extraArgs+=(--reference-if-able "$pwdRepo") +fi + +log "Fetching Nixpkgs commit history" +# We only need the commit history, not the contents, so we can do a tree-less clone using tree:0 +# https://github.blog/open-source/git/get-up-to-speed-with-partial-clone-and-shallow-clone/#user-content-quick-summary +git clone --bare --filter=tree:0 --no-tags --origin upstream "${extraArgs[@]}" https://github.com/"$baseRepo".git "$tmp"/nixpkgs.git + +log "Fetching the PR commit history" +# Fetch the PR +git -C "$tmp/nixpkgs.git" remote add fork https://github.com/"$prRepo".git +# This remote config is the same as --filter=tree:0 when cloning +git -C "$tmp/nixpkgs.git" config remote.fork.partialclonefilter tree:0 +git -C "$tmp/nixpkgs.git" config remote.fork.promisor true + +git -C "$tmp/nixpkgs.git" fetch --no-tags fork "$prBranch" +headRef=$(git -C "$tmp/nixpkgs.git" rev-parse refs/remotes/fork/"$prBranch") + +log "Checking correctness of the base branch" +if ! "$SCRIPT_DIR"/verify-base-branch.sh "$tmp/nixpkgs.git" "$headRef" "$baseRepo" "$baseBranch" "$prRepo" "$prBranch" | tee "$tmp/invalid-base-error" >&2; then + log "Posting error as comment" + if ! response=$(effect gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$baseRepo/issues/$prNumber/comments" \ + -F "body=@$tmp/invalid-base-error"); then + log "Failed to post the comment: $response" + fi + exit 1 +fi + +log "Getting code owners to request reviews from" +"$SCRIPT_DIR"/get-reviewers.sh "$tmp/nixpkgs.git" "$ownersFile" "$baseRepo" "$baseBranch" "$headRef" "$prNumber" "$prAuthor" > "$tmp/reviewers.json" + +log "Requesting reviews from: $(<"$tmp/reviewers.json")" + +if ! response=$(effect gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$baseRepo/pulls/$prNumber/requested_reviewers" \ + --input "$tmp/reviewers.json"); then + log "Failed to request reviews: $response" + exit 1 +fi + +log "Successfully requested reviews" diff --git a/ci/request-reviews/verify-base-branch.sh b/ci/request-reviews/verify-base-branch.sh new file mode 100755 index 000000000000..7be280db8d65 --- /dev/null +++ b/ci/request-reviews/verify-base-branch.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash + +# Check that a PR doesn't include commits from other development branches. +# Fails with next steps if it does + +set -euo pipefail +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' exit +SCRIPT_DIR=$(dirname "$0") + +log() { + echo "$@" >&2 +} + +# Small helper to check whether an element is in a list +# Usage: `elementIn foo "${list[@]}"` +elementIn() { + local e match=$1 + shift + for e; do + if [[ "$e" == "$match" ]]; then + return 0 + fi + done + return 1 +} + +if (( $# < 6 )); then + log "Usage: $0 LOCAL_REPO HEAD_REF BASE_REPO BASE_BRANCH PR_REPO PR_BRANCH" + exit 1 +fi +localRepo=$1 +headRef=$2 +baseRepo=$3 +baseBranch=$4 +prRepo=$5 +prBranch=$6 + +# All development branches +devBranchPatterns=() +while read -r pattern; do + if [[ "$pattern" != '#'* ]]; then + devBranchPatterns+=("$pattern") + fi +done < "$SCRIPT_DIR/dev-branches.txt" + +git -C "$localRepo" branch --list --format "%(refname:short)" "${devBranchPatterns[@]}" > "$tmp/dev-branches" +readarray -t devBranches < "$tmp/dev-branches" + +if [[ "$baseRepo" == "$prRepo" ]] && elementIn "$prBranch" "${devBranches[@]}"; then + log "This PR merges $prBranch into $baseBranch, no commit check necessary" + exit 0 +fi + +# The current merge base of the PR +prMergeBase=$(git -C "$localRepo" merge-base "$baseBranch" "$headRef") +log "The PR's merge base with the base branch $baseBranch is $prMergeBase" + +# This is purely for debugging +git -C "$localRepo" rev-list --reverse "$baseBranch".."$headRef" > "$tmp/pr-commits" +log "The PR includes these $(wc -l < "$tmp/pr-commits") commits:" +cat <"$tmp/pr-commits" >&2 + +for testBranch in "${devBranches[@]}"; do + + if [[ -z "$(git -C "$localRepo" rev-list -1 --since="1 month ago" "$testBranch")" ]]; then + log "Not checking $testBranch, was inactive for the last month" + continue + fi + log "Checking if commits from $testBranch are included in the PR" + + # We need to check for any commits that are in the PR which are also in the test branch. + # We could check each commit from the PR individually, but that's unnecessarily slow. + # + # This does _almost_ what we want: `git rev-list --count headRef testBranch ^baseBranch`, + # except that it includes commits that are reachable from _either_ headRef or testBranch, + # instead of restricting it to ones reachable by both + + # Easily fixable though, because we can use `git merge-base testBranch headRef` + # to get the least common ancestor (aka merge base) commit reachable by both. + # If the branch being tested is indeed the right base branch, + # this is then also the commit from that branch that the PR is based on top of. + testMergeBase=$(git -C "$localRepo" merge-base "$testBranch" "$headRef") + + # And then use the `git rev-list --count`, but replacing the non-working + # `headRef testBranch` with the merge base of the two. + extraCommits=$(git -C "$localRepo" rev-list --count "$testMergeBase" ^"$baseBranch") + + if (( extraCommits != 0 )); then + log -e "\e[33m" + echo "The PR's base branch is set to $baseBranch, but $extraCommits commits from the $testBranch branch are included. Make sure you know the [right base branch for your changes](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md#branch-conventions), then:" + echo "- If the changes should go to the $testBranch branch, [change the base branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-base-branch-of-a-pull-request) to $testBranch" + echo "- If the changes should go to the $baseBranch branch, rebase your PR onto the merge base with the $baseBranch branch:" + echo " \`\`\`bash" + echo " # git rebase --onto \$(git merge-base upstream/$baseBranch HEAD) \$(git merge-base upstream/$testBranch HEAD)" + echo " git rebase --onto $prMergeBase $testMergeBase" + echo " git push --force-with-lease" + echo " \`\`\`" + log -e "\e[m" + exit 1 + fi +done + +log "Base branch is correct, no commits from development branches are included" diff --git a/doc/README.md b/doc/README.md index d7a853d0ec35..d54b312da851 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,10 +2,20 @@ This directory houses the sources files for the Nixpkgs reference manual. -Going forward, it should only contain [reference](https://nix.dev/contributing/documentation/diataxis#reference) documentation. -For tutorials, guides and explanations, contribute to instead. +> [!IMPORTANT] +> We are actively restructuring our documentation to follow the [Diátaxis framework](https://diataxis.fr/) +> +> Going forward, this directory should **only** contain [reference documentation](https://nix.dev/contributing/documentation/diataxis#reference). +> For tutorials, guides and explanations, contribute to instead. +> +> We are actively working to generate **all** reference documentation from the [doc-comments](https://github.com/NixOS/rfcs/blob/master/rfcs/0145-doc-strings.md) present in code. +> This also provides the benefit of using `:doc` in the `nix repl` to view reference documentation locally on the fly. -For documentation only relevant for contributors, use Markdown files and code comments in the source code. +For documentation only relevant for contributors, use Markdown files next to the source and regular code comments. + +> [!TIP] +> Feedback for improving support for parsing and rendering doc-comments is highly appreciated. +> [Open an issue](https://github.com/NixOS/nixpkgs/issues/new?labels=6.topic%3A+documentation&title=Doc%3A+) to request bugfixes or new features. Rendered documentation: - [Unstable (from master)](https://nixos.org/manual/nixpkgs/unstable/) @@ -166,126 +176,138 @@ When needed, each convention explain why it exists, so you can make a decision w Note that these conventions are about the **structure** of the manual (and its source files), not about the content that goes in it. You, as the writer of documentation, are still in charge of its content. -- Put each sentence in its own line. - This makes reviews and suggestions much easier, since GitHub's review system is based on lines. - It also helps identifying long sentences at a glance. +### One sentence per line -- Use the [admonition syntax](#admonitions) for callouts and examples. +Put each sentence in its own line. +This makes reviews and suggestions much easier, since GitHub's review system is based on lines. +It also helps identifying long sentences at a glance. -- Provide at least one example per function, and make examples self-contained. - This is easier to understand for beginners. - It also helps with testing that it actually works – especially once we introduce automation. +### Callouts and examples - Example code should be such that it can be passed to `pkgs.callPackage`. - Instead of something like: +Use the [admonition syntax](#admonitions) for callouts and examples. - ```nix - pkgs.dockerTools.buildLayeredImage { - name = "hello"; - contents = [ pkgs.hello ]; - } - ``` +### Provide self-contained examples - Write something like: +Provide at least one example per function, and make examples self-contained. +This is easier to understand for beginners. +It also helps with testing that it actually works – especially once we introduce automation. - ```nix - { dockerTools, hello }: - dockerTools.buildLayeredImage { - name = "hello"; - contents = [ hello ]; - } - ``` +Example code should be such that it can be passed to `pkgs.callPackage`. +Instead of something like: -- When showing inputs/outputs of any [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop), such as a shell or the Nix REPL, use a format as you'd see in the REPL, while trying to visually separate inputs from outputs. - This means that for a shell, you should use a format like the following: - ```shell - $ nix-build -A hello '' \ - --option require-sigs false \ - --option trusted-substituters file:///tmp/hello-cache \ - --option substituters file:///tmp/hello-cache - /nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1 - ``` - Note how the input is preceded by `$` on the first line and indented on subsequent lines, and how the output is provided as you'd see on the shell. +```nix +pkgs.dockerTools.buildLayeredImage { + name = "hello"; + contents = [ pkgs.hello ]; +} +``` - For the Nix REPL, you should use a format like the following: - ```shell - nix-repl> builtins.attrNames { a = 1; b = 2; } - [ "a" "b" ] - ``` - Note how the input is preceded by `nix-repl>` and the output is provided as you'd see on the Nix REPL. +Write something like: -- When documenting functions or anything that has inputs/outputs and example usage, use nested headings to clearly separate inputs, outputs, and examples. - Keep examples as the last nested heading, and link to the examples wherever applicable in the documentation. +```nix +{ dockerTools, hello }: +dockerTools.buildLayeredImage { + name = "hello"; + contents = [ hello ]; +} +``` - The purpose of this convention is to provide a familiar structure for navigating the manual, so any reader can expect to find content related to inputs in an "inputs" heading, examples in an "examples" heading, and so on. - An example: - ``` - ## buildImage +### REPLs - Some explanation about the function here. - Describe a particular scenario, and point to [](#ex-dockerTools-buildImage), which is an example demonstrating it. +When showing inputs/outputs of any [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop), such as a shell or the Nix REPL, use a format as you'd see in the REPL, while trying to visually separate inputs from outputs. +This means that for a shell, you should use a format like the following: +```shell +$ nix-build -A hello '' \ + --option require-sigs false \ + --option trusted-substituters file:///tmp/hello-cache \ + --option substituters file:///tmp/hello-cache +/nix/store/zhl06z4lrfrkw5rp0hnjjfrgsclzvxpm-hello-2.12.1 +``` +Note how the input is preceded by `$` on the first line and indented on subsequent lines, and how the output is provided as you'd see on the shell. - ### Inputs +For the Nix REPL, you should use a format like the following: +```shell +nix-repl> builtins.attrNames { a = 1; b = 2; } +[ "a" "b" ] +``` +Note how the input is preceded by `nix-repl>` and the output is provided as you'd see on the Nix REPL. - Documentation for the inputs of `buildImage`. - Perhaps even point to [](#ex-dockerTools-buildImage) again when talking about something specifically linked to it. +### Headings for inputs, outputs and examples - ### Passthru outputs +When documenting functions or anything that has inputs/outputs and example usage, use nested headings to clearly separate inputs, outputs, and examples. +Keep examples as the last nested heading, and link to the examples wherever applicable in the documentation. - Documentation for any passthru outputs of `buildImage`. +The purpose of this convention is to provide a familiar structure for navigating the manual, so any reader can expect to find content related to inputs in an "inputs" heading, examples in an "examples" heading, and so on. +An example: +``` +## buildImage - ### Examples +Some explanation about the function here. +Describe a particular scenario, and point to [](#ex-dockerTools-buildImage), which is an example demonstrating it. - Note that this is the last nested heading in the `buildImage` section. +### Inputs - :::{.example #ex-dockerTools-buildImage} +Documentation for the inputs of `buildImage`. +Perhaps even point to [](#ex-dockerTools-buildImage) again when talking about something specifically linked to it. - # Using `buildImage` +### Passthru outputs - Example of how to use `buildImage` goes here. +Documentation for any passthru outputs of `buildImage`. - ::: - ``` +### Examples -- Use [definition lists](#definition-lists) to document function arguments, and the attributes of such arguments as well as their [types](https://nixos.org/manual/nix/stable/language/values). - For example: +Note that this is the last nested heading in the `buildImage` section. - ```markdown - # pkgs.coolFunction {#pkgs.coolFunction} +:::{.example #ex-dockerTools-buildImage} - `pkgs.coolFunction` *`name`* *`config`* +# Using `buildImage` - Description of what `callPackage` does. +Example of how to use `buildImage` goes here. + +::: +``` + +### Function arguments + +Use [definition lists](#definition-lists) to document function arguments, and the attributes of such arguments as well as their [types](https://nixos.org/manual/nix/stable/language/values). +For example: + +```markdown +# pkgs.coolFunction {#pkgs.coolFunction} + +`pkgs.coolFunction` *`name`* *`config`* + +Description of what `callPackage` does. - ## Inputs {#pkgs-coolFunction-inputs} +## Inputs {#pkgs-coolFunction-inputs} - If something's special about `coolFunction`'s general argument handling, you can say so here. - Otherwise, just describe the single argument or start the arguments' definition list without introduction. +If something's special about `coolFunction`'s general argument handling, you can say so here. +Otherwise, just describe the single argument or start the arguments' definition list without introduction. - *`name`* (String) +*`name`* (String) - : The name of the resulting image. +: The name of the resulting image. - *`config`* (Attribute set) +*`config`* (Attribute set) - : Introduce the parameter. Maybe you have a test to make sure `{ }` is a sensible default; then you can say: these attributes are optional; `{ }` is a valid argument. +: Introduce the parameter. Maybe you have a test to make sure `{ }` is a sensible default; then you can say: these attributes are optional; `{ }` is a valid argument. - `outputHash` (String; _optional_) + `outputHash` (String; _optional_) - : A brief explanation including when and when not to pass this attribute. + : A brief explanation including when and when not to pass this attribute. - : _Default:_ the output path's hash. - ``` + : _Default:_ the output path's hash. +``` - Checklist: - - Start with a synopsis, to show the order of positional arguments. - - Metavariables are in emphasized code spans: ``` *`arg1`* ```. Metavariables are placeholders where users may write arbitrary expressions. This includes positional arguments. - - Attribute names are regular code spans: ``` `attr1` ```. These identifiers can _not_ be picked freely by users, so they are _not_ metavariables. - - _optional_ attributes have a _`Default:`_ if it's easily described as a value. - - _optional_ attributes have a _`Default behavior:`_ if it's not easily described using a value. - - Nix types aren't in code spans, because they are not code - - Nix types are capitalized, to distinguish them from the camelCase [Module System](#module-system) types, which _are_ code and behave like functions. +Checklist: +- Start with a synopsis, to show the order of positional arguments. +- Metavariables are in emphasized code spans: ``` *`arg1`* ```. Metavariables are placeholders where users may write arbitrary expressions. This includes positional arguments. +- Attribute names are regular code spans: ``` `attr1` ```. These identifiers can _not_ be picked freely by users, so they are _not_ metavariables. +- _optional_ attributes have a _`Default:`_ if it's easily described as a value. +- _optional_ attributes have a _`Default behavior:`_ if it's not easily described using a value. +- Nix types aren't in code spans, because they are not code +- Nix types are capitalized, to distinguish them from the camelCase Module System types, which _are_ code and behave like functions. #### Examples diff --git a/doc/build-helpers/fetchers.chapter.md b/doc/build-helpers/fetchers.chapter.md index 2167df3f1748..21cadfaa21fa 100644 --- a/doc/build-helpers/fetchers.chapter.md +++ b/doc/build-helpers/fetchers.chapter.md @@ -157,6 +157,12 @@ Here are security considerations for this scenario: In more concrete terms, if you use any other hash, the [`--insecure` flag](https://curl.se/docs/manpage.html#-k) will be passed to the underlying call to `curl` when downloading content. +## Proxy usage {#sec-pkgs-fetchers-proxy} + +Nixpkgs fetchers can make use of a http(s) proxy. Each fetcher will automatically inherit proxy-related environment variables (`http_proxy`, `https_proxy`, etc) via [impureEnvVars](https://nixos.org/manual/nix/stable/language/advanced-attributes#adv-attr-impureEnvVars). + +The environment variable `NIX_SSL_CERT_FILE` is also inherited in fetchers, and can be used to provide a custom certificate bundle to fetchers. This is usually required for a https proxy to work without certificate validation errors. + []{#fetchurl} ## `fetchurl` {#sec-pkgs-fetchers-fetchurl} diff --git a/doc/build-helpers/images/appimagetools.section.md b/doc/build-helpers/images/appimagetools.section.md index 4d00e49c397d..b1640af9dff9 100644 --- a/doc/build-helpers/images/appimagetools.section.md +++ b/doc/build-helpers/images/appimagetools.section.md @@ -64,7 +64,7 @@ let src = fetchurl { url = "https://github.com/irccloud/irccloud-desktop/releases/download/v${version}/IRCCloud-${version}-linux-x86_64.AppImage"; - sha256 = "sha256-/hMPvYdnVB1XjKgU2v47HnVvW4+uC3rhRjbucqin4iI="; + hash = "sha256-/hMPvYdnVB1XjKgU2v47HnVvW4+uC3rhRjbucqin4iI="; }; in appimageTools.wrapType2 { inherit pname version src; @@ -100,7 +100,7 @@ let src = fetchurl { url = "https://github.com/irccloud/irccloud-desktop/releases/download/v${version}/IRCCloud-${version}-linux-x86_64.AppImage"; - sha256 = "sha256-/hMPvYdnVB1XjKgU2v47HnVvW4+uC3rhRjbucqin4iI="; + hash = "sha256-/hMPvYdnVB1XjKgU2v47HnVvW4+uC3rhRjbucqin4iI="; }; appimageContents = appimageTools.extract { @@ -141,7 +141,7 @@ let src = fetchurl { url = "https://github.com/irccloud/irccloud-desktop/releases/download/v${version}/IRCCloud-${version}-linux-x86_64.AppImage"; - sha256 = "sha256-/hMPvYdnVB1XjKgU2v47HnVvW4+uC3rhRjbucqin4iI="; + hash = "sha256-/hMPvYdnVB1XjKgU2v47HnVvW4+uC3rhRjbucqin4iI="; }; appimageContents = appimageTools.extract { diff --git a/doc/build-helpers/images/dockertools.section.md b/doc/build-helpers/images/dockertools.section.md index 60342a9d0edc..26c1d9c14a26 100644 --- a/doc/build-helpers/images/dockertools.section.md +++ b/doc/build-helpers/images/dockertools.section.md @@ -50,6 +50,10 @@ Similarly, if you encounter errors similar to `Error_Protocol ("certificate has If specified, the layer created by `buildImage` will be appended to the layers defined in the base image, resulting in an image with at least two layers (one or more layers from the base image, and the layer created by `buildImage`). Otherwise, the resulting image with contain the single layer created by `buildImage`. + :::{.note} + Only **Env** configuration is inherited from the base image. + ::: + _Default value:_ `null`. `fromImageName` (String or Null; _optional_) @@ -449,7 +453,7 @@ See [](#ex-dockerTools-streamLayeredImage-exploringlayers) to understand how the `streamLayeredImage` allows scripts to be run when creating the additional layer with symlinks, allowing custom behaviour to affect the final results of the image (see the documentation of the `extraCommands` and `fakeRootCommands` attributes). The resulting repository tarball will list a single image as specified by the `name` and `tag` attributes. -By default, that image will use a static creation date (see documentation for the `created` attribute). +By default, that image will use a static creation date (see documentation for the `created` and `mtime` attributes). This allows the function to produce reproducible images. ### Inputs {#ssec-pkgs-dockerTools-streamLayeredImage-inputs} @@ -512,6 +516,7 @@ This allows the function to produce reproducible images. `created` (String; _optional_) : Specifies the time of creation of the generated image. + This date will be used for the image metadata. This should be either a date and time formatted according to [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) or `"now"`, in which case the current date will be used. :::{.caution} @@ -520,6 +525,18 @@ This allows the function to produce reproducible images. _Default value:_ `"1970-01-01T00:00:01Z"`. +`mtime` (String; _optional_) + +: Specifies the time used for the modification timestamp of files within the layers of the generated image. + This should be either a date and time formatted according to [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) or `"now"`, in which case the current date will be used. + + :::{.caution} + Using a non-constant date will cause built layers to have a different hash each time, preventing deduplication. + Using `"now"` also means that the generated image will not be reproducible anymore (because the date will always change whenever it's built). + ::: + + _Default value:_ `"1970-01-01T00:00:01Z"`. + `uid` (Number; _optional_) []{#dockerTools-buildLayeredImage-arg-uid} `gid` (Number; _optional_) []{#dockerTools-buildLayeredImage-arg-gid} `uname` (String; _optional_) []{#dockerTools-buildLayeredImage-arg-uname} diff --git a/doc/build-helpers/trivial-build-helpers.chapter.md b/doc/build-helpers/trivial-build-helpers.chapter.md index 8af68845202f..ff00548e049a 100644 --- a/doc/build-helpers/trivial-build-helpers.chapter.md +++ b/doc/build-helpers/trivial-build-helpers.chapter.md @@ -501,7 +501,7 @@ writeTextFile { text = '' Contents of File ''; - destination = "share/my-file"; + destination = "/share/my-file"; } ``` @@ -533,7 +533,6 @@ writeScript "my-file" Contents of File '' ``` -::: This is equivalent to: @@ -546,6 +545,7 @@ writeTextFile { executable = true; } ``` +::: ### `writeScriptBin` {#trivial-builder-writeScriptBin} @@ -586,7 +586,7 @@ writeTextFile { echo "hi" ''; executable = true; - destination = "bin/my-script"; + destination = "/bin/my-script"; } ``` @@ -674,7 +674,7 @@ writeTextFile { echo "hi" ''; executable = true; - destination = "bin/my-script"; + destination = "/bin/my-script"; } ``` diff --git a/doc/doc-support/lib-function-docs.nix b/doc/doc-support/lib-function-docs.nix index 8c9673d887bf..4306fa926278 100644 --- a/doc/doc-support/lib-function-docs.nix +++ b/doc/doc-support/lib-function-docs.nix @@ -106,6 +106,7 @@ stdenvNoCC.mkDerivation { --arg nixpkgsPath "./." \ --argstr revision ${nixpkgs.rev or "master"} \ --argstr libsetsJSON ${lib.escapeShellArg (builtins.toJSON libsets)} \ + --store $(mktemp -d) \ > locations.json function docgen { diff --git a/doc/hooks/cernlib.section.md b/doc/hooks/cernlib.section.md new file mode 100644 index 000000000000..e12b49e127ea --- /dev/null +++ b/doc/hooks/cernlib.section.md @@ -0,0 +1,3 @@ +# CERNLIB {#cernlib-hook} + +This hook sets the `CERN`, `CERN_LEVEL`, and `CERN_ROOT` environment variables. They are part of [CERNLIB's build system](https://cernlib.web.cern.ch/install/install.html), and are are needed for some programs to compile correctly. diff --git a/doc/hooks/desktop-file-utils.section.md b/doc/hooks/desktop-file-utils.section.md new file mode 100644 index 000000000000..41cc3cad0d0c --- /dev/null +++ b/doc/hooks/desktop-file-utils.section.md @@ -0,0 +1,5 @@ +# desktop-file-utils {#desktop-file-utils} + +This setup hook removes the MIME cache (located at `$out/share/applications/mimeinfo.cache`) in the `preFixupPhase`. + +This hook is necessary because `mimeinfo.cache` can be created when a package uses `desktop-file-utils`, resulting in collisions if multiple packages are installed that contain this file (as in [#48295](https://github.com/NixOS/nixpkgs/issues/48295)). diff --git a/doc/hooks/haredo.section.md b/doc/hooks/haredo.section.md new file mode 100644 index 000000000000..e7ec269a7364 --- /dev/null +++ b/doc/hooks/haredo.section.md @@ -0,0 +1,29 @@ +# `haredo` {#haredo-hook} + +This hook uses [the `haredo` command runner](https://sr.ht/~autumnull/haredo/) to build, check, and install the package. It overrides `buildPhase`, `checkPhase`, and `installPhase` by default. + +The hook builds its targets in parallel if [`config.enableParallelBuilding`](#var-stdenv-enableParallelBuilding) is set to `true`. + +## `buildPhase` {#haredo-hook-buildPhase} + +This phase attempts to build the default target. + +[]{#haredo-hook-haredoBuildTargets} Targets can be explicitly set by adding a string to the `haredoBuildTargets` list. + +[]{#haredo-hook-dontUseHaredoBuild} This behavior can be disabled by setting `dontUseHaredoBuild` to `true`. + +## `checkPhase` {#haredo-hook-checkPhase} + +This phase searches for the `check.do` or `test.do` targets, running them if they exist. + +[]{#haredo-hook-haredoCheckTargets} Targets can be explicitly set by adding a string to the `haredoCheckTargets` list. + +[]{#haredo-hook-dontUseHaredoCheck} This behavior can be disabled by setting `dontUseHaredoCheck` to `true`. + +## `installPhase` {#haredo-hook-installPhase} + +This phase attempts to build the `install.do` target, if it exists. + +[]{#haredo-hook-haredoInstallTargets} Targets can be explicitly set by adding a string to the `haredoInstallTargets` list. + +[]{#haredo-hook-dontUseHaredoInstall} This behavior can be disabled by setting `dontUseHaredoInstall` to `true`. diff --git a/doc/hooks/index.md b/doc/hooks/index.md index 6d01c6cbcbe5..aaa447373516 100644 --- a/doc/hooks/index.md +++ b/doc/hooks/index.md @@ -10,11 +10,15 @@ automake.section.md autopatchelf.section.md bmake.section.md breakpoint.section.md +cernlib.section.md cmake.section.md +desktop-file-utils.section.md gdk-pixbuf.section.md ghc.section.md gnome.section.md +haredo.section.md installShellFiles.section.md +just.section.md libiconv.section.md libxml2.section.md meson.section.md @@ -24,8 +28,10 @@ patch-rc-path-hooks.section.md perl.section.md pkg-config.section.md postgresql-test-hook.section.md +premake.section.md python.section.md scons.section.md +tauri.section.md tetex-tex-live.section.md unzip.section.md validatePkgConfig.section.md diff --git a/doc/hooks/installShellFiles.section.md b/doc/hooks/installShellFiles.section.md index 9be67d57bfc6..edaea5895a3b 100644 --- a/doc/hooks/installShellFiles.section.md +++ b/doc/hooks/installShellFiles.section.md @@ -1,16 +1,79 @@ # `installShellFiles` {#installshellfiles} -This hook helps with installing manpages and shell completion files. It exposes 2 shell functions `installManPage` and `installShellCompletion` that can be used from your `postInstall` hook. +This hook adds helpers that install artifacts like executable files, manpages +and shell completions. -The `installManPage` function takes one or more paths to manpages to install. The manpages must have a section suffix, and may optionally be compressed (with `.gz` suffix). This function will place them into the correct `share/man/man
/` directory, in [`outputMan`](#outputman). +It exposes the following functions that can be used from your `postInstall` +hook: -The `installShellCompletion` function takes one or more paths to shell completion files. By default it will autodetect the shell type from the completion file extension, but you may also specify it by passing one of `--bash`, `--fish`, or `--zsh`. These flags apply to all paths listed after them (up until another shell flag is given). Each path may also have a custom installation name provided by providing a flag `--name NAME` before the path. If this flag is not provided, zsh completions will be renamed automatically such that `foobar.zsh` becomes `_foobar`. A root name may be provided for all paths using the flag `--cmd NAME`; this synthesizes the appropriate name depending on the shell (e.g. `--cmd foo` will synthesize the name `foo.bash` for bash and `_foo` for zsh). +## `installBin` {#installshellfiles-installbin} + +The `installBin` function takes one or more paths to files to install as +executable files. + +This function will place them into [`outputBin`](#outputbin). + +### Example Usage {#installshellfiles-installbin-exampleusage} + +```nix +{ + nativeBuildInputs = [ installShellFiles ]; + + # Sometimes the file has an undersirable name. It should be renamed before + # being installed via installBin + postInstall = '' + mv a.out delmar + installBin foobar delmar + ''; +} +``` + +## `installManPage` {#installshellfiles-installmanpage} + +The `installManPage` function takes one or more paths to manpages to install. + +The manpages must have a section suffix, and may optionally be compressed (with +`.gz` suffix). This function will place them into the correct +`share/man/man
/` directory in [`outputMan`](#outputman). + +### Example Usage {#installshellfiles-installmanpage-exampleusage} + +```nix +{ + nativeBuildInputs = [ installShellFiles ]; + + # Sometimes the manpage file has an undersirable name; e.g. it conflicts with + # another software with an equal name. It should be renamed before being + # installed via installManPage + postInstall = '' + mv fromsea.3 delmar.3 + installManPage foobar.1 delmar.3 + ''; +} +``` + +## `installShellCompletion` {#installshellfiles-installshellcompletion} + +The `installShellCompletion` function takes one or more paths to shell +completion files. + +By default it will autodetect the shell type from the completion file extension, +but you may also specify it by passing one of `--bash`, `--fish`, or +`--zsh`. These flags apply to all paths listed after them (up until another +shell flag is given). Each path may also have a custom installation name +provided by providing a flag `--name NAME` before the path. If this flag is not +provided, zsh completions will be renamed automatically such that `foobar.zsh` +becomes `_foobar`. A root name may be provided for all paths using the flag +`--cmd NAME`; this synthesizes the appropriate name depending on the shell +(e.g. `--cmd foo` will synthesize the name `foo.bash` for bash and `_foo` for +zsh). + +### Example Usage {#installshellfiles-installshellcompletion-exampleusage} ```nix { nativeBuildInputs = [ installShellFiles ]; postInstall = '' - installManPage doc/foobar.1 doc/barfoo.3 # explicit behavior installShellCompletion --bash --name foobar.bash share/completions.bash installShellCompletion --fish --name foobar.fish share/completions.fish @@ -21,9 +84,17 @@ The `installShellCompletion` function takes one or more paths to shell completio } ``` -The path may also be a fifo or named fd (such as produced by `<(cmd)`), in which case the shell and name must be provided (see below). +The path may also be a fifo or named fd (such as produced by `<(cmd)`), in which +case the shell and name must be provided (see below). -If the destination shell completion file is not actually present or consists of zero bytes after calling `installShellCompletion` this is treated as a build failure. In particular, if completion files are not vendored but are generated by running an executable, this is likely to fail in cross compilation scenarios. The result will be a zero byte completion file and hence a build failure. To prevent this, guard the completion commands against this, e.g. +If the destination shell completion file is not actually present or consists of +zero bytes after calling `installShellCompletion` this is treated as a build +failure. In particular, if completion files are not vendored but are generated +by running an executable, this is likely to fail in cross compilation +scenarios. The result will be a zero byte completion file and hence a build +failure. To prevent this, guard the completion generation commands. + +### Example Usage {#installshellfiles-installshellcompletion-exampleusage-guarded} ```nix { diff --git a/doc/hooks/just.section.md b/doc/hooks/just.section.md new file mode 100644 index 000000000000..0eb4864ac74b --- /dev/null +++ b/doc/hooks/just.section.md @@ -0,0 +1,23 @@ +# `just` {#just-hook} + +This setup hook attempts to use [the `just` command runner](https://just.systems/man/en/) to build, check, and install the package. The hook overrides `buildPhase`, `checkPhase`, and `installPhase` by default. + +[]{#just-hook-justFlags} The `justFlags` variable can be set to a list of strings to add additional flags passed to all invocations of `just`. + +## `buildPhase` {#just-hook-buildPhase} + +This phase attempts to invoke `just` with [the default recipe](https://just.systems/man/en/chapter_23.html). + +[]{#just-hook-dontUseJustBuild} This behavior can be disabled by setting `dontUseJustBuild` to `true`. + +## `checkPhase` {#just-hook-checkPhase} + +This phase attempts to invoke the `just test` recipe, if it is available. This can be overrided by setting `checkTarget` to a string. + +[]{#just-hook-dontUseJustCheck} This behavior can be disabled by setting `dontUseJustCheck` to `true`. + +## `installPhase` {#just-hook-installPhase} + +This phase attempts to invoke the `just install` recipe. + +[]{#just-hook-dontUseJustInstall} This behavior can be disabled by setting `dontUseJustInstall` to `true`. diff --git a/doc/hooks/premake.section.md b/doc/hooks/premake.section.md new file mode 100644 index 000000000000..b2c2d8fb637c --- /dev/null +++ b/doc/hooks/premake.section.md @@ -0,0 +1,7 @@ +# Premake {#premake-hook} + +This setup hook attempts to configure the package using [the Premake build configuration system](https://premake.github.io/). It overrides the `configurePhase` by default, if none exists. + +[]{#premake-hook-premakefile} The Premakefile to use can be specified by setting `premakefile` in the derivation. + +[]{#premake-hook-premakeFlagsArray} The flags passed to Premake can be configured by adding strings to the `premakeFlags` list. diff --git a/doc/hooks/tauri.section.md b/doc/hooks/tauri.section.md new file mode 100644 index 000000000000..1f468950580a --- /dev/null +++ b/doc/hooks/tauri.section.md @@ -0,0 +1,108 @@ +# cargo-tauri.hook {#tauri-hook} + +[Tauri](https://tauri.app/) is a framework for building smaller, faster, and +more secure desktop applications with a web frontend. + +In Nixpkgs, `cargo-tauri.hook` overrides the default build and install phases. + +## Example code snippet {#tauri-hook-example-code-snippet} + +```nix +{ + lib, + stdenv, + rustPlatform, + fetchNpmDeps, + cargo-tauri, + darwin, + glib-networking, + libsoup, + nodejs, + npmHooks, + openssl, + pkg-config, + webkitgtk, + wrapGAppsHook3, +}: + +rustPlatform.buildRustPackage rec { + # . . . + + cargoHash = "..."; + + # Assuming our app's frontend uses `npm` as a package manager + npmDeps = fetchNpmDeps { + name = "${pname}-npm-deps-${version}"; + inherit src; + hash = "..."; + }; + + nativeBuildInputs = [ + # Pull in our main hook + cargo-tauri.hook + + # Setup npm + nodejs + npmHooks.npmConfigHook + + # Make sure we can find our libraries + pkg-config + wrapGAppsHook3 + ]; + + buildInputs = + [ openssl ] + ++ lib.optionals stdenv.isLinux [ + glib-networking # Most Tauri apps need networking + libsoup + webkitgtk + ] + ++ lib.optionals stdenv.isDarwin ( + with darwin.apple_sdk.frameworks; + [ + AppKit + CoreServices + Security + WebKit + ] + ); + + # Set our Tauri source directory + cargoRoot = "src-tauri"; + # And make sure we build there too + buildAndTestSubdir = cargoRoot; + + # . . . +} +``` + +## Variables controlling cargo-tauri {#tauri-hook-variables-controlling} + +### Tauri Exclusive Variables {#tauri-hook-exclusive-variables} + +#### `tauriBuildFlags` {#tauri-build-flags} + +Controls the flags passed to `cargo tauri build`. + +#### `tauriBundleType` {#tauri-bundle-type} + +The [bundle type](https://tauri.app/v1/guides/building/) to build. + +#### `dontTauriBuild` {#dont-tauri-build} + +Disables using `tauriBuildHook`. + +#### `dontTauriInstall` {#dont-tauri-install} + +Disables using `tauriInstallPostBuildHook` and `tauriInstallHook`. + +### Honored Variables {#tauri-hook-honored-variables} + +Along with those found in [](#compiling-rust-applications-with-cargo), the +following variables used by `cargoBuildHook` and `cargoInstallHook` are honored +by the cargo-tauri setup hook. + +- `buildAndTestSubdir` +- `cargoBuildType` +- `cargoBuildNoDefaultFeatures` +- `cargoBuildFeatures` diff --git a/doc/hooks/versionCheckHook.section.md b/doc/hooks/versionCheckHook.section.md index 55b9fa916c40..b8ff79d5dac8 100644 --- a/doc/hooks/versionCheckHook.section.md +++ b/doc/hooks/versionCheckHook.section.md @@ -28,7 +28,7 @@ It does so in a clean environment (using `env --ignore-environment`), and it che The variables that this phase control are: -- `dontVersionCheck`: Disable adding this hook to the [`preDistPhases`](#var-stdenv-preDist). Useful if you do want to load the bash functions of the hook, but run them differently. +- `dontVersionCheck`: Disable adding this hook to the [`preInstallCheckHooks`](#ssec-installCheck-phase). Useful if you do want to load the bash functions of the hook, but run them differently. - `versionCheckProgram`: The full path to the program that should print the `${version}` string. Defaults roughly to `${placeholder "out"}/bin/${pname}`. Using `$out` in the value of this variable won't work, as environment variables from this variable are not expanded by the hook. Hence using `placeholder` is unavoidable. - `versionCheckProgramArg`: The argument that needs to be passed to `versionCheckProgram`. If undefined the hook tries first `--help` and then `--version`. Examples: `version`, `-V`, `-v`. - `preVersionCheck`: A hook to run before the check is done. diff --git a/doc/languages-frameworks/beam.section.md b/doc/languages-frameworks/beam.section.md index 3653cdb337d1..2aac65900b9a 100644 --- a/doc/languages-frameworks/beam.section.md +++ b/doc/languages-frameworks/beam.section.md @@ -349,8 +349,8 @@ let nodePackages.prettier ]; - inputs = basePackages ++ lib.optionals stdenv.isLinux [ inotify-tools ] - ++ lib.optionals stdenv.isDarwin + inputs = basePackages ++ lib.optionals stdenv.hostPlatform.isLinux [ inotify-tools ] + ++ lib.optionals stdenv.hostPlatform.isDarwin (with darwin.apple_sdk.frameworks; [ CoreFoundation CoreServices ]); # define shell startup command diff --git a/doc/languages-frameworks/bower.section.md b/doc/languages-frameworks/bower.section.md index 20c142dad5b9..346852c49426 100644 --- a/doc/languages-frameworks/bower.section.md +++ b/doc/languages-frameworks/bower.section.md @@ -4,7 +4,7 @@ The end result of running Bower is a `bower_components` directory which can be included in the web app's build process. -Bower can be run interactively, by installing `nodePackages.bower`. More interestingly, the Bower components can be declared in a Nix derivation, with the help of `nodePackages.bower2nix`. +Bower can be run interactively, by installing `nodePackages.bower`. More interestingly, the Bower components can be declared in a Nix derivation, with the help of `bower2nix`. ## bower2nix usage {#ssec-bower2nix-usage} diff --git a/doc/languages-frameworks/coq.section.md b/doc/languages-frameworks/coq.section.md index 557896074bf0..ca983eec4f0d 100644 --- a/doc/languages-frameworks/coq.section.md +++ b/doc/languages-frameworks/coq.section.md @@ -23,12 +23,13 @@ The recommended way of defining a derivation for a Coq library, is to use the `c * if it is a string of the form `owner:branch` then it tries to download the `branch` of owner `owner` for a project of the same name using the same vcs, and the `version` attribute of the resulting derivation is set to `"dev"`, additionally if the owner is not provided (i.e. if the `owner:` prefix is missing), it defaults to the original owner of the package (see below), * if it is a string of the form `"#N"`, and the domain is github, then it tries to download the current head of the pull request `#N` from github, * `defaultVersion` (optional). Coq libraries may be compatible with some specific versions of Coq only. The `defaultVersion` attribute is used when no `version` is provided (or if `version = null`) to select the version of the library to use by default, depending on the context. This selection will mainly depend on a `coq` version number but also possibly on other packages versions (e.g. `mathcomp`). If its value ends up to be `null`, the package is marked for removal in end-user `coqPackages` attribute set. -* `release` (optional, defaults to `{}`), lists all the known releases of the library and for each of them provides an attribute set with at least a `sha256` attribute (you may put the empty string `""` in order to automatically insert a fake sha256, this will trigger an error which will allow you to find the correct sha256), each attribute set of the list of releases also takes optional overloading arguments for the fetcher as below (i.e.`domain`, `owner`, `repo`, `rev` assuming the default fetcher is used) and optional overrides for the result of the fetcher (i.e. `version` and `src`). +* `release` (optional, defaults to `{}`), lists all the known releases of the library and for each of them provides an attribute set with at least a `hash` attribute (you may put the empty string `""` in order to automatically insert a fake hash, this will trigger an error which will allow you to find the correct hash), each attribute set of the list of releases also takes optional overloading arguments for the fetcher as below (i.e.`domain`, `owner`, `repo`, `rev`, `artifact` assuming the default fetcher is used) and optional overrides for the result of the fetcher (i.e. `version` and `src`). * `fetcher` (optional, defaults to a generic fetching mechanism supporting github or gitlab based infrastructures), is a function that takes at least an `owner`, a `repo`, a `rev`, and a `hash` and returns an attribute set with a `version` and `src`. * `repo` (optional, defaults to the value of `pname`), * `owner` (optional, defaults to `"coq-community"`). * `domain` (optional, defaults to `"github.com"`), domains including the strings `"github"` or `"gitlab"` in their names are automatically supported, otherwise, one must change the `fetcher` argument to support them (cf `pkgs/development/coq-modules/heq/default.nix` for an example), * `releaseRev` (optional, defaults to `(v: v)`), provides a default mapping from release names to revision hashes/branch names/tags, +* `releaseArtifact` (optional, defaults to `(v: null)`), provides a default mapping from release names to artifact names (only works for github artifact for now), * `displayVersion` (optional), provides a way to alter the computation of `name` from `pname`, by explaining how to display version numbers, * `namePrefix` (optional, defaults to `[ "coq" ]`), provides a way to alter the computation of `name` from `pname`, by explaining which dependencies must occur in `name`, * `nativeBuildInputs` (optional), is a list of executables that are required to build the current derivation, in addition to the default ones (namely `which`, `dune` and `ocaml` depending on whether `useDune`, `useDuneifVersion` and `mlPlugin` are set). @@ -69,15 +70,15 @@ mkCoqDerivation { { cases = [ (isEq "8.6") (range "1.6" "1.7") ]; out = "1.1"; } ] null; release = { - "1.5.2".sha256 = "15aspf3jfykp1xgsxf8knqkxv8aav2p39c2fyirw7pwsfbsv2c4s"; - "1.5.1".sha256 = "13nlfm2wqripaq671gakz5mn4r0xwm0646araxv0nh455p9ndjs3"; - "1.5.0".sha256 = "064rvc0x5g7y1a0nip6ic91vzmq52alf6in2bc2dmss6dmzv90hw"; - "1.5.0".rev = "1.5"; - "1.4".sha256 = "0vnkirs8iqsv8s59yx1fvg1nkwnzydl42z3scya1xp1b48qkgn0p"; - "1.3".sha256 = "0l3vi5n094nx3qmy66hsv867fnqm196r8v605kpk24gl0aa57wh4"; - "1.2".sha256 = "1mh1w339dslgv4f810xr1b8v2w7rpx6fgk9pz96q0fyq49fw2xcq"; - "1.1".sha256 = "1q8alsm89wkc0lhcvxlyn0pd8rbl2nnxg81zyrabpz610qqjqc3s"; - "1.0".sha256 = "1qmbxp1h81cy3imh627pznmng0kvv37k4hrwi2faa101s6bcx55m"; + "1.5.2".hash = "sha256-mjCx9XKa38Nz9E6wNK7YSqHdJ7YTua5fD3d6J4e7WpU="; + "1.5.1".hash = "sha256-Q8tm0y2FQAt2V1kZYkDlHWRia/lTvXAMVjdmzEV11I4="; + "1.5.0".hash = "sha256-HIK0f21G69oEW8JG46gSBde/Q2LR3GiBCv680gHbmRg="; + "1.5.0".rev = "1.5"; + "1.4".hash = "sha256-F9g3MSIr3B6UZ3p8QWjz3/Jpw9sudJ+KRlvjiHSO024="; + "1.3".hash = "sha256-BPJTlAL0ETHvLMBslE0KFVt3DNoaGuMrHt2SBGyJe1A="; + "1.2".hash = "sha256-mHXBXSLYO4BN+jfN50y/+XCx0Qq5g4Ac2Y/qlsbgAdY="; + "1.1".hash = "sha256-ejAsMQbB/LtU9j+g160VdGXULrCe9s0gBWzyhKqmCuE="; + "1.0".hash = "sha256-tZTOltEBBKWciDxDMs/Ye4Jnq/33CANrHJ4FBMPtq+I="; }; propagatedBuildInputs = @@ -126,7 +127,7 @@ For example, here is how you could locally add a new release of the `multinomial coqPackages.lib.overrideCoqDerivation { defaultVersion = "2.0"; - release."2.0".sha256 = "1lq8x86vd3vqqh2yq6hvyagpnhfq5wmk5pg2z0xq7b7dbbbhyfkk"; + release."2.0".hash = "sha256-czoP11rtrIM7+OLdMisv2EF7n/IbGuwFxHiPtg3qCNM="; } coqPackages.multinomials ``` diff --git a/doc/languages-frameworks/cuda.section.md b/doc/languages-frameworks/cuda.section.md index 1b2005bb1edd..af52a3d31d05 100644 --- a/doc/languages-frameworks/cuda.section.md +++ b/doc/languages-frameworks/cuda.section.md @@ -149,3 +149,104 @@ All new projects should use the CUDA redistributables available in [`cudaPackage | Find libraries | `buildPhase` or `patchelf` | Missing dependency on a `lib` or `static` output | Add the missing dependency | The `lib` or `static` output typically contain the libraries | In the scenario you are unable to run the resulting binary: this is arguably the most complicated as it could be any combination of the previous reasons. This type of failure typically occurs when a library attempts to load or open a library it depends on that it does not declare in its `DT_NEEDED` section. As a first step, ensure that dependencies are patched with [`autoAddDriverRunpath`](https://search.nixos.org/packages?channel=unstable&type=packages&query=autoAddDriverRunpath). Failing that, try running the application with [`nixGL`](https://github.com/guibou/nixGL) or a similar wrapper tool. If that works, it likely means that the application is attempting to load a library that is not in the `RPATH` or `RUNPATH` of the binary. + +## Running Docker or Podman containers with CUDA support {#running-docker-or-podman-containers-with-cuda-support} + +It is possible to run Docker or Podman containers with CUDA support. The recommended mechanism to perform this task is to use the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html). + +The NVIDIA Container Toolkit can be enabled in NixOS like follows: + +```nix +{ + hardware.nvidia-container-toolkit.enable = true; +} +``` + +This will automatically enable a service that generates a CDI specification (located at `/var/run/cdi/nvidia-container-toolkit.json`) based on the auto-detected hardware of your machine. You can check this service by running: + +```ShellSession +$ systemctl status nvidia-container-toolkit-cdi-generator.service +``` + +::: {.note} +Depending on what settings you had already enabled in your system, you might need to restart your machine in order for the NVIDIA Container Toolkit to generate a valid CDI specification for your machine. +::: + +Once that a valid CDI specification has been generated for your machine on boot time, both Podman and Docker (> 25) will use this spec if you provide them with the `--device` flag: + +```ShellSession +$ podman run --rm -it --device=nvidia.com/gpu=all ubuntu:latest nvidia-smi -L +GPU 0: NVIDIA GeForce RTX 4090 (UUID: ) +GPU 1: NVIDIA GeForce RTX 2080 SUPER (UUID: ) +``` + +```ShellSession +$ docker run --rm -it --device=nvidia.com/gpu=all ubuntu:latest nvidia-smi -L +GPU 0: NVIDIA GeForce RTX 4090 (UUID: ) +GPU 1: NVIDIA GeForce RTX 2080 SUPER (UUID: ) +``` + +You can check all the identifiers that have been generated for your auto-detected hardware by checking the contents of the `/var/run/cdi/nvidia-container-toolkit.json` file: + +```ShellSession +$ nix run nixpkgs#jq -- -r '.devices[].name' < /var/run/cdi/nvidia-container-toolkit.json +0 +1 +all +``` + +### Specifying what devices to expose to the container {#specifying-what-devices-to-expose-to-the-container} + +You can choose what devices are exposed to your containers by using the identifier on the generated CDI specification. Like follows: + +```ShellSession +$ podman run --rm -it --device=nvidia.com/gpu=0 ubuntu:latest nvidia-smi -L +GPU 0: NVIDIA GeForce RTX 4090 (UUID: ) +``` + +You can repeat the `--device` argument as many times as necessary if you have multiple GPU's and you want to pick up which ones to expose to the container: + +```ShellSession +$ podman run --rm -it --device=nvidia.com/gpu=0 --device=nvidia.com/gpu=1 ubuntu:latest nvidia-smi -L +GPU 0: NVIDIA GeForce RTX 4090 (UUID: ) +GPU 1: NVIDIA GeForce RTX 2080 SUPER (UUID: ) +``` + +::: {.note} +By default, the NVIDIA Container Toolkit will use the GPU index to identify specific devices. You can change the way to identify what devices to expose by using the `hardware.nvidia-container-toolkit.device-name-strategy` NixOS attribute. +::: + +### Using docker-compose {#using-docker-compose} + +It's possible to expose GPU's to a `docker-compose` environment as well. With a `docker-compose.yaml` file like follows: + +```yaml +services: + some-service: + image: ubuntu:latest + command: sleep infinity + deploy: + resources: + reservations: + devices: + - driver: cdi + device_ids: + - nvidia.com/gpu=all +``` + +In the same manner, you can pick specific devices that will be exposed to the container: + +```yaml +services: + some-service: + image: ubuntu:latest + command: sleep infinity + deploy: + resources: + reservations: + devices: + - driver: cdi + device_ids: + - nvidia.com/gpu=0 + - nvidia.com/gpu=1 +``` diff --git a/doc/languages-frameworks/dotnet.section.md b/doc/languages-frameworks/dotnet.section.md index 546b451f3117..d9e0cbe16351 100644 --- a/doc/languages-frameworks/dotnet.section.md +++ b/doc/languages-frameworks/dotnet.section.md @@ -93,7 +93,7 @@ The `dotnetCorePackages.sdk` contains both a runtime and the full sdk of a given To package Dotnet applications, you can use `buildDotnetModule`. This has similar arguments to `stdenv.mkDerivation`, with the following additions: * `projectFile` is used for specifying the dotnet project file, relative to the source root. These have `.sln` (entire solution) or `.csproj` (single project) file extensions. This can be a list of multiple projects as well. When omitted, will attempt to find and build the solution (`.sln`). If running into problems, make sure to set it to a file (or a list of files) with the `.csproj` extension - building applications as entire solutions is not fully supported by the .NET CLI. -* `nugetDeps` takes either a path to a `deps.nix` file, or a derivation. The `deps.nix` file can be generated using the script attached to `passthru.fetch-deps`. If the argument is a derivation, it will be used directly and assume it has the same output as `mkNugetDeps`. +* `nugetDeps` takes either a path to a `deps.nix` file, or a derivation. The `deps.nix` file can be generated using the script attached to `passthru.fetch-deps`. For compatibility, if the argument is a list of derivations, they will be added to `buildInputs`. ::: {.note} For more detail about managing the `deps.nix` file, see [Generating and updating NuGet dependencies](#generating-and-updating-nuget-dependencies) ::: @@ -118,6 +118,7 @@ For more detail about managing the `deps.nix` file, see [Generating and updating * `dotnet-sdk` is useful in cases where you need to change what dotnet SDK is being used. You can also set this to the result of `dotnetSdkPackages.combinePackages`, if the project uses multiple SDKs to build. * `dotnet-runtime` is useful in cases where you need to change what dotnet runtime is being used. This can be either a regular dotnet runtime, or an aspnetcore. * `testProjectFile` is useful in cases where the regular project file does not contain the unit tests. It gets restored and build, but not installed. You may need to regenerate your nuget lockfile after setting this. Note that if set, only tests from this project are executed. +* `testFilters` is used to disable running unit tests based on various [filters](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test#filter-option-details). This gets passed as: `dotnet test --filter "{}"`, with each filter being concatenated using `"&"`. * `disabledTests` is used to disable running specific unit tests. This gets passed as: `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all unit test frameworks. * `dotnetRestoreFlags` can be used to pass flags to `dotnet restore`. * `dotnetBuildFlags` can be used to pass flags to `dotnet build`. @@ -218,7 +219,7 @@ buildDotnetGlobalTool { ## Generating and updating NuGet dependencies {#generating-and-updating-nuget-dependencies} When writing a new expression, you can use the generated `fetch-deps` script to initialise the lockfile. -After creating a blank `deps.nix` and pointing `nugetDeps` to it, +After setting `nugetDeps` to the desired location of the lockfile (e.g. `./deps.nix`), build the script with `nix-build -A package.fetch-deps` and then run the result. (When the root attr is your package, it's simply `nix-build -A fetch-deps`.) diff --git a/doc/languages-frameworks/emscripten.section.md b/doc/languages-frameworks/emscripten.section.md index 9ce48db2c2de..d1ed62d0503f 100644 --- a/doc/languages-frameworks/emscripten.section.md +++ b/doc/languages-frameworks/emscripten.section.md @@ -84,7 +84,7 @@ One advantage is that when `pkgs.zlib` is updated, it will automatically update echo "================= /testing zlib using node =================" ''; - postPatch = pkgs.lib.optionalString pkgs.stdenv.isDarwin '' + postPatch = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin '' substituteInPlace configure \ --replace-fail '/usr/bin/libtool' 'ar' \ --replace-fail 'AR="libtool"' 'AR="ar"' \ diff --git a/doc/languages-frameworks/gnome.section.md b/doc/languages-frameworks/gnome.section.md index b4999aec8746..02dfa3508c4f 100644 --- a/doc/languages-frameworks/gnome.section.md +++ b/doc/languages-frameworks/gnome.section.md @@ -155,9 +155,11 @@ There are no schemas available in `XDG_DATA_DIRS`. Temporarily add a random pack Package is missing some GSettings schemas. You can find out the package containing the schema with `nix-locate org.gnome.foo.gschema.xml` and let the hooks handle the wrapping as [above](#ssec-gnome-common-issues-no-schemas). -### When using `wrapGApps*` hook with special derivers you can end up with double wrapped binaries. {#ssec-gnome-common-issues-double-wrapped} +### When using `wrapGApps*` hook with special derivers or hooks you can end up with double wrapped binaries. {#ssec-gnome-common-issues-double-wrapped} -This is because derivers like `python.pkgs.buildPythonApplication` or `qt5.mkDerivation` have setup-hooks automatically added that produce wrappers with makeWrapper. The simplest way to workaround that is to disable the `wrapGApps*` hook automatic wrapping with `dontWrapGApps = true;` and pass the arguments it intended to pass to makeWrapper to another. +This is because some setup hooks like `qt6.wrapQtAppsHook` also wrap programs using `makeWrapper`. Likewise, some derivers (e.g. `python.pkgs.buildPythonApplication`) automatically pull in their own setup hooks that produce wrappers. + +The simplest workaround is to disable the `wrapGApps*` hook's automatic wrapping using `dontWrapGApps = true;` while passing its `makeWrapper` arguments to another wrapper. In the case of a Python application it could look like: @@ -184,19 +186,19 @@ python3.pkgs.buildPythonApplication { And for a QT app like: ```nix -mkDerivation { +stdenv.mkDerivation { pname = "calibre"; version = "3.47.0"; nativeBuildInputs = [ wrapGAppsHook3 + qt6.wrapQtAppsHook qmake # ... ]; dontWrapGApps = true; - # Arguments to be passed to `makeWrapper`, only used by qt5’s mkDerivation preFixup = '' qtWrapperArgs+=("''${gappsWrapperArgs[@]}") ''; diff --git a/doc/languages-frameworks/go.section.md b/doc/languages-frameworks/go.section.md index b20308c7b4ab..3100124e0ce5 100644 --- a/doc/languages-frameworks/go.section.md +++ b/doc/languages-frameworks/go.section.md @@ -62,6 +62,65 @@ The following is an example expression using `buildGoModule`: } ``` +### Obtaining and overriding `vendorHash` for `buildGoModule` {#buildGoModule-vendorHash} + +We can use `nix-prefetch` to obtain the actual hash. The following command gets the value of `vendorHash` for package `pet`: + +```sh +cd path/to/nixpkgs +nix-prefetch -E "{ sha256 }: ((import ./. { }).my-package.overrideAttrs { vendorHash = sha256; }).goModules" +``` + +To obtain the hash without external tools, set `vendorHash = lib.fakeHash;` and run the build. ([more details here](#sec-source-hashes)). + +`vendorHash` can be overridden with `overrideAttrs`. Override the above example like this: + +```nix +{ + pet_0_4_0 = pet.overrideAttrs ( + finalAttrs: previousAttrs: { + version = "0.4.0"; + src = fetchFromGitHub { + inherit (previousAttrs.src) owner repo; + rev = "v${finalAttrs.version}"; + hash = "sha256-gVTpzmXekQxGMucDKskGi+e+34nJwwsXwvQTjRO6Gdg="; + }; + vendorHash = "sha256-dUvp7FEW09V0xMuhewPGw3TuAic/sD7xyXEYviZ2Ivs="; + } + ); +} +``` + +### Overriding `goModules` {#buildGoModule-goModules-override} + +Overriding `.goModules` by calling `goModules.overrideAttrs` is unsupported. Still, it is possible to override the `vendorHash` (`goModules`'s `outputHash`) and the `pre`/`post` hooks for both the build and patch phases of the primary and `goModules` derivation. Alternatively, the primary derivation provides an overridable `passthru.overrideModAttrs` function to store the attribute overlay implicitly taken by `goModules.overrideAttrs`. Here's an example usage of `overrideModAttrs`: + +```nix +{ + pet-overridden = pet.overrideAttrs ( + finalAttrs: previousAttrs: { + passthru = previousAttrs.passthru // { + # If the original package has an `overrideModAttrs` attribute set, you'd + # want to extend it, and not replace it. Hence we use + # `lib.composeExtensions`. If you are sure the `overrideModAttrs` of the + # original package trivially does nothing, you can safely replace it + # with your own by not using `lib.composeExtensions`. + overrideModAttrs = lib.composeExtensions previousAttrs.passthru.overrideModAttrs ( + finalModAttrs: previousModAttrs: { + # goModules-specific overriding goes here + postBuild = '' + # Here you have access to the `vendor` directory. + substituteInPlace vendor/github.com/example/repo/file.go \ + --replace-fail "panic(err)" "" + ''; + } + ); + }; + } + ); +} +``` + ## `buildGoPackage` (legacy) {#ssec-go-legacy} The function `buildGoPackage` builds legacy Go programs, not supporting Go modules. diff --git a/doc/languages-frameworks/haskell.section.md b/doc/languages-frameworks/haskell.section.md index e8970b2d0335..247daf8d1dbe 100644 --- a/doc/languages-frameworks/haskell.section.md +++ b/doc/languages-frameworks/haskell.section.md @@ -1076,6 +1076,9 @@ benchmark component. `disableLibraryProfiling drv` : Sets the `enableLibraryProfiling` argument to `false` for `drv`. +`disableParallelBuilding drv` +: Sets the `enableParallelBuilding` argument to `false` for `drv`. + #### Library functions in the Haskell package sets {#haskell-package-set-lib-functions} Some library functions depend on packages from the Haskell package sets. Thus they are diff --git a/doc/languages-frameworks/index.md b/doc/languages-frameworks/index.md index 021f4807fb22..c21f73e69a25 100644 --- a/doc/languages-frameworks/index.md +++ b/doc/languages-frameworks/index.md @@ -67,6 +67,7 @@ dotnet.section.md emscripten.section.md gnome.section.md go.section.md +gradle.section.md hare.section.md haskell.section.md hy.section.md diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md index 8eb3d1ff39a4..e68a29b0b3fd 100644 --- a/doc/languages-frameworks/javascript.section.md +++ b/doc/languages-frameworks/javascript.section.md @@ -258,26 +258,39 @@ It returns a derivation with all `package-lock.json` dependencies downloaded int #### importNpmLock {#javascript-buildNpmPackage-importNpmLock} -`importNpmLock` is a Nix function that requires the following optional arguments: +This function replaces the npm dependency references in `package.json` and `package-lock.json` with paths to the Nix store. +How each dependency is fetched can be customized with the `fetcherOpts` argument. -- `npmRoot`: Path to package directory containing the source tree +This is a simpler and more convenient alternative to [`fetchNpmDeps`](#javascript-buildNpmPackage-fetchNpmDeps) for managing npm dependencies in Nixpkgs. +There is no need to specify a `hash`, since it relies entirely on the integrity hashes already present in the `package-lock.json` file. + +##### Inputs {#javascript-buildNpmPackage-inputs} + +- `npmRoot`: Path to package directory containing the source tree. + If this is omitted, the `package` and `packageLock` arguments must be specified instead. - `package`: Parsed contents of `package.json` - `packageLock`: Parsed contents of `package-lock.json` - `pname`: Package name - `version`: Package version +- `fetcherOpts`: An attribute set of arguments forwarded to the underlying fetcher. It returns a derivation with a patched `package.json` & `package-lock.json` with all dependencies resolved to Nix store paths. -This function is analogous to using `fetchNpmDeps`, but instead of specifying `hash` it uses metadata from `package.json` & `package-lock.json`. +:::{.note} +`npmHooks.npmConfigHook` cannot be used with `importNpmLock`. +Use `importNpmLock.npmConfigHook` instead. +::: -Note that `npmHooks.npmConfigHook` cannot be used with `importNpmLock`. You will instead need to use `importNpmLock.npmConfigHook`: +:::{.example} +##### `pkgs.importNpmLock` usage example {#javascript-buildNpmPackage-example} ```nix { buildNpmPackage, importNpmLock }: buildNpmPackage { pname = "hello"; version = "0.1.0"; + src = ./.; npmDeps = importNpmLock { npmRoot = ./.; @@ -286,6 +299,75 @@ buildNpmPackage { npmConfigHook = importNpmLock.npmConfigHook; } ``` +::: + +:::{.example} +##### `pkgs.importNpmLock` usage example with `fetcherOpts` {#javascript-buildNpmPackage-example-fetcherOpts} + +`importNpmLock` uses the following fetchers: + +- `pkgs.fetchurl` for `http(s)` dependencies +- `builtins.fetchGit` for `git` dependencies + +It is possible to provide additional arguments to individual fetchers as needed: + +```nix +{ buildNpmPackage, importNpmLock }: + +buildNpmPackage { + pname = "hello"; + version = "0.1.0"; + src = ./.; + + npmDeps = importNpmLock { + npmRoot = ./.; + fetcherOpts = { + # Pass 'curlOptsList' to 'pkgs.fetchurl' while fetching 'axios' + { "node_modules/axios" = { curlOptsList = [ "--verbose" ]; }; } + }; + }; + + npmConfigHook = importNpmLock.npmConfigHook; +} +``` +::: + +#### importNpmLock.buildNodeModules {#javascript-buildNpmPackage-importNpmLock.buildNodeModules} + +`importNpmLock.buildNodeModules` returns a derivation with a pre-built `node_modules` directory, as imported by `importNpmLock`. + +This is to be used together with `importNpmLock.hooks.linkNodeModulesHook` to facilitate `nix-shell`/`nix develop` based development workflows. + +It accepts an argument with the following attributes: + +`npmRoot` (Path; optional) +: Path to package directory containing the source tree. If not specified, the `package` and `packageLock` arguments must both be specified. + +`package` (Attrset; optional) +: Parsed contents of `package.json`, as returned by `lib.importJSON ./my-package.json`. If not specified, the `package.json` in `npmRoot` is used. + +`packageLock` (Attrset; optional) +: Parsed contents of `package-lock.json`, as returned `lib.importJSON ./my-package-lock.json`. If not specified, the `package-lock.json` in `npmRoot` is used. + +`derivationArgs` (`mkDerivation` attrset; optional) +: Arguments passed to `stdenv.mkDerivation` + +For example: + +```nix +pkgs.mkShell { + packages = [ + importNpmLock.hooks.linkNodeModulesHook + nodejs + ]; + + npmDeps = importNpmLock.buildNodeModules { + npmRoot = ./.; + inherit nodejs; + }; +} +``` +will create a development shell where a `node_modules` directory is created & packages symlinked to the Nix store when activated. ### corepack {#javascript-corepack} @@ -430,6 +512,7 @@ Yarn based projects use a `yarn.lock` file instead of a `package-lock.json` to p - `yarnConfigHook`: Fetches the dependencies from the offline cache and installs them into `node_modules`. - `yarnBuildHook`: Runs `yarn build` or a specified `yarn` command that builds the project. +- `yarnInstallHook`: Runs `yarn install --production` to prune dependencies and installs the project into `$out`. An example usage of the above attributes is: @@ -441,8 +524,8 @@ An example usage of the above attributes is: fetchYarnDeps, yarnConfigHook, yarnBuildHook, + yarnInstallHook, nodejs, - npmHooks, }: stdenv.mkDerivation (finalAttrs: { @@ -458,15 +541,15 @@ stdenv.mkDerivation (finalAttrs: { yarnOfflineCache = fetchYarnDeps { yarnLock = finalAttrs.src + "/yarn.lock"; - hash = "sha256-mo8urQaWIHu33+r0Y7mL9mJ/aSe/5CihuIetTeDHEUQ="; + hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; }; nativeBuildInputs = [ yarnConfigHook yarnBuildHook + yarnInstallHook # Needed for executing package.json scripts nodejs - npmHooks.npmInstallHook ]; meta = { @@ -475,8 +558,6 @@ stdenv.mkDerivation (finalAttrs: { }) ``` -Note that there is no setup hook for installing yarn based packages - `npmHooks.npmInstallHook` should fit most cases, but sometimes you may need to override the `installPhase` completely. - #### `yarnConfigHook` arguments {#javascript-yarnconfighook} By default, `yarnConfigHook` relies upon the attribute `${yarnOfflineCache}` (or `${offlineCache}` if the former is not set) to find the location of the offline cache produced by `fetchYarnDeps`. To disable this phase, you can set `dontYarnInstallDeps = true` or override the `configurePhase`. @@ -488,9 +569,15 @@ This script by default runs `yarn --offline build`, and it relies upon the proje - `yarnBuildScript`: Sets a different `yarn --offline` subcommand (defaults to `build`). - `yarnBuildFlags`: Single string list of additional flags to pass the above command, or a Nix list of such additional flags. +#### `yarnInstallHook` arguments {#javascript-yarninstallhook} + +To install the package `yarnInstallHook` uses both `npm` and `yarn` to cleanup project files and dependencies. To disable this phase, you can set `dontYarnInstall = true` or override the `installPhase`. Below is a list of additional `mkDerivation` arguments read by this hook: + +- `yarnKeepDevDeps`: Disables the removal of devDependencies from `node_modules` before installation. + ### yarn2nix {#javascript-yarn2nix} -WARNING: The `yarn2nix` functions have been deprecated in favor of the new `yarnConfigHook` and `yarnBuildHook`. Documentation for them still appears here for the sake of the packages that still use them. See also a tracking issue [#324246](https://github.com/NixOS/nixpkgs/issues/324246). +WARNING: The `yarn2nix` functions have been deprecated in favor of the new `yarnConfigHook`, `yarnBuildHook` and `yarnInstallHook`. Documentation for them still appears here for the sake of the packages that still use them. See also a tracking issue [#324246](https://github.com/NixOS/nixpkgs/issues/324246). #### Preparation {#javascript-yarn2nix-preparation} diff --git a/doc/languages-frameworks/maven.section.md b/doc/languages-frameworks/maven.section.md index e56beb102570..d6c8357785e3 100644 --- a/doc/languages-frameworks/maven.section.md +++ b/doc/languages-frameworks/maven.section.md @@ -219,10 +219,10 @@ stdenv.mkDerivation { # don't do any fixup dontFixup = true; - outputHashAlgo = "sha256"; + outputHashAlgo = null; outputHashMode = "recursive"; # replace this with the correct SHA256 - outputHash = lib.fakeSha256; + outputHash = lib.fakeHash; } ``` diff --git a/doc/languages-frameworks/perl.section.md b/doc/languages-frameworks/perl.section.md index a3d76a44f656..843d46584cdd 100644 --- a/doc/languages-frameworks/perl.section.md +++ b/doc/languages-frameworks/perl.section.md @@ -125,8 +125,8 @@ On Darwin, if a script has too many `-Idir` flags in its first line (its “sheb hash = "sha256-vOhB/FwQMC8PPvdnjDvxRpU6jAZcC6GMQfc0AH4uwKg="; }; - nativeBuildInputs = lib.optional stdenv.isDarwin shortenPerlShebang; - postInstall = lib.optionalString stdenv.isDarwin '' + nativeBuildInputs = lib.optional stdenv.hostPlatform.isDarwin shortenPerlShebang; + postInstall = lib.optionalString stdenv.hostPlatform.isDarwin '' shortenPerlShebang $out/bin/exiftool ''; }; diff --git a/doc/languages-frameworks/python.section.md b/doc/languages-frameworks/python.section.md index 8992d36fb25b..3d9736da7fa0 100644 --- a/doc/languages-frameworks/python.section.md +++ b/doc/languages-frameworks/python.section.md @@ -214,9 +214,6 @@ because their behaviour is different: paths included in this list. Items listed in `install_requires` go here. * `optional-dependencies ? { }`: Optional feature flagged dependencies. Items listed in `extras_requires` go here. -Aside from propagating dependencies, - `buildPythonPackage` also injects code into and wraps executables with the - paths included in this list. Items listed in `extras_requires` go here. ##### Overriding Python packages {#overriding-python-packages} @@ -361,6 +358,66 @@ modifications. Do pay attention to passing in the right Python version! +#### `mkPythonMetaPackage` function {#mkpythonmetapackage-function} + +This will create a meta package containing [metadata files](https://packaging.python.org/en/latest/specifications/recording-installed-packages/) to satisfy a dependency on a package, without it actually having been installed into the environment. +In nixpkgs this is used to package Python packages with split binary/source distributions such as [psycopg2](https://pypi.org/project/psycopg2/)/[psycopg2-binary](https://pypi.org/project/psycopg2-binary/). + +```nix +mkPythonMetaPackage { + pname = "psycopg2-binary"; + inherit (psycopg2) optional-dependencies version; + dependencies = [ psycopg2 ]; + meta = { + inherit (psycopg2.meta) description homepage; + }; +} +``` + +#### `mkPythonEditablePackage` function {#mkpythoneditablepackage-function} + +When developing Python packages it's common to install packages in [editable mode](https://setuptools.pypa.io/en/latest/userguide/development_mode.html). +Like `mkPythonMetaPackage` this function exists to create an otherwise empty package, but also containing a pointer to an impure location outside the Nix store that can be changed without rebuilding. + +The editable root is passed as a string. Normally `.pth` files contains absolute paths to the mutable location. This isn't always ergonomic with Nix, so environment variables are expanded at runtime. +This means that a shell hook setting up something like a `$REPO_ROOT` variable can be used as the relative package root. + +As an implementation detail, the [PEP-518](https://peps.python.org/pep-0518/) `build-system` specified won't be used, but instead the editable package will be built using [hatchling](https://pypi.org/project/hatchling/). +The `build-system`'s provided will instead become runtime dependencies of the editable package. + +Note that overriding packages deeper in the dependency graph _can_ work, but it's not the primary use case and overriding existing packages can make others break in unexpected ways. + +``` nix +{ pkgs ? import { } }: + +let + pyproject = pkgs.lib.importTOML ./pyproject.toml; + + myPython = pkgs.python.override { + self = myPython; + packageOverrides = pyfinal: pyprev: { + # An editable package with a script that loads our mutable location + my-editable = pyfinal.mkPythonEditablePackage { + # Inherit project metadata from pyproject.toml + pname = pyproject.project.name; + inherit (pyproject.project) version; + + # The editable root passed as a string + root = "$REPO_ROOT/src"; # Use environment variable expansion at runtime + + # Inject a script (other PEP-621 entrypoints are also accepted) + inherit (pyproject.project) scripts; + }; + }; + }; + + pythonEnv = myPython.withPackages (ps: [ ps.my-editable ]); + +in pkgs.mkShell { + packages = [ pythonEnv ]; +} +``` + #### `python.buildEnv` function {#python.buildenv-function} Python environments can be created using the low-level `pkgs.buildEnv` function. @@ -1249,7 +1306,7 @@ for example: ] ++ lib.optionals (pythonAtLeast "3.8") [ # broken due to python3.8 async changes "async" - ] ++ lib.optionals stdenv.isDarwin [ + ] ++ lib.optionals stdenv.buildPlatform.isDarwin [ # can fail when building with other packages "socket" ]; @@ -2033,8 +2090,8 @@ no maintainer, so maintenance falls back to the package set maintainers. ### Updating packages in bulk {#python-package-bulk-updates} -There is a tool to update alot of python libraries in bulk, it exists at -`maintainers/scripts/update-python-libraries` with this repository. +A tool to bulk-update numerous Python libraries is available in the +repository at `maintainers/scripts/update-python-libraries`. It can quickly update minor or major versions for all packages selected and create update commits, and supports the `fetchPypi`, `fetchurl` and diff --git a/doc/languages-frameworks/ruby.section.md b/doc/languages-frameworks/ruby.section.md index 7dede6944a3d..31f696bd6427 100644 --- a/doc/languages-frameworks/ruby.section.md +++ b/doc/languages-frameworks/ruby.section.md @@ -2,7 +2,7 @@ ## Using Ruby {#using-ruby} -Several versions of Ruby interpreters are available on Nix, as well as over 250 gems and many applications written in Ruby. The attribute `ruby` refers to the default Ruby interpreter, which is currently MRI 3.1. It's also possible to refer to specific versions, e.g. `ruby_3_y`, `jruby`, or `mruby`. +Several versions of Ruby interpreters are available on Nix, as well as over 250 gems and many applications written in Ruby. The attribute `ruby` refers to the default Ruby interpreter, which is currently MRI 3.3. It's also possible to refer to specific versions, e.g. `ruby_3_y`, `jruby`, or `mruby`. In the Nixpkgs tree, Ruby packages can be found throughout, depending on what they do, and are called from the main package set. Ruby gems, however are separate sets, and there's one default set for each interpreter (currently MRI only). @@ -154,7 +154,7 @@ let defaultGemConfig = pkgs.defaultGemConfig // { pg = attrs: { buildFlags = - [ "--with-pg-config=${pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; + [ "--with-pg-config=${lib.getDev pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; }; }; }; @@ -172,7 +172,7 @@ let gemConfig = pkgs.defaultGemConfig // { pg = attrs: { buildFlags = - [ "--with-pg-config=${pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; + [ "--with-pg-config=${lib.getDev pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; }; }; }; @@ -190,9 +190,7 @@ let defaultGemConfig = super.defaultGemConfig // { pg = attrs: { buildFlags = [ - "--with-pg-config=${ - pkgs."postgresql_${pg_version}" - }/bin/pg_config" + "--with-pg-config=${lib.getDev pkgs."postgresql_${pg_version}"}/bin/pg_config" ]; }; }; diff --git a/doc/languages-frameworks/rust.section.md b/doc/languages-frameworks/rust.section.md index 15f16879a5b4..808936f49e60 100644 --- a/doc/languages-frameworks/rust.section.md +++ b/doc/languages-frameworks/rust.section.md @@ -567,8 +567,7 @@ buildPythonPackage rec { }; cargoDeps = rustPlatform.fetchCargoTarball { - inherit src sourceRoot; - name = "${pname}-${version}"; + inherit pname version src sourceRoot; hash = "sha256-miW//pnOmww2i6SOGbkrAIdc/JMDT4FJLqdMFojZeoY="; }; @@ -611,9 +610,8 @@ buildPythonPackage rec { }; cargoDeps = rustPlatform.fetchCargoTarball { - inherit src; + inherit pname version src; sourceRoot = "${pname}-${version}/${cargoRoot}"; - name = "${pname}-${version}"; hash = "sha256-PS562W4L1NimqDV2H0jl5vYhL08H9est/pbIxSdYVfo="; }; @@ -652,8 +650,7 @@ buildPythonPackage rec { }; cargoDeps = rustPlatform.fetchCargoTarball { - inherit src; - name = "${pname}-${version}"; + inherit pname version src; hash = "sha256-heOBK8qi2nuc/Ib+I/vLzZ1fUUD/G/KTw9d7M4Hz5O0="; }; @@ -697,8 +694,7 @@ stdenv.mkDerivation rec { }; cargoDeps = rustPlatform.fetchCargoTarball { - inherit src; - name = "${pname}-${version}"; + inherit pname version src; hash = "sha256-8fa3fa+sFi5H+49B5sr2vYPkp9C9s6CcE0zv4xB8gww="; }; diff --git a/doc/packages/darwin-builder.section.md b/doc/packages/darwin-builder.section.md index ca8519c5bf5f..06358c790165 100644 --- a/doc/packages/darwin-builder.section.md +++ b/doc/packages/darwin-builder.section.md @@ -100,7 +100,7 @@ $ sudo launchctl kickstart -k system/org.nixos.nix-daemon darwin-builder = nixpkgs.lib.nixosSystem { system = linuxSystem; modules = [ - "${nixpkgs}/nixos/modules/profiles/macos-builder.nix" + "${nixpkgs}/nixos/modules/profiles/nix-builder-vm.nix" { virtualisation = { host.pkgs = pkgs; darwin-builder.workingDirectory = "/var/lib/darwin-builder"; @@ -158,7 +158,7 @@ in the example below and rebuild. darwin-builder = nixpkgs.lib.nixosSystem { system = linuxSystem; modules = [ - "${nixpkgs}/nixos/modules/profiles/macos-builder.nix" + "${nixpkgs}/nixos/modules/profiles/nix-builder-vm.nix" { virtualisation.host.pkgs = pkgs; virtualisation.darwin-builder.diskSize = 5120; @@ -185,6 +185,6 @@ nix-repl> darwin.linux-builder.nixosConfig.nix.package «derivation /nix/store/...-nix-2.17.0.drv» nix-repl> :p darwin.linux-builder.nixosOptions.virtualisation.memorySize.definitionsWithLocations -[ { file = "/home/user/src/nixpkgs/nixos/modules/profiles/macos-builder.nix"; value = 3072; } ] +[ { file = "/home/user/src/nixpkgs/nixos/modules/profiles/nix-builder-vm.nix"; value = 3072; } ] ``` diff --git a/doc/packages/geant4.section.md b/doc/packages/geant4.section.md new file mode 100644 index 000000000000..3793953d5171 --- /dev/null +++ b/doc/packages/geant4.section.md @@ -0,0 +1,15 @@ +# Geant4 {#geant4} + +[Geant4](https://www.geant4.org/) is a toolkit for simulating how particles pass through matter. It is available through the `geant4` package. + +## Setup hook {#geant4-hook} + +The setup hook included in the package applies the environment variables set by the [`geant4.sh` script](https://github.com/Geant4/geant4/blob/master/cmake/Modules/G4ConfigureGNUMakeHelpers.cmake#L4-L55), which is typically necessary for compiling `make`-based programs that depend on Geant4. + +## Datasets {#geant4-datasets} + +All of [the Geant4 datasets provided by CERN](https://geant4.web.cern.ch/support/download) are available through the `geant4.data` attrset. + +### Setup hook {#geant4-datasets-hook} + +The hook provided by the packages in `geant4.data` will set an appropriate environment variable in the form of `G4[...]DATA`. For example, for the `G4RadioactiveDecay` dataset, the `G4RADIOACTIVEDATA` environment variable is set to the value expected by Geant4. diff --git a/doc/packages/index.md b/doc/packages/index.md index c5aa7dbfa0ee..89d7e477e76f 100644 --- a/doc/packages/index.md +++ b/doc/packages/index.md @@ -12,10 +12,12 @@ emacs.section.md firefox.section.md fish.section.md fuse.section.md +geant4.section.md ibus.section.md kakoune.section.md krita.section.md linux.section.md +lhapdf.section.md locales.section.md etc-files.section.md nginx.section.md diff --git a/doc/packages/lhapdf.section.md b/doc/packages/lhapdf.section.md new file mode 100644 index 000000000000..af07d4edd42a --- /dev/null +++ b/doc/packages/lhapdf.section.md @@ -0,0 +1,11 @@ +# LHAPDF {#lhapdf} + +[LHAPDF](https://lhapdf.hepforge.org/) is a tool for evaluating parton distribution functions (PDFs) in high-energy physics. LHAPDF is available in the `lhapdf` package. + +## PDF sets {#lhapdf-sets} + +All of [the PDF sets made available by the LHAPDF project](https://lhapdf.hepforge.org/pdfsets.html) are available through the `lhapdf.pdf_sets` attrset. + +### Setup hook {#lhapdf-sets-hook} + +Each package provided in the `lhapdf.pdf_sets` attrset contains a setup hook which adds itself to [the `LHAPDF_DATA_PATH` environment variable](https://lhapdf.hepforge.org/#sets). diff --git a/doc/packages/linux.section.md b/doc/packages/linux.section.md index 90d14772134b..5c36c593ca74 100644 --- a/doc/packages/linux.section.md +++ b/doc/packages/linux.section.md @@ -52,7 +52,7 @@ pkgs.linuxPackages_custom { version = "6.1.55"; src = pkgs.fetchurl { url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz"; - hash = "sha256:1h0mzx52q9pvdv7rhnvb8g68i7bnlc9rf8gy9qn4alsxq4g28zm8"; + hash = "sha256-qH4kHsFdU0UsTv4hlxOjdp2IzENrW5jPbvsmLEr/FcA="; }; configfile = ./path_to_config_file; } @@ -67,7 +67,7 @@ pkgs.linuxPackages_custom { modDirVersion = "6.1.55"; src = pkgs.fetchurl { url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${modDirVersion}.tar.xz"; - hash = "sha256:1h0mzx52q9pvdv7rhnvb8g68i7bnlc9rf8gy9qn4alsxq4g28zm8"; + hash = "sha256-qH4kHsFdU0UsTv4hlxOjdp2IzENrW5jPbvsmLEr/FcA="; }; configfile = ./path_to_config_file; } diff --git a/doc/stdenv/multiple-output.chapter.md b/doc/stdenv/multiple-output.chapter.md index 5e86d2aa3d56..09fdba01c44a 100644 --- a/doc/stdenv/multiple-output.chapter.md +++ b/doc/stdenv/multiple-output.chapter.md @@ -21,7 +21,7 @@ In the Nix language the individual outputs can be reached explicitly as attribut When a multiple-output derivation gets into a build input of another derivation, the `dev` output is added if it exists, otherwise the first output is added. In addition to that, `propagatedBuildOutputs` of that package which by default contain `$outputBin` and `$outputLib` are also added. (See [](#multiple-output-file-type-groups).) -In some cases it may be desirable to combine different outputs under a single store path. A function `symlinkJoin` can be used to do this. (Note that it may negate some closure size benefits of using a multiple-output package.) +In some cases it may be desirable to combine different outputs under a single store path. The `symlinkJoin` builder can be used to do this. (See [](#trivial-builder-symlinkJoin)). Note that this may negate some closure size benefits of using a multiple-output package. ## Writing a split derivation {#sec-multiple-outputs-} diff --git a/doc/stdenv/passthru.chapter.md b/doc/stdenv/passthru.chapter.md index 142b978d5880..0c0b03fd0dc2 100644 --- a/doc/stdenv/passthru.chapter.md +++ b/doc/stdenv/passthru.chapter.md @@ -79,7 +79,7 @@ Besides tests provided by upstream, that you run in the [`checkPhase`](#ssec-che - They access the package as consumers would, independently from the environment in which it was built - They can be run and debugged without rebuilding the package, which is useful if that takes a long time -- They don't add overhead to each build, as opposed checks added to the [`distPhase`](#ssec-distribution-phase), such as [`versionCheckHook`](#versioncheckhook). +- They don't add overhead to each build, as opposed checks added to the [`installCheckPhase`](#ssec-installCheck-phase), such as [`versionCheckHook`](#versioncheckhook). It is also possible to use `passthru.tests` to test the version with [`testVersion`](#tester-testVersion), but since that is pretty trivial and recommended thing to do, we recommend using [`versionCheckHook`](#versioncheckhook) for that, which has the following advantages over `passthru.tests`: diff --git a/doc/stdenv/platform-notes.chapter.md b/doc/stdenv/platform-notes.chapter.md index 409c9f2e7b2e..9b0fdd149f9a 100644 --- a/doc/stdenv/platform-notes.chapter.md +++ b/doc/stdenv/platform-notes.chapter.md @@ -22,7 +22,7 @@ Some common issues when packaging software for Darwin: stdenv.mkDerivation { name = "libfoo-1.2.3"; # ... - makeFlags = lib.optional stdenv.isDarwin "LDFLAGS=-Wl,-install_name,$(out)/lib/libfoo.dylib"; + makeFlags = lib.optional stdenv.hostPlatform.isDarwin "LDFLAGS=-Wl,-install_name,$(out)/lib/libfoo.dylib"; } ``` diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 35330305f189..1c6391472735 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -518,8 +518,10 @@ There are a number of variables that control what phases are executed and in wha Specifies the phases. You can change the order in which phases are executed, or add new phases, by setting this variable. If it’s not set, the default value is used, which is `$prePhases unpackPhase patchPhase $preConfigurePhases configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase installCheckPhase $preDistPhases distPhase $postPhases`. +The elements of `phases` must not contain spaces. If `phases` is specified as a Nix Language attribute, it should be specified as lists instead of strings. The same rules apply to the `*Phases` variables. + It is discouraged to set this variable, as it is easy to miss some important functionality hidden in some of the less obviously needed phases (like `fixupPhase` which patches the shebang of scripts). -Usually, if you just want to add a few phases, it’s more convenient to set one of the variables below (such as `preInstallPhases`). +Usually, if you just want to add a few phases, it’s more convenient to set one of the `*Phases` variables below. ##### `prePhases` {#var-stdenv-prePhases} @@ -580,7 +582,7 @@ After unpacking all of `src` and `srcs`, if neither of `sourceRoot` and `setSour If `unpackPhase` produces multiple source directories, you should set `sourceRoot` to the name of the intended directory. You can also set `sourceRoot = ".";` if you want to control it yourself in a later phase. -For example, if your want your build to start in a sub-directory inside your sources, and you are using `fetchzip`-derived `src` (like `fetchFromGitHub` or similar), you need to set `sourceRoot = "${src.name}/my-sub-directory"`. +For example, if you want your build to start in a sub-directory inside your sources, and you are using `fetchzip`-derived `src` (like `fetchFromGitHub` or similar), you need to set `sourceRoot = "${src.name}/my-sub-directory"`. ##### `setSourceRoot` {#var-stdenv-setSourceRoot} @@ -1136,6 +1138,12 @@ Example removing all references to the compiler in the output: } ``` +### `runHook` \ {#fun-runHook} + +Execute \ and the values in the array associated with it. The array's name is determined by removing `Hook` from the end of \ and appending `Hooks`. + +For example, `runHook postHook` would run the hook `postHook` and all of the values contained in the `postHooks` array, if it exists. + ### `substitute` \ \ \ {#fun-substitute} Performs string substitution on the contents of \, writing the result to \. The substitutions in \ are of the following form: diff --git a/flake.nix b/flake.nix index bb7d0d5d4de3..950eb2b5c4d1 100644 --- a/flake.nix +++ b/flake.nix @@ -16,10 +16,44 @@ }); in { + /** + `nixpkgs.lib` is a combination of the [Nixpkgs library](https://nixos.org/manual/nixpkgs/unstable/#id-1.4), and other attributes + that are _not_ part of the Nixpkgs library, but part of the Nixpkgs flake: + + - `lib.nixosSystem` for creating a NixOS system configuration + + - `lib.nixos` for other NixOS-provided functionality, such as [`runTest`](https://nixos.org/manual/nixos/unstable/#sec-call-nixos-test-outside-nixos) + */ lib = lib.extend (final: prev: { + /** + Other NixOS-provided functionality, such as [`runTest`](https://nixos.org/manual/nixos/unstable/#sec-call-nixos-test-outside-nixos). + See also `lib.nixosSystem`. + */ nixos = import ./nixos/lib { lib = final; }; + /** + Create a NixOS system configuration. + + Example: + + lib.nixosSystem { + modules = [ ./configuration.nix ]; + } + + Inputs: + + - `modules` (list of paths or inline modules): The NixOS modules to include in the system configuration. + + - `specialArgs` (attribute set): Extra arguments to pass to all modules, that are available in `imports` but can not be extended or overridden by the `modules`. + + - `modulesLocation` (path): A default location for modules that aren't passed by path, used for error messages. + + Legacy inputs: + + - `system`: Legacy alias for `nixpkgs.hostPlatform`, but this is already set in the generated `hardware-configuration.nix`, included by `configuration.nix`. + - `pkgs`: Legacy alias for `nixpkgs.pkgs`; use `nixpkgs.pkgs` and `nixosModules.readOnlyPkgs` instead. + */ nixosSystem = args: import ./nixos/lib/eval-config.nix ( { @@ -47,7 +81,7 @@ checks = forAllSystems (system: { tarball = jobs.${system}.tarball; # Exclude power64 due to "libressl is not available on the requested hostPlatform" with hostPlatform being power64 - } // lib.optionalAttrs (self.legacyPackages.${system}.stdenv.isLinux && !self.legacyPackages.${system}.targetPlatform.isPower64) { + } // lib.optionalAttrs (self.legacyPackages.${system}.stdenv.hostPlatform.isLinux && !self.legacyPackages.${system}.targetPlatform.isPower64) { # Test that ensures that the nixosSystem function can accept a lib argument # Note: prefer not to extend or modify `lib`, especially if you want to share reusable modules # alternatives include: `import` a file, or put a custom library in an option or in `_module.args.` @@ -64,7 +98,7 @@ boot.loader.grub.enable = false; fileSystems."/".device = "nodev"; # See https://search.nixos.org/options?show=system.stateVersion&query=stateversion - system.stateVersion = lib.versions.majorMinor lib.version; # DON'T do this in real configs! + system.stateVersion = lib.trivial.release; # DON'T do this in real configs! }) ]; }).config.system.build.toplevel; @@ -78,28 +112,56 @@ }; devShells = forAllSystems (system: { + /** A shell to get tooling for Nixpkgs development. See nixpkgs/shell.nix. */ default = import ./shell.nix { inherit system; }; }); - # The "legacy" in `legacyPackages` doesn't imply that the packages exposed - # through this attribute are "legacy" packages. Instead, `legacyPackages` - # is used here as a substitute attribute name for `packages`. The problem - # with `packages` is that it makes operations like `nix flake show - # nixpkgs` unusably slow due to the sheer number of packages the Nix CLI - # needs to evaluate. But when the Nix CLI sees a `legacyPackages` - # attribute it displays `omitted` instead of evaluating all packages, - # which keeps `nix flake show` on Nixpkgs reasonably fast, though less - # information rich. + /** + A nested structure of [packages](https://nix.dev/manual/nix/latest/glossary#package-attribute-set) and other values. + + The "legacy" in `legacyPackages` doesn't imply that the packages exposed + through this attribute are "legacy" packages. Instead, `legacyPackages` + is used here as a substitute attribute name for `packages`. The problem + with `packages` is that it makes operations like `nix flake show + nixpkgs` unusably slow due to the sheer number of packages the Nix CLI + needs to evaluate. But when the Nix CLI sees a `legacyPackages` + attribute it displays `omitted` instead of evaluating all packages, + which keeps `nix flake show` on Nixpkgs reasonably fast, though less + information rich. + + The reason why finding the tree structure of `legacyPackages` is slow, + is that for each attribute in the tree, it is necessary to check whether + the attribute value is a package or a package set that needs further + evaluation. Evaluating the attribute value tends to require a significant + amount of computation, even considering lazy evaluation. + */ legacyPackages = forAllSystems (system: (import ./. { inherit system; }).extend (final: prev: { lib = prev.lib.extend libVersionInfoOverlay; }) ); + /** + Optional modules that can be imported into a NixOS configuration. + + Example: + + # flake.nix + outputs = { nixpkgs, ... }: { + nixosConfigurations = { + foo = nixpkgs.lib.nixosSystem { + modules = [ + ./foo/configuration.nix + nixpkgs.nixosModules.notDetected + ]; + }; + }; + }; + */ nixosModules = { notDetected = ./nixos/modules/installer/scan/not-detected.nix; - /* + /** Make the `nixpkgs.*` configuration read-only. Guarantees that `pkgs` is the way you initialize it. diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 8bb4ef972fd8..7b8feb4fe89b 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -5,7 +5,7 @@ let inherit (builtins) head length; - inherit (lib.trivial) isInOldestRelease mergeAttrs warn warnIf; + inherit (lib.trivial) oldestSupportedReleaseIsAtLeast mergeAttrs warn warnIf; inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName; inherit (lib.lists) foldr foldl' concatMap elemAt all partition groupBy take foldl; in @@ -2137,6 +2137,6 @@ rec { "lib.zip is a deprecated alias of lib.zipAttrsWith." zipAttrsWith; # DEPRECATED - cartesianProductOfSets = warnIf (isInOldestRelease 2405) + cartesianProductOfSets = warnIf (oldestSupportedReleaseIsAtLeast 2405) "lib.cartesianProductOfSets is a deprecated alias of lib.cartesianProduct." cartesianProduct; } diff --git a/lib/default.nix b/lib/default.nix index 0ff3a3980745..aff1df150f13 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -73,13 +73,14 @@ let inherit (self.trivial) id const pipe concat or and xor bitAnd bitOr bitXor bitNot boolToString mergeAttrs flip mapNullable inNixShell isFloat min max importJSON importTOML warn warnIf warnIfNot throwIf throwIfNot checkListOfEnum - info showWarnings nixpkgsVersion version isInOldestRelease + info showWarnings nixpkgsVersion version isInOldestRelease oldestSupportedReleaseIsAtLeast mod compare splitByAndCompare seq deepSeq lessThan add sub functionArgs setFunctionArgs isFunction toFunction mirrorFunctionArgs fromHexString toHexString toBaseDigits inPureEvalMode isBool isInt pathExists genericClosure readFile; inherit (self.fixedPoints) fix fix' converge extends composeExtensions - composeManyExtensions makeExtensible makeExtensibleWithCustomName; + composeManyExtensions makeExtensible makeExtensibleWithCustomName + toExtension; inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath getAttrFromPath attrVals attrNames attrValues getAttrs catAttrs filterAttrs filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs diff --git a/lib/fetchers.nix b/lib/fetchers.nix index e94c611299be..cd6d5d7916d3 100644 --- a/lib/fetchers.nix +++ b/lib/fetchers.nix @@ -1,6 +1,17 @@ # snippets that can be shared by multiple fetchers (pkgs/build-support) { lib }: -{ +let + commonH = hashTypes: rec { + hashNames = [ "hash" ] ++ hashTypes; + hashSet = lib.genAttrs hashNames (lib.const {}); + }; + + fakeH = { + hash = lib.fakeHash; + sha256 = lib.fakeSha256; + sha512 = lib.fakeSha512; + }; +in rec { proxyImpureEnvVars = [ # We borrow these environment variables from the caller to allow @@ -9,6 +20,170 @@ # by definition pure. "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy" "HTTP_PROXY" "HTTPS_PROXY" "FTP_PROXY" "ALL_PROXY" "NO_PROXY" + + # https proxies typically need to inject custom root CAs too + "NIX_SSL_CERT_FILE" ]; + /** + Converts an attrset containing one of `hash`, `sha256` or `sha512`, + into one containing `outputHash{,Algo}` as accepted by `mkDerivation`. + + An appropriate “fake hash” is substituted when the hash value is `""`, + as is the [convention for fetchers](#sec-pkgs-fetchers-updating-source-hashes-fakehash-method). + + All other attributes in the set remain as-is. + + # Example + + ```nix + normalizeHash { } { hash = ""; foo = "bar"; } + => + { + outputHash = lib.fakeHash; + outputHashAlgo = null; + foo = "bar"; + } + ``` + + ```nix + normalizeHash { } { sha256 = lib.fakeSha256; } + => + { + outputHash = lib.fakeSha256; + outputHashAlgo = "sha256"; + } + ``` + + ```nix + normalizeHash { } { sha512 = lib.fakeSha512; } + => + { + outputHash = lib.fakeSha512; + outputHashAlgo = "sha512"; + } + ``` + + # Type + ``` + normalizeHash :: { hashTypes :: List String, required :: Bool } -> AttrSet -> AttrSet + ``` + + # Arguments + + hashTypes + : the set of attribute names accepted as hash inputs, in addition to `hash` + + required + : whether to throw if no hash was present in the input; otherwise returns the original input, unmodified + */ + normalizeHash = { + hashTypes ? [ "sha256" ], + required ? true, + }: + let + inherit (lib) concatMapStringsSep head tail throwIf; + inherit (lib.attrsets) attrsToList intersectAttrs removeAttrs optionalAttrs; + + inherit (commonH hashTypes) hashNames hashSet; + in + args: + if args ? "outputHash" then + args + else + let + # The argument hash, as a {name, value} pair + h = + # All hashes passed in arguments (possibly 0 or >1) as a list of {name, value} pairs + let hashesAsNVPairs = attrsToList (intersectAttrs hashSet args); in + if hashesAsNVPairs == [] then + throwIf required "fetcher called without `hash`" null + else if tail hashesAsNVPairs != [] then + throw "fetcher called with mutually-incompatible arguments: ${concatMapStringsSep ", " (a: a.name) hashesAsNVPairs}" + else + head hashesAsNVPairs + ; + in + removeAttrs args hashNames // (optionalAttrs (h != null) { + outputHashAlgo = if h.name == "hash" then null else h.name; + outputHash = + if h.value == "" then + fakeH.${h.name} or (throw "no “fake hash” defined for ${h.name}") + else + h.value; + }) + ; + + /** + Wraps a function which accepts `outputHash{,Algo}` into one which accepts `hash` or `sha{256,512}` + + # Example + ```nix + withNormalizedHash { hashTypes = [ "sha256" "sha512" ]; } ( + { outputHash, outputHashAlgo, ... }: + ... + ) + ``` + is a function which accepts one of `hash`, `sha256`, or `sha512` (or the original's `outputHash` and `outputHashAlgo`). + + Its `functionArgs` metadata only lists `hash` as a parameter, optional iff. `outputHash` was an optional parameter of + the original function. `sha256`, `sha512`, `outputHash`, or `outputHashAlgo` are not mentioned in the `functionArgs` + metadata. + + # Type + ``` + withNormalizedHash :: { hashTypes :: List String } -> (AttrSet -> T) -> (AttrSet -> T) + ``` + + # Arguments + + hashTypes + : the set of attribute names accepted as hash inputs, in addition to `hash` + : they must correspond to a valid value for `outputHashAlgo`, currently one of: `md5`, `sha1`, `sha256`, or `sha512`. + + f + : the function to be wrapped + + ::: {.note} + In nixpkgs, `mkDerivation` rejects MD5 `outputHash`es, and SHA-1 is being deprecated. + + As such, there is no reason to add `md5` to `hashTypes`, and + `sha1` should only ever be included for backwards compatibility. + ::: + + # Output + + `withNormalizedHash { inherit hashTypes; } f` is functionally equivalent to + ```nix + args: f (normalizeHash { + inherit hashTypes; + required = !(lib.functionArgs f).outputHash; + } args) + ``` + + However, `withNormalizedHash` preserves `functionArgs` metadata insofar as possible, + and is implemented somewhat more efficiently. + */ + withNormalizedHash = { + hashTypes ? [ "sha256" ] + }: fetcher: + let + inherit (lib.attrsets) genAttrs intersectAttrs removeAttrs; + inherit (lib.trivial) const functionArgs setFunctionArgs; + + inherit (commonH hashTypes) hashSet; + fArgs = functionArgs fetcher; + + normalize = normalizeHash { + inherit hashTypes; + required = !fArgs.outputHash; + }; + in + # The o.g. fetcher must *only* accept outputHash and outputHashAlgo + assert fArgs ? outputHash && fArgs ? outputHashAlgo; + assert intersectAttrs fArgs hashSet == {}; + + setFunctionArgs + (args: fetcher (normalize args)) + (removeAttrs fArgs [ "outputHash" "outputHashAlgo" ] // { hash = fArgs.outputHash; }); } diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 2a31b44f27c1..ccc897755c11 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -63,7 +63,6 @@ rec { See [`extends`](#function-library-lib.fixedPoints.extends) for an example use case. There `self` is also often called `final`. - # Inputs `f` @@ -90,7 +89,12 @@ rec { ::: */ - fix = f: let x = f x; in x; + fix = + f: + let + x = f x; + in + x; /** A variant of `fix` that records the original recursive attribute set in the @@ -99,14 +103,20 @@ rec { This is useful in combination with the `extends` function to implement deep overriding. - # Inputs `f` : 1\. Function argument */ - fix' = f: let x = f x // { __unfix__ = f; }; in x; + fix' = + f: + let + x = f x // { + __unfix__ = f; + }; + in + x; /** Return the fixpoint that `f` converges to when called iteratively, starting @@ -117,7 +127,6 @@ rec { 0 ``` - # Inputs `f` @@ -134,13 +143,12 @@ rec { (a -> a) -> a -> a ``` */ - converge = f: x: + converge = + f: x: let x' = f x; in - if x' == x - then x - else converge f x'; + if x' == x then x else converge f x'; /** Extend a function using an overlay. @@ -149,7 +157,6 @@ rec { A fixed-point function is a function which is intended to be evaluated by passing the result of itself as the argument. This is possible due to Nix's lazy evaluation. - A fixed-point function returning an attribute set has the form ```nix @@ -257,7 +264,6 @@ rec { ``` ::: - # Inputs `overlay` @@ -299,8 +305,7 @@ rec { ::: */ extends = - overlay: - f: + overlay: f: # The result should be thought of as a function, the argument of that function is not an argument to `extends` itself ( final: @@ -311,63 +316,98 @@ rec { ); /** - Compose two extending functions of the type expected by 'extends' - into one where changes made in the first are available in the - 'super' of the second - - - # Inputs - - `f` - - : 1\. Function argument - - `g` - - : 2\. Function argument - - `final` - - : 3\. Function argument - - `prev` - - : 4\. Function argument + Compose two overlay functions and return a single overlay function that combines them. + For more details see: [composeManyExtensions](#function-library-lib.fixedPoints.composeManyExtensions). */ composeExtensions = f: g: final: prev: - let fApplied = f final prev; - prev' = prev // fApplied; - in fApplied // g final prev'; + let + fApplied = f final prev; + prev' = prev // fApplied; + in + fApplied // g final prev'; /** - Compose several extending functions of the type expected by 'extends' into - one where changes made in preceding functions are made available to - subsequent ones. + Composes a list of [`overlays`](#chap-overlays) and returns a single overlay function that combines them. + + :::{.note} + The result is produced by using the update operator `//`. + This means nested values of previous overlays are not merged recursively. + In other words, previously defined attributes are replaced, ignoring the previous value, unless referenced by the overlay; for example `final: prev: { foo = final.foo + 1; }`. + ::: + + # Inputs + + `extensions` + + : A list of overlay functions + :::{.note} + The order of the overlays in the list is important. + ::: + + : Each overlay function takes two arguments, by convention `final` and `prev`, and returns an attribute set. + - `final` is the result of the fixed-point function, with all overlays applied. + - `prev` is the result of the previous overlay function(s). + + # Type ``` - composeManyExtensions : [packageSet -> packageSet -> packageSet] -> packageSet -> packageSet -> packageSet - ^final ^prev ^overrides ^final ^prev ^overrides + # Pseudo code + let + # final prev + # ↓ ↓ + OverlayFn = { ... } -> { ... } -> { ... }; + in + composeManyExtensions :: ListOf OverlayFn -> OverlayFn ``` + + # Examples + :::{.example} + ## `lib.fixedPoints.composeManyExtensions` usage example + + ```nix + let + # The "original function" that is extended by the overlays. + # Note that it doesn't have prev: as argument since no overlay function precedes it. + original = final: { a = 1; }; + + # Each overlay function has 'final' and 'prev' as arguments. + overlayA = final: prev: { b = final.c; c = 3; }; + overlayB = final: prev: { c = 10; x = prev.c or 5; }; + + extensions = composeManyExtensions [ overlayA overlayB ]; + + # Caluculate the fixed point of all composed overlays. + fixedpoint = lib.fix (lib.extends extensions original ); + + in fixedpoint + => + { + a = 1; + b = 10; + c = 10; + x = 3; + } + ``` + ::: */ - composeManyExtensions = - lib.foldr (x: y: composeExtensions x y) (final: prev: {}); + composeManyExtensions = lib.foldr (x: y: composeExtensions x y) (final: prev: { }); /** Create an overridable, recursive attribute set. For example: ``` - nix-repl> obj = makeExtensible (self: { }) + nix-repl> obj = makeExtensible (final: { }) nix-repl> obj { __unfix__ = «lambda»; extend = «lambda»; } - nix-repl> obj = obj.extend (self: super: { foo = "foo"; }) + nix-repl> obj = obj.extend (final: prev: { foo = "foo"; }) nix-repl> obj { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; } - nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; }) + nix-repl> obj = obj.extend (final: prev: { foo = prev.foo + " + "; bar = "bar"; foobar = final.foo + final.bar; }) nix-repl> obj { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } @@ -379,7 +419,6 @@ rec { Same as `makeExtensible` but the name of the extending attribute is customized. - # Inputs `extenderName` @@ -390,8 +429,85 @@ rec { : 2\. Function argument */ - makeExtensibleWithCustomName = extenderName: rattrs: - fix' (self: (rattrs self) // { - ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); - }); + makeExtensibleWithCustomName = + extenderName: rattrs: + fix' ( + self: + (rattrs self) + // { + ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); + } + ); + + /** + Convert to an extending function (overlay). + + `toExtension` is the `toFunction` for extending functions (a.k.a. extensions or overlays). + It converts a non-function or a single-argument function to an extending function, + while returning a two-argument function as-is. + + That is, it takes a value of the shape `x`, `prev: x`, or `final: prev: x`, + and returns `final: prev: x`, assuming `x` is not a function. + + This function takes care of the input to `stdenv.mkDerivation`'s + `overrideAttrs` function. + It bridges the gap between `.overrideAttrs` + before and after the overlay-style support. + + # Inputs + + `f` + : The function or value to convert to an extending function. + + # Type + + ``` + toExtension :: + b' -> Any -> Any -> b' + or + toExtension :: + (a -> b') -> Any -> a -> b' + or + toExtension :: + (a -> a -> b) -> a -> a -> b + where b' = ! Callable + + Set a = b = b' = AttrSet & ! Callable to make toExtension return an extending function. + ``` + + # Examples + :::{.example} + ## `lib.fixedPoints.toExtension` usage example + + ```nix + fix (final: { a = 0; c = final.a; }) + => { a = 0; c = 0; }; + + fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; })) + => { a = 1; b = 2; c = 1; }; + + fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; })) + => { a = 1; b = 0; c = 1; }; + + fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1 })) (final: { a = 0; c = final.a; })) + => { a = 1; b = 0; c = 2; }; + ``` + ::: + */ + toExtension = + f: + if lib.isFunction f then + final: prev: + let + fPrev = f prev; + in + if lib.isFunction fPrev then + # f is (final: prev: { ... }) + f final prev + else + # f is (prev: { ... }) + fPrev + else + # f is not a function; probably { ... } + final: prev: f; } diff --git a/lib/licenses.nix b/lib/licenses.nix index ff68d1486437..fb7b6c2e837f 100644 --- a/lib/licenses.nix +++ b/lib/licenses.nix @@ -92,6 +92,11 @@ lib.mapAttrs mkLicense ({ free = false; }; + ampas = { + spdxId = "AMPAS"; + fullName = "Academy of Motion Picture Arts and Sciences BSD"; + }; + aom = { fullName = "Alliance for Open Media Patent License 1.0"; url = "https://aomedia.org/license/patent-license/"; @@ -404,6 +409,12 @@ lib.mapAttrs mkLicense ({ fullName = "CeCILL-C Free Software License Agreement"; }; + cockroachdb-community-license = { + fullName = "CockroachDB Community License Agreement"; + url = "https://www.cockroachlabs.com/cockroachdb-community-license/"; + free = false; + }; + cpal10 = { spdxId = "CPAL-1.0"; fullName = "Common Public Attribution License 1.0"; @@ -548,6 +559,13 @@ lib.mapAttrs mkLicense ({ redistributable = true; }; + fsl11Asl20 = { + fullName = "Functional Source License, Version 1.1, Apache 2.0 Future License"; + url = "https://fsl.software/FSL-1.1-Apache-2.0.template.md"; + free = false; + redistributable = true; + }; + ftl = { spdxId = "FTL"; fullName = "Freetype Project License"; @@ -652,7 +670,7 @@ lib.mapAttrs mkLicense ({ # Intel's license, seems free iasl = { spdxId = "Intel-ACPI"; - fullName = "iASL"; + fullName = "Intel ACPI Software License Agreement"; url = "https://old.calculate-linux.org/packages/licenses/iASL"; }; @@ -715,10 +733,9 @@ lib.mapAttrs mkLicense ({ fullName = "ISC License"; }; - # Proprietary binaries; free to redistribute without modification. databricks = { - fullName = "Databricks Proprietary License"; - url = "https://pypi.org/project/databricks-connect"; + fullName = "Databricks License"; + url = "https://www.databricks.com/legal/db-license"; free = false; }; @@ -872,7 +889,7 @@ lib.mapAttrs mkLicense ({ spdxId = "MIT"; fullName = "MIT License"; }; - # https://spdx.org/licenses/MIT-feh.html + mit-feh = { spdxId = "MIT-feh"; fullName = "feh License"; @@ -1080,7 +1097,7 @@ lib.mapAttrs mkLicense ({ }; purdueBsd = { - fullName = " Purdue BSD-Style License"; # also know as lsof license + fullName = "Purdue BSD-Style License"; # also known as lsof license url = "https://enterprise.dejacode.com/licenses/public/purdue-bsd"; }; diff --git a/lib/meta.nix b/lib/meta.nix index 57f3a46d0698..798e7e74918c 100644 --- a/lib/meta.nix +++ b/lib/meta.nix @@ -133,12 +133,17 @@ rec { mapDerivationAttrset = f: set: lib.mapAttrs (name: pkg: if lib.isDerivation pkg then (f pkg) else pkg) set; /** - Set the nix-env priority of the package. + The default priority of packages in Nix. See `defaultPriority` in [`src/nix/profile.cc`](https://github.com/NixOS/nix/blob/master/src/nix/profile.cc#L47). + */ + defaultPriority = 5; + + /** + Set the nix-env priority of the package. Note that higher values are lower priority, and vice versa. # Inputs `priority` - : 1\. Function argument + : 1\. The priority to set. `drv` : 2\. Function argument @@ -159,8 +164,7 @@ rec { lowPrio = setPrio 10; /** - Apply lowPrio to an attrset with derivations - + Apply lowPrio to an attrset with derivations. # Inputs @@ -184,8 +188,7 @@ rec { hiPrio = setPrio (-10); /** - Apply hiPrio to an attrset with derivations - + Apply hiPrio to an attrset with derivations. # Inputs diff --git a/lib/modules.nix b/lib/modules.nix index b9e9ca1e5d78..855ffaf25ed8 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -23,7 +23,7 @@ let isAttrs isBool isFunction - isInOldestRelease + oldestSupportedReleaseIsAtLeast isList isString length @@ -354,12 +354,7 @@ let else if m._type == "if" || m._type == "override" then loadModule args fallbackFile fallbackKey { config = m; } else - throw ( - "Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}" - + optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}." - + optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice." - # Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line. - ) + throw (messages.not_a_module { inherit fallbackFile; value = m; _type = m._type; expectedClass = class; }) else if isList m then let defs = [{ file = fallbackFile; value = m; }]; in throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}" @@ -861,7 +856,7 @@ let else # (nixos-option detects this specific error message and gives it special # handling. If changed here, please change it there too.) - throw "The option `${showOption loc}' is used but not defined."; + throw "The option `${showOption loc}' was accessed but has no value defined. Try setting the option."; isDefined = defsFinal != []; @@ -1035,7 +1030,7 @@ let mkForce = mkOverride 50; mkVMOverride = mkOverride 10; # used by ‘nixos-rebuild build-vm’ - defaultPriority = warnIf (isInOldestRelease 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority; + defaultPriority = warnIf (oldestSupportedReleaseIsAtLeast 2305) "lib.modules.defaultPriority is deprecated, please use lib.modules.defaultOverridePriority instead." defaultOverridePriority; mkFixStrictness = warn "lib.mkFixStrictness has no effect and will be removed. It returns its argument unmodified, so you can just remove any calls." id; @@ -1151,8 +1146,8 @@ let }: doRename { inherit from to; visible = false; - warn = isInOldestRelease sinceRelease; - use = warnIf (isInOldestRelease sinceRelease) + warn = oldestSupportedReleaseIsAtLeast sinceRelease; + use = warnIf (oldestSupportedReleaseIsAtLeast sinceRelease) "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'."; }; @@ -1366,6 +1361,58 @@ let ]); }; + /** + `importApply file arg :: Path -> a -> Module`, where `import file :: a -> Module` + + `importApply` imports a Nix expression file much like the module system would, + after passing an extra positional argument to the function in the file. + + This function should be used when declaring a module in a file that refers to + values from a different scope, such as that in a flake. + + It solves the problems of alternative solutions: + + - While `importApply file arg` is _mostly_ equivalent to + `import file arg`, the latter returns a module without a location, + as `import` only returns the contained expression. This leads to worse + error messages. + + - Using `specialArgs` to provide arguments to all modules. This effectively + creates an incomplete module, and requires the user of the module to + manually pass the `specialArgs` to the configuration, which is error-prone, + verbose, and unnecessary. + + The nix file must contain a function that returns a module. + A module may itself be a function, so the file is often a function with two + positional arguments instead of one. See the example below. + + This function does not add support for deduplication and `disabledModules`, + although that could be achieved by wrapping the returned module and setting + the `_key` module attribute. + The reason for this omission is that the file path is not guaranteed to be + a unique identifier for the module, as two instances of the module may + reference different `arg`s in their closures. + + Example + + # lib.nix + imports = [ + (lib.modules.importApply ./module.nix { bar = bar; }) + ]; + + # module.nix + { bar }: + { lib, config, ... }: + { + options = ...; + config = ... bar ...; + } + + */ + importApply = + modulePath: staticArg: + lib.setDefaultModuleLocation modulePath (import modulePath staticArg); + /* Use this function to import a JSON file as NixOS configuration. modules.importJSON :: path -> attrs @@ -1398,6 +1445,110 @@ let collectModules = collectModules null; }; + /** + Error messages produced by the module system. + + We factor these out to improve the flow when reading the code. + + Functions in `messages` that produce error messages are spelled in + lower_snake_case. This goes against the convention in order to make the + error message implementation more readable, and to visually distinguish + them from other functions in the module system. + */ + messages = let + inherit (lib.strings) concatMapStringsSep escapeNixString trim; + /** "" or ", in file FOO" */ + into_fallback_file_maybe = file: + optionalString + (file != null && file != unknownModule) + ", while trying to load a module into ${toString file}"; + + /** Format text with one line break between each list item. */ + lines = concatMapStringsSep "\n" trim; + + /** Format text with two line break between each list item. */ + paragraphs = concatMapStringsSep "\n\n" trim; + + /** + ``` + optionalMatch + { foo = "Foo result"; + bar = "Bar result"; + } "foo" + == [ "Foo result" ] + + optionalMatch { foo = "Foo"; } "baz" == [ ] + + optionalMatch { foo = "Foo"; } true == [ ] + ``` + */ + optionalMatch = cases: value: + if isString value && cases?${value} + then [ cases.${value} ] + else []; + + # esc = builtins.fromJSON "\"\\u001b\""; + esc = builtins.fromJSON "\"\\u001b\""; + # Bold purple for warnings + warn = s: "${esc}[1;35m${s}${esc}[0m"; + # Bold green for suggestions + good = s: "${esc}[1;32m${s}${esc}[0m"; + # Bold, default color for code + code = s: "${esc}[1m${s}${esc}[0m"; + + in { + + /** When load a value with a (wrong) _type as a module */ + not_a_module = { fallbackFile, value, _type, expectedClass ? null }: + paragraphs ( + [ '' + Expected a module, but found a value of type ${warn (escapeNixString _type)}${into_fallback_file_maybe fallbackFile}. + A module is typically loaded by adding it the ${code "imports = [ ... ];"} attribute of an existing module, or in the ${code "modules = [ ... ];"} argument of various functions. + Please make sure that each of the list items is a module, and not a different kind of value. + '' + ] + ++ (optionalMatch + { + "configuration" = trim '' + If you really mean to import this configuration, instead please only import the modules that make up the configuration. + You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules. + While loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice. + ''; + # ^^ Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line. + + "flake" = lines + ([(trim '' + Perhaps you forgot to select an attribute name? + Instead of, for example, + ${warn "inputs.someflake"} + you need to write something like + ${warn "inputs.someflake"}${ + if expectedClass == null + then good ".modules.someApp.default" + else good ".modules.${expectedClass}.default" + + } + '')] + ++ optionalMatch + { # We'll no more than 5 custom suggestions here. + # Please switch to `.modules.${class}` in your Module System application. + "nixos" = trim '' + or + ${warn "inputs.someflake"}${good ".nixosModules.default"} + ''; + "darwin" = trim '' + or + ${warn "inputs.someflake"}${good ".darwinModules.default"} + ''; + } + expectedClass + ); + } + _type + ) + ); + }; + in private // { @@ -1415,6 +1566,7 @@ private // filterOverrides' fixMergeModules fixupOptionType # should be private? + importApply importJSON importTOML mergeDefinitions diff --git a/lib/sources.nix b/lib/sources.nix index f61ea306aec5..62c4a214536b 100644 --- a/lib/sources.nix +++ b/lib/sources.nix @@ -256,15 +256,15 @@ let in { - pathType = lib.warnIf (lib.isInOldestRelease 2305) + pathType = lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305) "lib.sources.pathType has been moved to lib.filesystem.pathType." lib.filesystem.pathType; - pathIsDirectory = lib.warnIf (lib.isInOldestRelease 2305) + pathIsDirectory = lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305) "lib.sources.pathIsDirectory has been moved to lib.filesystem.pathIsDirectory." lib.filesystem.pathIsDirectory; - pathIsRegularFile = lib.warnIf (lib.isInOldestRelease 2305) + pathIsRegularFile = lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305) "lib.sources.pathIsRegularFile has been moved to lib.filesystem.pathIsRegularFile." lib.filesystem.pathIsRegularFile; diff --git a/lib/strings.nix b/lib/strings.nix index aafbdffaa7bc..d9a2d786ed28 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -408,7 +408,6 @@ rec { start ? false, end ? false, }: - s: let # Define our own whitespace character class instead of using # `[:space:]`, which is not well-defined. @@ -425,12 +424,14 @@ rec { "(.*[^${chars}])[${chars}]*" else "(.*)"; - + in + s: + let # If the string was empty or entirely whitespace, # then the regex may not match and `res` will be `null`. res = match regex s; in - optionalString (res != null) (head res); + optionalString (res != null) (head res); /** Construct a Unix-style, colon-separated search path consisting of @@ -1026,7 +1027,8 @@ rec { replaceStrings (builtins.attrNames toEscape) (lib.mapAttrsToList (_: c: "%${fixedWidthString 2 "0" (lib.toHexString c)}") toEscape); /** - Quote `string` to be used safely within the Bourne shell. + Quote `string` to be used safely within the Bourne shell if it has any + special characters. # Inputs @@ -1051,10 +1053,17 @@ rec { ::: */ - escapeShellArg = arg: "'${replaceStrings ["'"] ["'\\''"] (toString arg)}'"; + escapeShellArg = arg: + let + string = toString arg; + in + if match "[[:alnum:],._+:@%/-]+" string == null + then "'${replaceStrings ["'"] ["'\\''"] string}'" + else string; /** - Quote all arguments to be safely passed to the Bourne shell. + Quote all arguments that have special characters to be safely passed to the + Bourne shell. # Inputs @@ -1073,7 +1082,7 @@ rec { ```nix escapeShellArgs ["one" "two three" "four'five"] - => "'one' 'two three' 'four'\\''five'" + => "one 'two three' 'four'\\''five'" ``` ::: @@ -2263,7 +2272,7 @@ rec { isCoercibleToString :: a -> bool ``` */ - isCoercibleToString = lib.warnIf (lib.isInOldestRelease 2305) + isCoercibleToString = lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2305) "lib.strings.isCoercibleToString is deprecated in favor of either isStringLike or isConvertibleWithToString. Only use the latter if it needs to return true for null, numbers, booleans and list of similarly coercibles." isConvertibleWithToString; diff --git a/lib/systems/architectures.nix b/lib/systems/architectures.nix index 9be8c80e3f11..df8ff438b17b 100644 --- a/lib/systems/architectures.nix +++ b/lib/systems/architectures.nix @@ -26,6 +26,8 @@ rec { cooperlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ]; tigerlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ]; alderlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma" ]; + sapphirerapids = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ]; + emeraldrapids = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ]; # x86_64 AMD btver1 = [ "sse3" "ssse3" "sse4_1" "sse4_2" ]; btver2 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" ]; @@ -73,6 +75,8 @@ rec { cascadelake = [ "cannonlake" ] ++ inferiors.cannonlake; cooperlake = [ "cascadelake" ] ++ inferiors.cascadelake; tigerlake = [ "icelake-server" ] ++ inferiors.icelake-server; + sapphirerapids = [ "tigerlake" ] ++ inferiors.tigerlake; + emeraldrapids = [ "sapphirerapids" ] ++ inferiors.sapphirerapids; # CX16 does not exist on alderlake, while it does on nearly all other intel CPUs alderlake = [ ]; diff --git a/lib/systems/default.nix b/lib/systems/default.nix index cee09791bf54..a6ceef2cc3a1 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -277,33 +277,17 @@ let let selectEmulator = pkgs: let - qemu-user = pkgs.qemu.override { - smartcardSupport = false; - spiceSupport = false; - openGLSupport = false; - virglSupport = false; - vncSupport = false; - gtkSupport = false; - sdlSupport = false; - alsaSupport = false; - pulseSupport = false; - pipewireSupport = false; - jackSupport = false; - smbdSupport = false; - seccompSupport = false; - tpmSupport = false; - capstoneSupport = false; - enableDocs = false; - hostCpuTargets = [ "${final.qemuArch}-linux-user" ]; - }; wine = (pkgs.winePackagesFor "wine${toString final.parsed.cpu.bits}").minimal; in + # Note: we guarantee that the return value is either `null` or a path + # to an emulator program. That is, if an emulator requires additional + # arguments, a wrapper should be used. if pkgs.stdenv.hostPlatform.canExecute final - then "${pkgs.runtimeShell} -c '\"$@\"' --" + then "${pkgs.execline}/bin/exec" else if final.isWindows then "${wine}/bin/wine${optionalString (final.parsed.cpu.bits == 64) "64"}" else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux && final.qemuArch != null - then "${qemu-user}/bin/qemu-${final.qemuArch}" + then "${pkgs.qemu-user}/bin/qemu-${final.qemuArch}" else if final.isWasi then "${pkgs.wasmtime}/bin/wasmtime" else if final.isMmix @@ -312,6 +296,10 @@ let in { emulatorAvailable = pkgs: (selectEmulator pkgs) != null; + # whether final.emulator pkgs.pkgsStatic works + staticEmulatorAvailable = pkgs: final.emulatorAvailable pkgs + && (final.isLinux || final.isWasi || final.isMmix); + emulator = pkgs: if (final.emulatorAvailable pkgs) then selectEmulator pkgs @@ -376,12 +364,22 @@ let "armv7l" = "armv7"; "armv6l" = "arm"; "armv5tel" = "armv5te"; + "riscv32" = "riscv32gc"; "riscv64" = "riscv64gc"; }.${cpu.name} or cpu.name; vendor_ = final.rust.platform.vendor; # TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL. - in args.rust.rustcTarget or args.rustc.config - or "${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi.name}"}"; + in + args.rust.rustcTarget or + args.rustc.config or ( + # Rust uses `wasm32-wasip?` rather than `wasm32-unknown-wasi`. + # We cannot know which subversion does the user want, and + # currently use WASI 0.1 as default for compatibility. Custom + # users can set `rust.rustcTarget` to override it. + if final.isWasi + then "${cpu_}-wasip1" + else "${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi.name}"}" + ); # The name of the rust target if it is standard, or the json file # containing the custom target spec. diff --git a/lib/systems/doubles.nix b/lib/systems/doubles.nix index b4cd5acfcc5b..6939e9a40c2d 100644 --- a/lib/systems/doubles.nix +++ b/lib/systems/doubles.nix @@ -69,6 +69,7 @@ in { arm = filterDoubles predicates.isAarch32; armv7 = filterDoubles predicates.isArmv7; + aarch = filterDoubles predicates.isAarch; aarch64 = filterDoubles predicates.isAarch64; x86 = filterDoubles predicates.isx86; i686 = filterDoubles predicates.isi686; @@ -114,6 +115,4 @@ in { genode = filterDoubles predicates.isGenode; embedded = filterDoubles predicates.isNone; - - mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "armv7a-linux" "aarch64-linux" "powerpc64-linux" "powerpc64le-linux" "aarch64-darwin" "riscv64-linux"]; } diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix index 971f6b87364b..5059f6e0c838 100644 --- a/lib/systems/examples.nix +++ b/lib/systems/examples.nix @@ -256,7 +256,7 @@ rec { iphone64 = { config = "aarch64-apple-ios"; # config = "aarch64-apple-darwin14"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneOS"; useiOSPrebuilt = true; @@ -265,7 +265,7 @@ rec { iphone32 = { config = "armv7a-apple-ios"; # config = "arm-apple-darwin10"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneOS"; useiOSPrebuilt = true; @@ -274,7 +274,7 @@ rec { iphone64-simulator = { config = "x86_64-apple-ios"; # config = "x86_64-apple-darwin14"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneSimulator"; darwinPlatform = "ios-simulator"; @@ -284,7 +284,7 @@ rec { iphone32-simulator = { config = "i686-apple-ios"; # config = "i386-apple-darwin11"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneSimulator"; darwinPlatform = "ios-simulator"; diff --git a/lib/systems/platforms.nix b/lib/systems/platforms.nix index 403ffc028f0b..873c3c7fc7f5 100644 --- a/lib/systems/platforms.nix +++ b/lib/systems/platforms.nix @@ -201,8 +201,9 @@ rec { target = "zImage"; }; gcc = { - arch = "armv6"; - fpu = "vfp"; + # https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications + arch = "armv6kz"; + fpu = "vfpv2"; }; }; diff --git a/lib/tests/fetchers.nix b/lib/tests/fetchers.nix new file mode 100644 index 000000000000..c36da35673a7 --- /dev/null +++ b/lib/tests/fetchers.nix @@ -0,0 +1,165 @@ +let + lib = import ./..; + + inherit (lib) + fakeHash + fakeSha256 + fakeSha512 + flip + functionArgs + runTests + ; + inherit (lib.fetchers) normalizeHash withNormalizedHash; + + testingThrow = expr: { + expr = with builtins; tryEval (seq expr "didn't throw"); + expected = { + success = false; + value = false; + }; + }; + + # hashes of empty + sri256 = "sha256-d6xi4mKdjkX2JFicDIv5niSzpyI0m/Hnm8GGAIU04kY="; + sri512 = "sha512-AXFyVo7jiZ5we10fxZ5E9qfPjSfqkizY2apCzORKFVYZaNhCIVbooY+J4cYST00ztLf0EjivIBPPdtIYFUMfzQ=="; + + unionOfDisjoints = lib.foldl lib.attrsets.unionOfDisjoint { }; + + genTests = n: f: { + "test${n}AlreadyNormalized" = { + expr = f { } { + outputHash = ""; + outputHashAlgo = "md42"; + }; + expected = { + outputHash = ""; + outputHashAlgo = "md42"; + }; + }; + + "test${n}EmptySha256" = { + expr = f { } { sha256 = ""; }; + expected = { + outputHash = fakeSha256; + outputHashAlgo = "sha256"; + }; + }; + + "test${n}EmptySha512" = { + expr = f { hashTypes = [ "sha512" ]; } { sha512 = ""; }; + expected = { + outputHash = fakeSha512; + outputHashAlgo = "sha512"; + }; + }; + + "test${n}EmptyHash" = { + expr = f { } { hash = ""; }; + expected = { + outputHash = fakeHash; + outputHashAlgo = null; + }; + }; + + "test${n}Sri256" = { + expr = f { } { hash = sri256; }; + expected = { + outputHash = sri256; + outputHashAlgo = null; + }; + }; + + "test${n}Sri512" = { + expr = f { } { hash = sri512; }; + expected = { + outputHash = sri512; + outputHashAlgo = null; + }; + }; + + "test${n}PreservesAttrs" = { + expr = f { } { + hash = "aaaa"; + destination = "Earth"; + }; + expected = { + outputHash = "aaaa"; + outputHashAlgo = null; + destination = "Earth"; + }; + }; + + "test${n}RejectsSha1ByDefault" = testingThrow (f { } { sha1 = ""; }); + "test${n}RejectsSha512ByDefault" = testingThrow (f { } { sha512 = ""; }); + + "test${n}ThrowsOnMissing" = testingThrow (f { } { gibi = false; }); + }; +in +runTests (unionOfDisjoints [ + (genTests "NormalizeHash" normalizeHash) + (genTests "WithNormalized" ( + flip withNormalizedHash ({ outputHash, outputHashAlgo, ... }@args: args) + )) + { + testNormalizeNotRequiredEquivalent = { + expr = normalizeHash { required = false; } { + hash = ""; + prof = "shadoko"; + }; + expected = normalizeHash { } { + hash = ""; + prof = "shadoko"; + }; + }; + + testNormalizeNotRequiredPassthru = { + expr = normalizeHash { required = false; } { "ga bu" = "zo meu"; }; + expected."ga bu" = "zo meu"; + }; + + testOptionalArg = { + expr = withNormalizedHash { } ( + { + outputHash ? "", + outputHashAlgo ? null, + ... + }@args: + args + ) { author = "Jacques Rouxel"; }; + expected.author = "Jacques Rouxel"; + }; + + testOptionalArgMetadata = { + expr = functionArgs ( + withNormalizedHash { } ( + { + outputHash ? "", + outputHashAlgo ? null, + }: + { } + ) + ); + expected.hash = true; + }; + + testPreservesArgsMetadata = { + expr = functionArgs ( + withNormalizedHash { } ( + { + outputHash, + outputHashAlgo, + pumping ? true, + }: + { } + ) + ); + expected = { + hash = false; + pumping = true; + }; + }; + + testRejectsMissingHashArg = testingThrow (withNormalizedHash { } ({ outputHashAlgo }: { })); + testRejectsMissingAlgoArg = testingThrow (withNormalizedHash { } ({ outputHash }: { })); + } +]) diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index d59f5586b82d..116d86cdfb3f 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -45,6 +45,7 @@ let const escapeXML evalModules + extends filter fix fold @@ -102,6 +103,7 @@ let take testAllTrue toBaseDigits + toExtension toHexString fromHexString toInt @@ -233,11 +235,6 @@ runTests { ]; }; - testFix = { - expr = fix (x: {a = if x ? a then "a" else "b";}); - expected = {a = "a";}; - }; - testComposeExtensions = { expr = let obj = makeExtensible (self: { foo = self.bar; }); f = self: super: { bar = false; baz = true; }; @@ -470,6 +467,26 @@ runTests { expected = [ "A" "B" ]; }; + testEscapeShellArg = { + expr = strings.escapeShellArg "esc'ape\nme"; + expected = "'esc'\\''ape\nme'"; + }; + + testEscapeShellArgEmpty = { + expr = strings.escapeShellArg ""; + expected = "''"; + }; + + testEscapeShellArgs = { + expr = strings.escapeShellArgs ["one" "two three" "four'five"]; + expected = "one 'two three' 'four'\\''five'"; + }; + + testEscapeShellArgsUnicode = { + expr = strings.escapeShellArg "á"; + expected = "'á'"; + }; + testSplitStringsDerivation = { expr = take 3 (strings.splitString "/" (derivation { name = "name"; @@ -569,12 +586,12 @@ runTests { ''; expected = '' STRing01='just a '\'''string'\'''' - declare -a _array_=('with' 'more strings') + declare -a _array_=(with 'more strings') declare -A assoc=(['with some']='strings possibly newlines ') - drv='/drv' - path='/path' + drv=/drv + path=/path stringable='hello toString' ''; }; @@ -1217,6 +1234,28 @@ runTests { attrsToList { someFunc= a: a + 1;} ); +# FIXED-POINTS + + testFix = { + expr = fix (x: {a = if x ? a then "a" else "b";}); + expected = {a = "a";}; + }; + + testToExtension = { + expr = [ + (fix (final: { a = 0; c = final.a; })) + (fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; }))) + (fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; }))) + (fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1; })) (final: { a = 0; c = final.a; }))) + ]; + expected = [ + { a = 0; c = 0; } + { a = 1; b = 2; c = 1; } + { a = 1; b = 0; c = 1; } + { a = 1; b = 0; c = 2; } + ]; + }; + # GENERATORS # these tests assume attributes are converted to lists # in alphabetical order @@ -1754,7 +1793,7 @@ runTests { verbose = true; }; - expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'"; + expected = "-X PUT --data '{\"id\":0}' --retry 3 --url https://example.com/foo --url https://example.com/bar --verbose"; }; testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName { diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 3a23766a17f5..ad2ea44c361a 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -247,6 +247,14 @@ checkConfigOutput '^true$' "$@" ./define-enable.nix ./define-attrsOfSub-if-foo-e checkConfigOutput '^true$' "$@" ./define-enable.nix ./define-attrsOfSub-foo-if-enable.nix checkConfigOutput '^true$' "$@" ./define-enable.nix ./define-attrsOfSub-foo-enable-if.nix +# Check importApply +checkConfigOutput '"abc"' config.value ./importApply.nix +# importApply does not set a key. +# Disabling the function file is not sufficient, because importApply can't reasonably assume that the key is unique. +# e.g. user may call it multiple times with different arguments and expect each of the module to apply. +# While this is excusable for the disabledModules aspect, it is not for the deduplication of modules. +checkConfigOutput '"abc"' config.value ./importApply-disabling.nix + # Check disabledModules with config definitions and option declarations. set -- config.enable ./define-enable.nix ./declare-enable.nix checkConfigOutput '^true$' "$@" @@ -286,6 +294,9 @@ checkConfigOutput '^"42"$' config.value ./declare-coerced-value.nix checkConfigOutput '^"24"$' config.value ./declare-coerced-value.nix ./define-value-string.nix checkConfigError 'A definition for option .* is not.*string or signed integer convertible to it.*. Definition values:\n\s*- In .*: \[ \]' config.value ./declare-coerced-value.nix ./define-value-list.nix +# Check coerced option merging. +checkConfigError 'The option .value. in .*/declare-coerced-value.nix. is already declared in .*/declare-coerced-value-no-default.nix.' config.value ./declare-coerced-value.nix ./declare-coerced-value-no-default.nix + # Check coerced value with unsound coercion checkConfigOutput '^12$' config.value ./declare-coerced-value-unsound.nix checkConfigError 'A definition for option .* is not of type .*. Definition values:\n\s*- In .*: "1000"' config.value ./declare-coerced-value-unsound.nix ./define-value-string-bigint.nix @@ -304,7 +315,7 @@ checkConfigOutput '^".*Hello.*"$' options.namedPackage.description ./declare-mkP checkConfigOutput '^"hello"$' config.pathPackage.pname ./declare-mkPackageOption.nix checkConfigOutput '^"pkgs\.hello\.override \{ stdenv = pkgs\.clangStdenv; \}"$' options.packageWithExample.example.text ./declare-mkPackageOption.nix checkConfigOutput '^".*Example extra description\..*"$' options.packageWithExtraDescription.description ./declare-mkPackageOption.nix -checkConfigError 'The option .undefinedPackage. is used but not defined' config.undefinedPackage ./declare-mkPackageOption.nix +checkConfigError 'The option .undefinedPackage. was accessed but has no value defined. Try setting the option.' config.undefinedPackage ./declare-mkPackageOption.nix checkConfigOutput '^null$' config.nullablePackage ./declare-mkPackageOption.nix checkConfigOutput '^"null or package"$' options.nullablePackageWithDefault.type.description ./declare-mkPackageOption.nix checkConfigOutput '^"myPkgs\.hello"$' options.packageWithPkgsText.defaultText.text ./declare-mkPackageOption.nix @@ -402,7 +413,7 @@ checkConfigOutput '^null$' config.foo ./freeform-attrsOf.nix ./freeform-str-dep- checkConfigOutput '^"24"$' config.foo ./freeform-attrsOf.nix ./freeform-str-dep-unstr.nix ./define-value-string.nix # Check whether an freeform-typed value can depend on a declared option, this can only work with lazyAttrsOf checkConfigError 'infinite recursion encountered' config.foo ./freeform-attrsOf.nix ./freeform-unstr-dep-str.nix -checkConfigError 'The option .* is used but not defined' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix +checkConfigError 'The option .* was accessed but has no value defined. Try setting the option.' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix checkConfigOutput '^"24"$' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix ./define-value-string.nix # submodules in freeformTypes should have their locations annotated checkConfigOutput '/freeform-submodules.nix"$' config.fooDeclarations.0 ./freeform-submodules.nix @@ -418,8 +429,8 @@ checkConfigOutput '^null$' config.value.l1.l2.foo ./types-anything/nested-attrs. checkConfigOutput '^null$' config.value.l1.l2.l3.foo ./types-anything/nested-attrs.nix # Attribute sets that are coercible to strings shouldn't be recursed into checkConfigOutput '^"foo"$' config.value.outPath ./types-anything/attrs-coercible.nix -# Multiple lists aren't concatenated together -checkConfigError 'The option .* has conflicting definitions' config.value ./types-anything/lists.nix +# Multiple lists aren't concatenated together if their definitions are not equal +checkConfigError 'The option .* has conflicting definition values' config.value ./types-anything/lists.nix # Check that all equalizable atoms can be used as long as all definitions are equal checkConfigOutput '^0$' config.value.int ./types-anything/equal-atoms.nix checkConfigOutput '^false$' config.value.bool ./types-anything/equal-atoms.nix @@ -427,6 +438,7 @@ checkConfigOutput '^""$' config.value.string ./types-anything/equal-atoms.nix checkConfigOutput '^"/[^"]+"$' config.value.path ./types-anything/equal-atoms.nix checkConfigOutput '^null$' config.value.null ./types-anything/equal-atoms.nix checkConfigOutput '^0.1$' config.value.float ./types-anything/equal-atoms.nix +checkConfigOutput '^\[1,"a",{"x":null}\]$' config.value.list ./types-anything/equal-atoms.nix # Functions can't be merged together checkConfigError "The option .value.multiple-lambdas.. has conflicting option types" config.applied.multiple-lambdas ./types-anything/functions.nix checkConfigOutput '^true$' config.valueIsFunction.single-lambda ./types-anything/functions.nix @@ -461,8 +473,8 @@ checkConfigOutput "{}" config.attrs.a ./emptyValues.nix checkConfigOutput "null" config.null.a ./emptyValues.nix checkConfigOutput "{}" config.submodule.a ./emptyValues.nix # These types don't have empty values -checkConfigError 'The option .int.a. is used but not defined' config.int.a ./emptyValues.nix -checkConfigError 'The option .nonEmptyList.a. is used but not defined' config.nonEmptyList.a ./emptyValues.nix +checkConfigError 'The option .int.a. was accessed but has no value defined. Try setting the option.' config.int.a ./emptyValues.nix +checkConfigError 'The option .nonEmptyList.a. was accessed but has no value defined. Try setting the option.' config.nonEmptyList.a ./emptyValues.nix # types.unique # requires a single definition @@ -522,9 +534,10 @@ checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nix checkConfigError 'A submoduleWith option is declared multiple times with conflicting class values "darwin" and "nixos".' config.sub.mergeFail.config ./class-check.nix # _type check -checkConfigError 'Could not load a value as a module, because it is of type "flake", in file .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix -checkConfigOutput '^true$' "$@" config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix -checkConfigError 'Could not load a value as a module, because it is of type "configuration", in file .*/import-configuration.nix.*please only import the modules that make up the configuration.*' config ./import-configuration.nix +checkConfigError 'Expected a module, but found a value of type .*"flake".*, while trying to load a module into .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix +checkConfigOutput '^true$' config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix +checkConfigError 'Expected a module, but found a value of type .*"configuration".*, while trying to load a module into .*/import-configuration.nix.' config ./import-configuration.nix +checkConfigError 'please only import the modules that make up the configuration' config ./import-configuration.nix # doRename works when `warnings` does not exist. checkConfigOutput '^1234$' config.c.d.e ./doRename-basic.nix @@ -542,21 +555,21 @@ checkConfigOutput '^"pear\\npear"$' config.twice.raw ./merge-module-with-key.nix # Declaration positions # Line should be present for direct options -checkConfigOutput '^10$' options.imported.line10.declarationPositions.0.line ./declaration-positions.nix -checkConfigOutput '/declaration-positions.nix"$' options.imported.line10.declarationPositions.0.file ./declaration-positions.nix +checkConfigOutput '^14$' options.imported.line14.declarationPositions.0.line ./declaration-positions.nix +checkConfigOutput '/declaration-positions.nix"$' options.imported.line14.declarationPositions.0.file ./declaration-positions.nix # Generated options may not have line numbers but they will at least get the # right file -checkConfigOutput '/declaration-positions.nix"$' options.generated.line18.declarationPositions.0.file ./declaration-positions.nix -checkConfigOutput '^null$' options.generated.line18.declarationPositions.0.line ./declaration-positions.nix +checkConfigOutput '/declaration-positions.nix"$' options.generated.line22.declarationPositions.0.file ./declaration-positions.nix +checkConfigOutput '^null$' options.generated.line22.declarationPositions.0.line ./declaration-positions.nix # Submodules don't break it -checkConfigOutput '^39$' config.submoduleLine34.submodDeclLine39.0.line ./declaration-positions.nix -checkConfigOutput '/declaration-positions.nix"$' config.submoduleLine34.submodDeclLine39.0.file ./declaration-positions.nix +checkConfigOutput '^45$' config.submoduleLine38.submodDeclLine45.0.line ./declaration-positions.nix +checkConfigOutput '/declaration-positions.nix"$' config.submoduleLine38.submodDeclLine45.0.file ./declaration-positions.nix # New options under freeform submodules get collected into the parent submodule # (consistent with .declarations behaviour, but weird; notably appears in system.build) -checkConfigOutput '^34|23$' options.submoduleLine34.declarationPositions.0.line ./declaration-positions.nix -checkConfigOutput '^34|23$' options.submoduleLine34.declarationPositions.1.line ./declaration-positions.nix +checkConfigOutput '^38|27$' options.submoduleLine38.declarationPositions.0.line ./declaration-positions.nix +checkConfigOutput '^38|27$' options.submoduleLine38.declarationPositions.1.line ./declaration-positions.nix # nested options work -checkConfigOutput '^30$' options.nested.nestedLine30.declarationPositions.0.line ./declaration-positions.nix +checkConfigOutput '^34$' options.nested.nestedLine34.declarationPositions.0.line ./declaration-positions.nix cat < 1 - then throw "The option `${showOption loc}' has conflicting definitions, in ${showFiles (getFiles defs)}." - else (listOf anything).merge; # This is the type of packages, only accept a single definition stringCoercibleSet = mergeOneOption; lambda = loc: defs: arg: anything.merge @@ -1035,7 +1029,7 @@ rec { getSubOptions = finalType.getSubOptions; getSubModules = finalType.getSubModules; substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); - typeMerge = t1: t2: null; + typeMerge = t: null; functor = (defaultFunctor name) // { wrapped = finalType; }; nestedTypes.coercedType = coercedType; nestedTypes.finalType = finalType; diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index a1f0e3e73117..8caa9a5de0fd 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -95,6 +95,11 @@ github = "0x120581f"; githubId = 130835755; }; + _0x3f = { + name = "0x3f"; + github = "0x3fiona"; + githubId = 178507884; + }; _0x4A6F = { email = "mail-maintainer@0x4A6F.dev"; matrix = "@0x4a6f:matrix.org"; @@ -238,6 +243,12 @@ github = "48cf"; githubId = 32851089; }; + _4ever2 = { + email = "eske@cs.au.dk"; + github = "4ever2"; + githubId = 3417013; + name = "Eske Nielsen"; + }; _6543 = { email = "6543@obermui.de"; github = "6543"; @@ -340,6 +351,12 @@ githubId = 22131756; name = "Aaqa Ishtyaq"; }; + aarnphm = { + email = "contact@aarnphm.xyz"; + github = "aarnphm"; + githubId = 29749331; + name = "Aaron Pham"; + }; aaronarinder = { email = "aaronarinder@gmail.com"; github = "aaronArinder"; @@ -651,6 +668,12 @@ githubId = 19290901; name = "Andrew Brooks"; }; + agilesteel = { + email = "agilesteel@gmail.com"; + github = "agilesteel"; + githubId = 1141462; + name = "Vladyslav Pekker"; + }; aherrmann = { email = "andreash87@gmx.ch"; github = "aherrmann"; @@ -731,6 +754,12 @@ githubId = 45179933; name = "Alex Jackson"; }; + ajgon = { + email = "igor@rzegocki.pl"; + github = "ajgon"; + githubId = 150545; + name = "Igor Rzegocki"; + }; ajgrf = { email = "a@ajgrf.com"; github = "ajgrf"; @@ -882,6 +911,18 @@ githubId = 217050; name = "Albert Chae"; }; + albertodvp = { + email = "alberto.fanton@protonmail.com"; + github = "albertodvp"; + githubId = 16022854; + matrix = "@albertodvp:matrix.org"; + name = "Alberto Fanton"; + keys = [ + { + fingerprint = "63FD 3A4F 4832 946C B808 8E3C C852 4052 69E7 A087"; + } + ]; + }; aldoborrero = { email = "aldoborrero+nixos@pm.me"; github = "aldoborrero"; @@ -919,6 +960,12 @@ githubId = 49609151; name = "Popa Ioan Alexandru"; }; + alexandru0-dev = { + email = "alexandru.italia32+nixpkgs@gmail.com"; + github = "alexandru0-dev"; + githubId = 45104896; + name = "Alexandru Nechita"; + }; alexarice = { email = "alexrice999@hotmail.co.uk"; github = "alexarice"; @@ -993,6 +1040,12 @@ githubId = 50754358; name = "Alex Winter"; }; + alfarel = { + email = "alfarelcynthesis@proton.me"; + github = "alfarelcynthesis"; + githubId = 104072649; + name = "Cynth"; + }; algram = { email = "aliasgram@gmail.com"; github = "Algram"; @@ -1005,12 +1058,6 @@ githubId = 30437811; name = "Alex Andrews"; }; - alibabzo = { - email = "alistair.bill@gmail.com"; - github = "alistairbill"; - githubId = 2822871; - name = "Alistair Bill"; - }; alirezameskin = { email = "alireza.meskin@gmail.com"; github = "alirezameskin"; @@ -1083,6 +1130,12 @@ githubId = 169249; name = "Alex Brandt"; }; + alx = { + email = "nix@alexgirard.com"; + github = "alx"; + githubId = 373; + name = "Alexandre Girard Davila"; + }; alxsimon = { email = "alexis.simon@normalesup.org"; github = "alxsimon"; @@ -1205,6 +1258,12 @@ githubId = 37040543; name = "Wroclaw"; }; + amuckstot30 = { + email = "amuckstot30@tutanota.com"; + github = "amuckstot30"; + githubId = 157274630; + name = "amuckstot30"; + }; amyipdev = { email = "amy@amyip.net"; github = "amyipdev"; @@ -1891,6 +1950,13 @@ githubId = 7745457; name = "Astavie"; }; + asterismono = { + email = "cmiki@amono.me"; + github = "AsterisMono"; + githubId = 54884471; + name = "Chatnoir Miki"; + matrix = "@mikiiki:matrix.org"; + }; astro = { email = "astro@spaceboyz.net"; github = "astro"; @@ -1992,12 +2058,25 @@ github = "Atry"; githubId = 601530; }; + attila = { + name = "Attila Oláh"; + email = "attila@dorn.haus"; + github = "attilaolah"; + githubId = 196617; + keys = [ { fingerprint = "BF2E 4759 74D3 88E0 E30C 9604 07E6 C064 3FD1 42C3"; } ]; + }; auchter = { name = "Michael Auchter"; email = "a@phire.org"; github = "auchter"; githubId = 1190483; }; + aucub = { + name = "aucub"; + email = "dr56ekgbb@mozmail.com"; + github = "aucub"; + githubId = 78630225; + }; augustebaum = { email = "auguste.apple@gmail.com"; github = "augustebaum"; @@ -2225,6 +2304,12 @@ github = "Baitinq"; githubId = 30861839; }; + baksa = { + email = "baksa@pm.me"; + name = "Kryštof Baksa"; + github = "Golbinex"; + githubId = 62813600; + }; balodja = { email = "balodja@gmail.com"; github = "balodja"; @@ -2243,6 +2328,12 @@ githubId = 18467667; name = "Alexander Bantyev"; }; + balssh = { + email = "george.bals25@gmail.com"; + github = "balssh"; + githubId = 82440615; + name = "George Bals"; + }; bananad3v = { email = "banana@banana.is-cool.dev"; github = "BANanaD3V"; @@ -2255,6 +2346,12 @@ githubId = 80325; name = "Benjamin Andresen"; }; + banh-canh = { + email = "vhvictorhang@gmail.com"; + github = "Banh-Canh"; + githubId = 66330398; + name = "Victor Hang"; + }; barab-i = { email = "barab_i@outlook.com"; github = "barab-i"; @@ -2273,6 +2370,11 @@ github = "barinov274"; githubId = 54442153; }; + BarrOff = { + name = "BarrOff"; + github = "BarrOff"; + githubId = 58253563; + }; barrucadu = { email = "mike@barrucadu.co.uk"; github = "barrucadu"; @@ -2447,6 +2549,26 @@ github = "beezow"; githubId = 42082156; }; + ben9986 = { + name = "Ben Carmichael"; + email = "ben9986.unvmn@passinbox.com"; + github = "ben9986"; + githubId = 38633150; + keys = [ { fingerprint = "03C7 A587 74B3 F0E8 CE1F 4F8E ABBC DD77 69BC D3B0"; } ]; + }; + benaryorg = { + name = "benaryorg"; + email = "binary@benary.org"; + github = "benaryorg"; + githubId = 6145260; + keys = [ { fingerprint = "804B 6CB8 AED5 61D9 3DAD 4DC5 E2F2 2C5E DF20 119D"; } ]; + }; + benchand = { + name = "Ben Chand"; + email = "BenChand1995@gmail.com"; + github = "BenChand"; + githubId = 3618457; + }; bendlas = { email = "herwig@bendlas.net"; matrix = "@bendlas:matrix.org"; @@ -2594,6 +2716,13 @@ githubId = 7346933; name = "betaboon"; }; + beviu = { + name = "beviu"; + email = "nixpkgs@beviu.com"; + github = "beviu"; + githubId = 56923875; + keys = [ { fingerprint = "30D6 A755 E3C3 5797 CBBB 05B6 CD20 2E66 5CAD 7D06"; } ]; + }; bew = { email = "benoit.dechezelles@gmail.com"; github = "bew"; @@ -2666,6 +2795,13 @@ githubId = 19915050; name = "binarycat"; }; + binary-eater = { + email = "sergeantsagara@protonmail.com"; + github = "Binary-Eater"; + githubId = 10691440; + name = "Rahul Rameshbabu"; + keys = [ { fingerprint = "678A 8DF1 D9F2 B51B 7110 BE53 FF24 7B3E 5411 387B"; } ]; + }; binsky = { email = "timo@binsky.org"; github = "binsky08"; @@ -2683,6 +2819,12 @@ githubId = 10164833; name = "Birk Bohne"; }; + bjesus = { + email = "nixpkgs@yoavmoshe.com"; + github = "bjesus"; + githubId = 55081; + name = "Yo'av Moshe"; + }; bjornfor = { email = "bjorn.forsman@gmail.com"; github = "bjornfor"; @@ -2736,7 +2878,7 @@ }; blitz = { email = "js@alien8.de"; - matrix = "@js:ukvly.org"; + matrix = "@blitz:chat.x86.lol"; github = "blitz"; githubId = 37907; name = "Julian Stecklina"; @@ -2832,6 +2974,14 @@ githubId = 3229981; name = "Duncan Fairbanks"; }; + BonusPlay = { + name = "Bonus"; + email = "nixos@bonusplay.pl"; + matrix = "@bonus:bonusplay.pl"; + github = "BonusPlay"; + githubId = 8405359; + keys = [ { fingerprint = "8279 6487 A4CA 2A28 E8B3 3CD6 C7F9 9743 6A20 4683"; } ]; + }; booklearner = { name = "booklearner"; email = "booklearner@proton.me"; @@ -2852,6 +3002,12 @@ githubId = 68566724; name = "bootstrap-prime"; }; + booxter = { + email = "ihar.hrachyshka@gmail.com"; + github = "booxter"; + githubId = 90200; + name = "Ihar Hrachyshka"; + }; boozedog = { email = "code@booze.dog"; github = "boozedog"; @@ -3035,7 +3191,7 @@ }; bryanhonof = { name = "Bryan Honof"; - email = "bryanhonof@gmail.com"; + email = "bryanhonof+nixpkgs@gmail.com"; github = "bryanhonof"; githubId = 5932804; }; @@ -3177,6 +3333,21 @@ { fingerprint = "208A 2A66 8A2F CDE7 B5D3 8F64 CDDC 792F 6552 51ED"; } ]; }; + cageyv = { + email = "pingme@cageyv.dev"; + github = "cageyv"; + githubId = 51059484; + name = "Vladmir Samoylov"; + keys = [ + { fingerprint = "8916 F727 734E 77AB 437F A33A 19AB 76F5 CEE1 1392"; } + ]; + }; + CaiqueFigueiredo = { + email = "public@caiquefigueiredo.me"; + github = "caiquefigueiredo"; + githubId = 20440897; + name = "Caique"; + }; CaitlinDavitt = { email = "CaitlinDavitt@gmail.com"; github = "CaitlinDavitt"; @@ -3202,6 +3373,16 @@ githubId = 24193; name = "Dan Callahan"; }; + callumio = { + email = "git@cleslie.uk"; + github = "callumio"; + githubId = 16057677; + name = "Callum Leslie"; + keys = [ + { fingerprint = "BC82 4BB5 1656 D144 285E A0EC D382 C4AF EECE AA90"; } + { fingerprint = "890B 06FB 209A 3E44 9491 C028 03B0 1F42 7831 BCFD"; } + ]; + }; calvertvl = { email = "calvertvl@gmail.com"; github = "calvertvl"; @@ -3220,6 +3401,12 @@ githubId = 141733; name = "Andrew Bruce"; }; + camerondugan = { + email = "cameron.dugan@protonmail.com"; + github = "camerondugan"; + githubId = 54632731; + name = "Cameron Dugan"; + }; cameronfyfe = { email = "cameron.j.fyfe@gmail.com"; github = "cameronfyfe"; @@ -3336,6 +3523,12 @@ githubId = 5241813; name = "Carter Sande"; }; + casaca = { + name = "J McNutt"; + email = "jmacasac@hotmail.com"; + github = "casaca24"; + githubId = 87252279; + }; casey = { email = "casey@rodarmor.net"; github = "casey"; @@ -3536,6 +3729,12 @@ matrix = "@chayleaf:matrix.pavluk.org"; name = "Anna Pavlyuk"; }; + cheeseecake = { + email = "chanelnjw@gmail.com"; + github = "cheeseecake"; + githubId = 34784816; + name = "Chanel"; + }; chekoopa = { email = "chekoopa@mail.ru"; github = "chekoopa"; @@ -3629,6 +3828,19 @@ githubId = 98980; name = "Chmouel Boudjnah"; }; + chn = { + name = "Haonan Chen"; + email = "chn@chn.moe"; + matrix = "@chn:chn.moe"; + github = "CHN-beta"; + githubId = 35858462; + }; + cholli = { + email = "christoph.hollizeck@hey.com"; + github = "Daholli"; + githubId = 25060097; + name = "Christoph Hollizeck"; + }; choochootrain = { email = "hurshal@imap.cc"; github = "choochootrain"; @@ -3812,6 +4024,12 @@ githubId = 199180; name = "Claes Wallin"; }; + claes = { + email = "claes.holmerson@gmail.com"; + github = "claes"; + githubId = 43564; + name = "Claes Holmerson"; + }; clebs = { email = "borja.clemente@gmail.com"; github = "clebs"; @@ -3952,6 +4170,12 @@ email = "jupiter@m.rdis.dev"; name = "Scott Little"; }; + codgician = { + email = "codgician@outlook.com"; + github = "codgician"; + githubId = 15964984; + name = "codgician"; + }; codifryed = { email = "gb@guyboldon.com"; name = "Guy Boldon"; @@ -4266,7 +4490,7 @@ keys = [ { fingerprint = "2017 E152 BB81 5C16 955C E612 45BC C1E2 709B 1788"; } ]; }; Cryolitia = { - name = "Beiyan Cryolitia"; + name = "Cryolitia PukNgae"; email = "Cryolitia@gmail.com"; github = "Cryolitia"; githubId = 23723294; @@ -4335,6 +4559,12 @@ keys = [ { fingerprint = "BBED 1B08 8CED 7F95 8917 FBE8 5004 F0FA D051 576D"; } ]; }; + cyewashish = { + name = "Cyewashish"; + email = "wawashish@cyekaivy.dev"; + github = "cyewashish"; + githubId = 180875322; + }; cynerd = { name = "Karel Kočí"; email = "cynerd@email.cz"; @@ -4461,6 +4691,12 @@ githubId = 24708079; name = "Dan Eads"; }; + danerieber = { + email = "danerieber@gmail.com"; + github = "danerieber"; + githubId = 6487079; + name = "Dane Rieber"; + }; danid3v = { email = "sch220233@spengergasse.at"; github = "DaniD3v"; @@ -4818,6 +5054,12 @@ name = "David Morgan"; keys = [ { fingerprint = "9B43 6B14 77A8 79C2 6CDB 6604 C171 2510 02C2 00F2"; } ]; }; + deekahy = { + email = "Lennart.Diego.Kahn@gmail.com"; + github = "deekahy"; + githubId = 97156953; + name = "Lennart Diego Kahn"; + }; deemp = { email = "deempleton@gmail.com"; github = "deemp"; @@ -4849,6 +5091,12 @@ github = "definfo"; githubId = 66514911; }; + deftdawg = { + name = "DeftDawg"; + github = "deftdawg"; + email = "deftdawg@gmail.com"; + githubId = 4991612; + }; deifactor = { name = "Ash Zahlen"; email = "ext0l@riseup.net"; @@ -4925,6 +5173,12 @@ githubId = 62989; name = "Demyan Rogozhin"; }; + denperidge = { + email = "contact@denperidge.com"; + github = "denperidge"; + githubId = 27348469; + name = "Cat"; + }; derchris = { email = "derchris@me.com"; github = "derchrisuk"; @@ -5406,6 +5660,12 @@ name = "Misha Gusarov"; keys = [ { fingerprint = "A8DF 1326 9E5D 9A38 E57C FAC2 9D20 F650 3E33 8888"; } ]; }; + dottybot = { + name = "Scala Organization (dottybot)"; + email = "dottybot@groupes.epfl.ch"; + github = "dottybot"; + githubId = 12519979; + }; dpaetzel = { email = "david.paetzel@posteo.de"; github = "dpaetzel"; @@ -5606,6 +5866,12 @@ githubId = 6872940; name = "Dennis Værum"; }; + dvcorreia = { + email = "dv_correia@hotmail.com"; + name = "Diogo Correia"; + github = "dvcorreia"; + githubId = 20357938; + }; dvn0 = { email = "git@dvn.me"; github = "dvn0"; @@ -5630,6 +5896,12 @@ githubId = 6689924; name = "David Terry"; }; + dxwil = { + email = "dovydas@kersys.lt"; + github = "dxwil"; + githubId = 90563298; + name = "Dovydas Kersys"; + }; dylan-gonzalez = { email = "dylcg10@gmail.com"; github = "dylan-gonzalez"; @@ -5718,12 +5990,6 @@ githubId = 8146736; name = "Florentin Eckl"; }; - eclairevoyant = { - email = "contactmeongithubinstead@proton.me"; - github = "eclairevoyant"; - githubId = 848000; - name = "éclairevoyant"; - }; edanaher = { email = "nixos@edanaher.net"; github = "edanaher"; @@ -5767,6 +6033,14 @@ githubId = 119483; name = "Matthew Brown"; }; + edgar-vincent = { + name = "Edgar Vincent"; + email = "e-v@posteo.net"; + matrix = "@edgar.vincent:matrix.org"; + github = "edgar-vincent"; + githubId = 63352906; + keys = [ { fingerprint = "922F CA48 5FDB 20B1 ED1B A61F 284D 11D3 33C4 D21B"; } ]; + }; edlimerkaj = { name = "Edli Merkaj"; email = "edli.merkaj@identinet.io"; @@ -6409,6 +6683,13 @@ githubId = 195032; name = "Eric Evenchick"; }; + eveeifyeve = { + name = "Eveeifyeve"; + github = "eveeifyeve"; + githubId = 88671402; + matrix = "@eveeifyeve:matrix.org"; + email = "eveeg1971@gmail.com"; + }; evenbrenden = { email = "packages@anythingexternal.com"; github = "evenbrenden"; @@ -6745,6 +7026,12 @@ { fingerprint = "elY15tXap1tddxbBVoUoAioe1u0RDWti5rc9cauSmwo"; } ]; }; + figboy9 = { + email = "figboy9@tuta.io"; + github = "figboy9"; + githubId = 52276064; + name = "figboy9"; + }; figsoda = { email = "figsoda@pm.me"; matrix = "@figsoda:matrix.org"; @@ -6807,6 +7094,12 @@ name = "Sebastian Neubauer"; keys = [ { fingerprint = "2F93 661D AC17 EA98 A104 F780 ECC7 55EE 583C 1672"; } ]; }; + Flameopathic = { + email = "flameopathic@gmail.com"; + github = "Flameopathic"; + githubId = 64027365; + name = "Erin Pletches"; + }; flandweber = { email = "finn@landweber.xyz"; github = "flandweber"; @@ -6905,6 +7198,13 @@ githubId = 5918766; name = "Franz Thoma"; }; + fnune = { + email = "fausto.nunez@mailbox.org"; + github = "fnune"; + githubId = 16181067; + name = "Fausto Núñez Alberro"; + keys = [ { fingerprint = "668E 01D1 B129 3F42 0A0F 933A C880 6451 94A2 D562"; } ]; + }; foo-dogsquared = { email = "foodogsquared@foodogsquared.one"; github = "foo-dogsquared"; @@ -6963,6 +7263,12 @@ githubId = 1202014; name = "Falco Peijnenburg"; }; + fqidz = { + email = "faidz.arante@gmail.com"; + github = "fqidz"; + githubId = 82884264; + name = "Faidz Arante"; + }; fragamus = { email = "innovative.engineer@gmail.com"; github = "fragamus"; @@ -6991,6 +7297,12 @@ githubId = 14952658; name = "Tom Dohrmann"; }; + frectonz = { + name = "Fraol Lemecha"; + email = "fraol0912@gmail.com"; + github = "frectonz"; + githubId = 53809656; + }; fredeb = { email = "im@fredeb.dev"; github = "FredeEB"; @@ -7314,6 +7626,12 @@ githubId = 91987; name = "Jim Garrison"; }; + garyguo = { + email = "gary@garyguo.net"; + github = "nbdd0121"; + githubId = 4065244; + name = "Gary Guo"; + }; gavin = { email = "gavin.rogers@holo.host"; github = "gavinrogers"; @@ -7394,6 +7712,12 @@ githubId = 111183546; keys = [ { fingerprint = "58CE D4BE 6B10 149E DA80 A990 2F48 6356 A4CB 30F3"; } ]; }; + genga898 = { + email = "genga898@gmail.com"; + github = "genga898"; + githubId = 84174227; + name = "Emmanuel Genga"; + }; genofire = { name = "genofire"; email = "geno+dev@fireorbit.de"; @@ -7981,12 +8305,25 @@ github = "hacker1024"; githubId = 20849728; }; + hadilq = { + name = "Hadi Lashkari Ghouchani"; + email = "hadilq.dev@gmail.com"; + github = "hadilq"; + githubId = 5190539; + keys = [ { fingerprint = "AD3D 53CB A68A FEC0 8065 BCBB 416A D9E8 E372 C075"; } ]; + }; hagl = { email = "harald@glie.be"; github = "hagl"; githubId = 1162118; name = "Harald Gliebe"; }; + hakan-demirli = { + email = "ehdemirli@proton.me"; + github = "hakan-demirli"; + githubId = 78746991; + name = "Emre Hakan Demirli"; + }; hakuch = { email = "hakuch@gmail.com"; github = "hakuch"; @@ -8005,6 +8342,12 @@ githubId = 1742172; name = "Hamish Hutchings"; }; + hamzaremmal = { + email = "hamza.remmal@epfl.ch"; + github = "hamzaremmal"; + githubId = 56235032; + name = "Hamza Remmal"; + }; hanemile = { email = "mail@emile.space"; github = "HanEmile"; @@ -8093,6 +8436,13 @@ githubId = 33969028; name = "Sebastian Hasler"; }; + hasnep = { + name = "Hannes"; + email = "h@nnes.dev"; + matrix = "@hasnep:matrix.org"; + github = "Hasnep"; + githubId = 25184102; + }; hausken = { name = "Hausken"; email = "hauskens-git@disp.lease>"; @@ -8162,6 +8512,12 @@ githubId = 287769; name = "Sergii Paryzhskyi"; }; + hehongbo = { + name = "Hongbo"; + github = "hehongbo"; + githubId = 665472; + matrix = "@hehongbo:matrix.org"; + }; heijligen = { email = "src@posteo.de"; github = "heijligen"; @@ -8193,6 +8549,11 @@ githubId = 2405974; name = "Sébastian Méric de Bellefon"; }; + hellodword = { + github = "hellodword"; + githubId = 46193371; + name = "hellodword"; + }; hellwolf = { email = "zhicheng.miao@gmail.com"; github = "hellwolf"; @@ -8254,6 +8615,11 @@ githubId = 15121114; name = "Tom Herbers"; }; + herschenglime = { + github = "Herschenglime"; + githubId = 69494718; + name = "Herschenglime"; + }; hexa = { email = "hexa@darmstadt.ccc.de"; matrix = "@hexa:lossy.network"; @@ -8509,6 +8875,12 @@ githubId = 1592375; name = "Walter Huf"; }; + hughmandalidis = { + name = "Hugh Mandalidis"; + email = "mandalidis.hugh@gmail.com"; + github = "ThanePatrol"; + githubId = 23148089; + }; hughobrien = { email = "github@hughobrien.ie"; github = "hughobrien"; @@ -8552,6 +8924,13 @@ name = "Luna Perego"; keys = [ { fingerprint = "09E4 B981 9B93 5B0C 0B91 1274 0578 7332 9217 08FF"; } ]; }; + hustlerone = { + email = "nine-ball@tutanota.com"; + matrix = "@hustlerone:matrix.org"; + github = "hustlerone"; + name = "Hustler One"; + githubId = 167621692; + }; huyngo = { email = "huyngo@disroot.org"; github = "Huy-Ngo"; @@ -8925,6 +9304,12 @@ githubId = 54999; name = "Ariel Nunez"; }; + interdependence = { + email = "git@williamvandervalk.com"; + github = "interdependence"; + githubId = 45567423; + name = "William Vandervalk"; + }; Intuinewin = { email = "antoinelabarussias@gmail.com"; github = "Intuinewin"; @@ -8956,6 +9341,12 @@ githubId = 1817528; name = "Igor Polyakov"; }; + iosmanthus = { + email = "myosmanthustree@gmail.com"; + github = "iosmanthus"; + githubId = 16307070; + name = "iosmanthus"; + }; iquerejeta = { github = "iquerejeta"; githubId = 31273774; @@ -9000,6 +9391,12 @@ githubId = 13622947; keys = [ { fingerprint = "1412 816B A9FA F62F D051 1975 D3E1 B013 B463 1293"; } ]; }; + istoph = { + email = "chr@istoph.de"; + name = "Christoph Hüffelmann"; + github = "istoph"; + githubId = 114227790; + }; ius = { email = "j.de.gram@gmail.com"; name = "Joerie de Gram"; @@ -9147,6 +9544,13 @@ github = "jacbart"; githubId = 7909687; }; + jacekpoz = { + name = "Jacek Poziemski"; + email = "jacekpoz@proton.me"; + matrix = "@jacekpoz:jacekpoz.pl"; + github = "jacekpoz"; + githubId = 64381190; + }; jacfal = { name = "Jakub Pravda"; email = "me@jakubpravda.net"; @@ -9165,6 +9569,13 @@ githubId = 7558482; name = "Jack Gerrits"; }; + jacobkoziej = { + name = "Jacob Koziej"; + email = "jacobkoziej@gmail.com"; + github = "jacobkoziej"; + githubId = 45084216; + keys = [ { fingerprint = "1BF9 8D10 E0D0 0B41 5723 5836 4C13 3A84 E646 9228"; } ]; + }; jaduff = { email = "jdduffpublic@proton.me"; github = "jaduff"; @@ -9257,6 +9668,12 @@ github = "jankaifer"; githubId = 12820484; }; + janlikar = { + name = "Jan Likar"; + email = "jan.likar@protonmail.com"; + github = "janlikar"; + githubId = 4228250; + }; jansol = { email = "jan.solanti@paivola.fi"; github = "jansol"; @@ -9681,6 +10098,11 @@ githubId = 1061229; name = "Jiehong Ma"; }; + jigglycrumb = { + github = "jigglycrumb"; + githubId = 1476865; + name = "jigglycrumb"; + }; jirkamarsik = { email = "jiri.marsik89@gmail.com"; github = "jirkamarsik"; @@ -9803,6 +10225,12 @@ { fingerprint = "816D 23F5 E672 EC58 7674 4A73 197F 9A63 2D13 9E30"; } ]; }; + jmendyk = { + email = "jakub@ndyk.me"; + github = "JMendyk"; + githubId = 9089004; + name = "Jakub Mendyk"; + }; jmettes = { email = "jonathan@jmettes.com"; github = "jmettes"; @@ -10047,12 +10475,6 @@ githubId = 57130301; keys = [ { fingerprint = "1CC5 B67C EB9A 13A5 EDF6 F10E 0B4A 3662 FC58 9202"; } ]; }; - jonafato = { - email = "jon@jonafato.com"; - github = "jonafato"; - githubId = 392720; - name = "Jon Banafato"; - }; jonas-w = { email = "nixpkgs@03j.de"; github = "jonas-w"; @@ -10463,6 +10885,13 @@ githubId = 46386452; name = "Jeroen Wijenbergh"; }; + jwillikers = { + email = "jordan@jwillikers.com"; + github = "jwillikers"; + githubId = 19399197; + name = "Jordan Williams"; + keys = [ { fingerprint = "A6AB 406A F5F1 DE02 CEA3 B6F0 9FB4 2B0E 7F65 7D8C"; } ]; + }; jwygoda = { email = "jaroslaw@wygoda.me"; github = "jwygoda"; @@ -10729,13 +11158,6 @@ githubId = 8211181; name = "Kevin Kandlbinder"; }; - kfears = { - email = "kfearsoff@gmail.com"; - github = "KFearsoff"; - githubId = 66781795; - matrix = "@kfears:matrix.org"; - name = "KFears"; - }; kfollesdal = { email = "kfollesdal@gmail.com"; github = "kfollesdal"; @@ -10809,12 +11231,6 @@ githubId = 8798449; name = "kidsan"; }; - kierdavis = { - email = "kierdavis@gmail.com"; - github = "kierdavis"; - githubId = 845652; - name = "Kier Davis"; - }; kiike = { email = "me@enric.me"; github = "kiike"; @@ -10882,7 +11298,7 @@ name = "kintrix"; }; kinzoku = { - email = "kinzokudev4869@gmail.com"; + email = "kinzoku@the-nebula.xyz"; github = "kinzoku-dev"; githubId = 140647311; name = "Ayman Hamza"; @@ -11108,6 +11524,12 @@ githubId = 17219127; name = "kotatsuyaki"; }; + kototama = { + email = "kototama@posteo.net"; + github = "kototama"; + githubId = 128620; + name = "Kototama"; + }; kouyk = { email = "skykinetic@stevenkou.xyz"; github = "kouyk"; @@ -11126,6 +11548,12 @@ githubId = 787421; name = "Kevin Quick"; }; + kraanzu = { + name = "Murli Tawari"; + email = "kraanzu@gmail.com"; + github = "kraanzu"; + githubId = 97718086; + }; kradalby = { name = "Kristoffer Dalby"; email = "kristoffer@dalby.cc"; @@ -11162,6 +11590,12 @@ githubId = 4032; name = "Kristoffer Thømt Ravneberg"; }; + kristianan = { + email = "kristian@krined.no"; + github = "KristianAN"; + githubId = 80984519; + name = "Kristian Alvestad Nedevold-Hansen"; + }; kristian-brucaj = { email = "kbrucaj@gmail.com"; github = "Flameslice"; @@ -11337,6 +11771,13 @@ githubId = 168301; name = "Victor Engmark"; }; + l33tname = { + name = "l33tname"; + email = "hi@l33t.name"; + + github = "Fliiiix"; + githubId = 1682954; + }; l3af = { email = "L3afMeAlon3@gmail.com"; matrix = "@L3afMe:matrix.org"; @@ -11658,6 +12099,12 @@ githubId = 13804737; keys = [ { fingerprint = "7FE2 113A A08B 695A C8B8 DDE6 AE53 B4C2 E58E DD45"; } ]; }; + lgbishop = { + email = "lachlan.bishop@hotmail.com"; + github = "lgbishop"; + githubId = 125634066; + name = "Lachlan Bishop"; + }; lgcl = { email = "dev@lgcl.de"; name = "Leon Vack"; @@ -11978,12 +12425,10 @@ githubId = 4969294; name = "Louis Tim Larsen"; }; - loveisgrief = { - name = "LoveIsGrief"; - email = "loveisgrief@tuta.io"; - github = "LoveIsGrief"; - githubId = 2829538; - keys = [ { fingerprint = "9847 4F48 18C6 4E0A F0C5 3529 E96D 1EDF A053 45EB"; } ]; + louis-thevenet = { + name = "Louis Thevenet"; + github = "louis-thevenet"; + githubId = 55986107; }; lovek323 = { email = "jason@oconal.id.au"; @@ -12050,6 +12495,12 @@ githubId = 8555953; name = "Laure Tavard"; }; + ltrump = { + email = "ltrump@163.com"; + github = "L-Trump"; + githubId = 37738631; + name = "Luo Chen"; + }; ltstf1re = { email = "ltstf1re@disroot.org"; github = "lsf1re"; @@ -12065,7 +12516,7 @@ name = "Luis Wirth"; }; luc65r = { - email = "lucas@ransan.tk"; + email = "lucas@ransan.fr"; github = "luc65r"; githubId = 59375051; name = "Lucas Ransan"; @@ -12095,6 +12546,12 @@ githubId = 15693688; name = "Lucas Eduardo Wendt"; }; + lucastso10 = { + email = "lucastso10@gmail.com"; + github = "lucastso10"; + githubId = 84486266; + name = "Lucas Teixeira Soares"; + }; lucc = { email = "lucc+nix@posteo.de"; github = "lucc"; @@ -12234,6 +12691,12 @@ githubId = 2486026; name = "Luca Fulchir"; }; + lukts30 = { + email = "llukas21307@gmail.com"; + github = "lukts30"; + githubId = 24390575; + name = "lukts30"; + }; luleyleo = { email = "git@leopoldluley.de"; github = "luleyleo"; @@ -12283,6 +12746,12 @@ githubId = 44469719; name = "Jussi Kuokkanen"; }; + lutzberger = { + email = "lutz.berger@airbus.com"; + github = "lutzberger"; + githubId = 115777584; + name = "Lutz Berger"; + }; lux = { email = "lux@lux.name"; github = "luxzeitlos"; @@ -12315,12 +12784,6 @@ githubId = 7910815; name = "Alex McGrath"; }; - lychee = { - email = "itslychee+nixpkgs@protonmail.com"; - githubId = 82718618; - github = "itslychee"; - name = "Lychee"; - }; lyndeno = { name = "Lyndon Sanche"; email = "lsanche@lyndeno.ca"; @@ -12345,6 +12808,12 @@ githubId = 3044438; name = "Lucas Savva"; }; + m1dugh = { + email = "romain103paris@gmail.com"; + name = "Romain LE MIERE"; + github = "m1dugh"; + githubId = 42266017; + }; ma27 = { email = "maximilian@mbosch.me"; matrix = "@ma27:nicht-so.sexy"; @@ -13086,6 +13555,12 @@ githubId = 10420834; name = "Mihai-Drosi Caju"; }; + mccartykim = { + email = "mccartykim@zoho.com"; + github = "mccartykim"; + githubId = 9851221; + name = "Kimberly McCarty"; + }; mccurdyc = { email = "mccurdyc22@gmail.com"; github = "mccurdyc"; @@ -13172,6 +13647,13 @@ githubId = 191622; name = "Denys Pavlov"; }; + meator = { + email = "meator.dev@gmail.com"; + github = "meator"; + githubId = 67633081; + name = "meator"; + keys = [ { fingerprint = "7B0F 58A5 E0F1 A2EA 1157 8A73 1A14 CB34 64CB E5BF"; } ]; + }; meditans = { email = "meditans@gmail.com"; github = "meditans"; @@ -13245,6 +13727,12 @@ github = "Mephistophiles"; githubId = 4850908; }; + merrkry = { + email = "merrkry@tsubasa.moe"; + name = "merrkry"; + github = "merrkry"; + githubId = 124278440; + }; mevatron = { email = "mevatron@gmail.com"; name = "mevatron"; @@ -13328,6 +13816,13 @@ github = "mi-ael"; githubId = 12199265; }; + miampf = { + email = "miampf@proton.me"; + github = "miampf"; + githubId = 111570799; + name = "Mia Motte Mallon"; + keys = [ { fingerprint = "7008 92AA 6F32 8CAC 8740 0070 EF03 9364 B5B6 886C"; } ]; + }; miangraham = { github = "miangraham"; githubId = 704580; @@ -13528,6 +14023,13 @@ name = "Mark Vainomaa"; keys = [ { fingerprint = "DB43 2895 CF68 F0CE D4B7 EF60 DA01 5B05 B5A1 1B22"; } ]; }; + mikut = { + email = "mikut@mikut.dev"; + github = "Mikutut"; + githubId = 65046942; + name = "Marcin Mikuła"; + keys = [ { fingerprint = "5547 2A56 AC30 69C9 15C8 B98D 997F 71FA 1D74 6E37"; } ]; + }; milahu = { email = "milahu@gmail.com"; github = "milahu"; @@ -13687,6 +14189,12 @@ githubId = 4587373; name = "Mitchell Nordine"; }; + mithicspirit = { + email = "rpc01234@gmail.com"; + github = "MithicSpirit"; + githubId = 24192522; + name = "MithicSpirit"; + }; mjanczyk = { email = "m@dragonvr.pl"; github = "mjanczyk"; @@ -13725,7 +14233,7 @@ name = "Maciej Kazulak"; }; mkez = { - email = "matias.zwinger+nix@protonmail.com"; + email = "matias+nix@zwinger.fi"; github = "mk3z"; githubId = 52108954; name = "Matias Zwinger"; @@ -13858,6 +14366,12 @@ githubId = 754512; name = "Mogria"; }; + mohe2015 = { + name = "Moritz Hedtke"; + email = "Moritz.Hedtke@t-online.de"; + github = "mohe2015"; + githubId = 13287984; + }; momeemt = { name = "Mutsuha Asada"; email = "me@momee.mt"; @@ -13935,6 +14449,12 @@ githubId = 42215704; name = "Moritz Böhme"; }; + mortenmunk = { + email = "mortenmunk97@gmail.com"; + github = "MortenMunk"; + githubId = 92527083; + name = "Morten Munk"; + }; MostAwesomeDude = { email = "cds@corbinsimpson.com"; github = "MostAwesomeDude"; @@ -14364,6 +14884,12 @@ githubId = 6709831; name = "Jake Hill"; }; + nartsiss = { + name = "Daniil Nartsissov"; + email = "nartsiss@proton.me"; + github = "nartsisss"; + githubId = 54633007; + }; nasageek = { github = "NasaGeek"; githubId = 474937; @@ -14404,6 +14930,13 @@ githubId = 818502; name = "Nathan Yong"; }; + natsukagami = { + email = "natsukagami@gmail.com"; + github = "natsukagami"; + githubId = 9061737; + name = "Natsu Kagami"; + keys = [ { fingerprint = "5581 26DC 886F E14D 501D B0F2 D6AD 7B57 A992 460C"; } ]; + }; natsukium = { email = "nixpkgs@natsukium.com"; github = "natsukium"; @@ -14923,6 +15456,11 @@ github = "noaccOS"; githubId = 24324352; }; + noahgitsham = { + name = "Noah Gitsham"; + github = "noahgitsham"; + githubId = 73707948; + }; nobbz = { name = "Norbert Melzer"; email = "timmelzer+nixpkgs@gmail.com"; @@ -15140,6 +15678,19 @@ githubId = 5047052; name = "Niclas Hirschfeld"; }; + nwjsmith = { + email = "nate@theinternate.com"; + github = "nwjsmith"; + githubId = 1348; + name = "Nate Smith"; + }; + nyabinary = { + name = "Niko Cantero"; + email = "nyanbinary@keemail.me"; + matrix = "@niko:conduit.rs"; + github = "nyabinary"; + githubId = 97130632; + }; nyadiia = { email = "nyadiia@pm.me"; github = "nyadiia"; @@ -15147,13 +15698,6 @@ name = "Nadia"; keys = [ { fingerprint = "6B51 E324 238A F455 2381 313A 9254 1B0C D2A9 3AD8"; } ]; }; - nyanbinary = { - email = "nyanbinary@keemail.me"; - matrix = "@niko:conduit.rs"; - github = "nyabinary"; - githubId = 97130632; - name = "Niko"; - }; nyanloutre = { email = "paul@nyanlout.re"; github = "nyanloutre"; @@ -15205,6 +15749,12 @@ github = "o0th"; githubId = 22490354; }; + oakenshield = { + email = "nix@thorin.theoakenshield.com"; + github = "HritwikSinghal"; + githubId = 29531474; + name = "Hritwik Singhal"; + }; oaksoaj = { email = "oaksoaj@riseup.net"; name = "Oaksoaj"; @@ -15347,6 +15897,12 @@ githubId = 39134647; name = "Oliver Koss"; }; + oliver-ni = { + email = "nixos@oliver.ni"; + github = "oliver-ni"; + githubId = 20295134; + name = "Oliver Ni"; + }; ollieB = { github = "oliverbunting"; githubId = 1237862; @@ -15430,12 +15986,6 @@ github = "ony"; githubId = 11265; }; - oo-infty = { - name = "Justin Chen"; - email = "oo-infty@outlook.com"; - github = "oo-infty"; - githubId = 42143810; - }; ooliver1 = { name = "Oliver Wilkes"; email = "oliverwilkes2006@icloud.com"; @@ -15443,6 +15993,12 @@ githubId = 34910574; keys = [ { fingerprint = "D055 8A23 3947 B7A0 F966 B07F 0B41 0348 9833 7273"; } ]; }; + oosquare = { + name = "Justin Chen"; + email = "oosquare@outlook.com"; + github = "oosquare"; + githubId = 42143810; + }; opeik = { email = "sandro@stikic.com"; github = "opeik"; @@ -15605,6 +16161,12 @@ githubId = 5948762; name = "Berk Özkütük"; }; + ozwaldorf = { + email = "self@ossian.dev"; + github = "ozwaldorf"; + githubId = 8976745; + name = "Ossian Mapes"; + }; p3psi = { name = "Elliot Boo"; email = "p3psi.boo@gmail.com"; @@ -15642,6 +16204,12 @@ githubId = 10776658; name = "Patrick Gordon"; }; + paepcke = { + email = "git@paepcke.de"; + github = "paepckehh"; + githubId = 120342602; + name = "Michael Paepcke"; + }; paholg = { email = "paho@paholg.com"; github = "paholg"; @@ -15763,6 +16331,12 @@ githubId = 4580157; name = "Patrick Hobusch"; }; + patka = { + email = "patka@patka.dev"; + github = "patka-123"; + githubId = 69802930; + name = "patka"; + }; patrickdag = { email = "patrick-nixos@failmail.dev"; github = "PatrickDaG"; @@ -16000,6 +16574,12 @@ githubId = 29493551; name = "Josh Peters"; }; + petertriho = { + email = "mail@petertriho.com"; + github = "petertriho"; + githubId = 7420227; + name = "Peter Tri Ho"; + }; peterwilli = { email = "peter@codebuffet.co"; github = "peterwilli"; @@ -16119,6 +16699,11 @@ githubId = 13309623; name = "Philipp Herzog"; }; + PhilVoel = { + github = "PhilVoel"; + githubId = 56931301; + name = "Philipp Völler"; + }; phip1611 = { email = "phip1611@gmail.com"; github = "phip1611"; @@ -16272,6 +16857,18 @@ githubId = 20472367; name = "Peter Hebden"; }; + pixelsergey = { + email = "sergey.ichtchenko@gmail.com"; + github = "PixelSergey"; + githubId = 14542417; + name = "Sergey Ichtchenko"; + }; + pizzapim = { + email = "pim@kunis.nl"; + github = "pizzapim"; + githubId = 23135512; + name = "Pim Kunis"; + }; pjbarnoy = { email = "pjbarnoy@gmail.com"; github = "waaamb"; @@ -16358,6 +16955,12 @@ githubId = 358550; name = "Philip Lykke Carlsen"; }; + plebhash = { + name = "plebhash"; + email = "plebhash@proton.me"; + github = "plebhash"; + githubId = 147345153; + }; pleshevskiy = { email = "dmitriy@pleshevski.ru"; github = "pleshevskiy"; @@ -16684,12 +17287,25 @@ githubId = 74465; name = "James Fargher"; }; + progrm_jarvis = { + email = "mrjarviscraft+nix@gmail.com"; + github = "JarvisCraft"; + githubId = 7693005; + name = "Petr Portnov"; + keys = [ { fingerprint = "884B 08D2 8DFF 6209 1857 C1C7 7E8F C8F7 D1BB 84A3"; } ]; + }; progval = { email = "progval+nix@progval.net"; github = "progval"; githubId = 406946; name = "Valentin Lorentz"; }; + projectinitiative = { + name = "ProjectInitiative"; + github = "ProjectInitiative"; + githubId = 6314611; + keys = [ { fingerprint = "EEC7 53FC EAAA FD9E 4DC0 9BB5 CAEB 4185 C226 D76B"; } ]; + }; prominentretail = { email = "me@jakepark.me"; github = "ProminentRetail"; @@ -16884,6 +17500,12 @@ githubId = 315234; name = "Serge Bazanski"; }; + qaidvoid = { + email = "contact@qaidvoid.dev"; + github = "qaidvoid"; + githubId = 12017109; + name = "Rabindra Dhakal"; + }; qbit = { name = "Aaron Bieber"; email = "aaron@bolddaemon.com"; @@ -16972,6 +17594,12 @@ githubId = 1332289; name = "Quentin Machu"; }; + quincepie = { + email = "flaky@quincepie.dev"; + github = "Quince-Pie"; + githubId = 127546159; + name = "QuincePie"; + }; quinn-dougherty = { email = "quinnd@riseup.net"; github = "quinn-dougherty"; @@ -17029,6 +17657,12 @@ githubId = 131856; name = "Arnout Engelen"; }; + racci = { + name = "James Draycott"; + email = "me@racci.dev"; + github = "DaRacci"; + githubId = 90304606; + }; raehik = { email = "thefirstmuffinman@gmail.com"; github = "raehik"; @@ -17131,6 +17765,12 @@ githubId = 5653911; name = "Rampoina"; }; + rane = { + email = "rane+nix@junkyard.systems"; + github = "digitalrane"; + githubId = 1829286; + name = "Rane"; + }; ranfdev = { email = "ranfdev@gmail.com"; name = "Lorenzo Miglietta"; @@ -17212,6 +17852,12 @@ githubId = 145816; name = "David McKay"; }; + rayhem = { + email = "glosser1@gmail.com"; + github = "rayhem"; + githubId = 49202382; + name = "Connor Glosser"; + }; raylas = { email = "r@raymond.sh"; github = "raylas"; @@ -17417,6 +18063,13 @@ github = "renesat"; githubId = 11363539; }; + rennsax = { + name = "Bojun Ren"; + email = "bj.ren.coding@outlook.com"; + github = "rennsax"; + githubId = 93167100; + keys = [ { fingerprint = "9075 CEF8 9850 D261 6599 641A A2C9 36D5 B88C 139C"; } ]; + }; renzo = { email = "renzocarbonara@gmail.com"; github = "k0001"; @@ -17800,6 +18453,12 @@ githubId = 17805516; name = "Rohan Rao"; }; + rolfschr = { + email = "rolf.schr@posteo.de"; + github = "rolfschr"; + githubId = 1188465; + name = "Rolf Schröder"; + }; rollf = { email = "rolf.schroeder@limbus-medtec.com"; github = "rollf"; @@ -17818,6 +18477,18 @@ githubId = 1217934; name = "José Romildo Malaquias"; }; + romner-set = { + email = "admin@cynosure.red"; + github = "romner-set"; + githubId = 41077433; + name = "romner-set"; + keys = [ + { + # uploaded to https://keys.openpgp.org + fingerprint = "4B75 244B 0279 9598 FF3B C21F 95FC 58F1 8CFD FAB0"; + } + ]; + }; ronanmacf = { email = "macfhlar@tcd.ie"; github = "RonanMacF"; @@ -17862,12 +18533,6 @@ github = "rosehobgoblin"; githubId = 84164410; }; - roshaen = { - name = "Roshan Kumar"; - email = "roshaen09@gmail.com"; - github = "roshaen"; - githubId = 58213083; - }; RossComputerGuy = { name = "Tristan Ross"; email = "tristan.ross@midstall.com"; @@ -18002,6 +18667,11 @@ githubId = 56157634; name = "Ruben Hönle"; }; + rubikcubed = { + github = "rubikcubed"; + githubId = 91467402; + name = "rubikcubed"; + }; ruby0b = { github = "ruby0b"; githubId = 106119328; @@ -18086,6 +18756,12 @@ githubId = 141248; name = "Ramses"; }; + rvfg = { + email = "i@rvf6.com"; + github = "duament"; + githubId = 30264485; + name = "Rvfg"; + }; rvl = { email = "dev+nix@rodney.id.au"; github = "rvl"; @@ -18215,6 +18891,13 @@ githubId = 766350; name = "Richard Zetterberg"; }; + s0me1newithhand7s = { + name = "hand7s"; + email = "s0me1newithhand7s@gmail.com"; + matrix = "@s0me1newithhand7s:matrix.org"; + github = "s0me1newithhand7s"; + githubId = 117505144; + }; s1341 = { email = "s1341@shmarya.net"; matrix = "@s1341:matrix.org"; @@ -18348,6 +19031,13 @@ githubId = 34161949; keys = [ { fingerprint = "155C F413 0129 C058 9A5F 5524 3658 73F2 F0C6 153B"; } ]; }; + sanana = { + email = "asya@waifu.club"; + github = "AsyaTheAbove"; + githubId = 40492846; + keys = [ { fingerprint = "B766 7717 1644 5ABC DE82 94AA 4679 BF7D CC04 4783"; } ]; + name = "sanana the skenana"; + }; sander = { email = "s.vanderburg@tudelft.nl"; github = "svanderburg"; @@ -18391,6 +19081,13 @@ githubId = 695473; name = "Sascha Grunert"; }; + saturn745 = { + email = "git-commits.rk7uq@aleeas.com"; + github = "saturn745"; + githubId = 90934664; + name = "Saturn745"; + matrix = "@galaxyyy:matrix.org"; + }; saulecabrera = { name = "Saúl Cabrera"; email = "saulecabrera@gmail.com"; @@ -18539,6 +19236,12 @@ githubId = 11320; name = "Sergiu Ivanov"; }; + scraptux = { + email = "git@thomasjasny.de"; + github = "scraptux"; + githubId = 12714892; + name = "Thomas Jasny"; + }; screendriver = { email = "nix@echooff.de"; github = "screendriver"; @@ -18743,6 +19446,12 @@ githubId = 307899; name = "Gurkan Gur"; }; + sequencer = { + email = "liu@jiuyang.me"; + github = "sequencer"; + githubId = 5791019; + name = "Jiuyang Liu"; + }; serge = { email = "sb@canva.com"; github = "serge-belov"; @@ -18976,6 +19685,12 @@ github = "kf5grd"; githubId = 18297490; }; + shogo = { + email = "shouryagoel10000@gmail.com"; + github = "Sh0g0-1758"; + githubId = 114918019; + name = "Shourya Goel"; + }; shortcord = { name = "Short Cord"; email = "short@shortcord.com"; @@ -18995,6 +19710,12 @@ githubId = 67710369; keys = [ { fingerprint = "EA88 EA07 26E9 6CBF 6365 3966 163B 16EE 76ED 24CE"; } ]; }; + shved = { + name = "Yury Shvedov"; + email = "mestofel13@gmail.com"; + github = "ein-shved"; + githubId = 3513222; + }; shyim = { email = "s.sayakci@gmail.com"; github = "shyim"; @@ -19181,6 +19902,12 @@ githubId = 74413170; name = "Johannes Klein"; }; + sith-lord-vader = { + email = "abhiayush23@gmail.com"; + github = "sith-lord-vader"; + githubId = 24388085; + name = "Abhishek Adhikari"; + }; sivteck = { email = "sivaram1992@gmail.com"; github = "sivteck"; @@ -19217,6 +19944,13 @@ githubId = 158321; name = "Stewart Mackenzie"; }; + skeuchel = { + name = "Steven Keuchel"; + email = "steven.keuchel@gmail.com"; + github = "skeuchel"; + githubId = 617130; + keys = [ { fingerprint = "C4F7 46C7 B560 38D8 210F 0288 5877 DEE9 7428 557F"; } ]; + }; skovati = { github = "skovati"; githubId = 49844593; @@ -19444,11 +20178,11 @@ name = "Kylie McClain"; }; SomeoneSerge = { - email = "sergei.kozlukov@aalto.fi"; + email = "else+nixpkgs@someonex.net"; matrix = "@ss:someonex.net"; github = "SomeoneSerge"; githubId = 9720532; - name = "Sergei K"; + name = "Else Someone"; }; sontek = { email = "sontek@gmail.com"; @@ -19623,6 +20357,12 @@ github = "srounce"; githubId = 60792; }; + sshine = { + email = "simon@simonshine.dk"; + github = "sshine"; + githubId = 50879; + name = "Simon Shine"; + }; SShrike = { email = "severen@shrike.me"; github = "severen"; @@ -19945,13 +20685,6 @@ githubId = 36031171; name = "Supa"; }; - superherointj = { - email = "sergiomarcelo@yandex.com"; - github = "superherointj"; - githubId = 5861043; - matrix = "@superherointj:matrix.org"; - name = "Sérgio Marcelo"; - }; SuperSandro2000 = { email = "sandro.jaeckel@gmail.com"; matrix = "@sandro:supersandro.de"; @@ -20191,6 +20924,12 @@ githubId = 18656090; name = "Yuki Takagi"; }; + takeda = { + name = "Derek Kuliński"; + email = "d@kulinski.us"; + github = "takeda"; + githubId = 411978; + }; taketwo = { email = "alexandrov88@gmail.com"; github = "taketwo"; @@ -20296,6 +21035,11 @@ githubId = 156964; name = "Thomas Boerger"; }; + tbwanderer = { + github = "tbwanderer"; + githubId = 125365236; + name = "Ice Layer"; + }; tcbravo = { email = "tomas.bravo@protonmail.ch"; github = "tcbravo"; @@ -20424,6 +21168,13 @@ githubId = 3889585; name = "Cheng Shao"; }; + terryg = { + name = "Terry Garcia"; + email = "terry@terryg.org"; + github = "TerryGarcia"; + githubId = 159372832; + keys = [ { fingerprint = "6F54 C08C 37C8 EC78 15FA 0D01 A721 8CBA 2D80 15C3"; } ]; + }; tesq0 = { email = "mikolaj.galkowski@gmail.com"; github = "tesq0"; @@ -20456,9 +21207,15 @@ githubId = 27386; name = "Milan Svoboda"; }; + textshell = { + email = "textshell@uchuujin.de"; + github = "textshell"; + githubId = 6579711; + name = "Martin Hostettler"; + }; tfc = { email = "jacek@galowicz.de"; - matrix = "@jonge:ukvly.org"; + matrix = "@tfc:matrix.org"; github = "tfc"; githubId = 29044; name = "Jacek Galowicz"; @@ -20546,6 +21303,13 @@ githubId = 3512122; keys = [ { fingerprint = "5F29 132D EFA8 5DA0 B598 5BF2 5941 754C 1CDE 33BB"; } ]; }; + TheColorman = { + name = "colorman"; + email = "nixpkgs@colorman.me"; + github = "TheColorman"; + githubId = 18369995; + keys = [ { fingerprint = "3D8C A43C FBA2 5D28 0196 19F0 AB11 0475 B417 291D"; } ]; + }; thedavidmeister = { email = "thedavidmeister@gmail.com"; github = "thedavidmeister"; @@ -20869,6 +21633,14 @@ github = "tirimia"; githubId = 11174371; }; + titaniumtown = { + email = "titaniumtown@proton.me"; + name = "Simon Gardling"; + github = "titaniumtown"; + githubId = 11786225; + matrix = "@titaniumtown:envs.net"; + keys = [ { fingerprint = "D15E 4754 FE1A EDA1 5A6D 4702 9AB2 8AC1 0ECE 533D"; } ]; + }; tjni = { email = "43ngvg@masqt.com"; matrix = "@tni:matrix.org"; @@ -21156,6 +21928,12 @@ githubId = 16036882; name = "Thibault Gagnaux"; }; + tri-ler = { + github = "tri-ler"; + githubId = 47867303; + email = "tylerh689@gmail.com"; + name = "Tyler Hong"; + }; trino = { email = "muehlhans.hubert@ekodia.de"; github = "hmuehlhans"; @@ -21215,12 +21993,25 @@ githubId = 4044033; name = "Thomas Sowell"; }; + ttrei = { + email = "reinis.taukulis@gmail.com"; + github = "ttrei"; + githubId = 27609929; + name = "Reinis Taukulis"; + }; ttuegel = { email = "ttuegel@mailbox.org"; github = "ttuegel"; githubId = 563054; name = "Thomas Tuegel"; }; + tudbut = { + name = "Daniella Hennig"; + email = "nixpkgs@mail.tudbut.de"; + matrix = "@tudbut:matrix.tudbut.de"; + github = "tudbut"; + githubId = 48156391; + }; tu-maurice = { email = "valentin.gehrke+nixpkgs@zom.bi"; github = "tu-maurice"; @@ -21314,6 +22105,11 @@ githubId = 1215104; keys = [ { fingerprint = "B1FD 4E2A 84B2 2379 F4BF 2EF5 FE33 A228 2371 E831"; } ]; }; + tyberius-prime = { + name = "Tyberius Prime"; + github = "TyberiusPrime"; + githubId = 1257580; + }; tylerjl = { email = "tyler+nixpkgs@langlois.to"; github = "tylerjl"; @@ -21369,6 +22165,13 @@ githubId = 12422133; name = "Chromo-residuum-opec"; }; + uku3lig = { + name = "uku"; + email = "hi@uku.moe"; + matrix = "@uku:m.uku.moe"; + github = "uku3lig"; + githubId = 61147779; + }; ulrikstrid = { email = "ulrik.strid@outlook.com"; github = "ulrikstrid"; @@ -21671,6 +22474,12 @@ github = "vector1dev"; githubId = 127302590; }; + vedantmgoyal9 = { + name = "Vedant Mohan Goyal"; + matrix = "@vedantmgoyal:beeper.com"; + github = "vedantmgoyal9"; + githubId = 83997633; + }; veehaitch = { name = "Vincent Haupert"; email = "mail@vincent-haupert.de"; @@ -21777,6 +22586,12 @@ githubId = 19894025; name = "Vinny Meller"; }; + vinylen = { + email = "victor@viclab.se"; + github = "vinylen"; + githubId = 98466471; + name = "Victor Nilsson"; + }; vinymeuh = { email = "vinymeuh@gmail.com"; github = "vinymeuh"; @@ -21904,6 +22719,13 @@ githubId = 144771550; name = "Luca Uricariu"; }; + voronind = { + email = "hi@voronind.com"; + name = "Dmitry Voronin"; + github = "voronind-com"; + githubId = 22127600; + keys = [ { fingerprint = "3241 FDAD 82A7 E22D 4279 F405 913F 3267 9278 2E1C"; } ]; + }; votava = { email = "votava@gmail.com"; github = "janvotava"; @@ -21928,6 +22750,14 @@ githubId = 230381; name = "Daniel Nilsson"; }; + vrifox = { + email = "vrifox@vrifox.cc"; + github = "vrifox"; + githubId = 109021367; + keys = [ { fingerprint = "413C 73F0 C5BD 6318 826A 42D9 D400 98E5 B60B 2197"; } ]; + matrix = "@vri:cozy.town"; + name = "Vri"; + }; vrinek = { email = "vrinek@hey.com"; github = "vrinek"; @@ -22122,6 +22952,12 @@ githubId = 24979302; name = "Vladimír Zahradník"; }; + wgunderwood = { + email = "wg.underwood13@gmail.com"; + github = "WGUNDERWOOD"; + githubId = 42812654; + name = "William Underwood"; + }; wheelsandmetal = { email = "jakob@schmutz.co.uk"; github = "wheelsandmetal"; @@ -22486,12 +23322,24 @@ githubId = 529003; name = "Christine Dodrill"; }; + xeals = { + email = "dev@xeal.me"; + github = "xeals"; + githubId = 21125058; + name = "xeals"; + }; xeji = { email = "xeji@cat3.de"; github = "xeji"; githubId = 36407913; name = "Uli Baum"; }; + xelden = { + email = "anpiz@protonmail.com"; + github = "Xelden"; + githubId = 117323435; + name = "Andrés Pico"; + }; xfnw = { email = "xfnw+nixos@riseup.net"; github = "xfnw"; @@ -22812,6 +23660,12 @@ github = "YoshiRulz"; githubId = 13409956; }; + youhaveme9 = { + name = "Roshan Kumar"; + email = "roshaen09@gmail.com"; + github = "youhaveme9"; + githubId = 58213083; + }; yrashk = { email = "yrashk@gmail.com"; github = "yrashk"; @@ -23025,6 +23879,12 @@ github = "zbioe"; githubId = 7332055; }; + zebradil = { + email = "german.lashevich+nixpkgs@gmail.com"; + github = "zebradil"; + githubId = 1475583; + name = "German Lashevich"; + }; zebreus = { matrix = "@lennart:cicen.net"; email = "lennarteichhorn+nixpkgs@gmail.com"; @@ -23128,6 +23988,13 @@ githubId = 1108325; name = "Théo Zimmermann"; }; + zimward = { + name = "zimward"; + github = "zimward"; + githubId = 96021122; + matrix = "@memoryfragmentation:matrix.org"; + keys = [ { fingerprint = "CBF7 FA5E F4B5 8B68 5977 3E3E 4CAC 61D6 A482 FCD9"; } ]; + }; zlepper = { name = "Rasmus Hansen"; github = "zlepper"; diff --git a/maintainers/scripts/README.md b/maintainers/scripts/README.md index 1af4715b05be..44a5fc9bc590 100644 --- a/maintainers/scripts/README.md +++ b/maintainers/scripts/README.md @@ -9,10 +9,6 @@ What follows is a (very incomplete) overview of available scripts. ## Metadata -### `check-by-name.sh` - -An alias for `pkgs/test/check-by-name/run-local.sh`, see [documentation](../../pkgs/test/check-by-name/README.md). - ### `get-maintainer.sh` `get-maintainer.sh [selector] value` returns a JSON object describing @@ -60,3 +56,16 @@ The maintainer is designated by a `selector` which must be one of: see [`maintainer-list.nix`] for the fields' definition. [`maintainer-list.nix`]: ../maintainer-list.nix + + +## Conventions + +### `sha-to-sri.py` + +`sha-to-sri.py path ...` (atomically) rewrites hash attributes (named `hash` or `sha(1|256|512)`) +into the SRI format: `hash = "{hash name}-{base64 encoded value}"`. + +`path` must point to either a nix file, or a directory which will be automatically traversed. + +`sha-to-sri.py` automatically skips files whose first non-empty line contains `generated by` or `do not edit`. +Moreover, when walking a directory tree, the script will skip files whose name is `yarn.nix` or contains `generated`. diff --git a/maintainers/scripts/build.nix b/maintainers/scripts/build.nix index ca401700b4a6..0783651df8f4 100644 --- a/maintainers/scripts/build.nix +++ b/maintainers/scripts/build.nix @@ -12,7 +12,27 @@ # nix-build build.nix --argstr maintainer --argstr system aarch64-linux let - pkgs = import ./../../default.nix (removeAttrs args [ "maintainer" ]); + # This avoids a common situation for maintainers, where due to Git's behavior of not tracking + # directories, they have an empty directory somewhere in `pkgs/by-name`. Because that directory + # exists, `pkgs/top-level/by-name-overlay.nix` picks it up and attempts to read `package.nix` out + # of it... which doesn't exist, since it's empty. + # + # We don't want to run the code below on every instantiation of `nixpkgs`, as the `pkgs/by-name` + # eval machinery is quite performance sensitive. So we use the internals of the `by-name` overlay + # to implement our own way to avoid an evaluation failure for this script. + # + # See for more motivation for this code block. + overlay = self: super: { + _internalCallByNamePackageFile = + file: if builtins.pathExists file then super._internalCallByNamePackageFile file else null; + }; + + nixpkgsArgs = removeAttrs args [ "maintainer" "overlays" ] // { + overlays = args.overlays or [] ++ [ overlay ]; + }; + + pkgs = import ./../../default.nix nixpkgsArgs; + maintainer_ = pkgs.lib.maintainers.${maintainer}; packagesWith = cond: return: set: (pkgs.lib.flatten diff --git a/maintainers/scripts/check-by-name.sh b/maintainers/scripts/check-by-name.sh index d267ed9352a0..bb24eb6878c0 120000 --- a/maintainers/scripts/check-by-name.sh +++ b/maintainers/scripts/check-by-name.sh @@ -1 +1 @@ -../../pkgs/test/check-by-name/run-local.sh \ No newline at end of file +../../ci/nixpkgs-vet.sh \ No newline at end of file diff --git a/maintainers/scripts/convert-to-import-cargo-lock/shell.nix b/maintainers/scripts/convert-to-import-cargo-lock/shell.nix index fc2e2348309d..2938cf2d0c0b 100644 --- a/maintainers/scripts/convert-to-import-cargo-lock/shell.nix +++ b/maintainers/scripts/convert-to-import-cargo-lock/shell.nix @@ -13,5 +13,5 @@ mkShell { clippy rustfmt ] - ++ lib.optional stdenv.isDarwin pkgs.libiconv; + ++ lib.optional stdenv.hostPlatform.isDarwin pkgs.libiconv; } diff --git a/maintainers/scripts/fetch-kde-qt.sh b/maintainers/scripts/fetch-kde-qt.sh index c43e8ad904d7..b5d49f835038 100755 --- a/maintainers/scripts/fetch-kde-qt.sh +++ b/maintainers/scripts/fetch-kde-qt.sh @@ -156,7 +156,7 @@ files_before=$(grep -c 'src = ' "$SRCS") echo "writing output file $SRCS ..." cat >"$SRCS" < 'List[Encoding]': - return [ c(h) for c in cls.__subclasses__() ] + def all(cls, h) -> "List[Encoding]": + return [c(h) for c in cls.__subclasses__()] def __init__(self, h): self.n = h.digest_size @@ -38,54 +39,56 @@ class Encoding(ABC): @property @abstractmethod - def length(self) -> int: - ... + def length(self) -> int: ... @property def regex(self) -> str: return f"[{self.alphabet}]{{{self.length}}}" @abstractmethod - def decode(self, s: str) -> bytes: - ... + def decode(self, s: str) -> bytes: ... class Nix32(Encoding): alphabet = "0123456789abcdfghijklmnpqrsvwxyz" - inverted = { c: i for i, c in enumerate(alphabet) } + inverted = {c: i for i, c in enumerate(alphabet)} @property def length(self): return 1 + (8 * self.n) // 5 + def decode(self, s: str): assert len(s) == self.length - out = [ 0 for _ in range(self.n) ] - # TODO: Do better than a list of byte-sized ints + out = bytearray(self.n) for n, c in enumerate(reversed(s)): digit = self.inverted[c] i, j = divmod(5 * n, 8) - out[i] = out[i] | (digit << j) & 0xff + out[i] = out[i] | (digit << j) & 0xFF rem = digit >> (8 - j) if rem == 0: continue elif i < self.n: - out[i+1] = rem + out[i + 1] = rem else: raise ValueError(f"Invalid nix32 hash: '{s}'") return bytes(out) + class Hex(Encoding): alphabet = "0-9A-Fa-f" @property def length(self): return 2 * self.n + def decode(self, s: str): from binascii import unhexlify + return unhexlify(s) + class Base64(Encoding): alphabet = "A-Za-z0-9+/" @@ -94,36 +97,39 @@ class Base64(Encoding): """Number of characters in data and padding.""" i, k = divmod(self.n, 3) return 4 * i + (0 if k == 0 else k + 1), (3 - k) % 3 + @property def length(self): return sum(self.format) + @property def regex(self): data, padding = self.format return f"[{self.alphabet}]{{{data}}}={{{padding}}}" + def decode(self, s): from base64 import b64decode + return b64decode(s, validate = True) -_HASHES = (hashlib.new(n) for n in ('SHA-256', 'SHA-512')) -ENCODINGS = { - h.name: Encoding.all(h) - for h in _HASHES -} +_HASHES = (hashlib.new(n) for n in ("SHA-256", "SHA-512")) +ENCODINGS = {h.name: Encoding.all(h) for h in _HASHES} RE = { h: "|".join( - (f"({h}-)?" if e.name == 'base64' else '') + - f"(?P<{h}_{e.name}>{e.regex})" + (f"({h}-)?" if e.name == "base64" else "") + f"(?P<{h}_{e.name}>{e.regex})" for e in encodings - ) for h, encodings in ENCODINGS.items() + ) + for h, encodings in ENCODINGS.items() } -_DEF_RE = re.compile("|".join( - f"(?P<{h}>{h} = (?P<{h}_quote>['\"])({re})(?P={h}_quote);)" - for h, re in RE.items() -)) +_DEF_RE = re.compile( + "|".join( + f"(?P<{h}>{h} = (?P<{h}_quote>['\"])({re})(?P={h}_quote);)" + for h, re in RE.items() + ) +) def defToSRI(s: str) -> str: @@ -153,7 +159,7 @@ def defToSRI(s: str) -> str: @contextmanager def atomicFileUpdate(target: Path): - '''Atomically replace the contents of a file. + """Atomically replace the contents of a file. Guarantees that no temporary files are left behind, and `target` is either left untouched, or overwritten with new content if no exception was raised. @@ -164,18 +170,20 @@ def atomicFileUpdate(target: Path): Upon exiting the context, the files are closed; if no exception was raised, `new` (atomically) replaces the `target`, otherwise it is deleted. - ''' + """ # That's mostly copied from noto-emoji.py, should DRY it out - from tempfile import mkstemp - fd, _p = mkstemp( - dir = target.parent, - prefix = target.name, - ) - tmpPath = Path(_p) + from tempfile import NamedTemporaryFile try: with target.open() as original: - with tmpPath.open('w') as new: + with NamedTemporaryFile( + dir = target.parent, + prefix = target.stem, + suffix = target.suffix, + delete = False, + mode="w", # otherwise the file would be opened in binary mode by default + ) as new: + tmpPath = Path(new.name) yield (original, new) tmpPath.replace(target) @@ -188,37 +196,35 @@ def atomicFileUpdate(target: Path): def fileToSRI(p: Path): with atomicFileUpdate(p) as (og, new): for i, line in enumerate(og): - with log_context(line=i): + with log_context(line = i): new.write(defToSRI(line)) -_SKIP_RE = re.compile( - "(generated by)|(do not edit)", - re.IGNORECASE -) +_SKIP_RE = re.compile("(generated by)|(do not edit)", re.IGNORECASE) +_IGNORE = frozenset({ + "gemset.nix", + "yarn.nix", +}) if __name__ == "__main__": - from sys import argv, stderr + from sys import argv + logger.info("Starting!") - for arg in argv[1:]: - p = Path(arg) - with log_context(path=str(p)): + def handleFile(p: Path, skipLevel = logging.INFO): + with log_context(file = str(p)): try: - if p.name == "yarn.nix" or p.name.find("generated") != -1: - logger.warning("File looks autogenerated, skipping!") - continue - with p.open() as f: for line in f: if line.strip(): break if _SKIP_RE.search(line): - logger.warning("File looks autogenerated, skipping!") - continue + logger.log(skipLevel, "File looks autogenerated, skipping!") + return fileToSRI(p) + except Exception as exn: logger.error( "Unhandled exception, skipping file!", @@ -226,3 +232,19 @@ if __name__ == "__main__": ) else: logger.info("Finished processing file") + + for arg in argv[1:]: + p = Path(arg) + with log_context(arg = arg): + if p.is_file(): + handleFile(p, skipLevel = logging.WARNING) + + elif p.is_dir(): + logger.info("Recursing into directory") + for q in p.glob("**/*.nix"): + if q.is_file(): + if q.name in _IGNORE or q.name.find("generated") != -1: + logger.info("File looks autogenerated, skipping!") + continue + + handleFile(q) diff --git a/maintainers/scripts/update-dotnet-lockfiles.nix b/maintainers/scripts/update-dotnet-lockfiles.nix index 22ceff1ffa99..f9db675418d5 100644 --- a/maintainers/scripts/update-dotnet-lockfiles.nix +++ b/maintainers/scripts/update-dotnet-lockfiles.nix @@ -9,36 +9,40 @@ infrastructure. Regular updates should be done through the individual packages update scripts. */ +{ startWith ? null }: let - pkgs = import ../.. {}; + pkgs = import ../.. { config.allowAliases = false; }; inherit (pkgs) lib; packagesWith = cond: pkgs: let packagesWithInner = attrs: - lib.unique ( - lib.concatLists ( - lib.mapAttrsToList (name: elem: - let - result = builtins.tryEval elem; - in - if result.success then - let - value = result.value; - in - if lib.isDerivation value then - lib.optional (cond value) value - else - if lib.isAttrs value && (value.recurseForDerivations or false || value.recurseForRelease or false) then - packagesWithInner value - else [] - else []) attrs)); + lib.concatLists ( + lib.mapAttrsToList (name: elem: + let + result = builtins.tryEval elem; + in + if result.success then + let + value = result.value; + in + if lib.isDerivation value then + lib.optional (cond value) value + else + if lib.isAttrs value && (value.recurseForDerivations or false || value.recurseForRelease or false) then + packagesWithInner value + else [] + else []) attrs); in packagesWithInner pkgs; - packages = - packagesWith (pkgs: pkgs ? fetch-deps) pkgs; + packages = lib.unique + (lib.filter (p: + (builtins.tryEval p.outPath).success || + builtins.trace "warning: skipping ${p.name} because it failed to evaluate" false) + ((pkgs: (lib.drop (lib.lists.findFirstIndex (p: p.name == startWith) 0 pkgs) pkgs)) + (packagesWith (p: p ? fetch-deps) pkgs))); helpText = '' Please run: diff --git a/maintainers/scripts/update.nix b/maintainers/scripts/update.nix old mode 100755 new mode 100644 diff --git a/maintainers/scripts/update.py b/maintainers/scripts/update.py index 5803ef32f6e7..7d0059db28a7 100644 --- a/maintainers/scripts/update.py +++ b/maintainers/scripts/update.py @@ -12,6 +12,7 @@ import tempfile class CalledProcessError(Exception): process: asyncio.subprocess.Process + stderr: Optional[bytes] class UpdateFailedException(Exception): pass @@ -19,20 +20,23 @@ class UpdateFailedException(Exception): def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) -async def check_subprocess(*args, **kwargs): +async def check_subprocess_output(*args, **kwargs): """ - Emulate check argument of subprocess.run function. + Emulate check and capture_output arguments of subprocess.run function. """ process = await asyncio.create_subprocess_exec(*args, **kwargs) - returncode = await process.wait() + # We need to use communicate() instead of wait(), as the OS pipe buffers + # can fill up and cause a deadlock. + stdout, stderr = await process.communicate() - if returncode != 0: + if process.returncode != 0: error = CalledProcessError() error.process = process + error.stderr = stderr raise error - return process + return stdout async def run_update_script(nixpkgs_root: str, merge_lock: asyncio.Lock, temp_dir: Optional[Tuple[str, str]], package: Dict, keep_going: bool): worktree: Optional[str] = None @@ -43,7 +47,7 @@ async def run_update_script(nixpkgs_root: str, merge_lock: asyncio.Lock, temp_di worktree, _branch = temp_dir # Ensure the worktree is clean before update. - await check_subprocess('git', 'reset', '--hard', '--quiet', 'HEAD', cwd=worktree) + await check_subprocess_output('git', 'reset', '--hard', '--quiet', 'HEAD', cwd=worktree) # Update scripts can use $(dirname $0) to get their location but we want to run # their clones in the git worktree, not in the main nixpkgs repo. @@ -52,7 +56,7 @@ async def run_update_script(nixpkgs_root: str, merge_lock: asyncio.Lock, temp_di eprint(f" - {package['name']}: UPDATING ...") try: - update_process = await check_subprocess( + update_info = await check_subprocess_output( 'env', f"UPDATE_NIX_NAME={package['name']}", f"UPDATE_NIX_PNAME={package['pname']}", @@ -63,8 +67,6 @@ async def run_update_script(nixpkgs_root: str, merge_lock: asyncio.Lock, temp_di stderr=asyncio.subprocess.PIPE, cwd=worktree, ) - update_info = await update_process.stdout.read() - await merge_changes(merge_lock, package, update_info, temp_dir) except KeyboardInterrupt as e: eprint('Cancelling…') @@ -74,10 +76,9 @@ async def run_update_script(nixpkgs_root: str, merge_lock: asyncio.Lock, temp_di eprint() eprint(f"--- SHOWING ERROR LOG FOR {package['name']} ----------------------") eprint() - stderr = await e.process.stderr.read() - eprint(stderr.decode('utf-8')) + eprint(e.stderr.decode('utf-8')) with open(f"{package['pname']}.log", 'wb') as logfile: - logfile.write(stderr) + logfile.write(e.stderr) eprint() eprint(f"--- SHOWING ERROR LOG FOR {package['name']} ----------------------") @@ -101,14 +102,14 @@ async def commit_changes(name: str, merge_lock: asyncio.Lock, worktree: str, bra for change in changes: # Git can only handle a single index operation at a time async with merge_lock: - await check_subprocess('git', 'add', *change['files'], cwd=worktree) + await check_subprocess_output('git', 'add', *change['files'], cwd=worktree) commit_message = '{attrPath}: {oldVersion} -> {newVersion}'.format(**change) if 'commitMessage' in change: commit_message = change['commitMessage'] elif 'commitBody' in change: commit_message = commit_message + '\n\n' + change['commitBody'] - await check_subprocess('git', 'commit', '--quiet', '-m', commit_message, cwd=worktree) - await check_subprocess('git', 'cherry-pick', branch) + await check_subprocess_output('git', 'commit', '--quiet', '-m', commit_message, cwd=worktree) + await check_subprocess_output('git', 'cherry-pick', branch) async def check_changes(package: Dict, worktree: str, update_info: str): if 'commit' in package['supportedFeatures']: @@ -129,12 +130,12 @@ async def check_changes(package: Dict, worktree: str, update_info: str): if 'newVersion' not in changes[0]: attr_path = changes[0]['attrPath'] - obtain_new_version_process = await check_subprocess('nix-instantiate', '--expr', f'with import ./. {{}}; lib.getVersion {attr_path}', '--eval', '--strict', '--json', stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=worktree) - changes[0]['newVersion'] = json.loads((await obtain_new_version_process.stdout.read()).decode('utf-8')) + obtain_new_version_output = await check_subprocess_output('nix-instantiate', '--expr', f'with import ./. {{}}; lib.getVersion {attr_path}', '--eval', '--strict', '--json', stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=worktree) + changes[0]['newVersion'] = json.loads(obtain_new_version_output.decode('utf-8')) if 'files' not in changes[0]: - changed_files_process = await check_subprocess('git', 'diff', '--name-only', 'HEAD', stdout=asyncio.subprocess.PIPE, cwd=worktree) - changed_files = (await changed_files_process.stdout.read()).splitlines() + changed_files_output = await check_subprocess_output('git', 'diff', '--name-only', 'HEAD', stdout=asyncio.subprocess.PIPE, cwd=worktree) + changed_files = changed_files_output.splitlines() changes[0]['files'] = changed_files if len(changed_files) == 0: @@ -176,8 +177,8 @@ async def start_updates(max_workers: int, keep_going: bool, commit: bool, packag # Do not create more workers than there are packages. num_workers = min(max_workers, len(packages)) - nixpkgs_root_process = await check_subprocess('git', 'rev-parse', '--show-toplevel', stdout=asyncio.subprocess.PIPE) - nixpkgs_root = (await nixpkgs_root_process.stdout.read()).decode('utf-8').strip() + nixpkgs_root_output = await check_subprocess_output('git', 'rev-parse', '--show-toplevel', stdout=asyncio.subprocess.PIPE) + nixpkgs_root = nixpkgs_root_output.decode('utf-8').strip() # Set up temporary directories when using auto-commit. for i in range(num_workers): diff --git a/maintainers/team-list.nix b/maintainers/team-list.nix index 7ed03296204c..1821660a506d 100644 --- a/maintainers/team-list.nix +++ b/maintainers/team-list.nix @@ -183,6 +183,16 @@ with lib.maintainers; githubTeams = [ "cuda-maintainers" ]; }; + cyberus = { + # Verify additions by approval of an already existing member of the team. + members = [ + xanderio + blitz + ]; + scope = "Team for Cyberus Technology employees who collectively maintain packages."; + shortName = "Cyberus Technology employees"; + }; + darwin = { members = [ toonn ]; githubTeams = [ "darwin-maintainers" ]; @@ -268,7 +278,11 @@ with lib.maintainers; }; emacs = { - members = [ adisbladis ]; + members = [ + AndersonTorres + adisbladis + linj + ]; scope = "Maintain the Emacs editor and packages."; shortName = "Emacs"; }; @@ -315,6 +329,7 @@ with lib.maintainers; leona osnyx ma27 + laalsaas ]; scope = "Team for Flying Circus employees who collectively maintain packages."; shortName = "Flying Circus employees"; @@ -484,7 +499,6 @@ with lib.maintainers; ryantm lassulus yayayayaka - asymmetric ]; scope = "Maintain Jitsi."; shortName = "Jitsi"; @@ -504,10 +518,10 @@ with lib.maintainers; githubTeams = [ "k3s" ]; members = [ euank + frederictobiasc marcusramberg mic92 rorosen - superherointj wrmilling yajo ]; @@ -554,6 +568,7 @@ with lib.maintainers; linux-kernel = { members = [ TredwellGit + k900 ma27 nequissimus qyliss @@ -733,6 +748,16 @@ with lib.maintainers; enableFeatureFreezePing = true; }; + ngi = { + members = [ + eljamm + fricklerhandwerk + wegank + ]; + scope = "Maintain NGI-supported software."; + shortName = "NGI"; + }; + node = { members = [ winter ]; scope = "Maintain Node.js runtimes and build tooling."; @@ -752,6 +777,7 @@ with lib.maintainers; members = [ SuperSandro2000 anthonyroussel + vinetos ]; scope = "Maintain the ecosystem around OpenStack"; shortName = "OpenStack"; @@ -780,7 +806,11 @@ with lib.maintainers; }; perl = { - members = [ sgo ]; + members = [ + sgo + marcusramberg + zakame + ]; scope = "Maintain the Perl interpreter and Perl packages."; shortName = "Perl"; enableFeatureFreezePing = true; @@ -936,7 +966,6 @@ with lib.maintainers; steam = { members = [ atemu - eclairevoyant k900 mkg20001 ]; @@ -947,7 +976,6 @@ with lib.maintainers; stridtech = { # Verify additions by approval of an already existing member of the team members = [ - superherointj ulrikstrid ]; scope = "Group registration for Strid Tech AB team members who collectively maintain packages"; @@ -1007,6 +1035,19 @@ with lib.maintainers; shortName = "WDZ GmbH"; }; + xen = { + members = [ + hehongbo + lach + rane + sigmasquadron + ]; + scope = "Maintain the Xen Project Hypervisor and the related tooling ecosystem."; + shortName = "Xen Project Hypervisor"; + enableFeatureFreezePing = true; + githubTeams = [ "xen-project" ]; + }; + xfce = { members = [ bobby285271 diff --git a/nixos/README.md b/nixos/README.md index 5f751e10e20a..2261803f4e7d 100644 --- a/nixos/README.md +++ b/nixos/README.md @@ -80,6 +80,7 @@ Reviewing process: - Ensure that all file paths [fit the guidelines](../CONTRIBUTING.md#file-naming-and-organisation). - Ensure that the module tests, if any, are succeeding. +- Ensure that new module tests are added to the package `passthru.tests`. - Ensure that the introduced options are correct. - Type should be appropriate (string related types differs in their merging capabilities, `loaOf` and `string` types are deprecated). - Description, default and example should be provided. @@ -95,7 +96,8 @@ Sample template for a new module review is provided below. ##### Reviewed points - [ ] module path fits the guidelines -- [ ] module tests succeed on ARCHITECTURE +- [ ] module tests, if any, succeed on ARCHITECTURE +- [ ] module tests, if any, are added to package `passthru.tests` - [ ] options have appropriate types - [ ] options have default - [ ] options have example diff --git a/nixos/doc/manual/configuration/linux-kernel.chapter.md b/nixos/doc/manual/configuration/linux-kernel.chapter.md index 3bc97446f452..4aeda5f46764 100644 --- a/nixos/doc/manual/configuration/linux-kernel.chapter.md +++ b/nixos/doc/manual/configuration/linux-kernel.chapter.md @@ -133,20 +133,3 @@ This section was moved to the [Nixpkgs manual](https://nixos.org/nixpkgs/manual# It's a common issue that the latest stable version of ZFS doesn't support the latest available Linux kernel. It is recommended to use the latest available LTS that's compatible with ZFS. Usually this is the default kernel provided by nixpkgs (i.e. `pkgs.linuxPackages`). - -Alternatively, it's possible to pin the system to the latest available kernel -version _that is supported by ZFS_ like this: - -```nix -{ - boot.kernelPackages = pkgs.zfs.latestCompatibleLinuxPackages; -} -``` - -Please note that the version this attribute points to isn't monotonic because the latest kernel -version only refers to kernel versions supported by the Linux developers. In other words, -the latest kernel version that ZFS is compatible with may decrease over time. - -An example: the latest version ZFS is compatible with is 5.19 which is a non-longterm version. When 5.19 -is out of maintenance, the latest supported kernel version is 5.15 because it's longterm and the versions -5.16, 5.17 and 5.18 are already out of maintenance because they're non-longterm. diff --git a/nixos/doc/manual/configuration/profiles/minimal.section.md b/nixos/doc/manual/configuration/profiles/minimal.section.md index 76d9585a0bd3..5b72112477f7 100644 --- a/nixos/doc/manual/configuration/profiles/minimal.section.md +++ b/nixos/doc/manual/configuration/profiles/minimal.section.md @@ -1,8 +1,6 @@ # Minimal {#sec-profile-minimal} This profile defines a small NixOS configuration. It does not contain any -graphical stuff. It's a very short file that enables -[noXlibs](#opt-environment.noXlibs), sets -[](#opt-i18n.supportedLocales) to -only support the user-selected locale, -and [disables packages' documentation](#opt-documentation.enable). +graphical stuff. It's a very short file that sets [](#opt-i18n.supportedLocales) +to only support the user-selected locale, and +[disables packages' documentation](#opt-documentation.enable). diff --git a/nixos/doc/manual/configuration/profiles/perlless.section.md b/nixos/doc/manual/configuration/profiles/perlless.section.md index bf055971cfc4..9ee70ed3b49c 100644 --- a/nixos/doc/manual/configuration/profiles/perlless.section.md +++ b/nixos/doc/manual/configuration/profiles/perlless.section.md @@ -1,11 +1,5 @@ # Perlless {#sec-perlless} -::: {.warning} -If you enable this profile, you will NOT be able to switch to a new -configuration and thus you will not be able to rebuild your system with -nixos-rebuild! -::: - Render your system completely perlless (i.e. without the perl interpreter). This includes a mechanism so that your build fails if it contains a Nix store path that references the string "perl". diff --git a/nixos/doc/manual/configuration/user-mgmt.chapter.md b/nixos/doc/manual/configuration/user-mgmt.chapter.md index 7d83121d41e0..2edca78f4a38 100644 --- a/nixos/doc/manual/configuration/user-mgmt.chapter.md +++ b/nixos/doc/manual/configuration/user-mgmt.chapter.md @@ -100,6 +100,9 @@ modified using `usermod`. Unix groups can be managed using `groupadd`, ::: {.note} This is experimental. + +Please consider using [Userborn](#sec-userborn) over systemd-sysusers as it's +more feature complete. ::: Instead of using a custom perl script to create users and groups, you can use @@ -112,3 +115,43 @@ systemd-sysusers: ``` The primary benefit of this is to remove a dependency on perl. + +## Manage users and groups with `userborn` {#sec-userborn} + +::: {.note} +This is experimental. +::: + +Like systemd-sysusers, Userborn adoesn't depend on Perl but offers some more +advantages over systemd-sysusers: + +1. It can create "normal" users (with a GID >= 1000). +2. It can update some information about users. Most notably it can update their + passwords. +3. It will warn when users use an insecure or unsupported password hashing + scheme. + +Userborn is the recommended way to manage users if you don't want to rely on +the Perl script. It aims to eventually replace the Perl script by default. + +You can enable Userborn via: + +```nix +services.userborn.enable = true; +``` + +You can configure Userborn to store the password files +(`/etc/{group,passwd,shadow}`) outside of `/etc` and symlink them from this +location to `/etc`: + +```nix +services.userborn.passwordFilesLocation = "/persistent/etc"; +``` + +This is useful when you store `/etc` on a `tmpfs` or if `/etc` is immutable +(e.g. when using `system.etc.overlay.mutable = false;`). In the latter case the +original files are by default stored in `/var/lib/nixos`. + +Userborn implements immutable users by re-mounting the password files +read-only. This means that unlike when using the Perl script, trying to add a +new user (e.g. via `useradd`) will fail right away. diff --git a/nixos/doc/manual/development/settings-options.section.md b/nixos/doc/manual/development/settings-options.section.md index cedc82d32f89..48cc62bb424c 100644 --- a/nixos/doc/manual/development/settings-options.section.md +++ b/nixos/doc/manual/development/settings-options.section.md @@ -46,6 +46,237 @@ have a predefined type and string generator already declared under `generate` to build a Java `.properties` file, taking care of the correct escaping, etc. +`pkgs.formats.hocon` { *`generator`* ? ``, *`validator`* ? ``, *`doCheck`* ? true } + +: A function taking an attribute set with values + + `generator` + + : A derivation used for converting the JSON output + from the nix settings into HOCON. This might be + useful if your HOCON variant is slightly different + from the java-based one, or for testing purposes. + + `validator` + + : A derivation used for verifying that the HOCON + output is correct and parsable. This might be + useful if your HOCON variant is slightly different + from the java-based one, or for testing purposes. + + `doCheck` + + : Whether to enable/disable the validator check. + + It returns an attrset with a `type`, `generate` function, + and a `lib` attset, as specified [below](#pkgs-formats-result). + Some of the lib functions will be best understood if you have + read the reference specification. You can find this + specification here: + + + + Inside of `lib`, you will find these functions + + `mkInclude` + + : This is used together with a specially named + attribute `includes`, to include other HOCON + sources into the document. + + The function has a shorthand variant where it + is up to the HOCON parser to figure out what type + of include is being used. The include will default + to being non-required. If you want to be more + explicit about the details of the include, you can + provide an attrset with following arguments + + `required` + + : Whether the parser should fail upon failure + to include the document + + `type` + + : Type of the source of the included document. + Valid values are `file`, `url` and `classpath`. + See upstream documentation for the semantics + behind each value + + `value` + + : The URI/path/classpath pointing to the source of + the document to be included. + + `Example usage:` + + ```nix + let + format = pkgs.formats.hocon { }; + hocon_file = pkgs.writeText "to_include.hocon" '' + a = 1; + ''; + in { + some.nested.hocon.attrset = { + _includes = [ + (format.lib.mkInclude hocon_file) + (format.lib.mkInclude "https://example.com/to_include.hocon") + (format.lib.mkInclude { + required = true; + type = "file"; + value = include_file; + }) + ]; + ... + }; + } + ``` + + `mkAppend` + + : This is used to invoke the `+=` operator. + This can be useful if you need to add something + to a list that is included from outside of nix. + See upstream documentation for the semantics + behind the `+=` operation. + + `Example usage:` + + ```nix + let + format = pkgs.formats.hocon { }; + hocon_file = pkgs.writeText "to_include.hocon" '' + a = [ 1 ]; + b = [ 2 ]; + ''; + in { + _includes = [ + (format.lib.mkInclude hocon_file) + ]; + + c = 3; + a = format.lib.mkAppend 3; + b = format.lib.mkAppend (format.lib.mkSubstitution "c"); + } + ``` + + `mkSubstitution` + + : This is used to make HOCON substitutions. + Similarly to `mkInclude`, this function has + a shorthand variant where you just give it + the string with the substitution value. + The substitution is not optional by default. + Alternatively, you can provide an attrset + with more options + + `optional` + + : Whether the parser should fail upon + failure to fetch the substitution value. + + `value` + + : The name of the variable to use for + substitution. + + See upstream documentation for semantics + behind the substitution functionality. + + `Example usage:` + + ```nix + let + format = pkgs.formats.hocon { }; + in { + a = 1; + b = format.lib.mkSubstitution "a"; + c = format.lib.mkSubstition "SOME_ENVVAR"; + d = format.lib.mkSubstition { + value = "SOME_OPTIONAL_ENVVAR"; + optional = true; + }; + } + ``` + + `Implementation notes:` + + - classpath includes are not implemented in pyhocon, + which is used for validating the HOCON output. This + means that if you are using classpath includes, + you will want to either use an alternative validator + or set `doCheck = false` in the format options. + +`pkgs.formats.libconfig` { *`generator`* ? ``, *`validator`* ? `` } + +: A function taking an attribute set with values + + `generator` + + : A derivation used for converting the JSON output + from the nix settings into libconfig. This might be + useful if your libconfig variant is slightly different + from the original one, or for testing purposes. + + `validator` + + : A derivation used for verifying that the libconfig + output is correct and parsable. This might be + useful if your libconfig variant is slightly different + from the original one, or for testing purposes. + + It returns an attrset with a `type`, `generate` function, + and a `lib` attset, as specified [below](#pkgs-formats-result). + Some of the lib functions will be best understood if you have + read the reference specification. You can find this + specification here: + + + + Inside of `lib`, you will find these functions + + `mkHex`, `mkOctal`, `mkFloat` + + : Use these to specify numbers in other formats. + + `Example usage:` + + ```nix + let + format = pkgs.formats.libconfig { }; + in { + myHexValue = format.lib.mkHex "0x1FC3"; + myOctalValue = format.lib.mkOctal "0027"; + myFloatValue = format.lib.mkFloat "1.2E-3"; + } + ``` + + `mkArray`, `mkList` + + : Use these to differentiate between whether + a nix list should be considered as a libconfig + array or a libconfig list. See the upstream + documentation for the semantics behind these types. + + `Example usage:` + + ```nix + let + format = pkgs.formats.libconfig { }; + in { + myList = format.lib.mkList [ "foo" 1 true ]; + myArray = format.lib.mkArray [ 1 2 3 ]; + } + ``` + + `Implementation notes:` + + - Since libconfig does not allow setting names to start with an underscore, + this is used as a prefix for both special types and include directives. + + - The difference between 32bit and 64bit values became optional in libconfig + 1.5, so we assume 64bit values for all numbers. + `pkgs.formats.json` { } : A function taking an empty attribute set (for future extensibility) diff --git a/nixos/doc/manual/development/testing-installer.chapter.md b/nixos/doc/manual/development/testing-installer.chapter.md index 2eaa01614920..92c759a8559a 100644 --- a/nixos/doc/manual/development/testing-installer.chapter.md +++ b/nixos/doc/manual/development/testing-installer.chapter.md @@ -6,13 +6,13 @@ tedious, so here is a quick way to see if the installer works properly: ```ShellSession # mount -t tmpfs none /mnt # nixos-generate-config --root /mnt -$ nix-build '' -A config.system.build.nixos-install +$ nix-build '' -A nixos-install # ./result/bin/nixos-install ``` To start a login shell in the new NixOS installation in `/mnt`: ```ShellSession -$ nix-build '' -A config.system.build.nixos-enter +$ nix-build '' -A nixos-enter # ./result/bin/nixos-enter ``` diff --git a/nixos/doc/manual/installation/changing-config.chapter.md b/nixos/doc/manual/installation/changing-config.chapter.md index 07a0074d17e7..192696b74171 100644 --- a/nixos/doc/manual/installation/changing-config.chapter.md +++ b/nixos/doc/manual/installation/changing-config.chapter.md @@ -5,12 +5,13 @@ configuration of your machine. Whenever you've [changed something](#ch-configuration) in that file, you should do ```ShellSession -# nixos-rebuild switch +$ nixos-rebuild switch --use-remote-sudo ``` -to build the new configuration, make it the default configuration for -booting, and try to realise the configuration in the running system -(e.g., by restarting system services). +to build the new configuration as your current user, and as the root user, +make it the default configuration for booting. `switch` will also try to +realise the configuration in the running system (e.g., by restarting system +services). ::: {.warning} This command doesn't start/stop [user services](#opt-systemd.user.services) @@ -19,14 +20,23 @@ user services. ::: ::: {.warning} -These commands must be executed as root, so you should either run them -from a root shell or by prefixing them with `sudo -i`. +Applying a configuration is an action that must be done by the root user, so the +`switch`, `boot` and `test` commands should be ran with the `--use-remote-sudo` +flag. Despite its odd name, this flag runs the activation script with elevated +permissions, regardless of whether or not the target system is remote, without +affecting the other stages of the `nixos-rebuild` call. This allows unprivileged +users to rebuild the system and only elevate their permissions when necessary. + +Alternatively, one can run the whole command as root while preserving user +environment variables by prefixing the command with `sudo -E`. However, this +method may create root-owned files in `$HOME/.cache` if Nix decides to use the +cache during evaluation. ::: You can also do ```ShellSession -# nixos-rebuild test +$ nixos-rebuild test --use-remote-sudo ``` to build the configuration and switch the running system to it, but @@ -37,7 +47,7 @@ configuration. There is also ```ShellSession -# nixos-rebuild boot +$ nixos-rebuild boot --use-remote-sudo ``` to build the configuration and make it the boot default, but not switch @@ -47,7 +57,7 @@ You can make your configuration show up in a different submenu of the GRUB 2 boot screen by giving it a different *profile name*, e.g. ```ShellSession -# nixos-rebuild switch -p test +$ nixos-rebuild switch -p test --use-remote-sudo ``` which causes the new configuration (and previous ones created using @@ -58,7 +68,7 @@ configurations. A repl, or read-eval-print loop, is also available. You can inspect your configuration and use the Nix language with ```ShellSession -# nixos-rebuild repl +$ nixos-rebuild repl ``` Your configuration is loaded into the `config` variable. Use tab for autocompletion, use the `:r` command to reload the configuration files. See `:?` or [`nix repl` in the Nix manual](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-repl.html) to learn more. diff --git a/nixos/doc/manual/installation/installing.chapter.md b/nixos/doc/manual/installation/installing.chapter.md index 9f3ff2ac6bac..b927c7c0e877 100644 --- a/nixos/doc/manual/installation/installing.chapter.md +++ b/nixos/doc/manual/installation/installing.chapter.md @@ -220,6 +220,8 @@ The NixOS installer ships with multiple partitioning tools. The examples below use `parted`, but also provides `fdisk`, `gdisk`, `cfdisk`, and `cgdisk`. +Use the command 'lsblk' to find the name of your 'disk' device. + The recommended partition scheme differs depending if the computer uses *Legacy Boot* or *UEFI*. @@ -496,6 +498,12 @@ Use the following commands: Retype new password: *** ``` + If you have a user account declared in your `configuration.nix` and plan to log in using this user, set a password before rebooting, e.g. for the `alice` user: + + ```ShellSession + # nixos-enter --root /mnt -c 'passwd alice' + ``` + ::: {.note} For unattended installations, it is possible to use `nixos-install --no-root-passwd` in order to disable the password @@ -515,15 +523,13 @@ Use the following commands: menu. This allows you to easily roll back to a previous configuration if something goes wrong. - You should log in and change the `root` password with `passwd`. + Use your declared user account to log in. + If you didn’t declare one, you should still be able to log in using the `root` user. - You'll probably want to create some user accounts as well, which can - be done with `useradd`: - - ```ShellSession - $ useradd -c 'Eelco Dolstra' -m eelco - $ passwd eelco - ``` + ::: {.note} + Some graphical display managers such as SDDM do not allow `root` login by default, so you might need to switch to TTY. + Refer to [](#sec-user-management) for details on declaring user accounts. + ::: You may also want to install some software. This will be covered in [](#sec-package-management). diff --git a/nixos/doc/manual/release-notes/rl-2009.section.md b/nixos/doc/manual/release-notes/rl-2009.section.md index 900c20dbe717..d128696b2570 100644 --- a/nixos/doc/manual/release-notes/rl-2009.section.md +++ b/nixos/doc/manual/release-notes/rl-2009.section.md @@ -120,7 +120,7 @@ In addition to 1119 new, 118 updated, and 476 removed options; 61 new modules we - Services: - - [services.ankisyncd.enable](options.html#opt-services.ankisyncd.enable) Anki sync server + - `services.ankisyncd.enable` Anki sync server - [services.bazarr.enable](options.html#opt-services.bazarr.enable) Subtitle manager for Sonarr and Radarr diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md index e729fdcbb139..2f869b07e072 100644 --- a/nixos/doc/manual/release-notes/rl-2205.section.md +++ b/nixos/doc/manual/release-notes/rl-2205.section.md @@ -85,7 +85,7 @@ In addition to numerous new and upgraded packages, this release has the followin - [filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html), a lightweight shipper for forwarding and centralizing log data. Available as [services.filebeat](#opt-services.filebeat.enable). -- [FRRouting](https://frrouting.org/), a popular suite of Internet routing protocol daemons (BGP, BFD, OSPF, IS-IS, VRRP and others). Available as [services.frr](#opt-services.frr.babel.enable). +- [FRRouting](https://frrouting.org/), a popular suite of Internet routing protocol daemons (BGP, BFD, OSPF, IS-IS, VRRP and others). Available as [services.frr](#opt-services.frr.babeld.enable). - [Grafana Mimir](https://grafana.com/oss/mimir/), an open source, horizontally scalable, highly available, multi-tenant, long-term storage for Prometheus. Available as [services.mimir](#opt-services.mimir.enable). diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md index f5d1d3016a78..cae573c3452a 100644 --- a/nixos/doc/manual/release-notes/rl-2305.section.md +++ b/nixos/doc/manual/release-notes/rl-2305.section.md @@ -252,7 +252,7 @@ In addition to numerous new and updated packages, this release has the following } ``` -- The default module options for [services.snapserver.openFirewall](#opt-services.snapserver.openFirewall), [services.tmate-ssh-server.openFirewall](#opt-services.tmate-ssh-server.openFirewall) and [services.unifi-video.openFirewall](#opt-services.unifi-video.openFirewall) have been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall. +- The default module options for [services.snapserver.openFirewall](#opt-services.snapserver.openFirewall), [services.tmate-ssh-server.openFirewall](#opt-services.tmate-ssh-server.openFirewall) and `services.unifi-video.openFirewall` have been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall. - The option `i18n.inputMethod.fcitx5.enableRimeData` has been removed. Default RIME data is now included in `fcitx5-rime` by default, and can be customized using diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index 0fd5f802d249..e8879e746a03 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -661,8 +661,7 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2 Cheese as the default camera application, and Photos will no longer be installed. -- The module [services.ankisyncd](#opt-services.ankisyncd.package) has been - switched to +- The module `services.ankisyncd` has been switched to [anki-sync-server-rs](https://github.com/ankicommunity/anki-sync-server-rs). The former version written in Python was difficult to update, did not receive updates in a while, and did not support recent versions of Anki. diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 3bb993ec33c6..158257f20a7a 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -62,7 +62,7 @@ In addition to numerous new and upgraded packages, this release has the followin - [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable). -The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the ankisyncd software. +The pre-existing `services.ankisyncd` has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the ankisyncd software. - [ALVR](https://github.com/alvr-org/alvr), a VR desktop streamer. Available as [programs.alvr](#opt-programs.alvr.enable). diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index 1c287414435d..371d338a3418 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -4,6 +4,23 @@ ## Highlights {#sec-release-24.11-highlights} +- **This will be the last release of Nixpkgs to support macOS Sierra 10.12 to macOS Catalina 10.15.** + Starting with release 25.05, the minimum supported version will be macOS Big Sur 11, and we cannot guarantee that packages will continue to work on older versions of macOS. + Users on old macOS versions should consider upgrading to a supported version (potentially using [OpenCore Legacy Patcher](https://dortania.github.io/OpenCore-Legacy-Patcher/) for old hardware) or installing NixOS. + If neither of those options are viable and you require new versions of software, [MacPorts](https://www.macports.org/) supports back to Mac OS X Snow Leopard 10.6. +- Nix was updated to 2.24, which brings a lot of improvements and fixes. See the release notes for + [2.19](https://nix.dev/manual/nix/latest/release-notes/rl-2.19), + [2.20](https://nix.dev/manual/nix/latest/release-notes/rl-2.20), + [2.21](https://nix.dev/manual/nix/latest/release-notes/rl-2.21), + [2.22](https://nix.dev/manual/nix/latest/release-notes/rl-2.22), + [2.23](https://nix.dev/manual/nix/latest/release-notes/rl-2.23), + [2.24](https://nix.dev/manual/nix/latest/release-notes/rl-2.24). + Notable changes include improvements to Git fetching, documentation comment support in `nix-repl> :doc`, as well as many quality of life improvements. + +- This will be the last release of Nixpkgs to support versions of CUDA prior to CUDA 12.0. + These versions only work with old compiler versions that will be unsupported by the time of the Nixpkgs 25.05 release. + In future, users should expect CUDA versions to be dropped as the compiler versions they require leave upstream support windows. + - Convenience options for `amdgpu`, open source driver for Radeon cards, is now available under `hardware.amdgpu`. - [AMDVLK](https://github.com/GPUOpen-Drivers/AMDVLK), AMD's open source Vulkan driver, is now available to be configured as `hardware.amdgpu.amdvlk` option. @@ -25,22 +42,68 @@ Users can use it by `services.displayManager.ly.enable` and config it by `services.displayManager.ly.settings` to generate `/etc/ly/config.ini` -## New Services {#sec-release-24.11-new-services} +- The default sound server for most graphical sessions has been switched from PulseAudio to PipeWire. + Users that want to keep PulseAudio will want to set `services.pipewire.enable = false;` and `hardware.pulseaudio.enable = true;`. + There is currently no plan to fully deprecate and remove PulseAudio, however, PipeWire should generally be preferred for new installs. -- [TaskChampion Sync-Server](https://github.com/GothenburgBitFactory/taskchampion-sync-server), a [Taskwariror 3](https://taskwarrior.org/docs/upgrade-3/) sync server, replacing Taskwarrior 2's sync server named [`taskserver`](https://github.com/GothenburgBitFactory/taskserver). +- The Rust rewrite of the `switch-to-configuration` program is now used for system activation by default. + If you experience any issues, please report them. + The original Perl script can still be used for now by setting `system.switch.enableNg` to `false`. + +- Support for mounting filesystems from block devices protected with [dm-verity](https://docs.kernel.org/admin-guide/device-mapper/verity.html) + was added through the `boot.initrd.systemd.dmVerity` option. + +- The [Xen Project Hypervisor](https://xenproject.org) is once again available as a virtualisation option under [`virtualisation.xen`](#opt-virtualisation.xen.enable). + - This release includes Xen [4.19.0](https://wiki.xenproject.org/wiki/Xen_Project_4.19_Release_Notes) and support for booting the hypervisor on EFI systems. + ::: {.warning} + Booting into the Xen Project Hypervisor through a legacy BIOS bootloader or with the legacy script-based Stage 1 initrd have been **deprecated**. Only EFI booting and the new systemd-based Stage 1 initrd are supported. + ::: + - The `qemu-xen-traditional` component has been deprecated by the upstream Xen Project, and is no longer included in the Xen build. + - The OCaml-based Xen Store can now be configured using [`virtualisation.xen.store.settings`](#opt-virtualisation.xen.store.settings). + - The `virtualisation.xen.bridge` options have been deprecated in this release cycle. Users who need network bridges are encouraged to set up their own networking configurations. + +- A new option [`systemd.enableStrictShellChecks`](#opt-systemd.enableStrictShellChecks) has been added. When enabled, all systemd scripts generated by NixOS will + be checked with [shellcheck](https://www.shellcheck.net) and any errors or warnings will cause the build to fail. + This affects all scripts that have been created through the `script`, `reload`, `preStart`, `postStart`, `preStop` and `postStop` options for systemd services. + This does not affect commandlines passed directly to `ExecStart`, `ExecReload`, `ExecStartPre`, `ExecStartPost`, `ExecStop` or `ExecStopPost`. + It therefore also does not affect systemd units that are coming from packages and that are not defined through the NixOS config. + This option is disabled by default, and although some services have already been fixed, it is still likely that you will encounter build failures when enabling this. + We encourage people to enable this option when they are willing and able to submit fixes for potential build failures to nixpkgs. + The option can also be enabled or disabled for individual services using the `enableStrictShellChecks` option on the service itself, which will take precedence over the global setting. + +## New Modules {#sec-release-24.11-new-modules} + +- [TaskChampion Sync-Server](https://github.com/GothenburgBitFactory/taskchampion-sync-server), a [Taskwarrior 3](https://taskwarrior.org/docs/upgrade-3/) sync server, replacing Taskwarrior 2's sync server named [`taskserver`](https://github.com/GothenburgBitFactory/taskserver). - [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr), proxy server to bypass Cloudflare protection. Available as [services.flaresolverr](#opt-services.flaresolverr.enable) service. +- [Gancio](https://gancio.org/), a shared agenda for local communities. Available as [services.gancio](#opt-services.gancio.enable). + - [Goatcounter](https://www.goatcounter.com/), Easy web analytics. No tracking of personal data. Available as [services.goatcounter](options.html#opt-services.goatcocunter.enable). +- [Privatebin](https://github.com/PrivateBin/PrivateBin/), A minimalist, open source online pastebin where the server has zero knowledge of pasted data. Available as [services.privatebin](#opt-services.privatebin.enable) + +- [UWSM](https://github.com/Vladimir-csp/uwsm), a wayland session manager to wrap Wayland Compositors into useful systemd units such as `graphical-session.target`. Available as [programs.uwsm](#opt-programs.uwsm.enable). + - [Open-WebUI](https://github.com/open-webui/open-webui), a user-friendly WebUI for LLMs. Available as [services.open-webui](#opt-services.open-webui.enable) service. - [Quickwit](https://quickwit.io), sub-second search & analytics engine on cloud storage. Available as [services.quickwit](options.html#opt-services.quickwit). +- [Userborn](https://github.com/nikstur/userborn), a service for declarative + user management. This can be used instead of the `update-users-groups.pl` + Perl script and instead of systemd-sysusers. To achieve a system without + Perl, this is the now recommended tool over systemd-sysusers because it can + also create normal users and change passwords. Available as + [services.userborn](#opt-services.userborn.enable) + +- [Hatsu](https://github.com/importantimport/hatsu), a self-hosted bridge that interacts with Fediverse on behalf of your static site. Available as [services.hatsu](options.html#opt-services.hatsu). + - [Flood](https://flood.js.org/), a beautiful WebUI for various torrent clients. Available as [services.flood](options.html#opt-services.flood). +- [Firefly-iii Data Importer](https://github.com/firefly-iii/data-importer), a data importer for Firefly-III. Available as [services.firefly-iii-data-importer](options.html#opt-services.firefly-iii-data-importer) + - [QGroundControl], a ground station support and configuration manager for the PX4 and APM Flight Stacks. Available as [programs.qgroundcontrol](options.html#opt-programs.qgroundcontrol.enable). - [Eintopf](https://eintopf.info), community event and calendar web application. Available as [services.eintopf](options.html#opt-services.eintopf). @@ -49,9 +112,11 @@ - [ddns-updater](https://github.com/qdm12/ddns-updater), a service to update DNS records periodically with WebUI for many DNS providers. Available as [services.ddns-updater](#opt-services.ddns-updater.enable). -- [Immersed VR](https://immersed.com/), a closed-source coworking platform. Available as [programs.immersed-vr](#opt-programs.immersed-vr.enable). +- [Immersed](https://immersed.com/), a closed-source coworking platform. Available as [programs.immersed](#opt-programs.immersed.enable). -- [HomeBox](https://github.com/hay-kot/homebox/): the inventory and organization system built for the Home User. Available as [services.homebox](#opt-services.homebox.enable). +- [HomeBox](https://github.com/sysadminsmedia/homebox): the inventory and organization system built for the Home User. Available as [services.homebox](#opt-services.homebox.enable). + +- [matrix-hookshot](https://matrix-org.github.io/matrix-hookshot), a Matrix bot for connecting to external services. Available as [services.matrix-hookshot](#opt-services.matrix-hookshot.enable). - [Renovate](https://github.com/renovatebot/renovate), a dependency updating tool for various git forges and language ecosystems. Available as [services.renovate](#opt-services.renovate.enable). @@ -59,6 +124,8 @@ - [zeronsd](https://github.com/zerotier/zeronsd), a DNS server for ZeroTier users. Available with [services.zeronsd.servedNetworks](#opt-services.zeronsd.servedNetworks). +- [Collabora Online](https://www.collaboraonline.com/), a collaborative online office suite based on LibreOffice technology. Available as [services.collabora-online](options.html#opt-services.collabora-online.enable). + - [wg-access-server](https://github.com/freifunkMUC/wg-access-server/), an all-in-one WireGuard VPN solution with a web ui for connecting devices. Available at [services.wg-access-server](#opt-services.wg-access-server.enable). - [Pingvin Share](https://github.com/stonith404/pingvin-share), a self-hosted file sharing platform and an alternative for WeTransfer. Available as [services.pingvin-share](#opt-services.pingvin-share.enable). @@ -67,12 +134,16 @@ - [Localsend](https://localsend.org/), an open source cross-platform alternative to AirDrop. Available as [programs.localsend](#opt-programs.localsend.enable). +- [Gatus](https://github.com/TwiN/gatus), an automated developer-oriented status page. Available as [services.gatus](#opt-services.gatus.enable). + - [cryptpad](https://cryptpad.org/), a privacy-oriented collaborative platform (docs/drive/etc), has been added back. Available as [services.cryptpad](#opt-services.cryptpad.enable). - [realm](https://github.com/zhboner/realm), a simple, high performance relay server written in rust. Available as [services.realm.enable](#opt-services.realm.enable). - [Gotenberg](https://gotenberg.dev), an API server for converting files to PDFs that can be used alongside Paperless-ngx. Available as [services.gotenberg](options.html#opt-services.gotenberg). +- [Suricata](https://suricata.io/), a free and open source, mature, fast and robust network threat detection engine. Available as [services.suricata](options.html#opt-services.suricata). + - [Playerctld](https://github.com/altdesktop/playerctl), a daemon to track media player activity. Available as [services.playerctld](option.html#opt-services.playerctld). - [MenhirLib](https://gitlab.inria.fr/fpottier/menhir/-/tree/master/coq-menhirlib) A support library for verified Coq parsers produced by Menhir. @@ -97,16 +168,65 @@ - [bitmagnet](https://bitmagnet.io/), A self-hosted BitTorrent indexer, DHT crawler, content classifier and torrent search engine with web UI, GraphQL API and Servarr stack integration. Available as [services.bitmagnet](options.html#opt-services.bitmagnet.enable). +- [Wakapi](https://wakapi.dev/), a time tracking software for programmers. Available as [services.wakapi](#opt-services.wakapi.enable). + +- [foot](https://codeberg.org/dnkl/foot), a fast, lightweight and minimalistic Wayland terminal emulator. Available as [programs.foot](#opt-programs.foot.enable). + +- [ToDesk](https://www.todesk.com/linux.html), a remote desktop applicaton. Available as [services.todesk.enable](#opt-services.todesk.enable). + +- [Dependency Track](https://dependencytrack.org/), an intelligent Component Analysis platform that allows organizations to identify and reduce risk in the software supply chain. Available as [services.dependency-track](option.html#opt-services.dependency-track). + +- [Immich](https://github.com/immich-app/immich), a self-hosted photo and video backup solution. Available as [services.immich](#opt-services.immich.enable). + +- [saunafs](https://saunafs.com) Distributed POSIX file system. Available as [services.saunafs](options.html#opt-services.saunafs). + +- [obs-studio](https://obsproject.com/), Free and open source software for video recording and live streaming. Available as [programs.obs-studio.enable](#opt-programs.obs-studio.enable). + +- [Veilid](https://veilid.com), a headless server that enables privacy-focused data sharing and messaging on a peer-to-peer network. Available as [services.veilid](#opt-services.veilid.enable). + +- [Fedimint](https://github.com/fedimint/fedimint), a module based system for building federated applications (Federated E-Cash Mint). Available as [services.fedimintd](#opt-services.fedimintd). + +- [Zapret](https://github.com/bol-van/zapret), a DPI bypass tool. Available as [services.zapret](option.html#opt-services.zapret). + ## Backward Incompatibilities {#sec-release-24.11-incompatibilities} +- The `sound` options have been removed or renamed, as they had a lot of unintended side effects. See [below](#sec-release-24.11-migration-sound) for details. + +- The nvidia driver no longer defaults to the proprietary driver starting with version 560. You will need to manually set `hardware.nvidia.open` to select the proprietary or open driver. + +- The `(buildPythonPackage { ... }).override` attribute is now deprecated and removed in favour of `overridePythonAttrs`. + This change does not affect the override interface of most Python packages, as [`.override`](https://nixos.org/manual/nixpkgs/unstable/#sec-pkg-override) provided by `callPackage` shadows such a locally-defined `override` attribute. + +- All Cinnamon and XApp packages have been moved to top-level (i.e., `cinnamon.nemo` is now `nemo`). + +- All GNOME packages have been moved to top-level (i.e., `gnome.nautilus` is now `nautilus`). + - `transmission` package has been aliased with a `trace` warning to `transmission_3`. Since [Transmission 4 has been released last year](https://github.com/transmission/transmission/releases/tag/4.0.0), and Transmission 3 will eventually go away, it was decided perform this warning alias to make people aware of the new version. The `services.transmission.package` defaults to `transmission_3` as well because the upgrade can cause data loss in certain specific usage patterns (examples: [#5153](https://github.com/transmission/transmission/issues/5153), [#6796](https://github.com/transmission/transmission/issues/6796)). Please make sure to back up to your data directory per your usage: - `transmission-gtk`: `~/.config/transmission` - `transmission-daemon` using NixOS module: `${config.services.transmission.home}/.config/transmission-daemon` (defaults to `/var/lib/transmission/.config/transmission-daemon`) +- The default `mongodb` version has been updated from 5.0 to 7.0. + For more information, see the compatibility changes for MongoDB [6.0](https://www.mongodb.com/docs/manual/release-notes/6.0-compatibility/) and [7.0](https://www.mongodb.com/docs/manual/release-notes/7.0-compatibility/). + +- `unifi` has been updated to UniFi 8. + `unifi7` was removed as it is vulnerable to CVE-2024-42025 and required a version of MongoDB that has reached end of life. + - `androidenv.androidPkgs_9_0` has been removed, and replaced with `androidenv.androidPkgs` for a more complete Android SDK including support for Android 9 and later. - `grafana` has been updated to version 11.1. This version doesn't support setting `http_addr` to a hostname anymore, an IP address is expected. +- `deno` has been updated to v2 which has breaking changes. Upstream will be abandoning v1 soon but for now you can use `deno_1` if you are yet to migrate (will be removed prior to cutting a final 24.11 release). + +- `gogs` has been removed. Upstream development has stalled and it has several + [critical vulnerabilities](https://github.com/gogs/gogs/issues/7777) that weren't addressed + within a year. Consider migrating to `forgejo` or `gitea`. + +- `knot-dns` has been updated to version 3.4.x. Check the [migration guide](https://www.knot-dns.cz/docs/latest/html/migration.html#upgrade-3-3-x-to-3-4-x) for breaking changes. + +- `services.kubernetes.kubelet.clusterDns` now accepts a list of DNS resolvers rather than a single string, bringing the module more in line with the upstream Kubelet configuration schema. + +- `bluemap` has changed the format used to store map tiles, and the database layout has been heavily modified. Upstream recommends a clean reinstallation: . Unless you are using an SQL storage backend, this should only entail deleting the contents of `config.services.bluemap.coreSettings.data` (defaults to `/var/lib/bluemap`) and `config.services.bluemap.webRoot` (defaults to `/var/lib/bluemap/web`). + - `wstunnel` has had a major version upgrade that entailed rewriting the program in Rust. The module was updated to accommodate for breaking changes. Breaking changes to the module API were minimised as much as possible, @@ -117,12 +237,19 @@ Also be aware that if you have set additional options in `services.wstunnel.{clients,servers}..extraArgs`, that those might have been removed or modified upstream. +- `percona-server_8_4` and `mysql84` now have password authentication via the deprecated `mysql_native_password` disabled by default. This authentication plugin can be enabled via a CLI argument again, for detailed instructions and alternative authentication methods [see upstream documentation](https://dev.mysql.com/doc/refman/8.4/en/native-pluggable-authentication.html). The config file directive `default_authentication_plugin` has been removed. + +- Percona has decided not to follow the LTS/ Innovation release scheme of upstream MySQL and thus [will only create releases for MySQL LTS versions](https://www.percona.com/blog/no-mysql-9-x-innovation-releases-from-percona/). Hence, the package names `percona-server_lts`, `percona-server_innovation`, `percona-xtrabackup_lts` and `percona-xtrabackup_innovation` are deprecated. + - `percona-server` and `percona-server_lts` now point towards the new LTS release `percona-server_8_4`. The previous LTS continues to be supported and is available as `percona-server_8_0`. The same is true for the supporting `percona-xtrabackup` tooling. + - `clang-tools_` packages have been moved into `llvmPackages_` (i.e. `clang-tools_18` is now `llvmPackages_18.clang-tools`). - For convenience, the top-level `clang-tools` attribute remains and is now bound to `llvmPackages.clang-tools`. - Top-level `clang_tools_` attributes are now aliases; these will be removed in a future release. - `buildbot` was updated to 4.0, the AngularJS frontend has been replaced by a React frontend, see the [upstream release notes](https://docs.buildbot.net/current/manual/upgrading/4.0-upgrade.html). +- `headscale` has been updated to version 0.23.0 which reworked large parts of the configuration including DNS, Magic DNS prefixes and ACL policy files. See the [upstream changelog](https://github.com/juanfont/headscale/releases/tag/v0.23.0) for details. + - `nginx` package no longer includes `gd` and `geoip` dependencies. For enabling it, override `nginx` package with the optionals `withImageFilter` and `withGeoIP`. - `systemd.enableUnifiedCgroupHierarchy` option has been removed. @@ -130,6 +257,8 @@ To forcibly reenable cgroup v1 support, you can `set boot.kernelParams = [ "systemd.unified_cgroup_hierachy=0" "SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1" ]`. NixOS does not officially support this configuration and might cause your system to be unbootable in future versions. You are on your own. +- `nrfutil` which previously pointed to the now-deprecated `pc-nrfutil` python package, has been repackaged under the same name with the new nrfutil tool. + - `openssh` and `openssh_hpn` are now compiled without Kerberos 5 / GSSAPI support in an effort to reduce the attack surface of the components for the majority of users. Users needing this support can use the new `opensshWithKerberos` and `openssh_hpnWithKerberos` flavors (e.g. `programs.ssh.package = pkgs.openssh_gssapi`). @@ -139,6 +268,11 @@ - The `MSMTP_QUEUE` and `MSMTP_LOG` environment variables accepted by `msmtpq` have now been renamed to `MSMTPQ_Q` and `MSMTPQ_LOG` respectively. +- The logrotate service has received hardening and now requires enabling `allowNetworking`, if logrotate needs to access the network. + +- qBittorrent has been updated to major version 5, which drops support for Qt 5. + The `qbittorrent-qt5` package has been removed. + - The fcgiwrap module now allows multiple instances running as distinct users. The option `services.fgciwrap` now takes an attribute set of the configuration of each individual instance. @@ -149,15 +283,26 @@ Processes also now run as a dynamically allocated user by default instead of root. +- The `mautrix-signal` module was adapted to incorporate the configuration rearrangement that resulted from the update to the mautrix bridgev2 architecture. Pre-0.7.0 configurations should continue to work. + In case you want to update your configuration make sure to check the NixOS manual. + +- The dhcpcd service (`networking.useDHCP`) has been hardened and now runs exclusively as the "dhcpcd" user. + Users that were relying on the root privileges in `networking.dhcpcd.runHook` will have to write specific [sudo](security.sudo.extraRules) or [polkit](security.polkit.extraConfig) rules to allow dhcpcd to perform privileged actions. + + As part of these changes, the DHCP lease files directory has also been moved from `/var/db/dhcpcd` to `/var/lib/dhcpcd`. This migration is performed automatically, but users may have to update their backup configuration. + - `singularity-tools` have the `storeDir` argument removed from its override interface and use `builtins.storeDir` instead. - Two build helpers in `singularity-tools`, i.e., `mkLayer` and `shellScript`, are deprecated, as they are no longer involved in image-building. Maintainers will remove them in future releases. +- The `rust.toTargetArch`, `rust.toTargetOs`, `rust.toTargetFamily`, `rust.toTargetVendor`, `rust.toRustTarget`, `rust.toRustTargetSpec`, `rust.toRustTargetSpecShort`, and `rust.IsNoStdTarget` functions are deprecated in favour of the `rust.platform.arch`, `rust.platform.os`, `rust.platform.target-family`, `rust.platform.vendor`, `rust.rustcTarget`, `rust.rustcTargetSpec`, `rust.cargoShortTarget`, `rust.cargoEnvVarTarget`, and `rust.isNoStdTarget` platform attributes respectively. + - The `budgie` and `budgiePlugins` scope have been removed and their packages moved into the top level scope (i.e., `budgie.budgie-desktop` is now `budgie-desktop`) -- All Cinnamon and XApp packages have been moved to top-level (i.e., `cinnamon.nemo` is now `nemo`). +- The method to safely handle secrets in the `networking.wireless` module has been changed to benefit from a [new feature](https://w1.fi/cgit/hostap/commit/?id=e680a51e94a33591f61edb210926bcb71217a21a) of wpa_supplicant. + The syntax to refer to secrets has changed slightly and the option `networking.wireless.environmentFile` has been replaced by `networking.wireless.secretsFile`; see the description of the latter for how to upgrade. - `services.cgit` now runs as the cgit user by default instead of root. This change requires granting access to the repositories to this user or @@ -187,25 +332,47 @@ - `pkgs.nextcloud27` has been removed since it's EOL. +- The `environment.noXlibs` option has been removed. It was a common source of unexpected rebuilds and breakage that was often hard to diagnose. + If you need to disable certain libraries, you're encouraged to add your own overlay to your configuration that targets the packages you care about. + +- `frigate` was updated past 0.14.0. This release includes various breaking changes, so please go read the [release notes](https://github.com/blakeblackshear/frigate/releases/tag/v0.14.0). + Most prominently access to the webinterface and API are now protected by authentication. Retrieve the auto-created + admin account from the `frigate.service` journal after upgrading. + +- `nodePackages.coc-python` was dropped, as [its upstream is unmaintained](https://github.com/neoclide/coc-python). The associated `vimPlugins.coc-python` was also dropped. + The upstream project recommends using `coc-pyright` or `coc-jedi` as replacements. + +- `forgejo` has been upgraded from version 7.0 to version 9.0, see the release notes for [8.0](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/RELEASE-NOTES.md#8-0-0) and [9.0](https://codeberg.org/forgejo/forgejo/milestone/7235). + - `services.forgejo.mailerPasswordFile` has been deprecated by the drop-in replacement `services.forgejo.secrets.mailer.PASSWD`, which is part of the new free-form `services.forgejo.secrets` option. `services.forgejo.secrets` is a small wrapper over systemd's `LoadCredential=`. It has the same structure (sections/keys) as `services.forgejo.settings` but takes file paths that will be read before service startup instead of some plaintext value. + `services.forgejo.package` now defaults to `forgejo-lts`, the Long Term Support version of Forgejo. - `forgejo` and `forgejo-lts` no longer support the opt-in feature [PAM (Pluggable Authentication Module)](https://forgejo.org/docs/latest/user/authentication/#pam-pluggable-authentication-module). -- `gitea` no longer supports the opt-in feature [PAM (Pluggable Authentication Module)][https://docs.gitea.com/usage/authentication#pam-pluggable-authentication-module]. +- `gitea` no longer supports the opt-in feature [PAM (Pluggable Authentication Module)](https://docs.gitea.com/usage/authentication#pam-pluggable-authentication-module). - `services.ddclient.use` has been deprecated: `ddclient` now supports separate IPv4 and IPv6 configuration. Use `services.ddclient.usev4` and `services.ddclient.usev6` instead. - `services.pgbouncer` systemd service is configured with `Type=notify-reload` and allows reloading configuration without process restart. PgBouncer configuration options were moved to the free-form type option named [`services.pgbouncer.settings`](#opt-services.pgbouncer.settings) according to the NixOS RFC 0042. +- `nodePackages.coc-metals` was removed due to being deprecated upstream. + `vimPlugins.nvim-metals` is its official replacement. + - `teleport` has been upgraded from major version 15 to major version 16. Refer to upstream [upgrade instructions](https://goteleport.com/docs/management/operations/upgrading/) and [release notes for v16](https://goteleport.com/docs/changelog/#1600-061324). - `tests.overriding` has its `passthru.tests` restructured as an attribute set instead of a list, making individual tests accessible by their names. +- Package `skk-dict` was split into multiple packages under `skkDictionaries`. + If in doubt, try `skkDictionaries.l`. As part of this change, the dictionaries + were moved from `$out/share` to `$out/share/skk`. Also, the dictionaries won't + be converted to UTF-8 unless the `useUtf8` package option is enabled. UTF-8 + converted dictionaries will have the .utf8 suffix appended to its filename. + - `vaultwarden` lost the capability to bind to privileged ports. If you rely on this behavior, override the systemd unit to allow `CAP_NET_BIND_SERVICE` in your local configuration. @@ -217,6 +384,15 @@ a static `user` and `group`. The `writablePaths` option has been removed and the models directory is now always exempt from sandboxing. +- The `gns3-server` service now runs under the `gns3` system user + instead of a dynamically created one via `DynamicUser`. + The use of SUID wrappers is incompatible with SystemD's `DynamicUser` setting, + and GNS3 requires calling ubridge through its SUID wrapper to function properly. + This change requires to manually move the following directories: + * from `/var/lib/private/gns3` to `/var/lib/gns3` + * from `/var/log/private/gns3` to `/var/log/gns3` + and to change the ownership of these directories and their contents to `gns3` (including `/etc/gns3`). + - Legacy package `stalwart-mail_0_6` was dropped, please note the [manual upgrade process](https://github.com/stalwartlabs/mail-server/blob/main/UPGRADING.md) before changing the package to `pkgs.stalwart-mail` in @@ -228,10 +404,14 @@ - Android NDK version 26 and SDK version 33 are now the default versions used for cross compilation to android. +- the `ankisyncd` package and its `services.ankisyncd` have been removed, use [`services.anki-sync-server`](#opt-services.anki-sync-server.enable) instead. + - `nodePackages.vscode-css-languageserver-bin`, `nodePackages.vscode-html-languageserver-bin`, and `nodePackages.vscode-json-languageserver-bin` were dropped due to an unmaintained upstream. The `vscode-langservers-extracted` package is a maintained drop-in replacement. +- `nodePackages.prisma` has been replaced by `prisma`. + - `fetchNextcloudApp` has been rewritten to use `fetchurl` rather than `fetchzip`. This invalidates all existing hashes but you can restore the old behavior by passing it `unpack = true`. @@ -255,6 +435,12 @@ for `stateVersion` ≥ 24.11. (It was previously using SQLite for structured data and the filesystem for blobs). +- The `stargazer` service has been hardened to improve security, but these + changes make break certain setups, particularly around traditional CGI. + + - The `stargazer.allowCgiUser` option has been added, enabling + Stargazer's `cgi-user` option to work, which was previously broken. + - The `shiori` service now requires an HTTP secret value `SHIORI_HTTP_SECRET_KEY` to be provided via environment variable. The nixos module therefore, now provides an environmentFile option: ``` @@ -267,6 +453,8 @@ - PPD files for Utax printers got renamed (spaces replaced by underscores) in newest `foomatic-db` package; users of Utax printers might need to adapt their `hardware.printers.ensurePrinters.*.model` value. +- The `kvdo` kernel module package was removed, because it was upstreamed in kernel version 6.9, where it is called `dm-vdo`. + - `libe57format` has been updated to `>= 3.0.0`, which contains some backward-incompatible API changes. See the [release note](https://github.com/asmaloney/libE57Format/releases/tag/v3.0.0) for more details. - `gitlab` deprecated support for *runner registration tokens* in GitLab 16.0, disabled their support in GitLab 17.0 and will @@ -285,9 +473,21 @@ - The `replay-sorcery` package and module was removed as it unmaintained upstream. Consider using `gpu-screen-recorder` or `obs-studio` instead. +- To follow [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) a few options of `samba` have been moved from `extraConfig` and `configText` to the new freeform option `settings` and renamed, e.g.: + - `services.samba.invalidUsers` to `services.samba.settings.global."invalid users"` + - `services.samba.securityType` to `services.samba.settings.global."security type"` + - `services.samba.shares` to `services.samba.settings` + - `services.samba.enableWinbindd` to `services.samba.winbindd.enable` + - `services.samba.enableNmbd` to `services.samba.nmbd.enable` + - `zx` was updated to v8, which introduces several breaking changes. See the [v8 changelog](https://github.com/google/zx/releases/tag/8.0.0) for more information. +- `feishin` removed support for Navidrome `< v0.53.2` due to an API change; more information in the [v0.10.0 release notes](https://github.com/jeffvli/feishin/releases/tag/v0.10.0). + +- The `dnscrypt-wrapper` module was removed since the project has been effectively unmaintained since 2018; moreover the NixOS module had to rely on an abandoned version of dnscrypt-proxy v1 for the rotation of keys. + To wrap a resolver with DNSCrypt you can instead use `dnsdist`. See options `services.dnsdist.dnscrypt.*` + - The `portunus` package and service do not support weak password hashes anymore. If you installed Portunus on NixOS 23.11 or earlier, upgrade to NixOS 24.05 first to get support for strong password hashing. Then, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all existing user accounts to strong password hashes. @@ -303,11 +503,15 @@ - Docker now defaults to 27.x, because version 24.x stopped receiving security updates and bug fixes after [February 1, 2024](https://github.com/moby/moby/pull/46772#discussion_r1686464084). +- `postgresql` was split into default and -dev outputs. To make this work without circular dependencies, the output of the `pg_config` system view has been removed. The `pg_config` binary is provided in the -dev output and still works as expected. + - `keycloak` was updated to version 25, which introduces new hostname related options. See [Upgrading Guide](https://www.keycloak.org/docs/25.0.1/upgrading/#migrating-to-25-0-0) for instructions. - `programs.vim.defaultEditor` now only works if `programs.vim.enable` is enabled. +- `services.mautrix-meta` was updated to [0.4](https://github.com/mautrix/meta/releases/tag/v0.4.0). This release makes significant changes to the settings format. If you have custom settings you should migrate them to the new format. Unfortunately upstream provides little guidance for how to do this, but [the auto-migration code](https://github.com/mautrix/meta/blob/f5440b05aac125b4c95b1af85635a717cbc6dd0e/cmd/mautrix-meta/legacymigrate.go#L23) may serve as a useful reference. The NixOS module should warn you if you still have any old settings configured. + - The `indi-full` package no longer contains non-free drivers. To get the old collection of drivers use `indi-full-nonfree` or create your own collection of drivers by overriding indi-with-drivers. E.g.: `pkgs.indi-with-drivers.override {extraDrivers = with pkgs.indi-3rdparty; [indi-gphoto];}` @@ -325,24 +529,91 @@ - `services.roundcube.maxAttachmentSize` will multiply the value set with `1.37` to offset overhead introduced by the base64 encoding applied to attachments. -- The `sound` options have been removed or renamed, as they had a lot of unintended side effects. See [below](#sec-release-24.11-migration-sound) for details. - - The `services.mxisd` module has been removed as both [mxisd](https://github.com/kamax-matrix/mxisd) and [ma1sd](https://github.com/ma1uta/ma1sd) are not maintained any longer. Consequently the package `pkgs.ma1sd` has also been removed. -- `ffmpeg_5` has been removed. Please use the unversioned `ffmpeg`, - pin a newer version, or if necessary pin `ffmpeg_4` for compatibility. +- The `rss-bridge` service drops the support to load a configuration file from `${config.services.rss-bridge.dataDir}/config.ini.php`. + Consider using the `services.rss-bridge.config` option instead. - The `xdg.portal.gtkUsePortal` option has been removed, as it had been deprecated for over 2 years. Using the `GTK_USE_PORTAL` environment variable in this manner is not intended nor encouraged by the GTK developers, but can still be done manually via `environment.sessionVariables`. +- Support for the legacy CUPS browsing and LDAP have been removed from `services.printing`. If `cups` or `ldap` are in the `BrowseRemoteProtocols` setting in `services.printing.browsedConf`, it needs to be removed. + - The `services.trust-dns` module has been renamed to `services.hickory-dns`. +- The option `services.prometheus.exporters.pgbouncer.connectionStringFile` has been removed since + it leaked the connection string (and thus potentially the DB password) into the cmdline + of process making it effectively world-readable. + + Use [`services.prometheus.exporters.pgbouncer.connectionEnvFile`](#opt-services.prometheus.exporters.pgbouncer.connectionEnvFile) instead. + - The `lsh` package and the `services.lshd` module have been removed as they had no maintainer in Nixpkgs and hadn’t seen an upstream release in over a decade. It is recommended to migrate to `openssh` and `services.openssh`. +- `ceph` has been upgraded to v19. See the [Ceph "squid" release notes](https://docs.ceph.com/en/latest/releases/squid/#v19-2-0-squid) for details and recommended upgrade procedure. + +- `services.frr` has been refactored to use upstream service scripts. The per-daemon configurations + have been removed in favour of an `integrated-vtysh-config` style config. The daemon submodules + now use the daemon name (e.g. `ospfd`) instead of the protocol name (`ospf`). The daemons `zebra`, + `mgmtd` and `staticd` are always enabled if a config is present. The `vtyListenAddress` and + `vtyListenPort` options have been removed; use `options` or `extraOptions` instead, respectively. + - `opencv2` and `opencv3` have been removed, as they are obsolete and were not used by any other package. External users are encouraged to migrate to OpenCV 4. +- The `tvheadend` package and the `services.tvheadend` module have been + removed as nobody was willing to maintain them and they were stuck on + an unmaintained version that required FFmpeg 4; please see [pull + request #332259](https://github.com/NixOS/nixpkgs/pull/332259) if you + are interested in maintaining a newer version. + +- The `antennas` package and the `services.antennas` module have been + removed as they only work with `tvheadend` (see above). + +- The `system.build.brightboxImage` image has been removed as It did not build anymore and has not seen any maintenance in over 7 years (excluding tree-wide changes). + +- The `services.syncplay` module now exposes all currently available command-line arguments for `syncplay-server` as options, as well as a `useACMEHost` option for easy TLS setup. + The systemd service now uses `DynamicUser`/`StateDirectory` and the `user` and `group` options have been deprecated. + +- The `openlens` package got removed, suggested replacement `lens-desktop` + +- The `services.dnsmasq.extraConfig` option has been removed, as it had been deprecated for over 2 years. This option has been replaced by `services.dnsmasq.settings`. + +- The NixOS installation media no longer support the ReiserFS or JFS file systems by default. + +- Minimal installer ISOs are no longer built on the small channel. + Please obtain installer images from the full release channels. + +- The default FFmpeg version is now 7, and FFmpeg 5 has been removed. + Please prefer using the package variants without a version suffix, + or pin FFmpeg 6 or 4 if necessary for compatibility. + Note that we keep old versions around only as required + to support packages in the tree, + and FFmpeg 4 especially should be avoided in favour of newer versions + as it may be removed soon. + +- `openssl` now defaults to the latest version line `3.3.x`, instead of `3.0.x` before. While there should be no major code incompatibilities, newer OpenSSL versions typically strengthen the default security level. This means that you may have to explicitly allow weak ciphers, hashes and key lengths if necessary. See: [OpenSSL security level documentation](https://docs.openssl.org/3.3/man3/SSL_CTX_set_security_level/). + +- The `isync` package has been updated to version `1.5.0`, which introduces some breaking changes. See the [compatibility concerns](https://sourceforge.net/projects/isync/files/isync/1.5.0/) for more details. + +- Legacy package `globalprotect-openconnect` 1.x and related module + `globalprotect-vpn` were dropped. Two new packages `gpauth` and `gpclient` + from the 2.x version of the GlobalProtect-openconnect project are added in its + place. The GUI components related to the project are non-free and not + packaged. + +- Compatible string matching for `hardware.deviceTree.overlays` has been changed to a more correct behavior. See [below](#sec-release-24.11-migration-dto-compatible) for details. + +- The `rustic` package was upgrade to `0.9.0`, which contains [breaking changes to the config file format](https://github.com/rustic-rs/rustic/releases/tag/v0.9.0). + +- `pkgs.formats.ini` and `pkgs.formats.iniWithGlobalSection` with + `listsAsDuplicateKeys` or `listToValue` no longer merge non-list values into + lists by default. Backwards-compatible behavior can be enabled with + `atomsCoercedToLists`. + +- `python3Packages.nose` has been removed, as it has been deprecated and unmaintained for almost a decade and does not work on Python 3.12. + Please switch to `pytest` or another test runner/framework. + ## Other Notable Changes {#sec-release-24.11-notable-changes} @@ -358,6 +629,16 @@ [buildRustPackage: Compiling Rust applications with Cargo](https://nixos.org/manual/nixpkgs/unstable/#compiling-rust-applications-with-cargo) for more information. +- The `vendorHash` of Go packages built with `buildGoModule` can now be overridden with `overrideAttrs`. + `goModules`, `modRoot`, `vendorHash`, `deleteVendor`, and `proxyVendor` are now passed as derivation attributes. + `goModules` and `vendorHash` are no longer placed under `passthru`. + +- `buildFlags`/`buildFlagsArray` on `buildGoModule` have been deprecated. 24.11 is the last release where `buildGoModule` accepts these flags (while throwing a warning). + Use the [`ldflags`](https://nixos.org/manual/nixpkgs/unstable/#var-go-ldflags) and/or [`tags`](https://nixos.org/manual/nixpkgs/unstable/#var-go-tags) attributes or + [the environment](https://nixos.org/manual/nixpkgs/unstable/#ssec-go-environment) instead. + +- `buildGoPackage` has been deprecated. 24.11 is the last release with `buildGoPackage` available. + - `hareHook` has been added as the language framework for Hare. From now on, it, not the `hare` package, should be added to `nativeBuildInputs` when building Hare programs. @@ -366,14 +647,41 @@ - `lib.misc.mapAttrsFlatten` is now formally deprecated and will be removed in future releases; use the identical [`lib.attrsets.mapAttrsToList`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.mapAttrsToList) instead. +- Tailscale's `authKeyFile` can now have its corresponding parameters set through `config.services.tailscale.authKeyParameters`, allowing for non-ephemeral unsupervised deployment and more. + See [Registering new nodes using OAuth credentials](https://tailscale.com/kb/1215/oauth-clients#registering-new-nodes-using-oauth-credentials) for the supported options. + - `nixosTests` now provide a working IPv6 setup for VLAN 1 by default. - Kanidm can now be provisioned using the new [`services.kanidm.provision`] option, but requires using a patched version available via `pkgs.kanidm.withSecretProvisioning`. +- Kanidm previously had an incorrect systemd service type, causing dependent units with an `after` and `requires` directive to start before `kanidm*` finished startup. The module has now been updated in line with upstream recommendations. + +- The kubelet configuration file can now be amended with arbitrary additional content using the `services.kubernetes.kubelet.extraConfig` option. + +- The `services.seafile` module was updated to major version 11. + - As part of this upgrade, the database backend will be migrated to MySQL. + This process should be automatic, but in case of a botched migration, + old sqlite files are not removed and can be used to manually migrate the database. + - Additionally, the updated CSRF protection may prevent some users from logging in. + Specific origin addresses can be whitelisted using the `services.seafile.seahubExtraConf` option + (e.g. `services.seafile.seahubExtraConf = ''CSRF_TRUSTED_ORIGINS = ["https://example.com"]'';`). + Note that first solution of the [official FAQ answer](https://cloud.seatable.io/dtable/external-links/7b976c85f504491cbe8e/?tid=0000&vid=0000&row-id=BQhH-2HSQs68Nq2EW91DBA) + is not allowed by the `services.nginx` module's config-checker. + +- The latest available version of Nextcloud is v30 (available as `pkgs.nextcloud30`). The installation logic is as follows: + - If [`services.nextcloud.package`](#opt-services.nextcloud.package) is specified explicitly, this package will be installed (**recommended**) + - If [`system.stateVersion`](#opt-system.stateVersion) is >=24.05, `pkgs.nextcloud29` will be installed by default. + - If [`system.stateVersion`](#opt-system.stateVersion) is >=24.11, `pkgs.nextcloud30` will be installed by default. + - Please note that an upgrade from v28 (or older) to v30 directly is not possible. Please upgrade to `nextcloud29` (or earlier) first. Nextcloud prohibits skipping major versions while upgrading. You can upgrade by declaring [`services.nextcloud.package = pkgs.nextcloud29;`](options.html#opt-services.nextcloud.package). + - To facilitate dependency injection, the `imgui` package now builds a static archive using vcpkg' CMake rules. The derivation now installs "impl" headers selectively instead of by a wildcard. Use `imgui.src` if you just want to access the unpacked sources. +- The new `boot.loader.systemd-boot.windows` option makes setting up dual-booting with Windows on a different drive easier + +- Linux 4.19 has been removed because it will reach its end of life within the lifespan of 24.11 + - Unprivileged access to the kernel syslog via `dmesg` is now restricted by default. Users wanting to keep an unrestricted access to it can set `boot.kernel.sysctl."kernel.dmesg_restrict" = false`. @@ -383,19 +691,40 @@ - `security.pam.u2f` now follows RFC42. All module options are now settable through the freeform `.settings`. +- Mikutter was removed because the package was broken and had no maintainers. + - Gollum was upgraded to major version 6. Read their [migration notes](https://github.com/gollum/gollum/wiki/6.0-Release-Notes). - The hooks `yarnConfigHook` and `yarnBuildHook` were added. These should replace `yarn2nix.mkYarnPackage` and other `yarn2nix` related tools. The motivation to get rid of `yarn2nix` tools is the fact that they are too complex and hard to maintain, and they rely upon too much Nix evaluation which is problematic if import-from-derivation is not allowed (see more details at [#296856](https://github.com/NixOS/nixpkgs/issues/296856). The transition from `mkYarnPackage` to `yarn{Config,Build}Hook` is tracked at [#324246](https://github.com/NixOS/nixpkgs/issues/324246). -- Cinnamon has been updated to 6.2. - - Following Mint 22 defaults, the Cinnamon module no longer ships geary and hexchat by default. - - Nemo is now built with gtk-layer-shell support, note that for now it will be expected to see nemo-desktop - listed as a regular entry in Cinnamon Wayland session's window list applet. +- `services.timesyncd.servers` now defaults to `null`, allowing systemd-timesyncd to use NTP servers advertised by DHCP. + +- `services.timesyncd.fallbackServers` was added and defaults to `networking.timeServers`. + +- Cinnamon has been updated to 6.2, please check [upstream announcement](https://www.linuxmint.com/rel_wilma_whatsnew.php) for more details. + Following Mint 22 defaults, the Cinnamon module no longer ships geary and hexchat by default. + +- `zfs.latestCompatibleLinuxPackages` is deprecated and is now pointing at the default kernel. If using the stable LTS kernel (default `linuxPackages` is not possible then you must explicitly pin a specific kernel release. For example, `boot.kernelPackages = pkgs.linuxPackages_6_6`. Please be aware that non-LTS kernels are likely to go EOL before ZFS supports the latest supported non-LTS release, requiring manual intervention. - The `shadowstack` hardening flag has been added, though disabled by default. +- `xxd` is now provided by the `tinyxxd` package, rather than `vim.xxd`, to reduce closure size and vulnerability impact. Since it has the same options and semantics as Vim's `xxd` utility, there is no user impact. Vim's `xxd` remains available as the `vim.xxd` package. + +- `prometheus-openldap-exporter` was removed since it was unmaintained upstream and had no nixpkgs maintainers. + - `restic` module now has an option for inhibiting system sleep while backups are running, defaulting to off (not inhibiting sleep), available as [`services.restic.backups..inhibitsSleep`](#opt-services.restic.backups._name_.inhibitsSleep). +- The arguments from [](#opt-services.postgresql.initdbArgs) now get shell-escaped. + +- `cargo-tauri.hook` was introduced to help users build [Tauri](https://tauri.app/) projects. It is meant to be used alongside + `rustPlatform.buildRustPackage` and Node hooks such as `npmConfigHook`, `pnpm.configHook`, and the new `yarnConfig` + +- `power.ups` now powers off UPSs during a power outage event. + This saves UPS battery and ensures that host(s) get back up again when power comes back, even in the scenario when the UPS would have had enough capacity to keep power on during the whole power outage. + If you like the old behaviour of keeping the UPSs on (and emptying the battery) after the host(s) have shut down, and risk not getting a power cycle event to get the host(s) back up, set `power.ups.upsmon.settings.POWERDOWNFLAG = null;`. + +- `nixos-firewall-tool` now supports nftables in addition to iptables and is installed by default when NixOS firewall is enabled. + - Support for *runner registration tokens* has been [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in `gitlab-runner` 15.6 and is expected to be removed in `gitlab-runner` 18.0. Configuration of existing runners should be changed to using *runner authentication tokens* by configuring @@ -405,7 +734,15 @@ - `iproute2` now has libbpf support. - `nix.channel.enable = false` no longer implies `nix.settings.nix-path = []`. - Since Nix 2.13, a `nix-path` set in `nix.conf` cannot be overriden by the `NIX_PATH` configuration variable. + Since Nix 2.13, a `nix-path` set in `nix.conf` cannot be overridden by the `NIX_PATH` configuration variable. + +- ZFS now imports its pools in `postResumeCommands` rather than `postDeviceCommands`. If you had `postDeviceCommands` scripts that depended on ZFS pools being imported, those now need to be in `postResumeCommands`. + +- `services.automatic-timezoned.enable = true` will now set `time.timeZone = null`. + This is to avoid silently shadowing a user's explicitly defined timezone without recognition on the user's part. + +- `services.localtimed.enable = true` will now set `time.timeZone = null`. + This is to avoid silently shadowing a user's explicitly defined timezone without recognition on the user's part. ## Detailed migration information {#sec-release-24.11-migration} @@ -449,3 +786,22 @@ in { ]; }; ``` + +### `hardware.deviceTree.overlays` compatible string matching {#sec-release-24.11-migration-dto-compatible} + +The original compatible string implementation in older NixOS versions relied on substring matching, +which is incorrect for overlays with multiple compatible strings and other cases. + +The new behavior is consistent with what other tools already do - the overlay is considered applicable if, +and only if, _any_ of the compatible strings in the overlay match _any_ of the compatible strings in the DT. + +To provide some examples: + +| Overlay `compatible` | DT `compatible` | Pre-24.11 behavior | Correct behavior | Notes | +|----------------------|-----------------|--------------------|------------------|--------------------------------------------| +| `"foo"` | `"foo", "bar"` | match | match | Most common use case does not change | +| `"foo"` | `"foobar"` | match | no match | Substrings should not be matched | +| `"foo bar"` | `"foo", "bar"` | match | no match | Separators should not be matched to spaces | +| `"foo", "bar"` | `"baz", "bar"` | no match | match | One compatible string matching is enough | + +Note that this also allows writing overlays that explicitly apply to multiple boards. diff --git a/nixos/lib/make-disk-image.nix b/nixos/lib/make-disk-image.nix index 208eaf59dc5c..a943edb7b574 100644 --- a/nixos/lib/make-disk-image.nix +++ b/nixos/lib/make-disk-image.nix @@ -321,7 +321,7 @@ let format' = format; in let e2fsprogs lkl config.system.build.nixos-install - config.system.build.nixos-enter + nixos-enter nix systemdMinimal ] diff --git a/nixos/lib/make-ext4-fs.nix b/nixos/lib/make-ext4-fs.nix index b8e1b8d24c48..8afc5555ced4 100644 --- a/nixos/lib/make-ext4-fs.nix +++ b/nixos/lib/make-ext4-fs.nix @@ -58,10 +58,18 @@ pkgs.stdenv.mkDerivation { # Make a crude approximation of the size of the target image. # If the script starts failing, increase the fudge factors here. numInodes=$(find ./rootImage | wc -l) - numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.10) }') + numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.20) }') bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks)) echo "Creating an EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)" + mebibyte=$(( 1024 * 1024 )) + # Round up to the nearest mebibyte. + # This ensures whole 512 bytes sector sizes in the disk image + # and helps towards aligning partitions optimally. + if (( bytes % mebibyte )); then + bytes=$(( ( bytes / mebibyte + 1) * mebibyte )) + fi + truncate -s $bytes $img faketime -f "1970-01-01 00:00:01" fakeroot mkfs.ext4 -L ${volumeLabel} -U ${uuid} -d ./rootImage $img diff --git a/nixos/lib/make-multi-disk-zfs-image.nix b/nixos/lib/make-multi-disk-zfs-image.nix index 077bb8f22707..1dac232e2b8c 100644 --- a/nixos/lib/make-multi-disk-zfs-image.nix +++ b/nixos/lib/make-multi-disk-zfs-image.nix @@ -124,7 +124,7 @@ let tools = lib.makeBinPath ( with pkgs; [ - config.system.build.nixos-enter + nixos-enter config.system.build.nixos-install dosfstools e2fsprogs diff --git a/nixos/lib/make-single-disk-zfs-image.nix b/nixos/lib/make-single-disk-zfs-image.nix index 585fa93b7fa0..e37b79797dca 100644 --- a/nixos/lib/make-single-disk-zfs-image.nix +++ b/nixos/lib/make-single-disk-zfs-image.nix @@ -112,7 +112,7 @@ let tools = lib.makeBinPath ( with pkgs; [ - config.system.build.nixos-enter + nixos-enter config.system.build.nixos-install dosfstools e2fsprogs diff --git a/nixos/lib/systemd-lib.nix b/nixos/lib/systemd-lib.nix index fedd85f09b80..ede54318d558 100644 --- a/nixos/lib/systemd-lib.nix +++ b/nixos/lib/systemd-lib.nix @@ -17,6 +17,7 @@ let filterAttrs flatten flip + hasPrefix head isInt isFloat @@ -196,6 +197,10 @@ in rec { optional (attr ? ${name}) "Systemd ${group} field `${name}' has been removed. See ${see}"; + assertKeyIsSystemdCredential = name: group: attr: + optional (attr ? ${name} && !(hasPrefix "@" attr.${name})) + "Systemd ${group} field `${name}' is not a systemd credential"; + checkUnitConfig = group: checks: attrs: let # We're applied at the top-level type (attrsOf unitOption), so the actual # unit options might contain attributes from mkOverride and mkIf that we need to @@ -386,18 +391,27 @@ in rec { ''} ''; # */ - makeJobScript = name: text: + makeJobScript = { name, text, enableStrictShellChecks }: let scriptName = replaceStrings [ "\\" "@" ] [ "-" "_" ] (shellEscape name); - out = (pkgs.writeShellScriptBin scriptName '' - set -e - ${text} - '').overrideAttrs (_: { + out = ( + if ! enableStrictShellChecks then + pkgs.writeShellScriptBin scriptName '' + set -e + + ${text} + '' + else + pkgs.writeShellApplication { + name = scriptName; + inherit text; + } + ).overrideAttrs (_: { # The derivation name is different from the script file name # to keep the script file name short to avoid cluttering logs. name = "unit-script-${scriptName}"; }); - in "${out}/bin/${scriptName}"; + in lib.getExe out; unitConfig = { config, name, options, ... }: { config = { @@ -448,10 +462,16 @@ in rec { }; }; - serviceConfig = { name, config, ... }: { + serviceConfig = + let + nixosConfig = config; + in + { name, lib, config, ... }: { config = { name = "${name}.service"; environment.PATH = mkIf (config.path != []) "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}"; + + enableStrictShellChecks = lib.mkOptionDefault nixosConfig.systemd.enableStrictShellChecks; }; }; diff --git a/nixos/lib/systemd-unit-options.nix b/nixos/lib/systemd-unit-options.nix index 160f2bf9483a..b02a11ef33a6 100644 --- a/nixos/lib/systemd-unit-options.nix +++ b/nixos/lib/systemd-unit-options.nix @@ -17,6 +17,7 @@ let concatMap filterOverrides isList + literalExpression mergeEqualOption mkIf mkMerge @@ -357,6 +358,14 @@ in rec { ''; }; + enableStrictShellChecks = mkOption { + type = types.bool; + description = "Enable running shellcheck on the generated scripts for this unit."; + # The default gets set in systemd-lib.nix because we don't have access to + # the full NixOS config here. + defaultText = literalExpression "config.systemd.enableStrictShellChecks"; + }; + script = mkOption { type = types.lines; default = ""; @@ -428,27 +437,51 @@ in rec { config = mkMerge [ (mkIf (config.preStart != "") rec { - jobScripts = makeJobScript "${name}-pre-start" config.preStart; + jobScripts = makeJobScript { + name = "${name}-pre-start"; + text = config.preStart; + inherit (config) enableStrictShellChecks; + }; serviceConfig.ExecStartPre = [ jobScripts ]; }) (mkIf (config.script != "") rec { - jobScripts = makeJobScript "${name}-start" config.script; + jobScripts = makeJobScript { + name = "${name}-start"; + text = config.script; + inherit (config) enableStrictShellChecks; + }; serviceConfig.ExecStart = jobScripts + " " + config.scriptArgs; }) (mkIf (config.postStart != "") rec { - jobScripts = (makeJobScript "${name}-post-start" config.postStart); + jobScripts = makeJobScript { + name = "${name}-post-start"; + text = config.postStart; + inherit (config) enableStrictShellChecks; + }; serviceConfig.ExecStartPost = [ jobScripts ]; }) (mkIf (config.reload != "") rec { - jobScripts = makeJobScript "${name}-reload" config.reload; + jobScripts = makeJobScript { + name = "${name}-reload"; + text = config.reload; + inherit (config) enableStrictShellChecks; + }; serviceConfig.ExecReload = jobScripts; }) (mkIf (config.preStop != "") rec { - jobScripts = makeJobScript "${name}-pre-stop" config.preStop; + jobScripts = makeJobScript { + name = "${name}-pre-stop"; + text = config.preStop; + inherit (config) enableStrictShellChecks; + }; serviceConfig.ExecStop = jobScripts; }) (mkIf (config.postStop != "") rec { - jobScripts = makeJobScript "${name}-post-stop" config.postStop; + jobScripts = makeJobScript { + name = "${name}-post-stop"; + text = config.postStop; + inherit (config) enableStrictShellChecks; + }; serviceConfig.ExecStopPost = jobScripts; }) ]; diff --git a/nixos/lib/test-driver/test_driver/driver.py b/nixos/lib/test-driver/test_driver/driver.py index 01b64b92e977..0f01bd6d0ab4 100644 --- a/nixos/lib/test-driver/test_driver/driver.py +++ b/nixos/lib/test-driver/test_driver/driver.py @@ -99,7 +99,16 @@ class Driver: with self.logger.nested("cleanup"): self.race_timer.cancel() for machine in self.machines: - machine.release() + try: + machine.release() + except Exception as e: + self.logger.error(f"Error during cleanup of {machine.name}: {e}") + + for vlan in self.vlans: + try: + vlan.stop() + except Exception as e: + self.logger.error(f"Error during cleanup of vlan{vlan.nr}: {e}") def subtest(self, name: str) -> Iterator[None]: """Group logs under a given test name""" diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py index 3a1d5bc1be76..7a602ce6608f 100644 --- a/nixos/lib/test-driver/test_driver/machine.py +++ b/nixos/lib/test-driver/test_driver/machine.py @@ -1234,6 +1234,9 @@ class Machine: self.monitor.close() self.serial_thread.join() + if self.qmp_client: + self.qmp_client.close() + def run_callbacks(self) -> None: for callback in self.callbacks: callback() diff --git a/nixos/lib/test-driver/test_driver/qmp.py b/nixos/lib/test-driver/test_driver/qmp.py index 62ca6d7d5b80..99c02ca1c120 100644 --- a/nixos/lib/test-driver/test_driver/qmp.py +++ b/nixos/lib/test-driver/test_driver/qmp.py @@ -49,7 +49,7 @@ class QMPSession: sock.connect(str(path)) return cls(sock) - def __del__(self) -> None: + def close(self) -> None: self.sock.close() def _wait_for_new_result(self) -> dict[str, str]: diff --git a/nixos/lib/test-driver/test_driver/vlan.py b/nixos/lib/test-driver/test_driver/vlan.py index 9340fc92ed4c..03ecbe25e8a2 100644 --- a/nixos/lib/test-driver/test_driver/vlan.py +++ b/nixos/lib/test-driver/test_driver/vlan.py @@ -59,7 +59,7 @@ class VLan: self.logger.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") - def __del__(self) -> None: + def stop(self) -> None: self.logger.info(f"kill vlan (pid {self.pid})") self.fd.close() self.process.terminate() diff --git a/nixos/lib/testing/nixos-test-base.nix b/nixos/lib/testing/nixos-test-base.nix index d76a25361f8c..c8b15a0ecce4 100644 --- a/nixos/lib/testing/nixos-test-base.nix +++ b/nixos/lib/testing/nixos-test-base.nix @@ -3,7 +3,7 @@ # even in `inheritParentConfig = false` specialisations. { lib, ... }: let - inherit (lib) mkForce; + inherit (lib) mkDefault mkForce; in { imports = [ @@ -22,6 +22,11 @@ in label = mkForce "test"; }; } - + ({ config, ... }: { + # Don't pull in switch-to-configuration by default, except when specialisations or early boot shenanigans are involved. + # This is mostly a Hydra optimization, so we don't rebuild all the tests every time switch-to-configuration-ng changes. + key = "no-switch-to-configuration"; + system.switch.enable = mkDefault (config.isSpecialisation || config.specialisation != {} || config.virtualisation.installBootLoader); + }) ]; } diff --git a/nixos/lib/testing/nodes.nix b/nixos/lib/testing/nodes.nix index 9aecca10ac6b..8b14d0a3bffd 100644 --- a/nixos/lib/testing/nodes.nix +++ b/nixos/lib/testing/nodes.nix @@ -151,7 +151,7 @@ in nodesCompat = mapAttrs (name: config: config // { - config = lib.warnIf (lib.isInOldestRelease 2211) + config = lib.warnIf (lib.oldestSupportedReleaseIsAtLeast 2211) "Module argument `nodes.${name}.config` is deprecated. Use `nodes.${name}` instead." config; }) diff --git a/nixos/modules/config/appstream.nix b/nixos/modules/config/appstream.nix index 1712273eff7d..edac18b9ba36 100644 --- a/nixos/modules/config/appstream.nix +++ b/nixos/modules/config/appstream.nix @@ -1,10 +1,8 @@ { config, lib, ... }: - -with lib; { options = { - appstream.enable = mkOption { - type = types.bool; + appstream.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to install files to support the @@ -13,7 +11,7 @@ with lib; }; }; - config = mkIf config.appstream.enable { + config = lib.mkIf config.appstream.enable { environment.pathsToLink = [ # per component metadata "/share/metainfo" diff --git a/nixos/modules/config/console.nix b/nixos/modules/config/console.nix index 5aadc0836fe7..9beb7dc58703 100644 --- a/nixos/modules/config/console.nix +++ b/nixos/modules/config/console.nix @@ -1,27 +1,23 @@ - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.console; - makeColor = i: concatMapStringsSep "," (x: "0x" + substring (2*i) 2 x); + makeColor = i: lib.concatMapStringsSep "," (x: "0x" + lib.substring (2*i) 2 x); - isUnicode = hasSuffix "UTF-8" (toUpper config.i18n.defaultLocale); + isUnicode = lib.hasSuffix "UTF-8" (lib.toUpper config.i18n.defaultLocale); optimizedKeymap = pkgs.runCommand "keymap" { nativeBuildInputs = [ pkgs.buildPackages.kbd ]; LOADKEYS_KEYMAP_PATH = "${consoleEnv pkgs.kbd}/share/keymaps/**"; preferLocalBuild = true; } '' - loadkeys -b ${optionalString isUnicode "-u"} "${cfg.keyMap}" > $out + loadkeys -b ${lib.optionalString isUnicode "-u"} "${cfg.keyMap}" > $out ''; # Sadly, systemd-vconsole-setup doesn't support binary keymaps. vconsoleConf = pkgs.writeText "vconsole.conf" '' KEYMAP=${cfg.keyMap} - ${optionalString (cfg.font != null) "FONT=${cfg.font}"} + ${lib.optionalString (cfg.font != null) "FONT=${cfg.font}"} ''; consoleEnv = kbd: pkgs.buildEnv { @@ -40,12 +36,12 @@ in ###### interface options.console = { - enable = mkEnableOption "virtual console" // { + enable = lib.mkEnableOption "virtual console" // { default = true; }; - font = mkOption { - type = with types; nullOr (either str path); + font = lib.mkOption { + type = with lib.types; nullOr (either str path); default = null; example = "LatArCyrHeb-16"; description = '' @@ -61,8 +57,8 @@ in ''; }; - keyMap = mkOption { - type = with types; either str path; + keyMap = lib.mkOption { + type = with lib.types; either str path; default = "us"; example = "fr"; description = '' @@ -70,8 +66,8 @@ in ''; }; - colors = mkOption { - type = with types; listOf (strMatching "[[:xdigit:]]{6}"); + colors = lib.mkOption { + type = with lib.types; listOf (strMatching "[[:xdigit:]]{6}"); default = [ ]; example = [ "002b36" "dc322f" "859900" "b58900" @@ -88,8 +84,8 @@ in }; - packages = mkOption { - type = types.listOf types.package; + packages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = [ ]; description = '' List of additional packages that provide console fonts, keymaps and @@ -97,8 +93,8 @@ in ''; }; - useXkbConfig = mkOption { - type = types.bool; + useXkbConfig = lib.mkOption { + type = lib.types.bool; default = false; description = '' If set, configure the virtual console keymap from the xserver @@ -106,9 +102,9 @@ in ''; }; - earlySetup = mkOption { + earlySetup = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable setting virtual console options as early as possible (in initrd). ''; @@ -119,12 +115,12 @@ in ###### implementation - config = mkMerge [ + config = lib.mkMerge [ { console.keyMap = with config.services.xserver; - mkIf cfg.useXkbConfig + lib.mkIf cfg.useXkbConfig (pkgs.runCommand "xkb-console-keymap" { preferLocalBuild = true; } '' '${pkgs.buildPackages.ckbcomp}/bin/ckbcomp' \ - ${optionalString (config.environment.sessionVariables ? XKB_CONFIG_ROOT) + ${lib.optionalString (config.environment.sessionVariables ? XKB_CONFIG_ROOT) "-I${config.environment.sessionVariables.XKB_CONFIG_ROOT}" } \ -model '${xkb.model}' -layout '${xkb.layout}' \ @@ -132,7 +128,7 @@ in ''); } - (mkIf (!cfg.enable) { + (lib.mkIf (!cfg.enable) { systemd.services = { "serial-getty@ttyS0".enable = false; "serial-getty@hvc0".enable = false; @@ -142,7 +138,7 @@ in }; }) - (mkIf cfg.enable (mkMerge [ + (lib.mkIf cfg.enable (lib.mkMerge [ { environment.systemPackages = [ pkgs.kbd ]; # Let systemd-vconsole-setup.service do the work of setting up the @@ -151,12 +147,12 @@ in # Provide kbd with additional packages. environment.etc.kbd.source = "${consoleEnv pkgs.kbd}/share"; - boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) (mkBefore '' + boot.initrd.preLVMCommands = lib.mkIf (!config.boot.initrd.systemd.enable) (lib.mkBefore '' kbd_mode ${if isUnicode then "-u" else "-a"} -C /dev/console printf "\033%%${if isUnicode then "G" else "@"}" >> /dev/console loadkmap < ${optimizedKeymap} - ${optionalString (cfg.earlySetup && cfg.font != null) '' + ${lib.optionalString (cfg.earlySetup && cfg.font != null) '' setfont -C /dev/console $extraUtils/share/consolefonts/font.psf ''} ''); @@ -176,9 +172,9 @@ in "${config.boot.initrd.systemd.package.kbd}/bin/setfont" "${config.boot.initrd.systemd.package.kbd}/bin/loadkeys" "${config.boot.initrd.systemd.package.kbd.gzip}/bin/gzip" # Fonts and keyboard layouts are compressed - ] ++ optionals (cfg.font != null && hasPrefix builtins.storeDir cfg.font) [ + ] ++ lib.optionals (cfg.font != null && lib.hasPrefix builtins.storeDir cfg.font) [ "${cfg.font}" - ] ++ optionals (hasPrefix builtins.storeDir cfg.keyMap) [ + ] ++ lib.optionals (lib.hasPrefix builtins.storeDir cfg.keyMap) [ "${cfg.keyMap}" ]; @@ -195,7 +191,7 @@ in }; } - (mkIf (cfg.colors != []) { + (lib.mkIf (cfg.colors != []) { boot.kernelParams = [ "vt.default_red=${makeColor 0 cfg.colors}" "vt.default_grn=${makeColor 1 cfg.colors}" @@ -203,10 +199,10 @@ in ]; }) - (mkIf (cfg.earlySetup && cfg.font != null && !config.boot.initrd.systemd.enable) { + (lib.mkIf (cfg.earlySetup && cfg.font != null && !config.boot.initrd.systemd.enable) { boot.initrd.extraUtilsCommands = '' mkdir -p $out/share/consolefonts - ${if substring 0 1 cfg.font == "/" then '' + ${if lib.substring 0 1 cfg.font == "/" then '' font="${cfg.font}" '' else '' font="$(echo ${consoleEnv pkgs.kbd}/share/consolefonts/${cfg.font}.*)" @@ -222,14 +218,14 @@ in ]; imports = [ - (mkRenamedOptionModule [ "i18n" "consoleFont" ] [ "console" "font" ]) - (mkRenamedOptionModule [ "i18n" "consoleKeyMap" ] [ "console" "keyMap" ]) - (mkRenamedOptionModule [ "i18n" "consoleColors" ] [ "console" "colors" ]) - (mkRenamedOptionModule [ "i18n" "consolePackages" ] [ "console" "packages" ]) - (mkRenamedOptionModule [ "i18n" "consoleUseXkbConfig" ] [ "console" "useXkbConfig" ]) - (mkRenamedOptionModule [ "boot" "earlyVconsoleSetup" ] [ "console" "earlySetup" ]) - (mkRenamedOptionModule [ "boot" "extraTTYs" ] [ "console" "extraTTYs" ]) - (mkRemovedOptionModule [ "console" "extraTTYs" ] '' + (lib.mkRenamedOptionModule [ "i18n" "consoleFont" ] [ "console" "font" ]) + (lib.mkRenamedOptionModule [ "i18n" "consoleKeyMap" ] [ "console" "keyMap" ]) + (lib.mkRenamedOptionModule [ "i18n" "consoleColors" ] [ "console" "colors" ]) + (lib.mkRenamedOptionModule [ "i18n" "consolePackages" ] [ "console" "packages" ]) + (lib.mkRenamedOptionModule [ "i18n" "consoleUseXkbConfig" ] [ "console" "useXkbConfig" ]) + (lib.mkRenamedOptionModule [ "boot" "earlyVconsoleSetup" ] [ "console" "earlySetup" ]) + (lib.mkRenamedOptionModule [ "boot" "extraTTYs" ] [ "console" "extraTTYs" ]) + (lib.mkRemovedOptionModule [ "console" "extraTTYs" ] '' Since NixOS switched to systemd (circa 2012), TTYs have been spawned on demand, so there is no need to configure them manually. '') diff --git a/nixos/modules/config/debug-info.nix b/nixos/modules/config/debug-info.nix index 05a2fd2ceeea..9bf3d82ace2a 100644 --- a/nixos/modules/config/debug-info.nix +++ b/nixos/modules/config/debug-info.nix @@ -1,13 +1,10 @@ { config, lib, ... }: - -with lib; - { options = { - environment.enableDebugInfo = mkOption { - type = types.bool; + environment.enableDebugInfo = lib.mkOption { + type = lib.types.bool; default = false; description = '' Some NixOS packages provide debug symbols. However, these are @@ -29,7 +26,7 @@ with lib; }; - config = mkIf config.environment.enableDebugInfo { + config = lib.mkIf config.environment.enableDebugInfo { # FIXME: currently disabled because /lib is already in # environment.pathsToLink, and we can't have both. diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix index 9a9ac08eefeb..205fd1fa7b96 100644 --- a/nixos/modules/config/fonts/fontconfig.nix +++ b/nixos/modules/config/fonts/fontconfig.nix @@ -23,13 +23,10 @@ And do not repeat our mistakes. */ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.fonts.fontconfig; - fcBool = x: "" + (boolToString x) + ""; + fcBool = x: "" + (lib.boolToString x) + ""; pkg = pkgs.fontconfig; # configuration file to read fontconfig cache @@ -51,11 +48,11 @@ let - ${concatStringsSep "\n" (map (font: "${font}") config.fonts.packages)} - ${optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) '' + ${lib.concatStringsSep "\n" (map (font: "${font}") config.fonts.packages)} + ${lib.optionalString (pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) '' ${cache} - ${optionalString (pkgs.stdenv.isx86_64 && cfg.cache32Bit) '' + ${lib.optionalString (pkgs.stdenv.hostPlatform.isx86_64 && cfg.cache32Bit) '' ${cache32} ''} ''} @@ -89,11 +86,11 @@ let # priority 52 defaultFontsConf = let genDefault = fonts: name: - optionalString (fonts != []) '' + lib.optionalString (fonts != []) '' ${name} - ${concatStringsSep "" + ${lib.concatStringsSep "" (map (font: '' ${font} '') fonts)} @@ -125,7 +122,7 @@ let - ${optionalString (!cfg.allowBitmaps) '' + ${lib.optionalString (!cfg.allowBitmaps) '' @@ -191,22 +188,22 @@ let ln -s ${pkg.out}/etc/fonts/conf.d/*.conf \ $dst/ - ${optionalString (!cfg.antialias) + ${lib.optionalString (!cfg.antialias) (replaceDefaultConfig "10-yes-antialias.conf" "10-no-antialias.conf") } - ${optionalString (cfg.hinting.style != "slight") + ${lib.optionalString (cfg.hinting.style != "slight") (replaceDefaultConfig "10-hinting-slight.conf" "10-hinting-${cfg.hinting.style}.conf") } - ${optionalString (cfg.subpixel.rgba != "none") + ${lib.optionalString (cfg.subpixel.rgba != "none") (replaceDefaultConfig "10-sub-pixel-none.conf" "10-sub-pixel-${cfg.subpixel.rgba}.conf") } - ${optionalString (cfg.subpixel.lcdfilter != "default") + ${lib.optionalString (cfg.subpixel.lcdfilter != "default") (replaceDefaultConfig "11-lcdfilter-default.conf" "11-lcdfilter-${cfg.subpixel.lcdfilter}.conf") } @@ -218,12 +215,12 @@ let ln -s ${renderConf} $dst/10-nixos-rendering.conf # 50-user.conf - ${optionalString (!cfg.includeUserConf) '' + ${lib.optionalString (!cfg.includeUserConf) '' rm $dst/50-user.conf ''} # local.conf (indirect priority 51) - ${optionalString (cfg.localConf != "") '' + ${lib.optionalString (cfg.localConf != "") '' ln -s ${localConf} $dst/../local.conf ''} @@ -233,7 +230,7 @@ let # 53-no-bitmaps.conf ln -s ${rejectBitmaps} $dst/53-no-bitmaps.conf - ${optionalString (!cfg.allowType1) '' + ${lib.optionalString (!cfg.allowType1) '' # 53-nixos-reject-type1.conf ln -s ${rejectType1} $dst/53-nixos-reject-type1.conf ''} @@ -251,16 +248,16 @@ let in { imports = [ - (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowBitmaps" ] [ "fonts" "fontconfig" "allowBitmaps" ]) - (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowType1" ] [ "fonts" "fontconfig" "allowType1" ]) - (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ] [ "fonts" "fontconfig" "useEmbeddedBitmaps" ]) - (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "fonts" "fontconfig" "forceAutohint" ]) - (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ]) - (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "") - (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "") - (mkRemovedOptionModule [ "fonts" "fontconfig" "dpi" ] "Use display server-specific options") - (mkRemovedOptionModule [ "hardware" "video" "hidpi" "enable" ] fontconfigNote) - (mkRemovedOptionModule [ "fonts" "optimizeForVeryHighDPI" ] fontconfigNote) + (lib.mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowBitmaps" ] [ "fonts" "fontconfig" "allowBitmaps" ]) + (lib.mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "allowType1" ] [ "fonts" "fontconfig" "allowType1" ]) + (lib.mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "useEmbeddedBitmaps" ] [ "fonts" "fontconfig" "useEmbeddedBitmaps" ]) + (lib.mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "fonts" "fontconfig" "forceAutohint" ]) + (lib.mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ]) + (lib.mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "") + (lib.mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "") + (lib.mkRemovedOptionModule [ "fonts" "fontconfig" "dpi" ] "Use display server-specific options") + (lib.mkRemovedOptionModule [ "hardware" "video" "hidpi" "enable" ] fontconfigNote) + (lib.mkRemovedOptionModule [ "fonts" "optimizeForVeryHighDPI" ] fontconfigNote) ] ++ lib.forEach [ "enable" "substitutions" "preset" ] (opt: lib.mkRemovedOptionModule [ "fonts" "fontconfig" "ultimate" "${opt}" ] '' The fonts.fontconfig.ultimate module and configuration is obsolete. @@ -275,8 +272,8 @@ in fonts = { fontconfig = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' If enabled, a Fontconfig configuration file will be built @@ -287,17 +284,17 @@ in ''; }; - confPackages = mkOption { + confPackages = lib.mkOption { internal = true; - type = with types; listOf path; + type = with lib.types; listOf path; default = [ ]; description = '' Fontconfig configuration packages. ''; }; - antialias = mkOption { - type = types.bool; + antialias = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable font antialiasing. At high resolution (> 200 DPI), @@ -306,8 +303,8 @@ in ''; }; - localConf = mkOption { - type = types.lines; + localConf = lib.mkOption { + type = lib.types.lines; default = ""; description = '' System-wide customization file contents, has higher priority than @@ -316,8 +313,8 @@ in }; defaultFonts = { - monospace = mkOption { - type = types.listOf types.str; + monospace = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["DejaVu Sans Mono"]; description = '' System-wide default monospace font(s). Multiple fonts may be @@ -325,8 +322,8 @@ in ''; }; - sansSerif = mkOption { - type = types.listOf types.str; + sansSerif = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["DejaVu Sans"]; description = '' System-wide default sans serif font(s). Multiple fonts may be @@ -334,8 +331,8 @@ in ''; }; - serif = mkOption { - type = types.listOf types.str; + serif = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["DejaVu Serif"]; description = '' System-wide default serif font(s). Multiple fonts may be listed @@ -343,8 +340,8 @@ in ''; }; - emoji = mkOption { - type = types.listOf types.str; + emoji = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["Noto Color Emoji"]; description = '' System-wide default emoji font(s). Multiple fonts may be listed @@ -360,8 +357,8 @@ in }; hinting = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable font hinting. Hinting aligns glyphs to pixel boundaries to @@ -371,8 +368,8 @@ in ''; }; - autohint = mkOption { - type = types.bool; + autohint = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable the autohinter in place of the default interpreter. @@ -381,8 +378,8 @@ in ''; }; - style = mkOption { - type = types.enum ["none" "slight" "medium" "full"]; + style = lib.mkOption { + type = lib.types.enum ["none" "slight" "medium" "full"]; default = "slight"; description = '' Hintstyle is the amount of font reshaping done to line up @@ -404,8 +401,8 @@ in }; }; - includeUserConf = mkOption { - type = types.bool; + includeUserConf = lib.mkOption { + type = lib.types.bool; default = true; description = '' Include the user configuration from @@ -416,9 +413,9 @@ in subpixel = { - rgba = mkOption { + rgba = lib.mkOption { default = "none"; - type = types.enum ["rgb" "bgr" "vrgb" "vbgr" "none"]; + type = lib.types.enum ["rgb" "bgr" "vrgb" "vbgr" "none"]; description = '' Subpixel order. The overwhelming majority of displays are `rgb` in their normal orientation. Select @@ -432,9 +429,9 @@ in ''; }; - lcdfilter = mkOption { + lcdfilter = lib.mkOption { default = "default"; - type = types.enum ["none" "default" "light" "legacy"]; + type = lib.types.enum ["none" "default" "light" "legacy"]; description = '' FreeType LCD filter. At high resolution (> 200 DPI), LCD filtering has no visible effect; users of such displays may want to select @@ -444,16 +441,16 @@ in }; - cache32Bit = mkOption { + cache32Bit = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Generate system fonts cache for 32-bit applications. ''; }; - allowBitmaps = mkOption { - type = types.bool; + allowBitmaps = lib.mkOption { + type = lib.types.bool; default = true; description = '' Allow bitmap fonts. Set to `false` to ban all @@ -461,8 +458,8 @@ in ''; }; - allowType1 = mkOption { - type = types.bool; + allowType1 = lib.mkOption { + type = lib.types.bool; default = false; description = '' Allow Type-1 fonts. Default is `false` because of @@ -470,8 +467,8 @@ in ''; }; - useEmbeddedBitmaps = mkOption { - type = types.bool; + useEmbeddedBitmaps = lib.mkOption { + type = lib.types.bool; default = false; description = "Use embedded bitmaps in fonts like Calibri."; }; @@ -481,8 +478,8 @@ in }; }; - config = mkMerge [ - (mkIf cfg.enable { + config = lib.mkMerge [ + (lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.fontconfig ]; environment.etc.fonts.source = "${fontconfigEtc}/etc/fonts/"; security.apparmor.includes."abstractions/fonts" = '' @@ -499,12 +496,12 @@ in r ${renderConf}, # 50-user.conf - ${optionalString cfg.includeUserConf '' + ${lib.optionalString cfg.includeUserConf '' r ${pkg.out}/etc/fonts/conf.d.bak/50-user.conf, ''} # local.conf (indirect priority 51) - ${optionalString (cfg.localConf != "") '' + ${lib.optionalString (cfg.localConf != "") '' r ${localConf}, ''} @@ -514,13 +511,13 @@ in # 53-no-bitmaps.conf r ${rejectBitmaps}, - ${optionalString (!cfg.allowType1) '' + ${lib.optionalString (!cfg.allowType1) '' # 53-nixos-reject-type1.conf r ${rejectType1}, ''} ''; }) - (mkIf cfg.enable { + (lib.mkIf cfg.enable { fonts.fontconfig.confPackages = [ confPkg ]; }) ]; diff --git a/nixos/modules/config/fonts/fontdir.nix b/nixos/modules/config/fonts/fontdir.nix index 7b21fe30f607..0181883d6c5c 100644 --- a/nixos/modules/config/fonts/fontdir.nix +++ b/nixos/modules/config/fonts/fontdir.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.fonts.fontDir; @@ -12,7 +9,7 @@ let find ${toString config.fonts.packages} -regex "$font_regexp" \ -exec ln -sf -t "$out/share/X11/fonts" '{}' \; cd "$out/share/X11/fonts" - ${optionalString cfg.decompressFonts '' + ${lib.optionalString cfg.decompressFonts '' ${pkgs.gzip}/bin/gunzip -f *.gz ''} ${pkgs.xorg.mkfontscale}/bin/mkfontscale @@ -27,8 +24,8 @@ in options = { fonts.fontDir = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to create a directory with links to all fonts in @@ -36,10 +33,10 @@ in ''; }; - decompressFonts = mkOption { - type = types.bool; + decompressFonts = lib.mkOption { + type = lib.types.bool; default = config.programs.xwayland.enable; - defaultText = literalExpression "config.programs.xwayland.enable"; + defaultText = lib.literalExpression "config.programs.xwayland.enable"; description = '' Whether to decompress fonts in {file}`/run/current-system/sw/share/X11/fonts`. @@ -49,7 +46,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ x11Fonts ]; environment.pathsToLink = [ "/share/X11/fonts" ]; @@ -61,7 +58,7 @@ in }; imports = [ - (mkRenamedOptionModule [ "fonts" "enableFontDir" ] [ "fonts" "fontDir" "enable" ]) + (lib.mkRenamedOptionModule [ "fonts" "enableFontDir" ] [ "fonts" "fontDir" "enable" ]) ]; } diff --git a/nixos/modules/config/fonts/ghostscript.nix b/nixos/modules/config/fonts/ghostscript.nix index 5db7c0ac7179..dd28c72bba76 100644 --- a/nixos/modules/config/fonts/ghostscript.nix +++ b/nixos/modules/config/fonts/ghostscript.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - { options = { - fonts.enableGhostscriptFonts = mkOption { - type = types.bool; + fonts.enableGhostscriptFonts = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to add the fonts provided by Ghostscript (such as @@ -17,7 +14,7 @@ with lib; }; - config = mkIf config.fonts.enableGhostscriptFonts { + config = lib.mkIf config.fonts.enableGhostscriptFonts { fonts.packages = [ pkgs.ghostscript.fonts ]; }; } diff --git a/nixos/modules/config/gtk/gtk-icon-cache.nix b/nixos/modules/config/gtk/gtk-icon-cache.nix index 0898260d4a59..d9d6031956a6 100644 --- a/nixos/modules/config/gtk/gtk-icon-cache.nix +++ b/nixos/modules/config/gtk/gtk-icon-cache.nix @@ -1,19 +1,17 @@ { config, lib, pkgs, ... }: - -with lib; { options = { - gtk.iconCache.enable = mkOption { - type = types.bool; + gtk.iconCache.enable = lib.mkOption { + type = lib.types.bool; default = config.services.xserver.enable; - defaultText = literalExpression "config.services.xserver.enable"; + defaultText = lib.literalExpression "config.services.xserver.enable"; description = '' Whether to build icon theme caches for GTK applications. ''; }; }; - config = mkIf config.gtk.iconCache.enable { + config = lib.mkIf config.gtk.iconCache.enable { # (Re)build icon theme caches # --------------------------- diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix index 9d2d3c23beb3..515805ef5b1b 100644 --- a/nixos/modules/config/i18n.nix +++ b/nixos/modules/config/i18n.nix @@ -1,26 +1,23 @@ { config, lib, pkgs, ... }: - -with lib; - { ###### interface options = { i18n = { - glibcLocales = mkOption { - type = types.path; + glibcLocales = lib.mkOption { + type = lib.types.path; default = pkgs.glibcLocales.override { - allLocales = any (x: x == "all") config.i18n.supportedLocales; + allLocales = lib.any (x: x == "all") config.i18n.supportedLocales; locales = config.i18n.supportedLocales; }; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' pkgs.glibcLocales.override { - allLocales = any (x: x == "all") config.i18n.supportedLocales; + allLocales = lib.any (x: x == "all") config.i18n.supportedLocales; locales = config.i18n.supportedLocales; } ''; - example = literalExpression "pkgs.glibcLocales"; + example = lib.literalExpression "pkgs.glibcLocales"; description = '' Customized pkg.glibcLocales package. @@ -29,8 +26,8 @@ with lib; ''; }; - defaultLocale = mkOption { - type = types.str; + defaultLocale = lib.mkOption { + type = lib.types.str; default = "en_US.UTF-8"; example = "nl_NL.UTF-8"; description = '' @@ -40,8 +37,8 @@ with lib; ''; }; - extraLocaleSettings = mkOption { - type = types.attrsOf types.str; + extraLocaleSettings = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = {}; example = { LC_MESSAGES = "en_US.UTF-8"; LC_TIME = "de_DE.UTF-8"; }; description = '' @@ -51,24 +48,24 @@ with lib; ''; }; - supportedLocales = mkOption { - type = types.listOf types.str; - default = unique - (builtins.map (l: (replaceStrings [ "utf8" "utf-8" "UTF8" ] [ "UTF-8" "UTF-8" "UTF-8" ] l) + "/UTF-8") ( + supportedLocales = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = lib.unique + (builtins.map (l: (lib.replaceStrings [ "utf8" "utf-8" "UTF8" ] [ "UTF-8" "UTF-8" "UTF-8" ] l) + "/UTF-8") ( [ "C.UTF-8" "en_US.UTF-8" config.i18n.defaultLocale - ] ++ (attrValues (filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings)) + ] ++ (lib.attrValues (lib.filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings)) )); - defaultText = literalExpression '' - unique - (builtins.map (l: (replaceStrings [ "utf8" "utf-8" "UTF8" ] [ "UTF-8" "UTF-8" "UTF-8" ] l) + "/UTF-8") ( + defaultText = lib.literalExpression '' + lib.unique + (builtins.map (l: (lib.replaceStrings [ "utf8" "utf-8" "UTF8" ] [ "UTF-8" "UTF-8" "UTF-8" ] l) + "/UTF-8") ( [ "C.UTF-8" "en_US.UTF-8" config.i18n.defaultLocale - ] ++ (attrValues (filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings)) + ] ++ (lib.attrValues (lib.filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings)) )) ''; example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"]; @@ -91,14 +88,14 @@ with lib; environment.systemPackages = # We increase the priority a little, so that plain glibc in systemPackages can't win. - optional (config.i18n.supportedLocales != []) (lib.setPrio (-1) config.i18n.glibcLocales); + lib.optional (config.i18n.supportedLocales != []) (lib.setPrio (-1) config.i18n.glibcLocales); environment.sessionVariables = { LANG = config.i18n.defaultLocale; LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; } // config.i18n.extraLocaleSettings; - systemd.globalEnvironment = mkIf (config.i18n.supportedLocales != []) { + systemd.globalEnvironment = lib.mkIf (config.i18n.supportedLocales != []) { LOCALE_ARCHIVE = "${config.i18n.glibcLocales}/lib/locale/locale-archive"; }; @@ -106,7 +103,7 @@ with lib; environment.etc."locale.conf".source = pkgs.writeText "locale.conf" '' LANG=${config.i18n.defaultLocale} - ${concatStringsSep "\n" (mapAttrsToList (n: v: "${n}=${v}") config.i18n.extraLocaleSettings)} + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "${n}=${v}") config.i18n.extraLocaleSettings)} ''; }; diff --git a/nixos/modules/config/iproute2.nix b/nixos/modules/config/iproute2.nix index 90f53c0eab69..1fa28a7a4c64 100644 --- a/nixos/modules/config/iproute2.nix +++ b/nixos/modules/config/iproute2.nix @@ -1,15 +1,12 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.networking.iproute2; in { options.networking.iproute2 = { - enable = mkEnableOption "copying IP route configuration files"; - rttablesExtraConfig = mkOption { - type = types.lines; + enable = lib.mkEnableOption "copying IP route configuration files"; + rttablesExtraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Verbatim lines to add to /etc/iproute2/rt_tables @@ -17,7 +14,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.etc."iproute2/rt_tables.d/nixos.conf" = { mode = "0644"; text = cfg.rttablesExtraConfig; diff --git a/nixos/modules/config/ldso.nix b/nixos/modules/config/ldso.nix index 60156dd04098..f8d89db0220e 100644 --- a/nixos/modules/config/ldso.nix +++ b/nixos/modules/config/ldso.nix @@ -32,7 +32,7 @@ in { config = { assertions = [ - { assertion = isNull config.environment.ldso32 || pkgs.stdenv.isx86_64; + { assertion = isNull config.environment.ldso32 || pkgs.stdenv.hostPlatform.isx86_64; message = "Option environment.ldso32 currently only works on x86_64."; } ]; @@ -44,7 +44,7 @@ in { "d /${libDir} 0755 root root - -" "L+ /${libDir}/${ldsoBasename} - - - - ${config.environment.ldso}" ] - ) ++ optionals pkgs.stdenv.isx86_64 ( + ) ++ optionals pkgs.stdenv.hostPlatform.isx86_64 ( if isNull config.environment.ldso32 then [ "r /${libDir32}/${ldsoBasename32} - - - - -" ] else [ diff --git a/nixos/modules/config/locale.nix b/nixos/modules/config/locale.nix index 486246081ec6..2d64f1bce4bc 100644 --- a/nixos/modules/config/locale.nix +++ b/nixos/modules/config/locale.nix @@ -1,12 +1,9 @@ { config, lib, pkgs, ... }: - -with lib; - let tzdir = "${pkgs.tzdata}/share/zoneinfo"; - nospace = str: filter (c: c == " ") (stringToCharacters str) == []; - timezone = types.nullOr (types.addCheck types.str nospace) + nospace = str: lib.filter (c: c == " ") (lib.stringToCharacters str) == []; + timezone = lib.types.nullOr (lib.types.addCheck lib.types.str nospace) // { description = "null or string without spaces"; }; lcfg = config.location; @@ -18,7 +15,7 @@ in time = { - timeZone = mkOption { + timeZone = lib.mkOption { default = null; type = timezone; example = "America/New_York"; @@ -31,9 +28,9 @@ in ''; }; - hardwareClockInLocalTime = mkOption { + hardwareClockInLocalTime = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "If set, keep the hardware clock in local time instead of UTC."; }; @@ -41,8 +38,8 @@ in location = { - latitude = mkOption { - type = types.float; + latitude = lib.mkOption { + type = lib.types.float; description = '' Your current latitude, between `-90.0` and `90.0`. Must be provided @@ -50,8 +47,8 @@ in ''; }; - longitude = mkOption { - type = types.float; + longitude = lib.mkOption { + type = lib.types.float; description = '' Your current longitude, between between `-180.0` and `180.0`. Must be @@ -59,8 +56,8 @@ in ''; }; - provider = mkOption { - type = types.enum [ "manual" "geoclue2" ]; + provider = lib.mkOption { + type = lib.types.enum [ "manual" "geoclue2" ]; default = "manual"; description = '' The location provider to use for determining your location. If set to @@ -75,7 +72,7 @@ in environment.sessionVariables.TZDIR = "/etc/zoneinfo"; - services.geoclue2.enable = mkIf (lcfg.provider == "geoclue2") true; + services.geoclue2.enable = lib.mkIf (lcfg.provider == "geoclue2") true; # This way services are restarted when tzdata changes. systemd.globalEnvironment.TZDIR = tzdir; diff --git a/nixos/modules/config/malloc.nix b/nixos/modules/config/malloc.nix index e414970b0be5..665cbdd27874 100644 --- a/nixos/modules/config/malloc.nix +++ b/nixos/modules/config/malloc.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.environment.memoryAllocator; @@ -85,12 +83,12 @@ in { meta = { - maintainers = [ maintainers.joachifm ]; + maintainers = [ lib.maintainers.joachifm ]; }; options = { - environment.memoryAllocator.provider = mkOption { - type = types.enum ([ "libc" ] ++ attrNames providers); + environment.memoryAllocator.provider = lib.mkOption { + type = lib.types.enum ([ "libc" ] ++ lib.attrNames providers); default = "libc"; description = '' The system-wide memory allocator. @@ -98,8 +96,8 @@ in Briefly, the system-wide memory allocator providers are: - `libc`: the standard allocator provided by libc - ${concatStringsSep "\n" (mapAttrsToList - (name: value: "- `${name}`: ${replaceStrings [ "\n" ] [ " " ] value.description}") + ${lib.concatStringsSep "\n" (lib.mapAttrsToList + (name: value: "- `${name}`: ${lib.replaceStrings [ "\n" ] [ " " ] value.description}") providers)} ::: {.warning} @@ -111,7 +109,7 @@ in }; }; - config = mkIf (cfg.provider != "libc") { + config = lib.mkIf (cfg.provider != "libc") { environment.etc."ld-nix.so.preload".text = '' ${providerLibPath} ''; diff --git a/nixos/modules/config/mysql.nix b/nixos/modules/config/mysql.nix index e1f9e223cc59..6b82603aa455 100644 --- a/nixos/modules/config/mysql.nix +++ b/nixos/modules/config/mysql.nix @@ -1,47 +1,44 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.users.mysql; in { - meta.maintainers = [ maintainers.netali ]; + meta.maintainers = [ lib.maintainers.netali ]; options = { users.mysql = { - enable = mkEnableOption "authentication against a MySQL/MariaDB database"; - host = mkOption { - type = types.str; + enable = lib.mkEnableOption "authentication against a MySQL/MariaDB database"; + host = lib.mkOption { + type = lib.types.str; example = "localhost"; description = "The hostname of the MySQL/MariaDB server"; }; - database = mkOption { - type = types.str; + database = lib.mkOption { + type = lib.types.str; example = "auth"; description = "The name of the database containing the users"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; example = "nss-user"; description = "The username to use when connecting to the database"; }; - passwordFile = mkOption { - type = types.path; + passwordFile = lib.mkOption { + type = lib.types.path; example = "/run/secrets/mysql-auth-db-passwd"; description = "The path to the file containing the password for the user"; }; - pam = mkOption { + pam = lib.mkOption { description = "Settings for `pam_mysql`"; - type = types.submodule { + type = lib.types.submodule { options = { - table = mkOption { - type = types.str; + table = lib.mkOption { + type = lib.types.str; example = "users"; description = "The name of table that maps unique login names to the passwords."; }; - updateTable = mkOption { - type = types.nullOr types.str; + updateTable = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "users_updates"; description = '' @@ -49,18 +46,18 @@ in of the `table` option will be used instead. ''; }; - userColumn = mkOption { - type = types.str; + userColumn = lib.mkOption { + type = lib.types.str; example = "username"; description = "The name of the column that contains a unix login name."; }; - passwordColumn = mkOption { - type = types.str; + passwordColumn = lib.mkOption { + type = lib.types.str; example = "password"; description = "The name of the column that contains a (encrypted) password string."; }; - statusColumn = mkOption { - type = types.nullOr types.str; + statusColumn = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "status"; description = '' @@ -79,9 +76,9 @@ in This ends up requiring that the user enter a new password. ''; }; - passwordCrypt = mkOption { + passwordCrypt = lib.mkOption { example = "2"; - type = types.enum [ + type = lib.types.enum [ "0" "plain" "1" "Y" "2" "mysql" @@ -121,28 +118,28 @@ in Use sha256 hashed passwords. ''; }; - cryptDefault = mkOption { - type = types.nullOr (types.enum [ "md5" "sha256" "sha512" "blowfish" ]); + cryptDefault = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "md5" "sha256" "sha512" "blowfish" ]); default = null; example = "blowfish"; description = "The default encryption method to use for `passwordCrypt = 1`."; }; - where = mkOption { - type = types.nullOr types.str; + where = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "host.name='web' AND user.active=1"; description = "Additional criteria for the query."; }; - verbose = mkOption { - type = types.bool; + verbose = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, produces logs with detailed messages that describes what `pam_mysql` is doing. May be useful for debugging. ''; }; - disconnectEveryOperation = mkOption { - type = types.bool; + disconnectEveryOperation = lib.mkOption { + type = lib.types.bool; default = false; description = '' By default, `pam_mysql` keeps the connection to the MySQL @@ -152,34 +149,34 @@ in ''; }; logging = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enables logging of authentication attempts in the MySQL database."; }; - table = mkOption { - type = types.str; + table = lib.mkOption { + type = lib.types.str; example = "logs"; description = "The name of the table to which logs are written."; }; - msgColumn = mkOption { - type = types.str; + msgColumn = lib.mkOption { + type = lib.types.str; example = "msg"; description = '' The name of the column in the log table to which the description of the performed operation is stored. ''; }; - userColumn = mkOption { - type = types.str; + userColumn = lib.mkOption { + type = lib.types.str; example = "user"; description = '' The name of the column in the log table to which the name of the user being authenticated is stored. ''; }; - pidColumn = mkOption { - type = types.str; + pidColumn = lib.mkOption { + type = lib.types.str; example = "pid"; description = '' The name of the column in the log table to which the pid of the @@ -187,16 +184,16 @@ in service is stored. ''; }; - hostColumn = mkOption { - type = types.str; + hostColumn = lib.mkOption { + type = lib.types.str; example = "host"; description = '' The name of the column in the log table to which the name of the user being authenticated is stored. ''; }; - rHostColumn = mkOption { - type = types.str; + rHostColumn = lib.mkOption { + type = lib.types.str; example = "rhost"; description = '' The name of the column in the log table to which the name of the remote @@ -204,8 +201,8 @@ in set by the PAM-aware application with `pam_set_item(PAM_RHOST)`. ''; }; - timeColumn = mkOption { - type = types.str; + timeColumn = lib.mkOption { + type = lib.types.str; example = "timestamp"; description = '' The name of the column in the log table to which the timestamp of the @@ -216,19 +213,19 @@ in }; }; }; - nss = mkOption { + nss = lib.mkOption { description = '' Settings for `libnss-mysql`. All examples are from the [minimal example](https://github.com/saknopper/libnss-mysql/tree/master/sample/minimal) of `libnss-mysql`, but they are modified with NixOS paths for bash. ''; - type = types.submodule { + type = lib.types.submodule { options = { - getpwnam = mkOption { - type = types.nullOr types.str; + getpwnam = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT username,'x',uid,'5000','MySQL User', CONCAT('/home/',username),'/run/sw/current-system/bin/bash' \ FROM users \ WHERE username='%1$s' \ @@ -239,10 +236,10 @@ in syscall. ''; }; - getpwuid = mkOption { - type = types.nullOr types.str; + getpwuid = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT username,'x',uid,'5000','MySQL User', CONCAT('/home/',username),'/run/sw/current-system/bin/bash' \ FROM users \ WHERE uid='%1$u' \ @@ -253,10 +250,10 @@ in syscall. ''; }; - getspnam = mkOption { - type = types.nullOr types.str; + getspnam = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT username,password,'1','0','99999','0','0','-1','0' \ FROM users \ WHERE username='%1$s' \ @@ -267,10 +264,10 @@ in syscall. ''; }; - getpwent = mkOption { - type = types.nullOr types.str; + getpwent = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT username,'x',uid,'5000','MySQL User', CONCAT('/home/',username),'/run/sw/current-system/bin/bash' FROM users ''; description = '' @@ -278,10 +275,10 @@ in syscall. ''; }; - getspent = mkOption { - type = types.nullOr types.str; + getspent = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT username,password,'1','0','99999','0','0','-1','0' FROM users ''; description = '' @@ -289,10 +286,10 @@ in syscall. ''; }; - getgrnam = mkOption { - type = types.nullOr types.str; + getgrnam = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT name,password,gid FROM groups WHERE name='%1$s' LIMIT 1 ''; description = '' @@ -300,10 +297,10 @@ in syscall. ''; }; - getgrgid = mkOption { - type = types.nullOr types.str; + getgrgid = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT name,password,gid FROM groups WHERE gid='%1$u' LIMIT 1 ''; description = '' @@ -311,10 +308,10 @@ in syscall. ''; }; - getgrent = mkOption { - type = types.nullOr types.str; + getgrent = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT name,password,gid FROM groups ''; description = '' @@ -322,10 +319,10 @@ in syscall. ''; }; - memsbygid = mkOption { - type = types.nullOr types.str; + memsbygid = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT username FROM grouplist WHERE gid='%1$u' ''; description = '' @@ -333,10 +330,10 @@ in syscall. ''; }; - gidsbymem = mkOption { - type = types.nullOr types.str; + gidsbymem = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; - example = literalExpression '' + example = lib.literalExpression '' SELECT gid FROM grouplist WHERE username='%1$s' ''; description = '' @@ -350,7 +347,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { system.nssModules = [ pkgs.libnss-mysql ]; system.nssDatabases.shadow = [ "mysql" ]; system.nssDatabases.group = [ "mysql" ]; @@ -371,15 +368,15 @@ in users.password_crypt=${cfg.pam.passwordCrypt} users.disconnect_every_operation=${if cfg.pam.disconnectEveryOperation then "1" else "0"} verbose=${if cfg.pam.verbose then "1" else "0"} - '' + optionalString (cfg.pam.cryptDefault != null) '' + '' + lib.optionalString (cfg.pam.cryptDefault != null) '' users.use_${cfg.pam.cryptDefault}=1 - '' + optionalString (cfg.pam.where != null) '' + '' + lib.optionalString (cfg.pam.where != null) '' users.where_clause=${cfg.pam.where} - '' + optionalString (cfg.pam.statusColumn != null) '' + '' + lib.optionalString (cfg.pam.statusColumn != null) '' users.status_column=${cfg.pam.statusColumn} - '' + optionalString (cfg.pam.updateTable != null) '' + '' + lib.optionalString (cfg.pam.updateTable != null) '' users.update_table=${cfg.pam.updateTable} - '' + optionalString cfg.pam.logging.enable '' + '' + lib.optionalString cfg.pam.logging.enable '' log.enabled=true log.table=${cfg.pam.logging.table} log.message_column=${cfg.pam.logging.msgColumn} @@ -395,25 +392,25 @@ in mode = "0600"; user = config.services.nscd.user; group = config.services.nscd.group; - text = optionalString (cfg.nss.getpwnam != null) '' + text = lib.optionalString (cfg.nss.getpwnam != null) '' getpwnam ${cfg.nss.getpwnam} - '' + optionalString (cfg.nss.getpwuid != null) '' + '' + lib.optionalString (cfg.nss.getpwuid != null) '' getpwuid ${cfg.nss.getpwuid} - '' + optionalString (cfg.nss.getspnam != null) '' + '' + lib.optionalString (cfg.nss.getspnam != null) '' getspnam ${cfg.nss.getspnam} - '' + optionalString (cfg.nss.getpwent != null) '' + '' + lib.optionalString (cfg.nss.getpwent != null) '' getpwent ${cfg.nss.getpwent} - '' + optionalString (cfg.nss.getspent != null) '' + '' + lib.optionalString (cfg.nss.getspent != null) '' getspent ${cfg.nss.getspent} - '' + optionalString (cfg.nss.getgrnam != null) '' + '' + lib.optionalString (cfg.nss.getgrnam != null) '' getgrnam ${cfg.nss.getgrnam} - '' + optionalString (cfg.nss.getgrgid != null) '' + '' + lib.optionalString (cfg.nss.getgrgid != null) '' getgrgid ${cfg.nss.getgrgid} - '' + optionalString (cfg.nss.getgrent != null) '' + '' + lib.optionalString (cfg.nss.getgrent != null) '' getgrent ${cfg.nss.getgrent} - '' + optionalString (cfg.nss.memsbygid != null) '' + '' + lib.optionalString (cfg.nss.memsbygid != null) '' memsbygid ${cfg.nss.memsbygid} - '' + optionalString (cfg.nss.gidsbymem != null) '' + '' + lib.optionalString (cfg.nss.gidsbymem != null) '' gidsbymem ${cfg.nss.gidsbymem} '' + '' host ${cfg.host} diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix index 72242b263ce0..8665a611e575 100644 --- a/nixos/modules/config/networking.nix +++ b/nixos/modules/config/networking.nix @@ -1,28 +1,24 @@ # /etc files related to networking, such as /etc/services. - { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.networking; opt = options.networking; - localhostMultiple = any (elem "localhost") (attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ])); + localhostMultiple = lib.any (lib.elem "localhost") (lib.attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ])); in { imports = [ - (mkRemovedOptionModule [ "networking" "hostConf" ] "Use environment.etc.\"host.conf\" instead.") + (lib.mkRemovedOptionModule [ "networking" "hostConf" ] "Use environment.etc.\"host.conf\" instead.") ]; options = { networking.hosts = lib.mkOption { - type = types.attrsOf (types.listOf types.str); - example = literalExpression '' + type = lib.types.attrsOf (lib.types.listOf lib.types.str); + example = lib.literalExpression '' { "127.0.0.1" = [ "foo.bar.baz" ]; "192.168.0.2" = [ "fileserver.local" "nameserver.local" ]; @@ -34,16 +30,16 @@ in }; networking.hostFiles = lib.mkOption { - type = types.listOf types.path; - defaultText = literalMD "Hosts from {option}`networking.hosts` and {option}`networking.extraHosts`"; - example = literalExpression ''[ "''${pkgs.my-blocklist-package}/share/my-blocklist/hosts" ]''; + type = lib.types.listOf lib.types.path; + defaultText = lib.literalMD "Hosts from {option}`networking.hosts` and {option}`networking.extraHosts`"; + example = lib.literalExpression ''[ "''${pkgs.my-blocklist-package}/share/my-blocklist/hosts" ]''; description = '' Files that should be concatenated together to form {file}`/etc/hosts`. ''; }; networking.extraHosts = lib.mkOption { - type = types.lines; + type = lib.types.lines; default = ""; example = "192.168.0.1 lanlocalhost"; description = '' @@ -52,14 +48,14 @@ in ''; }; - networking.timeServers = mkOption { + networking.timeServers = lib.mkOption { default = [ "0.nixos.pool.ntp.org" "1.nixos.pool.ntp.org" "2.nixos.pool.ntp.org" "3.nixos.pool.ntp.org" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' The set of NTP servers from which to synchronise. ''; @@ -68,7 +64,7 @@ in networking.proxy = { default = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; description = '' This option specifies the default value for httpProxy, httpsProxy, ftpProxy and rsyncProxy. @@ -77,9 +73,9 @@ in }; httpProxy = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = cfg.proxy.default; - defaultText = literalExpression "config.${opt.proxy.default}"; + defaultText = lib.literalExpression "config.${opt.proxy.default}"; description = '' This option specifies the http_proxy environment variable. ''; @@ -87,9 +83,9 @@ in }; httpsProxy = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = cfg.proxy.default; - defaultText = literalExpression "config.${opt.proxy.default}"; + defaultText = lib.literalExpression "config.${opt.proxy.default}"; description = '' This option specifies the https_proxy environment variable. ''; @@ -97,9 +93,9 @@ in }; ftpProxy = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = cfg.proxy.default; - defaultText = literalExpression "config.${opt.proxy.default}"; + defaultText = lib.literalExpression "config.${opt.proxy.default}"; description = '' This option specifies the ftp_proxy environment variable. ''; @@ -107,9 +103,9 @@ in }; rsyncProxy = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = cfg.proxy.default; - defaultText = literalExpression "config.${opt.proxy.default}"; + defaultText = lib.literalExpression "config.${opt.proxy.default}"; description = '' This option specifies the rsync_proxy environment variable. ''; @@ -117,9 +113,9 @@ in }; allProxy = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = cfg.proxy.default; - defaultText = literalExpression "config.${opt.proxy.default}"; + defaultText = lib.literalExpression "config.${opt.proxy.default}"; description = '' This option specifies the all_proxy environment variable. ''; @@ -127,7 +123,7 @@ in }; noProxy = lib.mkOption { - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; description = '' This option specifies the no_proxy environment variable. @@ -138,7 +134,7 @@ in }; envVars = lib.mkOption { - type = types.attrs; + type = lib.types.attrs; internal = true; default = {}; description = '' @@ -163,11 +159,11 @@ in # hostname and FQDN correctly: networking.hosts = let hostnames = # Note: The FQDN (canonical hostname) has to come first: - optional (cfg.hostName != "" && cfg.domain != null) "${cfg.hostName}.${cfg.domain}" - ++ optional (cfg.hostName != "") cfg.hostName; # Then the hostname (without the domain) + lib.optional (cfg.hostName != "" && cfg.domain != null) "${cfg.hostName}.${cfg.domain}" + ++ lib.optional (cfg.hostName != "") cfg.hostName; # Then the hostname (without the domain) in { "127.0.0.2" = hostnames; - } // optionalAttrs cfg.enableIPv6 { + } // lib.optionalAttrs cfg.enableIPv6 { "::1" = hostnames; }; @@ -178,15 +174,15 @@ in # FQDN so that e.g. "hostname -f" works correctly. localhostHosts = pkgs.writeText "localhost-hosts" '' 127.0.0.1 localhost - ${optionalString cfg.enableIPv6 "::1 localhost"} + ${lib.optionalString cfg.enableIPv6 "::1 localhost"} ''; stringHosts = let - oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip} + "\n"; - allToString = set: concatMapStrings (oneToString set) (attrNames set); - in pkgs.writeText "string-hosts" (allToString (filterAttrs (_: v: v != []) cfg.hosts)); + oneToString = set: ip: ip + " " + lib.concatStringsSep " " set.${ip} + "\n"; + allToString = set: lib.concatMapStrings (oneToString set) (lib.attrNames set); + in pkgs.writeText "string-hosts" (allToString (lib.filterAttrs (_: v: v != []) cfg.hosts)); extraHosts = pkgs.writeText "extra-hosts" cfg.extraHosts; - in mkBefore [ localhostHosts stringHosts extraHosts ]; + in lib.mkBefore [ localhostHosts stringHosts extraHosts ]; environment.etc = { # /etc/services: TCP/UDP port assignments. @@ -199,33 +195,33 @@ in hosts.source = pkgs.concatText "hosts" cfg.hostFiles; # /etc/netgroup: Network-wide groups. - netgroup.text = mkDefault ""; + netgroup.text = lib.mkDefault ""; # /etc/host.conf: resolver configuration file "host.conf".text = '' multi on ''; - } // optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") { + } // lib.optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") { # /etc/rpc: RPC program numbers. rpc.source = pkgs.stdenv.cc.libc.out + "/etc/rpc"; }; networking.proxy.envVars = - optionalAttrs (cfg.proxy.default != null) { + lib.optionalAttrs (cfg.proxy.default != null) { # other options already fallback to proxy.default no_proxy = "127.0.0.1,localhost"; - } // optionalAttrs (cfg.proxy.httpProxy != null) { + } // lib.optionalAttrs (cfg.proxy.httpProxy != null) { http_proxy = cfg.proxy.httpProxy; - } // optionalAttrs (cfg.proxy.httpsProxy != null) { + } // lib.optionalAttrs (cfg.proxy.httpsProxy != null) { https_proxy = cfg.proxy.httpsProxy; - } // optionalAttrs (cfg.proxy.rsyncProxy != null) { + } // lib.optionalAttrs (cfg.proxy.rsyncProxy != null) { rsync_proxy = cfg.proxy.rsyncProxy; - } // optionalAttrs (cfg.proxy.ftpProxy != null) { + } // lib.optionalAttrs (cfg.proxy.ftpProxy != null) { ftp_proxy = cfg.proxy.ftpProxy; - } // optionalAttrs (cfg.proxy.allProxy != null) { + } // lib.optionalAttrs (cfg.proxy.allProxy != null) { all_proxy = cfg.proxy.allProxy; - } // optionalAttrs (cfg.proxy.noProxy != null) { + } // lib.optionalAttrs (cfg.proxy.noProxy != null) { no_proxy = cfg.proxy.noProxy; }; diff --git a/nixos/modules/config/nix-flakes.nix b/nixos/modules/config/nix-flakes.nix index d6c31735a6ca..90e207fd4a61 100644 --- a/nixos/modules/config/nix-flakes.nix +++ b/nixos/modules/config/nix-flakes.nix @@ -72,7 +72,7 @@ in type = "path"; path = config.flake.outPath; } // filterAttrs - (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash") + (n: _: n == "lastModified" || n == "rev" || n == "narHash") config.flake )); }; diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix deleted file mode 100644 index 2448d08a2399..000000000000 --- a/nixos/modules/config/no-x-libs.nix +++ /dev/null @@ -1,95 +0,0 @@ -# This module gets rid of all dependencies on X11 client libraries -# (including fontconfig). - -{ config, lib, ... }: - -with lib; - -{ - options = { - environment.noXlibs = mkOption { - type = types.bool; - default = false; - description = '' - Switch off the options in the default configuration that - require X11 libraries. This includes client-side font - configuration and SSH forwarding of X11 authentication - in. Thus, you probably do not want to enable this option if - you want to run X11 programs on this machine via SSH. - ''; - }; - }; - - config = mkIf config.environment.noXlibs { - programs.ssh.setXAuthLocation = false; - security.pam.services.su.forwardXAuth = lib.mkForce false; - - fonts.fontconfig.enable = false; - - nixpkgs.overlays = singleton (const (super: { - beam = super.beam_nox; - cairo = super.cairo.override { x11Support = false; }; - dbus = super.dbus.override { x11Support = false; }; - fastfetch = super.fastfetch.override { vulkanSupport = false; waylandSupport = false; x11Support = false; }; - ffmpeg = super.ffmpeg.override { ffmpegVariant = "headless"; }; - ffmpeg_4 = super.ffmpeg_4.override { ffmpegVariant = "headless"; }; - ffmpeg_6 = super.ffmpeg_6.override { ffmpegVariant = "headless"; }; - ffmpeg_7 = super.ffmpeg_7.override { ffmpegVariant = "headless"; }; - # dep of graphviz, libXpm is optional for Xpm support - gd = super.gd.override { withXorg = false; }; - ghostscript = super.ghostscript.override { cupsSupport = false; x11Support = false; }; - gjs = (super.gjs.override { installTests = false; }).overrideAttrs { doCheck = false; }; # avoid test dependency on gtk3 - gobject-introspection = super.gobject-introspection.override { x11Support = false; }; - gpg-tui = super.gpg-tui.override { x11Support = false; }; - gpsd = super.gpsd.override { guiSupport = false; }; - graphviz = super.graphviz-nox; - gst_all_1 = super.gst_all_1 // { - gst-plugins-bad = super.gst_all_1.gst-plugins-bad.override { guiSupport = false; }; - gst-plugins-base = super.gst_all_1.gst-plugins-base.override { enableGl = false; enableWayland = false; enableX11 = false; }; - gst-plugins-good = super.gst_all_1.gst-plugins-good.override { enableWayland = false; enableX11 = false; gtkSupport = false; qt5Support = false; qt6Support = false; }; - gst-plugins-rs = super.gst_all_1.gst-plugins-rs.override { withGtkPlugins = false; }; - }; - imagemagick = super.imagemagick.override { libX11Support = false; libXtSupport = false; }; - imagemagickBig = super.imagemagickBig.override { libX11Support = false; libXtSupport = false; }; - intel-vaapi-driver = super.intel-vaapi-driver.override { enableGui = false; }; - libdevil = super.libdevil-nox; - libextractor = super.libextractor.override { gtkSupport = false; }; - libplacebo = super.libplacebo.override { vulkanSupport = false; }; - libva = super.libva-minimal; - limesuite = super.limesuite.override { withGui = false; }; - mc = super.mc.override { x11Support = false; }; - mpv-unwrapped = super.mpv-unwrapped.override { drmSupport = false; screenSaverSupport = false; sdl2Support = false; vulkanSupport = false; waylandSupport = false; x11Support = false; }; - msmtp = super.msmtp.override { withKeyring = false; }; - mupdf = super.mupdf.override { enableGL = false; enableX11 = false; }; - neofetch = super.neofetch.override { x11Support = false; }; - networkmanager-fortisslvpn = super.networkmanager-fortisslvpn.override { withGnome = false; }; - networkmanager-iodine = super.networkmanager-iodine.override { withGnome = false; }; - networkmanager-l2tp = super.networkmanager-l2tp.override { withGnome = false; }; - networkmanager-openconnect = super.networkmanager-openconnect.override { withGnome = false; }; - networkmanager-openvpn = super.networkmanager-openvpn.override { withGnome = false; }; - networkmanager-sstp = super.networkmanager-vpnc.override { withGnome = false; }; - networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; }; - pango = super.pango.override { x11Support = false; }; - pinentry-curses = super.pinentry-curses.override { withLibsecret = false; }; - pinentry-tty = super.pinentry-tty.override { withLibsecret = false; }; - pipewire = super.pipewire.override { vulkanSupport = false; x11Support = false; }; - pythonPackagesExtensions = super.pythonPackagesExtensions ++ [ - (python-final: python-prev: { - # tk feature requires wayland which fails to compile - matplotlib = python-prev.matplotlib.override { enableTk = false; }; - }) - ]; - qemu = super.qemu.override { gtkSupport = false; spiceSupport = false; sdlSupport = false; }; - qrencode = super.qrencode.overrideAttrs (_: { doCheck = false; }); - qt5 = super.qt5.overrideScope (const (super': { - qtbase = super'.qtbase.override { withGtk3 = false; withQttranslation = false; }; - })); - stoken = super.stoken.override { withGTK3 = false; }; - # translateManpages -> perlPackages.po4a -> texlive-combined-basic -> texlive-core-big -> libX11 - util-linux = super.util-linux.override { translateManpages = false; }; - vim-full = super.vim-full.override { guiSupport = false; }; - vte = super.vte.override { gtkVersion = null; }; - zbar = super.zbar.override { enableVideo = false; withXorg = false; }; - })); - }; -} diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix index fe0402ee9e66..71c79eafeb09 100644 --- a/nixos/modules/config/nsswitch.nix +++ b/nixos/modules/config/nsswitch.nix @@ -1,16 +1,12 @@ # Configuration for the Name Service Switch (/etc/nsswitch.conf). - { config, lib, pkgs, ... }: - -with lib; - { options = { # NSS modules. Hacky! # Only works with nscd! - system.nssModules = mkOption { - type = types.listOf types.path; + system.nssModules = lib.mkOption { + type = lib.types.listOf lib.types.path; internal = true; default = [ ]; description = '' @@ -21,13 +17,13 @@ with lib; apply = list: { inherit list; - path = makeLibraryPath list; + path = lib.makeLibraryPath list; }; }; system.nssDatabases = { - passwd = mkOption { - type = types.listOf types.str; + passwd = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of passwd entries to configure in {file}`/etc/nsswitch.conf`. @@ -38,8 +34,8 @@ with lib; default = [ ]; }; - group = mkOption { - type = types.listOf types.str; + group = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of group entries to configure in {file}`/etc/nsswitch.conf`. @@ -50,8 +46,8 @@ with lib; default = [ ]; }; - shadow = mkOption { - type = types.listOf types.str; + shadow = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of shadow entries to configure in {file}`/etc/nsswitch.conf`. @@ -62,8 +58,8 @@ with lib; default = [ ]; }; - sudoers = mkOption { - type = types.listOf types.str; + sudoers = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of sudoers entries to configure in {file}`/etc/nsswitch.conf`. @@ -74,8 +70,8 @@ with lib; default = [ ]; }; - hosts = mkOption { - type = types.listOf types.str; + hosts = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of hosts entries to configure in {file}`/etc/nsswitch.conf`. @@ -86,8 +82,8 @@ with lib; default = [ ]; }; - services = mkOption { - type = types.listOf types.str; + services = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of services entries to configure in {file}`/etc/nsswitch.conf`. @@ -101,7 +97,7 @@ with lib; }; imports = [ - (mkRenamedOptionModule [ "system" "nssHosts" ] [ "system" "nssDatabases" "hosts" ]) + (lib.mkRenamedOptionModule [ "system" "nssHosts" ] [ "system" "nssDatabases" "hosts" ]) ]; config = { @@ -121,30 +117,30 @@ with lib; # Name Service Switch configuration file. Required by the C # library. environment.etc."nsswitch.conf".text = '' - passwd: ${concatStringsSep " " config.system.nssDatabases.passwd} - group: ${concatStringsSep " " config.system.nssDatabases.group} - shadow: ${concatStringsSep " " config.system.nssDatabases.shadow} - sudoers: ${concatStringsSep " " config.system.nssDatabases.sudoers} + passwd: ${lib.concatStringsSep " " config.system.nssDatabases.passwd} + group: ${lib.concatStringsSep " " config.system.nssDatabases.group} + shadow: ${lib.concatStringsSep " " config.system.nssDatabases.shadow} + sudoers: ${lib.concatStringsSep " " config.system.nssDatabases.sudoers} - hosts: ${concatStringsSep " " config.system.nssDatabases.hosts} + hosts: ${lib.concatStringsSep " " config.system.nssDatabases.hosts} networks: files ethers: files - services: ${concatStringsSep " " config.system.nssDatabases.services} + services: ${lib.concatStringsSep " " config.system.nssDatabases.services} protocols: files rpc: files ''; system.nssDatabases = { - passwd = mkBefore [ "files" ]; - group = mkBefore [ "files" ]; - shadow = mkBefore [ "files" ]; - sudoers = mkBefore [ "files" ]; - hosts = mkMerge [ - (mkOrder 998 [ "files" ]) - (mkOrder 1499 [ "dns" ]) + passwd = lib.mkBefore [ "files" ]; + group = lib.mkBefore [ "files" ]; + shadow = lib.mkBefore [ "files" ]; + sudoers = lib.mkBefore [ "files" ]; + hosts = lib.mkMerge [ + (lib.mkOrder 998 [ "files" ]) + (lib.mkOrder 1499 [ "dns" ]) ]; - services = mkBefore [ "files" ]; + services = lib.mkBefore [ "files" ]; }; }; } diff --git a/nixos/modules/config/power-management.nix b/nixos/modules/config/power-management.nix index 70f2d199df10..524a23edab64 100644 --- a/nixos/modules/config/power-management.nix +++ b/nixos/modules/config/power-management.nix @@ -1,7 +1,4 @@ { config, lib, ... }: - -with lib; - let cfg = config.powerManagement; @@ -16,8 +13,8 @@ in powerManagement = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable power management. This includes support @@ -25,16 +22,16 @@ in ''; }; - resumeCommands = mkOption { - type = types.lines; + resumeCommands = lib.mkOption { + type = lib.types.lines; default = ""; description = "Commands executed after the system resumes from suspend-to-RAM."; }; - powerUpCommands = mkOption { - type = types.lines; + powerUpCommands = lib.mkOption { + type = lib.types.lines; default = ""; - example = literalExpression '' + example = lib.literalExpression '' "''${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda" ''; description = '' @@ -44,10 +41,10 @@ in ''; }; - powerDownCommands = mkOption { - type = types.lines; + powerDownCommands = lib.mkOption { + type = lib.types.lines; default = ""; - example = literalExpression '' + example = lib.literalExpression '' "''${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda" ''; description = '' @@ -64,7 +61,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.targets.post-resume = { description = "Post-Resume Actions"; diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 27c164a9a6dc..6e6e577e6e20 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -1,8 +1,4 @@ { config, lib, pkgs, ... }: - -with pkgs; -with lib; - let cfg = config.hardware.pulseaudio; @@ -10,28 +6,28 @@ let hasZeroconf = let z = cfg.zeroconf; in z.publish.enable || z.discovery.enable; overriddenPackage = cfg.package.override - (optionalAttrs hasZeroconf { zeroconfSupport = true; }); - binary = "${getBin overriddenPackage}/bin/pulseaudio"; + (lib.optionalAttrs hasZeroconf { zeroconfSupport = true; }); + binary = "${lib.getBin overriddenPackage}/bin/pulseaudio"; binaryNoDaemon = "${binary} --daemonize=no"; # Forces 32bit pulseaudio and alsa-plugins to be built/supported for apps # using 32bit alsa on 64bit linux. - enable32BitAlsaPlugins = cfg.support32Bit && stdenv.isx86_64 && (pkgs.pkgsi686Linux.alsa-lib != null && pkgs.pkgsi686Linux.libpulseaudio != null); + enable32BitAlsaPlugins = cfg.support32Bit && pkgs.stdenv.hostPlatform.isx86_64 && (pkgs.pkgsi686Linux.alsa-lib != null && pkgs.pkgsi686Linux.libpulseaudio != null); myConfigFile = let - addModuleIf = cond: mod: optionalString cond "load-module ${mod}"; - allAnon = optional cfg.tcp.anonymousClients.allowAll "auth-anonymous=1"; + addModuleIf = cond: mod: lib.optionalString cond "load-module ${mod}"; + allAnon = lib.optional cfg.tcp.anonymousClients.allowAll "auth-anonymous=1"; ipAnon = let a = cfg.tcp.anonymousClients.allowedIpRanges; - in optional (a != []) ''auth-ip-acl=${concatStringsSep ";" a}''; - in writeTextFile { + in lib.optional (a != []) ''auth-ip-acl=${lib.concatStringsSep ";" a}''; + in pkgs.writeTextFile { name = "default.pa"; text = '' .include ${cfg.configFile} ${addModuleIf cfg.zeroconf.publish.enable "module-zeroconf-publish"} ${addModuleIf cfg.zeroconf.discovery.enable "module-zeroconf-discover"} - ${addModuleIf cfg.tcp.enable (concatStringsSep " " + ${addModuleIf cfg.tcp.enable (lib.concatStringsSep " " ([ "module-native-protocol-tcp" ] ++ allAnon ++ ipAnon))} ${addModuleIf config.services.jack.jackd.enable "module-jack-sink"} ${addModuleIf config.services.jack.jackd.enable "module-jack-source"} @@ -49,7 +45,7 @@ let # Create pulse/client.conf even if PulseAudio is disabled so # that we can disable the autospawn feature in programs that # are built with PulseAudio support (like KDE). - clientConf = writeText "client.conf" '' + clientConf = pkgs.writeText "client.conf" '' autospawn=no ${cfg.extraClientConf} ''; @@ -82,16 +78,16 @@ in { options = { hardware.pulseaudio = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the PulseAudio sound server. ''; }; - systemWide = mkOption { - type = types.bool; + systemWide = lib.mkOption { + type = lib.types.bool; default = false; description = '' If false, a PulseAudio server is launched automatically for @@ -105,8 +101,8 @@ in { ''; }; - support32Bit = mkOption { - type = types.bool; + support32Bit = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to include the 32-bit pulseaudio libraries in the system or not. @@ -114,8 +110,8 @@ in { ''; }; - configFile = mkOption { - type = types.nullOr types.path; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' The path to the default configuration options the PulseAudio server should use. By default, the "default.pa" configuration @@ -123,8 +119,8 @@ in { ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Literal string to append to `configFile` @@ -132,21 +128,21 @@ in { ''; }; - extraClientConf = mkOption { - type = types.lines; + extraClientConf = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra configuration appended to pulse/client.conf file. ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = if config.services.jack.jackd.enable then pkgs.pulseaudioFull else pkgs.pulseaudio; - defaultText = literalExpression "pkgs.pulseaudio"; - example = literalExpression "pkgs.pulseaudioFull"; + defaultText = lib.literalExpression "pkgs.pulseaudio"; + example = lib.literalExpression "pkgs.pulseaudioFull"; description = '' The PulseAudio derivation to use. This can be used to enable features (such as JACK support, Bluetooth) via the @@ -154,10 +150,10 @@ in { ''; }; - extraModules = mkOption { - type = types.listOf types.package; + extraModules = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "[ pkgs.pulseaudio-modules-bt ]"; + example = lib.literalExpression "[ pkgs.pulseaudio-modules-bt ]"; description = '' Extra pulseaudio modules to use. This is intended for out-of-tree pulseaudio modules like extra bluetooth codecs. @@ -167,8 +163,8 @@ in { }; daemon = { - logLevel = mkOption { - type = types.str; + logLevel = lib.mkOption { + type = lib.types.str; default = "notice"; description = '' The log level that the system-wide pulseaudio daemon should use, @@ -176,31 +172,31 @@ in { ''; }; - config = mkOption { - type = types.attrsOf types.unspecified; + config = lib.mkOption { + type = lib.types.attrsOf lib.types.unspecified; default = {}; description = "Config of the pulse daemon. See `man pulse-daemon.conf`."; - example = literalExpression ''{ realtime-scheduling = "yes"; }''; + example = lib.literalExpression ''{ realtime-scheduling = "yes"; }''; }; }; zeroconf = { discovery.enable = - mkEnableOption "discovery of pulseaudio sinks in the local network"; + lib.mkEnableOption "discovery of pulseaudio sinks in the local network"; publish.enable = - mkEnableOption "publishing the pulseaudio sink in the local network"; + lib.mkEnableOption "publishing the pulseaudio sink in the local network"; }; # TODO: enable by default? tcp = { - enable = mkEnableOption "tcp streaming support"; + enable = lib.mkEnableOption "tcp streaming support"; anonymousClients = { - allowAll = mkEnableOption "all anonymous clients to stream to the server"; - allowedIpRanges = mkOption { - type = types.listOf types.str; + allowAll = lib.mkEnableOption "all anonymous clients to stream to the server"; + allowedIpRanges = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; - example = literalExpression ''[ "127.0.0.1" "192.168.1.0/24" ]''; + example = lib.literalExpression ''[ "127.0.0.1" "192.168.1.0/24" ]''; description = '' A list of IP subnets that are allowed to stream to the server. ''; @@ -213,7 +209,7 @@ in { }; - config = lib.mkIf cfg.enable (mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { environment.etc."pulse/client.conf".source = clientConf; @@ -222,21 +218,21 @@ in { environment.etc = { "alsa/conf.d/99-pulseaudio.conf".text = alsaConf; - "pulse/daemon.conf".source = writeText "daemon.conf" + "pulse/daemon.conf".source = pkgs.writeText "daemon.conf" (lib.generators.toKeyValue {} cfg.daemon.config); - "openal/alsoft.conf".source = writeText "alsoft.conf" "drivers=pulse"; + "openal/alsoft.conf".source = pkgs.writeText "alsoft.conf" "drivers=pulse"; - "libao.conf".source = writeText "libao.conf" "default_driver=pulse"; + "libao.conf".source = pkgs.writeText "libao.conf" "default_driver=pulse"; }; - hardware.pulseaudio.configFile = mkDefault "${getBin overriddenPackage}/etc/pulse/default.pa"; + hardware.pulseaudio.configFile = lib.mkDefault "${lib.getBin overriddenPackage}/etc/pulse/default.pa"; # Disable flat volumes to enable relative ones - hardware.pulseaudio.daemon.config.flat-volumes = mkDefault "no"; + hardware.pulseaudio.daemon.config.flat-volumes = lib.mkDefault "no"; # Upstream defaults to speex-float-1 which results in audible artifacts - hardware.pulseaudio.daemon.config.resample-method = mkDefault "speex-float-5"; + hardware.pulseaudio.daemon.config.resample-method = lib.mkDefault "speex-float-5"; # Allow PulseAudio to get realtime priority using rtkit. security.rtkit.enable = true; @@ -247,7 +243,7 @@ in { services.udev.packages = [ overriddenPackage ]; } - (mkIf (cfg.extraModules != []) { + (lib.mkIf (cfg.extraModules != []) { hardware.pulseaudio.daemon.config.dl-search-path = let overriddenModules = builtins.map (drv: drv.override { pulseaudio = overriddenPackage; }) @@ -259,15 +255,15 @@ in { in lib.concatStringsSep ":" modulePaths; }) - (mkIf hasZeroconf { + (lib.mkIf hasZeroconf { services.avahi.enable = true; }) - (mkIf cfg.zeroconf.publish.enable { + (lib.mkIf cfg.zeroconf.publish.enable { services.avahi.publish.enable = true; services.avahi.publish.userServices = true; }) - (mkIf (!cfg.systemWide) { + (lib.mkIf (!cfg.systemWide) { environment.etc = { "pulse/default.pa".source = myConfigFile; }; @@ -278,7 +274,7 @@ in { RestartSec = "500ms"; PassEnvironment = "DISPLAY"; }; - } // optionalAttrs config.services.jack.jackd.enable { + } // lib.optionalAttrs config.services.jack.jackd.enable { environment.JACK_PROMISCUOUS_SERVER = "jackaudio"; }; sockets.pulseaudio = { @@ -287,7 +283,7 @@ in { }; }) - (mkIf cfg.systemWide { + (lib.mkIf cfg.systemWide { users.users.pulse = { # For some reason, PulseAudio wants UID == GID. uid = assert uid == gid; uid; diff --git a/nixos/modules/config/resolvconf.nix b/nixos/modules/config/resolvconf.nix index 002a06be39a3..f6241e9bf96b 100644 --- a/nixos/modules/config/resolvconf.nix +++ b/nixos/modules/config/resolvconf.nix @@ -1,17 +1,13 @@ # /etc files related to networking, such as /etc/services. - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.networking.resolvconf; resolvconfOptions = cfg.extraOptions - ++ optional cfg.dnsSingleRequest "single-request" - ++ optional cfg.dnsExtensionMechanism "edns0" - ++ optional cfg.useLocalResolver "trust-ad"; + ++ lib.optional cfg.dnsSingleRequest "single-request" + ++ lib.optional cfg.dnsExtensionMechanism "edns0" + ++ lib.optional cfg.useLocalResolver "trust-ad"; configText = '' @@ -19,46 +15,46 @@ let # a collision with an apparently unrelated environment # variable with the same name exported by dhcpcd. interface_order='lo lo[0-9]*' - '' + optionalString config.services.nscd.enable '' + '' + lib.optionalString config.services.nscd.enable '' # Invalidate the nscd cache whenever resolv.conf is # regenerated. libc_restart='/run/current-system/systemd/bin/systemctl try-restart --no-block nscd.service 2> /dev/null' - '' + optionalString (length resolvconfOptions > 0) '' + '' + lib.optionalString (lib.length resolvconfOptions > 0) '' # Options as described in resolv.conf(5) - resolv_conf_options='${concatStringsSep " " resolvconfOptions}' - '' + optionalString cfg.useLocalResolver '' + resolv_conf_options='${lib.concatStringsSep " " resolvconfOptions}' + '' + lib.optionalString cfg.useLocalResolver '' # This hosts runs a full-blown DNS resolver. - name_servers='127.0.0.1${optionalString config.networking.enableIPv6 " ::1"}' + name_servers='127.0.0.1${lib.optionalString config.networking.enableIPv6 " ::1"}' '' + cfg.extraConfig; in { imports = [ - (mkRenamedOptionModule [ "networking" "dnsSingleRequest" ] [ "networking" "resolvconf" "dnsSingleRequest" ]) - (mkRenamedOptionModule [ "networking" "dnsExtensionMechanism" ] [ "networking" "resolvconf" "dnsExtensionMechanism" ]) - (mkRenamedOptionModule [ "networking" "extraResolvconfConf" ] [ "networking" "resolvconf" "extraConfig" ]) - (mkRenamedOptionModule [ "networking" "resolvconfOptions" ] [ "networking" "resolvconf" "extraOptions" ]) - (mkRemovedOptionModule [ "networking" "resolvconf" "useHostResolvConf" ] "This option was never used for anything anyways") + (lib.mkRenamedOptionModule [ "networking" "dnsSingleRequest" ] [ "networking" "resolvconf" "dnsSingleRequest" ]) + (lib.mkRenamedOptionModule [ "networking" "dnsExtensionMechanism" ] [ "networking" "resolvconf" "dnsExtensionMechanism" ]) + (lib.mkRenamedOptionModule [ "networking" "extraResolvconfConf" ] [ "networking" "resolvconf" "extraConfig" ]) + (lib.mkRenamedOptionModule [ "networking" "resolvconfOptions" ] [ "networking" "resolvconf" "extraOptions" ]) + (lib.mkRemovedOptionModule [ "networking" "resolvconf" "useHostResolvConf" ] "This option was never used for anything anyways") ]; options = { networking.resolvconf = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = !(config.environment.etc ? "resolv.conf"); - defaultText = literalExpression ''!(config.environment.etc ? "resolv.conf")''; + defaultText = lib.literalExpression ''!(config.environment.etc ? "resolv.conf")''; description = '' Whether DNS configuration is managed by resolvconf. ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = pkgs.openresolv; - defaultText = literalExpression "pkgs.openresolv"; + defaultText = lib.literalExpression "pkgs.openresolv"; description = '' The package that provides the system-wide resolvconf command. Defaults to `openresolv` if this module is enabled. Otherwise, can be used by other modules (for example {option}`services.resolved`) to @@ -69,7 +65,7 @@ in }; dnsSingleRequest = lib.mkOption { - type = types.bool; + type = lib.types.bool; default = false; description = '' Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA) @@ -81,8 +77,8 @@ in ''; }; - dnsExtensionMechanism = mkOption { - type = types.bool; + dnsExtensionMechanism = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable the `edns0` option in {file}`resolv.conf`. With @@ -92,8 +88,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = "libc=NO"; description = '' @@ -101,8 +97,8 @@ in ''; }; - extraOptions = mkOption { - type = types.listOf types.str; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "ndots:1" "rotate" ]; description = '' @@ -110,19 +106,28 @@ in ''; }; - useLocalResolver = mkOption { - type = types.bool; + useLocalResolver = lib.mkOption { + type = lib.types.bool; default = false; description = '' Use local DNS server for resolving. ''; }; + subscriberFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = []; + description = '' + Files written by resolvconf updates + ''; + internal = true; + }; + }; }; - config = mkMerge [ + config = lib.mkMerge [ { environment.etc."resolvconf.conf".text = if !cfg.enable then @@ -135,7 +140,11 @@ in else configText; } - (mkIf cfg.enable { + (lib.mkIf cfg.enable { + users.groups.resolvconf = {}; + + networking.resolvconf.subscriberFiles = [ "/etc/resolv.conf" ]; + networking.resolvconf.package = pkgs.openresolv; environment.systemPackages = [ cfg.package ]; @@ -147,12 +156,15 @@ in wants = [ "network-pre.target" ]; wantedBy = [ "multi-user.target" ]; restartTriggers = [ config.environment.etc."resolvconf.conf".source ]; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${cfg.package}/bin/resolvconf -u"; - RemainAfterExit = true; - }; + script = '' + ${lib.getExe cfg.package} -u + files=(/run/resolvconf ${lib.escapeShellArgs cfg.subscriberFiles}) + chgrp -R resolvconf "''${files[@]}" + chmod -R g=u "''${files[@]}" + ''; }; }) diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix index 50796f8bc6f1..9289eced109f 100644 --- a/nixos/modules/config/shells-environment.nix +++ b/nixos/modules/config/shells-environment.nix @@ -1,10 +1,6 @@ # This module defines a global environment configuration and # a common configuration for all shells. - { config, lib, utils, pkgs, ... }: - -with lib; - let cfg = config.environment; @@ -12,27 +8,27 @@ let exportedEnvVars = let absoluteVariables = - mapAttrs (n: toList) cfg.variables; + lib.mapAttrs (n: lib.toList) cfg.variables; suffixedVariables = - flip mapAttrs cfg.profileRelativeEnvVars (envVar: listSuffixes: - concatMap (profile: map (suffix: "${profile}${suffix}") listSuffixes) cfg.profiles + lib.flip lib.mapAttrs cfg.profileRelativeEnvVars (envVar: listSuffixes: + lib.concatMap (profile: map (suffix: "${profile}${suffix}") listSuffixes) cfg.profiles ); allVariables = - zipAttrsWith (n: concatLists) [ absoluteVariables suffixedVariables ]; + lib.zipAttrsWith (n: lib.concatLists) [ absoluteVariables suffixedVariables ]; exportVariables = - mapAttrsToList (n: v: ''export ${n}="${concatStringsSep ":" v}"'') allVariables; + lib.mapAttrsToList (n: v: ''export ${n}="${lib.concatStringsSep ":" v}"'') allVariables; in - concatStringsSep "\n" exportVariables; + lib.concatStringsSep "\n" exportVariables; in { options = { - environment.variables = mkOption { + environment.variables = lib.mkOption { default = {}; example = { EDITOR = "nvim"; VISUAL = "nvim"; }; description = '' @@ -42,22 +38,22 @@ in strings. The latter is concatenated, interspersed with colon characters. ''; - type = with types; attrsOf (oneOf [ (listOf (oneOf [ int str path ])) int str path ]); + type = with lib.types; attrsOf (oneOf [ (listOf (oneOf [ int str path ])) int str path ]); apply = let - toStr = v: if isPath v then "${v}" else toString v; - in mapAttrs (n: v: if isList v then concatMapStringsSep ":" toStr v else toStr v); + toStr = v: if lib.isPath v then "${v}" else toString v; + in lib.mapAttrs (n: v: if lib.isList v then lib.concatMapStringsSep ":" toStr v else toStr v); }; - environment.profiles = mkOption { + environment.profiles = lib.mkOption { default = []; description = '' A list of profiles used to setup the global environment. ''; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; }; - environment.profileRelativeEnvVars = mkOption { - type = types.attrsOf (types.listOf types.str); + environment.profileRelativeEnvVars = lib.mkOption { + type = lib.types.attrsOf (lib.types.listOf lib.types.str); example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; }; description = '' Attribute set of environment variable. Each attribute maps to a list @@ -68,7 +64,7 @@ in }; # !!! isn't there a better way? - environment.extraInit = mkOption { + environment.extraInit = lib.mkOption { default = ""; description = '' Shell script code called during global environment initialisation @@ -76,40 +72,40 @@ in This code is assumed to be shell-independent, which means you should stick to pure sh without sh word split. ''; - type = types.lines; + type = lib.types.lines; }; - environment.shellInit = mkOption { + environment.shellInit = lib.mkOption { default = ""; description = '' Shell script code called during shell initialisation. This code is assumed to be shell-independent, which means you should stick to pure sh without sh word split. ''; - type = types.lines; + type = lib.types.lines; }; - environment.loginShellInit = mkOption { + environment.loginShellInit = lib.mkOption { default = ""; description = '' Shell script code called during login shell initialisation. This code is assumed to be shell-independent, which means you should stick to pure sh without sh word split. ''; - type = types.lines; + type = lib.types.lines; }; - environment.interactiveShellInit = mkOption { + environment.interactiveShellInit = lib.mkOption { default = ""; description = '' Shell script code called during interactive shell initialisation. This code is assumed to be shell-independent, which means you should stick to pure sh without sh word split. ''; - type = types.lines; + type = lib.types.lines; }; - environment.shellAliases = mkOption { + environment.shellAliases = lib.mkOption { example = { l = null; ll = "ls -l"; }; description = '' An attribute set that maps aliases (the top level attribute names in @@ -117,30 +113,30 @@ in aliases are added to all users' shells. Aliases mapped to `null` are ignored. ''; - type = with types; attrsOf (nullOr (either str path)); + type = with lib.types; attrsOf (nullOr (either str path)); }; - environment.homeBinInPath = mkOption { + environment.homeBinInPath = lib.mkOption { description = '' Include ~/bin/ in $PATH. ''; default = false; - type = types.bool; + type = lib.types.bool; }; - environment.localBinInPath = mkOption { + environment.localBinInPath = lib.mkOption { description = '' Add ~/.local/bin/ to $PATH ''; default = false; - type = types.bool; + type = lib.types.bool; }; - environment.binsh = mkOption { + environment.binsh = lib.mkOption { default = "${config.system.build.binsh}/bin/sh"; - defaultText = literalExpression ''"''${config.system.build.binsh}/bin/sh"''; - example = literalExpression ''"''${pkgs.dash}/bin/dash"''; - type = types.path; + defaultText = lib.literalExpression ''"''${config.system.build.binsh}/bin/sh"''; + example = lib.literalExpression ''"''${pkgs.dash}/bin/dash"''; + type = lib.types.path; visible = false; description = '' The shell executable that is linked system-wide to @@ -150,15 +146,15 @@ in ''; }; - environment.shells = mkOption { + environment.shells = lib.mkOption { default = []; - example = literalExpression "[ pkgs.bashInteractive pkgs.zsh ]"; + example = lib.literalExpression "[ pkgs.bashInteractive pkgs.zsh ]"; description = '' A list of permissible login shells for user accounts. No need to mention `/bin/sh` here, it is placed into this list implicitly. ''; - type = types.listOf (types.either types.shellPackage types.path); + type = lib.types.listOf (lib.types.either lib.types.shellPackage lib.types.path); }; }; @@ -175,7 +171,7 @@ in environment.profileRelativeEnvVars = config.environment.profileRelativeSessionVariables; - environment.shellAliases = mapAttrs (name: mkDefault) { + environment.shellAliases = lib.mapAttrs (name: lib.mkDefault) { ls = "ls --color=tty"; ll = "ls -l"; l = "ls -alh"; @@ -183,7 +179,7 @@ in environment.etc.shells.text = '' - ${concatStringsSep "\n" (map utils.toShellPath cfg.shells)} + ${lib.concatStringsSep "\n" (map utils.toShellPath cfg.shells)} /bin/sh ''; @@ -202,17 +198,17 @@ in ${cfg.extraInit} - ${optionalString cfg.homeBinInPath '' + ${lib.optionalString cfg.homeBinInPath '' # ~/bin if it exists overrides other bin directories. export PATH="$HOME/bin:$PATH" ''} - ${optionalString cfg.localBinInPath '' + ${lib.optionalString cfg.localBinInPath '' export PATH="$HOME/.local/bin:$PATH" ''} ''; - system.activationScripts.binsh = stringAfter [ "stdio" ] + system.activationScripts.binsh = lib.stringAfter [ "stdio" ] '' # Create the required /bin/sh symlink; otherwise lots of things # (notably the system() function) won't work. diff --git a/nixos/modules/config/stub-ld.nix b/nixos/modules/config/stub-ld.nix index 87b7bdf07a2d..05945852ee45 100644 --- a/nixos/modules/config/stub-ld.nix +++ b/nixos/modules/config/stub-ld.nix @@ -49,7 +49,7 @@ in { config = mkIf cfg.enable { environment.ldso = mkDefault stub-ld; - environment.ldso32 = mkIf pkgs.stdenv.isx86_64 (mkDefault stub-ld32); + environment.ldso32 = mkIf pkgs.stdenv.hostPlatform.isx86_64 (mkDefault stub-ld32); }; meta.maintainers = with lib.maintainers; [ tejing ]; diff --git a/nixos/modules/config/sysctl.nix b/nixos/modules/config/sysctl.nix index 34028ce82dd7..1495215db902 100644 --- a/nixos/modules/config/sysctl.nix +++ b/nixos/modules/config/sysctl.nix @@ -1,17 +1,14 @@ { config, lib, ... }: - -with lib; - let - sysctlOption = mkOptionType { + sysctlOption = lib.mkOptionType { name = "sysctl option value"; check = val: let - checkType = x: isBool x || isString x || isInt x || x == null; + checkType = x: lib.isBool x || lib.isString x || lib.isInt x || x == null; in checkType val || (val._type or "" == "override" && checkType val.content); - merge = loc: defs: mergeOneOption loc (filterOverrides defs); + merge = loc: defs: lib.mergeOneOption loc (lib.filterOverrides defs); }; in @@ -20,33 +17,33 @@ in options = { - boot.kernel.sysctl = mkOption { + boot.kernel.sysctl = lib.mkOption { type = let - highestValueType = types.ints.unsigned // { + highestValueType = lib.types.ints.unsigned // { merge = loc: defs: - foldl + lib.foldl (a: b: if b.value == null then null else lib.max a b.value) 0 - (filterOverrides defs); + (lib.filterOverrides defs); }; - in types.submodule { - freeformType = types.attrsOf sysctlOption; + in lib.types.submodule { + freeformType = lib.types.attrsOf sysctlOption; options = { - "net.core.rmem_max" = mkOption { - type = types.nullOr highestValueType; + "net.core.rmem_max" = lib.mkOption { + type = lib.types.nullOr highestValueType; default = null; description = "The maximum receive socket buffer size in bytes. In case of conflicting values, the highest will be used."; }; - "net.core.wmem_max" = mkOption { - type = types.nullOr highestValueType; + "net.core.wmem_max" = lib.mkOption { + type = lib.types.nullOr highestValueType; default = null; description = "The maximum send socket buffer size in bytes. In case of conflicting values, the highest will be used."; }; }; }; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { "net.ipv4.tcp_syncookies" = false; "vm.swappiness" = 60; } ''; description = '' @@ -66,8 +63,8 @@ in config = { environment.etc."sysctl.d/60-nixos.conf".text = - concatStrings (mapAttrsToList (n: v: - optionalString (v != null) "${n}=${if v == false then "0" else toString v}\n" + lib.concatStrings (lib.mapAttrsToList (n: v: + lib.optionalString (v != null) "${n}=${if v == false then "0" else toString v}\n" ) config.boot.kernel.sysctl); systemd.services.systemd-sysctl = @@ -77,10 +74,10 @@ in # Hide kernel pointers (e.g. in /proc/modules) for unprivileged # users as these make it easier to exploit kernel vulnerabilities. - boot.kernel.sysctl."kernel.kptr_restrict" = mkDefault 1; + boot.kernel.sysctl."kernel.kptr_restrict" = lib.mkDefault 1; # Improve compatibility with applications that allocate # a lot of memory, like modern games - boot.kernel.sysctl."vm.max_map_count" = mkDefault 1048576; + boot.kernel.sysctl."vm.max_map_count" = lib.mkDefault 1048576; }; } diff --git a/nixos/modules/config/system-environment.nix b/nixos/modules/config/system-environment.nix index 3fd4ac730ab9..ef49701fb492 100644 --- a/nixos/modules/config/system-environment.nix +++ b/nixos/modules/config/system-environment.nix @@ -1,9 +1,6 @@ # This module defines a system-wide environment that will be # initialised by pam_env (that is, not only in shells). { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.environment; @@ -14,7 +11,7 @@ in options = { - environment.sessionVariables = mkOption { + environment.sessionVariables = lib.mkOption { default = {}; description = '' A set of environment variables used in the global environment. @@ -35,8 +32,8 @@ in inherit (options.environment.variables) type apply; }; - environment.profileRelativeSessionVariables = mkOption { - type = types.attrsOf (types.listOf types.str); + environment.profileRelativeSessionVariables = lib.mkOption { + type = lib.types.attrsOf (lib.types.listOf lib.types.str); example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; }; description = '' Attribute set of environment variable used in the global @@ -63,8 +60,8 @@ in config = { environment.etc."pam/environment".text = let suffixedVariables = - flip mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes: - flip concatMap cfg.profiles (profile: + lib.flip lib.mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes: + lib.flip lib.concatMap cfg.profiles (profile: map (suffix: "${profile}${suffix}") suffixes ) ); @@ -72,15 +69,15 @@ in # We're trying to use the same syntax for PAM variables and env variables. # That means we need to map the env variables that people might use to their # equivalent PAM variable. - replaceEnvVars = replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"]; + replaceEnvVars = lib.replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"]; pamVariable = n: v: - ''${n} DEFAULT="${concatStringsSep ":" (map replaceEnvVars (toList v))}"''; + ''${n} DEFAULT="${lib.concatStringsSep ":" (map replaceEnvVars (lib.toList v))}"''; pamVariables = - concatStringsSep "\n" - (mapAttrsToList pamVariable - (zipAttrsWith (n: concatLists) + lib.concatStringsSep "\n" + (lib.mapAttrsToList pamVariable + (lib.zipAttrsWith (n: lib.concatLists) [ # Make sure security wrappers are prioritized without polluting # shell environments with an extra entry. Sessions which depend on @@ -89,7 +86,7 @@ in # environment from a shell. { PATH = [ config.security.wrapperDir ]; } - (mapAttrs (n: toList) cfg.sessionVariables) + (lib.mapAttrs (n: lib.toList) cfg.sessionVariables) suffixedVariables ])); in '' diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index 21280d023a4c..6757078dbd9f 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -1,13 +1,9 @@ # This module defines the packages that appear in # /run/current-system/sw. - { config, lib, pkgs, ... }: - -with lib; - let - requiredPackages = map (pkg: setPrio ((pkg.meta.priority or 5) + 3) pkg) + requiredPackages = map (pkg: lib.setPrio ((pkg.meta.priority or lib.meta.defaultPriority) + 3) pkg) [ pkgs.acl pkgs.attr pkgs.bashInteractive # bash with ncurses support @@ -48,9 +44,9 @@ let ]; defaultPackages = map - (n: let pkg = pkgs.${n}; in setPrio ((pkg.meta.priority or 5) + 3) pkg) + (n: let pkg = pkgs.${n};in lib.setPrio ((pkg.meta.priority or lib.meta.defaultPriority) + 3) pkg) defaultPackageNames; - defaultPackagesText = "[ ${concatMapStringsSep " " (n: "pkgs.${n}") defaultPackageNames } ]"; + defaultPackagesText = "[ ${lib.concatMapStringsSep " " (n: "pkgs.${n}") defaultPackageNames } ]"; in @@ -59,10 +55,10 @@ in environment = { - systemPackages = mkOption { - type = types.listOf types.package; + systemPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "[ pkgs.firefox pkgs.thunderbird ]"; + example = lib.literalExpression "[ pkgs.firefox pkgs.thunderbird ]"; description = '' The set of packages that appear in /run/current-system/sw. These packages are @@ -74,10 +70,10 @@ in ''; }; - defaultPackages = mkOption { - type = types.listOf types.package; + defaultPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = defaultPackages; - defaultText = literalMD '' + defaultText = lib.literalMD '' these packages, with their `meta.priority` numerically increased (thus lowering their installation priority): @@ -97,8 +93,8 @@ in ''; }; - pathsToLink = mkOption { - type = types.listOf types.str; + pathsToLink = lib.mkOption { + type = lib.types.listOf lib.types.str; # Note: We need `/lib' to be among `pathsToLink' for NSS modules # to work. default = []; @@ -106,8 +102,8 @@ in description = "List of directories to be symlinked in {file}`/run/current-system/sw`."; }; - extraOutputsToInstall = mkOption { - type = types.listOf types.str; + extraOutputsToInstall = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "dev" "info" ]; description = '' @@ -119,8 +115,8 @@ in ''; }; - extraSetup = mkOption { - type = types.lines; + extraSetup = lib.mkOption { + type = lib.types.lines; default = ""; description = "Shell fragments to be run after the system environment has been created. This should only be used for things that need to modify the internals of the environment, e.g. generating MIME caches. The environment being built can be accessed at $out."; }; @@ -129,7 +125,7 @@ in system = { - path = mkOption { + path = lib.mkOption { internal = true; description = '' The packages you want in the boot environment. diff --git a/nixos/modules/config/terminfo.nix b/nixos/modules/config/terminfo.nix index b538d749ffcb..78d4847092d5 100644 --- a/nixos/modules/config/terminfo.nix +++ b/nixos/modules/config/terminfo.nix @@ -1,23 +1,20 @@ # This module manages the terminfo database # and its integration in the system. { config, lib, pkgs, ... }: - -with lib; - { options = with lib; { - environment.enableAllTerminfo = mkOption { + environment.enableAllTerminfo = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to install all terminfo outputs ''; }; - security.sudo.keepTerminfo = mkOption { + security.sudo.keepTerminfo = lib.mkOption { default = true; - type = types.bool; + type = lib.types.bool; description = '' Whether to preserve the `TERMINFO` and `TERMINFO_DIRS` environment variables, for `root` and the `wheel` group. @@ -27,25 +24,35 @@ with lib; config = { + # This should not contain packages that are broken or can't build, since it + # will break this expression + # + # Currently broken packages: + # - contour + # # can be generated with: - # attrNames (filterAttrs - # (_: drv: (builtins.tryEval (isDerivation drv && drv ? terminfo)).value) + # lib.attrNames (lib.filterAttrs + # (_: drv: (builtins.tryEval (lib.isDerivation drv && drv ? terminfo)).value) # pkgs) - environment.systemPackages = mkIf config.environment.enableAllTerminfo (map (x: x.terminfo) (with pkgs.pkgsBuildBuild; [ - alacritty - contour - foot - kitty - mtm - rio - rxvt-unicode-unwrapped - rxvt-unicode-unwrapped-emoji - st - termite - tmux - wezterm - yaft - ])); + environment.systemPackages = lib.mkIf config.environment.enableAllTerminfo ( + map (x: x.terminfo) ( + with pkgs.pkgsBuildBuild; + [ + alacritty + foot + kitty + mtm + rio + rxvt-unicode-unwrapped + rxvt-unicode-unwrapped-emoji + st + termite + tmux + wezterm + yaft + ] + ) + ); environment.pathsToLink = [ "/share/terminfo" @@ -65,7 +72,7 @@ with lib; export TERM=$TERM ''; - security.sudo.extraConfig = mkIf config.security.sudo.keepTerminfo '' + security.sudo.extraConfig = lib.mkIf config.security.sudo.keepTerminfo '' # Keep terminfo database for root and %wheel. Defaults:root,%wheel env_keep+=TERMINFO_DIRS diff --git a/nixos/modules/config/unix-odbc-drivers.nix b/nixos/modules/config/unix-odbc-drivers.nix index 28cf7e84b7bc..8bf7f3b28af6 100644 --- a/nixos/modules/config/unix-odbc-drivers.nix +++ b/nixos/modules/config/unix-odbc-drivers.nix @@ -1,7 +1,4 @@ { config, lib, ... }: - -with lib; - # unixODBC drivers (this solution is not perfect.. Because the user has to # ask the admin to add a driver.. but it's simple and works @@ -16,10 +13,10 @@ in { ###### interface options = { - environment.unixODBCDrivers = mkOption { - type = types.listOf types.package; + environment.unixODBCDrivers = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "with pkgs.unixODBCDrivers; [ sqlite psql ]"; + example = lib.literalExpression "with pkgs.unixODBCDrivers; [ sqlite psql ]"; description = '' Specifies Unix ODBC drivers to be registered in {file}`/etc/odbcinst.ini`. You may also want to @@ -31,8 +28,8 @@ in { ###### implementation - config = mkIf (config.environment.unixODBCDrivers != []) { - environment.etc."odbcinst.ini".text = concatMapStringsSep "\n" iniDescription config.environment.unixODBCDrivers; + config = lib.mkIf (config.environment.unixODBCDrivers != []) { + environment.etc."odbcinst.ini".text = lib.concatMapStringsSep "\n" iniDescription config.environment.unixODBCDrivers; }; } diff --git a/nixos/modules/config/vte.nix b/nixos/modules/config/vte.nix index e0b48c3fb4a8..a86a148b54f9 100644 --- a/nixos/modules/config/vte.nix +++ b/nixos/modules/config/vte.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let vteInitSnippet = '' @@ -15,14 +12,14 @@ in { meta = { - maintainers = teams.gnome.members; + maintainers = lib.teams.gnome.members; }; options = { - programs.bash.vteIntegration = mkOption { + programs.bash.vteIntegration = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to enable Bash integration for VTE terminals. This allows it to preserve the current directory of the shell @@ -30,9 +27,9 @@ in ''; }; - programs.zsh.vteIntegration = mkOption { + programs.zsh.vteIntegration = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to enable Zsh integration for VTE terminals. This allows it to preserve the current directory of the shell @@ -42,12 +39,12 @@ in }; - config = mkMerge [ - (mkIf config.programs.bash.vteIntegration { - programs.bash.interactiveShellInit = mkBefore vteInitSnippet; + config = lib.mkMerge [ + (lib.mkIf config.programs.bash.vteIntegration { + programs.bash.interactiveShellInit = lib.mkBefore vteInitSnippet; }) - (mkIf config.programs.zsh.vteIntegration { + (lib.mkIf config.programs.zsh.vteIntegration { programs.zsh.interactiveShellInit = vteInitSnippet; }) ]; diff --git a/nixos/modules/config/xdg/autostart.nix b/nixos/modules/config/xdg/autostart.nix index acdb7cd3adc6..6f33f592cf57 100644 --- a/nixos/modules/config/xdg/autostart.nix +++ b/nixos/modules/config/xdg/autostart.nix @@ -1,14 +1,12 @@ { config, lib, ... }: - -with lib; { meta = { - maintainers = teams.freedesktop.members; + maintainers = lib.teams.freedesktop.members; }; options = { - xdg.autostart.enable = mkOption { - type = types.bool; + xdg.autostart.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to install files to support the @@ -17,7 +15,7 @@ with lib; }; }; - config = mkIf config.xdg.autostart.enable { + config = lib.mkIf config.xdg.autostart.enable { environment.pathsToLink = [ "/etc/xdg/autostart" ]; diff --git a/nixos/modules/config/xdg/icons.nix b/nixos/modules/config/xdg/icons.nix index 3f198101d306..b0267d21d3eb 100644 --- a/nixos/modules/config/xdg/icons.nix +++ b/nixos/modules/config/xdg/icons.nix @@ -1,23 +1,29 @@ { config, lib, pkgs, ... }: - -with lib; { meta = { - maintainers = teams.freedesktop.members; + maintainers = lib.teams.freedesktop.members; }; options = { - xdg.icons.enable = mkOption { - type = types.bool; + xdg.icons.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to install files to support the [XDG Icon Theme specification](https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html). ''; }; + xdg.icons.fallbackCursorThemes = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = '' + Names of the fallback cursor themes, in order of preference, to be used when no other icon source can be found. + Set to `[]` to disable the fallback entirely. + ''; + }; }; - config = mkIf config.xdg.icons.enable { + config = lib.mkIf config.xdg.icons.enable { environment.pathsToLink = [ "/share/icons" "/share/pixmaps" @@ -27,6 +33,15 @@ with lib; # Empty icon theme that contains index.theme file describing directories # where toolkits should look for icons installed by apps. pkgs.hicolor-icon-theme + ] ++ lib.optionals (config.xdg.icons.fallbackCursorThemes != []) [ + (pkgs.writeTextFile { + name = "fallback-cursor-theme"; + text = '' + [Icon Theme] + Inherits=${lib.concatStringsSep "," config.xdg.icons.fallbackCursorThemes} + ''; + destination = "/share/icons/default/index.theme"; + }) ]; # libXcursor looks for cursors in XCURSOR_PATH diff --git a/nixos/modules/config/xdg/menus.nix b/nixos/modules/config/xdg/menus.nix index 8510c2db654e..a71a46dd36cc 100644 --- a/nixos/modules/config/xdg/menus.nix +++ b/nixos/modules/config/xdg/menus.nix @@ -1,14 +1,12 @@ { config, lib, ... }: - -with lib; { meta = { - maintainers = teams.freedesktop.members; + maintainers = lib.teams.freedesktop.members; }; options = { - xdg.menus.enable = mkOption { - type = types.bool; + xdg.menus.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to install files to support the @@ -17,7 +15,7 @@ with lib; }; }; - config = mkIf config.xdg.menus.enable { + config = lib.mkIf config.xdg.menus.enable { environment.pathsToLink = [ "/share/applications" "/share/desktop-directories" diff --git a/nixos/modules/config/xdg/mime.nix b/nixos/modules/config/xdg/mime.nix index 2cd88be5b023..9bd1af397002 100644 --- a/nixos/modules/config/xdg/mime.nix +++ b/nixos/modules/config/xdg/mime.nix @@ -1,22 +1,19 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.xdg.mime; - associationOptions = with types; attrsOf ( - coercedTo (either (listOf str) str) (x: concatStringsSep ";" (toList x)) str + associationOptions = with lib.types; attrsOf ( + coercedTo (either (listOf str) str) (x: lib.concatStringsSep ";" (lib.toList x)) str ); in { meta = { - maintainers = teams.freedesktop.members ++ (with maintainers; [ figsoda ]); + maintainers = lib.teams.freedesktop.members ++ (with lib.maintainers; [ figsoda ]); }; options = { - xdg.mime.enable = mkOption { - type = types.bool; + xdg.mime.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to install files to support the @@ -25,7 +22,7 @@ in ''; }; - xdg.mime.addedAssociations = mkOption { + xdg.mime.addedAssociations = lib.mkOption { type = associationOptions; default = {}; example = { @@ -39,7 +36,7 @@ in ''; }; - xdg.mime.defaultApplications = mkOption { + xdg.mime.defaultApplications = lib.mkOption { type = associationOptions; default = {}; example = { @@ -53,7 +50,7 @@ in ''; }; - xdg.mime.removedAssociations = mkOption { + xdg.mime.removedAssociations = lib.mkOption { type = associationOptions; default = {}; example = { @@ -68,13 +65,13 @@ in }; }; - config = mkIf cfg.enable { - environment.etc."xdg/mimeapps.list" = mkIf ( + config = lib.mkIf cfg.enable { + environment.etc."xdg/mimeapps.list" = lib.mkIf ( cfg.addedAssociations != {} || cfg.defaultApplications != {} || cfg.removedAssociations != {} ) { - text = generators.toINI { } { + text = lib.generators.toINI { } { "Added Associations" = cfg.addedAssociations; "Default Applications" = cfg.defaultApplications; "Removed Associations" = cfg.removedAssociations; diff --git a/nixos/modules/config/xdg/portal.nix b/nixos/modules/config/xdg/portal.nix index ec4e13169fa3..7e66a32c7db2 100644 --- a/nixos/modules/config/xdg/portal.nix +++ b/nixos/modules/config/xdg/portal.nix @@ -83,7 +83,7 @@ in configPackages = mkOption { type = types.listOf types.package; default = [ ]; - example = lib.literalExpression "[ pkgs.gnome.gnome-session ]"; + example = lib.literalExpression "[ pkgs.gnome-session ]"; description = '' List of packages that provide XDG desktop portal configuration, usually in the form of `share/xdg-desktop-portal/$desktop-portals.conf`. diff --git a/nixos/modules/config/xdg/portals/lxqt.nix b/nixos/modules/config/xdg/portals/lxqt.nix index 23a1622308bd..846c9b199437 100644 --- a/nixos/modules/config/xdg/portals/lxqt.nix +++ b/nixos/modules/config/xdg/portals/lxqt.nix @@ -1,18 +1,15 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.xdg.portal.lxqt; in { meta = { - maintainers = teams.lxqt.members; + maintainers = lib.teams.lxqt.members; }; options.xdg.portal.lxqt = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' the desktop portal for the LXQt desktop environment. This will add the `lxqt.xdg-desktop-portal-lxqt` @@ -20,10 +17,10 @@ in {option}`xdg.portal.extraPortals` option ''; - styles = mkOption { - type = types.listOf types.package; + styles = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression ''[ + example = lib.literalExpression ''[ pkgs.libsForQt5.qtstyleplugin-kvantum pkgs.breeze-qt5 pkgs.qtcurve @@ -36,7 +33,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { xdg.portal = { enable = true; extraPortals = [ diff --git a/nixos/modules/config/xdg/portals/wlr.nix b/nixos/modules/config/xdg/portals/wlr.nix index 954830eff2d3..ed09a31a86d7 100644 --- a/nixos/modules/config/xdg/portals/wlr.nix +++ b/nixos/modules/config/xdg/portals/wlr.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.xdg.portal.wlr; package = pkgs.xdg-desktop-portal-wlr; @@ -10,11 +7,11 @@ let in { meta = { - maintainers = with maintainers; [ minijackson ]; + maintainers = with lib.maintainers; [ minijackson ]; }; options.xdg.portal.wlr = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' desktop portal for wlroots-based desktops. This will add the `xdg-desktop-portal-wlr` package into @@ -22,7 +19,7 @@ in configuration file ''; - settings = mkOption { + settings = lib.mkOption { description = '' Configuration for `xdg-desktop-portal-wlr`. @@ -30,14 +27,14 @@ in values. ''; - type = types.submodule { + type = lib.types.submodule { freeformType = settingsFormat.type; }; default = { }; # Example taken from the manpage - example = literalExpression '' + example = lib.literalExpression '' { screencast = { output_name = "HDMI-A-1"; @@ -52,7 +49,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { xdg.portal = { enable = true; extraPortals = [ package ]; diff --git a/nixos/modules/config/xdg/sounds.nix b/nixos/modules/config/xdg/sounds.nix index 0aae77fe0107..e19e23d72a47 100644 --- a/nixos/modules/config/xdg/sounds.nix +++ b/nixos/modules/config/xdg/sounds.nix @@ -1,14 +1,12 @@ { config, lib, pkgs, ... }: - -with lib; { meta = { - maintainers = teams.freedesktop.members; + maintainers = lib.teams.freedesktop.members; }; options = { - xdg.sounds.enable = mkOption { - type = types.bool; + xdg.sounds.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to install files to support the @@ -17,7 +15,7 @@ with lib; }; }; - config = mkIf config.xdg.sounds.enable { + config = lib.mkIf config.xdg.sounds.enable { environment.systemPackages = [ pkgs.sound-theme-freedesktop ]; diff --git a/nixos/modules/hardware/acpilight.nix b/nixos/modules/hardware/acpilight.nix index 2de448a265c7..211d18ceb11a 100644 --- a/nixos/modules/hardware/acpilight.nix +++ b/nixos/modules/hardware/acpilight.nix @@ -1,15 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.hardware.acpilight; in { options = { hardware.acpilight = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable acpilight. This will allow brightness control via xbacklight from users in the video group @@ -18,7 +16,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs; [ acpilight ]; services.udev.packages = with pkgs; [ acpilight ]; }; diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix index abad6e08611f..6475cfc843d2 100644 --- a/nixos/modules/hardware/all-firmware.nix +++ b/nixos/modules/hardware/all-firmware.nix @@ -1,33 +1,30 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware; in { imports = [ - (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "hardware" "enableRedistributableFirmware" ]) - (mkRenamedOptionModule [ "networking" "enableIntel3945ABGFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) - (mkRenamedOptionModule [ "networking" "enableIntel2100BGFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) - (mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) - (mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) + (lib.mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "hardware" "enableRedistributableFirmware" ]) + (lib.mkRenamedOptionModule [ "networking" "enableIntel3945ABGFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) + (lib.mkRenamedOptionModule [ "networking" "enableIntel2100BGFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) + (lib.mkRenamedOptionModule [ "networking" "enableRalinkFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) + (lib.mkRenamedOptionModule [ "networking" "enableRTL8192cFirmware" ] [ "hardware" "enableRedistributableFirmware" ]) ]; ###### interface options = { - hardware.enableAllFirmware = mkEnableOption "all firmware regardless of license"; + hardware.enableAllFirmware = lib.mkEnableOption "all firmware regardless of license"; - hardware.enableRedistributableFirmware = mkEnableOption "firmware with a license allowing redistribution" // { + hardware.enableRedistributableFirmware = lib.mkEnableOption "firmware with a license allowing redistribution" // { default = config.hardware.enableAllFirmware; defaultText = lib.literalExpression "config.hardware.enableAllFirmware"; }; - hardware.wirelessRegulatoryDatabase = mkEnableOption "loading the wireless regulatory database at boot" // { + hardware.wirelessRegulatoryDatabase = lib.mkEnableOption "loading the wireless regulatory database at boot" // { default = cfg.enableRedistributableFirmware || cfg.enableAllFirmware; - defaultText = literalMD "Enabled if proprietary firmware is allowed via {option}`enableRedistributableFirmware` or {option}`enableAllFirmware`."; + defaultText = lib.literalMD "Enabled if proprietary firmware is allowed via {option}`enableRedistributableFirmware` or {option}`enableAllFirmware`."; }; }; @@ -35,8 +32,8 @@ in { ###### implementation - config = mkMerge [ - (mkIf (cfg.enableAllFirmware || cfg.enableRedistributableFirmware) { + config = lib.mkMerge [ + (lib.mkIf (cfg.enableAllFirmware || cfg.enableRedistributableFirmware) { hardware.firmware = with pkgs; [ linux-firmware intel2200BGFirmware @@ -47,9 +44,9 @@ in { alsa-firmware sof-firmware libreelec-dvb-firmware - ] ++ optional pkgs.stdenv.hostPlatform.isAarch raspberrypiWirelessFirmware; + ] ++ lib.optional pkgs.stdenv.hostPlatform.isAarch raspberrypiWirelessFirmware; }) - (mkIf cfg.enableAllFirmware { + (lib.mkIf cfg.enableAllFirmware { assertions = [{ assertion = !cfg.enableAllFirmware || pkgs.config.allowUnfree; message = '' @@ -63,12 +60,12 @@ in { b43Firmware_5_1_138 b43Firmware_6_30_163_46 xow_dongle-firmware - ] ++ optionals pkgs.stdenv.hostPlatform.isx86 [ + ] ++ lib.optionals pkgs.stdenv.hostPlatform.isx86 [ facetimehd-calibration facetimehd-firmware ]; }) - (mkIf cfg.wirelessRegulatoryDatabase { + (lib.mkIf cfg.wirelessRegulatoryDatabase { hardware.firmware = [ pkgs.wireless-regdb ]; }) ]; diff --git a/nixos/modules/hardware/bladeRF.nix b/nixos/modules/hardware/bladeRF.nix index 35b74b8382e3..877acbbf598c 100644 --- a/nixos/modules/hardware/bladeRF.nix +++ b/nixos/modules/hardware/bladeRF.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.bladeRF; @@ -9,8 +6,8 @@ in { options.hardware.bladeRF = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enables udev rules for BladeRF devices. By default grants access @@ -21,7 +18,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ pkgs.libbladeRF ]; users.groups.bladerf = {}; }; diff --git a/nixos/modules/hardware/brillo.nix b/nixos/modules/hardware/brillo.nix index 8e36022a9a30..915801c137be 100644 --- a/nixos/modules/hardware/brillo.nix +++ b/nixos/modules/hardware/brillo.nix @@ -1,20 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.hardware.brillo; in { options = { hardware.brillo = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' brillo in userspace. This will allow brightness control from users in the video group ''; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ pkgs.brillo ]; environment.systemPackages = [ pkgs.brillo ]; }; diff --git a/nixos/modules/hardware/ckb-next.nix b/nixos/modules/hardware/ckb-next.nix index 1fb97c16d75f..5de5666d20c9 100644 --- a/nixos/modules/hardware/ckb-next.nix +++ b/nixos/modules/hardware/ckb-next.nix @@ -1,22 +1,19 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.ckb-next; in { imports = [ - (mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ]) - (mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ]) + (lib.mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ]) + (lib.mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ]) ]; options.hardware.ckb-next = { - enable = mkEnableOption "the Corsair keyboard/mouse driver"; + enable = lib.mkEnableOption "the Corsair keyboard/mouse driver"; - gid = mkOption { - type = types.nullOr types.int; + gid = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 100; description = '' @@ -24,17 +21,17 @@ in ''; }; - package = mkPackageOption pkgs "ckb-next" { }; + package = lib.mkPackageOption pkgs "ckb-next" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; systemd.services.ckb-next = { description = "Corsair Keyboards and Mice Daemon"; wantedBy = ["multi-user.target"]; serviceConfig = { - ExecStart = "${cfg.package}/bin/ckb-next-daemon ${optionalString (cfg.gid != null) "--gid=${builtins.toString cfg.gid}"}"; + ExecStart = "${cfg.package}/bin/ckb-next-daemon ${lib.optionalString (cfg.gid != null) "--gid=${builtins.toString cfg.gid}"}"; Restart = "on-failure"; }; }; diff --git a/nixos/modules/hardware/corectrl.nix b/nixos/modules/hardware/corectrl.nix index 9e8b69cf6277..88b94e12f6b6 100644 --- a/nixos/modules/hardware/corectrl.nix +++ b/nixos/modules/hardware/corectrl.nix @@ -1,27 +1,24 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.programs.corectrl; in { options.programs.corectrl = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' CoreCtrl, a tool to overclock amd graphics cards and processors. Add your user to the corectrl group to run corectrl without needing to enter your password ''; - package = mkPackageOption pkgs "corectrl" { + package = lib.mkPackageOption pkgs "corectrl" { extraDescription = "Useful for overriding the configuration options used for the package."; }; gpuOverclock = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' GPU overclocking ''; - ppfeaturemask = mkOption { - type = types.str; + ppfeaturemask = lib.mkOption { + type = lib.types.str; default = "0xfffd7fff"; example = "0xffffffff"; description = '' @@ -34,7 +31,7 @@ in }; }; - config = mkIf cfg.enable (lib.mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/hardware/cpu/amd-microcode.nix b/nixos/modules/hardware/cpu/amd-microcode.nix index 621c7066bfe1..25ce70a5811d 100644 --- a/nixos/modules/hardware/cpu/amd-microcode.nix +++ b/nixos/modules/hardware/cpu/amd-microcode.nix @@ -1,16 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - { - ###### interface - options = { - hardware.cpu.amd.updateMicrocode = mkOption { + hardware.cpu.amd.updateMicrocode = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Update the CPU microcode for AMD processors. ''; @@ -18,12 +13,10 @@ with lib; }; - ###### implementation - - config = mkIf config.hardware.cpu.amd.updateMicrocode { + config = lib.mkIf config.hardware.cpu.amd.updateMicrocode { # Microcode updates must be the first item prepended in the initrd - boot.initrd.prepend = mkOrder 1 [ "${pkgs.microcodeAmd}/amd-ucode.img" ]; + boot.initrd.prepend = lib.mkOrder 1 [ "${pkgs.microcode-amd}/amd-ucode.img" ]; }; } diff --git a/nixos/modules/hardware/cpu/amd-sev.nix b/nixos/modules/hardware/cpu/amd-sev.nix index d6225bc35a1e..8dae958bf344 100644 --- a/nixos/modules/hardware/cpu/amd-sev.nix +++ b/nixos/modules/hardware/cpu/amd-sev.nix @@ -1,24 +1,23 @@ { config, options, lib, ... }: -with lib; let cfgSev = config.hardware.cpu.amd.sev; cfgSevGuest = config.hardware.cpu.amd.sevGuest; optionsFor = device: group: { - enable = mkEnableOption "access to the AMD ${device} device"; - user = mkOption { + enable = lib.mkEnableOption "access to the AMD ${device} device"; + user = lib.mkOption { description = "Owner to assign to the ${device} device."; - type = types.str; + type = lib.types.str; default = "root"; }; - group = mkOption { + group = lib.mkOption { description = "Group to assign to the ${device} device."; - type = types.str; + type = lib.types.str; default = group; }; - mode = mkOption { + mode = lib.mkOption { description = "Mode to set for the ${device} device."; - type = types.str; + type = lib.types.str; default = "0660"; }; }; @@ -28,16 +27,16 @@ with lib; { options.hardware.cpu.amd.sevGuest = optionsFor "SEV guest" "sev-guest"; - config = mkMerge [ + config = lib.mkMerge [ # /dev/sev - (mkIf cfgSev.enable { + (lib.mkIf cfgSev.enable { assertions = [ { - assertion = hasAttr cfgSev.user config.users.users; + assertion = lib.hasAttr cfgSev.user config.users.users; message = "Given user does not exist"; } { - assertion = (cfgSev.group == options.hardware.cpu.amd.sev.group.default) || (hasAttr cfgSev.group config.users.groups); + assertion = (cfgSev.group == options.hardware.cpu.amd.sev.group.default) || (lib.hasAttr cfgSev.group config.users.groups); message = "Given group does not exist"; } ]; @@ -46,7 +45,7 @@ with lib; { options kvm_amd sev=1 ''; - users.groups = optionalAttrs (cfgSev.group == options.hardware.cpu.amd.sev.group.default) { + users.groups = lib.optionalAttrs (cfgSev.group == options.hardware.cpu.amd.sev.group.default) { "${cfgSev.group}" = { }; }; @@ -56,19 +55,19 @@ with lib; { }) # /dev/sev-guest - (mkIf cfgSevGuest.enable { + (lib.mkIf cfgSevGuest.enable { assertions = [ { - assertion = hasAttr cfgSevGuest.user config.users.users; + assertion = lib.hasAttr cfgSevGuest.user config.users.users; message = "Given user does not exist"; } { - assertion = (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) || (hasAttr cfgSevGuest.group config.users.groups); + assertion = (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) || (lib.hasAttr cfgSevGuest.group config.users.groups); message = "Given group does not exist"; } ]; - users.groups = optionalAttrs (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) { + users.groups = lib.optionalAttrs (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) { "${cfgSevGuest.group}" = { }; }; diff --git a/nixos/modules/hardware/cpu/intel-microcode.nix b/nixos/modules/hardware/cpu/intel-microcode.nix index acce565fd808..e708d447910e 100644 --- a/nixos/modules/hardware/cpu/intel-microcode.nix +++ b/nixos/modules/hardware/cpu/intel-microcode.nix @@ -1,16 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - { - ###### interface - options = { - hardware.cpu.intel.updateMicrocode = mkOption { + hardware.cpu.intel.updateMicrocode = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Update the CPU microcode for Intel processors. ''; @@ -18,12 +13,10 @@ with lib; }; - ###### implementation - - config = mkIf config.hardware.cpu.intel.updateMicrocode { + config = lib.mkIf config.hardware.cpu.intel.updateMicrocode { # Microcode updates must be the first item prepended in the initrd - boot.initrd.prepend = mkOrder 1 [ "${pkgs.microcodeIntel}/intel-ucode.img" ]; + boot.initrd.prepend = lib.mkOrder 1 [ "${pkgs.microcode-intel}/intel-ucode.img" ]; }; } diff --git a/nixos/modules/hardware/cpu/intel-sgx.nix b/nixos/modules/hardware/cpu/intel-sgx.nix index c66b43a2ec27..79d0bc1599ee 100644 --- a/nixos/modules/hardware/cpu/intel-sgx.nix +++ b/nixos/modules/hardware/cpu/intel-sgx.nix @@ -1,11 +1,10 @@ { config, lib, ... }: -with lib; let cfg = config.hardware.cpu.intel.sgx; defaultPrvGroup = "sgx_prv"; in { - options.hardware.cpu.intel.sgx.enableDcapCompat = mkOption { + options.hardware.cpu.intel.sgx.enableDcapCompat = lib.mkOption { description = '' Whether to enable backward compatibility for SGX software build for the out-of-tree Intel SGX DCAP driver. @@ -15,43 +14,43 @@ in `/dev/sgx/enclave` and `/dev/sgx/provision`, respectively. ''; - type = types.bool; + type = lib.types.bool; default = true; }; options.hardware.cpu.intel.sgx.provision = { - enable = mkEnableOption "access to the Intel SGX provisioning device"; - user = mkOption { + enable = lib.mkEnableOption "access to the Intel SGX provisioning device"; + user = lib.mkOption { description = "Owner to assign to the SGX provisioning device."; - type = types.str; + type = lib.types.str; default = "root"; }; - group = mkOption { + group = lib.mkOption { description = "Group to assign to the SGX provisioning device."; - type = types.str; + type = lib.types.str; default = defaultPrvGroup; }; - mode = mkOption { + mode = lib.mkOption { description = "Mode to set for the SGX provisioning device."; - type = types.str; + type = lib.types.str; default = "0660"; }; }; - config = mkMerge [ - (mkIf cfg.provision.enable { + config = lib.mkMerge [ + (lib.mkIf cfg.provision.enable { assertions = [ { - assertion = hasAttr cfg.provision.user config.users.users; + assertion = lib.hasAttr cfg.provision.user config.users.users; message = "Given user does not exist"; } { - assertion = (cfg.provision.group == defaultPrvGroup) || (hasAttr cfg.provision.group config.users.groups); + assertion = (cfg.provision.group == defaultPrvGroup) || (lib.hasAttr cfg.provision.group config.users.groups); message = "Given group does not exist"; } ]; - users.groups = optionalAttrs (cfg.provision.group == defaultPrvGroup) { + users.groups = lib.optionalAttrs (cfg.provision.group == defaultPrvGroup) { "${cfg.provision.group}" = { }; }; @@ -59,7 +58,7 @@ in SUBSYSTEM=="misc", KERNEL=="sgx_provision", OWNER="${user}", GROUP="${group}", MODE="${mode}" ''; }) - (mkIf cfg.enableDcapCompat { + (lib.mkIf cfg.enableDcapCompat { services.udev.extraRules = '' SUBSYSTEM=="misc", KERNEL=="sgx_enclave", SYMLINK+="sgx/enclave" SUBSYSTEM=="misc", KERNEL=="sgx_provision", SYMLINK+="sgx/provision" diff --git a/nixos/modules/hardware/device-tree.nix b/nixos/modules/hardware/device-tree.nix index a29cc76ea8f9..b3feedf1edad 100644 --- a/nixos/modules/hardware/device-tree.nix +++ b/nixos/modules/hardware/device-tree.nix @@ -1,21 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.deviceTree; - overlayType = types.submodule { + overlayType = lib.types.submodule { options = { - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; description = '' Name of this overlay ''; }; - filter = mkOption { - type = types.nullOr types.str; + filter = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "*rpi*.dtb"; description = '' @@ -23,18 +20,18 @@ let ''; }; - dtsFile = mkOption { - type = types.nullOr types.path; + dtsFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' Path to .dts overlay file, overlay is applied to each .dtb file matching "compatible" of the overlay. ''; default = null; - example = literalExpression "./dts/overlays.dts"; + example = lib.literalExpression "./dts/overlays.dts"; }; - dtsText = mkOption { - type = types.nullOr types.str; + dtsText = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Literal DTS contents, overlay is applied to @@ -55,8 +52,8 @@ let ''; }; - dtboFile = mkOption { - type = types.nullOr types.path; + dtboFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to .dtbo compiled overlay file. @@ -79,9 +76,9 @@ let # Fill in `dtboFile` for each overlay if not set already. # Existence of one of these is guarded by assertion below - withDTBOs = xs: flip map xs (o: o // { dtboFile = + withDTBOs = xs: lib.flip map xs (o: o // { dtboFile = let - includePaths = ["${getDev cfg.kernelPackage}/lib/modules/${cfg.kernelPackage.modDirVersion}/source/scripts/dtc/include-prefixes"] ++ cfg.dtboBuildExtraIncludePaths; + includePaths = ["${lib.getDev cfg.kernelPackage}/lib/modules/${cfg.kernelPackage.modDirVersion}/source/scripts/dtc/include-prefixes"] ++ cfg.dtboBuildExtraIncludePaths; extraPreprocessorFlags = cfg.dtboBuildExtraPreprocessorFlags; in if o.dtboFile == null then @@ -97,67 +94,67 @@ let in { imports = [ - (mkRemovedOptionModule [ "hardware" "deviceTree" "base" ] "Use hardware.deviceTree.kernelPackage instead") + (lib.mkRemovedOptionModule [ "hardware" "deviceTree" "base" ] "Use hardware.deviceTree.kernelPackage instead") ]; options = { hardware.deviceTree = { - enable = mkOption { + enable = lib.mkOption { default = pkgs.stdenv.hostPlatform.linux-kernel.DTB or false; - type = types.bool; + type = lib.types.bool; description = '' Build device tree files. These are used to describe the non-discoverable hardware of a system. ''; }; - kernelPackage = mkOption { + kernelPackage = lib.mkOption { default = config.boot.kernelPackages.kernel; - defaultText = literalExpression "config.boot.kernelPackages.kernel"; - example = literalExpression "pkgs.linux_latest"; - type = types.path; + defaultText = lib.literalExpression "config.boot.kernelPackages.kernel"; + example = lib.literalExpression "pkgs.linux_latest"; + type = lib.types.path; description = '' Kernel package where device tree include directory is from. Also used as default source of dtb package to apply overlays to ''; }; - dtboBuildExtraPreprocessorFlags = mkOption { + dtboBuildExtraPreprocessorFlags = lib.mkOption { default = []; - example = literalExpression "[ \"-DMY_DTB_DEFINE\" ]"; - type = types.listOf types.str; + example = lib.literalExpression "[ \"-DMY_DTB_DEFINE\" ]"; + type = lib.types.listOf lib.types.str; description = '' Additional flags to pass to the preprocessor during dtbo compilations ''; }; - dtboBuildExtraIncludePaths = mkOption { + dtboBuildExtraIncludePaths = lib.mkOption { default = []; - example = literalExpression '' + example = lib.literalExpression '' [ ./my_custom_include_dir_1 ./custom_include_dir_2 ] ''; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; description = '' Additional include paths that will be passed to the preprocessor when creating the final .dts to compile into .dtbo ''; }; - dtbSource = mkOption { + dtbSource = lib.mkOption { default = "${cfg.kernelPackage}/dtbs"; - defaultText = literalExpression "\${cfg.kernelPackage}/dtbs"; - type = types.path; + defaultText = lib.literalExpression "\${cfg.kernelPackage}/dtbs"; + type = lib.types.path; description = '' Path to dtb directory that overlays and other processing will be applied to. Uses device trees bundled with the Linux kernel by default. ''; }; - name = mkOption { + name = lib.mkOption { default = null; example = "some-dtb.dtb"; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The name of an explicit dtb to be loaded, relative to the dtb base. Useful in extlinux scenarios if the bootloader doesn't pick the @@ -165,8 +162,8 @@ in ''; }; - filter = mkOption { - type = types.nullOr types.str; + filter = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "*rpi*.dtb"; description = '' @@ -174,9 +171,9 @@ in ''; }; - overlays = mkOption { + overlays = lib.mkOption { default = []; - example = literalExpression '' + example = lib.literalExpression '' [ { name = "pps"; dtsFile = ./dts/pps.dts; } { name = "spi"; @@ -185,7 +182,7 @@ in { name = "precompiled"; dtboFile = ./dtbos/example.dtbo; } ] ''; - type = types.listOf (types.coercedTo types.path (path: { + type = lib.types.listOf (lib.types.coercedTo lib.types.path (path: { name = baseNameOf path; filter = null; dtboFile = path; @@ -195,9 +192,9 @@ in ''; }; - package = mkOption { + package = lib.mkOption { default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; internal = true; description = '' A path containing the result of applying `overlays` to `kernelPackage`. @@ -206,7 +203,7 @@ in }; }; - config = mkIf (cfg.enable) { + config = lib.mkIf (cfg.enable) { assertions = let invalidOverlay = o: (o.dtsFile == null) && (o.dtsText == null) && (o.dtboFile == null); diff --git a/nixos/modules/hardware/digitalbitbox.nix b/nixos/modules/hardware/digitalbitbox.nix index 7df15288ecfe..c5c8204e321a 100644 --- a/nixos/modules/hardware/digitalbitbox.nix +++ b/nixos/modules/hardware/digitalbitbox.nix @@ -1,29 +1,26 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.digitalbitbox; in { options.hardware.digitalbitbox = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enables udev rules for Digital Bitbox devices. ''; }; - package = mkPackageOption pkgs "digitalbitbox" { + package = lib.mkPackageOption pkgs "digitalbitbox" { extraDescription = '' This can be used to install a package with udev rules that differ from the defaults. ''; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ cfg.package ]; }; } diff --git a/nixos/modules/hardware/flipperzero.nix b/nixos/modules/hardware/flipperzero.nix index 3a6d29d0f9eb..bda2e2c8e0a5 100644 --- a/nixos/modules/hardware/flipperzero.nix +++ b/nixos/modules/hardware/flipperzero.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.flipperzero; @@ -9,9 +6,9 @@ let in { - options.hardware.flipperzero.enable = mkEnableOption "udev rules and software for Flipper Zero devices"; + options.hardware.flipperzero.enable = lib.mkEnableOption "udev rules and software for Flipper Zero devices"; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.qFlipper ]; services.udev.packages = [ pkgs.qFlipper ]; }; diff --git a/nixos/modules/hardware/gkraken.nix b/nixos/modules/hardware/gkraken.nix index 97d15369db0a..90b0069e80c8 100644 --- a/nixos/modules/hardware/gkraken.nix +++ b/nixos/modules/hardware/gkraken.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.gkraken; in { options.hardware.gkraken = { - enable = mkEnableOption "gkraken's udev rules for NZXT AIO liquid coolers"; + enable = lib.mkEnableOption "gkraken's udev rules for NZXT AIO liquid coolers"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = with pkgs; [ gkraken ]; diff --git a/nixos/modules/hardware/gpgsmartcards.nix b/nixos/modules/hardware/gpgsmartcards.nix index cc3f4c769976..3940efd09e22 100644 --- a/nixos/modules/hardware/gpgsmartcards.nix +++ b/nixos/modules/hardware/gpgsmartcards.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let # gnupg's manual describes how to setup ccid udev rules: # https://www.gnupg.org/howtos/card-howto/en/ch02s03.html @@ -28,10 +26,10 @@ let cfg = config.hardware.gpgSmartcards; in { options.hardware.gpgSmartcards = { - enable = mkEnableOption "udev rules for gnupg smart cards"; + enable = lib.mkEnableOption "udev rules for gnupg smart cards"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ scdaemonUdevRulesPkg ]; }; } diff --git a/nixos/modules/hardware/graphics.nix b/nixos/modules/hardware/graphics.nix index 99c122f75c2a..2d6b377ae5fb 100644 --- a/nixos/modules/hardware/graphics.nix +++ b/nixos/modules/hardware/graphics.nix @@ -14,7 +14,7 @@ let in { imports = [ - (lib.mkRenamedOptionModule [ "services" "xserver" "vaapiDrivers" ] [ "hardware" "opengl" "extraPackages" ]) + (lib.mkRenamedOptionModule [ "services" "xserver" "vaapiDrivers" ] [ "hardware" "graphics" "extraPackages" ]) (lib.mkRemovedOptionModule [ "hardware" "opengl" "s3tcSupport" ] "S3TC support is now always enabled in Mesa.") (lib.mkRemovedOptionModule [ "hardware" "opengl" "driSupport"] "The setting can be removed.") @@ -100,7 +100,7 @@ in config = lib.mkIf cfg.enable { assertions = [ { - assertion = cfg.enable32Bit -> pkgs.stdenv.isx86_64; + assertion = cfg.enable32Bit -> pkgs.stdenv.hostPlatform.isx86_64; message = "`hardware.graphics.enable32Bit` only makes sense on a 64-bit system."; } { @@ -112,7 +112,7 @@ in systemd.tmpfiles.settings.graphics-driver = { "/run/opengl-driver"."L+".argument = toString driversEnv; "/run/opengl-driver-32" = - if pkgs.stdenv.isi686 then + if pkgs.stdenv.hostPlatform.isi686 then { "L+".argument = "opengl-driver"; } else if cfg.enable32Bit then { "L+".argument = toString driversEnv32; } diff --git a/nixos/modules/hardware/i2c.nix b/nixos/modules/hardware/i2c.nix index b1e5cfd9e025..4dd7a8ccc531 100644 --- a/nixos/modules/hardware/i2c.nix +++ b/nixos/modules/hardware/i2c.nix @@ -1,21 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.i2c; in { options.hardware.i2c = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' i2c devices support. By default access is granted to users in the "i2c" group (will be created if non-existent) and any user with a seat, meaning logged on the computer locally ''; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "i2c"; description = '' Grant access to i2c devices (/dev/i2c-*) to users in this group. @@ -23,11 +20,11 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "i2c-dev" ]; - users.groups = mkIf (cfg.group == "i2c") { + users.groups = lib.mkIf (cfg.group == "i2c") { i2c = { }; }; @@ -42,6 +39,6 @@ in }; - meta.maintainers = [ maintainers.rnhmjoj ]; + meta.maintainers = [ lib.maintainers.rnhmjoj ]; } diff --git a/nixos/modules/hardware/infiniband.nix b/nixos/modules/hardware/infiniband.nix index 6780aee9f36b..b09453116cf9 100644 --- a/nixos/modules/hardware/infiniband.nix +++ b/nixos/modules/hardware/infiniband.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.infiniband; @@ -31,9 +28,9 @@ in { options.hardware.infiniband = { - enable = mkEnableOption "Infiniband support"; - guids = mkOption { - type = with types; listOf str; + enable = lib.mkEnableOption "Infiniband support"; + guids = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "0xe8ebd30000eee2e1" ]; description = '' @@ -42,7 +39,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.initrd.kernelModules = [ "mlx5_core" "mlx5_ib" "ib_cm" "rdma_cm" "rdma_ucm" "rpcrdma" diff --git a/nixos/modules/hardware/ksm.nix b/nixos/modules/hardware/ksm.nix index e0b5949ffb21..41d61e04697c 100644 --- a/nixos/modules/hardware/ksm.nix +++ b/nixos/modules/hardware/ksm.nix @@ -1,19 +1,16 @@ { config, lib, ... }: - -with lib; - let cfg = config.hardware.ksm; in { imports = [ - (mkRenamedOptionModule [ "hardware" "enableKSM" ] [ "hardware" "ksm" "enable" ]) + (lib.mkRenamedOptionModule [ "hardware" "enableKSM" ] [ "hardware" "ksm" "enable" ]) ]; options.hardware.ksm = { - enable = mkEnableOption "Linux kernel Same-Page Merging"; - sleep = mkOption { - type = types.nullOr types.int; + enable = lib.mkEnableOption "Linux kernel Same-Page Merging"; + sleep = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' How many milliseconds ksmd should sleep between scans. @@ -22,14 +19,14 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.enable-ksm = { description = "Enable Kernel Same-Page Merging"; wantedBy = [ "multi-user.target" ]; script = '' echo 1 > /sys/kernel/mm/ksm/run - '' + optionalString (cfg.sleep != null) + '' + lib.optionalString (cfg.sleep != null) '' echo ${toString cfg.sleep} > /sys/kernel/mm/ksm/sleep_millisecs ''; diff --git a/nixos/modules/hardware/ledger.nix b/nixos/modules/hardware/ledger.nix index 41abe74315a0..8510c97c5e38 100644 --- a/nixos/modules/hardware/ledger.nix +++ b/nixos/modules/hardware/ledger.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.ledger; in { - options.hardware.ledger.enable = mkEnableOption "udev rules for Ledger devices"; + options.hardware.ledger.enable = lib.mkEnableOption "udev rules for Ledger devices"; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ pkgs.ledger-udev-rules ]; }; } diff --git a/nixos/modules/hardware/logitech.nix b/nixos/modules/hardware/logitech.nix index 94a1287e051c..aeb97a2f9d94 100644 --- a/nixos/modules/hardware/logitech.nix +++ b/nixos/modules/hardware/logitech.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.logitech; @@ -12,25 +9,25 @@ let in { imports = [ - (mkRenamedOptionModule [ "hardware" "logitech" "enable" ] [ "hardware" "logitech" "wireless" "enable" ]) - (mkRenamedOptionModule [ "hardware" "logitech" "enableGraphical" ] [ "hardware" "logitech" "wireless" "enableGraphical" ]) + (lib.mkRenamedOptionModule [ "hardware" "logitech" "enable" ] [ "hardware" "logitech" "wireless" "enable" ]) + (lib.mkRenamedOptionModule [ "hardware" "logitech" "enableGraphical" ] [ "hardware" "logitech" "wireless" "enableGraphical" ]) ]; options.hardware.logitech = { lcd = { - enable = mkEnableOption "support for Logitech LCD Devices"; + enable = lib.mkEnableOption "support for Logitech LCD Devices"; - startWhenNeeded = mkOption { - type = types.bool; + startWhenNeeded = lib.mkOption { + type = lib.types.bool; default = true; description = '' Only run the service when an actual supported device is plugged. ''; }; - devices = mkOption { - type = types.listOf types.str; + devices = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "0a07" "c222" "c225" "c227" "c251" ]; description = '' List of USB device ids supported by g15daemon. @@ -41,10 +38,10 @@ in }; wireless = { - enable = mkEnableOption "support for Logitech Wireless Devices"; + enable = lib.mkEnableOption "support for Logitech Wireless Devices"; - enableGraphical = mkOption { - type = types.bool; + enableGraphical = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable graphical support applications."; }; diff --git a/nixos/modules/hardware/mcelog.nix b/nixos/modules/hardware/mcelog.nix index 13ad238870c2..38629c4ba945 100644 --- a/nixos/modules/hardware/mcelog.nix +++ b/nixos/modules/hardware/mcelog.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - { - meta.maintainers = with maintainers; [ grahamc ]; + meta.maintainers = with lib.maintainers; [ grahamc ]; options = { hardware.mcelog = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable the Machine Check Exception logger. @@ -18,7 +15,7 @@ with lib; }; - config = mkIf config.hardware.mcelog.enable { + config = lib.mkIf config.hardware.mcelog.enable { systemd = { packages = [ pkgs.mcelog ]; diff --git a/nixos/modules/hardware/network/ath-user-regd.nix b/nixos/modules/hardware/network/ath-user-regd.nix index b5ade5ed5010..4cd3fb69604b 100644 --- a/nixos/modules/hardware/network/ath-user-regd.nix +++ b/nixos/modules/hardware/network/ath-user-regd.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let kernelVersion = config.boot.kernelPackages.kernel.version; linuxKernelMinVersion = "5.8"; @@ -11,9 +9,9 @@ let }; in { - options.networking.wireless.athUserRegulatoryDomain = mkOption { + options.networking.wireless.athUserRegulatoryDomain = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' If enabled, sets the ATH_USER_REGD kernel config switch to true to disable the enforcement of EEPROM regulatory restrictions for ath @@ -21,9 +19,9 @@ in ''; }; - config = mkIf config.networking.wireless.athUserRegulatoryDomain { - assertions = singleton { - assertion = lessThan 0 (builtins.compareVersions kernelVersion linuxKernelMinVersion); + config = lib.mkIf config.networking.wireless.athUserRegulatoryDomain { + assertions = lib.singleton { + assertion = lib.lessThan 0 (builtins.compareVersions kernelVersion linuxKernelMinVersion); message = "ATH_USER_REGD patch for kernels older than ${linuxKernelMinVersion} not ported yet!"; }; boot.kernelPatches = [ kernelPatch ]; diff --git a/nixos/modules/hardware/network/b43.nix b/nixos/modules/hardware/network/b43.nix index eb03bf223ccf..fc4020c09a5d 100644 --- a/nixos/modules/hardware/network/b43.nix +++ b/nixos/modules/hardware/network/b43.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let kernelVersion = config.boot.kernelPackages.kernel.version; in { @@ -10,9 +7,9 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in options = { - networking.enableB43Firmware = mkOption { + networking.enableB43Firmware = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Turn on this option if you want firmware for the NICs supported by the b43 module. ''; @@ -23,7 +20,7 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in ###### implementation - config = mkIf config.networking.enableB43Firmware { + config = lib.mkIf config.networking.enableB43Firmware { hardware.firmware = [ pkgs.b43Firmware_5_1_138 ]; }; diff --git a/nixos/modules/hardware/new-lg4ff.nix b/nixos/modules/hardware/new-lg4ff.nix index 3c7f66f8d89b..ac5d3e77df0b 100644 --- a/nixos/modules/hardware/new-lg4ff.nix +++ b/nixos/modules/hardware/new-lg4ff.nix @@ -1,14 +1,11 @@ { pkgs, lib, config, ... }: - -with lib; - let cfg = config.hardware.new-lg4ff; kernelPackages = config.boot.kernelPackages; in { options.hardware.new-lg4ff = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enables improved Linux module drivers for Logitech driving wheels. diff --git a/nixos/modules/hardware/nitrokey.nix b/nixos/modules/hardware/nitrokey.nix index 9bc8da41a4a7..08d6b16790f7 100644 --- a/nixos/modules/hardware/nitrokey.nix +++ b/nixos/modules/hardware/nitrokey.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.nitrokey; @@ -10,8 +7,8 @@ in { options.hardware.nitrokey = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enables udev rules for Nitrokey devices. By default grants access @@ -21,7 +18,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ pkgs.libnitrokey ]; }; } diff --git a/nixos/modules/hardware/onlykey/default.nix b/nixos/modules/hardware/onlykey/default.nix index 07358c8a8782..9bf167ba5341 100644 --- a/nixos/modules/hardware/onlykey/default.nix +++ b/nixos/modules/hardware/onlykey/default.nix @@ -1,7 +1,4 @@ { config, lib, ... }: - -with lib; - { ####### interface @@ -9,8 +6,8 @@ with lib; options = { hardware.onlykey = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable OnlyKey device (https://crp.to/p/) support. @@ -25,7 +22,7 @@ with lib; ####### implementation - config = mkIf config.hardware.onlykey.enable { + config = lib.mkIf config.hardware.onlykey.enable { services.udev.extraRules = builtins.readFile ./onlykey.udev; }; diff --git a/nixos/modules/hardware/openrazer.nix b/nixos/modules/hardware/openrazer.nix index 6f61254a60c1..c4a60c619f17 100644 --- a/nixos/modules/hardware/openrazer.nix +++ b/nixos/modules/hardware/openrazer.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.hardware.openrazer; kernelPackages = config.boot.kernelPackages; @@ -51,20 +48,20 @@ in { options = { hardware.openrazer = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' OpenRazer drivers and userspace daemon ''; - verboseLogging = mkOption { - type = types.bool; + verboseLogging = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable verbose logging. Logs debug messages. ''; }; - syncEffectsEnabled = mkOption { - type = types.bool; + syncEffectsEnabled = lib.mkOption { + type = lib.types.bool; default = true; description = '' Set the sync effects flag to true so any assignment of @@ -72,30 +69,30 @@ in ''; }; - devicesOffOnScreensaver = mkOption { - type = types.bool; + devicesOffOnScreensaver = lib.mkOption { + type = lib.types.bool; default = true; description = '' Turn off the devices when the systems screensaver kicks in. ''; }; - batteryNotifier = mkOption { + batteryNotifier = lib.mkOption { description = '' Settings for device battery notifications. ''; default = {}; - type = types.submodule { + type = lib.types.submodule { options = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Mouse battery notifier. ''; }; - frequency = mkOption { - type = types.int; + frequency = lib.mkOption { + type = lib.types.int; default = 600; description = '' How often battery notifications should be shown (in seconds). @@ -103,8 +100,8 @@ in ''; }; - percentage = mkOption { - type = types.int; + percentage = lib.mkOption { + type = lib.types.int; default = 33; description = '' At what battery percentage the device should reach before @@ -115,8 +112,8 @@ in }; }; - keyStatistics = mkOption { - type = types.bool; + keyStatistics = lib.mkOption { + type = lib.types.bool; default = false; description = '' Collects number of keypresses per hour per key used to @@ -124,8 +121,8 @@ in ''; }; - users = mkOption { - type = with types; listOf str; + users = lib.mkOption { + type = with lib.types; listOf str; default = []; description = '' Usernames to be added to the "openrazer" group, so that they @@ -136,10 +133,10 @@ in }; imports = [ - (mkRenamedOptionModule [ "hardware" "openrazer" "mouseBatteryNotifier" ] [ "hardware" "openrazer" "batteryNotifier" "enable" ]) + (lib.mkRenamedOptionModule [ "hardware" "openrazer" "mouseBatteryNotifier" ] [ "hardware" "openrazer" "batteryNotifier" "enable" ]) ]; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.extraModulePackages = [ kernelPackages.openrazer ]; boot.kernelModules = drivers; diff --git a/nixos/modules/hardware/opentabletdriver.nix b/nixos/modules/hardware/opentabletdriver.nix index d8958ed4f68d..993d51d87986 100644 --- a/nixos/modules/hardware/opentabletdriver.nix +++ b/nixos/modules/hardware/opentabletdriver.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.hardware.opentabletdriver; in @@ -9,29 +7,29 @@ in options = { hardware.opentabletdriver = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable OpenTabletDriver udev rules, user service and blacklist kernel modules known to conflict with OpenTabletDriver. ''; }; - blacklistedKernelModules = mkOption { - type = types.listOf types.str; + blacklistedKernelModules = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "hid-uclogic" "wacom" ]; description = '' Blacklist of kernel modules known to conflict with OpenTabletDriver. ''; }; - package = mkPackageOption pkgs "opentabletdriver" { }; + package = lib.mkPackageOption pkgs "opentabletdriver" { }; daemon = { - enable = mkOption { + enable = lib.mkOption { default = true; - type = types.bool; + type = lib.types.bool; description = '' Whether to start OpenTabletDriver daemon as a systemd user service. ''; @@ -40,14 +38,14 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; services.udev.packages = [ cfg.package ]; boot.blacklistedKernelModules = cfg.blacklistedKernelModules; - systemd.user.services.opentabletdriver = with pkgs; mkIf cfg.daemon.enable { + systemd.user.services.opentabletdriver = with pkgs; lib.mkIf cfg.daemon.enable { description = "Open source, cross-platform, user-mode tablet driver"; wantedBy = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ]; diff --git a/nixos/modules/hardware/pcmcia.nix b/nixos/modules/hardware/pcmcia.nix index aef35a28e54d..557925018d68 100644 --- a/nixos/modules/hardware/pcmcia.nix +++ b/nixos/modules/hardware/pcmcia.nix @@ -1,53 +1,45 @@ { config, lib, pkgs, ... }: - -with lib; - let - pcmciaUtils = pkgs.pcmciaUtils.passthru.function { inherit (config.hardware.pcmcia) firmware config; }; - in - { ###### interface - options = { hardware.pcmcia = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable this option to support PCMCIA card. ''; }; - firmware = mkOption { - type = types.listOf types.path; + firmware = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' List of firmware used to handle specific PCMCIA card. ''; }; - config = mkOption { + config = lib.mkOption { default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; description = '' Path to the configuration file which maps the memory, IRQs and ports used by the PCMCIA hardware. ''; }; }; - }; ###### implementation - config = mkIf config.hardware.pcmcia.enable { + config = lib.mkIf config.hardware.pcmcia.enable { boot.kernelModules = [ "pcmcia" ]; diff --git a/nixos/modules/hardware/printers.nix b/nixos/modules/hardware/printers.nix index ace900d88586..a40822df11f5 100644 --- a/nixos/modules/hardware/printers.nix +++ b/nixos/modules/hardware/printers.nix @@ -1,19 +1,18 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.hardware.printers; ensurePrinter = p: let - args = cli.toGNUCommandLineShell {} ({ + args = lib.cli.toGNUCommandLineShell {} ({ p = p.name; v = p.deviceUri; m = p.model; - } // optionalAttrs (p.location != null) { + } // lib.optionalAttrs (p.location != null) { L = p.location; - } // optionalAttrs (p.description != null) { + } // lib.optionalAttrs (p.description != null) { D = p.description; - } // optionalAttrs (p.ppdOptions != {}) { - o = mapAttrsToList (name: value: "${name}=${value}") p.ppdOptions; + } // lib.optionalAttrs (p.ppdOptions != {}) { + o = lib.mapAttrsToList (name: value: "${name}=${value}") p.ppdOptions; }); in '' ${pkgs.cups}/bin/lpadmin ${args} -E @@ -24,22 +23,22 @@ let ''; # "graph but not # or /" can't be implemented as regex alone due to missing lookahead support - noInvalidChars = str: all (c: c != "#" && c != "/") (stringToCharacters str); - printerName = (types.addCheck (types.strMatching "[[:graph:]]+") noInvalidChars) + noInvalidChars = str: lib.all (c: c != "#" && c != "/") (lib.stringToCharacters str); + printerName = (lib.types.addCheck (lib.types.strMatching "[[:graph:]]+") noInvalidChars) // { description = "printable string without spaces, # and /"; }; in { options = { hardware.printers = { - ensureDefaultPrinter = mkOption { - type = types.nullOr printerName; + ensureDefaultPrinter = lib.mkOption { + type = lib.types.nullOr printerName; default = null; description = '' Ensures the named printer is the default CUPS printer / printer queue. ''; }; - ensurePrinters = mkOption { + ensurePrinters = lib.mkOption { description = '' Will regularly ensure that the given CUPS printers are configured as declared here. If a printer's options are manually changed afterwards, they will be overwritten eventually. @@ -49,9 +48,9 @@ in { Printers not listed here can still be manually configured. ''; default = []; - type = types.listOf (types.submodule { + type = lib.types.listOf (lib.types.submodule { options = { - name = mkOption { + name = lib.mkOption { type = printerName; example = "BrotherHL_Workroom"; description = '' @@ -59,25 +58,25 @@ in { May contain any printable characters except "/", "#", and space. ''; }; - location = mkOption { - type = types.nullOr types.str; + location = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "Workroom"; description = '' Optional human-readable location. ''; }; - description = mkOption { - type = types.nullOr types.str; + description = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "Brother HL-5140"; description = '' Optional human-readable description. ''; }; - deviceUri = mkOption { - type = types.str; - example = literalExpression '' + deviceUri = lib.mkOption { + type = lib.types.str; + example = lib.literalExpression '' "ipp://printserver.local/printers/BrotherHL_Workroom" "usb://HP/DESKJET%20940C?serial=CN16E6C364BH" ''; @@ -86,9 +85,9 @@ in { {command}`lpinfo -v` shows a list of supported device URIs and schemes. ''; }; - model = mkOption { - type = types.str; - example = literalExpression '' + model = lib.mkOption { + type = lib.types.str; + example = lib.literalExpression '' "gutenprint.''${lib.versions.majorMinor (lib.getVersion pkgs.gutenprint)}://brother-hl-5140/expert" ''; description = '' @@ -96,8 +95,8 @@ in { {command}`lpinfo -m` shows a list of supported models. ''; }; - ppdOptions = mkOption { - type = types.attrsOf types.str; + ppdOptions = lib.mkOption { + type = lib.types.attrsOf lib.types.str; example = { PageSize = "A4"; Duplex = "DuplexNoTumble"; @@ -114,7 +113,7 @@ in { }; }; - config = mkIf (cfg.ensurePrinters != [] && config.services.printing.enable) { + config = lib.mkIf (cfg.ensurePrinters != [] && config.services.printing.enable) { systemd.services.ensure-printers = { description = "Ensure NixOS-configured CUPS printers"; wantedBy = [ "multi-user.target" ]; @@ -126,13 +125,13 @@ in { RemainAfterExit = true; }; - script = concatStringsSep "\n" [ - (concatMapStrings ensurePrinter cfg.ensurePrinters) - (optionalString (cfg.ensureDefaultPrinter != null) + script = lib.concatStringsSep "\n" [ + (lib.concatMapStrings ensurePrinter cfg.ensurePrinters) + (lib.optionalString (cfg.ensureDefaultPrinter != null) (ensureDefaultPrinter cfg.ensureDefaultPrinter)) # Note: if cupsd is "stateless" the service can't be stopped, # otherwise the configuration will be wiped on the next start. - (optionalString (with config.services.printing; startWhenNeeded && !stateless) + (lib.optionalString (with config.services.printing; startWhenNeeded && !stateless) "systemctl stop cups.service") ]; }; diff --git a/nixos/modules/hardware/raid/hpsa.nix b/nixos/modules/hardware/raid/hpsa.nix index 873a2db38091..2ec2398760b6 100644 --- a/nixos/modules/hardware/raid/hpsa.nix +++ b/nixos/modules/hardware/raid/hpsa.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let hpssacli = pkgs.stdenv.mkDerivation rec { pname = "hpssacli"; @@ -48,13 +45,13 @@ in { options = { hardware.raid.HPSmartArray = { - enable = mkEnableOption "HP Smart Array kernel modules and CLI utility"; + enable = lib.mkEnableOption "HP Smart Array kernel modules and CLI utility"; }; }; ###### implementation - config = mkIf config.hardware.raid.HPSmartArray.enable { + config = lib.mkIf config.hardware.raid.HPSmartArray.enable { boot.initrd.kernelModules = [ "sg" ]; /* hpssacli wants it */ boot.initrd.availableKernelModules = [ "hpsa" ]; diff --git a/nixos/modules/hardware/sensor/iio.nix b/nixos/modules/hardware/sensor/iio.nix index 8b3ba87a7d9c..fbdc929390f2 100644 --- a/nixos/modules/hardware/sensor/iio.nix +++ b/nixos/modules/hardware/sensor/iio.nix @@ -1,20 +1,17 @@ { config, lib, pkgs, ... }: - -with lib; - { ###### interface options = { hardware.sensor.iio = { - enable = mkOption { + enable = lib.mkOption { description = '' Enable this option to support IIO sensors with iio-sensor-proxy. IIO sensors are used for orientation and ambient light sensors on some mobile devices. ''; - type = types.bool; + type = lib.types.bool; default = false; }; }; @@ -22,7 +19,7 @@ with lib; ###### implementation - config = mkIf config.hardware.sensor.iio.enable { + config = lib.mkIf config.hardware.sensor.iio.enable { boot.initrd.availableKernelModules = [ "hid-sensor-hub" ]; diff --git a/nixos/modules/hardware/steam-hardware.nix b/nixos/modules/hardware/steam-hardware.nix index 6218c9ffbb9b..bd1e6ae8f708 100644 --- a/nixos/modules/hardware/steam-hardware.nix +++ b/nixos/modules/hardware/steam-hardware.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.steam-hardware; @@ -10,16 +7,16 @@ in { options.hardware.steam-hardware = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable udev rules for Steam hardware such as the Steam Controller, other supported controllers and the HTC Vive"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ - pkgs.steamPackages.steam + pkgs.steam-unwrapped ]; # The uinput module needs to be loaded in order to trigger the udev rules diff --git a/nixos/modules/hardware/system-76.nix b/nixos/modules/hardware/system-76.nix index ca40ee0ebb37..d81c59fbc924 100644 --- a/nixos/modules/hardware/system-76.nix +++ b/nixos/modules/hardware/system-76.nix @@ -36,7 +36,7 @@ let }; }; - power-pkg = config.boot.kernelPackages.system76-power; + power-pkg = pkgs.system76-power; powerConfig = mkIf cfg.power-daemon.enable { # Make system76-power usable by root from the command line. environment.systemPackages = [ power-pkg ]; diff --git a/nixos/modules/hardware/tuxedo-keyboard.nix b/nixos/modules/hardware/tuxedo-keyboard.nix index f90dfc6e3134..01ec486fb88f 100644 --- a/nixos/modules/hardware/tuxedo-keyboard.nix +++ b/nixos/modules/hardware/tuxedo-keyboard.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.tuxedo-keyboard; tuxedo-keyboard = config.boot.kernelPackages.tuxedo-keyboard; in { options.hardware.tuxedo-keyboard = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' the tuxedo-keyboard driver. To configure the driver, pass the options to the {option}`boot.kernelParams` configuration. @@ -27,7 +24,7 @@ in ''; }; - config = mkIf cfg.enable + config = lib.mkIf cfg.enable { boot.kernelModules = ["tuxedo_keyboard"]; boot.extraModulePackages = [ tuxedo-keyboard ]; diff --git a/nixos/modules/hardware/ubertooth.nix b/nixos/modules/hardware/ubertooth.nix index f65c2da25522..98cd0a0fb047 100644 --- a/nixos/modules/hardware/ubertooth.nix +++ b/nixos/modules/hardware/ubertooth.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.ubertooth; @@ -10,17 +7,17 @@ let }; in { options.hardware.ubertooth = { - enable = mkEnableOption "Ubertooth software and its udev rules"; + enable = lib.mkEnableOption "Ubertooth software and its udev rules"; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "ubertooth"; example = "wheel"; description = "Group for Ubertooth's udev rules."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ ubertoothPkg ]; services.udev.packages = [ ubertoothPkg ]; diff --git a/nixos/modules/hardware/uinput.nix b/nixos/modules/hardware/uinput.nix index 55e86bfa6bdb..1845d9cfe565 100644 --- a/nixos/modules/hardware/uinput.nix +++ b/nixos/modules/hardware/uinput.nix @@ -1,8 +1,9 @@ -{ config, pkgs, lib, ... }: +{ config, lib, ... }: let cfg = config.hardware.uinput; -in { +in +{ options.hardware.uinput = { enable = lib.mkEnableOption "uinput support"; }; @@ -10,7 +11,7 @@ in { config = lib.mkIf cfg.enable { boot.kernelModules = [ "uinput" ]; - users.groups.uinput = {}; + users.groups.uinput.gid = config.ids.gids.uinput; services.udev.extraRules = '' SUBSYSTEM=="misc", KERNEL=="uinput", MODE="0660", GROUP="uinput", OPTIONS+="static_node=uinput" diff --git a/nixos/modules/hardware/usb-modeswitch.nix b/nixos/modules/hardware/usb-modeswitch.nix index f36d293a867f..cbce5daa840d 100644 --- a/nixos/modules/hardware/usb-modeswitch.nix +++ b/nixos/modules/hardware/usb-modeswitch.nix @@ -1,15 +1,12 @@ { config, lib, pkgs, ... }: - -with lib; - { ###### interface options = { hardware.usb-modeswitch = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable this option to support certain USB WLAN and WWAN adapters. @@ -24,10 +21,10 @@ with lib; ###### implementation imports = [ - (mkRenamedOptionModule ["hardware" "usbWwan" ] ["hardware" "usb-modeswitch" ]) + (lib.mkRenamedOptionModule ["hardware" "usbWwan" ] ["hardware" "usb-modeswitch" ]) ]; - config = mkIf config.hardware.usb-modeswitch.enable { + config = lib.mkIf config.hardware.usb-modeswitch.enable { # Attaches device specific handlers. services.udev.packages = with pkgs; [ usb-modeswitch-data ]; diff --git a/nixos/modules/hardware/usb-storage.nix b/nixos/modules/hardware/usb-storage.nix index 6e20b93d2262..32c1707b2716 100644 --- a/nixos/modules/hardware/usb-storage.nix +++ b/nixos/modules/hardware/usb-storage.nix @@ -1,10 +1,9 @@ { config, lib, pkgs, ... }: -with lib; { - options.hardware.usbStorage.manageStartStop = mkOption { - type = types.bool; - default = true; + options.hardware.usbStorage.manageShutdown = lib.mkOption { + type = lib.types.bool; + default = false; description = '' Enable this option to gracefully spin-down external storage during shutdown. If you suspect improper head parking after poweroff, install `smartmontools` and check @@ -12,9 +11,11 @@ with lib; ''; }; - config = mkIf config.hardware.usbStorage.manageStartStop { + config = lib.mkIf config.hardware.usbStorage.manageShutdown { services.udev.extraRules = '' - ACTION=="add|change", SUBSYSTEM=="scsi_disk", DRIVERS=="usb-storage", ATTR{manage_system_start_stop}="1" + ACTION=="add|change", SUBSYSTEM=="scsi_disk", DRIVERS=="usb-storage|uas", ATTR{manage_shutdown}="1" ''; }; + + imports = [(lib.mkRenamedOptionModule [ "hardware" "usbStorage" "manageStartStop" ] [ "hardware" "usbStorage" "manageShutdown" ])]; } diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix index b6af4f80445a..b5339f0dda53 100644 --- a/nixos/modules/hardware/video/bumblebee.nix +++ b/nixos/modules/hardware/video/bumblebee.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.hardware.bumblebee; @@ -26,9 +24,9 @@ in options = { hardware.bumblebee = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable the bumblebee daemon to manage Optimus hybrid video cards. This should power off secondary GPU until its use is requested @@ -36,16 +34,16 @@ in ''; }; - group = mkOption { + group = lib.mkOption { default = "wheel"; example = "video"; - type = types.str; + type = lib.types.str; description = "Group for bumblebee socket"; }; - connectDisplay = mkOption { + connectDisplay = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Set to true if you intend to connect your discrete card to a monitor. This option will set up your Nvidia card for EDID @@ -55,17 +53,17 @@ in ''; }; - driver = mkOption { + driver = lib.mkOption { default = "nvidia"; - type = types.enum [ "nvidia" "nouveau" ]; + type = lib.types.enum [ "nvidia" "nouveau" ]; description = '' Set driver used by bumblebeed. Supported are nouveau and nvidia. ''; }; - pmMethod = mkOption { + pmMethod = lib.mkOption { default = "auto"; - type = types.enum [ "auto" "bbswitch" "switcheroo" "none" ]; + type = lib.types.enum [ "auto" "bbswitch" "switcheroo" "none" ]; description = '' Set preferred power management method for unused card. ''; @@ -74,10 +72,10 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.blacklistedKernelModules = [ "nvidia-drm" "nvidia" "nouveau" ]; - boot.kernelModules = optional useBbswitch "bbswitch"; - boot.extraModulePackages = optional useBbswitch kernel.bbswitch ++ optional useNvidia kernel.nvidia_x11.bin; + boot.kernelModules = lib.optional useBbswitch "bbswitch"; + boot.extraModulePackages = lib.optional useBbswitch kernel.bbswitch ++ lib.optional useNvidia kernel.nvidia_x11.bin; environment.systemPackages = [ bumblebee primus ]; diff --git a/nixos/modules/hardware/video/capture/mwprocapture.nix b/nixos/modules/hardware/video/capture/mwprocapture.nix index c63535f0faa7..6ec23249f5c9 100644 --- a/nixos/modules/hardware/video/capture/mwprocapture.nix +++ b/nixos/modules/hardware/video/capture/mwprocapture.nix @@ -1,7 +1,4 @@ { config, lib, ... }: - -with lib; - let cfg = config.hardware.mwProCapture; @@ -12,9 +9,9 @@ in { - options.hardware.mwProCapture.enable = mkEnableOption "the Magewell Pro Capture family kernel module"; + options.hardware.mwProCapture.enable = lib.mkEnableOption "the Magewell Pro Capture family kernel module"; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "ProCapture" ]; diff --git a/nixos/modules/hardware/video/displaylink.nix b/nixos/modules/hardware/video/displaylink.nix index ce5fbeeae536..32e5eaf2b978 100644 --- a/nixos/modules/hardware/video/displaylink.nix +++ b/nixos/modules/hardware/video/displaylink.nix @@ -1,10 +1,7 @@ { config, lib, pkgs, ... }: - -with lib; - let - enabled = elem "displaylink" config.services.xserver.videoDrivers; + enabled = lib.elem "displaylink" config.services.xserver.videoDrivers; evdi = config.boot.kernelPackages.evdi; @@ -16,7 +13,7 @@ in { - config = mkIf enabled { + config = lib.mkIf enabled { boot.extraModulePackages = [ evdi ]; boot.kernelModules = [ "evdi" ]; diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index ee8904da8572..3d3165e44913 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -10,13 +10,15 @@ let cfg = config.hardware.nvidia; + useOpenModules = cfg.open == true; + pCfg = cfg.prime; syncCfg = pCfg.sync; offloadCfg = pCfg.offload; reverseSyncCfg = pCfg.reverseSync; primeEnabled = syncCfg.enable || reverseSyncCfg.enable || offloadCfg.enable; busIDType = lib.types.strMatching "([[:print:]]+[\:\@][0-9]{1,3}\:[0-9]{1,2}\:[0-9])?"; - ibtSupport = cfg.open || (nvidia_x11.ibtSupport or false); + ibtSupport = useOpenModules || (nvidia_x11.ibtSupport or false); settingsFormat = pkgs.formats.keyValue { }; in { @@ -254,10 +256,23 @@ in ''; }; - open = lib.mkEnableOption '' - the open source NVIDIA kernel module + open = lib.mkOption { + example = true; + description = "Whether to enable the open source NVIDIA kernel module."; + type = lib.types.nullOr lib.types.bool; + default = if lib.versionOlder nvidia_x11.version "560" then false else null; + defaultText = lib.literalExpression '' + if lib.versionOlder config.hardware.nvidia.package.version "560" then false else null + ''; + }; + + gsp.enable = lib.mkEnableOption '' + the GPU System Processor (GSP) on the video card '' // { - defaultText = lib.literalExpression ''lib.versionAtLeast config.hardware.nvidia.package.version "560"''; + default = useOpenModules || lib.versionAtLeast nvidia_x11.version "555"; + defaultText = lib.literalExpression '' + config.hardware.nvidia.open == true || lib.versionAtLeast config.hardware.nvidia.package.version "555" + ''; }; }; }; @@ -276,6 +291,13 @@ in assertion = !(nvidiaEnabled && cfg.datacenter.enable); message = "You cannot configure both X11 and Data Center drivers at the same time."; } + { + assertion = cfg.open != null; + message = '' + You must configure `hardware.nvidia.open` on NVIDIA driver versions >= 560. + It is suggested to use the open source kernel modules on Turing or later GPUs (RTX series, GTX 16xx), and the closed source modules otherwise. + ''; + } ]; boot = { blacklistedKernelModules = [ @@ -307,8 +329,6 @@ in extraPackages32 = [ nvidia_x11.lib32 ]; }; environment.systemPackages = [ nvidia_x11.bin ]; - - hardware.nvidia.open = lib.mkDefault (lib.versionAtLeast nvidia_x11.version "560"); }) # X11 @@ -367,8 +387,18 @@ in } { - assertion = cfg.open -> (cfg.package ? open && cfg.package ? firmware); - message = "This version of NVIDIA driver does not provide a corresponding opensource kernel driver"; + assertion = cfg.gsp.enable -> (cfg.package ? firmware); + message = "This version of NVIDIA driver does not provide a GSP firmware."; + } + + { + assertion = useOpenModules -> (cfg.package ? open); + message = "This version of NVIDIA driver does not provide a corresponding opensource kernel driver."; + } + + { + assertion = useOpenModules -> cfg.gsp.enable; + message = "The GSP cannot be disabled when using the opensource kernel driver."; } { @@ -555,7 +585,7 @@ in services.dbus.packages = lib.optional cfg.dynamicBoost.enable nvidia_x11.bin; - hardware.firmware = lib.optional (cfg.open || lib.versionAtLeast nvidia_x11.version "555") nvidia_x11.firmware; + hardware.firmware = lib.optional cfg.gsp.enable nvidia_x11.firmware; systemd.tmpfiles.rules = [ @@ -570,7 +600,7 @@ in "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; boot = { - extraModulePackages = if cfg.open then [ nvidia_x11.open ] else [ nvidia_x11.bin ]; + extraModulePackages = if useOpenModules then [ nvidia_x11.open ] else [ nvidia_x11.bin ]; # nvidia-uvm is required by CUDA applications. kernelModules = lib.optionals config.services.xserver.enable [ @@ -581,14 +611,14 @@ in # With the open driver, nvidia-uvm does not automatically load as # a softdep of the nvidia module, so we explicitly load it for now. # See https://github.com/NixOS/nixpkgs/issues/334180 - ++ lib.optionals (config.services.xserver.enable && cfg.open) [ "nvidia_uvm" ]; + ++ lib.optionals (config.services.xserver.enable && useOpenModules) [ "nvidia_uvm" ]; # If requested enable modesetting via kernel parameters. kernelParams = lib.optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" ++ lib.optional ((offloadCfg.enable || cfg.modesetting.enable) && lib.versionAtLeast nvidia_x11.version "545") "nvidia-drm.fbdev=1" ++ lib.optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1" - ++ lib.optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1" + ++ lib.optional useOpenModules "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1" ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2" && !ibtSupport) "ibt=off"; # enable finegrained power management diff --git a/nixos/modules/hardware/video/uvcvideo/default.nix b/nixos/modules/hardware/video/uvcvideo/default.nix index 901ff938d90e..8b9f1244e5b5 100644 --- a/nixos/modules/hardware/video/uvcvideo/default.nix +++ b/nixos/modules/hardware/video/uvcvideo/default.nix @@ -1,8 +1,4 @@ - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.uvcvideo; @@ -19,8 +15,8 @@ in options = { services.uvcvideo.dynctrl = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable {command}`uvcvideo` dynamic controls. @@ -31,9 +27,9 @@ in ''; }; - packages = mkOption { - type = types.listOf types.path; - example = literalExpression "[ pkgs.tiscamera ]"; + packages = lib.mkOption { + type = lib.types.listOf lib.types.path; + example = lib.literalExpression "[ pkgs.tiscamera ]"; description = '' List of packages containing {command}`uvcvideo` dynamic controls rules. All files found in @@ -45,12 +41,12 @@ in the dynamic controls from specified packages to the {command}`uvcvideo` driver. ''; - apply = map getBin; + apply = map lib.getBin; }; }; }; - config = mkIf cfg.dynctrl.enable { + config = lib.mkIf cfg.dynctrl.enable { services.udev.packages = [ (uvcdynctrl-udev-rules cfg.dynctrl.packages) diff --git a/nixos/modules/hardware/video/webcam/facetimehd.nix b/nixos/modules/hardware/video/webcam/facetimehd.nix index 1e6e6442c372..06391ea5425e 100644 --- a/nixos/modules/hardware/video/webcam/facetimehd.nix +++ b/nixos/modules/hardware/video/webcam/facetimehd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.facetimehd; @@ -12,12 +9,12 @@ in { - options.hardware.facetimehd.enable = mkEnableOption "the facetimehd kernel module"; + options.hardware.facetimehd.enable = lib.mkEnableOption "the facetimehd kernel module"; - options.hardware.facetimehd.withCalibration = mkOption { + options.hardware.facetimehd.withCalibration = lib.mkOption { default = false; example = true; - type = types.bool; + type = lib.types.bool; description = '' Whether to include sensor calibration files for facetimehd. This makes colors look much better but is experimental, see @@ -26,7 +23,7 @@ in ''; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "facetimehd" ]; @@ -35,7 +32,7 @@ in boot.extraModulePackages = [ kernelPackages.facetimehd ]; hardware.firmware = [ pkgs.facetimehd-firmware ] - ++ optional cfg.withCalibration pkgs.facetimehd-calibration; + ++ lib.optional cfg.withCalibration pkgs.facetimehd-calibration; # unload module during suspend/hibernate as it crashes the whole system powerManagement.powerDownCommands = '' diff --git a/nixos/modules/hardware/video/webcam/ipu6.nix b/nixos/modules/hardware/video/webcam/ipu6.nix index ae54e24ee2da..803902530dd9 100644 --- a/nixos/modules/hardware/video/webcam/ipu6.nix +++ b/nixos/modules/hardware/video/webcam/ipu6.nix @@ -26,9 +26,9 @@ in config = mkIf cfg.enable { - # Module is upstream as of 6.10 - boot.extraModulePackages = with config.boot.kernelPackages; - optional (kernelOlder "6.10") ipu6-drivers; + # Module is upstream as of 6.10, + # but still needs various out-of-tree i2c and the `intel-ipu6-psys` kernel driver + boot.extraModulePackages = with config.boot.kernelPackages; [ ipu6-drivers ]; hardware.firmware = with pkgs; [ ipu6-camera-bins diff --git a/nixos/modules/hardware/wooting.nix b/nixos/modules/hardware/wooting.nix index 56ef77d31ef2..101bd2d32010 100644 --- a/nixos/modules/hardware/wooting.nix +++ b/nixos/modules/hardware/wooting.nix @@ -1,11 +1,9 @@ { config, lib, pkgs, ... }: - -with lib; { - options.hardware.wooting.enable = mkEnableOption ''support for Wooting keyboards. + options.hardware.wooting.enable = lib.mkEnableOption ''support for Wooting keyboards. Note that users must be in the "input" group for udev rules to apply''; - config = mkIf config.hardware.wooting.enable { + config = lib.mkIf config.hardware.wooting.enable { environment.systemPackages = [ pkgs.wootility ]; services.udev.packages = [ pkgs.wooting-udev-rules ]; }; diff --git a/nixos/modules/hardware/xone.nix b/nixos/modules/hardware/xone.nix index bb3b42399d8e..4a8e692001e4 100644 --- a/nixos/modules/hardware/xone.nix +++ b/nixos/modules/hardware/xone.nix @@ -1,15 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.hardware.xone; in { options.hardware.xone = { - enable = mkEnableOption "the xone driver for Xbox One and Xbox Series X|S accessories"; + enable = lib.mkEnableOption "the xone driver for Xbox One and Xbox Series X|S accessories"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot = { blacklistedKernelModules = [ "xpad" "mt76x2u" ]; extraModulePackages = with config.boot.kernelPackages; [ xone ]; @@ -18,6 +16,6 @@ in }; meta = { - maintainers = with maintainers; [ rhysmdnz ]; + maintainers = with lib.maintainers; [ rhysmdnz ]; }; } diff --git a/nixos/modules/hardware/xpadneo.nix b/nixos/modules/hardware/xpadneo.nix index 474f0f7fcf64..d42164060e83 100644 --- a/nixos/modules/hardware/xpadneo.nix +++ b/nixos/modules/hardware/xpadneo.nix @@ -1,20 +1,18 @@ { config, lib, ... }: - -with lib; let cfg = config.hardware.xpadneo; in { options.hardware.xpadneo = { - enable = mkEnableOption "the xpadneo driver for Xbox One wireless controllers"; + enable = lib.mkEnableOption "the xpadneo driver for Xbox One wireless controllers"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot = { # Must disable Enhanced Retransmission Mode to support bluetooth pairing # https://wiki.archlinux.org/index.php/Gamepad#Connect_Xbox_Wireless_Controller_with_Bluetooth extraModprobeConfig = - mkIf + lib.mkIf (config.hardware.bluetooth.enable && (lib.versionOlder config.boot.kernelPackages.kernel.version "5.12")) "options bluetooth disable_ertm=1"; @@ -25,6 +23,6 @@ in }; meta = { - maintainers = with maintainers; [ kira-bruneau ]; + maintainers = with lib.maintainers; [ kira-bruneau ]; }; } diff --git a/nixos/modules/i18n/input-method/default.nix b/nixos/modules/i18n/input-method/default.nix index 15125ceb4a2d..a706b045e377 100644 --- a/nixos/modules/i18n/input-method/default.nix +++ b/nixos/modules/i18n/input-method/default.nix @@ -1,10 +1,8 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.i18n.inputMethod; - allowedTypes = types.enum [ "ibus" "fcitx5" "nabi" "uim" "hime" "kime" ]; + allowedTypes = lib.types.enum [ "ibus" "fcitx5" "nabi" "uim" "hime" "kime" ]; gtk2_cache = pkgs.runCommand "gtk2-immodule.cache" { preferLocalBuild = true; @@ -30,22 +28,22 @@ in { options.i18n = { inputMethod = { - enable = mkEnableOption "an additional input method type" // { + enable = lib.mkEnableOption "an additional input method type" // { default = cfg.enabled != null; - defaultText = literalMD "`true` if the deprecated option `enabled` is set, false otherwise"; + defaultText = lib.literalMD "`true` if the deprecated option `enabled` is set, false otherwise"; }; - enabled = mkOption { - type = types.nullOr allowedTypes; + enabled = lib.mkOption { + type = lib.types.nullOr allowedTypes; default = null; example = "fcitx5"; description = "Deprecated - use `type` and `enable = true` instead"; }; - type = mkOption { - type = types.nullOr allowedTypes; + type = lib.mkOption { + type = lib.types.nullOr allowedTypes; default = cfg.enabled; - defaultText = literalMD "The value of the deprecated option `enabled`, defaulting to null"; + defaultText = lib.literalMD "The value of the deprecated option `enabled`, defaulting to null"; example = "fcitx5"; description = '' Select the enabled input method. Input methods is a software to input symbols that are not available on standard input devices. @@ -63,9 +61,9 @@ in ''; }; - package = mkOption { + package = lib.mkOption { internal = true; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; description = '' The input method method package. @@ -74,8 +72,8 @@ in }; }; - config = mkIf cfg.enable { - warnings = optional (cfg.enabled != null) "i18n.inputMethod.enabled will be removed in a future release. Please use .type, and .enable = true instead"; + config = lib.mkIf cfg.enable { + warnings = lib.optional (cfg.enabled != null) "i18n.inputMethod.enabled will be removed in a future release. Please use .type, and .enable = true instead"; environment.systemPackages = [ cfg.package gtk2_cache gtk3_cache ]; }; diff --git a/nixos/modules/i18n/input-method/fcitx5.nix b/nixos/modules/i18n/input-method/fcitx5.nix index 2678c4a39e4e..cba0da6d815f 100644 --- a/nixos/modules/i18n/input-method/fcitx5.nix +++ b/nixos/modules/i18n/input-method/fcitx5.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let imcfg = config.i18n.inputMethod; cfg = imcfg.fcitx5; @@ -14,35 +11,35 @@ in { options = { i18n.inputMethod.fcitx5 = { - addons = mkOption { - type = with types; listOf package; + addons = lib.mkOption { + type = with lib.types; listOf package; default = [ ]; - example = literalExpression "with pkgs; [ fcitx5-rime ]"; + example = lib.literalExpression "with pkgs; [ fcitx5-rime ]"; description = '' Enabled Fcitx5 addons. ''; }; - waylandFrontend = mkOption { - type = types.bool; + waylandFrontend = lib.mkOption { + type = lib.types.bool; default = false; description = '' Use the Wayland input method frontend. See [Using Fcitx 5 on Wayland](https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland). ''; }; - plasma6Support = mkOption { - type = types.bool; + plasma6Support = lib.mkOption { + type = lib.types.bool; default = config.services.desktopManager.plasma6.enable; - defaultText = literalExpression "config.services.desktopManager.plasma6.enable"; + defaultText = lib.literalExpression "config.services.desktopManager.plasma6.enable"; description = '' Use qt6 versions of fcitx5 packages. Required for configuring fcitx5 in KDE System Settings. ''; }; - quickPhrase = mkOption { - type = with types; attrsOf str; + quickPhrase = lib.mkOption { + type = with lib.types; attrsOf str; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { smile = "(・∀・)"; angry = "( ̄ー ̄)"; @@ -50,10 +47,10 @@ in ''; description = "Quick phrases."; }; - quickPhraseFiles = mkOption { - type = with types; attrsOf path; + quickPhraseFiles = lib.mkOption { + type = with lib.types; attrsOf path; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { words = ./words.mb; numbers = ./numbers.mb; @@ -87,7 +84,7 @@ in The addon configures in `conf` folder in ini format with global sections. Each item is written to the corresponding file. ''; - example = literalExpression "{ pinyin.globalSection.EmojiEnabled = \"True\"; }"; + example = lib.literalExpression "{ pinyin.globalSection.EmojiEnabled = \"True\"; }"; }; }; ignoreUserConfig = lib.mkOption { @@ -103,12 +100,12 @@ in }; imports = [ - (mkRemovedOptionModule [ "i18n" "inputMethod" "fcitx5" "enableRimeData" ] '' + (lib.mkRemovedOptionModule [ "i18n" "inputMethod" "fcitx5" "enableRimeData" ] '' RIME data is now included in `fcitx5-rime` by default, and can be customized using `fcitx5-rime.override { rimeDataPkgs = ...; }` '') ]; - config = mkIf (imcfg.enable && imcfg.type == "fcitx5") { + config = lib.mkIf (imcfg.enable && imcfg.type == "fcitx5") { i18n.inputMethod.package = fcitx5Package; i18n.inputMethod.fcitx5.addons = lib.optionals (cfg.quickPhrase != { }) [ diff --git a/nixos/modules/image/assert_uki_repart_match.py b/nixos/modules/image/assert_uki_repart_match.py new file mode 100644 index 000000000000..e0f266cf15bf --- /dev/null +++ b/nixos/modules/image/assert_uki_repart_match.py @@ -0,0 +1,78 @@ +import json +import sys + +store_verity_type = "@NIX_STORE_VERITY@" # replaced at import by Nix + + +def extract_uki_cmdline_params(ukify_json: dict) -> dict[str, str]: + """ + Return a dict of the parameters in the .cmdline section of the UKI + Exits early if "usrhash" is not included. + """ + cmdline = ukify_json.get(".cmdline", {}).get("text") + if cmdline is None: + print("Failed to get cmdline from ukify output") + + params = {} + for param in cmdline.split(): + key, val = param.partition("=")[::2] + params[key] = val + + if "usrhash" not in params: + print( + f"UKI cmdline does not contain a usrhash:\n{cmdline}" + ) + exit(1) + + return params + + +def hashes_match(partition: dict[str, str], expected: str) -> bool: + """ + Checks if the value of the "roothash" key in the passed partition object matches `expected`. + """ + if partition.get("roothash") != expected: + pretty_part = json.dumps(partition, indent=2) + print( + f"hash mismatch, expected to find roothash {expected} in:\n{pretty_part}" + ) + return False + else: + return True + + +def check_partitions( + partitions: list[dict], uki_params: dict[str, str] +) -> bool: + """ + Checks if the usrhash from `uki_params` has a matching roothash + for the corresponding partition in `partitions`. + """ + for part in partitions: + if part.get("type") == store_verity_type: + expected = uki_params["usrhash"] + return hashes_match(part, expected) + + return False + + +def main() -> None: + ukify_json = json.load(sys.stdin) + repart_json_output = sys.argv[1] + + with open(repart_json_output, "r") as r: + repart_json = json.load(r) + + uki_params = extract_uki_cmdline_params(ukify_json) + + if check_partitions(repart_json, uki_params): + print("UKI and repart verity hashes match") + else: + print("Compatibility check for UKI and image failed!") + print(f"UKI cmdline parameters:\n{uki_params}") + print(f"repart config: {repart_json_output}") + exit(1) + + +if __name__ == "__main__": + main() diff --git a/nixos/modules/image/repart-image.nix b/nixos/modules/image/repart-image.nix index 41f68a0282ac..cc4c2211e3d3 100644 --- a/nixos/modules/image/repart-image.nix +++ b/nixos/modules/image/repart-image.nix @@ -30,7 +30,7 @@ , imageFileBasename , compression , fileSystems -, partitionsJSON +, finalPartitions , split , seed , definitionsDirectory @@ -110,7 +110,9 @@ in env = mkfsEnv; - inherit partitionsJSON definitionsDirectory; + inherit finalPartitions definitionsDirectory; + + partitionsJSON = builtins.toJSON finalAttrs.finalPartitions; # relative path to the repart definitions that are read by systemd-repart finalRepartDefinitions = "repart.d"; @@ -136,7 +138,7 @@ in patchPhase = '' runHook prePatch - amendedRepartDefinitionsDir=$(${amendRepartDefinitions} $partitionsJSON $definitionsDirectory) + amendedRepartDefinitionsDir=$(${amendRepartDefinitions} <(echo "$partitionsJSON") $definitionsDirectory) ln -vs $amendedRepartDefinitionsDir $finalRepartDefinitions runHook postPatch diff --git a/nixos/modules/image/repart-verity-store.nix b/nixos/modules/image/repart-verity-store.nix new file mode 100644 index 000000000000..e8706a5f79d0 --- /dev/null +++ b/nixos/modules/image/repart-verity-store.nix @@ -0,0 +1,226 @@ +# opinionated module that can be used to build nixos images with +# a dm-verity protected nix store +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.image.repart.verityStore; + + verityMatchKey = "store"; + + # TODO: make these and other arch mappings available from systemd-lib for example + partitionTypes = { + usr = + { + "x86_64" = "usr-x86-64"; + "arm64" = "usr-arm64"; + } + ."${pkgs.stdenv.hostPlatform.linuxArch}"; + + usr-verity = + { + "x86_64" = "usr-x86-64-verity"; + "arm64" = "usr-arm64-verity"; + } + ."${pkgs.stdenv.hostPlatform.linuxArch}"; + }; + + verityHashCheck = + pkgs.buildPackages.writers.writePython3Bin "assert_uki_repart_match.py" + { + flakeIgnore = [ "E501" ]; # ignores PEP8's line length limit of 79 (black defaults to 88 characters) + } + ( + builtins.replaceStrings [ "@NIX_STORE_VERITY@" ] [ + partitionTypes.usr-verity + ] (builtins.readFile ./assert_uki_repart_match.py) + ); +in +{ + options.image.repart.verityStore = { + enable = lib.mkEnableOption "building images with a dm-verity protected nix store"; + + ukiPath = lib.mkOption { + type = lib.types.str; + default = "/EFI/Linux/${config.system.boot.loader.ukiFile}"; + defaultText = "/EFI/Linux/\${config.system.boot.loader.ukiFile}"; + description = '' + Specify the location on the ESP where the UKI is placed. + ''; + }; + + partitionIds = { + esp = lib.mkOption { + type = lib.types.str; + default = "00-esp"; + description = '' + Specify the attribute name of the ESP. + ''; + }; + store-verity = lib.mkOption { + type = lib.types.str; + default = "10-store-verity"; + description = '' + Specify the attribute name of the store's dm-verity hash partition. + ''; + }; + store = lib.mkOption { + type = lib.types.str; + default = "20-store"; + description = '' + Specify the attribute name of the store partition. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + boot.initrd.systemd.dmVerity.enable = true; + + image.repart.partitions = { + # dm-verity hash partition + ${cfg.partitionIds.store-verity}.repartConfig = { + Type = partitionTypes.usr-verity; + Verity = "hash"; + VerityMatchKey = lib.mkDefault verityMatchKey; + Label = lib.mkDefault "store-verity"; + }; + # dm-verity data partition that contains the nix store + ${cfg.partitionIds.store} = { + storePaths = [ config.system.build.toplevel ]; + repartConfig = { + Type = partitionTypes.usr; + Verity = "data"; + Format = lib.mkDefault "erofs"; + VerityMatchKey = lib.mkDefault verityMatchKey; + Label = lib.mkDefault "store"; + }; + }; + + }; + + system.build = { + + # intermediate system image without ESP + intermediateImage = + (config.system.build.image.override { + # always disable compression for the intermediate image + compression.enable = false; + }).overrideAttrs + ( + _: previousAttrs: { + # make it easier to identify the intermediate image in build logs + pname = "${previousAttrs.pname}-intermediate"; + + # do not prepare the ESP, this is done in the final image + systemdRepartFlags = previousAttrs.systemdRepartFlags ++ [ "--defer-partitions=esp" ]; + + # the image will be self-contained so we can drop references + # to the closure that was used to build it + unsafeDiscardReferences.out = true; + } + ); + + # UKI with embedded usrhash from intermediateImage + uki = + let + inherit (config.system.boot.loader) ukiFile; + cmdline = "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}"; + in + # override the default UKI + lib.mkOverride 99 ( + pkgs.runCommand ukiFile + { + nativeBuildInputs = [ + pkgs.jq + pkgs.systemdUkify + ]; + } + '' + mkdir -p $out + + # Extract the usrhash from the output of the systemd-repart invocation for the intermediate image. + usrhash=$(jq -r \ + '.[] | select(.type=="${partitionTypes.usr-verity}") | .roothash' \ + ${config.system.build.intermediateImage}/repart-output.json + ) + + # Build UKI with the embedded usrhash. + ukify build \ + --config=${config.boot.uki.configFile} \ + --cmdline="${cmdline} usrhash=$usrhash" \ + --output="$out/${ukiFile}" + '' + ); + + # final system image that is created from the intermediate image by injecting the UKI from above + finalImage = + (config.system.build.image.override { + # continue building with existing intermediate image + createEmpty = false; + }).overrideAttrs + ( + finalAttrs: previousAttrs: { + # add entry to inject UKI into ESP + finalPartitions = lib.recursiveUpdate previousAttrs.finalPartitions { + ${cfg.partitionIds.esp}.contents = { + "${cfg.ukiPath}".source = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; + }; + }; + + nativeBuildInputs = previousAttrs.nativeBuildInputs ++ [ + pkgs.systemdUkify + verityHashCheck + pkgs.jq + ]; + + preBuild = '' + # check that we build the final image with the same intermediate image for + # which the injected UKI was built by comparing the UKI cmdline with the repart output + # of the intermediate image + # + # This is necessary to notice incompatible substitutions of + # non-reproducible store paths, for example when working with distributed + # builds, or when offline-signing the UKI. + ukify --json=short inspect ${config.system.build.uki}/${config.system.boot.loader.ukiFile} \ + | assert_uki_repart_match.py "${config.system.build.intermediateImage}/repart-output.json" + + # copy the uncompressed intermediate image, so that systemd-repart picks it up + cp -v ${config.system.build.intermediateImage}/${config.image.repart.imageFileBasename}.raw . + chmod +w ${config.image.repart.imageFileBasename}.raw + ''; + + # replace "TBD" with the original roothash values + preInstall = '' + mv -v repart-output{.json,_orig.json} + + jq --slurp --indent -1 \ + '.[0] as $intermediate | .[1] as $final + | $intermediate | map(select(.roothash != null) | { "uuid":.uuid,"roothash":.roothash }) as $uuids + | $final + $uuids + | group_by(.uuid) + | map(add) + | sort_by(.offset)' \ + ${config.system.build.intermediateImage}/repart-output.json \ + repart-output_orig.json \ + > repart-output.json + + rm -v repart-output_orig.json + ''; + + # the image will be self-contained so we can drop references + # to the closure that was used to build it + unsafeDiscardReferences.out = true; + } + ); + }; + }; + + meta.maintainers = with lib.maintainers; [ + nikstur + willibutz + ]; +} diff --git a/nixos/modules/image/repart.nix b/nixos/modules/image/repart.nix index e471f9485cd0..544779cd6e9b 100644 --- a/nixos/modules/image/repart.nix +++ b/nixos/modules/image/repart.nix @@ -69,6 +69,10 @@ let }) opts; in { + imports = [ + ./repart-verity-store.nix + ]; + options.image.repart = { name = lib.mkOption { @@ -314,14 +318,12 @@ in format (lib.mapAttrs (_n: v: { Partition = v.repartConfig; }) cfg.finalPartitions); - partitionsJSON = pkgs.writeText "partitions.json" (builtins.toJSON cfg.finalPartitions); - mkfsEnv = mkfsOptionsToEnv cfg.mkfsOptions; in pkgs.callPackage ./repart-image.nix { systemd = cfg.package; - inherit (cfg) name version imageFileBasename compression split seed sectorSize; - inherit fileSystems definitionsDirectory partitionsJSON mkfsEnv; + inherit (cfg) name version imageFileBasename compression split seed sectorSize finalPartitions; + inherit fileSystems definitionsDirectory mkfsEnv; }; meta.maintainers = with lib.maintainers; [ nikstur willibutz ]; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index 3f92b779d60a..d36c90c6254e 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -1,10 +1,6 @@ # This module contains the basic configuration for building a NixOS # installation CD. - { config, lib, options, pkgs, ... }: - -with lib; - { imports = [ ./iso-image.nix @@ -32,8 +28,8 @@ with lib; # An installation media cannot tolerate a host config defined file # system layout on a fresh machine, before it has been formatted. - swapDevices = mkImageMediaOverride [ ]; - fileSystems = mkImageMediaOverride config.lib.isoFileSystems; + swapDevices = lib.mkImageMediaOverride [ ]; + fileSystems = lib.mkImageMediaOverride config.lib.isoFileSystems; boot.postBootCommands = '' for o in $( $out/EFI/boot/grub.cfg + cat < $out/EFI/BOOT/grub.cfg - set textmode=${boolToString (config.isoImage.forceTextMode)} + set textmode=${lib.boolToString (config.isoImage.forceTextMode)} set timeout=${toString grubEfiTimeout} clear @@ -335,12 +331,12 @@ let ${grubMenuCfg} hiddenentry 'Text mode' --hotkey 't' { - loadfont (\$root)/EFI/boot/unicode.pf2 + loadfont (\$root)/EFI/BOOT/unicode.pf2 set textmode=true terminal_output console } hiddenentry 'GUI mode' --hotkey 'g' { - $(find ${config.isoImage.grubTheme} -iname '*.pf2' -printf "loadfont (\$root)/EFI/boot/grub-theme/%P\n") + $(find ${config.isoImage.grubTheme} -iname '*.pf2' -printf "loadfont (\$root)/EFI/BOOT/grub-theme/%P\n") set textmode=false terminal_output gfxterm } @@ -415,7 +411,7 @@ let # Force root to be the FAT partition # Otherwise it breaks rEFInd's boot search --set=root --no-floppy --fs-uuid 1234-5678 - chainloader (\$root)/EFI/boot/${refindBinary} + chainloader (\$root)/EFI/BOOT/${refindBinary} } fi ''} @@ -431,7 +427,7 @@ let } EOF - grub-script-check $out/EFI/boot/grub.cfg + grub-script-check $out/EFI/BOOT/grub.cfg ${refind} ''; @@ -444,8 +440,8 @@ let # dates (cp -p, touch, mcopy -m, faketime for label), IDs (mkfs.vfat -i) '' mkdir ./contents && cd ./contents - mkdir -p ./EFI/boot - cp -rp "${efiDir}"/EFI/boot/{grub.cfg,*.efi} ./EFI/boot + mkdir -p ./EFI/BOOT + cp -rp "${efiDir}"/EFI/BOOT/{grub.cfg,*.EFI,*.efi} ./EFI/BOOT # Rewrite dates for everything in the FS find . -exec touch --date=2000-01-01 {} + @@ -480,7 +476,7 @@ in { options = { - isoImage.isoName = mkOption { + isoImage.isoName = lib.mkOption { default = "${config.isoImage.isoBaseName}.iso"; type = lib.types.str; description = '' @@ -488,7 +484,7 @@ in ''; }; - isoImage.isoBaseName = mkOption { + isoImage.isoBaseName = lib.mkOption { default = config.system.nixos.distroId; type = lib.types.str; description = '' @@ -496,7 +492,7 @@ in ''; }; - isoImage.compressImage = mkOption { + isoImage.compressImage = lib.mkOption { default = false; type = lib.types.bool; description = '' @@ -505,13 +501,8 @@ in ''; }; - isoImage.squashfsCompression = mkOption { - default = with pkgs.stdenv.hostPlatform; "xz -Xdict-size 100% " - + lib.optionalString isx86 "-Xbcj x86" - # Untested but should also reduce size for these platforms - + lib.optionalString isAarch "-Xbcj arm" - + lib.optionalString (isPower && is32bit && isBigEndian) "-Xbcj powerpc" - + lib.optionalString (isSparc) "-Xbcj sparc"; + isoImage.squashfsCompression = lib.mkOption { + default = "zstd -Xcompression-level 19"; type = lib.types.nullOr lib.types.str; description = '' Compression settings to use for the squashfs nix store. @@ -520,7 +511,7 @@ in example = "zstd -Xcompression-level 6"; }; - isoImage.edition = mkOption { + isoImage.edition = lib.mkOption { default = ""; type = lib.types.str; description = '' @@ -529,9 +520,9 @@ in ''; }; - isoImage.volumeID = mkOption { + isoImage.volumeID = lib.mkOption { # nixos-$EDITION-$RELEASE-$ARCH - default = "nixos${optionalString (config.isoImage.edition != "") "-${config.isoImage.edition}"}-${config.system.nixos.release}-${pkgs.stdenv.hostPlatform.uname.processor}"; + default = "nixos${lib.optionalString (config.isoImage.edition != "") "-${config.isoImage.edition}"}-${config.system.nixos.release}-${pkgs.stdenv.hostPlatform.uname.processor}"; type = lib.types.str; description = '' Specifies the label or volume ID of the generated ISO image. @@ -540,8 +531,8 @@ in ''; }; - isoImage.contents = mkOption { - example = literalExpression '' + isoImage.contents = lib.mkOption { + example = lib.literalExpression '' [ { source = pkgs.memtest86 + "/memtest.bin"; target = "boot/memtest.bin"; } @@ -553,15 +544,15 @@ in ''; }; - isoImage.storeContents = mkOption { - example = literalExpression "[ pkgs.stdenv ]"; + isoImage.storeContents = lib.mkOption { + example = lib.literalExpression "[ pkgs.stdenv ]"; description = '' This option lists additional derivations to be included in the Nix store in the generated ISO image. ''; }; - isoImage.includeSystemBuildDependencies = mkOption { + isoImage.includeSystemBuildDependencies = lib.mkOption { default = false; type = lib.types.bool; description = '' @@ -573,7 +564,7 @@ in ''; }; - isoImage.makeBiosBootable = mkOption { + isoImage.makeBiosBootable = lib.mkOption { # Before this option was introduced, images were BIOS-bootable if the # hostPlatform was x86-based. This option is enabled by default for # backwards compatibility. @@ -591,7 +582,7 @@ in ''; }; - isoImage.makeEfiBootable = mkOption { + isoImage.makeEfiBootable = lib.mkOption { default = false; type = lib.types.bool; description = '' @@ -599,7 +590,7 @@ in ''; }; - isoImage.makeUsbBootable = mkOption { + isoImage.makeUsbBootable = lib.mkOption { default = false; type = lib.types.bool; description = '' @@ -607,7 +598,7 @@ in ''; }; - isoImage.efiSplashImage = mkOption { + isoImage.efiSplashImage = lib.mkOption { default = pkgs.fetchurl { url = "https://raw.githubusercontent.com/NixOS/nixos-artwork/a9e05d7deb38a8e005a2b52575a3f59a63a4dba0/bootloader/efi-background.png"; sha256 = "18lfwmp8yq923322nlb9gxrh5qikj1wsk6g5qvdh31c4h5b1538x"; @@ -617,7 +608,7 @@ in ''; }; - isoImage.splashImage = mkOption { + isoImage.splashImage = lib.mkOption { default = pkgs.fetchurl { url = "https://raw.githubusercontent.com/NixOS/nixos-artwork/a9e05d7deb38a8e005a2b52575a3f59a63a4dba0/bootloader/isolinux/bios-boot.png"; sha256 = "1wp822zrhbg4fgfbwkr7cbkr4labx477209agzc0hr6k62fr6rxd"; @@ -627,15 +618,15 @@ in ''; }; - isoImage.grubTheme = mkOption { + isoImage.grubTheme = lib.mkOption { default = pkgs.nixos-grub2-theme; - type = types.nullOr (types.either types.path types.package); + type = lib.types.nullOr (lib.types.either lib.types.path lib.types.package); description = '' The grub2 theme used for UEFI boot. ''; }; - isoImage.syslinuxTheme = mkOption { + isoImage.syslinuxTheme = lib.mkOption { default = '' MENU TITLE ${config.system.nixos.distroName} MENU RESOLUTION 800 600 @@ -660,15 +651,15 @@ in MENU COLOR UNSEL 37;44 #FF000000 #00000000 none MENU COLOR SEL 7;37;40 #FFFFFFFF #FF5277C3 std ''; - type = types.str; + type = lib.types.str; description = '' The syslinux theme used for BIOS boot. ''; }; - isoImage.prependToMenuLabel = mkOption { + isoImage.prependToMenuLabel = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; example = "Install "; description = '' The string to prepend before the menu label for the NixOS system. @@ -679,9 +670,9 @@ in ''; }; - isoImage.appendToMenuLabel = mkOption { + isoImage.appendToMenuLabel = lib.mkOption { default = " Installer"; - type = types.str; + type = lib.types.str; example = " Live System"; description = '' The string to append after the menu label for the NixOS system. @@ -692,9 +683,9 @@ in ''; }; - isoImage.forceTextMode = mkOption { + isoImage.forceTextMode = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; example = true; description = '' Whether to use text mode instead of graphical grub. @@ -711,7 +702,7 @@ in # store them in lib so we can mkImageMediaOverride the # entire file system layout in installation media (only) config.lib.isoFileSystems = { - "/" = mkImageMediaOverride + "/" = lib.mkImageMediaOverride { fsType = "tmpfs"; options = [ "mode=0755" ]; @@ -720,7 +711,7 @@ in # Note that /dev/root is a symlink to the actual root device # specified on the kernel command line, created in the stage 1 # init script. - "/iso" = mkImageMediaOverride + "/iso" = lib.mkImageMediaOverride { device = "/dev/root"; neededForBoot = true; noCheck = true; @@ -728,20 +719,20 @@ in # In stage 1, mount a tmpfs on top of /nix/store (the squashfs # image) to make this a live CD. - "/nix/.ro-store" = mkImageMediaOverride + "/nix/.ro-store" = lib.mkImageMediaOverride { fsType = "squashfs"; device = "/iso/nix-store.squashfs"; - options = [ "loop" ]; + options = [ "loop" ] ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2") "threads=multi"; neededForBoot = true; }; - "/nix/.rw-store" = mkImageMediaOverride + "/nix/.rw-store" = lib.mkImageMediaOverride { fsType = "tmpfs"; options = [ "mode=0755" ]; neededForBoot = true; }; - "/nix/store" = mkImageMediaOverride + "/nix/store" = lib.mkImageMediaOverride { fsType = "overlay"; device = "overlay"; options = [ @@ -765,11 +756,11 @@ in message = "BIOS boot is only supported on x86-based architectures."; } { - assertion = !(stringLength config.isoImage.volumeID > 32); + assertion = !(lib.stringLength config.isoImage.volumeID > 32); # https://wiki.osdev.org/ISO_9660#The_Primary_Volume_Descriptor # Volume Identifier can only be 32 bytes message = let - length = stringLength config.isoImage.volumeID; + length = lib.stringLength config.isoImage.volumeID; howmany = toString length; toomany = toString (length - 32); in @@ -781,9 +772,10 @@ in # here and it causes a cyclic dependency. boot.loader.grub.enable = false; - environment.systemPackages = [ grubPkgs.grub2 grubPkgs.grub2_efi ] - ++ optional (config.isoImage.makeBiosBootable) pkgs.syslinux + environment.systemPackages = [ grubPkgs.grub2 ] + ++ lib.optional (config.isoImage.makeBiosBootable) pkgs.syslinux ; + system.extraDependencies = [ grubPkgs.grub2_efi ]; # In stage 1 of the boot, mount the CD as the root FS by label so # that we don't need to know its device. We pass the label of the @@ -808,7 +800,7 @@ in # script and the top-level system configuration directory. isoImage.storeContents = [ config.system.build.toplevel ] ++ - optional config.isoImage.includeSystemBuildDependencies + lib.optional config.isoImage.includeSystemBuildDependencies config.system.build.toplevel.drvPath; # Individual files to be included on the CD, outside of the Nix @@ -824,7 +816,7 @@ in { source = pkgs.writeText "version" config.system.nixos.label; target = "/version.txt"; } - ] ++ optionals (config.isoImage.makeBiosBootable) [ + ] ++ lib.optionals (config.isoImage.makeBiosBootable) [ { source = config.isoImage.splashImage; target = "/isolinux/background.png"; } @@ -838,26 +830,26 @@ in { source = "${pkgs.syslinux}/share/syslinux"; target = "/isolinux"; } - ] ++ optionals config.isoImage.makeEfiBootable [ + ] ++ lib.optionals config.isoImage.makeEfiBootable [ { source = efiImg; target = "/boot/efi.img"; } { source = "${efiDir}/EFI"; target = "/EFI"; } - { source = (pkgs.writeTextDir "grub/loopback.cfg" "source /EFI/boot/grub.cfg") + "/grub"; + { source = (pkgs.writeTextDir "grub/loopback.cfg" "source /EFI/BOOT/grub.cfg") + "/grub"; target = "/boot/grub"; } { source = config.isoImage.efiSplashImage; - target = "/EFI/boot/efi-background.png"; + target = "/EFI/BOOT/efi-background.png"; } - ] ++ optionals (config.boot.loader.grub.memtest86.enable && config.isoImage.makeBiosBootable) [ + ] ++ lib.optionals (config.boot.loader.grub.memtest86.enable && config.isoImage.makeBiosBootable) [ { source = "${pkgs.memtest86plus}/memtest.bin"; target = "/boot/memtest.bin"; } - ] ++ optionals (config.isoImage.grubTheme != null) [ + ] ++ lib.optionals (config.isoImage.grubTheme != null) [ { source = config.isoImage.grubTheme; - target = "/EFI/boot/grub-theme"; + target = "/EFI/BOOT/grub-theme"; } ]; @@ -871,10 +863,10 @@ in syslinux = if config.isoImage.makeBiosBootable then pkgs.syslinux else null; squashfsContents = config.isoImage.storeContents; squashfsCompression = config.isoImage.squashfsCompression; - } // optionalAttrs (config.isoImage.makeUsbBootable && config.isoImage.makeBiosBootable) { + } // lib.optionalAttrs (config.isoImage.makeUsbBootable && config.isoImage.makeBiosBootable) { usbBootable = true; isohybridMbrImage = "${pkgs.syslinux}/share/syslinux/isohdpfx.bin"; - } // optionalAttrs config.isoImage.makeEfiBootable { + } // lib.optionalAttrs config.isoImage.makeEfiBootable { efiBootable = true; efiBootImage = "boot/efi.img"; }); diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix index 33301c6423db..adcc10316fea 100644 --- a/nixos/modules/installer/netboot/netboot.nix +++ b/nixos/modules/installer/netboot/netboot.nix @@ -9,12 +9,7 @@ with lib; options = { netboot.squashfsCompression = mkOption { - default = with pkgs.stdenv.hostPlatform; "xz -Xdict-size 100% " - + lib.optionalString isx86 "-Xbcj x86" - # Untested but should also reduce size for these platforms - + lib.optionalString isAarch "-Xbcj arm" - + lib.optionalString (isPower && is32bit && isBigEndian) "-Xbcj powerpc" - + lib.optionalString (isSparc) "-Xbcj sparc"; + default = "zstd -Xcompression-level 19"; description = '' Compression settings to use for the squashfs nix store. ''; @@ -47,7 +42,7 @@ with lib; fileSystems."/nix/.ro-store" = mkImageMediaOverride { fsType = "squashfs"; device = "../nix-store.squashfs"; - options = [ "loop" ]; + options = [ "loop" ] ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2") "threads=multi"; neededForBoot = true; }; diff --git a/nixos/modules/installer/scan/detected.nix b/nixos/modules/installer/scan/detected.nix index 5c5fba56f517..d66ee8983d6b 100644 --- a/nixos/modules/installer/scan/detected.nix +++ b/nixos/modules/installer/scan/detected.nix @@ -1,11 +1,8 @@ # List all devices which are detected by nixos-generate-config. # Common devices are enabled by default. { lib, ... }: - -with lib; - { - config = mkDefault { + config = lib.mkDefault { # Common firmware, i.e. for wifi cards hardware.enableRedistributableFirmware = true; }; diff --git a/nixos/modules/installer/sd-card/sd-image.nix b/nixos/modules/installer/sd-card/sd-image.nix index 42584d88160a..0e717a2b6a7a 100644 --- a/nixos/modules/installer/sd-card/sd-image.nix +++ b/nixos/modules/installer/sd-card/sd-image.nix @@ -150,6 +150,15 @@ in Whether to configure the sd image to expand it's partition on boot. ''; }; + + nixPathRegistrationFile = mkOption { + type = types.str; + default = "/nix-path-registration"; + description = '' + Location of the file containing the input for nix-store --load-db once the machine has booted. + If overriding fileSystems."/" then you should to set this to the root mount + /nix-path-registration + ''; + }; }; config = { @@ -255,11 +264,8 @@ in ''; }) {}; - boot.postBootCommands = lib.mkIf config.sdImage.expandOnBoot '' - # On the first boot do some maintenance tasks - if [ -f /nix-path-registration ]; then - set -euo pipefail - set -x + boot.postBootCommands = let + expandOnBoot = lib.optionalString config.sdImage.expandOnBoot '' # Figure out device names for the boot device and root filesystem. rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /) bootDevice=$(lsblk -npo PKNAME $rootPart) @@ -269,16 +275,25 @@ in echo ",+," | sfdisk -N$partNum --no-reread $bootDevice ${pkgs.parted}/bin/partprobe ${pkgs.e2fsprogs}/bin/resize2fs $rootPart + ''; + nixPathRegistrationFile = config.sdImage.nixPathRegistrationFile; + in '' + # On the first boot do some maintenance tasks + if [ -f ${nixPathRegistrationFile} ]; then + set -euo pipefail + set -x + + ${expandOnBoot} # Register the contents of the initial Nix store - ${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration + ${config.nix.package.out}/bin/nix-store --load-db < ${nixPathRegistrationFile} # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag. touch /etc/NIXOS ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system # Prevents this from running on later boots. - rm -f /nix-path-registration + rm -f ${nixPathRegistrationFile} fi ''; }; diff --git a/nixos/modules/installer/tools/get-version-suffix b/nixos/modules/installer/tools/get-version-suffix deleted file mode 100644 index 8d72905cdcb4..000000000000 --- a/nixos/modules/installer/tools/get-version-suffix +++ /dev/null @@ -1,23 +0,0 @@ -getVersion() { - local dir="$1" - rev= - gitDir="$dir/.git" - if [ -e "$gitDir" ]; then - if [ -z "$(type -P git)" ]; then - echo "warning: Git not found; cannot figure out revision of $dir" >&2 - return - fi - cd "$dir" - rev=$(git --git-dir="$gitDir" rev-parse --short HEAD) - if git --git-dir="$gitDir" describe --always --dirty | grep -q dirty; then - rev+=M - fi - fi -} - -if nixpkgs=$(nix-instantiate --find-file nixpkgs "$@"); then - getVersion $nixpkgs - if [ -n "$rev" ]; then - echo ".git.$rev" - fi -fi diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix index f9ea7eb39597..0bc5787af676 100644 --- a/nixos/modules/installer/tools/nix-fallback-paths.nix +++ b/nixos/modules/installer/tools/nix-fallback-paths.nix @@ -1,7 +1,8 @@ { - x86_64-linux = "/nix/store/f409bhlpp0xkzvdz95qr2yvfjfi8r9jc-nix-2.18.5"; - i686-linux = "/nix/store/ra39jzrxq3bcpf55aahwv5037akvylf5-nix-2.18.5"; - aarch64-linux = "/nix/store/xiw8a4jbnw18svgdb04hyqzg5bsjspqf-nix-2.18.5"; - x86_64-darwin = "/nix/store/k2gzx7i90x3h2c8g6xdi1jkwbl6ic895-nix-2.18.5"; - aarch64-darwin = "/nix/store/rqwymbndaqxma6p8s5brcl9k32n5xx54-nix-2.18.5"; + x86_64-linux = "/nix/store/2nhrwv91g6ycpyxvhmvc0xs8p92wp4bk-nix-2.24.9"; + i686-linux = "/nix/store/idaxj9ji6ggpn1h47a35mf0c8ns4ma39-nix-2.24.9"; + aarch64-linux = "/nix/store/7b5q44l2p70bf6m6dprr8f0587ypwq1z-nix-2.24.9"; + riscv64-linux = "/nix/store/mgw3il1qk59750g5hbf02km79rgyx00y-nix-riscv64-unknown-linux-gnu-2.24.9"; + x86_64-darwin = "/nix/store/rp8rc0pfgham7d7spj5s9syzb138dmmd-nix-2.24.9"; + aarch64-darwin = "/nix/store/1n95r340s7p3vdwqh7m94q0a42crahqq-nix-2.24.9"; } diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index 7f16b97440c1..ee7c3e8c887f 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -3,8 +3,6 @@ { config, lib, pkgs, ... }: -with lib; - let makeProg = args: pkgs.substituteAll (args // { dir = "bin"; @@ -17,28 +15,6 @@ let ''; }); - nixos-build-vms = makeProg { - name = "nixos-build-vms"; - src = ./nixos-build-vms/nixos-build-vms.sh; - inherit (pkgs) runtimeShell; - manPage = ./manpages/nixos-build-vms.8; - }; - - nixos-install = makeProg { - name = "nixos-install"; - src = ./nixos-install.sh; - inherit (pkgs) runtimeShell; - nix = config.nix.package.out; - path = makeBinPath [ - pkgs.jq - nixos-enter - pkgs.util-linuxMinimal - ]; - manPage = ./manpages/nixos-install.8; - }; - - nixos-rebuild = pkgs.nixos-rebuild.override { nix = config.nix.package.out; }; - nixos-generate-config = makeProg { name = "nixos-generate-config"; src = ./nixos-generate-config.pl; @@ -51,8 +27,6 @@ let manPage = ./manpages/nixos-generate-config.8; }; - inherit (pkgs) nixos-option; - nixos-version = makeProg { name = "nixos-version"; src = ./nixos-version.sh; @@ -61,32 +35,141 @@ let inherit (config.system) configurationRevision; json = builtins.toJSON ({ nixosVersion = config.system.nixos.version; - } // optionalAttrs (config.system.nixos.revision != null) { + } // lib.optionalAttrs (config.system.nixos.revision != null) { nixpkgsRevision = config.system.nixos.revision; - } // optionalAttrs (config.system.configurationRevision != null) { + } // lib.optionalAttrs (config.system.configurationRevision != null) { configurationRevision = config.system.configurationRevision; }); manPage = ./manpages/nixos-version.8; }; - nixos-enter = makeProg { - name = "nixos-enter"; - src = ./nixos-enter.sh; - inherit (pkgs) runtimeShell; - path = makeBinPath [ - pkgs.util-linuxMinimal - ]; - manPage = ./manpages/nixos-enter.8; - }; + nixos-install = pkgs.nixos-install.override { nix = config.nix.package; }; + nixos-rebuild = pkgs.nixos-rebuild.override { nix = config.nix.package; }; + defaultConfigTemplate = '' + # Edit this configuration file to define what should be installed on + # your system. Help is available in the configuration.nix(5) man page, on + # https://search.nixos.org/options and in the NixOS manual (`nixos-help`). + + { config, lib, pkgs, ... }: + + { + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + $bootLoaderConfig + # networking.hostName = "nixos"; # Define your hostname. + # Pick only one of the below networking options. + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + # networking.networkmanager.enable = true; # Easiest to use and most distros use this by default. + + # Set your time zone. + # time.timeZone = "Europe/Amsterdam"; + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password\@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Select internationalisation properties. + # i18n.defaultLocale = "en_US.UTF-8"; + # console = { + # font = "Lat2-Terminus16"; + # keyMap = "us"; + # useXkbConfig = true; # use xkb.options in tty. + # }; + + $xserverConfig + + $desktopConfiguration + # Configure keymap in X11 + # services.xserver.xkb.layout = "us"; + # services.xserver.xkb.options = "eurosign:e,caps:escape"; + + # Enable CUPS to print documents. + # services.printing.enable = true; + + # Enable sound. + # hardware.pulseaudio.enable = true; + # OR + # services.pipewire = { + # enable = true; + # pulse.enable = true; + # }; + + # Enable touchpad support (enabled default in most desktopManager). + # services.libinput.enable = true; + + # Define a user account. Don't forget to set a password with ‘passwd’. + # users.users.alice = { + # isNormalUser = true; + # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + # packages = with pkgs; [ + # firefox + # tree + # ]; + # }; + + # List packages installed in system profile. To search, run: + # \$ nix search wget + # environment.systemPackages = with pkgs; [ + # vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. + # wget + # ]; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + # programs.gnupg.agent = { + # enable = true; + # enableSSHSupport = true; + # }; + + # List services that you want to enable: + + # Enable the OpenSSH daemon. + # services.openssh.enable = true; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # Copy the NixOS configuration file and link it from the resulting system + # (/run/current-system/configuration.nix). This is useful in case you + # accidentally delete configuration.nix. + # system.copySystemConfiguration = true; + + # This option defines the first version of NixOS you have installed on this particular machine, + # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. + # + # Most users should NEVER change this value after the initial install, for any reason, + # even if you've upgraded your system to a new NixOS release. + # + # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, + # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how + # to actually do that. + # + # This value being lower than the current NixOS release does NOT mean your system is + # out of date, out of support, or vulnerable. + # + # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, + # and migrated your data accordingly. + # + # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . + system.stateVersion = "${config.system.nixos.release}"; # Did you read the comment? + + } + ''; in - { - options.system.nixos-generate-config = { - configuration = mkOption { + configuration = lib.mkOption { internal = true; - type = types.str; + type = lib.types.str; + default = defaultConfigTemplate; description = '' The NixOS module that `nixos-generate-config` saves to `/etc/nixos/configuration.nix`. @@ -100,9 +183,9 @@ in ''; }; - desktopConfiguration = mkOption { + desktopConfiguration = lib.mkOption { internal = true; - type = types.listOf types.lines; + type = lib.types.listOf lib.types.lines; default = []; description = '' Text to preseed the desktop configuration that `nixos-generate-config` @@ -118,9 +201,9 @@ in }; }; - options.system.disableInstallerTools = mkOption { + options.system.disableInstallerTools = lib.mkOption { internal = true; - type = types.bool; + type = lib.types.bool; default = false; description = '' Disable nixos-rebuild, nixos-generate-config, nixos-installer @@ -130,145 +213,48 @@ in ''; }; - config = lib.mkMerge [ (lib.mkIf (config.nix.enable && !config.system.disableInstallerTools) { + imports = let + mkToolModule = { name, package ? pkgs.${name} }: { config, ... }: { + options.system.tools.${name}.enable = lib.mkEnableOption "${name} script" // { + default = config.nix.enable; + internal = true; + }; - system.nixos-generate-config.configuration = mkDefault '' - # Edit this configuration file to define what should be installed on - # your system. Help is available in the configuration.nix(5) man page, on - # https://search.nixos.org/options and in the NixOS manual (`nixos-help`). - - { config, lib, pkgs, ... }: - - { - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - $bootLoaderConfig - # networking.hostName = "nixos"; # Define your hostname. - # Pick only one of the below networking options. - # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. - # networking.networkmanager.enable = true; # Easiest to use and most distros use this by default. - - # Set your time zone. - # time.timeZone = "Europe/Amsterdam"; - - # Configure network proxy if necessary - # networking.proxy.default = "http://user:password\@proxy:port/"; - # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; - - # Select internationalisation properties. - # i18n.defaultLocale = "en_US.UTF-8"; - # console = { - # font = "Lat2-Terminus16"; - # keyMap = "us"; - # useXkbConfig = true; # use xkb.options in tty. - # }; - - $xserverConfig - - $desktopConfiguration - # Configure keymap in X11 - # services.xserver.xkb.layout = "us"; - # services.xserver.xkb.options = "eurosign:e,caps:escape"; - - # Enable CUPS to print documents. - # services.printing.enable = true; - - # Enable sound. - # hardware.pulseaudio.enable = true; - # OR - # services.pipewire = { - # enable = true; - # pulse.enable = true; - # }; - - # Enable touchpad support (enabled default in most desktopManager). - # services.libinput.enable = true; - - # Define a user account. Don't forget to set a password with ‘passwd’. - # users.users.alice = { - # isNormalUser = true; - # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. - # packages = with pkgs; [ - # firefox - # tree - # ]; - # }; - - # List packages installed in system profile. To search, run: - # \$ nix search wget - # environment.systemPackages = with pkgs; [ - # vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. - # wget - # ]; - - # Some programs need SUID wrappers, can be configured further or are - # started in user sessions. - # programs.mtr.enable = true; - # programs.gnupg.agent = { - # enable = true; - # enableSSHSupport = true; - # }; - - # List services that you want to enable: - - # Enable the OpenSSH daemon. - # services.openssh.enable = true; - - # Open ports in the firewall. - # networking.firewall.allowedTCPPorts = [ ... ]; - # networking.firewall.allowedUDPPorts = [ ... ]; - # Or disable the firewall altogether. - # networking.firewall.enable = false; - - # Copy the NixOS configuration file and link it from the resulting system - # (/run/current-system/configuration.nix). This is useful in case you - # accidentally delete configuration.nix. - # system.copySystemConfiguration = true; - - # This option defines the first version of NixOS you have installed on this particular machine, - # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. - # - # Most users should NEVER change this value after the initial install, for any reason, - # even if you've upgraded your system to a new NixOS release. - # - # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, - # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how - # to actually do that. - # - # This value being lower than the current NixOS release does NOT mean your system is - # out of date, out of support, or vulnerable. - # - # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, - # and migrated your data accordingly. - # - # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . - system.stateVersion = "${config.system.nixos.release}"; # Did you read the comment? - - } - ''; - - environment.systemPackages = - [ nixos-build-vms - nixos-install - nixos-rebuild - nixos-generate-config - nixos-option - nixos-version - nixos-enter - ]; - - documentation.man.man-db.skipPackages = [ nixos-version ]; - - }) - - # These may be used in auxiliary scripts (ie not part of toplevel), so they are defined unconditionally. - ({ - system.build = { - inherit nixos-install nixos-generate-config nixos-option nixos-rebuild nixos-enter; + config = lib.mkIf config.system.tools.${name}.enable { + environment.systemPackages = [ package ]; + }; }; - })]; + in [ + (mkToolModule { name = "nixos-build-vms"; }) + (mkToolModule { name = "nixos-enter"; }) + (mkToolModule { name = "nixos-generate-config"; package = nixos-generate-config; }) + (mkToolModule { name = "nixos-install"; package = nixos-install; }) + (mkToolModule { name = "nixos-option"; }) + (mkToolModule { name = "nixos-rebuild"; package = nixos-rebuild; }) + (mkToolModule { name = "nixos-version"; package = nixos-version; }) + ]; + config = lib.mkMerge [ + (lib.mkIf config.system.disableInstallerTools { + system.tools = { + nixos-build-vms.enable = false; + nixos-enter.enable = false; + nixos-generate-config.enable = false; + nixos-install.enable = false; + nixos-option.enable = false; + nixos-rebuild.enable = false; + nixos-version.enable = false; + }; + }) + { + documentation.man.man-db.skipPackages = [ nixos-version ]; + + # These may be used in auxiliary scripts (ie not part of toplevel), so they are defined unconditionally. + system.build = { + inherit nixos-generate-config nixos-install nixos-rebuild; + nixos-option = lib.warn "Accessing nixos-option through `config.system.build` is deprecated, use `pkgs.nixos-option` instead." pkgs.nixos-option; + nixos-enter = lib.warn "Accessing nixos-enter through `config.system.build` is deprecated, use `pkgs.nixos-enter` instead." pkgs.nixos-enter; + }; + } + ]; } diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 1bdaf713ab5d..8b0127dc29f7 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -35,7 +35,6 @@ in }; - config = { ids.uids = { @@ -111,7 +110,7 @@ in postgres = 71; #vboxusers = 72; # unused #vboxsf = 73; # unused - smbguest = 74; # unused + smbguest = 74; # unused varnish = 75; datadog = 76; lighttpd = 77; @@ -290,14 +289,14 @@ in postgrey = 258; # hound = 259; # unused, removed 2023-11-21 leaps = 260; - ipfs = 261; + ipfs = 261; # stanchion = 262; # unused, removed 2020-10-14 # riak-cs = 263; # unused, removed 2020-10-14 infinoted = 264; sickbeard = 265; headphones = 266; # couchpotato = 267; # unused, removed 2022-01-01 - gogs = 268; + # gogs = 268; # unused, removed in 2024-10-12 #pdns-recursor = 269; # dynamically allocated as of 2020-20-18 #kresd = 270; # switched to "knot-resolver" with dynamic ID rpc = 271; @@ -436,7 +435,7 @@ in postgres = 71; vboxusers = 72; vboxsf = 73; - smbguest = 74; # unused + smbguest = 74; # unused varnish = 75; datadog = 76; lighttpd = 77; @@ -608,7 +607,7 @@ in sickbeard = 265; headphones = 266; # couchpotato = 267; # unused, removed 2022-01-01 - gogs = 268; + # gogs = 268; # unused, removed in 2024-10-12 #kresd = 270; # switched to "knot-resolver" with dynamic ID #rpc = 271; # unused #geoip = 272; # unused @@ -666,6 +665,7 @@ in rstudio-server = 324; localtimed = 325; automatic-timezoned = 326; + uinput = 327; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/misc/nixpkgs-flake.nix b/nixos/modules/misc/nixpkgs-flake.nix index f58c3fbbe2e2..4c91d5e604f2 100644 --- a/nixos/modules/misc/nixpkgs-flake.nix +++ b/nixos/modules/misc/nixpkgs-flake.nix @@ -1,19 +1,16 @@ { config, options, lib, pkgs, ... }: - -with lib; - let cfg = config.nixpkgs.flake; in { options.nixpkgs.flake = { - source = mkOption { + source = lib.mkOption { # In newer Nix versions, particularly with lazy trees, outPath of # flakes becomes a Nix-language path object. We deliberately allow this # to gracefully come through the interface in discussion with @roberth. # # See: https://github.com/NixOS/nixpkgs/pull/278522#discussion_r1460292639 - type = types.nullOr (types.either types.str types.path); + type = lib.types.nullOr (lib.types.either lib.types.str lib.types.path); default = null; defaultText = "if (using nixpkgsFlake.lib.nixosSystem) then self.outPath else null"; @@ -34,8 +31,8 @@ in ''; }; - setNixPath = mkOption { - type = types.bool; + setNixPath = lib.mkOption { + type = lib.types.bool; default = cfg.source != null; defaultText = "config.nixpkgs.flake.source != null"; @@ -54,8 +51,8 @@ in ''; }; - setFlakeRegistry = mkOption { - type = types.bool; + setFlakeRegistry = lib.mkOption { + type = lib.types.bool; default = cfg.source != null; defaultText = "config.nixpkgs.flake.source != null"; @@ -75,7 +72,7 @@ in }; }; - config = mkIf (cfg.source != null) (mkMerge [ + config = lib.mkIf (cfg.source != null) (lib.mkMerge [ { assertions = [ { @@ -87,19 +84,19 @@ in } ]; } - (mkIf cfg.setFlakeRegistry { - nix.registry.nixpkgs.to = mkDefault { + (lib.mkIf cfg.setFlakeRegistry { + nix.registry.nixpkgs.to = lib.mkDefault { type = "path"; path = cfg.source; }; }) - (mkIf cfg.setNixPath { + (lib.mkIf cfg.setNixPath { # N.B. This does not include nixos-config in NIX_PATH unlike modules/config/nix-channel.nix # because we would need some kind of evil shim taking the *calling* flake's self path, # perhaps, to ever make that work (in order to know where the Nix expr for the system came # from and how to call it). - nix.nixPath = mkDefault ([ "nixpkgs=flake:nixpkgs" ] - ++ optional config.nix.channel.enable "/nix/var/nix/profiles/per-user/root/channels"); + nix.nixPath = lib.mkDefault ([ "nixpkgs=flake:nixpkgs" ] + ++ lib.optional config.nix.channel.enable "/nix/var/nix/profiles/per-user/root/channels"); }) ]); } diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index 60a6fb57c7a2..4048fd685737 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -1,7 +1,4 @@ { config, options, lib, pkgs, ... }: - -with lib; - let cfg = config.nixpkgs; opt = options.nixpkgs; @@ -19,19 +16,19 @@ let lhs = optCall lhs_ { inherit pkgs; }; rhs = optCall rhs_ { inherit pkgs; }; in - recursiveUpdate lhs rhs // - optionalAttrs (lhs ? packageOverrides) { + lib.recursiveUpdate lhs rhs // + lib.optionalAttrs (lhs ? packageOverrides) { packageOverrides = pkgs: optCall lhs.packageOverrides pkgs // - optCall (attrByPath [ "packageOverrides" ] { } rhs) pkgs; + optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs; } // - optionalAttrs (lhs ? perlPackageOverrides) { + lib.optionalAttrs (lhs ? perlPackageOverrides) { perlPackageOverrides = pkgs: optCall lhs.perlPackageOverrides pkgs // - optCall (attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs; + optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs; }; - configType = mkOptionType { + configType = lib.mkOptionType { name = "nixpkgs-config"; description = "nixpkgs config"; check = x: @@ -39,34 +36,34 @@ let if c x then true else lib.traceSeqN 1 x false; in traceXIfNot isConfig; - merge = args: foldr (def: mergeConfig def.value) {}; + merge = args: lib.foldr (def: mergeConfig def.value) {}; }; - overlayType = mkOptionType { + overlayType = lib.mkOptionType { name = "nixpkgs-overlay"; description = "nixpkgs overlay"; check = lib.isFunction; merge = lib.mergeOneOption; }; - pkgsType = types.pkgs // { + pkgsType = lib.types.pkgs // { # This type is only used by itself, so let's elaborate the description a bit # for the purpose of documentation. description = "An evaluation of Nixpkgs; the top level attribute set of packages"; }; - hasBuildPlatform = opt.buildPlatform.highestPrio < (mkOptionDefault {}).priority; + hasBuildPlatform = opt.buildPlatform.highestPrio < (lib.mkOptionDefault {}).priority; hasHostPlatform = opt.hostPlatform.isDefined; hasPlatform = hasHostPlatform || hasBuildPlatform; # Context for messages - hostPlatformLine = optionalString hasHostPlatform "${showOptionWithDefLocs opt.hostPlatform}"; - buildPlatformLine = optionalString hasBuildPlatform "${showOptionWithDefLocs opt.buildPlatform}"; + hostPlatformLine = lib.optionalString hasHostPlatform "${lib.showOptionWithDefLocs opt.hostPlatform}"; + buildPlatformLine = lib.optionalString hasBuildPlatform "${lib.showOptionWithDefLocs opt.buildPlatform}"; legacyOptionsDefined = - optional (opt.localSystem.highestPrio < (mkDefault {}).priority) opt.system - ++ optional (opt.localSystem.highestPrio < (mkOptionDefault {}).priority) opt.localSystem - ++ optional (opt.crossSystem.highestPrio < (mkOptionDefault {}).priority) opt.crossSystem + lib.optional (opt.localSystem.highestPrio < (lib.mkDefault {}).priority) opt.system + ++ lib.optional (opt.localSystem.highestPrio < (lib.mkOptionDefault {}).priority) opt.localSystem + ++ lib.optional (opt.crossSystem.highestPrio < (lib.mkOptionDefault {}).priority) opt.crossSystem ; defaultPkgs = @@ -99,19 +96,19 @@ in imports = [ ./assertions.nix ./meta.nix - (mkRemovedOptionModule [ "nixpkgs" "initialSystem" ] "The NixOS options `nesting.clone` and `nesting.children` have been deleted, and replaced with named specialisation. Therefore `nixpgks.initialSystem` has no effect anymore.") + (lib.mkRemovedOptionModule [ "nixpkgs" "initialSystem" ] "The NixOS options `nesting.clone` and `nesting.children` have been deleted, and replaced with named specialisation. Therefore `nixpgks.initialSystem` has no effect anymore.") ]; options.nixpkgs = { - pkgs = mkOption { - defaultText = literalExpression '' + pkgs = lib.mkOption { + defaultText = lib.literalExpression '' import "''${nixos}/.." { inherit (cfg) config overlays localSystem crossSystem; } ''; type = pkgsType; - example = literalExpression "import {}"; + example = lib.literalExpression "import {}"; description = '' If set, the pkgs argument to all NixOS modules is the value of this option, extended with `nixpkgs.overlays`, if @@ -145,9 +142,9 @@ in ''; }; - config = mkOption { + config = lib.mkOption { default = {}; - example = literalExpression + example = lib.literalExpression '' { allowBroken = true; allowUnfree = true; } ''; @@ -160,9 +157,9 @@ in ''; }; - overlays = mkOption { + overlays = lib.mkOption { default = []; - example = literalExpression + example = lib.literalExpression '' [ (self: super: { @@ -173,7 +170,7 @@ in }) ] ''; - type = types.listOf overlayType; + type = lib.types.listOf overlayType; description = '' List of overlays to apply to Nixpkgs. This option allows modifying the Nixpkgs package set accessed through the `pkgs` module argument. @@ -184,13 +181,13 @@ in ''; }; - hostPlatform = mkOption { - type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform + hostPlatform = lib.mkOption { + type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform example = { system = "aarch64-linux"; }; # Make sure that the final value has all fields for sake of other modules # referring to this. TODO make `lib.systems` itself use the module system. apply = lib.systems.elaborate; - defaultText = literalExpression + defaultText = lib.literalExpression ''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform''; description = '' Specifies the platform where the NixOS configuration will run. @@ -201,8 +198,8 @@ in ''; }; - buildPlatform = mkOption { - type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform + buildPlatform = lib.mkOption { + type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform default = cfg.hostPlatform; example = { system = "x86_64-linux"; }; # Make sure that the final value has all fields for sake of other modules @@ -212,7 +209,7 @@ in in if lib.systems.equals elaborated cfg.hostPlatform then cfg.hostPlatform # make identical, so that `==` equality works; see https://github.com/NixOS/nixpkgs/issues/278001 else elaborated; - defaultText = literalExpression + defaultText = lib.literalExpression ''config.nixpkgs.hostPlatform''; description = '' Specifies the platform on which NixOS should be built. @@ -228,14 +225,14 @@ in ''; }; - localSystem = mkOption { - type = types.attrs; # TODO utilize lib.systems.parsedPlatform + localSystem = lib.mkOption { + type = lib.types.attrs; # TODO utilize lib.systems.parsedPlatform default = { inherit (cfg) system; }; example = { system = "aarch64-linux"; }; # Make sure that the final value has all fields for sake of other modules # referring to this. TODO make `lib.systems` itself use the module system. apply = lib.systems.elaborate; - defaultText = literalExpression + defaultText = lib.literalExpression ''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform''; description = '' Systems with a recently generated `hardware-configuration.nix` @@ -262,8 +259,8 @@ in # TODO deprecate. "crossSystem" is a nonsense identifier, because "cross" # is a relation between at least 2 systems in the context of a # specific build step, not a single system. - crossSystem = mkOption { - type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform + crossSystem = lib.mkOption { + type = lib.types.nullOr lib.types.attrs; # TODO utilize lib.systems.parsedPlatform default = null; example = { system = "aarch64-linux"; }; description = '' @@ -283,8 +280,8 @@ in ''; }; - system = mkOption { - type = types.str; + system = lib.mkOption { + type = lib.types.str; example = "i686-linux"; default = if opt.hostPlatform.isDefined @@ -372,12 +369,12 @@ in { assertion = constructedByMe -> hasPlatform -> legacyOptionsDefined == []; message = '' - Your system configures nixpkgs with the platform parameter${optionalString hasBuildPlatform "s"}: + Your system configures nixpkgs with the platform parameter${lib.optionalString hasBuildPlatform "s"}: ${hostPlatformLine }${buildPlatformLine } However, it also defines the legacy options: - ${concatMapStrings showOptionWithDefLocs legacyOptionsDefined} + ${lib.concatMapStrings lib.showOptionWithDefLocs legacyOptionsDefined} For a future proof system configuration, we recommend to remove the legacy definitions. ''; @@ -389,7 +386,10 @@ in `nixpkgs.config` options should be passed when creating the instance instead. Current value: - ${lib.generators.toPretty { multiline = true; } opt.config} + ${lib.generators.toPretty { multiline = true; } cfg.config} + + Defined in: + ${lib.concatMapStringsSep "\n" (file: " - ${file}") opt.config.files} ''; } ]; diff --git a/nixos/modules/misc/nixpkgs/test.nix b/nixos/modules/misc/nixpkgs/test.nix index be9a88a07788..e70b7a12e8dd 100644 --- a/nixos/modules/misc/nixpkgs/test.nix +++ b/nixos/modules/misc/nixpkgs/test.nix @@ -16,6 +16,11 @@ let nixpkgs.hostPlatform = "aarch64-linux"; nixpkgs.buildPlatform = "aarch64-linux"; }; + externalPkgsWithConfig = { + _file = "ext-pkgs-config.nix"; + nixpkgs.pkgs = pkgs; + nixpkgs.config.allowUnfree = true; + }; ambiguous = { _file = "ambiguous.nix"; nixpkgs.hostPlatform = "aarch64-linux"; @@ -108,6 +113,20 @@ lib.recurseIntoAttrs { For a future proof system configuration, we recommend to remove the legacy definitions. '']; + assert builtins.trace (lib.head (getErrors externalPkgsWithConfig)) + getErrors externalPkgsWithConfig == + ['' + Your system configures nixpkgs with an externally created instance. + `nixpkgs.config` options should be passed when creating the instance instead. + + Current value: + { + allowUnfree = true; + } + + Defined in: + - ext-pkgs-config.nix + '']; assert getErrors { nixpkgs.localSystem = pkgs.stdenv.hostPlatform; nixpkgs.hostPlatform = pkgs.stdenv.hostPlatform; diff --git a/nixos/modules/misc/wordlist.nix b/nixos/modules/misc/wordlist.nix index 988b522d7431..67c83ff2baaa 100644 --- a/nixos/modules/misc/wordlist.nix +++ b/nixos/modules/misc/wordlist.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let concatAndSort = name: files: pkgs.runCommand name {} '' awk 1 ${lib.escapeShellArgs files} | sed '{ /^\s*$/d; s/^\s\+//; s/\s\+$// }' | sort | uniq > $out @@ -8,16 +7,16 @@ in { options = { environment.wordlist = { - enable = mkEnableOption "environment variables for lists of words"; + enable = lib.mkEnableOption "environment variables for lists of words"; - lists = mkOption { - type = types.attrsOf (types.nonEmptyListOf types.path); + lists = lib.mkOption { + type = lib.types.attrsOf (lib.types.nonEmptyListOf lib.types.path); default = { WORDLIST = [ "${pkgs.scowl}/share/dict/words.txt" ]; }; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' { WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ]; } @@ -34,7 +33,7 @@ in task. ''; - example = literalExpression '' + example = lib.literalExpression '' { WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ]; AUGMENTED_WORDLIST = [ @@ -50,7 +49,7 @@ in }; }; - config = mkIf config.environment.wordlist.enable { + config = lib.mkIf config.environment.wordlist.enable { environment.variables = lib.mapAttrs (name: value: "${concatAndSort "wordlist-${name}" value}") diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index cf79c8b4792b..6ac03cca94e9 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -20,7 +20,6 @@ ./config/nix-channel.nix ./config/nix-flakes.nix ./config/nix-remote-build.nix - ./config/no-x-libs.nix ./config/nsswitch.nix ./config/power-management.nix ./config/pulseaudio.nix @@ -193,6 +192,7 @@ ./programs/fish.nix ./programs/flashrom.nix ./programs/flexoptix-app.nix + ./programs/foot ./programs/freetds.nix ./programs/fuse.nix ./programs/fzf.nix @@ -215,7 +215,7 @@ ./programs/iftop.nix ./programs/i3lock.nix ./programs/iio-hyprland.nix - ./programs/immersed-vr.nix + ./programs/immersed.nix ./programs/iotop.nix ./programs/java.nix ./programs/joycond-cemuhook.nix @@ -259,11 +259,13 @@ ./programs/oblogout.nix ./programs/oddjobd.nix ./programs/openvpn3.nix + ./programs/obs-studio.nix ./programs/partition-manager.nix ./programs/plotinus.nix ./programs/pqos-wrapper.nix ./programs/projecteur.nix ./programs/proxychains.nix + ./programs/pulseview.nix ./programs/qdmr.nix ./programs/qgroundcontrol.nix ./programs/qt5ct.nix @@ -286,6 +288,7 @@ ./programs/ssh.nix ./programs/starship.nix ./programs/steam.nix + ./programs/streamcontroller.nix ./programs/streamdeck-ui.nix ./programs/sysdig.nix ./programs/system-config-printer.nix @@ -310,6 +313,7 @@ ./programs/wayland/miracle-wm.nix ./programs/wayland/river.nix ./programs/wayland/sway.nix + ./programs/wayland/uwsm.nix ./programs/wayland/waybar.nix ./programs/wayland/wayfire.nix ./programs/weylus.nix @@ -360,6 +364,7 @@ ./security/systemd-confinement.nix ./security/tpm2.nix ./security/wrappers/default.nix + ./services/accessibility/orca.nix ./services/accessibility/speechd.nix ./services/admin/docuum.nix ./services/admin/meshcentral.nix @@ -653,6 +658,7 @@ ./services/logging/syslogd.nix ./services/logging/vector.nix ./services/logging/ulogd.nix + ./services/mail/automx2.nix ./services/mail/clamsmtp.nix ./services/mail/davmail.nix ./services/mail/dkimproxy-out.nix @@ -693,6 +699,7 @@ ./services/matrix/conduit.nix ./services/matrix/dendrite.nix ./services/matrix/hebbot.nix + ./services/matrix/hookshot.nix ./services/matrix/maubot.nix ./services/matrix/mautrix-facebook.nix ./services/matrix/mautrix-meta.nix @@ -707,7 +714,6 @@ ./services/misc/airsonic.nix ./services/misc/amazon-ssm-agent.nix ./services/misc/ananicy.nix - ./services/misc/ankisyncd.nix ./services/misc/anki-sync-server.nix ./services/misc/apache-kafka.nix ./services/misc/atuin.nix @@ -753,7 +759,6 @@ ./services/misc/gitlab.nix ./services/misc/gitolite.nix ./services/misc/gitweb.nix - ./services/misc/gogs.nix ./services/misc/gollum.nix ./services/misc/gotenberg.nix ./services/misc/gpsd.nix @@ -852,6 +857,7 @@ ./services/misc/tautulli.nix ./services/misc/tiddlywiki.nix ./services/misc/tp-auto-kbbl.nix + ./services/misc/turn-rs.nix ./services/misc/tuxclocker.nix ./services/misc/transfer-sh.nix ./services/misc/tzupdate.nix @@ -876,6 +882,7 @@ ./services/monitoring/datadog-agent.nix ./services/monitoring/do-agent.nix ./services/monitoring/fusion-inventory.nix + ./services/monitoring/gatus.nix ./services/monitoring/goss.nix ./services/monitoring/grafana-agent.nix ./services/monitoring/grafana-image-renderer.nix @@ -924,6 +931,7 @@ ./services/monitoring/teamviewer.nix ./services/monitoring/telegraf.nix ./services/monitoring/thanos.nix + ./services/monitoring/todesk.nix ./services/monitoring/tremor-rs.nix ./services/monitoring/tuptime.nix ./services/monitoring/unpoller.nix @@ -957,6 +965,7 @@ ./services/network-filesystems/rsyncd.nix ./services/network-filesystems/samba-wsdd.nix ./services/network-filesystems/samba.nix + ./services/network-filesystems/saunafs.nix ./services/network-filesystems/tahoe.nix ./services/network-filesystems/u9fs.nix ./services/network-filesystems/webdav-server-rs.nix @@ -968,10 +977,10 @@ ./services/networking/adguardhome.nix ./services/networking/alice-lg.nix ./services/networking/amuled.nix - ./services/networking/antennas.nix ./services/networking/aria2.nix ./services/networking/asterisk.nix ./services/networking/atftpd.nix + ./services/networking/atticd.nix ./services/networking/autossh.nix ./services/networking/avahi-daemon.nix ./services/networking/babeld.nix @@ -1010,7 +1019,6 @@ ./services/networking/dhcpcd.nix ./services/networking/dnscache.nix ./services/networking/dnscrypt-proxy2.nix - ./services/networking/dnscrypt-wrapper.nix ./services/networking/dnsdist.nix ./services/networking/dnsmasq.nix ./services/networking/dnsproxy.nix @@ -1024,6 +1032,7 @@ ./services/networking/expressvpn.nix ./services/networking/fakeroute.nix ./services/networking/fastnetmon-advanced.nix + ./services/networking/fedimintd.nix ./services/networking/ferm.nix ./services/networking/firefox-syncserver.nix ./services/networking/fireqos.nix @@ -1039,7 +1048,6 @@ ./services/networking/gdomap.nix ./services/networking/ghostunnel.nix ./services/networking/git-daemon.nix - ./services/networking/globalprotect-vpn.nix ./services/networking/gns3-server.nix ./services/networking/gnunet.nix ./services/networking/go-autoconfig.nix @@ -1188,6 +1196,7 @@ ./services/networking/scion/scion-daemon.nix ./services/networking/scion/scion-dispatcher.nix ./services/networking/scion/scion-router.nix + ./services/networking/scion/scion-ip-gateway.nix ./services/networking/seafile.nix ./services/networking/searx.nix ./services/networking/shadowsocks.nix @@ -1223,6 +1232,7 @@ ./services/networking/syncthing.nix ./services/networking/tailscale.nix ./services/networking/tailscale-auth.nix + ./services/networking/tailscale-derper.nix ./services/networking/tayga.nix ./services/networking/tcpcrypt.nix ./services/networking/teamspeak3.nix @@ -1239,7 +1249,6 @@ ./services/networking/tox-node.nix ./services/networking/toxvpn.nix ./services/networking/trickster.nix - ./services/networking/tvheadend.nix ./services/networking/twingate.nix ./services/networking/ucarp.nix ./services/networking/unbound.nix @@ -1247,6 +1256,7 @@ ./services/networking/uptermd.nix ./services/networking/v2ray.nix ./services/networking/v2raya.nix + ./services/networking/veilid.nix ./services/networking/vdirsyncer.nix ./services/networking/vsftpd.nix ./services/networking/wasabibackend.nix @@ -1267,6 +1277,7 @@ ./services/networking/xray.nix ./services/networking/xrdp.nix ./services/networking/yggdrasil.nix + ./services/networking/zapret.nix ./services/networking/zerobin.nix ./services/networking/zeronet.nix ./services/networking/zerotierone.nix @@ -1346,6 +1357,7 @@ ./services/system/systembus-notify.nix ./services/system/systemd-lock-handler.nix ./services/system/uptimed.nix + ./services/system/userborn.nix ./services/system/zram-generator.nix ./services/torrent/deluge.nix ./services/torrent/flexget.nix @@ -1366,7 +1378,6 @@ ./services/video/mirakurun.nix ./services/video/photonvision.nix ./services/video/mediamtx.nix - ./services/video/unifi-video.nix ./services/video/v4l2-relayd.nix ./services/wayland/cage.nix ./services/wayland/hypridle.nix @@ -1378,6 +1389,7 @@ ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix ./services/web-apps/audiobookshelf.nix + ./services/web-apps/bluemap.nix ./services/web-apps/bookstack.nix ./services/web-apps/c2fmzq-server.nix ./services/web-apps/calibre-web.nix @@ -1387,11 +1399,13 @@ ./services/web-apps/chatgpt-retrieval-plugin.nix ./services/web-apps/cloudlog.nix ./services/web-apps/code-server.nix + ./services/web-apps/collabora-online.nix ./services/web-apps/commafeed.nix ./services/web-apps/convos.nix ./services/web-apps/crabfit.nix ./services/web-apps/davis.nix ./services/web-apps/cryptpad.nix + ./services/web-apps/dependency-track.nix ./services/web-apps/dex.nix ./services/web-apps/discourse.nix ./services/web-apps/documize.nix @@ -1402,10 +1416,12 @@ ./services/web-apps/ethercalc.nix ./services/web-apps/filesender.nix ./services/web-apps/firefly-iii.nix + ./services/web-apps/firefly-iii-data-importer.nix ./services/web-apps/flarum.nix ./services/web-apps/fluidd.nix ./services/web-apps/freshrss.nix ./services/web-apps/galene.nix + ./services/web-apps/gancio.nix ./services/web-apps/gerrit.nix ./services/web-apps/glance.nix ./services/web-apps/gotify-server.nix @@ -1415,6 +1431,7 @@ ./services/web-apps/goatcounter.nix ./services/web-apps/guacamole-client.nix ./services/web-apps/guacamole-server.nix + ./services/web-apps/hatsu.nix ./services/web-apps/healthchecks.nix ./services/web-apps/hedgedoc.nix ./services/web-apps/hledger-web.nix @@ -1423,6 +1440,7 @@ ./services/web-apps/icingaweb2/icingaweb2.nix ./services/web-apps/icingaweb2/module-monitoring.nix ./services/web-apps/ifm.nix + ./services/web-apps/immich.nix ./services/web-apps/invidious.nix ./services/web-apps/invoiceplane.nix ./services/web-apps/isso.nix @@ -1473,8 +1491,10 @@ ./services/web-apps/powerdns-admin.nix ./services/web-apps/pretalx.nix ./services/web-apps/pretix.nix + ./services/web-apps/privatebin.nix ./services/web-apps/prosody-filer.nix ./services/web-apps/rimgo.nix + ./services/web-apps/rutorrent.nix ./services/web-apps/screego.nix ./services/web-apps/sftpgo.nix ./services/web-apps/suwayomi-server.nix @@ -1490,6 +1510,7 @@ ./services/web-apps/trilium.nix ./services/web-apps/tt-rss.nix ./services/web-apps/vikunja.nix + ./services/web-apps/wakapi.nix ./services/web-apps/weblate.nix ./services/web-apps/whitebophir.nix ./services/web-apps/wiki-js.nix @@ -1502,7 +1523,6 @@ ./services/web-apps/zitadel.nix ./services/web-servers/agate.nix ./services/web-servers/apache-httpd/default.nix - ./services/web-servers/bluemap.nix ./services/web-servers/caddy/default.nix ./services/web-servers/darkhttpd.nix ./services/web-servers/fcgiwrap.nix @@ -1615,6 +1635,7 @@ ./system/boot/stage-2.nix ./system/boot/systemd.nix ./system/boot/systemd/coredump.nix + ./system/boot/systemd/dm-verity.nix ./system/boot/systemd/initrd-secrets.nix ./system/boot/systemd/initrd.nix ./system/boot/systemd/journald.nix @@ -1629,6 +1650,7 @@ ./system/boot/systemd/sysupdate.nix ./system/boot/systemd/sysusers.nix ./system/boot/systemd/tmpfiles.nix + ./system/boot/systemd/tpm2.nix ./system/boot/systemd/user.nix ./system/boot/systemd/userdbd.nix ./system/boot/systemd/homed.nix diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix index 249b767593f2..970b76cfbfdf 100644 --- a/nixos/modules/profiles/all-hardware.nix +++ b/nixos/modules/profiles/all-hardware.nix @@ -52,7 +52,7 @@ in # VMware support. "mptspi" "vmxnet3" "vsock" ] ++ lib.optional platform.isx86 "vmw_balloon" - ++ lib.optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [ + ++ lib.optionals (pkgs.stdenv.hostPlatform.isi686 || pkgs.stdenv.hostPlatform.isx86_64) [ "vmw_vmci" "vmwgfx" "vmw_vsock_vmci_transport" # Hyper-V support. @@ -68,7 +68,7 @@ in # Broadcom "vc4" - ] ++ lib.optionals pkgs.stdenv.isAarch64 [ + ] ++ lib.optionals pkgs.stdenv.hostPlatform.isAarch64 [ # Most of the following falls into two categories: # - early KMS / early display # - early storage (e.g. USB) support diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 9f32f85a61ec..943f9d8e3106 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -19,13 +19,7 @@ pkgs.cryptsetup # needed for dm-crypt volumes # Some text editors. - (pkgs.vim.customize { - name = "vim"; - vimrcConfig.packages.default = { - start = [ pkgs.vimPlugins.vim-nix ]; - }; - vimrcConfig.customRC = "syntax on"; - }) + pkgs.vim # Some networking tools. pkgs.fuse @@ -50,7 +44,7 @@ # Include support for various filesystems and tools to create / manipulate them. boot.supportedFilesystems = - [ "btrfs" "cifs" "f2fs" "jfs" "ntfs" "reiserfs" "vfat" "xfs" ] ++ + [ "btrfs" "cifs" "f2fs" "ntfs" "vfat" "xfs" ] ++ lib.optional (lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs"; # Configure host id for ZFS to work diff --git a/nixos/modules/profiles/graphical.nix b/nixos/modules/profiles/graphical.nix index 72b865c584f0..f96b11b35367 100644 --- a/nixos/modules/profiles/graphical.nix +++ b/nixos/modules/profiles/graphical.nix @@ -14,8 +14,5 @@ libinput.enable = true; # for touchpad support on many laptops }; - # Enable sound in virtualbox appliances. - hardware.pulseaudio.enable = true; - - environment.systemPackages = [ pkgs.glxinfo pkgs.firefox ]; + environment.systemPackages = [ pkgs.mesa-demos pkgs.firefox ]; } diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix index 7e5aec053df9..7e22d4b6b684 100644 --- a/nixos/modules/profiles/installation-device.nix +++ b/nixos/modules/profiles/installation-device.nix @@ -128,13 +128,13 @@ with lib; nix.settings.trusted-users = [ "nixos" ]; # Install less voices for speechd to save some space - services.speechd.package = pkgs.speechd.override { - mbrola = pkgs.mbrola.override { - mbrola-voices = pkgs.mbrola-voices.override { + nixpkgs.overlays = [ + (_: prev: { + mbrola-voices = prev.mbrola-voices.override { # only ship with one voice per language languages = [ "*1" ]; }; - }; - }; + }) + ]; }; } diff --git a/nixos/modules/profiles/macos-builder.nix b/nixos/modules/profiles/macos-builder.nix index bf8414e1e108..896bb6bc9fbd 100644 --- a/nixos/modules/profiles/macos-builder.nix +++ b/nixos/modules/profiles/macos-builder.nix @@ -1,268 +1,5 @@ -{ config, lib, options, ... }: - -let - keysDirectory = "/var/keys"; - - user = "builder"; - - keyType = "ed25519"; - - cfg = config.virtualisation.darwin-builder; - +let lib = import ../../../lib; in - -{ - imports = [ - ../virtualisation/qemu-vm.nix - - # Avoid a dependency on stateVersion - { - disabledModules = [ - ../virtualisation/nixos-containers.nix - ../services/x11/desktop-managers/xterm.nix - ]; - # swraid's default depends on stateVersion - config.boot.swraid.enable = false; - options.boot.isContainer = lib.mkOption { default = false; internal = true; }; - } - ]; - - options.virtualisation.darwin-builder = with lib; { - diskSize = mkOption { - default = 20 * 1024; - type = types.int; - example = 30720; - description = "The maximum disk space allocated to the runner in MB"; - }; - memorySize = mkOption { - default = 3 * 1024; - type = types.int; - example = 8192; - description = "The runner's memory in MB"; - }; - min-free = mkOption { - default = 1024 * 1024 * 1024; - type = types.int; - example = 1073741824; - description = '' - The threshold (in bytes) of free disk space left at which to - start garbage collection on the runner - ''; - }; - max-free = mkOption { - default = 3 * 1024 * 1024 * 1024; - type = types.int; - example = 3221225472; - description = '' - The threshold (in bytes) of free disk space left at which to - stop garbage collection on the runner - ''; - }; - workingDirectory = mkOption { - default = "."; - type = types.str; - example = "/var/lib/darwin-builder"; - description = '' - The working directory to use to run the script. When running - as part of a flake will need to be set to a non read-only filesystem. - ''; - }; - hostPort = mkOption { - default = 31022; - type = types.int; - example = 22; - description = '' - The localhost host port to forward TCP to the guest port. - ''; - }; - }; - - config = { - # The builder is not intended to be used interactively - documentation.enable = false; - - environment.etc = { - "ssh/ssh_host_ed25519_key" = { - mode = "0600"; - - source = ./keys/ssh_host_ed25519_key; - }; - - "ssh/ssh_host_ed25519_key.pub" = { - mode = "0644"; - - source = ./keys/ssh_host_ed25519_key.pub; - }; - }; - - # DNS fails for QEMU user networking (SLiRP) on macOS. See: - # - # https://github.com/utmapp/UTM/issues/2353 - # - # This works around that by using a public DNS server other than the DNS - # server that QEMU provides (normally 10.0.2.3) - networking.nameservers = [ "8.8.8.8" ]; - - # The linux builder is a lightweight VM for remote building; not evaluation. - nix.channel.enable = false; - # remote builder uses `nix-daemon` (ssh-ng:) or `nix-store --serve` (ssh:) - # --force: do not complain when missing - # TODO: install a store-only nix - # https://github.com/NixOS/rfcs/blob/master/rfcs/0134-nix-store-layer.md#detailed-design - environment.extraSetup = '' - rm --force $out/bin/{nix-instantiate,nix-build,nix-shell,nix-prefetch*,nix} - ''; - # Deployment is by image. - # TODO system.switch.enable = false;? - system.disableInstallerTools = true; - - nix.settings = { - auto-optimise-store = true; - - min-free = cfg.min-free; - - max-free = cfg.max-free; - - trusted-users = [ user ]; - }; - - services = { - getty.autologinUser = user; - - openssh = { - enable = true; - - authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ]; - }; - }; - - system.build.macos-builder-installer = - let - privateKey = "/etc/nix/${user}_${keyType}"; - - publicKey = "${privateKey}.pub"; - - # This installCredentials script is written so that it's as easy as - # possible for a user to audit before confirming the `sudo` - installCredentials = hostPkgs.writeShellScript "install-credentials" '' - set -euo pipefail - - KEYS="''${1}" - INSTALL=${hostPkgs.coreutils}/bin/install - "''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey} - "''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey} - ''; - - hostPkgs = config.virtualisation.host.pkgs; - - script = hostPkgs.writeShellScriptBin "create-builder" ( - '' - set -euo pipefail - '' + - # When running as non-interactively as part of a DarwinConfiguration the working directory - # must be set to a writeable directory. - (if cfg.workingDirectory != "." then '' - ${hostPkgs.coreutils}/bin/mkdir --parent "${cfg.workingDirectory}" - cd "${cfg.workingDirectory}" - '' else "") + '' - KEYS="''${KEYS:-./keys}" - ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}" - PRIVATE_KEY="''${KEYS}/${user}_${keyType}" - PUBLIC_KEY="''${PRIVATE_KEY}.pub" - if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then - ${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}" - ${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost' - fi - if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then - (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}") - fi - KEYS="$(${hostPkgs.nix}/bin/nix-store --add "$KEYS")" ${lib.getExe config.system.build.vm} - ''); - - in - script.overrideAttrs (old: { - pos = __curPos; # sets meta.position to point here; see script binding above for package definition - meta = (old.meta or { }) // { - platforms = lib.platforms.darwin; - }; - passthru = (old.passthru or { }) // { - # Let users in the repl inspect the config - nixosConfig = config; - nixosOptions = options; - }; - }); - - system = { - # To prevent gratuitous rebuilds on each change to Nixpkgs - nixos.revision = null; - - stateVersion = lib.mkDefault (throw '' - The macOS linux builder should not need a stateVersion to be set, but a module - has accessed stateVersion nonetheless. - Please inspect the trace of the following command to figure out which module - has a dependency on stateVersion. - - nix-instantiate --attr darwin.linux-builder --show-trace - ''); - }; - - users.users."${user}" = { - isNormalUser = true; - }; - - security.polkit.enable = true; - - security.polkit.extraConfig = '' - polkit.addRule(function(action, subject) { - if (action.id === "org.freedesktop.login1.power-off" && subject.user === "${user}") { - return "yes"; - } else { - return "no"; - } - }) - ''; - - virtualisation = { - diskSize = cfg.diskSize; - - memorySize = cfg.memorySize; - - forwardPorts = [ - { from = "host"; guest.port = 22; host.port = cfg.hostPort; } - ]; - - # Disable graphics for the builder since users will likely want to run it - # non-interactively in the background. - graphics = false; - - sharedDirectories.keys = { - source = "\"$KEYS\""; - target = keysDirectory; - }; - - # If we don't enable this option then the host will fail to delegate builds - # to the guest, because: - # - # - The host will lock the path to build - # - The host will delegate the build to the guest - # - The guest will attempt to lock the same path and fail because - # the lockfile on the host is visible on the guest - # - # Snapshotting the host's /nix/store as an image isolates the guest VM's - # /nix/store from the host's /nix/store, preventing this problem. - useNixStoreImage = true; - - # Obviously the /nix/store needs to be writable on the guest in order for it - # to perform builds. - writableStore = true; - - # This ensures that anything built on the guest isn't lost when the guest is - # restarted. - writableStoreUseTmpfs = false; - - # Pass certificates from host to the guest otherwise when custom CA certificates - # are required we can't use the cached builder. - useHostCerts = true; - }; - }; -} + lib.warnIf (lib.isInOldestRelease 2411) + "nixos/modules/profiles/macos-builder.nix has moved to nixos/modules/profiles/nix-builder-vm.nix; please update your NixOS imports." + ./nix-builder-vm.nix diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix index b76740f7cc58..df21b75c82b1 100644 --- a/nixos/modules/profiles/minimal.nix +++ b/nixos/modules/profiles/minimal.nix @@ -6,8 +6,6 @@ with lib; { - environment.noXlibs = mkDefault true; - documentation.enable = mkDefault false; documentation.doc.enable = mkDefault false; @@ -21,7 +19,7 @@ with lib; # Perl is a default package. environment.defaultPackages = mkDefault [ ]; - environment.stub-ld.enable = false; + environment.stub-ld.enable = mkDefault false; # The lessopen package pulls in Perl. programs.less.lessopen = mkDefault null; @@ -31,6 +29,8 @@ with lib; programs.command-not-found.enable = mkDefault false; + programs.ssh.setXAuthLocation = mkDefault false; + services.logrotate.enable = mkDefault false; services.udisks2.enable = mkDefault false; diff --git a/nixos/modules/profiles/nix-builder-vm.nix b/nixos/modules/profiles/nix-builder-vm.nix new file mode 100644 index 000000000000..fcaca974f302 --- /dev/null +++ b/nixos/modules/profiles/nix-builder-vm.nix @@ -0,0 +1,284 @@ +/* + This profile uses NixOS to create a remote builder VM to build Linux packages, + which can be used to build packages for Linux on other operating systems; + primarily macOS. + + It contains both the relevant guest settings as well as an installer script + that manages it as a QEMU virtual machine on the host. +*/ +{ + config, + lib, + options, + ... +}: + +let + keysDirectory = "/var/keys"; + + user = "builder"; + + keyType = "ed25519"; + + cfg = config.virtualisation.darwin-builder; + +in + +{ + imports = [ + ../virtualisation/qemu-vm.nix + + # Avoid a dependency on stateVersion + { + disabledModules = [ + ../virtualisation/nixos-containers.nix + ../services/x11/desktop-managers/xterm.nix + ]; + # swraid's default depends on stateVersion + config.boot.swraid.enable = false; + options.boot.isContainer = lib.mkOption { + default = false; + internal = true; + }; + } + ]; + + options.virtualisation.darwin-builder = with lib; { + diskSize = mkOption { + default = 20 * 1024; + type = types.int; + example = 30720; + description = "The maximum disk space allocated to the runner in MB"; + }; + memorySize = mkOption { + default = 3 * 1024; + type = types.int; + example = 8192; + description = "The runner's memory in MB"; + }; + min-free = mkOption { + default = 1024 * 1024 * 1024; + type = types.int; + example = 1073741824; + description = '' + The threshold (in bytes) of free disk space left at which to + start garbage collection on the runner + ''; + }; + max-free = mkOption { + default = 3 * 1024 * 1024 * 1024; + type = types.int; + example = 3221225472; + description = '' + The threshold (in bytes) of free disk space left at which to + stop garbage collection on the runner + ''; + }; + workingDirectory = mkOption { + default = "."; + type = types.str; + example = "/var/lib/darwin-builder"; + description = '' + The working directory to use to run the script. When running + as part of a flake will need to be set to a non read-only filesystem. + ''; + }; + hostPort = mkOption { + default = 31022; + type = types.int; + example = 22; + description = '' + The localhost host port to forward TCP to the guest port. + ''; + }; + }; + + config = { + # The builder is not intended to be used interactively + documentation.enable = false; + + environment.etc = { + "ssh/ssh_host_ed25519_key" = { + mode = "0600"; + + source = ./keys/ssh_host_ed25519_key; + }; + + "ssh/ssh_host_ed25519_key.pub" = { + mode = "0644"; + + source = ./keys/ssh_host_ed25519_key.pub; + }; + }; + + # DNS fails for QEMU user networking (SLiRP) on macOS. See: + # + # https://github.com/utmapp/UTM/issues/2353 + # + # This works around that by using a public DNS server other than the DNS + # server that QEMU provides (normally 10.0.2.3) + networking.nameservers = [ "8.8.8.8" ]; + + # The linux builder is a lightweight VM for remote building; not evaluation. + nix.channel.enable = false; + + # Deployment is by image. + # TODO system.switch.enable = false;? + system.disableInstallerTools = true; + + nix.settings = { + auto-optimise-store = true; + + min-free = cfg.min-free; + + max-free = cfg.max-free; + + trusted-users = [ user ]; + }; + + services = { + getty.autologinUser = user; + + openssh = { + enable = true; + + authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ]; + }; + }; + + system.build.macos-builder-installer = + let + privateKey = "/etc/nix/${user}_${keyType}"; + + publicKey = "${privateKey}.pub"; + + # This installCredentials script is written so that it's as easy as + # possible for a user to audit before confirming the `sudo` + installCredentials = hostPkgs.writeShellScript "install-credentials" '' + set -euo pipefail + + KEYS="''${1}" + INSTALL=${hostPkgs.coreutils}/bin/install + "''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey} + "''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey} + ''; + + hostPkgs = config.virtualisation.host.pkgs; + + script = hostPkgs.writeShellScriptBin "create-builder" ( + '' + set -euo pipefail + '' + + + # When running as non-interactively as part of a DarwinConfiguration the working directory + # must be set to a writeable directory. + ( + if cfg.workingDirectory != "." then + '' + ${hostPkgs.coreutils}/bin/mkdir --parent "${cfg.workingDirectory}" + cd "${cfg.workingDirectory}" + '' + else + "" + ) + + '' + KEYS="''${KEYS:-./keys}" + ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}" + PRIVATE_KEY="''${KEYS}/${user}_${keyType}" + PUBLIC_KEY="''${PRIVATE_KEY}.pub" + if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then + ${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}" + ${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost' + fi + if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then + (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}") + fi + KEYS="$(${hostPkgs.nix}/bin/nix-store --add "$KEYS")" ${lib.getExe config.system.build.vm} + '' + ); + + in + script.overrideAttrs (old: { + pos = __curPos; # sets meta.position to point here; see script binding above for package definition + meta = (old.meta or { }) // { + platforms = lib.platforms.darwin; + }; + passthru = (old.passthru or { }) // { + # Let users in the repl inspect the config + nixosConfig = config; + nixosOptions = options; + }; + }); + + system = { + # To prevent gratuitous rebuilds on each change to Nixpkgs + nixos.revision = null; + + # to be updated by module maintainers, see nixpkgs#325610 + stateVersion = "24.05"; + }; + + users.users."${user}" = { + isNormalUser = true; + }; + + security.polkit.enable = true; + + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if (action.id === "org.freedesktop.login1.power-off" && subject.user === "${user}") { + return "yes"; + } else { + return "no"; + } + }) + ''; + + virtualisation = { + diskSize = cfg.diskSize; + + memorySize = cfg.memorySize; + + forwardPorts = [ + { + from = "host"; + guest.port = 22; + host.port = cfg.hostPort; + } + ]; + + # Disable graphics for the builder since users will likely want to run it + # non-interactively in the background. + graphics = false; + + sharedDirectories.keys = { + source = "\"$KEYS\""; + target = keysDirectory; + }; + + # If we don't enable this option then the host will fail to delegate builds + # to the guest, because: + # + # - The host will lock the path to build + # - The host will delegate the build to the guest + # - The guest will attempt to lock the same path and fail because + # the lockfile on the host is visible on the guest + # + # Snapshotting the host's /nix/store as an image isolates the guest VM's + # /nix/store from the host's /nix/store, preventing this problem. + useNixStoreImage = true; + + # Obviously the /nix/store needs to be writable on the guest in order for it + # to perform builds. + writableStore = true; + + # This ensures that anything built on the guest isn't lost when the guest is + # restarted. + writableStoreUseTmpfs = false; + + # Pass certificates from host to the guest otherwise when custom CA certificates + # are required we can't use the cached builder. + useHostCerts = true; + }; + }; +} diff --git a/nixos/modules/profiles/perlless.nix b/nixos/modules/profiles/perlless.nix index f34c3d2d210b..c331a9088267 100644 --- a/nixos/modules/profiles/perlless.nix +++ b/nixos/modules/profiles/perlless.nix @@ -2,17 +2,10 @@ { - # switch-to-configuration-ng reimplements switch-to-configuration, but - # without perl. - system.switch = lib.mkDefault { - enable = false; - enableNg = true; - }; - # Remove perl from activation boot.initrd.systemd.enable = lib.mkDefault true; system.etc.overlay.enable = lib.mkDefault true; - systemd.sysusers.enable = lib.mkDefault true; + services.userborn.enable = lib.mkDefault true; # Random perl remnants system.disableInstallerTools = lib.mkDefault true; diff --git a/nixos/modules/programs/cdemu.nix b/nixos/modules/programs/cdemu.nix index 1aac28af1d2c..cdfab3ee9f39 100644 --- a/nixos/modules/programs/cdemu.nix +++ b/nixos/modules/programs/cdemu.nix @@ -60,7 +60,7 @@ in { systemd.user.services.cdemu-daemon.serviceConfig = { Type = "dbus"; BusName = "net.sf.cdemu.CDEmuDaemon"; - ExecStart = "${pkgs.cdemu-daemon}/bin/cdemu-daemon --config-file \"%h/.config/cdemu-daemon\""; + ExecStart = "${lib.getExe pkgs.cdemu-daemon} --config-file \"%h/.config/cdemu-daemon\""; Restart = "no"; }; diff --git a/nixos/modules/programs/clash-verge.nix b/nixos/modules/programs/clash-verge.nix index 4425fe1a9fe7..a2912cb1d8e0 100644 --- a/nixos/modules/programs/clash-verge.nix +++ b/nixos/modules/programs/clash-verge.nix @@ -1,9 +1,22 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: { options.programs.clash-verge = { enable = lib.mkEnableOption "Clash Verge"; - package = lib.mkPackageOption pkgs "clash-verge" {}; + package = lib.mkOption { + type = lib.types.package; + description = '' + The clash-verge package to use. Available options are + clash-verge-rev and clash-nyanpasu, both are forks of + the original clash-verge project. + ''; + example = "pkgs.clash-verge-rev"; + }; autoStart = lib.mkEnableOption "Clash Verge auto launch"; tunMode = lib.mkEnableOption "Clash Verge TUN mode"; }; @@ -16,10 +29,12 @@ environment.systemPackages = [ cfg.package - (lib.mkIf cfg.autoStart (pkgs.makeAutostartItem { - name = "clash-verge"; - package = cfg.package; - })) + (lib.mkIf cfg.autoStart ( + pkgs.makeAutostartItem { + name = "clash-verge"; + package = cfg.package; + } + )) ]; security.wrappers.clash-verge = lib.mkIf cfg.tunMode { diff --git a/nixos/modules/programs/firefox.nix b/nixos/modules/programs/firefox.nix index 7521708fa94f..ed874cad74e4 100644 --- a/nixos/modules/programs/firefox.nix +++ b/nixos/modules/programs/firefox.nix @@ -1,4 +1,9 @@ -{ pkgs, config, lib, ... }: +{ + pkgs, + config, + lib, + ... +}: let cfg = config.programs.firefox; @@ -78,7 +83,7 @@ in wrapperConfig = lib.mkOption { type = lib.types.attrs; - default = {}; + default = { }; description = "Arguments to pass to Firefox wrapper"; }; @@ -99,7 +104,13 @@ in }; preferences = lib.mkOption { - type = with lib.types; attrsOf (oneOf [ bool int str ]); + type = + with lib.types; + attrsOf (oneOf [ + bool + int + str + ]); default = { }; description = '' Preferences to set from `about:config`. @@ -112,7 +123,12 @@ in }; preferencesStatus = lib.mkOption { - type = lib.types.enum [ "default" "locked" "user" "clear" ]; + type = lib.types.enum [ + "default" + "locked" + "user" + "clear" + ]; default = "locked"; description = '' The status of `firefox.preferences`. @@ -127,111 +143,113 @@ in languagePacks = lib.mkOption { # Available languages can be found in https://releases.mozilla.org/pub/firefox/releases/${cfg.package.version}/linux-x86_64/xpi/ - type = lib.types.listOf (lib.types.enum ([ - "ach" - "af" - "an" - "ar" - "ast" - "az" - "be" - "bg" - "bn" - "br" - "bs" - "ca-valencia" - "ca" - "cak" - "cs" - "cy" - "da" - "de" - "dsb" - "el" - "en-CA" - "en-GB" - "en-US" - "eo" - "es-AR" - "es-CL" - "es-ES" - "es-MX" - "et" - "eu" - "fa" - "ff" - "fi" - "fr" - "fur" - "fy-NL" - "ga-IE" - "gd" - "gl" - "gn" - "gu-IN" - "he" - "hi-IN" - "hr" - "hsb" - "hu" - "hy-AM" - "ia" - "id" - "is" - "it" - "ja" - "ka" - "kab" - "kk" - "km" - "kn" - "ko" - "lij" - "lt" - "lv" - "mk" - "mr" - "ms" - "my" - "nb-NO" - "ne-NP" - "nl" - "nn-NO" - "oc" - "pa-IN" - "pl" - "pt-BR" - "pt-PT" - "rm" - "ro" - "ru" - "sat" - "sc" - "sco" - "si" - "sk" - "skr" - "sl" - "son" - "sq" - "sr" - "sv-SE" - "szl" - "ta" - "te" - "tg" - "th" - "tl" - "tr" - "trs" - "uk" - "ur" - "uz" - "vi" - "xh" - "zh-CN" - "zh-TW" - ])); + type = lib.types.listOf ( + lib.types.enum ([ + "ach" + "af" + "an" + "ar" + "ast" + "az" + "be" + "bg" + "bn" + "br" + "bs" + "ca-valencia" + "ca" + "cak" + "cs" + "cy" + "da" + "de" + "dsb" + "el" + "en-CA" + "en-GB" + "en-US" + "eo" + "es-AR" + "es-CL" + "es-ES" + "es-MX" + "et" + "eu" + "fa" + "ff" + "fi" + "fr" + "fur" + "fy-NL" + "ga-IE" + "gd" + "gl" + "gn" + "gu-IN" + "he" + "hi-IN" + "hr" + "hsb" + "hu" + "hy-AM" + "ia" + "id" + "is" + "it" + "ja" + "ka" + "kab" + "kk" + "km" + "kn" + "ko" + "lij" + "lt" + "lv" + "mk" + "mr" + "ms" + "my" + "nb-NO" + "ne-NP" + "nl" + "nn-NO" + "oc" + "pa-IN" + "pl" + "pt-BR" + "pt-PT" + "rm" + "ro" + "ru" + "sat" + "sc" + "sco" + "si" + "sk" + "skr" + "sl" + "son" + "sq" + "sr" + "sv-SE" + "szl" + "ta" + "te" + "tg" + "th" + "tl" + "tr" + "trs" + "uk" + "ur" + "uz" + "vi" + "xh" + "zh-CN" + "zh-TW" + ]) + ); default = [ ]; description = '' The language packs to install. @@ -249,10 +267,23 @@ in ''; }; + autoConfigFiles = lib.mkOption { + type = with lib.types; listOf path; + default = [ ]; + description = '' + AutoConfig files can be used to set and lock preferences that are not covered + by the policies.json for Mac and Linux. This method can be used to automatically + change user preferences or prevent the end user from modifiying specific + preferences by locking them. More info can be found in https://support.mozilla.org/en-US/kb/customizing-firefox-using-autoconfig. + + Files are concated and autoConfig is appended. + ''; + }; + nativeMessagingHosts = ({ packages = lib.mkOption { type = lib.types.listOf lib.types.package; - default = []; + default = [ ]; description = '' Additional packages containing native messaging hosts that should be made available to Firefox extensions. ''; @@ -260,48 +291,64 @@ in }) // (builtins.mapAttrs (k: v: lib.mkEnableOption "${v.name} support") nmhOptions); }; - config = let - forEachEnabledNmh = fn: lib.flatten (lib.mapAttrsToList (k: v: lib.optional cfg.nativeMessagingHosts.${k} (fn k v)) nmhOptions); - in lib.mkIf cfg.enable { - warnings = forEachEnabledNmh (k: v: - "The `programs.firefox.nativeMessagingHosts.${k}` option is deprecated, " + - "please add `${v.package.pname}` to `programs.firefox.nativeMessagingHosts.packages` instead." - ); - programs.firefox.nativeMessagingHosts.packages = forEachEnabledNmh (_: v: v.package); + config = + let + forEachEnabledNmh = + fn: + lib.flatten ( + lib.mapAttrsToList (k: v: lib.optional cfg.nativeMessagingHosts.${k} (fn k v)) nmhOptions + ); + in + lib.mkIf cfg.enable { + warnings = forEachEnabledNmh ( + k: v: + "The `programs.firefox.nativeMessagingHosts.${k}` option is deprecated, " + + "please add `${v.package.pname}` to `programs.firefox.nativeMessagingHosts.packages` instead." + ); + programs.firefox.nativeMessagingHosts.packages = forEachEnabledNmh (_: v: v.package); - environment.systemPackages = [ - (cfg.package.override (old: { - extraPrefsFiles = old.extraPrefsFiles or [] ++ [(pkgs.writeText "firefox-autoconfig.js" cfg.autoConfig)]; - nativeMessagingHosts = old.nativeMessagingHosts or [] ++ cfg.nativeMessagingHosts.packages; - cfg = (old.cfg or {}) // cfg.wrapperConfig; - })) - ]; + environment.systemPackages = [ + (cfg.package.override (old: { + extraPrefsFiles = + old.extraPrefsFiles or [ ] + ++ cfg.autoConfigFiles + ++ [ (pkgs.writeText "firefox-autoconfig.js" cfg.autoConfig) ]; + nativeMessagingHosts = old.nativeMessagingHosts or [ ] ++ cfg.nativeMessagingHosts.packages; + cfg = (old.cfg or { }) // cfg.wrapperConfig; + })) + ]; - environment.etc = - let - policiesJSON = policyFormat.generate "firefox-policies.json" { inherit (cfg) policies; }; - in - lib.mkIf (cfg.policies != { }) { - "firefox/policies/policies.json".source = "${policiesJSON}"; + environment.etc = + let + policiesJSON = policyFormat.generate "firefox-policies.json" { inherit (cfg) policies; }; + in + lib.mkIf (cfg.policies != { }) { + "firefox/policies/policies.json".source = "${policiesJSON}"; + }; + + # Preferences are converted into a policy + programs.firefox.policies = { + DisableAppUpdate = true; + Preferences = ( + builtins.mapAttrs (_: value: { + Value = value; + Status = cfg.preferencesStatus; + }) cfg.preferences + ); + ExtensionSettings = builtins.listToAttrs ( + builtins.map ( + lang: + lib.attrsets.nameValuePair "langpack-${lang}@firefox.mozilla.org" { + installation_mode = "normal_installed"; + install_url = "https://releases.mozilla.org/pub/firefox/releases/${cfg.package.version}/linux-x86_64/xpi/${lang}.xpi"; + } + ) cfg.languagePacks + ); }; - - # Preferences are converted into a policy - programs.firefox.policies = { - DisableAppUpdate = true; - Preferences = (builtins.mapAttrs - (_: value: { Value = value; Status = cfg.preferencesStatus; }) - cfg.preferences); - ExtensionSettings = builtins.listToAttrs (builtins.map - (lang: lib.attrsets.nameValuePair - "langpack-${lang}@firefox.mozilla.org" - { - installation_mode = "normal_installed"; - install_url = "https://releases.mozilla.org/pub/firefox/releases/${cfg.package.version}/linux-x86_64/xpi/${lang}.xpi"; - } - ) - cfg.languagePacks); }; - }; - meta.maintainers = with lib.maintainers; [ danth ]; + meta.maintainers = with lib.maintainers; [ + danth + linsui + ]; } diff --git a/nixos/modules/programs/foot/bashrc b/nixos/modules/programs/foot/bashrc new file mode 100644 index 000000000000..e35bc29f117b --- /dev/null +++ b/nixos/modules/programs/foot/bashrc @@ -0,0 +1,27 @@ +osc7_cwd() { + local strlen=${#PWD} + local encoded="" + local pos c o + for (( pos=0; pos for available themes. + ''; + example = "aeroroot"; + }; + + enableBashIntegration = lib.mkEnableOption "foot bash integration" // { + default = true; + }; + + enableFishIntegration = lib.mkEnableOption "foot fish integration" // { + default = true; + }; + + enableZshIntegration = lib.mkEnableOption "foot zsh integration" // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + environment = { + systemPackages = [ cfg.package ]; + etc."xdg/foot/foot.ini".source = settingsFormat.generate "foot.ini" cfg.settings; + }; + programs = { + foot.settings.main.include = lib.optionals (cfg.theme != null) [ + "${pkgs.foot.themes}/share/foot/themes/${cfg.theme}" + ]; + # https://codeberg.org/dnkl/foot/wiki#user-content-shell-integration + bash.interactiveShellInit = lib.mkIf cfg.enableBashIntegration ". ${./bashrc} # enable shell integration for foot terminal"; + fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration "source ${./config.fish} # enable shell integration for foot terminal"; + zsh.interactiveShellInit = lib.mkIf cfg.enableZshIntegration ". ${./zshrc} # enable shell integration for foot terminal"; + }; + }; + + meta = { + maintainers = with lib.maintainers; [ linsui ]; + }; +} diff --git a/nixos/modules/programs/foot/zshrc b/nixos/modules/programs/foot/zshrc new file mode 100644 index 000000000000..a1d652a80ca4 --- /dev/null +++ b/nixos/modules/programs/foot/zshrc @@ -0,0 +1,25 @@ +function osc7-pwd() { + emulate -L zsh # also sets localoptions for us + setopt extendedglob + local LC_ALL=C + printf '\e]7;file://%s%s\e\' $HOST ${PWD//(#m)([^@-Za-z&-;_~])/%${(l:2::0:)$(([##16]#MATCH))}} +} + +function chpwd-osc7-pwd() { + (( ZSH_SUBSHELL )) || osc7-pwd +} +add-zsh-hook -Uz chpwd chpwd-osc7-pwd + +precmd() { + print -Pn "\e]133;A\e\\" +} + +function precmd { + if ! builtin zle; then + print -n "\e]133;D\e\\" + fi +} + +function preexec { + print -n "\e]133;C\e\\" +} diff --git a/nixos/modules/programs/gamemode.nix b/nixos/modules/programs/gamemode.nix index 14892f9c6eac..bd3248c1c5a2 100644 --- a/nixos/modules/programs/gamemode.nix +++ b/nixos/modules/programs/gamemode.nix @@ -2,7 +2,7 @@ let cfg = config.programs.gamemode; - settingsFormat = pkgs.formats.ini { }; + settingsFormat = pkgs.formats.ini { listsAsDuplicateKeys = true; }; configFile = settingsFormat.generate "gamemode.ini" cfg.settings; in { diff --git a/nixos/modules/programs/gamescope.nix b/nixos/modules/programs/gamescope.nix index 6a0b0a8fbddd..ccd4fd448a8f 100644 --- a/nixos/modules/programs/gamescope.nix +++ b/nixos/modules/programs/gamescope.nix @@ -17,6 +17,7 @@ let mkdir -p $out/bin makeWrapper ${cfg.package}/bin/gamescope $out/bin/gamescope --inherit-argv0 \ ${builtins.toString wrapperArgs} + ln -s ${cfg.package}/bin/gamescopectl $out/bin/gamescopectl ''; in { diff --git a/nixos/modules/programs/gpu-screen-recorder.nix b/nixos/modules/programs/gpu-screen-recorder.nix index 39d0e2545241..5a9401943dfe 100644 --- a/nixos/modules/programs/gpu-screen-recorder.nix +++ b/nixos/modules/programs/gpu-screen-recorder.nix @@ -1,14 +1,20 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let cfg = config.programs.gpu-screen-recorder; package = cfg.package.override { inherit (config.security) wrapperDir; }; -in { +in +{ options = { programs.gpu-screen-recorder = { - package = lib.mkPackageOption pkgs "gpu-screen-recorder" {}; + package = lib.mkPackageOption pkgs "gpu-screen-recorder" { }; enable = lib.mkOption { type = lib.types.bool; @@ -28,12 +34,6 @@ in { capabilities = "cap_sys_admin+ep"; source = "${package}/bin/gsr-kms-server"; }; - security.wrappers."gpu-screen-recorder" = { - owner = "root"; - group = "root"; - capabilities = "cap_sys_nice+ep"; - source = "${package}/bin/gpu-screen-recorder"; - }; }; meta.maintainers = with lib.maintainers; [ timschumi ]; diff --git a/nixos/modules/programs/immersed-vr.nix b/nixos/modules/programs/immersed-vr.nix deleted file mode 100644 index 57edb3cbaea0..000000000000 --- a/nixos/modules/programs/immersed-vr.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: - -let - cfg = config.programs.immersed-vr; -in -{ - - options = { - programs.immersed-vr = { - enable = lib.mkEnableOption "immersed-vr"; - - package = lib.mkPackageOption pkgs "immersed-vr" {}; - }; - }; - - config = lib.mkIf cfg.enable { - boot = { - kernelModules = [ "v4l2loopback" "snd-aloop" ]; - extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; - extraModprobeConfig = '' - options v4l2loopback exclusive_caps=1 card_label="v4l2loopback Virtual Camera" - ''; - }; - - environment.systemPackages = [ cfg.package ]; - }; - - meta.maintainers = pkgs.immersed-vr.meta.maintainers; -} diff --git a/nixos/modules/programs/immersed.nix b/nixos/modules/programs/immersed.nix new file mode 100644 index 000000000000..0fb217b91d54 --- /dev/null +++ b/nixos/modules/programs/immersed.nix @@ -0,0 +1,49 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.programs.immersed; +in +{ + imports = [ + (lib.mkRenamedOptionModule + [ + "programs" + "immersed-vr" + ] + [ + "programs" + "immersed" + ] + ) + ]; + + options = { + programs.immersed = { + enable = lib.mkEnableOption "immersed"; + + package = lib.mkPackageOption pkgs "immersed" { }; + }; + }; + + config = lib.mkIf cfg.enable { + boot = { + kernelModules = [ + "v4l2loopback" + "snd-aloop" + ]; + extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; + extraModprobeConfig = '' + options v4l2loopback exclusive_caps=1 card_label="v4l2loopback Virtual Camera" + ''; + }; + + environment.systemPackages = [ cfg.package ]; + }; + + meta.maintainers = pkgs.immersed.meta.maintainers; +} diff --git a/nixos/modules/programs/mouse-actions.nix b/nixos/modules/programs/mouse-actions.nix index 73dc783e3100..297cc4d3bfe7 100644 --- a/nixos/modules/programs/mouse-actions.nix +++ b/nixos/modules/programs/mouse-actions.nix @@ -3,13 +3,39 @@ let cfg = config.programs.mouse-actions; in - { - options.programs.mouse-actions = { - enable = lib.mkEnableOption '' - mouse-actions udev rules. This is a prerequisite for using mouse-actions without being root +{ + options.programs.mouse-actions = { + enable = lib.mkEnableOption "" // { + description = '' + Whether to install and set up mouse-actions and it's udev rules. + + Note that only users in the "uinput" group will be able to use the package ''; }; - config = lib.mkIf cfg.enable { - services.udev.packages = [ pkgs.mouse-actions ]; + package = lib.mkPackageOption pkgs "mouse-actions" { + example = "mouse-actions-gui"; }; - } + autorun = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to start a user service to run mouse-actions on startup. + ''; + }; + }; + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + services.udev.packages = [ cfg.package ]; + systemd.user.services.mouse-actions = lib.mkIf cfg.autorun { + description = "mouse-actions launcher"; + wantedBy = [ "graphical-session.target" ]; + bindsTo = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + environment.PATH = lib.mkForce null; # don't use the default PATH provided by NixOS + serviceConfig = { + ExecStart = "${lib.getExe cfg.package} start"; + PassEnvironment = "PATH"; # inherit PATH from user environment + }; + }; + }; +} diff --git a/nixos/modules/programs/nautilus-open-any-terminal.nix b/nixos/modules/programs/nautilus-open-any-terminal.nix index ff0e77607b5e..41f26e03d312 100644 --- a/nixos/modules/programs/nautilus-open-any-terminal.nix +++ b/nixos/modules/programs/nautilus-open-any-terminal.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let cfg = config.programs.nautilus-open-any-terminal; @@ -22,15 +27,29 @@ in nautilus-python nautilus-open-any-terminal ]; + + environment.sessionVariables = lib.mkIf (!config.services.xserver.desktopManager.gnome.enable) { + NAUTILUS_4_EXTENSION_DIR = "${pkgs.nautilus-python}/lib/nautilus/extensions-4"; + }; + + environment.pathsToLink = [ + "/share/nautilus-python/extensions" + ]; + programs.dconf = lib.optionalAttrs (cfg.terminal != null) { enable = true; - profiles.user.databases = [{ - settings."com/github/stunkymonkey/nautilus-open-any-terminal".terminal = cfg.terminal; - lockAll = true; - }]; + profiles.user.databases = [ + { + settings."com/github/stunkymonkey/nautilus-open-any-terminal".terminal = cfg.terminal; + lockAll = true; + } + ]; }; }; meta = { - maintainers = with lib.maintainers; [ stunkymonkey linsui ]; + maintainers = with lib.maintainers; [ + stunkymonkey + linsui + ]; }; } diff --git a/nixos/modules/programs/nncp.nix b/nixos/modules/programs/nncp.nix index 3feccef4cf11..6ac0363e50a0 100644 --- a/nixos/modules/programs/nncp.nix +++ b/nixos/modules/programs/nncp.nix @@ -74,19 +74,13 @@ in { wantedBy = [ "basic.target" ]; serviceConfig.Type = "oneshot"; script = '' - umask u=rw - nncpCfgDir=$(mktemp --directory nncp.XXX) - for f in ${jsonCfgFile} ${builtins.toString config.programs.nncp.secrets}; do - tmpdir=$(mktemp --directory nncp.XXX) - nncp-cfgdir -cfg $f -dump $tmpdir - find $tmpdir -size 1c -delete - cp -a $tmpdir/* $nncpCfgDir/ - rm -rf $tmpdir - done - nncp-cfgdir -load $nncpCfgDir > ${nncpCfgFile} - rm -rf $nncpCfgDir + umask 127 + rm -f ${nncpCfgFile} + for f in ${jsonCfgFile} ${builtins.toString config.programs.nncp.secrets} + do + ${lib.getExe pkgs.hjson-go} -c <"$f" + done |${lib.getExe pkgs.jq} --slurp add >${nncpCfgFile} chgrp ${programCfg.group} ${nncpCfgFile} - chmod g+r ${nncpCfgFile} ''; }; }; diff --git a/nixos/modules/programs/obs-studio.nix b/nixos/modules/programs/obs-studio.nix new file mode 100644 index 000000000000..ee9ec520d1fb --- /dev/null +++ b/nixos/modules/programs/obs-studio.nix @@ -0,0 +1,64 @@ +{ + pkgs, + lib, + config, + ... +}: + +let + cfg = config.programs.obs-studio; +in +{ + options.programs.obs-studio = { + enable = lib.mkEnableOption "Free and open source software for video recording and live streaming"; + + package = lib.mkPackageOption pkgs "obs-studio" { example = "obs-studio"; }; + + finalPackage = lib.mkOption { + type = lib.types.package; + visible = false; + readOnly = true; + description = "Resulting customized OBS Studio package."; + }; + + plugins = lib.mkOption { + default = [ ]; + example = lib.literalExpression "[ pkgs.obs-studio-plugins.wlrobs ]"; + description = "Optional OBS plugins."; + type = lib.types.listOf lib.types.package; + }; + + enableVirtualCamera = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Installs and sets up the v4l2loopback kernel module, necessary for OBS + to start a virtual camera. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + programs.obs-studio.finalPackage = pkgs.wrapOBS.override { obs-studio = cfg.package; } { + plugins = cfg.plugins; + }; + + environment.systemPackages = [ cfg.finalPackage ]; + + boot = lib.mkIf cfg.enableVirtualCamera { + kernelModules = [ "v4l2loopback" ]; + extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; + + extraModprobeConfig = '' + options v4l2loopback devices=1 video_nr=1 card_label="OBS Cam" exclusive_caps=1 + ''; + }; + + security.polkit.enable = lib.mkIf cfg.enableVirtualCamera true; + }; + + meta.maintainers = with lib.maintainers; [ + CaptainJawZ + GaetanLepage + ]; +} diff --git a/nixos/modules/programs/pulseview.nix b/nixos/modules/programs/pulseview.nix new file mode 100644 index 000000000000..f8db5a467d53 --- /dev/null +++ b/nixos/modules/programs/pulseview.nix @@ -0,0 +1,28 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.programs.pulseview; +in +{ + options.programs.pulseview = { + enable = lib.mkEnableOption "pulseview, a sigrok GUI"; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + pkgs.pulseview + ]; + + services.udev = { + packages = [ + # Pulseview needs some udev rules provided by libsigrok to access devices + pkgs.libsigrok + ]; + }; + }; +} diff --git a/nixos/modules/programs/rust-motd.nix b/nixos/modules/programs/rust-motd.nix index 301b7cebb7f8..19f98868ee34 100644 --- a/nixos/modules/programs/rust-motd.nix +++ b/nixos/modules/programs/rust-motd.nix @@ -88,7 +88,7 @@ in { }; config = lib.mkIf cfg.enable { assertions = [ - { assertion = config.users.motd == null; + { assertion = config.users.motd == ""; message = '' `programs.rust-motd` is incompatible with `users.motd`! ''; diff --git a/nixos/modules/programs/steam.nix b/nixos/modules/programs/steam.nix index 2ee464dc22d3..dab8425721c5 100644 --- a/nixos/modules/programs/steam.nix +++ b/nixos/modules/programs/steam.nix @@ -31,7 +31,7 @@ in { default = pkgs.steam; defaultText = lib.literalExpression "pkgs.steam"; example = lib.literalExpression '' - pkgs.steam-small.override { + pkgs.steam.override { extraEnv = { MANGOHUD = true; OBS_VKCAPTURE = true; @@ -196,8 +196,9 @@ in { programs.gamescope.enable = lib.mkDefault cfg.gamescopeSession.enable; services.displayManager.sessionPackages = lib.mkIf cfg.gamescopeSession.enable [ gamescopeSessionFile ]; - # optionally enable 32bit pulseaudio support if pulseaudio is enabled + # enable 32bit pulseaudio/pipewire support if needed hardware.pulseaudio.support32Bit = config.hardware.pulseaudio.enable; + services.pipewire.alsa.support32Bit = config.services.pipewire.alsa.enable; hardware.steam-hardware.enable = true; diff --git a/nixos/modules/programs/streamcontroller.nix b/nixos/modules/programs/streamcontroller.nix new file mode 100644 index 000000000000..2f85d37625c8 --- /dev/null +++ b/nixos/modules/programs/streamcontroller.nix @@ -0,0 +1,22 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.programs.streamcontroller; +in +{ + options.programs.streamcontroller = { + enable = lib.mkEnableOption "StreamController"; + package = lib.mkPackageOption pkgs "streamcontroller" { default = [ "streamcontroller" ]; }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + services.udev.packages = [ cfg.package ]; + }; + + meta.maintainers = with lib.maintainers; [ sifmelcara ]; +} diff --git a/nixos/modules/programs/tsm-client.nix b/nixos/modules/programs/tsm-client.nix index a010bb6c6d57..1795db5c2470 100644 --- a/nixos/modules/programs/tsm-client.nix +++ b/nixos/modules/programs/tsm-client.nix @@ -22,7 +22,7 @@ let serverOptions = { name, config, ... }: { freeformType = attrsOf (either scalarType (listOf scalarType)); # Client system-options file directives are explained here: - # https://www.ibm.com/docs/en/storage-protect/8.1.23?topic=commands-processing-options + # https://www.ibm.com/docs/en/storage-protect/8.1.24?topic=commands-processing-options options.servername = mkOption { type = servernameType; default = name; diff --git a/nixos/modules/programs/wayland/cardboard.nix b/nixos/modules/programs/wayland/cardboard.nix index 5a25b5359c24..96089bdf94ed 100644 --- a/nixos/modules/programs/wayland/cardboard.nix +++ b/nixos/modules/programs/wayland/cardboard.nix @@ -19,6 +19,6 @@ in # To make a cardboard session available for certain DMs like SDDM services.displayManager.sessionPackages = [ cfg.package ]; } - (import ./wayland-session.nix { inherit lib; }) + (import ./wayland-session.nix { inherit lib pkgs; }) ]); } diff --git a/nixos/modules/programs/wayland/hyprland.nix b/nixos/modules/programs/wayland/hyprland.nix index f8b70af40600..6e69c1730e57 100644 --- a/nixos/modules/programs/wayland/hyprland.nix +++ b/nixos/modules/programs/wayland/hyprland.nix @@ -70,7 +70,7 @@ in } (import ./wayland-session.nix { - inherit lib; + inherit lib pkgs; enableXWayland = cfg.xwayland.enable; enableWlrPortal = lib.mkDefault false; # Hyprland has its own portal, wlr is not needed }) diff --git a/nixos/modules/programs/wayland/labwc.nix b/nixos/modules/programs/wayland/labwc.nix index 4c74b45bb4a3..c09ab8240d9f 100644 --- a/nixos/modules/programs/wayland/labwc.nix +++ b/nixos/modules/programs/wayland/labwc.nix @@ -20,6 +20,6 @@ in # To make a labwc session available for certain DMs like SDDM services.displayManager.sessionPackages = [ cfg.package ]; } - (import ./wayland-session.nix { inherit lib; }) + (import ./wayland-session.nix { inherit lib pkgs; }) ]); } diff --git a/nixos/modules/programs/wayland/miracle-wm.nix b/nixos/modules/programs/wayland/miracle-wm.nix index e20b62acb462..3cee538c8997 100644 --- a/nixos/modules/programs/wayland/miracle-wm.nix +++ b/nixos/modules/programs/wayland/miracle-wm.nix @@ -30,11 +30,12 @@ in } (import ./wayland-session.nix { - inherit lib; + inherit lib pkgs; # Hardcoded path in Mir, not really possible to disable enableXWayland = true; # No portal support yet: https://github.com/mattkae/miracle-wm/issues/164 enableWlrPortal = false; + enableGtkPortal = false; }) ] ); diff --git a/nixos/modules/programs/wayland/river.nix b/nixos/modules/programs/wayland/river.nix index da793a9ff344..6391f00e2f62 100644 --- a/nixos/modules/programs/wayland/river.nix +++ b/nixos/modules/programs/wayland/river.nix @@ -56,7 +56,7 @@ in } (import ./wayland-session.nix { - inherit lib; + inherit lib pkgs; enableXWayland = cfg.xwayland.enable; }) ]); diff --git a/nixos/modules/programs/wayland/sway.nix b/nixos/modules/programs/wayland/sway.nix index 8d43a3329f41..7c5f49ce6d79 100644 --- a/nixos/modules/programs/wayland/sway.nix +++ b/nixos/modules/programs/wayland/sway.nix @@ -123,12 +123,23 @@ in # Import the most important environment variables into the D-Bus and systemd # user environments (e.g. required for screen sharing and Pinentry prompts): exec dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP + # enable systemd-integration + exec "systemctl --user import-environment {,WAYLAND_}DISPLAY SWAYSOCK; systemctl --user start sway-session.target" + exec swaymsg -t subscribe '["shutdown"]' && systemctl --user stop sway-session.target ''; } // lib.optionalAttrs (cfg.package != null) { "sway/config".source = lib.mkOptionDefault "${cfg.package}/etc/sway/config"; }; }; + systemd.user.targets.sway-session = { + description = "sway compositor session"; + documentation = [ "man:systemd.special(7)" ]; + bindsTo = [ "graphical-session.target" ]; + wants = [ "graphical-session-pre.target" ]; + after = [ "graphical-session-pre.target" ]; + }; + # To make a Sway session available if a display manager like SDDM is enabled: services.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package; @@ -137,7 +148,7 @@ in } (import ./wayland-session.nix { - inherit lib; + inherit lib pkgs; enableXWayland = cfg.xwayland.enable; }) ]); diff --git a/nixos/modules/programs/wayland/uwsm.nix b/nixos/modules/programs/wayland/uwsm.nix new file mode 100644 index 000000000000..5497cc269ebe --- /dev/null +++ b/nixos/modules/programs/wayland/uwsm.nix @@ -0,0 +1,129 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.programs.uwsm; + + # Helper function to create desktop entry files for UWSM-managed compositors + mk_uwsm_desktop_entry = + opts: + (pkgs.writeTextFile { + name = "${opts.name}-uwsm"; + text = '' + [Desktop Entry] + Name=${opts.prettyName} (UWSM) + Comment=${opts.comment} + Exec=${lib.getExe cfg.package} start -S -F ${opts.binPath} + Type=Application + ''; + destination = "/share/wayland-sessions/${opts.name}-uwsm.desktop"; + derivationArgs = { + passthru.providedSessions = [ "${opts.name}-uwsm" ]; + }; + }); +in +{ + options.programs.uwsm = { + enable = lib.mkEnableOption '' + uwsm, which wraps standalone Wayland compositors with a set + of Systemd units on the fly. This essentially + binds the wayland compositor into `graphical-session-pre.target`, + `graphical-session.target`, `xdg-desktop-autostart.target`. + + This is useful for Wayland compositors like Hyprland, Sway, Wayfire, + etc. that do not start these targets and services on their own. + + ::: {.note} + You must configure `waylandCompositors` suboptions as well + so that UWSM knows which compositors to manage. + + Additionally, this by default uses `dbus-broker` as the dbus + implementation for better compatibility. If you dislike this behavior + you can set `services.dbus.implementation = lib.mkForce "dbus"` + in your configuration. + ::: + + If you are having trouble starting a service that depends on + `graphical-session.target`, while using a WM, enabling this option + might help + ''; + package = lib.mkPackageOption pkgs "uwsm" { }; + + waylandCompositors = lib.mkOption { + description = '' + Configuration for UWSM-managed Wayland Compositors. This + creates a desktop entry file which will be used by Display + Managers like GDM, to allow starting the UWSM managed session. + ''; + type = lib.types.attrsOf ( + lib.types.submodule ( + { ... }: + { + options = { + prettyName = lib.mkOption { + type = lib.types.str; + description = "The full name of the desktop entry file."; + example = "ExampleWaylandCompositor"; + }; + comment = lib.mkOption { + type = lib.types.str; + description = "The comment field of the desktop entry file."; + default = "An intelligent Wayland compositor managed by UWSM."; + }; + binPath = lib.mkOption { + type = lib.types.path; + description = '' + The wayland-compositor binary path that will be called by UWSM. + + It is recommended to use the `/run/current-system/sw/bin/` path + instead of `lib.getExe pkgs.` to avoid version mismatch + of the compositor used by UWSM and the one installed in the system. + ''; + example = "/run/current-system/sw/bin/ExampleCompositor"; + }; + }; + } + ) + ); + example = lib.literalExpression '' + hyprland = { + prettyName = "Hyprland"; + comment = "Hyprland compositor managed by UWSM"; + binPath = "/run/current-system/sw/bin/Hyprland"; + }; + sway = { + prettyName = "Sway"; + comment = "Sway compositor managed by UWSM"; + binPath = "/run/current-system/sw/bin/sway"; + }; + ''; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; + environment.pathsToLink = [ "/share/uwsm" ]; + + services.graphical-desktop.enable = true; + + # UWSM recommends dbus broker for better compatibility + services.dbus.implementation = "broker"; + + services.displayManager.sessionPackages = lib.mapAttrsToList ( + name: value: + mk_uwsm_desktop_entry { + inherit name; + inherit (value) prettyName comment binPath; + } + ) cfg.waylandCompositors; + }; + + meta.maintainers = with lib.maintainers; [ + johnrtitor + kai-tub + ]; +} diff --git a/nixos/modules/programs/wayland/waybar.nix b/nixos/modules/programs/wayland/waybar.nix index ab811994be07..074537ea9ed3 100644 --- a/nixos/modules/programs/wayland/waybar.nix +++ b/nixos/modules/programs/wayland/waybar.nix @@ -1,4 +1,9 @@ -{ lib, pkgs, config, ... }: +{ + lib, + pkgs, + config, + ... +}: let cfg = config.programs.waybar; @@ -6,16 +11,18 @@ in { options.programs.waybar = { enable = lib.mkEnableOption "waybar, a highly customizable Wayland bar for Sway and Wlroots based compositors"; - package = lib.mkPackageOption pkgs "waybar" { }; + package = + lib.mkPackageOption pkgs "waybar" { } + // lib.mkOption { + apply = pkg: pkg.override { systemdSupport = true; }; + }; }; config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; - systemd.user.services.waybar = { - description = "Waybar as systemd service"; - wantedBy = [ "graphical-session.target" ]; - partOf = [ "graphical-session.target" ]; - script = "${cfg.package}/bin/waybar"; + systemd = { + packages = [ cfg.package ]; + user.services.waybar.wantedBy = [ "graphical-session.target" ]; }; }; diff --git a/nixos/modules/programs/wayland/wayfire.nix b/nixos/modules/programs/wayland/wayfire.nix index 726300ce5381..1c3950bff47d 100644 --- a/nixos/modules/programs/wayland/wayfire.nix +++ b/nixos/modules/programs/wayland/wayfire.nix @@ -63,7 +63,7 @@ in }; } (import ./wayland-session.nix { - inherit lib; + inherit lib pkgs; enableXWayland = cfg.xwayland.enable; }) ] diff --git a/nixos/modules/programs/wayland/wayland-session.nix b/nixos/modules/programs/wayland/wayland-session.nix index b3d6cc368b20..1f5dc413d377 100644 --- a/nixos/modules/programs/wayland/wayland-session.nix +++ b/nixos/modules/programs/wayland/wayland-session.nix @@ -1,7 +1,9 @@ { lib, + pkgs, enableXWayland ? true, enableWlrPortal ? true, + enableGtkPortal ? true, }: { @@ -18,6 +20,9 @@ services.graphical-desktop.enable = true; xdg.portal.wlr.enable = enableWlrPortal; + xdg.portal.extraPortals = lib.mkIf enableGtkPortal [ + pkgs.xdg-desktop-portal-gtk + ]; # Window manager only sessions (unlike DEs) don't handle XDG # autostart files, so force them to run the service diff --git a/nixos/modules/programs/yubikey-touch-detector.nix b/nixos/modules/programs/yubikey-touch-detector.nix index 9a0d107f73c9..42beabbc4e94 100644 --- a/nixos/modules/programs/yubikey-touch-detector.nix +++ b/nixos/modules/programs/yubikey-touch-detector.nix @@ -1,9 +1,44 @@ -{ config, lib, pkgs, ... }: -let cfg = config.programs.yubikey-touch-detector; -in { +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) types; + cfg = config.programs.yubikey-touch-detector; +in +{ options = { programs.yubikey-touch-detector = { + enable = lib.mkEnableOption "yubikey-touch-detector"; + + libnotify = lib.mkOption { + # This used to be true previously and using libnotify would be a sane default. + default = true; + type = types.bool; + description = '' + If set to true, yubikey-touch-detctor will send notifications using libnotify + ''; + }; + + unixSocket = lib.mkOption { + default = true; + type = types.bool; + description = '' + If set to true, yubikey-touch-detector will send notifications to a unix socket + ''; + }; + + verbose = lib.mkOption { + default = false; + type = types.bool; + description = '' + Enables verbose logging + ''; + }; + }; }; @@ -12,6 +47,13 @@ in { systemd.user.services.yubikey-touch-detector = { path = [ pkgs.gnupg ]; + + environment = { + YUBIKEY_TOUCH_DETECTOR_LIBNOTIFY = builtins.toString cfg.libnotify; + YUBIKEY_TOUCH_DETECTOR_NOSOCKET = builtins.toString (!cfg.unixSocket); + YUBIKEY_TOUCH_DETECTOR_VERBOSE = builtins.toString cfg.verbose; + }; + wantedBy = [ "graphical-session.target" ]; }; systemd.user.sockets.yubikey-touch-detector = { diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 374d127198d0..762c3ddbae9a 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -21,6 +21,10 @@ in # Completely removed modules (mkRemovedOptionModule [ "environment" "blcr" "enable" ] "The BLCR module has been removed") + (mkRemovedOptionModule [ "environment" "noXlibs" ] '' + The environment.noXlibs option was removed, as it often caused surprising breakages for new users. + If you need its functionality, you can apply similar overlays in your own config. + '') (mkRemovedOptionModule [ "fonts" "fontconfig" "penultimate" ] "The corresponding package has removed from nixpkgs.") (mkRemovedOptionModule [ "hardware" "brightnessctl" ] '' The brightnessctl module was removed because newer versions of @@ -51,6 +55,8 @@ in The hidepid module was removed, since the underlying machinery is broken when using cgroups-v2. '') + (mkRemovedOptionModule [ "services" "antennas" ] "The antennas package and the corresponding module have been removed as they only work with tvheadend, which nobody was willing to maintain and was stuck on an unmaintained version that required FFmpeg 4; please see https://github.com/NixOS/nixpkgs/pull/332259 if you are interested in maintaining a newer version.") + (mkRemovedOptionModule [ "services" "ankisyncd" ] "`services.ankisyncd` has been replaced by `services.anki-sync-server`.") (mkRemovedOptionModule [ "services" "baget" "enable" ] "The baget module was removed due to the upstream package being unmaintained.") (mkRemovedOptionModule [ "services" "beegfs" ] "The BeeGFS module has been removed") (mkRemovedOptionModule [ "services" "beegfsEnable" ] "The BeeGFS module has been removed") @@ -59,6 +65,12 @@ in (mkRemovedOptionModule [ "services" "couchpotato" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "dd-agent" ] "dd-agent was removed from nixpkgs in favor of the newer datadog-agent.") (mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead") + (mkRemovedOptionModule [ "services" "dnscrypt-wrapper" ] '' + The dnscrypt-wrapper module was removed since the project has been effectively unmaintained since 2018; + moreover the NixOS module had to rely on an abandoned version of dnscrypt-proxy v1 for the rotation of keys. + + To wrap a resolver with DNSCrypt you can instead use dnsdist. See options `services.dnsdist.dnscrypt.*` + '') (mkRemovedOptionModule [ "services" "exhibitor" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "firefox" "syncserver" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.") @@ -66,6 +78,7 @@ in (mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed") (mkRemovedOptionModule [ "services" "fprot" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "frab" ] "The frab module has been removed") + (mkRemovedOptionModule [ "services" "globalprotect"] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "homeassistant-satellite"] "The `services.homeassistant-satellite` module has been replaced by `services.wyoming-satellite`.") (mkRemovedOptionModule [ "services" "hydron" ] "The `services.hydron` module has been removed as the project has been archived upstream since 2022 and is affected by a severe remote code execution vulnerability.") (mkRemovedOptionModule [ "services" "ihatemoney" ] "The ihatemoney module has been removed for lack of downstream maintainer") @@ -94,6 +107,8 @@ in the program being unmaintained. The options `programs.msmtp.*` can be used instead. '') + (mkRemovedOptionModule [ "services" "tvheadend" ] "The tvheadend package and the corresponding module have been removed as nobody was willing to maintain them and they were stuck on an unmaintained version that required FFmpeg 4; please see https://github.com/NixOS/nixpkgs/pull/332259 if you are interested in maintaining a newer version.") + (mkRemovedOptionModule [ "services" "unifi-video" ] "The unifi-video package and the corresponding module have been removed as the software has been unsupported since 2021 and requires a MongoDB version that has reached end of life.") (mkRemovedOptionModule [ "services" "venus" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "wakeonlan"] "This module was removed in favor of enabling it with networking.interfaces..wakeOnLan") (mkRemovedOptionModule [ "services" "winstone" ] "The corresponding package was removed from nixpkgs.") diff --git a/nixos/modules/security/acme/default.nix b/nixos/modules/security/acme/default.nix index 83581d02840e..a9cb396f13fd 100644 --- a/nixos/modules/security/acme/default.nix +++ b/nixos/modules/security/acme/default.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, options, ... }: -with lib; let @@ -8,11 +7,11 @@ let user = if cfg.useRoot then "root" else "acme"; # Used to calculate timer accuracy for coalescing - numCerts = length (builtins.attrNames cfg.certs); + numCerts = lib.length (builtins.attrNames cfg.certs); _24hSecs = 60 * 60 * 24; # Used to make unique paths for each cert/account config set - mkHash = with builtins; val: substring 0 20 (hashString "sha256" val); + mkHash = with builtins; val: lib.substring 0 20 (hashString "sha256" val); mkAccountHash = acmeServer: data: mkHash "${toString acmeServer} ${data.keyType} ${data.email}"; accountDirRoot = "/var/lib/acme/.lego/accounts/"; @@ -29,7 +28,7 @@ let else [{ fst = head workingBaseList; snd = head needAssignmentList;}] ++ _rrCycler origBaseList (if (tail workingBaseList == []) then origBaseList else tail workingBaseList) (tail needAssignmentList); - attrsToList = mapAttrsToList (attrname: attrval: {name = attrname; value = attrval;}); + attrsToList = lib.mapAttrsToList (attrname: attrval: {name = attrname; value = attrval;}); # for an AttrSet `funcsAttrs` having functions as values, apply single arguments from # `argsList` to them in a round-robin manner. # Returns an attribute set with the applied functions as values. @@ -57,7 +56,7 @@ let commonServiceConfig = { Type = "oneshot"; User = user; - Group = mkDefault "acme"; + Group = lib.mkDefault "acme"; UMask = "0022"; StateDirectoryMode = "750"; ProtectSystem = "strict"; @@ -136,8 +135,8 @@ let userMigrationService = let script = with builtins; '' chown -R ${user} .lego/accounts - '' + (concatStringsSep "\n" (mapAttrsToList (cert: data: '' - for fixpath in ${escapeShellArg cert} .lego/${escapeShellArg cert}; do + '' + (lib.concatStringsSep "\n" (lib.mapAttrsToList (cert: data: '' + for fixpath in ${lib.escapeShellArg cert} .lego/${lib.escapeShellArg cert}; do if [ -d "$fixpath" ]; then chmod -R u=rwX,g=rX,o= "$fixpath" chown -R ${user}:${data.group} "$fixpath" @@ -166,8 +165,8 @@ let # ensure all required lock files exist, but none more script = '' - GLOBIGNORE="${concatStringsSep ":" concurrencyLockfiles}" - rm -f * + GLOBIGNORE="${lib.concatStringsSep ":" concurrencyLockfiles}" + rm -f -- * unset GLOBIGNORE xargs touch <<< "${toString concurrencyLockfiles}" @@ -186,7 +185,7 @@ let useDns = data.dnsProvider != null; useDnsOrS3 = useDns || data.s3Bucket != null; destPath = "/var/lib/acme/${cert}"; - selfsignedDeps = optionals (cfg.preliminarySelfsigned) [ "acme-selfsigned-${cert}.service" ]; + selfsignedDeps = lib.optionals (cfg.preliminarySelfsigned) [ "acme-selfsigned-${cert}.service" ]; # Minica and lego have a "feature" which replaces * with _. We need # to make this substitution to reference the output files from both programs. @@ -196,7 +195,7 @@ let # FIXME when mkChangedOptionModule supports submodules, change to that. # This is a workaround extraDomains = data.extraDomainNames ++ ( - optionals + lib.optionals (data.extraDomains != "_mkMergedOptionModule") (builtins.attrNames data.extraDomains) ); @@ -204,22 +203,22 @@ let # Create hashes for cert data directories based on configuration # Flags are separated to avoid collisions hashData = with builtins; '' - ${concatStringsSep " " data.extraLegoFlags} - - ${concatStringsSep " " data.extraLegoRunFlags} - - ${concatStringsSep " " data.extraLegoRenewFlags} - + ${lib.concatStringsSep " " data.extraLegoFlags} - + ${lib.concatStringsSep " " data.extraLegoRunFlags} - + ${lib.concatStringsSep " " data.extraLegoRenewFlags} - ${toString acmeServer} ${toString data.dnsProvider} ${toString data.ocspMustStaple} ${data.keyType} ''; certDir = mkHash hashData; # TODO remove domainHash usage entirely. Waiting on go-acme/lego#1532 - domainHash = mkHash "${concatStringsSep " " extraDomains} ${data.domain}"; + domainHash = mkHash "${lib.concatStringsSep " " extraDomains} ${data.domain}"; accountHash = (mkAccountHash acmeServer data); accountDir = accountDirRoot + accountHash; protocolOpts = if useDns then ( [ "--dns" data.dnsProvider ] - ++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ] - ++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ] + ++ lib.optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ] + ++ lib.optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ] ) else if data.s3Bucket != null then [ "--http" "--http.s3-bucket" data.s3Bucket ] else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ] else [ "--http" "--http.webroot" data.webroot ]; @@ -231,22 +230,22 @@ let "--email" data.email "--key-type" data.keyType ] ++ protocolOpts - ++ optionals (acmeServer != null) [ "--server" acmeServer ] - ++ concatMap (name: [ "-d" name ]) extraDomains + ++ lib.optionals (acmeServer != null) [ "--server" acmeServer ] + ++ lib.concatMap (name: [ "-d" name ]) extraDomains ++ data.extraLegoFlags; # Although --must-staple is common to both modes, it is not declared as a # mode-agnostic argument in lego and thus must come after the mode. - runOpts = escapeShellArgs ( + runOpts = lib.escapeShellArgs ( commonOpts ++ [ "run" ] - ++ optionals data.ocspMustStaple [ "--must-staple" ] + ++ lib.optionals data.ocspMustStaple [ "--must-staple" ] ++ data.extraLegoRunFlags ); - renewOpts = escapeShellArgs ( + renewOpts = lib.escapeShellArgs ( commonOpts ++ [ "renew" "--no-random-sleep" ] - ++ optionals data.ocspMustStaple [ "--must-staple" ] + ++ lib.optionals data.ocspMustStaple [ "--must-staple" ] ++ data.extraLegoRenewFlags ); @@ -286,8 +285,8 @@ let selfsignService = lockfileName: { description = "Generate self-signed certificate for ${cert}"; - after = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ] ++ optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; - requires = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ] ++ optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; + after = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ] ++ lib.optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; + requires = [ "acme-selfsigned-ca.service" "acme-fixperms.service" ] ++ lib.optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; path = with pkgs; [ minica ]; @@ -315,7 +314,7 @@ let minica \ --ca-key ca/key.pem \ --ca-cert ca/cert.pem \ - --domains ${escapeShellArg (builtins.concatStringsSep "," ([ data.domain ] ++ extraDomains))} + --domains ${lib.escapeShellArg (builtins.concatStringsSep "," ([ data.domain ] ++ extraDomains))} # Create files to match directory layout for real certificates cd '${keyName}' @@ -324,28 +323,28 @@ let cat key.pem fullchain.pem > full.pem # Group might change between runs, re-apply it - chown '${user}:${data.group}' * + chown '${user}:${data.group}' -- * # Default permissions make the files unreadable by group + anon # Need to be readable by group - chmod 640 * + chmod 640 -- * ''; }; renewService = lockfileName: { description = "Renew ACME certificate for ${cert}"; - after = [ "network.target" "network-online.target" "acme-fixperms.service" "nss-lookup.target" ] ++ selfsignedDeps ++ optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; - wants = [ "network-online.target" "acme-fixperms.service" ] ++ selfsignedDeps ++ optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; + after = [ "network.target" "network-online.target" "acme-fixperms.service" "nss-lookup.target" ] ++ selfsignedDeps ++ lib.optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; + wants = [ "network-online.target" "acme-fixperms.service" ] ++ selfsignedDeps ++ lib.optional (cfg.maxConcurrentRenewals > 0) "acme-lockfiles.service"; # https://github.com/NixOS/nixpkgs/pull/81371#issuecomment-605526099 - wantedBy = optionals (!config.boot.isContainer) [ "multi-user.target" ]; + wantedBy = lib.optionals (!config.boot.isContainer) [ "multi-user.target" ]; path = with pkgs; [ lego coreutils diffutils openssl ]; serviceConfig = commonServiceConfig // { Group = data.group; - # Let's Encrypt Failed Validation Limit allows 5 retries per hour, per account, hostname and hour. + # Let's Encrypt Failed Validation Limit allows 5 retries per hour, per account, hostname and hour. # This avoids eating them all up if something is misconfigured upon the first try. RestartSec = 15 * 60; @@ -368,33 +367,33 @@ let "/var/lib/acme/.lego/${cert}/${certDir}:/tmp/certificates" ]; - EnvironmentFile = mkIf useDnsOrS3 data.environmentFile; + EnvironmentFile = lib.mkIf useDnsOrS3 data.environmentFile; - Environment = mkIf useDnsOrS3 - (mapAttrsToList (k: v: ''"${k}=%d/${k}"'') data.credentialFiles); + Environment = lib.mkIf useDnsOrS3 + (lib.mapAttrsToList (k: v: ''"${k}=%d/${k}"'') data.credentialFiles); - LoadCredential = mkIf useDnsOrS3 - (mapAttrsToList (k: v: "${k}:${v}") data.credentialFiles); + LoadCredential = lib.mkIf useDnsOrS3 + (lib.mapAttrsToList (k: v: "${k}:${v}") data.credentialFiles); # Run as root (Prefixed with +) ExecStartPost = "+" + (pkgs.writeShellScript "acme-postrun" '' - cd /var/lib/acme/${escapeShellArg cert} + cd /var/lib/acme/${lib.escapeShellArg cert} if [ -e renewed ]; then rm renewed ${data.postRun} - ${optionalString (data.reloadServices != []) - "systemctl --no-block try-reload-or-restart ${escapeShellArgs data.reloadServices}" + ${lib.optionalString (data.reloadServices != []) + "systemctl --no-block try-reload-or-restart ${lib.escapeShellArgs data.reloadServices}" } fi ''); - } // optionalAttrs (data.listenHTTP != null && toInt (last (splitString ":" data.listenHTTP)) < 1024) { + } // lib.optionalAttrs (data.listenHTTP != null && lib.toInt (lib.last (lib.splitString ":" data.listenHTTP)) < 1024) { CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; }; # Working directory will be /tmp script = (if (lockfileName == null) then lib.id else wrapInFlock "${lockdir}${lockfileName}") '' - ${optionalString data.enableDebugLogs "set -x"} + ${lib.optionalString data.enableDebugLogs "set -x"} set -euo pipefail # This reimplements the expiration date check, but without querying @@ -411,7 +410,7 @@ let expiration_line="$( set -euxo pipefail - openssl x509 -noout -enddate <$pem \ + openssl x509 -noout -enddate <"$pem" \ | grep notAfter \ | sed -e 's/^notAfter=//' )" @@ -419,13 +418,13 @@ let expiration_date="$(date -d "$expiration_line" +%s)" now="$(date +%s)" - expiration_s=$[expiration_date - now] - expiration_days=$[expiration_s / (3600 * 24)] # rounds down + expiration_s=$((expiration_date - now)) + expiration_days=$((expiration_s / (3600 * 24))) # rounds down [[ $expiration_days -gt ${toString data.validMinDays} ]] } - ${optionalString (data.webroot != null) '' + ${lib.optionalString (data.webroot != null) '' # Ensure the webroot exists. Fixing group is required in case configuration was changed between runs. # Lego will fail if the webroot does not exist at all. ( @@ -442,7 +441,7 @@ let # Check if we can renew. # We can only renew if the list of domains has not changed. # We also need an account key. Avoids #190493 - if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(find accounts -name '${data.email}.key')" ]; then + if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' ] && [ -e 'certificates/${keyName}.crt' ] && [ -n "$(find accounts -name '${data.email}.key')" ]; then # Even if a cert is not expired, it may be revoked by the CA. # Try to renew, and silently fail if the cert is not expired. @@ -461,7 +460,7 @@ let # Produce a nice error for those doing their first nixos-rebuild with these certs echo Failed to fetch certificates. \ This may mean your DNS records are set up incorrectly. \ - ${optionalString (cfg.preliminarySelfsigned) "Selfsigned certs are in place and dependant services will still start."} + ${lib.optionalString (cfg.preliminarySelfsigned) "Selfsigned certs are in place and dependant services will still start."} # Exit 10 so that users can potentially amend SuccessExitStatus to ignore this error. # High number to avoid Systemd reserved codes. exit 10 @@ -490,7 +489,7 @@ let }; }; - certConfigs = mapAttrs certToConfig cfg.certs; + certConfigs = lib.mapAttrs certToConfig cfg.certs; # These options can be specified within # security.acme.defaults or security.acme.certs. @@ -504,22 +503,22 @@ let # stay constant. Though notably it wouldn't matter much, because to get # the option information, a submodule with name `` is evaluated # without any definitions. - defaultText = if isDefaults then default else literalExpression "config.security.acme.defaults.${name}"; + defaultText = if isDefaults then default else lib.literalExpression "config.security.acme.defaults.${name}"; }; in { imports = [ - (mkRenamedOptionModule [ "credentialsFile" ] [ "environmentFile" ]) + (lib.mkRenamedOptionModule [ "credentialsFile" ] [ "environmentFile" ]) ]; options = { - validMinDays = mkOption { - type = types.int; + validMinDays = lib.mkOption { + type = lib.types.int; inherit (defaultAndText "validMinDays" 30) default defaultText; description = "Minimum remaining validity before renewal in days."; }; - renewInterval = mkOption { - type = types.str; + renewInterval = lib.mkOption { + type = lib.types.str; inherit (defaultAndText "renewInterval" "daily") default defaultText; description = '' Systemd calendar expression when to check for renewal. See @@ -527,12 +526,12 @@ let ''; }; - enableDebugLogs = mkEnableOption "debug logging for this certificate" // { + enableDebugLogs = lib.mkEnableOption "debug logging for this certificate" // { inherit (defaultAndText "enableDebugLogs" true) default defaultText; }; - webroot = mkOption { - type = types.nullOr types.str; + webroot = lib.mkOption { + type = lib.types.nullOr lib.types.str; inherit (defaultAndText "webroot" null) default defaultText; example = "/var/lib/acme/acme-challenge"; description = '' @@ -544,8 +543,8 @@ let ''; }; - server = mkOption { - type = types.nullOr types.str; + server = lib.mkOption { + type = lib.types.nullOr lib.types.str; inherit (defaultAndText "server" "https://acme-v02.api.letsencrypt.org/directory") default defaultText; example = "https://acme-staging-v02.api.letsencrypt.org/directory"; description = '' @@ -556,8 +555,8 @@ let ''; }; - email = mkOption { - type = types.nullOr types.str; + email = lib.mkOption { + type = lib.types.nullOr lib.types.str; inherit (defaultAndText "email" null) default defaultText; description = '' Email address for account creation and correspondence from the CA. @@ -566,14 +565,14 @@ let ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; inherit (defaultAndText "group" "acme") default defaultText; description = "Group running the ACME client."; }; - reloadServices = mkOption { - type = types.listOf types.str; + reloadServices = lib.mkOption { + type = lib.types.listOf lib.types.str; inherit (defaultAndText "reloadServices" []) default defaultText; description = '' The list of systemd services to call `systemctl try-reload-or-restart` @@ -581,8 +580,8 @@ let ''; }; - postRun = mkOption { - type = types.lines; + postRun = lib.mkOption { + type = lib.types.lines; inherit (defaultAndText "postRun" "") default defaultText; example = "cp full.pem backup.pem"; description = '' @@ -593,8 +592,8 @@ let ''; }; - keyType = mkOption { - type = types.str; + keyType = lib.mkOption { + type = lib.types.str; inherit (defaultAndText "keyType" "ec256") default defaultText; description = '' Key type to use for private keys. @@ -603,8 +602,8 @@ let ''; }; - dnsProvider = mkOption { - type = types.nullOr types.str; + dnsProvider = lib.mkOption { + type = lib.types.nullOr lib.types.str; inherit (defaultAndText "dnsProvider" null) default defaultText; example = "route53"; description = '' @@ -613,8 +612,8 @@ let ''; }; - dnsResolver = mkOption { - type = types.nullOr types.str; + dnsResolver = lib.mkOption { + type = lib.types.nullOr lib.types.str; inherit (defaultAndText "dnsResolver" null) default defaultText; example = "1.1.1.1:53"; description = '' @@ -624,8 +623,8 @@ let ''; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; inherit (defaultAndText "environmentFile" null) default defaultText; description = '' Path to an EnvironmentFile for the cert's service containing any required and @@ -636,8 +635,8 @@ let example = "/var/src/secrets/example.org-route53-api-token"; }; - credentialFiles = mkOption { - type = types.attrsOf (types.path); + credentialFiles = lib.mkOption { + type = lib.types.attrsOf (lib.types.path); inherit (defaultAndText "credentialFiles" {}) default defaultText; description = '' Environment variables suffixed by "_FILE" to set for the cert's service @@ -647,15 +646,15 @@ let This allows to securely pass credential files to lego by leveraging systemd credentials. ''; - example = literalExpression '' + example = lib.literalExpression '' { "RFC2136_TSIG_SECRET_FILE" = "/run/secrets/tsig-secret-example.org"; } ''; }; - dnsPropagationCheck = mkOption { - type = types.bool; + dnsPropagationCheck = lib.mkOption { + type = lib.types.bool; inherit (defaultAndText "dnsPropagationCheck" true) default defaultText; description = '' Toggles lego DNS propagation check, which is used alongside DNS-01 @@ -663,8 +662,8 @@ let ''; }; - ocspMustStaple = mkOption { - type = types.bool; + ocspMustStaple = lib.mkOption { + type = lib.types.bool; inherit (defaultAndText "ocspMustStaple" false) default defaultText; description = '' Turns on the OCSP Must-Staple TLS extension. @@ -675,24 +674,24 @@ let ''; }; - extraLegoFlags = mkOption { - type = types.listOf types.str; + extraLegoFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; inherit (defaultAndText "extraLegoFlags" []) default defaultText; description = '' Additional global flags to pass to all lego commands. ''; }; - extraLegoRenewFlags = mkOption { - type = types.listOf types.str; + extraLegoRenewFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; inherit (defaultAndText "extraLegoRenewFlags" []) default defaultText; description = '' Additional flags to pass to lego renew. ''; }; - extraLegoRunFlags = mkOption { - type = types.listOf types.str; + extraLegoRunFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; inherit (defaultAndText "extraLegoRunFlags" []) default defaultText; description = '' Additional flags to pass to lego run. @@ -704,40 +703,40 @@ let certOpts = { name, config, ... }: { options = { # user option has been removed - user = mkOption { + user = lib.mkOption { visible = false; default = "_mkRemovedOptionModule"; }; # allowKeysForGroup option has been removed - allowKeysForGroup = mkOption { + allowKeysForGroup = lib.mkOption { visible = false; default = "_mkRemovedOptionModule"; }; # extraDomains was replaced with extraDomainNames - extraDomains = mkOption { + extraDomains = lib.mkOption { visible = false; default = "_mkMergedOptionModule"; }; - directory = mkOption { - type = types.str; + directory = lib.mkOption { + type = lib.types.str; readOnly = true; default = "/var/lib/acme/${name}"; description = "Directory where certificate and other state is stored."; }; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; default = name; description = "Domain to fetch certificate for (defaults to the entry name)."; }; - extraDomainNames = mkOption { - type = types.listOf types.str; + extraDomainNames = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; - example = literalExpression '' + example = lib.literalExpression '' [ "example.org" "mydomain.org" @@ -751,8 +750,8 @@ let # This setting must be different for each configured certificate, otherwise # two or more renewals may fail to bind to the address. Hence, it is not in # the inheritableOpts. - listenHTTP = mkOption { - type = types.nullOr types.str; + listenHTTP = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = ":1360"; description = '' @@ -762,8 +761,8 @@ let ''; }; - s3Bucket = mkOption { - type = types.nullOr types.str; + s3Bucket = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "acme"; description = '' @@ -771,7 +770,7 @@ let ''; }; - inheritDefaults = mkOption { + inheritDefaults = lib.mkOption { default = true; example = true; description = "Whether to inherit values set in `security.acme.defaults` or not."; @@ -784,8 +783,8 @@ in { options = { security.acme = { - preliminarySelfsigned = mkOption { - type = types.bool; + preliminarySelfsigned = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether a preliminary self-signed certificate should be generated before @@ -797,8 +796,8 @@ in { ''; }; - acceptTerms = mkOption { - type = types.bool; + acceptTerms = lib.mkOption { + type = lib.types.bool; default = false; description = '' Accept the CA's terms of service. The default provider is Let's Encrypt, @@ -806,8 +805,8 @@ in { ''; }; - useRoot = mkOption { - type = types.bool; + useRoot = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to use the root user when generating certs. This is not recommended @@ -818,8 +817,8 @@ in { ''; }; - defaults = mkOption { - type = types.submodule (inheritableModule true); + defaults = lib.mkOption { + type = lib.types.submodule (inheritableModule true); description = '' Default values inheritable by all configured certs. You can use this to define options shared by all your certs. These defaults @@ -828,9 +827,9 @@ in { ''; }; - certs = mkOption { + certs = lib.mkOption { default = { }; - type = with types; attrsOf (submodule [ (inheritableModule false) certOpts ]); + type = with lib.types; attrsOf (submodule [ (inheritableModule false) certOpts ]); description = '' Attribute set of certificates to get signed and renewed. Creates `acme-''${cert}.{service,timer}` systemd units for @@ -838,7 +837,7 @@ in { to those units if they rely on the certificates being present, or trigger restarts of the service if certificates get renewed. ''; - example = literalExpression '' + example = lib.literalExpression '' { "example.com" = { webroot = "/var/lib/acme/acme-challenge/"; @@ -852,9 +851,9 @@ in { } ''; }; - maxConcurrentRenewals = mkOption { + maxConcurrentRenewals = lib.mkOption { default = 5; - type = types.int; + type = lib.types.int; description = '' Maximum number of concurrent certificate generation or renewal jobs. All other jobs will queue and wait running jobs to finish. Reduces the system load of @@ -867,39 +866,39 @@ in { }; imports = [ - (mkRemovedOptionModule [ "security" "acme" "production" ] '' + (lib.mkRemovedOptionModule [ "security" "acme" "production" ] '' Use security.acme.server to define your staging ACME server URL instead. To use the let's encrypt staging server, use security.acme.server = "https://acme-staging-v02.api.letsencrypt.org/directory". '') - (mkRemovedOptionModule [ "security" "acme" "directory" ] "ACME Directory is now hardcoded to /var/lib/acme and its permissions are managed by systemd. See https://github.com/NixOS/nixpkgs/issues/53852 for more info.") - (mkRemovedOptionModule [ "security" "acme" "preDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal") - (mkRemovedOptionModule [ "security" "acme" "activationDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal") - (mkChangedOptionModule [ "security" "acme" "validMin" ] [ "security" "acme" "defaults" "validMinDays" ] (config: config.security.acme.validMin / (24 * 3600))) - (mkChangedOptionModule [ "security" "acme" "validMinDays" ] [ "security" "acme" "defaults" "validMinDays" ] (config: config.security.acme.validMinDays)) - (mkChangedOptionModule [ "security" "acme" "renewInterval" ] [ "security" "acme" "defaults" "renewInterval" ] (config: config.security.acme.renewInterval)) - (mkChangedOptionModule [ "security" "acme" "email" ] [ "security" "acme" "defaults" "email" ] (config: config.security.acme.email)) - (mkChangedOptionModule [ "security" "acme" "server" ] [ "security" "acme" "defaults" "server" ] (config: config.security.acme.server)) - (mkChangedOptionModule [ "security" "acme" "enableDebugLogs" ] [ "security" "acme" "defaults" "enableDebugLogs" ] (config: config.security.acme.enableDebugLogs)) + (lib.mkRemovedOptionModule [ "security" "acme" "directory" ] "ACME Directory is now hardcoded to /var/lib/acme and its permissions are managed by systemd. See https://github.com/NixOS/nixpkgs/issues/53852 for more info.") + (lib.mkRemovedOptionModule [ "security" "acme" "preDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal") + (lib.mkRemovedOptionModule [ "security" "acme" "activationDelay" ] "This option has been removed. If you want to make sure that something executes before certificates are provisioned, add a RequiredBy=acme-\${cert}.service to the service you want to execute before the cert renewal") + (lib.mkChangedOptionModule [ "security" "acme" "validMin" ] [ "security" "acme" "defaults" "validMinDays" ] (config: config.security.acme.validMin / (24 * 3600))) + (lib.mkChangedOptionModule [ "security" "acme" "validMinDays" ] [ "security" "acme" "defaults" "validMinDays" ] (config: config.security.acme.validMinDays)) + (lib.mkChangedOptionModule [ "security" "acme" "renewInterval" ] [ "security" "acme" "defaults" "renewInterval" ] (config: config.security.acme.renewInterval)) + (lib.mkChangedOptionModule [ "security" "acme" "email" ] [ "security" "acme" "defaults" "email" ] (config: config.security.acme.email)) + (lib.mkChangedOptionModule [ "security" "acme" "server" ] [ "security" "acme" "defaults" "server" ] (config: config.security.acme.server)) + (lib.mkChangedOptionModule [ "security" "acme" "enableDebugLogs" ] [ "security" "acme" "defaults" "enableDebugLogs" ] (config: config.security.acme.enableDebugLogs)) ]; - config = mkMerge [ - (mkIf (cfg.certs != { }) { + config = lib.mkMerge [ + (lib.mkIf (cfg.certs != { }) { # FIXME Most of these custom warnings and filters for security.acme.certs.* are required # because using mkRemovedOptionModule/mkChangedOptionModule with attrsets isn't possible. - warnings = filter (w: w != "") (mapAttrsToList (cert: data: optionalString (data.extraDomains != "_mkMergedOptionModule") '' + warnings = lib.filter (w: w != "") (lib.mapAttrsToList (cert: data: lib.optionalString (data.extraDomains != "_mkMergedOptionModule") '' The option definition `security.acme.certs.${cert}.extraDomains` has changed to `security.acme.certs.${cert}.extraDomainNames` and is now a list of strings. Setting a custom webroot for extra domains is not possible, instead use separate certs. '') cfg.certs); assertions = let - certs = attrValues cfg.certs; + certs = lib.attrValues cfg.certs; in [ { - assertion = cfg.defaults.email != null || all (certOpts: certOpts.email != null) certs; + assertion = cfg.defaults.email != null || lib.all (certOpts: certOpts.email != null) certs; message = '' You must define `security.acme.certs..email` or `security.acme.defaults.email` to register with the CA. Note that using @@ -914,7 +913,7 @@ in { to `true`. For Let's Encrypt's ToS see https://letsencrypt.org/repository/ ''; } - ] ++ (builtins.concatLists (mapAttrsToList (cert: data: [ + ] ++ (builtins.concatLists (lib.mapAttrsToList (cert: data: [ { assertion = data.user == "_mkRemovedOptionModule"; message = '' @@ -936,7 +935,7 @@ in { # referencing them as a user quite weird too. Best practice is to use # the domain option. { - assertion = ! hasInfix "*" cert; + assertion = ! lib.hasInfix "*" cert; message = '' The cert option path `security.acme.certs.${cert}.dnsProvider` cannot contain a * character. @@ -959,7 +958,7 @@ in { ''; }) { - assertion = all (hasSuffix "_FILE") (attrNames data.credentialFiles); + assertion = lib.all (lib.hasSuffix "_FILE") (lib.attrNames data.credentialFiles); message = '' Option `security.acme.certs.${cert}.credentialFiles` can only be used for variables suffixed by "_FILE". @@ -982,27 +981,27 @@ in { ]; systemd.services = let - renewServiceFunctions = mapAttrs' (cert: conf: nameValuePair "acme-${cert}" conf.renewService) certConfigs; + renewServiceFunctions = lib.mapAttrs' (cert: conf: lib.nameValuePair "acme-${cert}" conf.renewService) certConfigs; renewServices = if cfg.maxConcurrentRenewals > 0 then roundRobinApplyAttrs renewServiceFunctions concurrencyLockfiles - else mapAttrs (_: f: f null) renewServiceFunctions; - selfsignServiceFunctions = mapAttrs' (cert: conf: nameValuePair "acme-selfsigned-${cert}" conf.selfsignService) certConfigs; + else lib.mapAttrs (_: f: f null) renewServiceFunctions; + selfsignServiceFunctions = lib.mapAttrs' (cert: conf: lib.nameValuePair "acme-selfsigned-${cert}" conf.selfsignService) certConfigs; selfsignServices = if cfg.maxConcurrentRenewals > 0 then roundRobinApplyAttrs selfsignServiceFunctions concurrencyLockfiles - else mapAttrs (_: f: f null) selfsignServiceFunctions; + else lib.mapAttrs (_: f: f null) selfsignServiceFunctions; in { "acme-fixperms" = userMigrationService; } - // (optionalAttrs (cfg.maxConcurrentRenewals > 0) {"acme-lockfiles" = lockfilePrepareService; }) + // (lib.optionalAttrs (cfg.maxConcurrentRenewals > 0) {"acme-lockfiles" = lockfilePrepareService; }) // renewServices - // (optionalAttrs (cfg.preliminarySelfsigned) ({ + // (lib.optionalAttrs (cfg.preliminarySelfsigned) ({ "acme-selfsigned-ca" = selfsignCAService; } // selfsignServices)); - systemd.timers = mapAttrs' (cert: conf: nameValuePair "acme-${cert}" conf.renewTimer) certConfigs; + systemd.timers = lib.mapAttrs' (cert: conf: lib.nameValuePair "acme-${cert}" conf.renewTimer) certConfigs; systemd.targets = let # Create some targets which can be depended on to be "active" after cert renewals - finishedTargets = mapAttrs' (cert: conf: nameValuePair "acme-finished-${cert}" { + finishedTargets = lib.mapAttrs' (cert: conf: lib.nameValuePair "acme-finished-${cert}" { wantedBy = [ "default.target" ]; requires = [ "acme-${cert}.service" ]; after = [ "acme-${cert}.service" ]; @@ -1017,15 +1016,15 @@ in { # Using a target here is fine - account creation is a one time event. Even if # systemd clean --what=state is used to delete the account, so long as the user # then runs one of the cert services, there won't be any issues. - accountTargets = mapAttrs' (hash: confs: let + accountTargets = lib.mapAttrs' (hash: confs: let leader = "acme-${(builtins.head confs).cert}.service"; dependantServices = map (conf: "acme-${conf.cert}.service") (builtins.tail confs); - in nameValuePair "acme-account-${hash}" { + in lib.nameValuePair "acme-account-${hash}" { requiredBy = dependantServices; before = dependantServices; requires = [ leader ]; after = [ leader ]; - }) (groupBy (conf: conf.accountHash) (attrValues certConfigs)); + }) (lib.groupBy (conf: conf.accountHash) (lib.attrValues certConfigs)); in finishedTargets // accountTargets; }) ]; diff --git a/nixos/modules/security/auditd.nix b/nixos/modules/security/auditd.nix index cd377c66f86d..e9ffecdfbea5 100644 --- a/nixos/modules/security/auditd.nix +++ b/nixos/modules/security/auditd.nix @@ -1,19 +1,29 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ + config, + lib, + pkgs, + ... +}: { - options.security.auditd.enable = mkEnableOption "the Linux Audit daemon"; + options.security.auditd.enable = lib.mkEnableOption "the Linux Audit daemon"; - config = mkIf config.security.auditd.enable { + config = lib.mkIf config.security.auditd.enable { boot.kernelParams = [ "audit=1" ]; environment.systemPackages = [ pkgs.audit ]; systemd.services.auditd = { description = "Linux Audit daemon"; - wantedBy = [ "basic.target" ]; - before = [ "shutdown.target" ]; + wantedBy = [ "sysinit.target" ]; + after = [ + "local-fs.target" + "systemd-tmpfiles-setup.service" + ]; + before = [ + "sysinit.target" + "shutdown.target" + ]; conflicts = [ "shutdown.target" ]; unitConfig = { diff --git a/nixos/modules/security/dhparams.nix b/nixos/modules/security/dhparams.nix index 738062c95c47..c501ea70d05c 100644 --- a/nixos/modules/security/dhparams.nix +++ b/nixos/modules/security/dhparams.nix @@ -157,7 +157,7 @@ in { continue fi '') cfg.params)} - rm $file + rm "$file" done # TODO: Ideally this would be removing the *former* cfg.path, though diff --git a/nixos/modules/security/isolate.nix b/nixos/modules/security/isolate.nix index 3cc0176f3db3..11a6af588b5b 100644 --- a/nixos/modules/security/isolate.nix +++ b/nixos/modules/security/isolate.nix @@ -125,7 +125,7 @@ in }; systemd.slices.isolate = { - description = "Isolate sandbox slice"; + description = "Isolate Sandbox Slice"; }; meta.maintainers = with maintainers; [ virchau13 ]; diff --git a/nixos/modules/security/misc.nix b/nixos/modules/security/misc.nix index 5e13b4caddd8..d3ffefe46fc6 100644 --- a/nixos/modules/security/misc.nix +++ b/nixos/modules/security/misc.nix @@ -1,10 +1,7 @@ { config, lib, ... }: - -with lib; - { meta = { - maintainers = [ maintainers.joachifm ]; + maintainers = [ lib.maintainers.joachifm ]; }; imports = [ @@ -12,8 +9,8 @@ with lib; ]; options = { - security.allowUserNamespaces = mkOption { - type = types.bool; + security.allowUserNamespaces = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to allow creation of user namespaces. @@ -31,8 +28,8 @@ with lib; ''; }; - security.unprivilegedUsernsClone = mkOption { - type = types.bool; + security.unprivilegedUsernsClone = lib.mkOption { + type = lib.types.bool; default = false; description = '' When disabled, unprivileged users will not be able to create new namespaces. @@ -41,16 +38,16 @@ with lib; ''; }; - security.protectKernelImage = mkOption { - type = types.bool; + security.protectKernelImage = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to prevent replacing the running kernel image. ''; }; - security.allowSimultaneousMultithreading = mkOption { - type = types.bool; + security.allowSimultaneousMultithreading = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to allow SMT/hyperthreading. Disabling SMT means that only @@ -68,8 +65,8 @@ with lib; ''; }; - security.forcePageTableIsolation = mkOption { - type = types.bool; + security.forcePageTableIsolation = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to force-enable the Page Table Isolation (PTI) Linux kernel @@ -80,8 +77,8 @@ with lib; ''; }; - security.virtualisation.flushL1DataCache = mkOption { - type = types.nullOr (types.enum [ "never" "cond" "always" ]); + security.virtualisation.flushL1DataCache = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "never" "cond" "always" ]); default = null; description = '' Whether the hypervisor should flush the L1 data cache before @@ -100,8 +97,8 @@ with lib; }; }; - config = mkMerge [ - (mkIf (!config.security.allowUserNamespaces) { + config = lib.mkMerge [ + (lib.mkIf (!config.security.allowUserNamespaces) { # Setting the number of allowed user namespaces to 0 effectively disables # the feature at runtime. Note that root may raise the limit again # at any time. @@ -114,26 +111,26 @@ with lib; ]; }) - (mkIf config.security.unprivilegedUsernsClone { - boot.kernel.sysctl."kernel.unprivileged_userns_clone" = mkDefault true; + (lib.mkIf config.security.unprivilegedUsernsClone { + boot.kernel.sysctl."kernel.unprivileged_userns_clone" = lib.mkDefault true; }) - (mkIf config.security.protectKernelImage { + (lib.mkIf config.security.protectKernelImage { # Disable hibernation (allows replacing the running kernel) boot.kernelParams = [ "nohibernate" ]; # Prevent replacing the running kernel image w/o reboot - boot.kernel.sysctl."kernel.kexec_load_disabled" = mkDefault true; + boot.kernel.sysctl."kernel.kexec_load_disabled" = lib.mkDefault true; }) - (mkIf (!config.security.allowSimultaneousMultithreading) { + (lib.mkIf (!config.security.allowSimultaneousMultithreading) { boot.kernelParams = [ "nosmt" ]; }) - (mkIf config.security.forcePageTableIsolation { + (lib.mkIf config.security.forcePageTableIsolation { boot.kernelParams = [ "pti=on" ]; }) - (mkIf (config.security.virtualisation.flushL1DataCache != null) { + (lib.mkIf (config.security.virtualisation.flushL1DataCache != null) { boot.kernelParams = [ "kvm-intel.vmentry_l1d_flush=${config.security.virtualisation.flushL1DataCache}" ]; }) ]; diff --git a/nixos/modules/security/oath.nix b/nixos/modules/security/oath.nix index 93bdc851117a..acf9440b9b92 100644 --- a/nixos/modules/security/oath.nix +++ b/nixos/modules/security/oath.nix @@ -1,32 +1,28 @@ # This module provides configuration for the OATH PAM modules. - { lib, ... }: - -with lib; - { options = { security.pam.oath = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable the OATH (one-time password) PAM module. ''; }; - digits = mkOption { - type = types.enum [ 6 7 8 ]; + digits = lib.mkOption { + type = lib.types.enum [ 6 7 8 ]; default = 6; description = '' - Specify the length of the one-time password in number of + Specify the lib.length of the one-time password in number of digits. ''; }; - window = mkOption { - type = types.int; + window = lib.mkOption { + type = lib.types.int; default = 5; description = '' Specify the number of one-time passwords to check in order @@ -36,8 +32,8 @@ with lib; ''; }; - usersFile = mkOption { - type = types.path; + usersFile = lib.mkOption { + type = lib.types.path; default = "/etc/users.oath"; description = '' Set the path to file where the user's credentials are diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 2ff08cbfde81..acd0673877b8 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -287,6 +287,18 @@ let ''; }; + rssh = lib.mkOption { + default = false; + type = lib.types.bool; + description = '' + If set, the calling user's SSH agent is used to authenticate + against the configured keys. This module works in a manner + similar to pam_ssh_agent_auth, but supports a wider range + of SSH key types, including those protected by security + keys (FIDO2). + ''; + }; + duoSecurity = { enable = lib.mkOption { default = false; @@ -673,6 +685,7 @@ let { name = "ssh_agent_auth"; enable = config.security.pam.sshAgentAuth.enable && cfg.sshAgentAuth; control = "sufficient"; modulePath = "${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so"; settings = { file = lib.concatStringsSep ":" config.security.pam.sshAgentAuth.authorizedKeysFiles; }; } + (let inherit (config.security.pam) rssh; in { name = "rssh"; enable = rssh.enable && cfg.rssh; control = "sufficient"; modulePath = "${pkgs.pam_rssh}/lib/libpam_rssh.so"; inherit (rssh) settings; }) (let p11 = config.security.pam.p11; in { name = "p11"; enable = cfg.p11Auth; control = p11.control; modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so"; args = [ "${pkgs.opensc}/lib/opensc-pkcs11.so" ]; }) @@ -950,8 +963,9 @@ let value.source = pkgs.writeText "${name}.pam" service.text; }; - optionalSudoConfigForSSHAgentAuth = lib.optionalString config.security.pam.sshAgentAuth.enable '' - # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic. + optionalSudoConfigForSSHAgentAuth = lib.optionalString + (config.security.pam.sshAgentAuth.enable || config.security.pam.rssh.enable) '' + # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so and libpam_rssh.so can do their magic. Defaults env_keep+=SSH_AUTH_SOCK ''; @@ -1068,6 +1082,55 @@ in }; }; + security.pam.rssh = { + enable = lib.mkEnableOption "authenticating using a signature performed by the ssh-agent"; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = moduleSettingsType; + options = { + auth_key_file = lib.mkOption { + type = with lib.types; nullOr nonEmptyStr; + description = '' + Path to file with trusted public keys in OpenSSH's `authorized_keys` format. The following + variables are expanded to the respective PAM items: + + - `service`: `PAM_SERVICE`, the service name, + - `user`: `PAM_USER`, the username of the entity under whose identity service will be given, + - `tty`: `PAM_TTY`, the terminal name, + - `rhost`: `PAM_RHOST`, the requesting hostname, and + - `ruser`: `PAM_RUSER`, the requesting entity. + + These PAM items are explained in {manpage}`pam_get_item(3)`. + + Variables may be specified as `$var`, `''${var}` or `''${var:defaultValue}`. + + ::: {.note} + Specifying user-writeable files here results in an insecure configuration: a malicious process + can then edit such an `authorized_keys` file and bypass the ssh-agent-based authentication. + + This option is ignored if {option}`security.pam.rssh.settings.authorized_keys_command` is set. + + If both this option and {option}`security.pam.rssh.settings.authorized_keys_command` are unset, + the keys will be read from `''${HOME}/.ssh/authorized_keys`, which should be considered + insecure. + ''; + default = "/etc/ssh/authorized_keys.d/$ruser"; + }; + }; + }; + + default = { }; + description = '' + Options to pass to the pam_rssh module. Refer to + + for supported values. + + ${moduleSettingsDescription} + ''; + }; + }; + security.pam.enableOTPW = lib.mkEnableOption "the OTPW (one-time password) PAM module"; security.pam.dp9ik = { @@ -1512,16 +1575,30 @@ in Did you forget to set `services.openssh.enable` ? ''; } + { + assertion = with config.security.pam.rssh; + enable -> (settings.auth_key_file or null != null || settings.authorized_keys_command or null != null); + message = '' + security.pam.rssh.enable requires either security.pam.rssh.settings.auth_key_file or + security.pam.rssh.settings.authorized_keys_command to be set. + ''; + } ]; warnings = lib.optional - (with lib; with config.security.pam.sshAgentAuth; + (with config.security.pam.sshAgentAuth; enable && lib.any (s: lib.hasPrefix "%h" s || lib.hasPrefix "~" s) authorizedKeysFiles) ''config.security.pam.sshAgentAuth.authorizedKeysFiles contains files in the user's home directory. Specifying user-writeable files there result in an insecure configuration: a malicious process can then edit such an authorized_keys file and bypass the ssh-agent-based authentication. See https://github.com/NixOS/nixpkgs/issues/31611 + '' ++ lib.optional + (with config.security.pam.rssh; + enable && settings.auth_key_file or null != null && settings.authorized_keys_command or null != null) '' + security.pam.rssh.settings.auth_key_file will be ignored as + security.pam.rssh.settings.authorized_keys_command has been specified. + Explictly set the former to null to silence this warning. ''; environment.systemPackages = diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix index 76f623096fb7..eb783179af55 100644 --- a/nixos/modules/security/polkit.nix +++ b/nixos/modules/security/polkit.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.security.polkit; @@ -12,14 +9,14 @@ in options = { - security.polkit.enable = mkEnableOption "polkit"; + security.polkit.enable = lib.mkEnableOption "polkit"; - security.polkit.package = mkPackageOption pkgs "polkit" { }; + security.polkit.package = lib.mkPackageOption pkgs "polkit" { }; - security.polkit.debug = mkEnableOption "debug logs from polkit. This is required in order to see log messages from rule definitions"; + security.polkit.debug = lib.mkEnableOption "debug logs from polkit. This is required in order to see log messages from rule definitions"; - security.polkit.extraConfig = mkOption { - type = types.lines; + security.polkit.extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = '' @@ -41,8 +38,8 @@ in ''; }; - security.polkit.adminIdentities = mkOption { - type = types.listOf types.str; + security.polkit.adminIdentities = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "unix-group:wheel" ]; example = [ "unix-user:alice" "unix-group:admin" ]; description = @@ -57,7 +54,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package.bin cfg.package.out ]; @@ -65,7 +62,7 @@ in systemd.services.polkit.serviceConfig.ExecStart = [ "" - "${cfg.package.out}/lib/polkit-1/polkitd ${optionalString (!cfg.debug) "--no-debug"}" + "${cfg.package.out}/lib/polkit-1/polkitd ${lib.optionalString (!cfg.debug) "--no-debug"}" ]; systemd.services.polkit.restartTriggers = [ config.system.path ]; @@ -78,7 +75,7 @@ in environment.etc."polkit-1/rules.d/10-nixos.rules".text = '' polkit.addAdminRule(function(action, subject) { - return [${concatStringsSep ", " (map (i: "\"${i}\"") cfg.adminIdentities)}]; + return [${lib.concatStringsSep ", " (map (i: "\"${i}\"") cfg.adminIdentities)}]; }); ${cfg.extraConfig} diff --git a/nixos/modules/security/sudo-rs.nix b/nixos/modules/security/sudo-rs.nix index e63a64d4691c..b920015c4911 100644 --- a/nixos/modules/security/sudo-rs.nix +++ b/nixos/modules/security/sudo-rs.nix @@ -1,21 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.security.sudo-rs; - toUserString = user: if (isInt user) then "#${toString user}" else "${user}"; - toGroupString = group: if (isInt group) then "%#${toString group}" else "%${group}"; + toUserString = user: if (lib.isInt user) then "#${toString user}" else "${user}"; + toGroupString = group: if (lib.isInt group) then "%#${toString group}" else "%${group}"; toCommandOptionsString = options: - "${concatStringsSep ":" options}${optionalString (length options != 0) ":"} "; + "${lib.concatStringsSep ":" options}${lib.optionalString (lib.length options != 0) ":"} "; toCommandsString = commands: - concatStringsSep ", " ( + lib.concatStringsSep ", " ( map (command: - if (isString command) then + if (lib.isString command) then command else "${toCommandOptionsString command.options}${command.command}" @@ -30,8 +27,8 @@ in options.security.sudo-rs = { - defaultOptions = mkOption { - type = with types; listOf str; + defaultOptions = lib.mkOption { + type = with lib.types; listOf str; default = []; description = '' Options used for the default rules, granting `root` and the @@ -39,15 +36,15 @@ in ''; }; - enable = mkEnableOption '' + enable = lib.mkEnableOption '' a memory-safe implementation of the {command}`sudo` command, which allows non-root users to execute commands as root ''; - package = mkPackageOption pkgs "sudo-rs" { }; + package = lib.mkPackageOption pkgs "sudo-rs" { }; - wheelNeedsPassword = mkOption { - type = types.bool; + wheelNeedsPassword = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether users of the `wheel` group must @@ -55,8 +52,8 @@ in ''; }; - execWheelOnly = mkOption { - type = types.bool; + execWheelOnly = lib.mkOption { + type = lib.types.bool; default = false; description = '' Only allow members of the `wheel` group to execute sudo by @@ -66,8 +63,8 @@ in ''; }; - configFile = mkOption { - type = types.lines; + configFile = lib.mkOption { + type = lib.types.lines; # Note: if syntax errors are detected in this file, the NixOS # configuration will fail to build. description = '' @@ -76,15 +73,15 @@ in ''; }; - extraRules = mkOption { + extraRules = lib.mkOption { description = '' Define specific rules to be in the {file}`sudoers` file. More specific rules should come after more general ones in order to - yield the expected behavior. You can use mkBefore/mkAfter to ensure + yield the expected behavior. You can use `lib.mkBefore`/`lib.mkAfter` to ensure this is the case when configuration options are merged. ''; default = []; - example = literalExpression '' + example = lib.literalExpression '' [ # Allow execution of any command by all users in group sudo, # requiring a password. @@ -103,34 +100,34 @@ in { command = '''/home/baz/cmd2.sh ""'''; options = [ "SETENV" ]; } ]; } ] ''; - type = with types; listOf (submodule { + type = with lib.types; listOf (submodule { options = { - users = mkOption { - type = with types; listOf (either str int); + users = lib.mkOption { + type = with lib.types; listOf (either str int); description = '' The usernames / UIDs this rule should apply for. ''; default = []; }; - groups = mkOption { - type = with types; listOf (either str int); + groups = lib.mkOption { + type = with lib.types; listOf (either str int); description = '' The groups / GIDs this rule should apply for. ''; default = []; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "ALL"; description = '' For what host this rule should apply. ''; }; - runAs = mkOption { - type = with types; str; + runAs = lib.mkOption { + type = with lib.types; str; default = "ALL:ALL"; description = '' Under which user/group the specified command is allowed to run. @@ -141,15 +138,15 @@ in ''; }; - commands = mkOption { + commands = lib.mkOption { description = '' The commands for which the rule should apply. ''; - type = with types; listOf (either str (submodule { + type = with lib.types; listOf (either str (submodule { options = { - command = mkOption { - type = with types; str; + command = lib.mkOption { + type = with lib.types; str; description = '' A command being either just a path to a binary to allow any arguments, the full command with arguments pre-set or with `""` used as the argument, @@ -157,8 +154,8 @@ in ''; }; - options = mkOption { - type = with types; listOf (enum [ "NOPASSWD" "PASSWD" "NOEXEC" "EXEC" "SETENV" "NOSETENV" "LOG_INPUT" "NOLOG_INPUT" "LOG_OUTPUT" "NOLOG_OUTPUT" ]); + options = lib.mkOption { + type = with lib.types; listOf (enum [ "NOPASSWD" "PASSWD" "NOEXEC" "EXEC" "SETENV" "NOSETENV" "LOG_INPUT" "NOLOG_INPUT" "LOG_OUTPUT" "NOLOG_OUTPUT" ]); description = '' Options for running the command. Refer to the [sudo manual](https://www.sudo.ws/man/1.7.10/sudoers.man.html). ''; @@ -172,8 +169,8 @@ in }); }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra configuration text appended to {file}`sudoers`. @@ -184,12 +181,12 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = ! config.security.sudo.enable; message = "`security.sudo` and `security.sudo-rs` cannot both be enabled"; }]; - security.sudo.enable = mkDefault false; + security.sudo.enable = lib.mkDefault false; security.sudo-rs.extraRules = let @@ -200,35 +197,35 @@ in options = opts ++ cfg.defaultOptions; } ]; } ]; - in mkMerge [ - # This is ordered before users' `mkBefore` rules, + in lib.mkMerge [ + # This is ordered before users' `lib.mkBefore` rules, # so as not to introduce unexpected changes. - (mkOrder 400 (defaultRule { users = [ "root" ]; })) + (lib.mkOrder 400 (defaultRule { users = [ "root" ]; })) # This is ordered to show before (most) other rules, but - # late-enough for a user to `mkBefore` it. - (mkOrder 600 (defaultRule { + # late-enough for a user to `lib.mkBefore` it. + (lib.mkOrder 600 (defaultRule { groups = [ "wheel" ]; - opts = (optional (!cfg.wheelNeedsPassword) "NOPASSWD"); + opts = (lib.optional (!cfg.wheelNeedsPassword) "NOPASSWD"); })) ]; - security.sudo-rs.configFile = concatStringsSep "\n" (filter (s: s != "") [ + security.sudo-rs.configFile = lib.concatStringsSep "\n" (lib.filter (s: s != "") [ '' # Don't edit this file. Set the NixOS options ‘security.sudo-rs.configFile’ # or ‘security.sudo-rs.extraRules’ instead. '' - (pipe cfg.extraRules [ - (filter (rule: length rule.commands != 0)) + (lib.pipe cfg.extraRules [ + (lib.filter (rule: lib.length rule.commands != 0)) (map (rule: [ (map (user: "${toUserString user} ${rule.host}=(${rule.runAs}) ${toCommandsString rule.commands}") rule.users) (map (group: "${toGroupString group} ${rule.host}=(${rule.runAs}) ${toCommandsString rule.commands}") rule.groups) ])) - flatten - (concatStringsSep "\n") + lib.flatten + (lib.concatStringsSep "\n") ]) "\n" - (optionalString (cfg.extraConfig != "") '' + (lib.optionalString (cfg.extraConfig != "") '' # extraConfig ${cfg.extraConfig} '') diff --git a/nixos/modules/services/accessibility/orca.nix b/nixos/modules/services/accessibility/orca.nix new file mode 100644 index 000000000000..4487afba103c --- /dev/null +++ b/nixos/modules/services/accessibility/orca.nix @@ -0,0 +1,25 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.orca; + inherit (lib) + mkEnableOption + mkIf + mkPackageOption + ; +in +{ + options.services.orca = { + enable = mkEnableOption "Orca screen reader"; + package = mkPackageOption pkgs "orca" { }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + services.speechd.enable = true; + }; +} diff --git a/nixos/modules/services/admin/pgadmin.nix b/nixos/modules/services/admin/pgadmin.nix index 9c430bd05e71..c9da556b763d 100644 --- a/nixos/modules/services/admin/pgadmin.nix +++ b/nixos/modules/services/admin/pgadmin.nix @@ -1,15 +1,12 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.pgadmin; - _base = with types; [ int bool str ]; - base = with types; oneOf ([ (listOf (oneOf _base)) (attrsOf (oneOf _base)) ] ++ _base); + _base = with lib.types; [ int bool str ]; + base = with lib.types; oneOf ([ (listOf (oneOf _base)) (attrsOf (oneOf _base)) ] ++ _base); formatAttrset = attr: - "{${concatStringsSep "\n" (mapAttrsToList (key: value: "${builtins.toJSON key}: ${formatPyValue value},") attr)}}"; + "{${lib.concatStringsSep "\n" (lib.mapAttrsToList (key: value: "${builtins.toJSON key}: ${formatPyValue value},") attr)}}"; formatPyValue = value: if builtins.isString value then builtins.toJSON value @@ -17,98 +14,98 @@ let else if builtins.isInt value then toString value else if builtins.isBool value then (if value then "True" else "False") else if builtins.isAttrs value then (formatAttrset value) - else if builtins.isList value then "[${concatStringsSep "\n" (map (v: "${formatPyValue v},") value)}]" + else if builtins.isList value then "[${lib.concatStringsSep "\n" (map (v: "${formatPyValue v},") value)}]" else throw "Unrecognized type"; formatPy = attrs: - concatStringsSep "\n" (mapAttrsToList (key: value: "${key} = ${formatPyValue value}") attrs); + lib.concatStringsSep "\n" (lib.mapAttrsToList (key: value: "${key} = ${formatPyValue value}") attrs); - pyType = with types; attrsOf (oneOf [ (attrsOf base) (listOf base) base ]); + pyType = with lib.types; attrsOf (oneOf [ (attrsOf base) (listOf base) base ]); in { options.services.pgadmin = { - enable = mkEnableOption "PostgreSQL Admin 4"; + enable = lib.mkEnableOption "PostgreSQL Admin 4"; - port = mkOption { + port = lib.mkOption { description = "Port for pgadmin4 to run on"; - type = types.port; + type = lib.types.port; default = 5050; }; - package = mkPackageOption pkgs "pgadmin4" { }; + package = lib.mkPackageOption pkgs "pgadmin4" { }; - initialEmail = mkOption { + initialEmail = lib.mkOption { description = "Initial email for the pgAdmin account"; - type = types.str; + type = lib.types.str; }; - initialPasswordFile = mkOption { + initialPasswordFile = lib.mkOption { description = '' Initial password file for the pgAdmin account. Minimum length by default is 6. Please see `services.pgadmin.minimumPasswordLength`. NOTE: Should be string not a store path, to prevent the password from being world readable ''; - type = types.path; + type = lib.types.path; }; - minimumPasswordLength = mkOption { + minimumPasswordLength = lib.mkOption { description = "Minimum length of the password"; - type = types.int; + type = lib.types.int; default = 6; }; emailServer = { - enable = mkOption { + enable = lib.mkOption { description = '' Enable SMTP email server. This is necessary, if you want to use password recovery or change your own password ''; - type = types.bool; + type = lib.types.bool; default = false; }; - address = mkOption { + address = lib.mkOption { description = "SMTP server for email delivery"; - type = types.str; + type = lib.types.str; default = "localhost"; }; - port = mkOption { + port = lib.mkOption { description = "SMTP server port for email delivery"; - type = types.port; + type = lib.types.port; default = 25; }; - useSSL = mkOption { + useSSL = lib.mkOption { description = "SMTP server should use SSL"; - type = types.bool; + type = lib.types.bool; default = false; }; - useTLS = mkOption { + useTLS = lib.mkOption { description = "SMTP server should use TLS"; - type = types.bool; + type = lib.types.bool; default = false; }; - username = mkOption { + username = lib.mkOption { description = "SMTP server username for email delivery"; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; }; - sender = mkOption { + sender = lib.mkOption { description = '' SMTP server sender email for email delivery. Some servers require this to be a valid email address from that server ''; - type = types.str; + type = lib.types.str; example = "noreply@example.com"; }; - passwordFile = mkOption { + passwordFile = lib.mkOption { description = '' Password for SMTP email account. NOTE: Should be string not a store path, to prevent the password from being world readable ''; - type = types.path; + type = lib.types.path; }; }; - openFirewall = mkEnableOption "firewall passthrough for pgadmin4"; + openFirewall = lib.mkEnableOption "firewall passthrough for pgadmin4"; - settings = mkOption { + settings = lib.mkOption { description = '' Settings for pgadmin4. [Documentation](https://www.pgadmin.org/docs/pgadmin4/development/config_py.html) @@ -118,17 +115,17 @@ in }; }; - config = mkIf (cfg.enable) { - networking.firewall.allowedTCPPorts = mkIf (cfg.openFirewall) [ cfg.port ]; + config = lib.mkIf (cfg.enable) { + networking.firewall.allowedTCPPorts = lib.mkIf (cfg.openFirewall) [ cfg.port ]; services.pgadmin.settings = { DEFAULT_SERVER_PORT = cfg.port; PASSWORD_LENGTH_MIN = cfg.minimumPasswordLength; SERVER_MODE = true; UPGRADE_CHECK_ENABLED = false; - } // (optionalAttrs cfg.openFirewall { - DEFAULT_SERVER = mkDefault "::"; - }) // (optionalAttrs cfg.emailServer.enable { + } // (lib.optionalAttrs cfg.openFirewall { + DEFAULT_SERVER = lib.mkDefault "::"; + }) // (lib.optionalAttrs cfg.emailServer.enable { MAIL_SERVER = cfg.emailServer.address; MAIL_PORT = cfg.emailServer.port; MAIL_USE_SSL = cfg.emailServer.useSSL; @@ -160,7 +157,7 @@ in fi ( # Email address: - echo ${escapeShellArg cfg.initialEmail} + echo ${lib.escapeShellArg cfg.initialEmail} # file might not contain newline. echo hack fixes that. PW=$(cat "$PW_FILE") @@ -183,7 +180,7 @@ in StateDirectory = "pgadmin"; ExecStart = "${cfg.package}/bin/pgadmin4"; LoadCredential = [ "initial_password:${cfg.initialPasswordFile}" ] - ++ optional cfg.emailServer.enable "email_password:${cfg.emailServer.passwordFile}"; + ++ lib.optional cfg.emailServer.enable "email_password:${cfg.emailServer.passwordFile}"; }; }; diff --git a/nixos/modules/services/admin/salt/master.nix b/nixos/modules/services/admin/salt/master.nix index c447540da1f8..1ffe6b6cb27a 100644 --- a/nixos/modules/services/admin/salt/master.nix +++ b/nixos/modules/services/admin/salt/master.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.salt.master; @@ -20,16 +17,16 @@ in { options = { services.salt.master = { - enable = mkEnableOption "Salt configuration management system master service"; - configuration = mkOption { - type = types.attrs; + enable = lib.mkEnableOption "Salt configuration management system master service"; + configuration = lib.mkOption { + type = lib.types.attrs; default = {}; description = "Salt master configuration as Nix attribute set."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment = { # Set this up in /etc/salt/master so `salt`, `salt-key`, etc. work. # The alternatives are diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix index b5aebaaf1275..fba26591e0ba 100644 --- a/nixos/modules/services/amqp/rabbitmq.nix +++ b/nixos/modules/services/amqp/rabbitmq.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.rabbitmq; @@ -16,7 +13,7 @@ in { imports = [ - (mkRemovedOptionModule [ "services" "rabbitmq" "cookie" ] '' + (lib.mkRemovedOptionModule [ "services" "rabbitmq" "cookie" ] '' This option wrote the Erlang cookie to the store, while it should be kept secret. Please remove it from your NixOS configuration and deploy a cookie securely instead. The renamed `unsafeCookie` must ONLY be used in isolated non-production environments such as NixOS VM tests. @@ -26,8 +23,8 @@ in ###### interface options = { services.rabbitmq = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the RabbitMQ server, an Advanced Message @@ -35,9 +32,9 @@ in ''; }; - package = mkPackageOption pkgs "rabbitmq-server" { }; + package = lib.mkPackageOption pkgs "rabbitmq-server" { }; - listenAddress = mkOption { + listenAddress = lib.mkOption { default = "127.0.0.1"; example = ""; description = '' @@ -52,28 +49,28 @@ in configItems."listeners.tcp.1" and it's left for backwards compatibility with previous version of this module. ''; - type = types.str; + type = lib.types.str; }; - port = mkOption { + port = lib.mkOption { default = 5672; description = '' Port on which RabbitMQ will listen for AMQP connections. ''; - type = types.port; + type = lib.types.port; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/rabbitmq"; description = '' Data directory for rabbitmq. ''; }; - unsafeCookie = mkOption { + unsafeCookie = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Erlang cookie is a string of arbitrary length which must be the same for several nodes to be allowed to communicate. @@ -86,10 +83,10 @@ in ''; }; - configItems = mkOption { + configItems = lib.mkOption { default = { }; - type = types.attrsOf types.str; - example = literalExpression '' + type = lib.types.attrsOf lib.types.str; + example = lib.literalExpression '' { "auth_backends.1.authn" = "rabbit_auth_backend_ldap"; "auth_backends.1.authz" = "rabbit_auth_backend_internal"; @@ -112,9 +109,9 @@ in ''; }; - config = mkOption { + config = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Verbatim advanced configuration file contents using the Erlang syntax. This is also known as the `advanced.config` file or the old config format. @@ -130,23 +127,23 @@ in ''; }; - plugins = mkOption { + plugins = lib.mkOption { default = [ ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = "The names of plugins to enable"; }; - pluginDirs = mkOption { + pluginDirs = lib.mkOption { default = [ ]; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; description = "The list of directories containing external plugins"; }; managementPlugin = { - enable = mkEnableOption "the management plugin"; - port = mkOption { + enable = lib.mkEnableOption "the management plugin"; + port = lib.mkOption { default = 15672; - type = types.port; + type = lib.types.port; description = '' On which port to run the management plugin ''; @@ -157,7 +154,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # This is needed so we will have 'rabbitmqctl' in our PATH environment.systemPackages = [ cfg.package ]; @@ -175,13 +172,13 @@ in users.groups.rabbitmq.gid = config.ids.gids.rabbitmq; services.rabbitmq.configItems = { - "listeners.tcp.1" = mkDefault "${cfg.listenAddress}:${toString cfg.port}"; - } // optionalAttrs cfg.managementPlugin.enable { + "listeners.tcp.1" = lib.mkDefault "${cfg.listenAddress}:${toString cfg.port}"; + } // lib.optionalAttrs cfg.managementPlugin.enable { "management.tcp.port" = toString cfg.managementPlugin.port; "management.tcp.ip" = cfg.listenAddress; }; - services.rabbitmq.plugins = optional cfg.managementPlugin.enable "rabbitmq_management"; + services.rabbitmq.plugins = lib.optional cfg.managementPlugin.enable "rabbitmq_management"; systemd.services.rabbitmq = { description = "RabbitMQ Server"; @@ -200,11 +197,11 @@ in RABBITMQ_LOGS = "-"; SYS_PREFIX = ""; RABBITMQ_CONFIG_FILE = config_file; - RABBITMQ_PLUGINS_DIR = concatStringsSep ":" cfg.pluginDirs; + RABBITMQ_PLUGINS_DIR = lib.concatStringsSep ":" cfg.pluginDirs; RABBITMQ_ENABLED_PLUGINS_FILE = pkgs.writeText "enabled_plugins" '' - [ ${concatStringsSep "," cfg.plugins} ]. + [ ${lib.concatStringsSep "," cfg.plugins} ]. ''; - } // optionalAttrs (cfg.config != "") { RABBITMQ_ADVANCED_CONFIG_FILE = advanced_config_file; }; + } // lib.optionalAttrs (cfg.config != "") { RABBITMQ_ADVANCED_CONFIG_FILE = advanced_config_file; }; serviceConfig = { ExecStart = "${cfg.package}/sbin/rabbitmq-server"; @@ -223,7 +220,7 @@ in }; preStart = '' - ${optionalString (cfg.unsafeCookie != "") '' + ${lib.optionalString (cfg.unsafeCookie != "") '' install -m 600 <(echo -n ${cfg.unsafeCookie}) ${cfg.dataDir}/.erlang.cookie ''} ''; diff --git a/nixos/modules/services/audio/jack.nix b/nixos/modules/services/audio/jack.nix index a5cb0da29592..7344fdf4a218 100644 --- a/nixos/modules/services/audio/jack.nix +++ b/nixos/modules/services/audio/jack.nix @@ -8,7 +8,7 @@ let pcmPlugin = cfg.jackd.enable && cfg.alsa.enable; loopback = cfg.jackd.enable && cfg.loopback.enable; - enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.isx86_64 && pkgs.pkgsi686Linux.alsa-lib != null; + enable32BitAlsaPlugins = cfg.alsa.support32Bit && pkgs.stdenv.hostPlatform.isx86_64 && pkgs.pkgsi686Linux.alsa-lib != null; umaskNeeded = versionOlder cfg.jackd.package.version "1.9.12"; bridgeNeeded = versionAtLeast cfg.jackd.package.version "1.9.12"; diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix index b5e33f3c0986..a6cd80384533 100644 --- a/nixos/modules/services/audio/mpd.nix +++ b/nixos/modules/services/audio/mpd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let name = "mpd"; @@ -12,11 +9,11 @@ let credentialsPlaceholder = (creds: let - placeholders = (imap0 - (i: c: ''password "{{password-${toString i}}}@${concatStringsSep "," c.permissions}"'') + placeholders = (lib.imap0 + (i: c: ''password "{{password-${toString i}}}@${lib.concatStringsSep "," c.permissions}"'') creds); in - concatStringsSep "\n" placeholders); + lib.concatStringsSep "\n" placeholders); mpdConf = pkgs.writeText "mpd.conf" '' # This file was automatically generated by NixOS. Edit mpd's configuration @@ -31,16 +28,16 @@ let state_file "${cfg.dataDir}/state" sticker_file "${cfg.dataDir}/sticker.sql" - ${optionalString (cfg.network.listenAddress != "any") ''bind_to_address "${cfg.network.listenAddress}"''} - ${optionalString (cfg.network.port != 6600) ''port "${toString cfg.network.port}"''} - ${optionalString (cfg.fluidsynth) '' + ${lib.optionalString (cfg.network.listenAddress != "any") ''bind_to_address "${cfg.network.listenAddress}"''} + ${lib.optionalString (cfg.network.port != 6600) ''port "${toString cfg.network.port}"''} + ${lib.optionalString (cfg.fluidsynth) '' decoder { plugin "fluidsynth" soundfont "${pkgs.soundfont-fluid}/share/soundfonts/FluidR3_GM2-2.sf2" } ''} - ${optionalString (cfg.credentials != []) (credentialsPlaceholder cfg.credentials)} + ${lib.optionalString (cfg.credentials != []) (credentialsPlaceholder cfg.credentials)} ${cfg.extraConfig} ''; @@ -53,16 +50,16 @@ in { services.mpd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable MPD, the music player daemon. ''; }; - startWhenNeeded = mkOption { - type = types.bool; + startWhenNeeded = lib.mkOption { + type = lib.types.bool; default = false; description = '' If set, {command}`mpd` is socket-activated; that @@ -71,10 +68,10 @@ in { ''; }; - musicDirectory = mkOption { - type = with types; either path (strMatching "(http|https|nfs|smb)://.+"); + musicDirectory = lib.mkOption { + type = with lib.types; either path (strMatching "(http|https|nfs|smb)://.+"); default = "${cfg.dataDir}/music"; - defaultText = literalExpression ''"''${dataDir}/music"''; + defaultText = lib.literalExpression ''"''${dataDir}/music"''; description = '' The directory or NFS/SMB network share where MPD reads music from. If left as the default value this directory will automatically be created before @@ -83,10 +80,10 @@ in { ''; }; - playlistDirectory = mkOption { - type = types.path; + playlistDirectory = lib.mkOption { + type = lib.types.path; default = "${cfg.dataDir}/playlists"; - defaultText = literalExpression ''"''${dataDir}/playlists"''; + defaultText = lib.literalExpression ''"''${dataDir}/playlists"''; description = '' The directory where MPD stores playlists. If left as the default value this directory will automatically be created before the MPD server starts, @@ -95,8 +92,8 @@ in { ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra directives added to to the end of MPD's configuration file, @@ -106,8 +103,8 @@ in { ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/${name}"; description = '' The directory where MPD stores its state, tag cache, playlists etc. If @@ -117,22 +114,22 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = name; description = "User account under which MPD runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = name; description = "Group account under which MPD runs."; }; network = { - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; example = "any"; description = '' @@ -141,8 +138,8 @@ in { ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 6600; description = '' This setting is the TCP port that is desired for the daemon to get assigned @@ -152,33 +149,33 @@ in { }; - dbFile = mkOption { - type = types.nullOr types.str; + dbFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "${cfg.dataDir}/tag_cache"; - defaultText = literalExpression ''"''${dataDir}/tag_cache"''; + defaultText = lib.literalExpression ''"''${dataDir}/tag_cache"''; description = '' The path to MPD's database. If set to `null` the parameter is omitted from the configuration. ''; }; - credentials = mkOption { - type = types.listOf (types.submodule { + credentials = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - passwordFile = mkOption { - type = types.path; + passwordFile = lib.mkOption { + type = lib.types.path; description = '' Path to file containing the password. ''; }; permissions = let perms = ["read" "add" "control" "admin"]; - in mkOption { - type = types.listOf (types.enum perms); + in lib.mkOption { + type = lib.types.listOf (lib.types.enum perms); default = [ "read" ]; description = '' List of permissions that are granted with this password. - Permissions can be "${concatStringsSep "\", \"" perms}". + Permissions can be "${lib.concatStringsSep "\", \"" perms}". ''; }; }; @@ -193,8 +190,8 @@ in { ]; }; - fluidsynth = mkOption { - type = types.bool; + fluidsynth = lib.mkOption { + type = lib.types.bool; default = false; description = '' If set, add fluidsynth soundfont and configure the plugin. @@ -207,31 +204,31 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # install mpd units systemd.packages = [ pkgs.mpd ]; - systemd.sockets.mpd = mkIf cfg.startWhenNeeded { + systemd.sockets.mpd = lib.mkIf cfg.startWhenNeeded { wantedBy = [ "sockets.target" ]; listenStreams = [ "" # Note: this is needed to override the upstream unit (if pkgs.lib.hasPrefix "/" cfg.network.listenAddress then cfg.network.listenAddress - else "${optionalString (cfg.network.listenAddress != "any") "${cfg.network.listenAddress}:"}${toString cfg.network.port}") + else "${lib.optionalString (cfg.network.listenAddress != "any") "${cfg.network.listenAddress}:"}${toString cfg.network.port}") ]; }; systemd.services.mpd = { - wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; + wantedBy = lib.optional (!cfg.startWhenNeeded) "multi-user.target"; preStart = '' set -euo pipefail install -m 600 ${mpdConf} /run/mpd/mpd.conf - '' + optionalString (cfg.credentials != []) - (concatStringsSep "\n" - (imap0 + '' + lib.optionalString (cfg.credentials != []) + (lib.concatStringsSep "\n" + (lib.imap0 (i: c: ''${pkgs.replace-secret}/bin/replace-secret '{{password-${toString i}}}' '${c.passwordFile}' /run/mpd/mpd.conf'') cfg.credentials)); @@ -242,13 +239,13 @@ in { ExecStart = [ "" "${pkgs.mpd}/bin/mpd --systemd /run/mpd/mpd.conf" ]; RuntimeDirectory = "mpd"; StateDirectory = [] - ++ optionals (cfg.dataDir == "/var/lib/${name}") [ name ] - ++ optionals (cfg.playlistDirectory == "/var/lib/${name}/playlists") [ name "${name}/playlists" ] - ++ optionals (cfg.musicDirectory == "/var/lib/${name}/music") [ name "${name}/music" ]; + ++ lib.optionals (cfg.dataDir == "/var/lib/${name}") [ name ] + ++ lib.optionals (cfg.playlistDirectory == "/var/lib/${name}/playlists") [ name "${name}/playlists" ] + ++ lib.optionals (cfg.musicDirectory == "/var/lib/${name}/music") [ name "${name}/music" ]; }; }; - users.users = optionalAttrs (cfg.user == name) { + users.users = lib.optionalAttrs (cfg.user == name) { ${name} = { inherit uid; group = cfg.group; @@ -258,7 +255,7 @@ in { }; }; - users.groups = optionalAttrs (cfg.group == name) { + users.groups = lib.optionalAttrs (cfg.group == name) { ${name}.gid = gid; }; }; diff --git a/nixos/modules/services/audio/snapserver.nix b/nixos/modules/services/audio/snapserver.nix index e624dacf34bf..c1e5f8cf43e1 100644 --- a/nixos/modules/services/audio/snapserver.nix +++ b/nixos/modules/services/audio/snapserver.nix @@ -1,7 +1,4 @@ { config, options, lib, pkgs, ... }: - -with lib; - let name = "snapserver"; @@ -9,8 +6,8 @@ let cfg = config.services.snapserver; # Using types.nullOr to inherit upstream defaults. - sampleFormat = mkOption { - type = with types; nullOr str; + sampleFormat = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Default sample format. @@ -18,8 +15,8 @@ let example = "48000:16:2"; }; - codec = mkOption { - type = with types; nullOr str; + codec = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Default audio compression method. @@ -30,20 +27,20 @@ let streamToOption = name: opt: let os = val: - optionalString (val != null) "${val}"; + lib.optionalString (val != null) "${val}"; os' = prefix: val: - optionalString (val != null) (prefix + "${val}"); - flatten = key: value: + lib.optionalString (val != null) (prefix + "${val}"); + toQueryString = key: value: "&${key}=${value}"; in "--stream.stream=\"${opt.type}://" + os opt.location + "?" + os' "name=" name + os' "&sampleformat=" opt.sampleFormat + os' "&codec=" opt.codec - + concatStrings (mapAttrsToList flatten opt.query) + "\""; + + lib.concatStrings (lib.mapAttrsToList toQueryString opt.query) + "\""; optionalNull = val: ret: - optional (val != null) ret; + lib.optional (val != null) ret; - optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams + optionString = lib.concatStringsSep " " (lib.mapAttrsToList streamToOption cfg.streams # global options ++ [ "--stream.bind_to_address=${cfg.listenAddress}" ] ++ [ "--stream.port=${toString cfg.port}" ] @@ -51,22 +48,22 @@ let ++ optionalNull cfg.codec "--stream.codec=${cfg.codec}" ++ optionalNull cfg.streamBuffer "--stream.stream_buffer=${toString cfg.streamBuffer}" ++ optionalNull cfg.buffer "--stream.buffer=${toString cfg.buffer}" - ++ optional cfg.sendToMuted "--stream.send_to_muted" + ++ lib.optional cfg.sendToMuted "--stream.send_to_muted" # tcp json rpc ++ [ "--tcp.enabled=${toString cfg.tcp.enable}" ] - ++ optionals cfg.tcp.enable [ + ++ lib.optionals cfg.tcp.enable [ "--tcp.bind_to_address=${cfg.tcp.listenAddress}" "--tcp.port=${toString cfg.tcp.port}" ] # http json rpc ++ [ "--http.enabled=${toString cfg.http.enable}" ] - ++ optionals cfg.http.enable [ + ++ lib.optionals cfg.http.enable [ "--http.bind_to_address=${cfg.http.listenAddress}" "--http.port=${toString cfg.http.port}" - ] ++ optional (cfg.http.docRoot != null) "--http.doc_root=\"${toString cfg.http.docRoot}\""); + ] ++ lib.optional (cfg.http.docRoot != null) "--http.doc_root=\"${toString cfg.http.docRoot}\""); in { imports = [ - (mkRenamedOptionModule [ "services" "snapserver" "controlPort" ] [ "services" "snapserver" "tcp" "port" ]) + (lib.mkRenamedOptionModule [ "services" "snapserver" "controlPort" ] [ "services" "snapserver" "tcp" "port" ]) ]; ###### interface @@ -75,16 +72,16 @@ in { services.snapserver = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable snapserver. ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "::"; example = "0.0.0.0"; description = '' @@ -92,16 +89,16 @@ in { ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 1704; description = '' The port that snapclients can connect to. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to automatically open the specified ports in the firewall. @@ -111,8 +108,8 @@ in { inherit sampleFormat; inherit codec; - streamBuffer = mkOption { - type = with types; nullOr int; + streamBuffer = lib.mkOption { + type = with lib.types; nullOr int; default = null; description = '' Stream read (input) buffer in ms. @@ -120,8 +117,8 @@ in { example = 20; }; - buffer = mkOption { - type = with types; nullOr int; + buffer = lib.mkOption { + type = with lib.types; nullOr int; default = null; description = '' Network buffer in ms. @@ -129,24 +126,24 @@ in { example = 1000; }; - sendToMuted = mkOption { - type = types.bool; + sendToMuted = lib.mkOption { + type = lib.types.bool; default = false; description = '' Send audio to muted clients. ''; }; - tcp.enable = mkOption { - type = types.bool; + tcp.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable the JSON-RPC via TCP. ''; }; - tcp.listenAddress = mkOption { - type = types.str; + tcp.listenAddress = lib.mkOption { + type = lib.types.str; default = "::"; example = "0.0.0.0"; description = '' @@ -154,24 +151,24 @@ in { ''; }; - tcp.port = mkOption { - type = types.port; + tcp.port = lib.mkOption { + type = lib.types.port; default = 1705; description = '' The port where the TCP JSON-RPC listens on. ''; }; - http.enable = mkOption { - type = types.bool; + http.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable the JSON-RPC via HTTP. ''; }; - http.listenAddress = mkOption { - type = types.str; + http.listenAddress = lib.mkOption { + type = lib.types.str; default = "::"; example = "0.0.0.0"; description = '' @@ -179,27 +176,28 @@ in { ''; }; - http.port = mkOption { - type = types.port; + http.port = lib.mkOption { + type = lib.types.port; default = 1780; description = '' The port where the HTTP JSON-RPC listens on. ''; }; - http.docRoot = mkOption { - type = with types; nullOr path; - default = null; + http.docRoot = lib.mkOption { + type = with lib.types; nullOr path; + default = pkgs.snapweb; + defaultText = lib.literalExpression "pkgs.snapweb"; description = '' Path to serve from the HTTP servers root. ''; }; - streams = mkOption { - type = with types; attrsOf (submodule { + streams = lib.mkOption { + type = with lib.types; attrsOf (submodule { options = { - location = mkOption { - type = types.oneOf [ types.path types.str ]; + location = lib.mkOption { + type = lib.types.oneOf [ lib.types.path lib.types.str ]; description = '' For type `pipe` or `file`, the path to the pipe or file. For type `librespot`, `airplay` or `process`, the path to the corresponding binary. @@ -207,27 +205,27 @@ in { For type `meta`, a list of stream names in the form `/one/two/...`. Don't forget the leading slash. For type `alsa`, use an empty string. ''; - example = literalExpression '' + example = lib.literalExpression '' "/path/to/pipe" "/path/to/librespot" "192.168.1.2:4444" "/MyTCP/Spotify/MyPipe" ''; }; - type = mkOption { - type = types.enum [ "pipe" "librespot" "airplay" "file" "process" "tcp" "alsa" "spotify" "meta" ]; + type = lib.mkOption { + type = lib.types.enum [ "pipe" "librespot" "airplay" "file" "process" "tcp" "alsa" "spotify" "meta" ]; default = "pipe"; description = '' The type of input stream. ''; }; - query = mkOption { + query = lib.mkOption { type = attrsOf str; default = {}; description = '' Key-value pairs that convey additional parameters about a stream. ''; - example = literalExpression '' + example = lib.literalExpression '' # for type == "pipe": { mode = "create"; @@ -255,7 +253,7 @@ in { description = '' The definition for an input source. ''; - example = literalExpression '' + example = lib.literalExpression '' { mpd = { type = "pipe"; @@ -272,16 +270,16 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { warnings = # https://github.com/badaix/snapcast/blob/98ac8b2fb7305084376607b59173ce4097c620d8/server/streamreader/stream_manager.cpp#L85 - filter (w: w != "") (mapAttrsToList (k: v: optionalString (v.type == "spotify") '' + lib.filter (w: w != "") (lib.mapAttrsToList (k: v: lib.optionalString (v.type == "spotify") '' services.snapserver.streams.${k}.type = "spotify" is deprecated, use services.snapserver.streams.${k}.type = "librespot" instead. '') cfg.streams); systemd.services.snapserver = { - after = [ "network.target" ]; + after = [ "network.target" "nss-lookup.target" ]; description = "Snapserver"; wantedBy = [ "multi-user.target" ]; before = [ "mpd.service" "mopidy.service" ]; @@ -305,13 +303,13 @@ in { }; networking.firewall.allowedTCPPorts = - optionals cfg.openFirewall [ cfg.port ] - ++ optional (cfg.openFirewall && cfg.tcp.enable) cfg.tcp.port - ++ optional (cfg.openFirewall && cfg.http.enable) cfg.http.port; + lib.optionals cfg.openFirewall [ cfg.port ] + ++ lib.optional (cfg.openFirewall && cfg.tcp.enable) cfg.tcp.port + ++ lib.optional (cfg.openFirewall && cfg.http.enable) cfg.http.port; }; meta = { - maintainers = with maintainers; [ tobim ]; + maintainers = with lib.maintainers; [ tobim ]; }; } diff --git a/nixos/modules/services/backup/automysqlbackup.nix b/nixos/modules/services/backup/automysqlbackup.nix index cf3b6b8d13a4..d5efda74f26f 100644 --- a/nixos/modules/services/backup/automysqlbackup.nix +++ b/nixos/modules/services/backup/automysqlbackup.nix @@ -118,15 +118,6 @@ in name = user; ensurePermissions = { "*.*" = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT"; - - # https://forums.mysql.com/read.php?10,668311,668315#msg-668315 - "function sys.extract_table_from_file_name" = "execute"; - "function sys.format_path" = "execute"; - "function sys.format_statement" = "execute"; - "function sys.extract_schema_from_file_name" = "execute"; - "function sys.ps_thread_account" = "execute"; - "function sys.format_time" = "execute"; - "function sys.format_bytes" = "execute"; }; }; diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix index 94f6e6ba4fd5..0851b5b0bf14 100644 --- a/nixos/modules/services/backup/bacula.nix +++ b/nixos/modules/services/backup/bacula.nix @@ -656,6 +656,11 @@ in { }; config = mkIf (fd_cfg.enable || sd_cfg.enable || dir_cfg.enable) { + systemd.slices.system-bacula = { + description = "Bacula Backup System Slice"; + documentation = [ "man:bacula(8)" "https://www.bacula.org/" ]; + }; + systemd.services.bacula-fd = mkIf fd_cfg.enable { after = [ "network.target" ]; description = "Bacula File Daemon"; @@ -666,6 +671,7 @@ in { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; LogsDirectory = "bacula"; StateDirectory = "bacula"; + Slice = "system-bacula.slice"; }; }; @@ -679,6 +685,7 @@ in { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; LogsDirectory = "bacula"; StateDirectory = "bacula"; + Slice = "system-bacula.slice"; }; }; @@ -694,6 +701,7 @@ in { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; LogsDirectory = "bacula"; StateDirectory = "bacula"; + Slice = "system-bacula.slice"; }; preStart = '' if ! test -e "${libDir}/db-created"; then diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix index abb7925e0935..36f2274d5eaa 100644 --- a/nixos/modules/services/backup/borgbackup.nix +++ b/nixos/modules/services/backup/borgbackup.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let isLocalPath = x: @@ -11,17 +8,17 @@ let mkExcludeFile = cfg: # Write each exclude pattern to a new line - pkgs.writeText "excludefile" (concatMapStrings (s: s + "\n") cfg.exclude); + pkgs.writeText "excludefile" (lib.concatMapStrings (s: s + "\n") cfg.exclude); mkPatternsFile = cfg: # Write each pattern to a new line - pkgs.writeText "patternsfile" (concatMapStrings (s: s + "\n") cfg.patterns); + pkgs.writeText "patternsfile" (lib.concatMapStrings (s: s + "\n") cfg.patterns); mkKeepArgs = cfg: # If cfg.prune.keep e.g. has a yearly attribute, # its content is passed on as --keep-yearly - concatStringsSep " " - (mapAttrsToList (x: y: "--keep-${x}=${toString y}") cfg.prune.keep); + lib.concatStringsSep " " + (lib.mapAttrsToList (x: y: "--keep-${x}=${toString y}") cfg.prune.keep); mkBackupScript = name: cfg: pkgs.writeShellScript "${name}-script" ('' set -e @@ -44,10 +41,10 @@ let fi } - archiveName="${optionalString (cfg.archiveBaseName != null) (cfg.archiveBaseName + "-")}$(date ${cfg.dateFormat})" - archiveSuffix="${optionalString cfg.appendFailedSuffix ".failed"}" + archiveName="${lib.optionalString (cfg.archiveBaseName != null) (cfg.archiveBaseName + "-")}$(date ${cfg.dateFormat})" + archiveSuffix="${lib.optionalString cfg.appendFailedSuffix ".failed"}" ${cfg.preHook} - '' + optionalString cfg.doInit '' + '' + lib.optionalString cfg.doInit '' # Run borg init if the repo doesn't exist yet if ! borgWrapper list $extraArgs > /dev/null; then borgWrapper init $extraArgs \ @@ -58,24 +55,24 @@ let '' + '' ( set -o pipefail - ${optionalString (cfg.dumpCommand != null) ''${escapeShellArg cfg.dumpCommand} | \''} + ${lib.optionalString (cfg.dumpCommand != null) ''${lib.escapeShellArg cfg.dumpCommand} | \''} borgWrapper create $extraArgs \ --compression ${cfg.compression} \ --exclude-from ${mkExcludeFile cfg} \ --patterns-from ${mkPatternsFile cfg} \ $extraCreateArgs \ "::$archiveName$archiveSuffix" \ - ${if cfg.paths == null then "-" else escapeShellArgs cfg.paths} + ${if cfg.paths == null then "-" else lib.escapeShellArgs cfg.paths} ) - '' + optionalString cfg.appendFailedSuffix '' + '' + lib.optionalString cfg.appendFailedSuffix '' borgWrapper rename $extraArgs \ "::$archiveName$archiveSuffix" "$archiveName" '' + '' ${cfg.postCreate} - '' + optionalString (cfg.prune.keep != { }) '' + '' + lib.optionalString (cfg.prune.keep != { }) '' borgWrapper prune $extraArgs \ ${mkKeepArgs cfg} \ - ${optionalString (cfg.prune.prefix != null) "--glob-archives ${escapeShellArg "${cfg.prune.prefix}*"}"} \ + ${lib.optionalString (cfg.prune.prefix != null) "--glob-archives ${lib.escapeShellArg "${cfg.prune.prefix}*"}"} \ $extraPruneArgs borgWrapper compact $extraArgs $extraCompactArgs ${cfg.postPrune} @@ -93,18 +90,18 @@ let userHome = config.users.users.${cfg.user}.home; backupJobName = "borgbackup-job-${name}"; backupScript = mkBackupScript backupJobName cfg; - in nameValuePair backupJobName { + in lib.nameValuePair backupJobName { description = "BorgBackup job ${name}"; path = [ config.services.borgbackup.package pkgs.openssh ]; - script = "exec " + optionalString cfg.inhibitsSleep ''\ + script = "exec " + lib.optionalString cfg.inhibitsSleep ''\ ${pkgs.systemd}/bin/systemd-inhibit \ --who="borgbackup" \ --what="sleep" \ --why="Scheduled backup" \ '' + backupScript; - unitConfig = optionalAttrs (isLocalPath cfg.repo) { + unitConfig = lib.optionalAttrs (isLocalPath cfg.repo) { RequiresMountsFor = [ cfg.repo ]; }; serviceConfig = { @@ -118,7 +115,7 @@ let [ "${userHome}/.config/borg" "${userHome}/.cache/borg" ] ++ cfg.readWritePaths # Borg needs write access to repo if it is not remote - ++ optional (isLocalPath cfg.repo) cfg.repo; + ++ lib.optional (isLocalPath cfg.repo) cfg.repo; PrivateTmp = cfg.privateTmp; }; environment = { @@ -128,7 +125,7 @@ let }; mkBackupTimers = name: cfg: - nameValuePair "borgbackup-job-${name}" { + lib.nameValuePair "borgbackup-job-${name}" { description = "BorgBackup job ${name} timer"; wantedBy = [ "timers.target" ]; timerConfig = { @@ -136,8 +133,8 @@ let OnCalendar = cfg.startAt; }; # if remote-backup wait for network - after = optional (cfg.persistentTimer && !isLocalPath cfg.repo) "network-online.target"; - wants = optional (cfg.persistentTimer && !isLocalPath cfg.repo) "network-online.target"; + after = lib.optional (cfg.persistentTimer && !isLocalPath cfg.repo) "network-online.target"; + wants = lib.optional (cfg.persistentTimer && !isLocalPath cfg.repo) "network-online.target"; }; # utility function around makeWrapper @@ -148,11 +145,11 @@ let nativeBuildInputs = [ pkgs.makeWrapper ]; } (with lib; '' makeWrapper "${original}" "$out/bin/${name}" \ - ${concatStringsSep " \\\n " (mapAttrsToList (name: value: ''--set ${name} "${value}"'') set)} + ${lib.concatStringsSep " \\\n " (lib.mapAttrsToList (name: value: ''--set ${name} "${value}"'') set)} ''); mkBorgWrapper = name: cfg: mkWrapperDrv { - original = getExe config.services.borgbackup.package; + original = lib.getExe config.services.borgbackup.package; name = "borg-job-${name}"; set = { BORG_REPO = cfg.repo; } // (mkPassEnv cfg) // cfg.environment; }; @@ -167,7 +164,7 @@ let "${config.users.users."${cfg.user}".home}/.cache".d = settings; "${config.users.users."${cfg.user}".home}/.config/borg".d = settings; "${config.users.users."${cfg.user}".home}/.cache/borg".d = settings; - } // optionalAttrs (isLocalPath cfg.repo && !cfg.removableDevice) { + } // lib.optionalAttrs (isLocalPath cfg.repo && !cfg.removableDevice) { "${cfg.repo}".d = settings; }); @@ -180,11 +177,11 @@ let }; mkRepoService = name: cfg: - nameValuePair "borgbackup-repo-${name}" { + lib.nameValuePair "borgbackup-repo-${name}" { description = "Create BorgBackup repository ${name} directory"; script = '' - mkdir -p ${escapeShellArg cfg.path} - chown ${cfg.user}:${cfg.group} ${escapeShellArg cfg.path} + mkdir -p ${lib.escapeShellArg cfg.path} + chown ${cfg.user}:${cfg.group} ${lib.escapeShellArg cfg.path} ''; serviceConfig = { # The service's only task is to ensure that the specified path exists @@ -196,10 +193,10 @@ let mkAuthorizedKey = cfg: appendOnly: key: let # Because of the following line, clients do not need to specify an absolute repo path - cdCommand = "cd ${escapeShellArg cfg.path}"; + cdCommand = "cd ${lib.escapeShellArg cfg.path}"; restrictedArg = "--restrict-to-${if cfg.allowSubRepos then "path" else "repository"} ."; - appendOnlyArg = optionalString appendOnly "--append-only"; - quotaArg = optionalString (cfg.quota != null) "--storage-quota ${cfg.quota}"; + appendOnlyArg = lib.optionalString appendOnly "--append-only"; + quotaArg = lib.optionalString (cfg.quota != null) "--storage-quota ${cfg.quota}"; serveCommand = "borg serve ${restrictedArg} ${appendOnlyArg} ${quotaArg}"; in ''command="${cdCommand} && ${serveCommand}",restrict ${key}''; @@ -224,7 +221,7 @@ let }; mkSourceAssertions = name: cfg: { - assertion = count isNull [ cfg.dumpCommand cfg.paths ] == 1; + assertion = lib.count isNull [ cfg.dumpCommand cfg.paths ] == 1; message = '' Exactly one of borgbackup.jobs.${name}.paths or borgbackup.jobs.${name}.dumpCommand must be set. @@ -239,14 +236,14 @@ let }; in { - meta.maintainers = with maintainers; [ dotlambda ]; + meta.maintainers = with lib.maintainers; [ dotlambda ]; meta.doc = ./borgbackup.md; ###### interface - options.services.borgbackup.package = mkPackageOption pkgs "borgbackup" { }; + options.services.borgbackup.package = lib.mkPackageOption pkgs "borgbackup" { }; - options.services.borgbackup.jobs = mkOption { + options.services.borgbackup.jobs = lib.mkOption { description = '' Deduplicating backups using BorgBackup. Adding a job will cause a borg-job-NAME wrapper to be added @@ -254,7 +251,7 @@ in { See also the chapter about BorgBackup in the NixOS manual. ''; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { # for a local backup rootBackup = { paths = "/"; @@ -286,12 +283,12 @@ in { startAt = "daily"; }; ''; - type = types.attrsOf (types.submodule (let globalConfig = config; in + type = lib.types.attrsOf (lib.types.submodule (let globalConfig = config; in { name, config, ... }: { options = { - paths = mkOption { - type = with types; nullOr (coercedTo str lib.singleton (listOf str)); + paths = lib.mkOption { + type = with lib.types; nullOr (coercedTo str lib.singleton (listOf str)); default = null; description = '' Path(s) to back up. @@ -300,8 +297,8 @@ in { example = "/home/user"; }; - dumpCommand = mkOption { - type = with types; nullOr path; + dumpCommand = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' Backup the stdout of this program instead of filesystem paths. @@ -310,22 +307,22 @@ in { example = "/path/to/createZFSsend.sh"; }; - repo = mkOption { - type = types.str; + repo = lib.mkOption { + type = lib.types.str; description = "Remote or local repository to back up to."; example = "user@machine:/path/to/repo"; }; - removableDevice = mkOption { - type = types.bool; + removableDevice = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether the repo (which must be local) is a removable device."; }; - archiveBaseName = mkOption { - type = types.nullOr (types.strMatching "[^/{}]+"); + archiveBaseName = lib.mkOption { + type = lib.types.nullOr (lib.types.strMatching "[^/{}]+"); default = "${globalConfig.networking.hostName}-${name}"; - defaultText = literalExpression ''"''${config.networking.hostName}-"''; + defaultText = lib.literalExpression ''"''${config.networking.hostName}-"''; description = '' How to name the created archives. A timestamp, whose format is determined by {option}`dateFormat`, will be appended. The full @@ -335,8 +332,8 @@ in { ''; }; - dateFormat = mkOption { - type = types.str; + dateFormat = lib.mkOption { + type = lib.types.str; description = '' Arguments passed to {command}`date` to create a timestamp suffix for the archive name. @@ -345,8 +342,8 @@ in { example = "-u +%s"; }; - startAt = mkOption { - type = with types; either str (listOf str); + startAt = lib.mkOption { + type = with lib.types; either str (listOf str); default = "daily"; description = '' When or how often the backup should run. @@ -359,9 +356,9 @@ in { ''; }; - persistentTimer = mkOption { + persistentTimer = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; example = true; description = '' Set the `Persistent` option for the @@ -371,17 +368,17 @@ in { ''; }; - inhibitsSleep = mkOption { + inhibitsSleep = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; example = true; description = '' Prevents the system from sleeping while backing up. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = '' The user {command}`borg` is run as. User or group need read permission @@ -390,8 +387,8 @@ in { default = "root"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; description = '' The group borg is run as. User or group needs read permission for the specified {option}`paths`. @@ -399,8 +396,8 @@ in { default = "root"; }; - encryption.mode = mkOption { - type = types.enum [ + encryption.mode = lib.mkOption { + type = lib.types.enum [ "repokey" "keyfile" "repokey-blake2" "keyfile-blake2" "authenticated" "authenticated-blake2" @@ -415,8 +412,8 @@ in { example = "repokey-blake2"; }; - encryption.passCommand = mkOption { - type = with types; nullOr str; + encryption.passCommand = lib.mkOption { + type = with lib.types; nullOr str; description = '' A command which prints the passphrase to stdout. Mutually exclusive with {option}`passphrase`. @@ -425,8 +422,8 @@ in { example = "cat /path/to/passphrase_file"; }; - encryption.passphrase = mkOption { - type = with types; nullOr str; + encryption.passphrase = lib.mkOption { + type = with lib.types; nullOr str; description = '' The passphrase the backups are encrypted with. Mutually exclusive with {option}`passCommand`. @@ -436,11 +433,11 @@ in { default = null; }; - compression = mkOption { + compression = lib.mkOption { # "auto" is optional, # compression mode must be given, # compression level is optional - type = types.strMatching "none|(auto,)?(lz4|zstd|zlib|lzma)(,[[:digit:]]{1,2})?"; + type = lib.types.strMatching "none|(auto,)?(lz4|zstd|zlib|lzma)(,[[:digit:]]{1,2})?"; description = '' Compression method to use. Refer to {command}`borg help compression` @@ -450,8 +447,8 @@ in { example = "auto,lzma"; }; - exclude = mkOption { - type = with types; listOf str; + exclude = lib.mkOption { + type = with lib.types; listOf str; description = '' Exclude paths matching any of the given patterns. See {command}`borg help patterns` for pattern syntax. @@ -463,8 +460,8 @@ in { ]; }; - patterns = mkOption { - type = with types; listOf str; + patterns = lib.mkOption { + type = with lib.types; listOf str; description = '' Include/exclude paths matching the given patterns. The first matching patterns is used, so if an include pattern (prefix `+`) @@ -478,8 +475,8 @@ in { ]; }; - readWritePaths = mkOption { - type = with types; listOf path; + readWritePaths = lib.mkOption { + type = with lib.types; listOf path; description = '' By default, borg cannot write anywhere on the system but `$HOME/.config/borg` and `$HOME/.cache/borg`. @@ -492,8 +489,8 @@ in { ]; }; - privateTmp = mkOption { - type = types.bool; + privateTmp = lib.mkOption { + type = lib.types.bool; description = '' Set the `PrivateTmp` option for the systemd-service. Set to false if you need sockets @@ -502,8 +499,8 @@ in { default = true; }; - failOnWarnings = mkOption { - type = types.bool; + failOnWarnings = lib.mkOption { + type = lib.types.bool; description = '' Fail the whole backup job if any borg command returns a warning (exit code 1), for example because a file changed during backup. @@ -511,8 +508,8 @@ in { default = true; }; - doInit = mkOption { - type = types.bool; + doInit = lib.mkOption { + type = lib.types.bool; description = '' Run {command}`borg init` if the specified {option}`repo` does not exist. @@ -523,8 +520,8 @@ in { default = true; }; - appendFailedSuffix = mkOption { - type = types.bool; + appendFailedSuffix = lib.mkOption { + type = lib.types.bool; description = '' Append a `.failed` suffix to the archive name, which is only removed if @@ -533,18 +530,18 @@ in { default = true; }; - prune.keep = mkOption { + prune.keep = lib.mkOption { # Specifying e.g. `prune.keep.yearly = -1` # means there is no limit of yearly archives to keep # The regex is for use with e.g. --keep-within 1y - type = with types; attrsOf (either int (strMatching "[[:digit:]]+[Hdwmy]")); + type = with lib.types; attrsOf (either int (strMatching "[[:digit:]]+[Hdwmy]")); description = '' Prune a repository by deleting all archives not matching any of the specified retention options. See {command}`borg help prune` for the available options. ''; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { within = "1d"; # Keep all archives from the last day daily = 7; @@ -554,19 +551,19 @@ in { ''; }; - prune.prefix = mkOption { - type = types.nullOr (types.str); + prune.prefix = lib.mkOption { + type = lib.types.nullOr (lib.types.str); description = '' Only consider archive names starting with this prefix for pruning. By default, only archives created by this job are considered. Use `""` or `null` to consider all archives. ''; default = config.archiveBaseName; - defaultText = literalExpression "archiveBaseName"; + defaultText = lib.literalExpression "archiveBaseName"; }; - environment = mkOption { - type = with types; attrsOf str; + environment = lib.mkOption { + type = with lib.types; attrsOf str; description = '' Environment variables passed to the backup script. You can for example specify which SSH key to use. @@ -575,8 +572,8 @@ in { example = { BORG_RSH = "ssh -i /path/to/key"; }; }; - preHook = mkOption { - type = types.lines; + preHook = lib.mkOption { + type = lib.types.lines; description = '' Shell commands to run before the backup. This can for example be used to mount file systems. @@ -588,16 +585,16 @@ in { ''; }; - postInit = mkOption { - type = types.lines; + postInit = lib.mkOption { + type = lib.types.lines; description = '' Shell commands to run after {command}`borg init`. ''; default = ""; }; - postCreate = mkOption { - type = types.lines; + postCreate = lib.mkOption { + type = lib.types.lines; description = '' Shell commands to run after {command}`borg create`. The name of the created archive is stored in `$archiveName`. @@ -605,16 +602,16 @@ in { default = ""; }; - postPrune = mkOption { - type = types.lines; + postPrune = lib.mkOption { + type = lib.types.lines; description = '' Shell commands to run after {command}`borg prune`. ''; default = ""; }; - postHook = mkOption { - type = types.lines; + postHook = lib.mkOption { + type = lib.types.lines; description = '' Shell commands to run just before exit. They are executed even if a previous command exits with a non-zero exit code. @@ -623,8 +620,8 @@ in { default = ""; }; - extraArgs = mkOption { - type = with types; coercedTo (listOf str) escapeShellArgs str; + extraArgs = lib.mkOption { + type = with lib.types; coercedTo (listOf str) lib.escapeShellArgs str; description = '' Additional arguments for all {command}`borg` calls the service has. Handle with care. @@ -633,8 +630,8 @@ in { example = [ "--remote-path=/path/to/borg" ]; }; - extraInitArgs = mkOption { - type = with types; coercedTo (listOf str) escapeShellArgs str; + extraInitArgs = lib.mkOption { + type = with lib.types; coercedTo (listOf str) lib.escapeShellArgs str; description = '' Additional arguments for {command}`borg init`. Can also be set at runtime using `$extraInitArgs`. @@ -643,8 +640,8 @@ in { example = [ "--append-only" ]; }; - extraCreateArgs = mkOption { - type = with types; coercedTo (listOf str) escapeShellArgs str; + extraCreateArgs = lib.mkOption { + type = with lib.types; coercedTo (listOf str) lib.escapeShellArgs str; description = '' Additional arguments for {command}`borg create`. Can also be set at runtime using `$extraCreateArgs`. @@ -656,8 +653,8 @@ in { ]; }; - extraPruneArgs = mkOption { - type = with types; coercedTo (listOf str) escapeShellArgs str; + extraPruneArgs = lib.mkOption { + type = with lib.types; coercedTo (listOf str) lib.escapeShellArgs str; description = '' Additional arguments for {command}`borg prune`. Can also be set at runtime using `$extraPruneArgs`. @@ -666,8 +663,8 @@ in { example = [ "--save-space" ]; }; - extraCompactArgs = mkOption { - type = with types; coercedTo (listOf str) escapeShellArgs str; + extraCompactArgs = lib.mkOption { + type = with lib.types; coercedTo (listOf str) lib.escapeShellArgs str; description = '' Additional arguments for {command}`borg compact`. Can also be set at runtime using `$extraCompactArgs`. @@ -680,7 +677,7 @@ in { )); }; - options.services.borgbackup.repos = mkOption { + options.services.borgbackup.repos = lib.mkOption { description = '' Serve BorgBackup repositories to given public SSH keys, restricting their access to the repository only. @@ -689,11 +686,11 @@ in { i.e. `user@machine:.` is enough. (Note colon and dot.) ''; default = { }; - type = types.attrsOf (types.submodule ( + type = lib.types.attrsOf (lib.types.submodule ( { ... }: { options = { - path = mkOption { - type = types.path; + path = lib.mkOption { + type = lib.types.path; description = '' Where to store the backups. Note that the directory is created automatically, with correct permissions. @@ -701,8 +698,8 @@ in { default = "/var/lib/borgbackup"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = '' The user {command}`borg serve` is run as. User or group needs write permission @@ -711,8 +708,8 @@ in { default = "borg"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; description = '' The group {command}`borg serve` is run as. User or group needs write permission @@ -721,8 +718,8 @@ in { default = "borg"; }; - authorizedKeys = mkOption { - type = with types; listOf str; + authorizedKeys = lib.mkOption { + type = with lib.types; listOf str; description = '' Public SSH keys that are given full write access to this repository. You should use a different SSH key for each repository you write to, because @@ -732,8 +729,8 @@ in { default = [ ]; }; - authorizedKeysAppendOnly = mkOption { - type = with types; listOf str; + authorizedKeysAppendOnly = lib.mkOption { + type = with lib.types; listOf str; description = '' Public SSH keys that can only be used to append new data (archives) to the repository. Note that archives can still be marked as deleted and are subsequently removed from disk @@ -742,8 +739,8 @@ in { default = [ ]; }; - allowSubRepos = mkOption { - type = types.bool; + allowSubRepos = lib.mkOption { + type = lib.types.bool; description = '' Allow clients to create repositories in subdirectories of the specified {option}`path`. These can be accessed using @@ -755,9 +752,9 @@ in { default = false; }; - quota = mkOption { + quota = lib.mkOption { # See the definition of parse_file_size() in src/borg/helpers/parseformat.py - type = with types; nullOr (strMatching "[[:digit:].]+[KMGTP]?"); + type = with lib.types; nullOr (strMatching "[[:digit:].]+[KMGTP]?"); description = '' Storage quota for the repository. This quota is ensured for all sub-repositories if {option}`allowSubRepos` is enabled @@ -774,29 +771,29 @@ in { ###### implementation - config = mkIf (with config.services.borgbackup; jobs != { } || repos != { }) + config = lib.mkIf (with config.services.borgbackup; jobs != { } || repos != { }) (with config.services.borgbackup; { assertions = - mapAttrsToList mkPassAssertion jobs - ++ mapAttrsToList mkKeysAssertion repos - ++ mapAttrsToList mkSourceAssertions jobs - ++ mapAttrsToList mkRemovableDeviceAssertions jobs; + lib.mapAttrsToList mkPassAssertion jobs + ++ lib.mapAttrsToList mkKeysAssertion repos + ++ lib.mapAttrsToList mkSourceAssertions jobs + ++ lib.mapAttrsToList mkRemovableDeviceAssertions jobs; - systemd.tmpfiles.settings = mapAttrs' mkTmpfiles jobs; + systemd.tmpfiles.settings = lib.mapAttrs' mkTmpfiles jobs; systemd.services = # A job named "foo" is mapped to systemd.services.borgbackup-job-foo - mapAttrs' mkBackupService jobs + lib.mapAttrs' mkBackupService jobs # A repo named "foo" is mapped to systemd.services.borgbackup-repo-foo - // mapAttrs' mkRepoService repos; + // lib.mapAttrs' mkRepoService repos; # A job named "foo" is mapped to systemd.timers.borgbackup-job-foo # only generate the timer if interval (startAt) is set - systemd.timers = mapAttrs' mkBackupTimers (filterAttrs (_: cfg: cfg.startAt != []) jobs); + systemd.timers = lib.mapAttrs' mkBackupTimers (lib.filterAttrs (_: cfg: cfg.startAt != []) jobs); - users = mkMerge (mapAttrsToList mkUsersConfig repos); + users = lib.mkMerge (lib.mapAttrsToList mkUsersConfig repos); environment.systemPackages = - [ config.services.borgbackup.package ] ++ (mapAttrsToList mkBorgWrapper jobs); + [ config.services.borgbackup.package ] ++ (lib.mapAttrsToList mkBorgWrapper jobs); }); } diff --git a/nixos/modules/services/backup/mysql-backup.nix b/nixos/modules/services/backup/mysql-backup.nix index e3fa7f45844f..8ad4f98dce8a 100644 --- a/nixos/modules/services/backup/mysql-backup.nix +++ b/nixos/modules/services/backup/mysql-backup.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let inherit (pkgs) mariadb gzip; @@ -12,7 +9,7 @@ let backupScript = '' set -o pipefail failed="" - ${concatMapStringsSep "\n" backupDatabaseScript cfg.databases} + ${lib.concatMapStringsSep "\n" backupDatabaseScript cfg.databases} if [ -n "$failed" ]; then echo "Backup of database(s) failed:$failed" exit 1 @@ -20,7 +17,7 @@ let ''; backupDatabaseScript = db: '' dest="${cfg.location}/${db}.gz" - if ${mariadb}/bin/mysqldump ${optionalString cfg.singleTransaction "--single-transaction"} ${db} | ${gzip}/bin/gzip -c ${cfg.gzipOptions} > $dest.tmp; then + if ${mariadb}/bin/mysqldump ${lib.optionalString cfg.singleTransaction "--single-transaction"} ${db} | ${gzip}/bin/gzip -c ${cfg.gzipOptions} > $dest.tmp; then mv $dest.tmp $dest echo "Backed up to $dest" else @@ -37,51 +34,51 @@ in services.mysqlBackup = { - enable = mkEnableOption "MySQL backups"; + enable = lib.mkEnableOption "MySQL backups"; - calendar = mkOption { - type = types.str; + calendar = lib.mkOption { + type = lib.types.str; default = "01:15:00"; description = '' Configured when to run the backup service systemd unit (DayOfWeek Year-Month-Day Hour:Minute:Second). ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = defaultUser; description = '' User to be used to perform backup. ''; }; - databases = mkOption { + databases = lib.mkOption { default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' List of database names to dump. ''; }; - location = mkOption { - type = types.path; + location = lib.mkOption { + type = lib.types.path; default = "/var/backup/mysql"; description = '' Location to put the gzipped MySQL database dumps. ''; }; - singleTransaction = mkOption { + singleTransaction = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to create database dump in a single transaction ''; }; - gzipOptions = mkOption { + gzipOptions = lib.mkOption { default = "--no-name --rsyncable"; - type = types.str; + type = lib.types.str; description = '' Command line options to use when invoking `gzip`. ''; @@ -90,8 +87,8 @@ in }; - config = mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == defaultUser) { + config = lib.mkIf cfg.enable { + users.users = lib.optionalAttrs (cfg.user == defaultUser) { ${defaultUser} = { isSystemUser = true; createHome = false; @@ -105,9 +102,9 @@ in ensurePermissions = with lib; let privs = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES"; - grant = db: nameValuePair "${db}.*" privs; + grant = db: lib.nameValuePair "${db}.*" privs; in - listToAttrs (map grant cfg.databases); + lib.listToAttrs (map grant cfg.databases); }]; systemd = { diff --git a/nixos/modules/services/backup/postgresql-backup.nix b/nixos/modules/services/backup/postgresql-backup.nix index 5dd9e075862d..3302375c7889 100644 --- a/nixos/modules/services/backup/postgresql-backup.nix +++ b/nixos/modules/services/backup/postgresql-backup.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.postgresqlBackup; @@ -13,9 +10,9 @@ let "gzip" = ".gz"; "zstd" = ".zstd"; }; - compressSuffix = getAttr cfg.compression compressSuffixes; + compressSuffix = lib.getAttr cfg.compression compressSuffixes; - compressCmd = getAttr cfg.compression { + compressCmd = lib.getAttr cfg.compression { "none" = "cat"; "gzip" = "${pkgs.gzip}/bin/gzip -c -${toString cfg.compressionLevel} --rsyncable"; "zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel} --rsyncable"; @@ -24,7 +21,7 @@ let mkSqlPath = prefix: suffix: "${cfg.location}/${db}${prefix}.sql${suffix}"; curFile = mkSqlPath "" compressSuffix; prevFile = mkSqlPath ".prev" compressSuffix; - prevFiles = map (mkSqlPath ".prev") (attrValues compressSuffixes); + prevFiles = map (mkSqlPath ".prev") (lib.attrValues compressSuffixes); inProgressFile = mkSqlPath ".in-progress" compressSuffix; in { enable = true; @@ -63,7 +60,7 @@ let in { imports = [ - (mkRemovedOptionModule [ "services" "postgresqlBackup" "period" ] '' + (lib.mkRemovedOptionModule [ "services" "postgresqlBackup" "period" ] '' A systemd timer is now used instead of cron. The starting time can be configured via services.postgresqlBackup.startAt. '') @@ -71,11 +68,11 @@ in { options = { services.postgresqlBackup = { - enable = mkEnableOption "PostgreSQL dumps"; + enable = lib.mkEnableOption "PostgreSQL dumps"; - startAt = mkOption { + startAt = lib.mkOption { default = "*-*-* 01:15:00"; - type = with types; either (listOf str) str; + type = with lib.types; either (listOf str) str; description = '' This option defines (see `systemd.time` for format) when the databases should be dumped. @@ -83,9 +80,9 @@ in { ''; }; - backupAll = mkOption { + backupAll = lib.mkOption { default = cfg.databases == []; - defaultText = literalExpression "services.postgresqlBackup.databases == []"; + defaultText = lib.literalExpression "services.postgresqlBackup.databases == []"; type = lib.types.bool; description = '' Backup all databases using pg_dumpall. @@ -96,24 +93,24 @@ in { ''; }; - databases = mkOption { + databases = lib.mkOption { default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' List of database names to dump. ''; }; - location = mkOption { + location = lib.mkOption { default = "/var/backup/postgresql"; - type = types.path; + type = lib.types.path; description = '' Path of directory where the PostgreSQL database dumps will be placed. ''; }; - pgdumpOptions = mkOption { - type = types.separatedString " "; + pgdumpOptions = lib.mkOption { + type = lib.types.separatedString " "; default = "-C"; description = '' Command line options for pg_dump. This options is not used @@ -123,16 +120,16 @@ in { ''; }; - compression = mkOption { - type = types.enum ["none" "gzip" "zstd"]; + compression = lib.mkOption { + type = lib.types.enum ["none" "gzip" "zstd"]; default = "gzip"; description = '' The type of compression to use on the generated database dump. ''; }; - compressionLevel = mkOption { - type = types.ints.between 1 19; + compressionLevel = lib.mkOption { + type = lib.types.ints.between 1 19; default = 6; description = '' The compression level used when compression is enabled. @@ -143,7 +140,7 @@ in { }; - config = mkMerge [ + config = lib.mkMerge [ { assertions = [ { @@ -158,17 +155,17 @@ in { } ]; } - (mkIf cfg.enable { + (lib.mkIf cfg.enable { systemd.tmpfiles.rules = [ "d '${cfg.location}' 0700 postgres - - -" ]; }) - (mkIf (cfg.enable && cfg.backupAll) { + (lib.mkIf (cfg.enable && cfg.backupAll) { systemd.services.postgresqlBackup = postgresqlBackupService "all" "pg_dumpall"; }) - (mkIf (cfg.enable && !cfg.backupAll) { - systemd.services = listToAttrs (map (db: + (lib.mkIf (cfg.enable && !cfg.backupAll) { + systemd.services = lib.listToAttrs (map (db: let cmd = "pg_dump ${cfg.pgdumpOptions} ${db}"; in { diff --git a/nixos/modules/services/backup/postgresql-wal-receiver.nix b/nixos/modules/services/backup/postgresql-wal-receiver.nix index a8f2cf514d54..b355637ff5a0 100644 --- a/nixos/modules/services/backup/postgresql-wal-receiver.nix +++ b/nixos/modules/services/backup/postgresql-wal-receiver.nix @@ -1,24 +1,21 @@ { config, lib, pkgs, ... }: - -with lib; - let receiverSubmodule = { options = { - postgresqlPackage = mkPackageOption pkgs "postgresql" { + postgresqlPackage = lib.mkPackageOption pkgs "postgresql" { example = "postgresql_15"; }; - directory = mkOption { - type = types.path; - example = literalExpression "/mnt/pg_wal/main/"; + directory = lib.mkOption { + type = lib.types.path; + example = lib.literalExpression "/mnt/pg_wal/main/"; description = '' Directory to write the output to. ''; }; - statusInterval = mkOption { - type = types.int; + statusInterval = lib.mkOption { + type = lib.types.int; default = 10; description = '' Specifies the number of seconds between status packets sent back to the server. @@ -28,8 +25,8 @@ let ''; }; - slot = mkOption { - type = types.str; + slot = lib.mkOption { + type = lib.types.str; default = ""; example = "some_slot_name"; description = '' @@ -45,8 +42,8 @@ let ''; }; - synchronous = mkOption { - type = types.bool; + synchronous = lib.mkOption { + type = lib.types.bool; default = false; description = '' Flush the WAL data to disk immediately after it has been received. @@ -57,8 +54,8 @@ let ''; }; - compress = mkOption { - type = types.ints.between 0 9; + compress = lib.mkOption { + type = lib.types.ints.between 0 9; default = 0; description = '' Enables gzip compression of write-ahead logs, and specifies the compression level @@ -69,8 +66,8 @@ let ''; }; - connection = mkOption { - type = types.str; + connection = lib.mkOption { + type = lib.types.str; example = "postgresql://user@somehost"; description = '' Specifies parameters used to connect to the server, as a connection string. @@ -81,10 +78,10 @@ let ''; }; - extraArgs = mkOption { - type = with types; listOf str; + extraArgs = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; - example = literalExpression '' + example = lib.literalExpression '' [ "--no-sync" ] @@ -94,10 +91,10 @@ let ''; }; - environment = mkOption { - type = with types; attrsOf str; + environment = lib.mkOption { + type = with lib.types; attrsOf str; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { PGPASSFILE = "/private/passfile"; PGSSLMODE = "require"; @@ -114,10 +111,10 @@ let in { options = { services.postgresqlWalReceiver = { - receivers = mkOption { - type = with types; attrsOf (submodule receiverSubmodule); + receivers = lib.mkOption { + type = with lib.types; attrsOf (submodule receiverSubmodule); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { main = { postgresqlPackage = pkgs.postgresql_15; @@ -138,7 +135,7 @@ in { config = let receivers = config.services.postgresqlWalReceiver.receivers; - in mkIf (receivers != { }) { + in lib.mkIf (receivers != { }) { users = { users.postgres = { uid = config.ids.uids.postgres; @@ -151,18 +148,18 @@ in { }; }; - assertions = concatLists (attrsets.mapAttrsToList (name: config: [ + assertions = lib.concatLists (lib.attrsets.mapAttrsToList (name: config: [ { - assertion = config.compress > 0 -> versionAtLeast config.postgresqlPackage.version "10"; + assertion = config.compress > 0 -> lib.versionAtLeast config.postgresqlPackage.version "10"; message = "Invalid configuration for WAL receiver \"${name}\": compress requires PostgreSQL version >= 10."; } ]) receivers); - systemd.tmpfiles.rules = mapAttrsToList (name: config: '' - d ${escapeShellArg config.directory} 0750 postgres postgres - - + systemd.tmpfiles.rules = lib.mapAttrsToList (name: config: '' + d ${lib.escapeShellArg config.directory} 0750 postgres postgres - - '') receivers; - systemd.services = with attrsets; mapAttrs' (name: config: nameValuePair "postgresql-wal-receiver-${name}" { + systemd.services = lib.mapAttrs' (name: config: lib.nameValuePair "postgresql-wal-receiver-${name}" { description = "PostgreSQL WAL receiver (${name})"; wantedBy = [ "multi-user.target" ]; startLimitIntervalSec = 0; # retry forever, useful in case of network disruption @@ -179,22 +176,22 @@ in { script = let receiverCommand = postgresqlPackage: - if (versionAtLeast postgresqlPackage.version "10") + if (lib.versionAtLeast postgresqlPackage.version "10") then "${postgresqlPackage}/bin/pg_receivewal" else "${postgresqlPackage}/bin/pg_receivexlog"; in '' ${receiverCommand config.postgresqlPackage} \ --no-password \ - --directory=${escapeShellArg config.directory} \ + --directory=${lib.escapeShellArg config.directory} \ --status-interval=${toString config.statusInterval} \ - --dbname=${escapeShellArg config.connection} \ - ${optionalString (config.compress > 0) "--compress=${toString config.compress}"} \ - ${optionalString (config.slot != "") "--slot=${escapeShellArg config.slot}"} \ - ${optionalString config.synchronous "--synchronous"} \ - ${concatStringsSep " " config.extraArgs} + --dbname=${lib.escapeShellArg config.connection} \ + ${lib.optionalString (config.compress > 0) "--compress=${toString config.compress}"} \ + ${lib.optionalString (config.slot != "") "--slot=${lib.escapeShellArg config.slot}"} \ + ${lib.optionalString config.synchronous "--synchronous"} \ + ${lib.concatStringsSep " " config.extraArgs} ''; }) receivers; }; - meta.maintainers = with maintainers; [ pacien ]; + meta.maintainers = with lib.maintainers; [ pacien ]; } diff --git a/nixos/modules/services/backup/restic-rest-server.nix b/nixos/modules/services/backup/restic-rest-server.nix index eb7b57800333..333609444da2 100644 --- a/nixos/modules/services/backup/restic-rest-server.nix +++ b/nixos/modules/services/backup/restic-rest-server.nix @@ -1,32 +1,29 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.restic.server; in { - meta.maintainers = [ maintainers.bachp ]; + meta.maintainers = [ lib.maintainers.bachp ]; options.services.restic.server = { - enable = mkEnableOption "Restic REST Server"; + enable = lib.mkEnableOption "Restic REST Server"; - listenAddress = mkOption { + listenAddress = lib.mkOption { default = "8000"; example = "127.0.0.1:8080"; - type = types.str; + type = lib.types.str; description = "Listen on a specific IP address and port or unix socket."; }; - dataDir = mkOption { + dataDir = lib.mkOption { default = "/var/lib/restic"; - type = types.path; + type = lib.types.path; description = "The directory for storing the restic repository."; }; - appendOnly = mkOption { + appendOnly = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable append only mode. This mode allows creation of new backups but prevents deletion and modification of existing backups. @@ -34,33 +31,33 @@ in ''; }; - privateRepos = mkOption { + privateRepos = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable private repos. Grants access only when a subdirectory with the same name as the user is specified in the repository URL. ''; }; - prometheus = mkOption { + prometheus = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "Enable Prometheus metrics at /metrics."; }; - extraFlags = mkOption { - type = types.listOf types.str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Extra commandline options to pass to Restic REST server. ''; }; - package = mkPackageOption pkgs "restic-rest-server" { }; + package = lib.mkPackageOption pkgs "restic-rest-server" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [{ assertion = lib.substring 0 1 cfg.listenAddress != ":"; message = "The restic-rest-server now uses systemd socket activation, which expects only the Port number: services.restic.server.listenAddress = \"${lib.substring 1 6 cfg.listenAddress}\";"; @@ -75,10 +72,10 @@ in ExecStart = '' ${cfg.package}/bin/rest-server \ --path ${cfg.dataDir} \ - ${optionalString cfg.appendOnly "--append-only"} \ - ${optionalString cfg.privateRepos "--private-repos"} \ - ${optionalString cfg.prometheus "--prometheus"} \ - ${escapeShellArgs cfg.extraFlags} \ + ${lib.optionalString cfg.appendOnly "--append-only"} \ + ${lib.optionalString cfg.privateRepos "--private-repos"} \ + ${lib.optionalString cfg.prometheus "--prometheus"} \ + ${lib.escapeShellArgs cfg.extraFlags} \ ''; Type = "simple"; User = "restic"; @@ -119,7 +116,7 @@ in wantedBy = [ "sockets.target" ]; }; - systemd.tmpfiles.rules = mkIf cfg.privateRepos [ + systemd.tmpfiles.rules = lib.mkIf cfg.privateRepos [ "f ${cfg.dataDir}/.htpasswd 0700 restic restic -" ]; diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix index a7c2ef2eacd5..0fb601cce589 100644 --- a/nixos/modules/services/backup/restic.nix +++ b/nixos/modules/services/backup/restic.nix @@ -1,28 +1,25 @@ { config, lib, pkgs, utils, ... }: - -with lib; - let # Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers" inherit (utils.systemdUtils.unitOptions) unitOption; in { - options.services.restic.backups = mkOption { + options.services.restic.backups = lib.mkOption { description = '' Periodic backups to create with Restic. ''; - type = types.attrsOf (types.submodule ({ name, ... }: { + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { options = { - passwordFile = mkOption { - type = types.str; + passwordFile = lib.mkOption { + type = lib.types.str; description = '' Read the repository password from a file. ''; example = "/etc/nixos/restic-password"; }; - environmentFile = mkOption { - type = with types; nullOr str; + environmentFile = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' file containing the credentials to access the repository, in the @@ -30,8 +27,8 @@ in ''; }; - rcloneOptions = mkOption { - type = with types; nullOr (attrsOf (oneOf [ str bool ])); + rcloneOptions = lib.mkOption { + type = with lib.types; nullOr (attrsOf (oneOf [ str bool ])); default = null; description = '' Options to pass to rclone to control its behavior. @@ -47,8 +44,8 @@ in }; }; - rcloneConfig = mkOption { - type = with types; nullOr (attrsOf (oneOf [ str bool ])); + rcloneConfig = lib.mkOption { + type = with lib.types; nullOr (attrsOf (oneOf [ str bool ])); default = null; description = '' Configuration for the rclone remote being used for backup. @@ -71,8 +68,8 @@ in }; }; - rcloneConfigFile = mkOption { - type = with types; nullOr path; + rcloneConfigFile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' Path to the file containing rclone configuration. This file @@ -83,17 +80,17 @@ in ''; }; - inhibitsSleep = mkOption { + inhibitsSleep = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; example = true; description = '' Prevents the system from sleeping while backing up. ''; }; - repository = mkOption { - type = with types; nullOr str; + repository = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' repository to backup to. @@ -101,18 +98,18 @@ in example = "sftp:backup@192.168.1.100:/backups/${name}"; }; - repositoryFile = mkOption { - type = with types; nullOr path; + repositoryFile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' Path to the file containing the repository location to backup to. ''; }; - paths = mkOption { + paths = lib.mkOption { # This is nullable for legacy reasons only. We should consider making it a pure listOf # after some time has passed since this comment was added. - type = types.nullOr (types.listOf types.str); + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = [ ]; description = '' Which paths to backup, in addition to ones specified via @@ -126,8 +123,8 @@ in ]; }; - exclude = mkOption { - type = types.listOf types.str; + exclude = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' Patterns to exclude when backing up. See @@ -141,8 +138,8 @@ in ]; }; - timerConfig = mkOption { - type = types.nullOr (types.attrsOf unitOption); + timerConfig = lib.mkOption { + type = lib.types.nullOr (lib.types.attrsOf unitOption); default = { OnCalendar = "daily"; Persistent = true; @@ -159,8 +156,8 @@ in }; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "root"; description = '' As which user the backup should run. @@ -168,8 +165,8 @@ in example = "postgresql"; }; - extraBackupArgs = mkOption { - type = types.listOf types.str; + extraBackupArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' Extra arguments passed to restic backup. @@ -179,8 +176,8 @@ in ]; }; - extraOptions = mkOption { - type = types.listOf types.str; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' Extra extended options to be passed to the restic --option flag. @@ -190,16 +187,16 @@ in ]; }; - initialize = mkOption { - type = types.bool; + initialize = lib.mkOption { + type = lib.types.bool; default = false; description = '' Create the repository if it doesn't exist. ''; }; - pruneOpts = mkOption { - type = types.listOf types.str; + pruneOpts = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' A list of options (--keep-\* et al.) for 'restic forget @@ -215,16 +212,16 @@ in ]; }; - runCheck = mkOption { - type = types.bool; + runCheck = lib.mkOption { + type = lib.types.bool; default = (builtins.length config.services.restic.backups.${name}.checkOpts > 0); - defaultText = literalExpression ''builtins.length config.services.backups.${name}.checkOpts > 0''; + defaultText = lib.literalExpression ''builtins.length config.services.backups.${name}.checkOpts > 0''; description = "Whether to run the `check` command with the provided `checkOpts` options."; example = true; }; - checkOpts = mkOption { - type = types.listOf types.str; + checkOpts = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' A list of options for 'restic check'. @@ -234,8 +231,8 @@ in ]; }; - dynamicFilesFrom = mkOption { - type = with types; nullOr str; + dynamicFilesFrom = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' A script that produces a list of files to back up. The @@ -245,23 +242,23 @@ in example = "find /home/matt/git -type d -name .git"; }; - backupPrepareCommand = mkOption { - type = with types; nullOr str; + backupPrepareCommand = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' A script that must run before starting the backup process. ''; }; - backupCleanupCommand = mkOption { - type = with types; nullOr str; + backupCleanupCommand = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' A script that must run after finishing the backup process. ''; }; - package = mkPackageOption pkgs "restic" { }; + package = lib.mkPackageOption pkgs "restic" { }; createWrapper = lib.mkOption { type = lib.types.bool; @@ -299,54 +296,54 @@ in }; config = { - assertions = mapAttrsToList (n: v: { + assertions = lib.mapAttrsToList (n: v: { assertion = (v.repository == null) != (v.repositoryFile == null); message = "services.restic.backups.${n}: exactly one of repository or repositoryFile should be set"; }) config.services.restic.backups; systemd.services = - mapAttrs' + lib.mapAttrs' (name: backup: let - extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions; - inhibitCmd = concatStringsSep " " [ + extraOptions = lib.concatMapStrings (arg: " -o ${arg}") backup.extraOptions; + inhibitCmd = lib.concatStringsSep " " [ "${pkgs.systemd}/bin/systemd-inhibit" "--mode='block'" "--who='restic'" "--what='sleep'" - "--why=${escapeShellArg "Scheduled backup ${name}"} " + "--why=${lib.escapeShellArg "Scheduled backup ${name}"} " ]; - resticCmd = "${optionalString backup.inhibitsSleep inhibitCmd}${backup.package}/bin/restic${extraOptions}"; - excludeFlags = optional (backup.exclude != []) "--exclude-file=${pkgs.writeText "exclude-patterns" (concatStringsSep "\n" backup.exclude)}"; + resticCmd = "${lib.optionalString backup.inhibitsSleep inhibitCmd}${backup.package}/bin/restic${extraOptions}"; + excludeFlags = lib.optional (backup.exclude != []) "--exclude-file=${pkgs.writeText "exclude-patterns" (lib.concatStringsSep "\n" backup.exclude)}"; filesFromTmpFile = "/run/restic-backups-${name}/includes"; doBackup = (backup.dynamicFilesFrom != null) || (backup.paths != null && backup.paths != []); - pruneCmd = optionals (builtins.length backup.pruneOpts > 0) [ - (resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts)) + pruneCmd = lib.optionals (builtins.length backup.pruneOpts > 0) [ + (resticCmd + " forget --prune " + (lib.concatStringsSep " " backup.pruneOpts)) ]; - checkCmd = optionals backup.runCheck [ - (resticCmd + " check " + (concatStringsSep " " backup.checkOpts)) + checkCmd = lib.optionals backup.runCheck [ + (resticCmd + " check " + (lib.concatStringsSep " " backup.checkOpts)) ]; # Helper functions for rclone remotes - rcloneRemoteName = builtins.elemAt (splitString ":" backup.repository) 1; - rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v); - rcloneAttrToConf = v: "RCLONE_CONFIG_" + toUpper (rcloneRemoteName + "_" + v); + rcloneRemoteName = builtins.elemAt (lib.splitString ":" backup.repository) 1; + rcloneAttrToOpt = v: "RCLONE_" + lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v); + rcloneAttrToConf = v: "RCLONE_CONFIG_" + lib.toUpper (rcloneRemoteName + "_" + v); toRcloneVal = v: if lib.isBool v then lib.boolToString v else v; in - nameValuePair "restic-backups-${name}" ({ + lib.nameValuePair "restic-backups-${name}" ({ environment = { # not %C, because that wouldn't work in the wrapper script RESTIC_CACHE_DIR = "/var/cache/restic-backups-${name}"; RESTIC_PASSWORD_FILE = backup.passwordFile; RESTIC_REPOSITORY = backup.repository; RESTIC_REPOSITORY_FILE = backup.repositoryFile; - } // optionalAttrs (backup.rcloneOptions != null) (mapAttrs' + } // lib.optionalAttrs (backup.rcloneOptions != null) (lib.mapAttrs' (name: value: - nameValuePair (rcloneAttrToOpt name) (toRcloneVal value) + lib.nameValuePair (rcloneAttrToOpt name) (toRcloneVal value) ) - backup.rcloneOptions) // optionalAttrs (backup.rcloneConfigFile != null) { + backup.rcloneOptions) // lib.optionalAttrs (backup.rcloneConfigFile != null) { RCLONE_CONFIG = backup.rcloneConfigFile; - } // optionalAttrs (backup.rcloneConfig != null) (mapAttrs' + } // lib.optionalAttrs (backup.rcloneConfig != null) (lib.mapAttrs' (name: value: - nameValuePair (rcloneAttrToConf name) (toRcloneVal value) + lib.nameValuePair (rcloneAttrToConf name) (toRcloneVal value) ) backup.rcloneConfig); path = [ config.programs.ssh.package ]; @@ -355,37 +352,37 @@ in after = [ "network-online.target" ]; serviceConfig = { Type = "oneshot"; - ExecStart = (optionals doBackup [ "${resticCmd} backup ${concatStringsSep " " (backup.extraBackupArgs ++ excludeFlags)} --files-from=${filesFromTmpFile}" ]) + ExecStart = (lib.optionals doBackup [ "${resticCmd} backup ${lib.concatStringsSep " " (backup.extraBackupArgs ++ excludeFlags)} --files-from=${filesFromTmpFile}" ]) ++ pruneCmd ++ checkCmd; User = backup.user; RuntimeDirectory = "restic-backups-${name}"; CacheDirectory = "restic-backups-${name}"; CacheDirectoryMode = "0700"; PrivateTmp = true; - } // optionalAttrs (backup.environmentFile != null) { + } // lib.optionalAttrs (backup.environmentFile != null) { EnvironmentFile = backup.environmentFile; }; - } // optionalAttrs (backup.initialize || doBackup || backup.backupPrepareCommand != null) { + } // lib.optionalAttrs (backup.initialize || doBackup || backup.backupPrepareCommand != null) { preStart = '' - ${optionalString (backup.backupPrepareCommand != null) '' + ${lib.optionalString (backup.backupPrepareCommand != null) '' ${pkgs.writeScript "backupPrepareCommand" backup.backupPrepareCommand} ''} - ${optionalString (backup.initialize) '' + ${lib.optionalString (backup.initialize) '' ${resticCmd} cat config > /dev/null || ${resticCmd} init ''} - ${optionalString (backup.paths != null && backup.paths != []) '' - cat ${pkgs.writeText "staticPaths" (concatLines backup.paths)} >> ${filesFromTmpFile} + ${lib.optionalString (backup.paths != null && backup.paths != []) '' + cat ${pkgs.writeText "staticPaths" (lib.concatLines backup.paths)} >> ${filesFromTmpFile} ''} - ${optionalString (backup.dynamicFilesFrom != null) '' + ${lib.optionalString (backup.dynamicFilesFrom != null) '' ${pkgs.writeScript "dynamicFilesFromScript" backup.dynamicFilesFrom} >> ${filesFromTmpFile} ''} ''; - } // optionalAttrs (doBackup || backup.backupCleanupCommand != null) { + } // lib.optionalAttrs (doBackup || backup.backupCleanupCommand != null) { postStop = '' - ${optionalString (backup.backupCleanupCommand != null) '' + ${lib.optionalString (backup.backupCleanupCommand != null) '' ${pkgs.writeScript "backupCleanupCommand" backup.backupCleanupCommand} ''} - ${optionalString doBackup '' + ${lib.optionalString doBackup '' rm ${filesFromTmpFile} ''} ''; @@ -393,12 +390,12 @@ in ) config.services.restic.backups; systemd.timers = - mapAttrs' - (name: backup: nameValuePair "restic-backups-${name}" { + lib.mapAttrs' + (name: backup: lib.nameValuePair "restic-backups-${name}" { wantedBy = [ "timers.target" ]; timerConfig = backup.timerConfig; }) - (filterAttrs (_: backup: backup.timerConfig != null) config.services.restic.backups); + (lib.filterAttrs (_: backup: backup.timerConfig != null) config.services.restic.backups); # generate wrapper scripts, as described in the createWrapper option environment.systemPackages = lib.mapAttrsToList (name: backup: let diff --git a/nixos/modules/services/backup/rsnapshot.nix b/nixos/modules/services/backup/rsnapshot.nix index 6635a51ec2c6..aedb8acd60ac 100644 --- a/nixos/modules/services/backup/rsnapshot.nix +++ b/nixos/modules/services/backup/rsnapshot.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.rsnapshot; cfgfile = pkgs.writeText "rsnapshot.conf" '' @@ -22,21 +19,21 @@ in { options = { services.rsnapshot = { - enable = mkEnableOption "rsnapshot backups"; - enableManualRsnapshot = mkOption { + enable = lib.mkEnableOption "rsnapshot backups"; + enableManualRsnapshot = lib.mkOption { description = "Whether to enable manual usage of the rsnapshot command with this module."; default = true; - type = types.bool; + type = lib.types.bool; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; example = '' retains hourly 24 retain daily 365 backup /home/ localhost/ ''; - type = types.lines; + type = lib.types.lines; description = '' rsnapshot configuration option in addition to the defaults from rsnapshot and this module. @@ -49,10 +46,10 @@ in ''; }; - cronIntervals = mkOption { + cronIntervals = lib.mkOption { default = {}; example = { hourly = "0 * * * *"; daily = "50 21 * * *"; }; - type = types.attrsOf types.str; + type = lib.types.attrsOf lib.types.str; description = '' Periodicity at which intervals should be run by cron. Note that the intervals also have to exist in configuration @@ -62,12 +59,12 @@ in }; }; - config = mkIf cfg.enable (mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { services.cron.systemCronJobs = - mapAttrsToList (interval: time: "${time} root ${pkgs.rsnapshot}/bin/rsnapshot -c ${cfgfile} ${interval}") cfg.cronIntervals; + lib.mapAttrsToList (interval: time: "${time} root ${pkgs.rsnapshot}/bin/rsnapshot -c ${cfgfile} ${interval}") cfg.cronIntervals; } - (mkIf cfg.enableManualRsnapshot { + (lib.mkIf cfg.enableManualRsnapshot { environment.systemPackages = [ pkgs.rsnapshot ]; environment.etc."rsnapshot.conf".source = cfgfile; }) diff --git a/nixos/modules/services/backup/sanoid.nix b/nixos/modules/services/backup/sanoid.nix index 1b9ace358cab..823a2ed565e7 100644 --- a/nixos/modules/services/backup/sanoid.nix +++ b/nixos/modules/services/backup/sanoid.nix @@ -1,85 +1,82 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.sanoid; - datasetSettingsType = with types; + datasetSettingsType = with lib.types; (attrsOf (nullOr (oneOf [ str int bool (listOf str) ]))) // { description = "dataset/template options"; }; commonOptions = { - hourly = mkOption { + hourly = lib.mkOption { description = "Number of hourly snapshots."; - type = with types; nullOr ints.unsigned; + type = with lib.types; nullOr ints.unsigned; default = null; }; - daily = mkOption { + daily = lib.mkOption { description = "Number of daily snapshots."; - type = with types; nullOr ints.unsigned; + type = with lib.types; nullOr ints.unsigned; default = null; }; - monthly = mkOption { + monthly = lib.mkOption { description = "Number of monthly snapshots."; - type = with types; nullOr ints.unsigned; + type = with lib.types; nullOr ints.unsigned; default = null; }; - yearly = mkOption { + yearly = lib.mkOption { description = "Number of yearly snapshots."; - type = with types; nullOr ints.unsigned; + type = with lib.types; nullOr ints.unsigned; default = null; }; - autoprune = mkOption { + autoprune = lib.mkOption { description = "Whether to automatically prune old snapshots."; - type = with types; nullOr bool; + type = with lib.types; nullOr bool; default = null; }; - autosnap = mkOption { + autosnap = lib.mkOption { description = "Whether to automatically take snapshots."; - type = with types; nullOr bool; + type = with lib.types; nullOr bool; default = null; }; }; datasetOptions = rec { - use_template = mkOption { + use_template = lib.mkOption { description = "Names of the templates to use for this dataset."; - type = types.listOf (types.str // { - check = (types.enum (attrNames cfg.templates)).check; + type = lib.types.listOf (lib.types.str // { + check = (lib.types.enum (lib.attrNames cfg.templates)).check; description = "configured template name"; }); default = [ ]; }; useTemplate = use_template; - recursive = mkOption { + recursive = lib.mkOption { description = '' Whether to recursively snapshot dataset children. You can also set this to `"zfs"` to handle datasets recursively in an atomic way without the possibility to override settings for child datasets. ''; - type = with types; oneOf [ bool (enum [ "zfs" ]) ]; + type = with lib.types; oneOf [ bool (enum [ "zfs" ]) ]; default = false; }; - process_children_only = mkOption { + process_children_only = lib.mkOption { description = "Whether to only snapshot child datasets if recursing."; - type = types.bool; + type = lib.types.bool; default = false; }; processChildrenOnly = process_children_only; }; # Extract unique dataset names - datasets = unique (attrNames cfg.datasets); + datasets = lib.unique (lib.attrNames cfg.datasets); # Function to build "zfs allow" and "zfs unallow" commands for the # filesystems we've delegated permissions to. @@ -88,23 +85,23 @@ let "-+/run/booted-system/sw/bin/zfs" zfsAction "sanoid" - (concatStringsSep "," permissions) + (lib.concatStringsSep "," permissions) dataset ]; configFile = let mkValueString = v: - if builtins.isList v then concatStringsSep "," v - else generators.mkValueStringDefault { } v; + if lib.isList v then lib.concatStringsSep "," v + else lib.generators.mkValueStringDefault { } v; mkKeyValue = k: v: if v == null then "" else if k == "processChildrenOnly" then "" else if k == "useTemplate" then "" - else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v; + else lib.generators.mkKeyValueDefault { inherit mkValueString; } "=" k v; in - generators.toINI { inherit mkKeyValue; } cfg.settings; + lib.generators.toINI { inherit mkKeyValue; } cfg.settings; in { @@ -112,12 +109,12 @@ in # Interface options.services.sanoid = { - enable = mkEnableOption "Sanoid ZFS snapshotting service"; + enable = lib.mkEnableOption "Sanoid ZFS snapshotting service"; package = lib.mkPackageOption pkgs "sanoid" {}; - interval = mkOption { - type = types.str; + interval = lib.mkOption { + type = lib.types.str; default = "hourly"; example = "daily"; description = '' @@ -128,19 +125,19 @@ in ''; }; - datasets = mkOption { - type = types.attrsOf (types.submodule ({ config, options, ... }: { + datasets = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ config, options, ... }: { freeformType = datasetSettingsType; options = commonOptions // datasetOptions; - config.use_template = modules.mkAliasAndWrapDefsWithPriority id (options.useTemplate or { }); - config.process_children_only = modules.mkAliasAndWrapDefsWithPriority id (options.processChildrenOnly or { }); + config.use_template = lib.modules.mkAliasAndWrapDefsWithPriority lib.id (options.useTemplate or { }); + config.process_children_only = lib.modules.mkAliasAndWrapDefsWithPriority lib.id (options.processChildrenOnly or { }); })); default = { }; description = "Datasets to snapshot."; }; - templates = mkOption { - type = types.attrsOf (types.submodule { + templates = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { freeformType = datasetSettingsType; options = commonOptions; }); @@ -148,8 +145,8 @@ in description = "Templates for datasets."; }; - settings = mkOption { - type = types.attrsOf datasetSettingsType; + settings = lib.mkOption { + type = lib.types.attrsOf datasetSettingsType; description = '' Free-form settings written directly to the config file. See @@ -157,8 +154,8 @@ in ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "--verbose" "--readonly" "--debug" ]; description = '' @@ -171,10 +168,10 @@ in # Implementation - config = mkIf cfg.enable { - services.sanoid.settings = mkMerge [ - (mapAttrs' (d: v: nameValuePair ("template_" + d) v) cfg.templates) - (mapAttrs (d: v: v) cfg.datasets) + config = lib.mkIf cfg.enable { + services.sanoid.settings = lib.mkMerge [ + (lib.mapAttrs' (d: v: lib.nameValuePair ("template_" + d) v) cfg.templates) + (lib.mapAttrs (d: v: v) cfg.datasets) ]; systemd.services.sanoid = { @@ -201,5 +198,5 @@ in }; }; - meta.maintainers = with maintainers; [ lopsided98 ]; + meta.maintainers = with lib.maintainers; [ lopsided98 ]; } diff --git a/nixos/modules/services/backup/snapraid.nix b/nixos/modules/services/backup/snapraid.nix index a621c9f62ff7..72b4d9caef3c 100644 --- a/nixos/modules/services/backup/snapraid.nix +++ b/nixos/modules/services/backup/snapraid.nix @@ -1,18 +1,15 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.snapraid; in { imports = [ # Should have never been on the top-level. - (mkRenamedOptionModule [ "snapraid" ] [ "services" "snapraid" ]) + (lib.mkRenamedOptionModule [ "snapraid" ] [ "services" "snapraid" ]) ]; - options.services.snapraid = with types; { - enable = mkEnableOption "SnapRAID"; - dataDisks = mkOption { + options.services.snapraid = with lib.types; { + enable = lib.mkEnableOption "SnapRAID"; + dataDisks = lib.mkOption { default = { }; example = { d1 = "/mnt/disk1/"; @@ -22,7 +19,7 @@ in description = "SnapRAID data disks."; type = attrsOf str; }; - parityFiles = mkOption { + parityFiles = lib.mkOption { default = [ ]; example = [ "/mnt/diskp/snapraid.parity" @@ -35,7 +32,7 @@ in description = "SnapRAID parity files."; type = listOf str; }; - contentFiles = mkOption { + contentFiles = lib.mkOption { default = [ ]; example = [ "/var/snapraid.content" @@ -45,40 +42,40 @@ in description = "SnapRAID content list files."; type = listOf str; }; - exclude = mkOption { + exclude = lib.mkOption { default = [ ]; example = [ "*.unrecoverable" "/tmp/" "/lost+found/" ]; description = "SnapRAID exclude directives."; type = listOf str; }; - touchBeforeSync = mkOption { + touchBeforeSync = lib.mkOption { default = true; example = false; description = "Whether {command}`snapraid touch` should be run before {command}`snapraid sync`."; type = bool; }; - sync.interval = mkOption { + sync.interval = lib.mkOption { default = "01:00"; example = "daily"; description = "How often to run {command}`snapraid sync`."; type = str; }; scrub = { - interval = mkOption { + interval = lib.mkOption { default = "Mon *-*-* 02:00:00"; example = "weekly"; description = "How often to run {command}`snapraid scrub`."; type = str; }; - plan = mkOption { + plan = lib.mkOption { default = 8; example = 5; description = "Percent of the array that should be checked by {command}`snapraid scrub`."; type = int; }; - olderThan = mkOption { + olderThan = lib.mkOption { default = 10; example = 20; description = @@ -86,7 +83,7 @@ in type = int; }; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; example = '' nohidden @@ -105,7 +102,7 @@ in nParity = builtins.length cfg.parityFiles; mkPrepend = pre: s: pre + s; in - mkIf cfg.enable { + lib.mkIf cfg.enable { assertions = [ { assertion = nParity <= 6; @@ -128,11 +125,11 @@ in prependContent = mkPrepend "content "; prependExclude = mkPrepend "exclude "; in - concatStringsSep "\n" + lib.concatStringsSep "\n" (map prependData - ((mapAttrsToList (name: value: name + " " + value)) dataDisks) - ++ zipListsWith (a: b: a + b) - ([ "parity " ] ++ map (i: toString i + "-parity ") (range 2 6)) + ((lib.mapAttrsToList (name: value: name + " " + value)) dataDisks) + ++ lib.zipListsWith (a: b: a + b) + ([ "parity " ] ++ map (i: toString i + "-parity ") (lib.range 2 6)) parityFiles ++ map prependContent contentFiles ++ map prependExclude exclude) + "\n" + extraConfig; }; @@ -179,8 +176,8 @@ in let contentDirs = map dirOf contentFiles; in - unique ( - attrValues dataDisks ++ contentDirs + lib.unique ( + lib.attrValues dataDisks ++ contentDirs ); }; unitConfig.After = "snapraid-sync.service"; @@ -225,12 +222,12 @@ in # Multiple "split" parity files can be specified in a single # "parityFile", separated by a comma. # https://www.snapraid.it/manual#7.1 - splitParityFiles = map (s: splitString "," s) parityFiles; + splitParityFiles = map (s: lib.splitString "," s) parityFiles; in - unique ( - attrValues dataDisks ++ splitParityFiles ++ contentDirs + lib.unique ( + lib.attrValues dataDisks ++ splitParityFiles ++ contentDirs ); - } // optionalAttrs touchBeforeSync { + } // lib.optionalAttrs touchBeforeSync { ExecStartPre = "${pkgs.snapraid}/bin/snapraid touch"; }; }; diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix index ec9ccaa46d42..4a59336fbdec 100644 --- a/nixos/modules/services/backup/syncoid.nix +++ b/nixos/modules/services/backup/syncoid.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.syncoid; # Extract local dasaset names (so no datasets containing "@") - localDatasetName = d: optionals (d != null) ( + localDatasetName = d: lib.optionals (d != null) ( let m = builtins.match "([^/@]+[^@]*)" d; in - optionals (m != null) m + lib.optionals (m != null) m ); # Escape as required by: https://www.freedesktop.org/software/systemd/man/systemd.unit.html @@ -35,7 +32,7 @@ let "/run/booted-system/sw/bin/zfs" "allow" cfg.user - (concatStringsSep "," permissions) + (lib.concatStringsSep "," permissions) dataset ]} ${lib.optionalString ((builtins.dirOf dataset) != ".") '' @@ -44,7 +41,7 @@ let "/run/booted-system/sw/bin/zfs" "allow" cfg.user - (concatStringsSep "," permissions) + (lib.concatStringsSep "," permissions) # Remove the last part of the path (builtins.dirOf dataset) ]} @@ -66,14 +63,14 @@ let "/run/booted-system/sw/bin/zfs" "unallow" cfg.user - (concatStringsSep "," permissions) + (lib.concatStringsSep "," permissions) dataset ]} ${lib.optionalString ((builtins.dirOf dataset) != ".") (lib.escapeShellArgs [ "/run/booted-system/sw/bin/zfs" "unallow" cfg.user - (concatStringsSep "," permissions) + (lib.concatStringsSep "," permissions) # Remove the last part of the path (builtins.dirOf dataset) ])} @@ -85,12 +82,12 @@ in # Interface options.services.syncoid = { - enable = mkEnableOption "Syncoid ZFS synchronization service"; + enable = lib.mkEnableOption "Syncoid ZFS synchronization service"; package = lib.mkPackageOption pkgs "sanoid" {}; - interval = mkOption { - type = types.str; + interval = lib.mkOption { + type = lib.types.str; default = "hourly"; example = "*-*-* *:15:00"; description = '' @@ -101,8 +98,8 @@ in ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "syncoid"; example = "backup"; description = '' @@ -115,15 +112,15 @@ in ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "syncoid"; example = "backup"; description = "The group for the service."; }; - sshKey = mkOption { - type = with types; nullOr (coercedTo path toString str); + sshKey = lib.mkOption { + type = with lib.types; nullOr (coercedTo path toString str); default = null; description = '' SSH private key file to use to login to the remote system. Can be @@ -131,8 +128,8 @@ in ''; }; - localSourceAllow = mkOption { - type = types.listOf types.str; + localSourceAllow = lib.mkOption { + type = lib.types.listOf lib.types.str; # Permissions snapshot and destroy are in case --no-sync-snap is not used default = [ "bookmark" "hold" "send" "snapshot" "destroy" "mount" ]; description = '' @@ -143,8 +140,8 @@ in ''; }; - localTargetAllow = mkOption { - type = types.listOf types.str; + localTargetAllow = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "change-key" "compression" "create" "mount" "mountpoint" "receive" "rollback" ]; example = [ "create" "mount" "receive" "rollback" ]; description = '' @@ -158,8 +155,8 @@ in ''; }; - commonArgs = mkOption { - type = types.listOf types.str; + commonArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "--no-sync-snap" ]; description = '' @@ -170,19 +167,19 @@ in ''; }; - service = mkOption { - type = types.attrs; + service = lib.mkOption { + type = lib.types.attrs; default = { }; description = '' Systemd configuration common to all syncoid services. ''; }; - commands = mkOption { - type = types.attrsOf (types.submodule ({ name, ... }: { + commands = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { options = { - source = mkOption { - type = types.str; + source = lib.mkOption { + type = lib.types.str; example = "pool/dataset"; description = '' Source ZFS dataset. Can be either local or remote. Defaults to @@ -190,8 +187,8 @@ in ''; }; - target = mkOption { - type = types.str; + target = lib.mkOption { + type = lib.types.str; example = "user@server:pool/dataset"; description = '' Target ZFS dataset. Can be either local @@ -200,18 +197,18 @@ in ''; }; - recursive = mkEnableOption ''the transfer of child datasets''; + recursive = lib.mkEnableOption ''the transfer of child datasets''; - sshKey = mkOption { - type = with types; nullOr (coercedTo path toString str); + sshKey = lib.mkOption { + type = with lib.types; nullOr (coercedTo path toString str); description = '' SSH private key file to use to login to the remote system. Defaults to {option}`services.syncoid.sshKey` option. ''; }; - localSourceAllow = mkOption { - type = types.listOf types.str; + localSourceAllow = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' Permissions granted for the {option}`services.syncoid.user` user for local source datasets. See @@ -221,8 +218,8 @@ in ''; }; - localTargetAllow = mkOption { - type = types.listOf types.str; + localTargetAllow = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' Permissions granted for the {option}`services.syncoid.user` user for local target datasets. See @@ -234,8 +231,8 @@ in ''; }; - sendOptions = mkOption { - type = types.separatedString " "; + sendOptions = lib.mkOption { + type = lib.types.separatedString " "; default = ""; example = "Lc e"; description = '' @@ -244,8 +241,8 @@ in ''; }; - recvOptions = mkOption { - type = types.separatedString " "; + recvOptions = lib.mkOption { + type = lib.types.separatedString " "; default = ""; example = "ux recordsize o compression=lz4"; description = '' @@ -254,38 +251,38 @@ in ''; }; - useCommonArgs = mkOption { - type = types.bool; + useCommonArgs = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to add the configured common arguments to this command. ''; }; - service = mkOption { - type = types.attrs; + service = lib.mkOption { + type = lib.types.attrs; default = { }; description = '' Systemd configuration specific to this syncoid service. ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "--sshport 2222" ]; description = "Extra syncoid arguments for this command."; }; }; config = { - source = mkDefault name; - sshKey = mkDefault cfg.sshKey; - localSourceAllow = mkDefault cfg.localSourceAllow; - localTargetAllow = mkDefault cfg.localTargetAllow; + source = lib.mkDefault name; + sshKey = lib.mkDefault cfg.sshKey; + localSourceAllow = lib.mkDefault cfg.localSourceAllow; + localTargetAllow = lib.mkDefault cfg.localTargetAllow; }; })); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "pool/test".target = "root@target:pool/test"; } @@ -296,9 +293,9 @@ in # Implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users = { - users = mkIf (cfg.user == "syncoid") { + users = lib.mkIf (cfg.user == "syncoid") { syncoid = { group = cfg.group; isSystemUser = true; @@ -308,14 +305,14 @@ in createHome = false; }; }; - groups = mkIf (cfg.group == "syncoid") { + groups = lib.mkIf (cfg.group == "syncoid") { syncoid = { }; }; }; - systemd.services = mapAttrs' + systemd.services = lib.mapAttrs' (name: c: - nameValuePair "syncoid-${escapeUnitName name}" (mkMerge [ + lib.nameValuePair "syncoid-${escapeUnitName name}" (lib.mkMerge [ { description = "Syncoid ZFS synchronization from ${c.source} to ${c.target}"; after = [ "zfs.target" ]; @@ -330,9 +327,9 @@ in (map (buildUnallowCommand c.localSourceAllow) (localDatasetName c.source)) ++ (map (buildUnallowCommand c.localTargetAllow) (localDatasetName c.target)); ExecStart = lib.escapeShellArgs ([ "${cfg.package}/bin/syncoid" ] - ++ optionals c.useCommonArgs cfg.commonArgs - ++ optional c.recursive "-r" - ++ optionals (c.sshKey != null) [ "--sshkey" c.sshKey ] + ++ lib.optionals c.useCommonArgs cfg.commonArgs + ++ lib.optional c.recursive "-r" + ++ lib.optionals (c.sshKey != null) [ "--sshkey" c.sshKey ] ++ c.extraArgs ++ [ "--sendoptions" @@ -364,7 +361,7 @@ in NoNewPrivileges = true; PrivateDevices = true; PrivateMounts = true; - PrivateNetwork = mkDefault false; + PrivateNetwork = lib.mkDefault false; PrivateUsers = false; # Enabling this breaks on zfs-2.2.0 ProtectClock = true; ProtectControlGroups = true; @@ -416,5 +413,5 @@ in cfg.commands; }; - meta.maintainers = with maintainers; [ julm lopsided98 ]; + meta.maintainers = with lib.maintainers; [ julm lopsided98 ]; } diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix index b8f848451d40..43493997931c 100644 --- a/nixos/modules/services/backup/tarsnap.nix +++ b/nixos/modules/services/backup/tarsnap.nix @@ -1,41 +1,38 @@ { config, lib, options, pkgs, utils, ... }: - -with lib; - let gcfg = config.services.tarsnap; opt = options.services.tarsnap; configFile = name: cfg: '' keyfile ${cfg.keyfile} - ${optionalString (cfg.cachedir != null) "cachedir ${cfg.cachedir}"} - ${optionalString cfg.nodump "nodump"} - ${optionalString cfg.printStats "print-stats"} - ${optionalString cfg.printStats "humanize-numbers"} - ${optionalString (cfg.checkpointBytes != null) ("checkpoint-bytes "+cfg.checkpointBytes)} - ${optionalString cfg.aggressiveNetworking "aggressive-networking"} - ${concatStringsSep "\n" (map (v: "exclude ${v}") cfg.excludes)} - ${concatStringsSep "\n" (map (v: "include ${v}") cfg.includes)} - ${optionalString cfg.lowmem "lowmem"} - ${optionalString cfg.verylowmem "verylowmem"} - ${optionalString (cfg.maxbw != null) "maxbw ${toString cfg.maxbw}"} - ${optionalString (cfg.maxbwRateUp != null) "maxbw-rate-up ${toString cfg.maxbwRateUp}"} - ${optionalString (cfg.maxbwRateDown != null) "maxbw-rate-down ${toString cfg.maxbwRateDown}"} + ${lib.optionalString (cfg.cachedir != null) "cachedir ${cfg.cachedir}"} + ${lib.optionalString cfg.nodump "nodump"} + ${lib.optionalString cfg.printStats "print-stats"} + ${lib.optionalString cfg.printStats "humanize-numbers"} + ${lib.optionalString (cfg.checkpointBytes != null) ("checkpoint-bytes "+cfg.checkpointBytes)} + ${lib.optionalString cfg.aggressiveNetworking "aggressive-networking"} + ${lib.concatStringsSep "\n" (map (v: "exclude ${v}") cfg.excludes)} + ${lib.concatStringsSep "\n" (map (v: "include ${v}") cfg.includes)} + ${lib.optionalString cfg.lowmem "lowmem"} + ${lib.optionalString cfg.verylowmem "verylowmem"} + ${lib.optionalString (cfg.maxbw != null) "maxbw ${toString cfg.maxbw}"} + ${lib.optionalString (cfg.maxbwRateUp != null) "maxbw-rate-up ${toString cfg.maxbwRateUp}"} + ${lib.optionalString (cfg.maxbwRateDown != null) "maxbw-rate-down ${toString cfg.maxbwRateDown}"} ''; in { imports = [ - (mkRemovedOptionModule [ "services" "tarsnap" "cachedir" ] "Use services.tarsnap.archives..cachedir") + (lib.mkRemovedOptionModule [ "services" "tarsnap" "cachedir" ] "Use services.tarsnap.archives..cachedir") ]; options = { services.tarsnap = { - enable = mkEnableOption "periodic tarsnap backups"; + enable = lib.mkEnableOption "periodic tarsnap backups"; - package = mkPackageOption pkgs "tarsnap" { }; + package = lib.mkPackageOption pkgs "tarsnap" { }; - keyfile = mkOption { - type = types.str; + keyfile = lib.mkOption { + type = lib.types.str; default = "/root/tarsnap.key"; description = '' The keyfile which associates this machine with your tarsnap @@ -61,14 +58,14 @@ in ''; }; - archives = mkOption { - type = types.attrsOf (types.submodule ({ config, options, ... }: + archives = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({ config, options, ... }: { options = { - keyfile = mkOption { - type = types.str; + keyfile = lib.mkOption { + type = lib.types.str; default = gcfg.keyfile; - defaultText = literalExpression "config.${opt.keyfile}"; + defaultText = lib.literalExpression "config.${opt.keyfile}"; description = '' Set a specific keyfile for this archive. This defaults to `"/root/tarsnap.key"` if left unspecified. @@ -88,10 +85,10 @@ in ''; }; - cachedir = mkOption { - type = types.nullOr types.path; + cachedir = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = "/var/cache/tarsnap/${utils.escapeSystemdPath config.keyfile}"; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' "/var/cache/tarsnap/''${utils.escapeSystemdPath config.${options.keyfile}}" ''; description = '' @@ -106,16 +103,16 @@ in ''; }; - nodump = mkOption { - type = types.bool; + nodump = lib.mkOption { + type = lib.types.bool; default = true; description = '' Exclude files with the `nodump` flag. ''; }; - printStats = mkOption { - type = types.bool; + printStats = lib.mkOption { + type = lib.types.bool; default = true; description = '' Print global archive statistics upon completion. @@ -124,8 +121,8 @@ in ''; }; - checkpointBytes = mkOption { - type = types.nullOr types.str; + checkpointBytes = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "1GB"; description = '' Create a checkpoint every `checkpointBytes` @@ -138,8 +135,8 @@ in ''; }; - period = mkOption { - type = types.str; + period = lib.mkOption { + type = lib.types.str; default = "01:15"; example = "hourly"; description = '' @@ -150,8 +147,8 @@ in ''; }; - aggressiveNetworking = mkOption { - type = types.bool; + aggressiveNetworking = lib.mkOption { + type = lib.types.bool; default = false; description = '' Upload data over multiple TCP connections, potentially @@ -162,22 +159,22 @@ in ''; }; - directories = mkOption { - type = types.listOf types.path; + directories = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = "List of filesystem paths to archive."; }; - excludes = mkOption { - type = types.listOf types.str; + excludes = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Exclude files and directories matching these patterns. ''; }; - includes = mkOption { - type = types.listOf types.str; + includes = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Include only files and directories matching these @@ -187,8 +184,8 @@ in ''; }; - lowmem = mkOption { - type = types.bool; + lowmem = lib.mkOption { + type = lib.types.bool; default = false; description = '' Reduce memory consumption by not caching small files. @@ -198,8 +195,8 @@ in ''; }; - verylowmem = mkOption { - type = types.bool; + verylowmem = lib.mkOption { + type = lib.types.bool; default = false; description = '' Reduce memory consumption by a factor of 2 beyond what @@ -208,8 +205,8 @@ in ''; }; - maxbw = mkOption { - type = types.nullOr types.int; + maxbw = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' Abort archival if upstream bandwidth usage in bytes @@ -217,40 +214,40 @@ in ''; }; - maxbwRateUp = mkOption { - type = types.nullOr types.int; + maxbwRateUp = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; - example = literalExpression "25 * 1000"; + example = lib.literalExpression "25 * 1000"; description = '' Upload bandwidth rate limit in bytes. ''; }; - maxbwRateDown = mkOption { - type = types.nullOr types.int; + maxbwRateDown = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; - example = literalExpression "50 * 1000"; + example = lib.literalExpression "50 * 1000"; description = '' Download bandwidth rate limit in bytes. ''; }; - verbose = mkOption { - type = types.bool; + verbose = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to produce verbose logging output. ''; }; - explicitSymlinks = mkOption { - type = types.bool; + explicitSymlinks = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to follow symlinks specified as archives. ''; }; - followSymlinks = mkOption { - type = types.bool; + followSymlinks = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to follow all symlinks in archive trees. @@ -262,7 +259,7 @@ in default = {}; - example = literalExpression '' + example = lib.literalExpression '' { nixos = { directories = [ "/home" "/root/ssl" ]; @@ -292,19 +289,19 @@ in }; }; - config = mkIf gcfg.enable { + config = lib.mkIf gcfg.enable { assertions = - (mapAttrsToList (name: cfg: + (lib.mapAttrsToList (name: cfg: { assertion = cfg.directories != []; message = "Must specify paths for tarsnap to back up"; }) gcfg.archives) ++ - (mapAttrsToList (name: cfg: + (lib.mapAttrsToList (name: cfg: { assertion = !(cfg.lowmem && cfg.verylowmem); message = "You cannot set both lowmem and verylowmem"; }) gcfg.archives); systemd.services = - (mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" { + (lib.mapAttrs' (name: cfg: lib.nameValuePair "tarsnap-${name}" { description = "Tarsnap archive '${name}'"; requires = [ "network-online.target" ]; after = [ "network-online.target" ]; @@ -322,11 +319,11 @@ in script = let tarsnap = ''${lib.getExe gcfg.package} --configfile "/etc/tarsnap/${name}.conf"''; run = ''${tarsnap} -c -f "${name}-$(date +"%Y%m%d%H%M%S")" \ - ${optionalString cfg.verbose "-v"} \ - ${optionalString cfg.explicitSymlinks "-H"} \ - ${optionalString cfg.followSymlinks "-L"} \ - ${concatStringsSep " " cfg.directories}''; - cachedir = escapeShellArg cfg.cachedir; + ${lib.optionalString cfg.verbose "-v"} \ + ${lib.optionalString cfg.explicitSymlinks "-H"} \ + ${lib.optionalString cfg.followSymlinks "-L"} \ + ${lib.concatStringsSep " " cfg.directories}''; + cachedir = lib.escapeShellArg cfg.cachedir; in if (cfg.cachedir != null) then '' mkdir -p ${cachedir} chmod 0700 ${cachedir} @@ -353,7 +350,7 @@ in }; }) gcfg.archives) // - (mapAttrs' (name: cfg: nameValuePair "tarsnap-restore-${name}"{ + (lib.mapAttrs' (name: cfg: lib.nameValuePair "tarsnap-restore-${name}"{ description = "Tarsnap restore '${name}'"; requires = [ "network-online.target" ]; @@ -362,8 +359,8 @@ in script = let tarsnap = ''${lib.getExe gcfg.package} --configfile "/etc/tarsnap/${name}.conf"''; lastArchive = "$(${tarsnap} --list-archives | sort | tail -1)"; - run = ''${tarsnap} -x -f "${lastArchive}" ${optionalString cfg.verbose "-v"}''; - cachedir = escapeShellArg cfg.cachedir; + run = ''${tarsnap} -x -f "${lastArchive}" ${lib.optionalString cfg.verbose "-v"}''; + cachedir = lib.escapeShellArg cfg.cachedir; in if (cfg.cachedir != null) then '' mkdir -p ${cachedir} @@ -393,14 +390,14 @@ in # Note: the timer must be Persistent=true, so that systemd will start it even # if e.g. your laptop was asleep while the latest interval occurred. - systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" + systemd.timers = lib.mapAttrs' (name: cfg: lib.nameValuePair "tarsnap-${name}" { timerConfig.OnCalendar = cfg.period; timerConfig.Persistent = "true"; wantedBy = [ "timers.target" ]; }) gcfg.archives; environment.etc = - mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf" + lib.mapAttrs' (name: cfg: lib.nameValuePair "tarsnap/${name}.conf" { text = configFile name cfg; }) gcfg.archives; diff --git a/nixos/modules/services/backup/tsm.nix b/nixos/modules/services/backup/tsm.nix index 9e1abb85bfe5..6589fcd9466c 100644 --- a/nixos/modules/services/backup/tsm.nix +++ b/nixos/modules/services/backup/tsm.nix @@ -90,7 +90,7 @@ in environment.HOME = "/var/lib/tsm-backup"; serviceConfig = { # for exit status description see - # https://www.ibm.com/docs/en/storage-protect/8.1.23?topic=clients-client-return-codes + # https://www.ibm.com/docs/en/storage-protect/8.1.24?topic=clients-client-return-codes SuccessExitStatus = "4 8"; # The `-se` option must come after the command. # The `-optfile` option suppresses a `dsm.opt`-not-found warning. diff --git a/nixos/modules/services/backup/zfs-replication.nix b/nixos/modules/services/backup/zfs-replication.nix index c89d6fb8ad60..5aefaa35df50 100644 --- a/nixos/modules/services/backup/zfs-replication.nix +++ b/nixos/modules/services/backup/zfs-replication.nix @@ -1,56 +1,53 @@ { lib, pkgs, config, ... }: - -with lib; - let cfg = config.services.zfs.autoReplication; - recursive = optionalString cfg.recursive " --recursive"; - followDelete = optionalString cfg.followDelete " --follow-delete"; + recursive = lib.optionalString cfg.recursive " --recursive"; + followDelete = lib.optionalString cfg.followDelete " --follow-delete"; in { options = { services.zfs.autoReplication = { - enable = mkEnableOption "ZFS snapshot replication"; + enable = lib.mkEnableOption "ZFS snapshot replication"; - followDelete = mkOption { + followDelete = lib.mkOption { description = "Remove remote snapshots that don't have a local correspondent."; default = true; - type = types.bool; + type = lib.types.bool; }; - host = mkOption { + host = lib.mkOption { description = "Remote host where snapshots should be sent. `lz4` is expected to be installed on this host."; example = "example.com"; - type = types.str; + type = lib.types.str; }; - identityFilePath = mkOption { + identityFilePath = lib.mkOption { description = "Path to SSH key used to login to host."; example = "/home/username/.ssh/id_rsa"; - type = types.path; + type = lib.types.path; }; - localFilesystem = mkOption { + localFilesystem = lib.mkOption { description = "Local ZFS filesystem from which snapshots should be sent. Defaults to the attribute name."; example = "pool/file/path"; - type = types.str; + type = lib.types.str; }; - remoteFilesystem = mkOption { + remoteFilesystem = lib.mkOption { description = "Remote ZFS filesystem where snapshots should be sent."; example = "pool/file/path"; - type = types.str; + type = lib.types.str; }; - recursive = mkOption { + recursive = lib.mkOption { description = "Recursively discover snapshots to send."; default = true; - type = types.bool; + type = lib.types.bool; }; - username = mkOption { + username = lib.mkOption { description = "Username used by SSH to login to remote host."; example = "username"; - type = types.str; + type = lib.types.str; }; }; }; @@ -73,7 +70,7 @@ in { "https://github.com/alunduil/zfs-replicate" ]; restartIfChanged = false; - serviceConfig.ExecStart = "${pkgs.zfs-replicate}/bin/zfs-replicate${recursive} -l ${escapeShellArg cfg.username} -i ${escapeShellArg cfg.identityFilePath}${followDelete} ${escapeShellArg cfg.host} ${escapeShellArg cfg.remoteFilesystem} ${escapeShellArg cfg.localFilesystem}"; + serviceConfig.ExecStart = "${pkgs.zfs-replicate}/bin/zfs-replicate${recursive} -l ${lib.escapeShellArg cfg.username} -i ${lib.escapeShellArg cfg.identityFilePath}${followDelete} ${lib.escapeShellArg cfg.host} ${lib.escapeShellArg cfg.remoteFilesystem} ${lib.escapeShellArg cfg.localFilesystem}"; wantedBy = [ "zfs-snapshot-daily.service" "zfs-snapshot-frequent.service" diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix index 7f2c89edbf37..a3ea8b209bb6 100644 --- a/nixos/modules/services/backup/znapzend.nix +++ b/nixos/modules/services/backup/znapzend.nix @@ -1,8 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; -with types; - let planDescription = '' @@ -29,46 +25,46 @@ let planExample = "1h=>10min,1d=>1h,1w=>1d,1m=>1w,1y=>1m"; # A type for a string of the form number{b|k|M|G} - mbufferSizeType = str // { - check = x: str.check x && builtins.isList (builtins.match "^[0-9]+[bkMG]$" x); + mbufferSizeType = lib.types.str // { + check = x: lib.types.str.check x && builtins.isList (builtins.match "^[0-9]+[bkMG]$" x); description = "string of the form number{b|k|M|G}"; }; - enabledFeatures = concatLists (mapAttrsToList (name: enabled: optional enabled name) cfg.features); + enabledFeatures = lib.concatLists (lib.mapAttrsToList (name: enabled: lib.optional enabled name) cfg.features); # Type for a string that must contain certain other strings (the list parameter). # Note that these would need regex escaping. stringContainingStrings = list: let matching = s: map (str: builtins.match ".*${str}.*" s) list; - in str // { - check = x: str.check x && all isList (matching x); - description = "string containing all of the characters ${concatStringsSep ", " list}"; + in lib.types.str // { + check = x: lib.types.str.check x && lib.all lib.isList (matching x); + description = "string containing all of the characters ${lib.concatStringsSep ", " list}"; }; timestampType = stringContainingStrings [ "%Y" "%m" "%d" "%H" "%M" "%S" ]; - destType = srcConfig: submodule ({ name, ... }: { + destType = srcConfig: lib.types.submodule ({ name, ... }: { options = { - label = mkOption { - type = str; + label = lib.mkOption { + type = lib.types.str; description = "Label for this destination. Defaults to the attribute name."; }; - plan = mkOption { - type = str; + plan = lib.mkOption { + type = lib.types.str; description = planDescription; example = planExample; }; - dataset = mkOption { - type = str; + dataset = lib.mkOption { + type = lib.types.str; description = "Dataset name to send snapshots to."; example = "tank/main"; }; - host = mkOption { - type = nullOr str; + host = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Host to use for the destination dataset. Can be prefixed with `user@` to specify the ssh user. @@ -77,8 +73,8 @@ let example = "john@example.com"; }; - presend = mkOption { - type = nullOr str; + presend = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Command to run before sending the snapshot to the destination. Intended to run a remote script via {command}`ssh` on the @@ -89,8 +85,8 @@ let example = "ssh root@bserv zpool import -Nf tank"; }; - postsend = mkOption { - type = nullOr str; + postsend = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Command to run after sending the snapshot to the destination. Intended to run a remote script via {command}`ssh` on the @@ -103,37 +99,37 @@ let }; config = { - label = mkDefault name; - plan = mkDefault srcConfig.plan; + label = lib.mkDefault name; + plan = lib.mkDefault srcConfig.plan; }; }); - srcType = submodule ({ name, config, ... }: { + srcType = lib.types.submodule ({ name, config, ... }: { options = { - enable = mkOption { - type = bool; + enable = lib.mkOption { + type = lib.types.bool; description = "Whether to enable this source."; default = true; }; - recursive = mkOption { - type = bool; + recursive = lib.mkOption { + type = lib.types.bool; description = "Whether to do recursive snapshots."; default = false; }; mbuffer = { - enable = mkOption { - type = bool; + enable = lib.mkOption { + type = lib.types.bool; description = "Whether to use {command}`mbuffer`."; default = false; }; - port = mkOption { - type = nullOr ints.u16; + port = lib.mkOption { + type = lib.types.nullOr lib.types.ints.u16; description = '' Port to use for {command}`mbuffer`. @@ -147,7 +143,7 @@ let default = null; }; - size = mkOption { + size = lib.mkOption { type = mbufferSizeType; description = '' The size for {command}`mbuffer`. @@ -158,32 +154,32 @@ let }; }; - presnap = mkOption { - type = nullOr str; + presnap = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Command to run before snapshots are taken on the source dataset, e.g. for database locking/flushing. See also {option}`postsnap`. ''; default = null; - example = literalExpression '' + example = lib.literalExpression '' '''''${pkgs.mariadb}/bin/mysql -e "set autocommit=0;flush tables with read lock;\\! ''${pkgs.coreutils}/bin/sleep 600" & ''${pkgs.coreutils}/bin/echo $! > /tmp/mariadblock.pid ; sleep 10''' ''; }; - postsnap = mkOption { - type = nullOr str; + postsnap = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Command to run after snapshots are taken on the source dataset, e.g. for database unlocking. See also {option}`presnap`. ''; default = null; - example = literalExpression '' + example = lib.literalExpression '' "''${pkgs.coreutils}/bin/kill `''${pkgs.coreutils}/bin/cat /tmp/mariadblock.pid`;''${pkgs.coreutils}/bin/rm /tmp/mariadblock.pid" ''; }; - timestampFormat = mkOption { + timestampFormat = lib.mkOption { type = timestampType; description = '' The timestamp format to use for constructing snapshot names. @@ -197,8 +193,8 @@ let example = "znapzend-%m.%d.%Y-%H%M%SZ"; }; - sendDelay = mkOption { - type = int; + sendDelay = lib.mkOption { + type = lib.types.int; description = '' Specify delay (in seconds) before sending snaps to the destination. May be useful if you want to control sending time. @@ -207,23 +203,23 @@ let example = 60; }; - plan = mkOption { - type = str; + plan = lib.mkOption { + type = lib.types.str; description = planDescription; example = planExample; }; - dataset = mkOption { - type = str; + dataset = lib.mkOption { + type = lib.types.str; description = "The dataset to use for this source."; example = "tank/home"; }; - destinations = mkOption { - type = attrsOf (destType config); + destinations = lib.mkOption { + type = lib.types.attrsOf (destType config); description = "Additional destinations."; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { local = { dataset = "btank/backup"; @@ -240,7 +236,7 @@ let }; config = { - dataset = mkDefault name; + dataset = lib.mkDefault name; }; }); @@ -251,18 +247,18 @@ let onOff = b: if b then "on" else "off"; nullOff = b: if b == null then "off" else toString b; - stripSlashes = replaceStrings [ "/" ] [ "." ]; + stripSlashes = lib.replaceStrings [ "/" ] [ "." ]; - attrsToFile = config: concatStringsSep "\n" (builtins.attrValues ( - mapAttrs (n: v: "${n}=${v}") config)); + attrsToFile = config: lib.concatStringsSep "\n" (builtins.attrValues ( + lib.mapAttrs (n: v: "${n}=${v}") config)); mkDestAttrs = dst: with dst; - mapAttrs' (n: v: nameValuePair "dst_${label}${n}" v) ({ - "" = optionalString (host != null) "${host}:" + dataset; + lib.mapAttrs' (n: v: lib.nameValuePair "dst_${label}${n}" v) ({ + "" = lib.optionalString (host != null) "${host}:" + dataset; _plan = plan; - } // optionalAttrs (presend != null) { + } // lib.optionalAttrs (presend != null) { _precmd = presend; - } // optionalAttrs (postsend != null) { + } // lib.optionalAttrs (postsend != null) { _pstcmd = postsend; }); @@ -270,7 +266,7 @@ let enabled = onOff enable; # mbuffer is not referenced by its full path to accommodate non-NixOS systems or differing mbuffer versions between source and target mbuffer = with mbuffer; if enable then "mbuffer" - + optionalString (port != null) ":${toString port}" else "off"; + + lib.optionalString (port != null) ":${toString port}" else "off"; mbuffer_size = mbuffer.size; post_znap_cmd = nullOff postsnap; pre_znap_cmd = nullOff presnap; @@ -279,11 +275,11 @@ let src_plan = plan; tsformat = timestampFormat; zend_delay = toString sendDelay; - } // foldr (a: b: a // b) {} ( + } // lib.foldr (a: b: a // b) {} ( map mkDestAttrs (builtins.attrValues destinations) ); - files = mapAttrs' (n: srcCfg: let + files = lib.mapAttrs' (n: srcCfg: let fileText = attrsToFile (mkSrcAttrs srcCfg); in { name = srcCfg.dataset; @@ -294,20 +290,20 @@ in { options = { services.znapzend = { - enable = mkEnableOption "ZnapZend ZFS backup daemon"; + enable = lib.mkEnableOption "ZnapZend ZFS backup daemon"; - logLevel = mkOption { + logLevel = lib.mkOption { default = "debug"; example = "warning"; - type = enum ["debug" "info" "warning" "err" "alert"]; + type = lib.types.enum ["debug" "info" "warning" "err" "alert"]; description = '' The log level when logging to file. Any of debug, info, warning, err, alert. Default in daemonized form is debug. ''; }; - logTo = mkOption { - type = str; + logTo = lib.mkOption { + type = lib.types.str; default = "syslog::daemon"; example = "/var/log/znapzend.log"; description = '' @@ -315,31 +311,31 @@ in ''; }; - mailErrorSummaryTo = mkOption { - type = singleLineStr; + mailErrorSummaryTo = lib.mkOption { + type = lib.types.singleLineStr; default = ""; description = '' Email address to send a summary to if "send task(s) failed". ''; }; - noDestroy = mkOption { - type = bool; + noDestroy = lib.mkOption { + type = lib.types.bool; default = false; description = "Does all changes to the filesystem except destroy."; }; - autoCreation = mkOption { - type = bool; + autoCreation = lib.mkOption { + type = lib.types.bool; default = false; description = "Automatically create the destination dataset if it does not exist."; }; - zetup = mkOption { - type = attrsOf srcType; + zetup = lib.mkOption { + type = lib.types.attrsOf srcType; description = "Znapzend configuration."; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { "tank/home" = { # Make snapshots of tank/home every hour, keep those for 1 day, @@ -356,8 +352,8 @@ in ''; }; - pure = mkOption { - type = bool; + pure = lib.mkOption { + type = lib.types.bool; description = '' Do not persist any stateful znapzend setups. If this option is enabled, your previously set znapzend setups will be cleared and only @@ -366,17 +362,17 @@ in default = false; }; - features.oracleMode = mkEnableOption '' + features.oracleMode = lib.mkEnableOption '' destroying snapshots one by one instead of using one long argument list. If source and destination are out of sync for a long time, you may have so many snapshots to destroy that the argument gets is too long and the command fails ''; - features.recvu = mkEnableOption '' + features.recvu = lib.mkEnableOption '' recvu feature which uses `-u` on the receiving end to keep the destination filesystem unmounted ''; - features.compressed = mkEnableOption '' + features.compressed = lib.mkEnableOption '' compressed feature which adds the options `-Lce` to the {command}`zfs send` command. When this is enabled, make sure that both the sending and receiving pool have the same relevant @@ -387,7 +383,7 @@ in and {manpage}`zfs(8)` for more info ''; - features.sendRaw = mkEnableOption '' + features.sendRaw = lib.mkEnableOption '' sendRaw feature which adds the options `-w` to the {command}`zfs send` command. For encrypted source datasets this instructs zfs not to decrypt before sending which results in a remote @@ -396,7 +392,7 @@ in option must be used consistently, raw incrementals cannot be based on non-raw snapshots and vice versa ''; - features.skipIntermediates = mkEnableOption '' + features.skipIntermediates = lib.mkEnableOption '' the skipIntermediates feature to send a single increment between latest common snapshot and the newly made one. It may skip several source snaps if the destination was offline for some time, and @@ -404,14 +400,14 @@ in destinations, the new snapshot is sent as soon as it is created on the source, so there are no automatic increments to skip ''; - features.lowmemRecurse = mkEnableOption '' + features.lowmemRecurse = lib.mkEnableOption '' use lowmemRecurse on systems where you have too many datasets, so a recursive listing of attributes to find backup plans exhausts the memory available to {command}`znapzend`: instead, go the slower way to first list all impacted dataset names, and then query their configs one by one ''; - features.zfsGetType = mkEnableOption '' + features.zfsGetType = lib.mkEnableOption '' using zfsGetType if your {command}`zfs get` supports a `-t` argument for filtering by dataset type at all AND lists properties for snapshots by default when recursing, so that there @@ -425,7 +421,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.znapzend ]; systemd.services = { @@ -436,12 +432,12 @@ in path = with pkgs; [ zfs mbuffer openssh ]; - preStart = optionalString cfg.pure '' + preStart = lib.optionalString cfg.pure '' echo Resetting znapzend zetups ${pkgs.znapzend}/bin/znapzendzetup list \ | grep -oP '(?<=\*\*\* backup plan: ).*(?= \*\*\*)' \ | xargs -I{} ${pkgs.znapzend}/bin/znapzendzetup delete "{}" - '' + concatStringsSep "\n" (mapAttrsToList (dataset: config: '' + '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (dataset: config: '' echo Importing znapzend zetup ${config} for dataset ${dataset} ${pkgs.znapzend}/bin/znapzendzetup import --write ${dataset} ${config} & '') files) + '' @@ -458,15 +454,15 @@ in # Needs to have write access to ZFS User = "root"; ExecStart = let - args = concatStringsSep " " [ + args = lib.concatStringsSep " " [ "--logto=${cfg.logTo}" "--loglevel=${cfg.logLevel}" - (optionalString cfg.noDestroy "--nodestroy") - (optionalString cfg.autoCreation "--autoCreation") - (optionalString (cfg.mailErrorSummaryTo != "") + (lib.optionalString cfg.noDestroy "--nodestroy") + (lib.optionalString cfg.autoCreation "--autoCreation") + (lib.optionalString (cfg.mailErrorSummaryTo != "") "--mailErrorSummaryTo=${cfg.mailErrorSummaryTo}") - (optionalString (enabledFeatures != []) - "--features=${concatStringsSep "," enabledFeatures}") + (lib.optionalString (enabledFeatures != []) + "--features=${lib.concatStringsSep "," enabledFeatures}") ]; in "${pkgs.znapzend}/bin/znapzend ${args}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; @@ -475,5 +471,5 @@ in }; }; - meta.maintainers = with maintainers; [ SlothOfAnarchy ]; + meta.maintainers = with lib.maintainers; [ SlothOfAnarchy ]; } diff --git a/nixos/modules/services/backup/zrepl.nix b/nixos/modules/services/backup/zrepl.nix index a0e9a0da7e49..d46823adbadb 100644 --- a/nixos/modules/services/backup/zrepl.nix +++ b/nixos/modules/services/backup/zrepl.nix @@ -1,27 +1,25 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.services.zrepl; format = pkgs.formats.yaml { }; configFile = format.generate "zrepl.yml" cfg.settings; in { - meta.maintainers = with maintainers; [ cole-h ]; + meta.maintainers = with lib.maintainers; [ cole-h ]; options = { services.zrepl = { - enable = mkEnableOption "zrepl"; + enable = lib.mkEnableOption "zrepl"; - package = mkPackageOption pkgs "zrepl" { }; + package = lib.mkPackageOption pkgs "zrepl" { }; - settings = mkOption { + settings = lib.mkOption { default = { }; description = '' Configuration for zrepl. See for more information. ''; - type = types.submodule { + type = lib.types.submodule { freeformType = format.type; }; }; @@ -30,7 +28,7 @@ in ### Implementation ### - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; # zrepl looks for its config in this location by default. This diff --git a/nixos/modules/services/blockchain/ethereum/erigon.nix b/nixos/modules/services/blockchain/ethereum/erigon.nix index 24705b3433df..5ac952339151 100644 --- a/nixos/modules/services/blockchain/ethereum/erigon.nix +++ b/nixos/modules/services/blockchain/ethereum/erigon.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.erigon; @@ -11,18 +9,18 @@ in { options = { services.erigon = { - enable = mkEnableOption "Ethereum implementation on the efficiency frontier"; + enable = lib.mkEnableOption "Ethereum implementation on the efficiency frontier"; - package = mkPackageOption pkgs "erigon" { }; + package = lib.mkPackageOption pkgs "erigon" { }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Additional arguments passed to Erigon"; default = [ ]; }; - secretJwtPath = mkOption { - type = types.path; + secretJwtPath = lib.mkOption { + type = lib.types.path; description = '' Path to the secret jwt used for the http api authentication. ''; @@ -30,7 +28,7 @@ in { example = "config.age.secrets.ERIGON_JWT.path"; }; - settings = mkOption { + settings = lib.mkOption { description = '' Configuration for Erigon Refer to for details on supported values. @@ -52,7 +50,7 @@ in { "log.console.verbosity" = 3; # info }; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' { datadir = "/var/lib/erigon"; chain = "mainnet"; @@ -71,20 +69,20 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Default values are the same as in the binary, they are just written here for convenience. services.erigon.settings = { - datadir = mkDefault "/var/lib/erigon"; - chain = mkDefault "mainnet"; - http = mkDefault true; - "http.port" = mkDefault 8545; - "http.api" = mkDefault ["eth" "debug" "net" "trace" "web3" "erigon"]; - ws = mkDefault true; - port = mkDefault 30303; - "authrpc.port" = mkDefault 8551; - "torrent.port" = mkDefault 42069; - "private.api.addr" = mkDefault "localhost:9090"; - "log.console.verbosity" = mkDefault 3; # info + datadir = lib.mkDefault "/var/lib/erigon"; + chain = lib.mkDefault "mainnet"; + http = lib.mkDefault true; + "http.port" = lib.mkDefault 8545; + "http.api" = lib.mkDefault ["eth" "debug" "net" "trace" "web3" "erigon"]; + ws = lib.mkDefault true; + port = lib.mkDefault 30303; + "authrpc.port" = lib.mkDefault 8551; + "torrent.port" = lib.mkDefault 42069; + "private.api.addr" = lib.mkDefault "localhost:9090"; + "log.console.verbosity" = lib.mkDefault 3; # info }; systemd.services.erigon = { diff --git a/nixos/modules/services/blockchain/ethereum/geth.nix b/nixos/modules/services/blockchain/ethereum/geth.nix index f2a7e080ada1..52040f2b9ec5 100644 --- a/nixos/modules/services/blockchain/ethereum/geth.nix +++ b/nixos/modules/services/blockchain/ethereum/geth.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let eachGeth = config.services.geth; @@ -11,28 +8,28 @@ let enable = lib.mkEnableOption "Go Ethereum Node"; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 30303; description = "Port number Go Ethereum will be listening on, both TCP and UDP."; }; http = { enable = lib.mkEnableOption "Go Ethereum HTTP API"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Listen address of Go Ethereum HTTP API."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8545; description = "Port number of Go Ethereum HTTP API."; }; - apis = mkOption { - type = types.nullOr (types.listOf types.str); + apis = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; description = "APIs to enable over WebSocket"; example = ["net" "eth"]; @@ -41,20 +38,20 @@ let websocket = { enable = lib.mkEnableOption "Go Ethereum WebSocket API"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Listen address of Go Ethereum WebSocket API."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8546; description = "Port number of Go Ethereum WebSocket API."; }; - apis = mkOption { - type = types.nullOr (types.listOf types.str); + apis = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; description = "APIs to enable over WebSocket"; example = ["net" "eth"]; @@ -63,27 +60,27 @@ let authrpc = { enable = lib.mkEnableOption "Go Ethereum Auth RPC API"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Listen address of Go Ethereum Auth RPC API."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8551; description = "Port number of Go Ethereum Auth RPC API."; }; - vhosts = mkOption { - type = types.nullOr (types.listOf types.str); + vhosts = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = ["localhost"]; description = "List of virtual hostnames from which to accept requests."; example = ["localhost" "geth.example.org"]; }; - jwtsecret = mkOption { - type = types.str; + jwtsecret = lib.mkOption { + type = lib.types.str; default = ""; description = "Path to a JWT secret for authenticated RPC endpoint."; example = "/var/run/geth/jwtsecret"; @@ -92,50 +89,50 @@ let metrics = { enable = lib.mkEnableOption "Go Ethereum prometheus metrics"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Listen address of Go Ethereum metrics service."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 6060; description = "Port number of Go Ethereum metrics service."; }; }; - network = mkOption { - type = types.nullOr (types.enum [ "goerli" "rinkeby" "yolov2" "ropsten" ]); + network = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "goerli" "holesky" "rinkeby" "yolov2" "ropsten" ]); default = null; description = "The network to connect to. Mainnet (null) is the default ethereum network."; }; - syncmode = mkOption { - type = types.enum [ "snap" "fast" "full" "light" ]; + syncmode = lib.mkOption { + type = lib.types.enum [ "snap" "fast" "full" "light" ]; default = "snap"; description = "Blockchain sync mode."; }; - gcmode = mkOption { - type = types.enum [ "full" "archive" ]; + gcmode = lib.mkOption { + type = lib.types.enum [ "full" "archive" ]; default = "full"; description = "Blockchain garbage collection mode."; }; - maxpeers = mkOption { - type = types.int; + maxpeers = lib.mkOption { + type = lib.types.int; default = 50; description = "Maximum peers to connect to."; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Additional arguments passed to Go Ethereum."; default = []; }; - package = mkPackageOption pkgs [ "go-ethereum" "geth" ] { }; + package = lib.mkPackageOption pkgs [ "go-ethereum" "geth" ] { }; }; }; in @@ -145,8 +142,8 @@ in ###### interface options = { - services.geth = mkOption { - type = types.attrsOf (types.submodule gethOpts); + services.geth = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule gethOpts); default = {}; description = "Specification of one or more geth instances."; }; @@ -154,17 +151,17 @@ in ###### implementation - config = mkIf (eachGeth != {}) { + config = lib.mkIf (eachGeth != {}) { - environment.systemPackages = flatten (mapAttrsToList (gethName: cfg: [ + environment.systemPackages = lib.flatten (lib.mapAttrsToList (gethName: cfg: [ cfg.package ]) eachGeth); - systemd.services = mapAttrs' (gethName: cfg: let + systemd.services = lib.mapAttrs' (gethName: cfg: let stateDir = "goethereum/${gethName}/${if (cfg.network == null) then "mainnet" else cfg.network}"; dataDir = "/var/lib/${stateDir}"; in ( - nameValuePair "geth-${gethName}" (mkIf cfg.enable { + lib.nameValuePair "geth-${gethName}" (lib.mkIf cfg.enable { description = "Go Ethereum node (${gethName})"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; @@ -186,16 +183,16 @@ in ${cfg.package}/bin/geth \ --nousb \ --ipcdisable \ - ${optionalString (cfg.network != null) ''--${cfg.network}''} \ + ${lib.optionalString (cfg.network != null) ''--${cfg.network}''} \ --syncmode ${cfg.syncmode} \ --gcmode ${cfg.gcmode} \ --port ${toString cfg.port} \ --maxpeers ${toString cfg.maxpeers} \ - ${optionalString cfg.http.enable ''--http --http.addr ${cfg.http.address} --http.port ${toString cfg.http.port}''} \ - ${optionalString (cfg.http.apis != null) ''--http.api ${lib.concatStringsSep "," cfg.http.apis}''} \ - ${optionalString cfg.websocket.enable ''--ws --ws.addr ${cfg.websocket.address} --ws.port ${toString cfg.websocket.port}''} \ - ${optionalString (cfg.websocket.apis != null) ''--ws.api ${lib.concatStringsSep "," cfg.websocket.apis}''} \ - ${optionalString cfg.metrics.enable ''--metrics --metrics.addr ${cfg.metrics.address} --metrics.port ${toString cfg.metrics.port}''} \ + ${lib.optionalString cfg.http.enable ''--http --http.addr ${cfg.http.address} --http.port ${toString cfg.http.port}''} \ + ${lib.optionalString (cfg.http.apis != null) ''--http.api ${lib.concatStringsSep "," cfg.http.apis}''} \ + ${lib.optionalString cfg.websocket.enable ''--ws --ws.addr ${cfg.websocket.address} --ws.port ${toString cfg.websocket.port}''} \ + ${lib.optionalString (cfg.websocket.apis != null) ''--ws.api ${lib.concatStringsSep "," cfg.websocket.apis}''} \ + ${lib.optionalString cfg.metrics.enable ''--metrics --metrics.addr ${cfg.metrics.address} --metrics.port ${toString cfg.metrics.port}''} \ --authrpc.addr ${cfg.authrpc.address} --authrpc.port ${toString cfg.authrpc.port} --authrpc.vhosts ${lib.concatStringsSep "," cfg.authrpc.vhosts} \ ${if (cfg.authrpc.jwtsecret != "") then ''--authrpc.jwtsecret ${cfg.authrpc.jwtsecret}'' else ''--authrpc.jwtsecret ${dataDir}/geth/jwtsecret''} \ ${lib.escapeShellArgs cfg.extraArgs} \ diff --git a/nixos/modules/services/blockchain/ethereum/lighthouse.nix b/nixos/modules/services/blockchain/ethereum/lighthouse.nix index a5ace1a9450f..66a762763cb8 100644 --- a/nixos/modules/services/blockchain/ethereum/lighthouse.nix +++ b/nixos/modules/services/blockchain/ethereum/lighthouse.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.lighthouse; @@ -8,47 +6,47 @@ in { options = { services.lighthouse = { - beacon = mkOption { + beacon = lib.mkOption { description = "Beacon node"; default = {}; - type = types.submodule { + type = lib.types.submodule { options = { enable = lib.mkEnableOption "Lightouse Beacon node"; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/lighthouse-beacon"; description = '' Directory where data will be stored. Each chain will be stored under it's own specific subdirectory. ''; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = '' Listen address of Beacon node. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 9000; description = '' Port number the Beacon node will be listening on. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open the port in the firewall ''; }; - disableDepositContractSync = mkOption { - type = types.bool; + disableDepositContractSync = lib.mkOption { + type = lib.types.bool; default = false; description = '' Explicitly disables syncing of deposit logs from the execution node. @@ -58,24 +56,24 @@ in { }; execution = { - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Listen address for the execution layer. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8551; description = '' Port number the Beacon node will be listening on for the execution layer. ''; }; - jwtPath = mkOption { - type = types.str; + jwtPath = lib.mkOption { + type = lib.types.str; default = ""; description = '' Path for the jwt secret required to connect to the execution layer. @@ -85,16 +83,16 @@ in { http = { enable = lib.mkEnableOption "Beacon node http api"; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5052; description = '' Port number of Beacon node RPC service. ''; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Listen address of Beacon node RPC service. @@ -104,16 +102,16 @@ in { metrics = { enable = lib.mkEnableOption "Beacon node prometheus metrics"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Listen address of Beacon node metrics service. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5054; description = '' Port number of Beacon node metrics service. @@ -121,8 +119,8 @@ in { }; }; - extraArgs = mkOption { - type = types.str; + extraArgs = lib.mkOption { + type = lib.types.str; description = '' Additional arguments passed to the lighthouse beacon command. ''; @@ -133,27 +131,27 @@ in { }; }; - validator = mkOption { + validator = lib.mkOption { description = "Validator node"; default = {}; - type = types.submodule { + type = lib.types.submodule { options = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable Lightouse Validator node."; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/lighthouse-validator"; description = '' Directory where data will be stored. Each chain will be stored under it's own specific subdirectory. ''; }; - beaconNodes = mkOption { - type = types.listOf types.str; + beaconNodes = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["http://localhost:5052"]; description = '' Beacon nodes to connect to. @@ -162,16 +160,16 @@ in { metrics = { enable = lib.mkEnableOption "Validator node prometheus metrics"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Listen address of Validator node metrics service. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5056; description = '' Port number of Validator node metrics service. @@ -179,8 +177,8 @@ in { }; }; - extraArgs = mkOption { - type = types.str; + extraArgs = lib.mkOption { + type = lib.types.str; description = '' Additional arguments passed to the lighthouse validator command. ''; @@ -191,16 +189,16 @@ in { }; }; - network = mkOption { - type = types.enum [ "mainnet" "gnosis" "chiado" "sepolia" "holesky" ]; + network = lib.mkOption { + type = lib.types.enum [ "mainnet" "gnosis" "chiado" "sepolia" "holesky" ]; default = "mainnet"; description = '' The network to connect to. Mainnet is the default ethereum network. ''; }; - extraArgs = mkOption { - type = types.str; + extraArgs = lib.mkOption { + type = lib.types.str; description = '' Additional arguments passed to every lighthouse command. ''; @@ -210,17 +208,17 @@ in { }; }; - config = mkIf (cfg.beacon.enable || cfg.validator.enable) { + config = lib.mkIf (cfg.beacon.enable || cfg.validator.enable) { environment.systemPackages = [ pkgs.lighthouse ] ; - networking.firewall = mkIf cfg.beacon.enable { - allowedTCPPorts = mkIf cfg.beacon.openFirewall [ cfg.beacon.port ]; - allowedUDPPorts = mkIf cfg.beacon.openFirewall [ cfg.beacon.port ]; + networking.firewall = lib.mkIf cfg.beacon.enable { + allowedTCPPorts = lib.mkIf cfg.beacon.openFirewall [ cfg.beacon.port ]; + allowedUDPPorts = lib.mkIf cfg.beacon.openFirewall [ cfg.beacon.port ]; }; - systemd.services.lighthouse-beacon = mkIf cfg.beacon.enable { + systemd.services.lighthouse-beacon = lib.mkIf cfg.beacon.enable { description = "Lighthouse beacon node (connect to P2P nodes and verify blocks)"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; @@ -268,7 +266,7 @@ in { }; }; - systemd.services.lighthouse-validator = mkIf cfg.validator.enable { + systemd.services.lighthouse-validator = lib.mkIf cfg.validator.enable { description = "Lighthouse validtor node (manages validators, using data obtained from the beacon node via a HTTP API)"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; @@ -281,7 +279,7 @@ in { --network ${cfg.network} \ --beacon-nodes ${lib.concatStringsSep "," cfg.validator.beaconNodes} \ --datadir ${cfg.validator.dataDir}/${cfg.network} \ - ${optionalString cfg.validator.metrics.enable ''--metrics --metrics-address ${cfg.validator.metrics.address} --metrics-port ${toString cfg.validator.metrics.port}''} \ + ${lib.optionalString cfg.validator.metrics.enable ''--metrics --metrics-address ${cfg.validator.metrics.address} --metrics-port ${toString cfg.validator.metrics.port}''} \ ${cfg.extraArgs} ${cfg.validator.extraArgs} ''; diff --git a/nixos/modules/services/cluster/k3s/default.nix b/nixos/modules/services/cluster/k3s/default.nix index 83dfe2067147..2925745c9e09 100644 --- a/nixos/modules/services/cluster/k3s/default.nix +++ b/nixos/modules/services/cluster/k3s/default.nix @@ -4,8 +4,6 @@ pkgs, ... }: - -with lib; let cfg = config.services.k3s; removeOption = @@ -98,7 +96,7 @@ let } ); - enabledManifests = with builtins; filter (m: m.enable) (attrValues cfg.manifests); + 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 = @@ -132,11 +130,11 @@ in # interface options.services.k3s = { - enable = mkEnableOption "k3s"; + enable = lib.mkEnableOption "k3s"; - package = mkPackageOption pkgs "k3s" { }; + package = lib.mkPackageOption pkgs "k3s" { }; - role = mkOption { + role = lib.mkOption { description = '' Whether k3s should run as a server or agent. @@ -152,14 +150,14 @@ in - `serverAddr` is required. ''; default = "server"; - type = types.enum [ + type = lib.types.enum [ "server" "agent" ]; }; - serverAddr = mkOption { - type = types.str; + serverAddr = lib.mkOption { + type = lib.types.str; description = '' The k3s server to connect to. @@ -171,8 +169,8 @@ in default = ""; }; - clusterInit = mkOption { - type = types.bool; + clusterInit = lib.mkOption { + type = lib.types.bool; default = false; description = '' Initialize HA cluster using an embedded etcd datastore. @@ -193,8 +191,8 @@ in ''; }; - token = mkOption { - type = types.str; + token = lib.mkOption { + type = lib.types.str; description = '' The k3s token to use when connecting to a server. @@ -204,15 +202,15 @@ in default = ""; }; - tokenFile = mkOption { - type = types.nullOr types.path; + tokenFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "File path containing k3s token to use when connecting to the server."; default = null; }; - extraFlags = mkOption { + extraFlags = lib.mkOption { description = "Extra flags to pass to the k3s command."; - type = with types; either str (listOf str); + type = with lib.types; either str (listOf str); default = [ ]; example = [ "--no-deploy traefik" @@ -220,28 +218,28 @@ in ]; }; - disableAgent = mkOption { - type = types.bool; + disableAgent = lib.mkOption { + type = lib.types.bool; default = false; description = "Only run the server. This option only makes sense for a server."; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' File path containing environment variables for configuring the k3s service in the format of an EnvironmentFile. See systemd.exec(5). ''; default = null; }; - configPath = mkOption { - type = types.nullOr types.path; + configPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = "File path containing the k3s YAML config. This is useful when the config is generated (for example on boot)."; }; - manifests = mkOption { - type = types.attrsOf manifestModule; + manifests = lib.mkOption { + type = lib.types.attrsOf manifestModule; default = { }; example = lib.literalExpression '' deployment.source = ../manifests/deployment.yaml; @@ -328,8 +326,8 @@ in ''; }; - charts = mkOption { - type = with types; attrsOf (either path package); + charts = lib.mkOption { + type = with lib.types; attrsOf (either path package); default = { }; example = lib.literalExpression '' nginx = ../charts/my-nginx-chart.tgz; @@ -346,8 +344,8 @@ in ''; }; - containerdConfigTemplate = mkOption { - type = types.nullOr types.str; + containerdConfigTemplate = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = lib.literalExpression '' # Base K3s config @@ -366,8 +364,8 @@ in ''; }; - images = mkOption { - type = with types; listOf package; + images = lib.mkOption { + type = with lib.types; listOf package; default = [ ]; example = lib.literalExpression '' [ @@ -440,7 +438,7 @@ in # implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { warnings = (lib.optional (cfg.role != "server" && cfg.manifests != { }) "k3s: Auto deploying manifests are only installed on server nodes (role == server), they will be ignored by this node." @@ -500,7 +498,7 @@ in "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - path = optional config.boot.zfs.enabled config.boot.zfs.package; + path = lib.optional config.boot.zfs.enabled config.boot.zfs.package; serviceConfig = { # See: https://github.com/rancher/k3s/blob/dddbd16305284ae4bd14c0aade892412310d7edc/install.sh#L197 Type = if cfg.role == "agent" then "exec" else "notify"; @@ -514,15 +512,15 @@ in TasksMax = "infinity"; EnvironmentFile = cfg.environmentFile; ExecStartPre = activateK3sContent; - ExecStart = concatStringsSep " \\\n " ( + ExecStart = lib.concatStringsSep " \\\n " ( [ "${cfg.package}/bin/k3s ${cfg.role}" ] - ++ (optional cfg.clusterInit "--cluster-init") - ++ (optional cfg.disableAgent "--disable-agent") - ++ (optional (cfg.serverAddr != "") "--server ${cfg.serverAddr}") - ++ (optional (cfg.token != "") "--token ${cfg.token}") - ++ (optional (cfg.tokenFile != null) "--token-file ${cfg.tokenFile}") - ++ (optional (cfg.configPath != null) "--config ${cfg.configPath}") - ++ (optional (kubeletParams != { }) "--kubelet-arg=config=${kubeletConfig}") + ++ (lib.optional cfg.clusterInit "--cluster-init") + ++ (lib.optional cfg.disableAgent "--disable-agent") + ++ (lib.optional (cfg.serverAddr != "") "--server ${cfg.serverAddr}") + ++ (lib.optional (cfg.token != "") "--token ${cfg.token}") + ++ (lib.optional (cfg.tokenFile != null) "--token-file ${cfg.tokenFile}") + ++ (lib.optional (cfg.configPath != null) "--config ${cfg.configPath}") + ++ (lib.optional (kubeletParams != { }) "--kubelet-arg=config=${kubeletConfig}") ++ (lib.flatten cfg.extraFlags) ); }; diff --git a/nixos/modules/services/cluster/kubernetes/addons/dns.nix b/nixos/modules/services/cluster/kubernetes/addons/dns.nix index f18003527064..485c6f8e2b5f 100644 --- a/nixos/modules/services/cluster/kubernetes/addons/dns.nix +++ b/nixos/modules/services/cluster/kubernetes/addons/dns.nix @@ -1,7 +1,4 @@ { config, options, pkgs, lib, ... }: - -with lib; - let version = "1.10.1"; cfg = config.services.kubernetes.addons.dns; @@ -12,37 +9,37 @@ let }; in { options.services.kubernetes.addons.dns = { - enable = mkEnableOption "kubernetes dns addon"; + enable = lib.mkEnableOption "kubernetes dns addon"; - clusterIp = mkOption { + clusterIp = lib.mkOption { description = "Dns addon clusterIP"; # this default is also what kubernetes users default = ( - concatStringsSep "." ( - take 3 (splitString "." config.services.kubernetes.apiserver.serviceClusterIpRange + lib.concatStringsSep "." ( + lib.take 3 (lib.splitString "." config.services.kubernetes.apiserver.serviceClusterIpRange )) ) + ".254"; - defaultText = literalMD '' + defaultText = lib.literalMD '' The `x.y.z.254` IP of `config.${options.services.kubernetes.apiserver.serviceClusterIpRange}`. ''; - type = types.str; + type = lib.types.str; }; - clusterDomain = mkOption { + clusterDomain = lib.mkOption { description = "Dns cluster domain"; default = "cluster.local"; - type = types.str; + type = lib.types.str; }; - replicas = mkOption { + replicas = lib.mkOption { description = "Number of DNS pod replicas to deploy in the cluster."; default = 2; - type = types.int; + type = lib.types.int; }; - reconcileMode = mkOption { + reconcileMode = lib.mkOption { description = '' Controls the addon manager reconciliation mode for the DNS addon. @@ -51,12 +48,12 @@ in { See: . ''; default = "Reconcile"; - type = types.enum [ "Reconcile" "EnsureExists" ]; + type = lib.types.enum [ "Reconcile" "EnsureExists" ]; }; - coredns = mkOption { + coredns = lib.mkOption { description = "Docker image to seed for the CoreDNS container."; - type = types.attrs; + type = lib.types.attrs; default = { imageName = "coredns/coredns"; imageDigest = "sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e"; @@ -65,13 +62,13 @@ in { }; }; - corefile = mkOption { + corefile = lib.mkOption { description = '' Custom coredns corefile configuration. See: . ''; - type = types.str; + type = lib.types.str; default = '' .:${toString ports.dns} { errors @@ -87,7 +84,7 @@ in { reload loadbalance }''; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' ''' .:${toString ports.dns} { errors @@ -108,9 +105,9 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.kubernetes.kubelet.seedDockerImages = - singleton (pkgs.dockerTools.pullImage cfg.coredns); + lib.singleton (pkgs.dockerTools.pullImage cfg.coredns); services.kubernetes.addonManager.bootstrapAddons = { coredns-cr = { @@ -366,7 +363,7 @@ in { }; }; - services.kubernetes.kubelet.clusterDns = mkDefault cfg.clusterIp; + services.kubernetes.kubelet.clusterDns = lib.mkDefault [ cfg.clusterIp ]; }; meta.buildDocsInSandbox = false; diff --git a/nixos/modules/services/cluster/kubernetes/flannel.nix b/nixos/modules/services/cluster/kubernetes/flannel.nix index 93a460971055..f0269cd0bc21 100644 --- a/nixos/modules/services/cluster/kubernetes/flannel.nix +++ b/nixos/modules/services/cluster/kubernetes/flannel.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let top = config.services.kubernetes; cfg = top.flannel; @@ -12,28 +9,28 @@ in { ###### interface options.services.kubernetes.flannel = { - enable = mkEnableOption "flannel networking"; + enable = lib.mkEnableOption "flannel networking"; - openFirewallPorts = mkOption { + openFirewallPorts = lib.mkOption { description = '' Whether to open the Flannel UDP ports in the firewall on all interfaces.''; - type = types.bool; + type = lib.types.bool; default = true; }; }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.flannel = { - enable = mkDefault true; - network = mkDefault top.clusterCidr; + enable = lib.mkDefault true; + network = lib.mkDefault top.clusterCidr; inherit storageBackend; nodeName = config.services.kubernetes.kubelet.hostname; }; services.kubernetes.kubelet = { - cni.config = mkDefault [{ + cni.config = lib.mkDefault [{ name = "mynet"; type = "flannel"; cniVersion = "0.3.1"; @@ -45,7 +42,7 @@ in }; networking = { - firewall.allowedUDPPorts = mkIf cfg.openFirewallPorts [ + firewall.allowedUDPPorts = lib.mkIf cfg.openFirewallPorts [ 8285 # flannel udp 8472 # flannel vxlan ]; @@ -61,7 +58,7 @@ in }; # give flannel some kubernetes rbac permissions if applicable - services.kubernetes.addonManager.bootstrapAddons = mkIf ((storageBackend == "kubernetes") && (elem "RBAC" top.apiserver.authorizationMode)) { + services.kubernetes.addonManager.bootstrapAddons = lib.mkIf ((storageBackend == "kubernetes") && (lib.elem "RBAC" top.apiserver.authorizationMode)) { flannel-cr = { apiVersion = "rbac.authorization.k8s.io/v1"; diff --git a/nixos/modules/services/cluster/kubernetes/kubelet.nix b/nixos/modules/services/cluster/kubernetes/kubelet.nix index fd9df556e7ec..8fa820ac44e9 100644 --- a/nixos/modules/services/cluster/kubernetes/kubelet.nix +++ b/nixos/modules/services/cluster/kubernetes/kubelet.nix @@ -64,8 +64,9 @@ let } // lib.optionalAttrs (cfg.tlsCertFile != null) { tlsCertFile = cfg.tlsCertFile; } // lib.optionalAttrs (cfg.tlsKeyFile != null) { tlsPrivateKeyFile = cfg.tlsKeyFile; } // lib.optionalAttrs (cfg.clusterDomain != "") { clusterDomain = cfg.clusterDomain; } - // lib.optionalAttrs (cfg.clusterDns != "") { clusterDNS = [ cfg.clusterDns ] ; } + // lib.optionalAttrs (cfg.clusterDns != []) { clusterDNS = cfg.clusterDns; } // lib.optionalAttrs (cfg.featureGates != {}) { featureGates = cfg.featureGates; } + // lib.optionalAttrs (cfg.extraConfig != {}) cfg.extraConfig )); manifestPath = "kubernetes/manifests"; @@ -112,8 +113,8 @@ in clusterDns = mkOption { description = "Use alternative DNS."; - default = "10.1.0.1"; - type = str; + default = [ "10.1.0.1" ]; + type = listOf str; }; clusterDomain = mkOption { @@ -184,6 +185,12 @@ in type = separatedString " "; }; + extraConfig = mkOption { + description = "Kubernetes kubelet extra configuration file entries."; + default = {}; + type = attrsOf attrs; + }; + featureGates = mkOption { description = "Attribute set of feature gate"; default = top.featureGates; diff --git a/nixos/modules/services/cluster/pacemaker/default.nix b/nixos/modules/services/cluster/pacemaker/default.nix index 005a952e8025..92cd9311eb7d 100644 --- a/nixos/modules/services/cluster/pacemaker/default.nix +++ b/nixos/modules/services/cluster/pacemaker/default.nix @@ -1,19 +1,17 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.pacemaker; in { # interface options.services.pacemaker = { - enable = mkEnableOption "pacemaker"; + enable = lib.mkEnableOption "pacemaker"; - package = mkPackageOption pkgs "pacemaker" { }; + package = lib.mkPackageOption pkgs "pacemaker" { }; }; # implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = config.services.corosync.enable; message = '' diff --git a/nixos/modules/services/cluster/patroni/default.nix b/nixos/modules/services/cluster/patroni/default.nix index 3b563bb89fff..91eb9214a60e 100644 --- a/nixos/modules/services/cluster/patroni/default.nix +++ b/nixos/modules/services/cluster/patroni/default.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.patroni; defaultUser = "patroni"; @@ -21,20 +20,20 @@ in options.services.patroni = { - enable = mkEnableOption "Patroni"; + enable = lib.mkEnableOption "Patroni"; - postgresqlPackage = mkOption { - type = types.package; - example = literalExpression "pkgs.postgresql_14"; + postgresqlPackage = lib.mkOption { + type = lib.types.package; + example = lib.literalExpression "pkgs.postgresql_14"; description = '' PostgreSQL package to use. Plugins can be enabled like this `pkgs.postgresql_14.withPackages (p: [ p.pg_safeupdate p.postgis ])`. ''; }; - postgresqlDataDir = mkOption { - type = types.path; - defaultText = literalExpression ''"/var/lib/postgresql/''${config.services.patroni.postgresqlPackage.psqlSchema}"''; + postgresqlDataDir = lib.mkOption { + type = lib.types.path; + defaultText = lib.literalExpression ''"/var/lib/postgresql/''${config.services.patroni.postgresqlPackage.psqlSchema}"''; example = "/var/lib/postgresql/14"; default = "/var/lib/postgresql/${cfg.postgresqlPackage.psqlSchema}"; description = '' @@ -45,16 +44,16 @@ in ''; }; - postgresqlPort = mkOption { - type = types.port; + postgresqlPort = lib.mkOption { + type = lib.types.port; default = 5432; description = '' The port on which PostgreSQL listens. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = defaultUser; example = "postgres"; description = '' @@ -63,8 +62,8 @@ in ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = defaultGroup; example = "postgres"; description = '' @@ -73,64 +72,64 @@ in ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/patroni"; description = '' Folder where Patroni data will be written, this is where the pgpass password file will be written. ''; }; - scope = mkOption { - type = types.str; + scope = lib.mkOption { + type = lib.types.str; example = "cluster1"; description = '' Cluster name. ''; }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; example = "node1"; description = '' The name of the host. Must be unique for the cluster. ''; }; - namespace = mkOption { - type = types.str; + namespace = lib.mkOption { + type = lib.types.str; default = "/service"; description = '' Path within the configuration store where Patroni will keep information about the cluster. ''; }; - nodeIp = mkOption { - type = types.str; + nodeIp = lib.mkOption { + type = lib.types.str; example = "192.168.1.1"; description = '' IP address of this node. ''; }; - otherNodesIps = mkOption { - type = types.listOf types.str; + otherNodesIps = lib.mkOption { + type = lib.types.listOf lib.types.str; example = [ "192.168.1.2" "192.168.1.3" ]; description = '' IP addresses of the other nodes. ''; }; - restApiPort = mkOption { - type = types.port; + restApiPort = lib.mkOption { + type = lib.types.port; default = 8008; description = '' The port on Patroni's REST api listens. ''; }; - softwareWatchdog = mkOption { - type = types.bool; + softwareWatchdog = lib.mkOption { + type = lib.types.bool; default = false; description = '' This will configure Patroni to use the software watchdog built into the Linux kernel @@ -138,7 +137,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; description = '' @@ -148,8 +147,8 @@ in ''; }; - environmentFiles = mkOption { - type = with types; attrsOf (nullOr (oneOf [ str path package ])); + environmentFiles = lib.mkOption { + type = with lib.types; attrsOf (nullOr (oneOf [ str path package ])); default = { }; example = { PATRONI_REPLICATION_PASSWORD = "/secret/file"; @@ -159,7 +158,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.patroni.settings = { scope = cfg.scope; @@ -179,7 +178,7 @@ in pgpass = "${cfg.dataDir}/pgpass"; }; - watchdog = mkIf cfg.softwareWatchdog { + watchdog = lib.mkIf cfg.softwareWatchdog { mode = "required"; device = "/dev/watchdog"; safety_margin = 5; @@ -188,13 +187,13 @@ in users = { - users = mkIf (cfg.user == defaultUser) { + users = lib.mkIf (cfg.user == defaultUser) { patroni = { group = cfg.group; isSystemUser = true; }; }; - groups = mkIf (cfg.group == defaultGroup) { + groups = lib.mkIf (cfg.group == defaultGroup) { patroni = { }; }; }; @@ -207,11 +206,11 @@ in after = [ "network.target" ]; script = '' - ${concatStringsSep "\n" (attrValues (mapAttrs (name: path: ''export ${name}="$(< ${escapeShellArg path})"'') cfg.environmentFiles))} + ${lib.concatStringsSep "\n" (lib.attrValues (lib.mapAttrs (name: path: ''export ${name}="$(< ${lib.escapeShellArg path})"'') cfg.environmentFiles))} exec ${pkgs.patroni}/bin/patroni ${configFile} ''; - serviceConfig = mkMerge [ + serviceConfig = lib.mkMerge [ { User = cfg.user; Group = cfg.group; @@ -221,7 +220,7 @@ in ExecReload = "${pkgs.coreutils}/bin/kill -s HUP $MAINPID"; KillMode = "process"; } - (mkIf (cfg.postgresqlDataDir == "/var/lib/postgresql/${cfg.postgresqlPackage.psqlSchema}" && cfg.dataDir == "/var/lib/patroni") { + (lib.mkIf (cfg.postgresqlDataDir == "/var/lib/postgresql/${cfg.postgresqlPackage.psqlSchema}" && cfg.dataDir == "/var/lib/patroni") { StateDirectory = "patroni postgresql postgresql/${cfg.postgresqlPackage.psqlSchema}"; StateDirectoryMode = "0750"; }) @@ -229,9 +228,9 @@ in }; }; - boot.kernelModules = mkIf cfg.softwareWatchdog [ "softdog" ]; + boot.kernelModules = lib.mkIf cfg.softwareWatchdog [ "softdog" ]; - services.udev.extraRules = mkIf cfg.softwareWatchdog '' + services.udev.extraRules = lib.mkIf cfg.softwareWatchdog '' KERNEL=="watchdog", OWNER="${cfg.user}", GROUP="${cfg.group}", MODE="0600" ''; @@ -247,5 +246,5 @@ in }; }; - meta.maintainers = [ maintainers.phfroidmont ]; + meta.maintainers = [ lib.maintainers.phfroidmont ]; } diff --git a/nixos/modules/services/cluster/rke2/default.nix b/nixos/modules/services/cluster/rke2/default.nix index 51b849ebcc80..2e6816f43374 100644 --- a/nixos/modules/services/cluster/rke2/default.nix +++ b/nixos/modules/services/cluster/rke2/default.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.rke2; in @@ -8,12 +6,12 @@ in imports = [ ]; options.services.rke2 = { - enable = mkEnableOption "rke2"; + enable = lib.mkEnableOption "rke2"; - package = mkPackageOption pkgs "rke2" { }; + package = lib.mkPackageOption pkgs "rke2" { }; - role = mkOption { - type = types.enum [ "server" "agent" ]; + role = lib.mkOption { + type = lib.types.enum [ "server" "agent" ]; description = '' Whether rke2 should run as a server or agent. @@ -31,26 +29,26 @@ in default = "server"; }; - configPath = mkOption { - type = types.path; + configPath = lib.mkOption { + type = lib.types.path; description = "Load configuration from FILE."; default = "/etc/rancher/rke2/config.yaml"; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; description = "Turn on debug logs."; default = false; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; description = "The folder to hold state in."; default = "/var/lib/rancher/rke2"; }; - token = mkOption { - type = types.str; + token = lib.mkOption { + type = lib.types.str; description = '' Shared secret used to join a server or agent to a cluster. @@ -60,44 +58,44 @@ in default = ""; }; - tokenFile = mkOption { - type = types.nullOr types.path; + tokenFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "File path containing rke2 token to use when connecting to the server."; default = null; }; - disable = mkOption { - type = types.listOf types.str; + disable = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Do not deploy packaged components and delete any deployed components."; default = [ ]; }; - nodeName = mkOption { - type = types.nullOr types.str; + nodeName = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Node name."; default = null; }; - nodeLabel = mkOption { - type = types.listOf types.str; + nodeLabel = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Registering and starting kubelet with set of labels."; default = [ ]; }; - nodeTaint = mkOption { - type = types.listOf types.str; + nodeTaint = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Registering kubelet with set of taints."; default = [ ]; }; - nodeIP = mkOption { - type = types.nullOr types.str; + nodeIP = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "IPv4/IPv6 addresses to advertise for node."; default = null; }; - agentToken = mkOption { - type = types.str; + agentToken = lib.mkOption { + type = lib.types.str; description = '' Shared secret used to join agents to the cluster, but not servers. @@ -107,27 +105,27 @@ in default = ""; }; - agentTokenFile = mkOption { - type = types.nullOr types.path; + agentTokenFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "File path containing rke2 agent token to use when connecting to the server."; default = null; }; - serverAddr = mkOption { - type = types.str; + serverAddr = lib.mkOption { + type = lib.types.str; description = "The rke2 server to connect to, used to join a cluster."; example = "https://10.0.0.10:6443"; default = ""; }; - selinux = mkOption { - type = types.bool; + selinux = lib.mkOption { + type = lib.types.bool; description = "Enable SELinux in containerd."; default = false; }; - cni = mkOption { - type = types.enum [ "none" "canal" "cilium" "calico" "flannel" ]; + cni = lib.mkOption { + type = lib.types.enum [ "none" "canal" "cilium" "calico" "flannel" ]; description = '' CNI Plugins to deploy, one of `none`, `calico`, `canal`, `cilium` or `flannel`. @@ -141,8 +139,8 @@ in default = "canal"; }; - cisHardening = mkOption { - type = types.bool; + cisHardening = lib.mkOption { + type = lib.types.bool; description = '' Enable CIS Hardening for RKE2. @@ -162,8 +160,8 @@ in default = false; }; - extraFlags = mkOption { - type = types.listOf types.str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' Extra flags to pass to the rke2 service/agent. @@ -176,8 +174,8 @@ in default = [ ]; }; - environmentVars = mkOption { - type = types.attrsOf types.str; + environmentVars = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = '' Environment variables for configuring the rke2 service/agent. @@ -199,7 +197,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.role == "agent" -> (builtins.pathExists cfg.configPath || cfg.serverAddr != ""); @@ -234,7 +232,7 @@ in ''; }; # See: https://docs.rke2.io/security/hardening_guide#set-kernel-parameters - boot.kernel.sysctl = mkIf cfg.cisHardening { + boot.kernel.sysctl = lib.mkIf cfg.cisHardening { "vm.panic_on_oom" = 0; "vm.overcommit_memory" = 1; "kernel.panic" = 10; @@ -254,7 +252,7 @@ in "-/etc/sysconfig/%N" "-/usr/local/lib/systemd/system/%N.env" ]; - Environment = mapAttrsToList (k: v: "${k}=${v}") cfg.environmentVars; + Environment = lib.mapAttrsToList (k: v: "${k}=${v}") cfg.environmentVars; KillMode = "process"; Delegate = "yes"; LimitNOFILE = 1048576; @@ -277,23 +275,23 @@ in "-${pkgs.kmod}/bin/modprobe br_netfilter" "-${pkgs.kmod}/bin/modprobe overlay" ]; - ExecStart = "${cfg.package}/bin/rke2 '${cfg.role}' ${escapeShellArgs ( - (optional (cfg.configPath != "/etc/rancher/rke2/config.yaml") "--config=${cfg.configPath}") - ++ (optional cfg.debug "--debug") - ++ (optional (cfg.dataDir != "/var/lib/rancher/rke2") "--data-dir=${cfg.dataDir}") - ++ (optional (cfg.token != "") "--token=${cfg.token}") - ++ (optional (cfg.tokenFile != null) "--token-file=${cfg.tokenFile}") - ++ (optionals (cfg.role == "server" && cfg.disable != [ ]) (map (d: "--disable=${d}") cfg.disable)) - ++ (optional (cfg.nodeName != null) "--node-name=${cfg.nodeName}") - ++ (optionals (cfg.nodeLabel != [ ]) (map (l: "--node-label=${l}") cfg.nodeLabel)) - ++ (optionals (cfg.nodeTaint != [ ]) (map (t: "--node-taint=${t}") cfg.nodeTaint)) - ++ (optional (cfg.nodeIP != null) "--node-ip=${cfg.nodeIP}") - ++ (optional (cfg.role == "server" && cfg.agentToken != "") "--agent-token=${cfg.agentToken}") - ++ (optional (cfg.role == "server" && cfg.agentTokenFile != null) "--agent-token-file=${cfg.agentTokenFile}") - ++ (optional (cfg.serverAddr != "") "--server=${cfg.serverAddr}") - ++ (optional cfg.selinux "--selinux") - ++ (optional (cfg.role == "server" && cfg.cni != "canal") "--cni=${cfg.cni}") - ++ (optional cfg.cisHardening "--profile=${if cfg.package.version >= "1.25" then "cis-1.23" else "cis-1.6"}") + ExecStart = "${cfg.package}/bin/rke2 '${cfg.role}' ${lib.escapeShellArgs ( + (lib.optional (cfg.configPath != "/etc/rancher/rke2/config.yaml") "--config=${cfg.configPath}") + ++ (lib.optional cfg.debug "--debug") + ++ (lib.optional (cfg.dataDir != "/var/lib/rancher/rke2") "--data-dir=${cfg.dataDir}") + ++ (lib.optional (cfg.token != "") "--token=${cfg.token}") + ++ (lib.optional (cfg.tokenFile != null) "--token-file=${cfg.tokenFile}") + ++ (lib.optionals (cfg.role == "server" && cfg.disable != [ ]) (map (d: "--disable=${d}") cfg.disable)) + ++ (lib.optional (cfg.nodeName != null) "--node-name=${cfg.nodeName}") + ++ (lib.optionals (cfg.nodeLabel != [ ]) (map (l: "--node-label=${l}") cfg.nodeLabel)) + ++ (lib.optionals (cfg.nodeTaint != [ ]) (map (t: "--node-taint=${t}") cfg.nodeTaint)) + ++ (lib.optional (cfg.nodeIP != null) "--node-ip=${cfg.nodeIP}") + ++ (lib.optional (cfg.role == "server" && cfg.agentToken != "") "--agent-token=${cfg.agentToken}") + ++ (lib.optional (cfg.role == "server" && cfg.agentTokenFile != null) "--agent-token-file=${cfg.agentTokenFile}") + ++ (lib.optional (cfg.serverAddr != "") "--server=${cfg.serverAddr}") + ++ (lib.optional cfg.selinux "--selinux") + ++ (lib.optional (cfg.role == "server" && cfg.cni != "canal") "--cni=${cfg.cni}") + ++ (lib.optional cfg.cisHardening "--profile=${if cfg.package.version >= "1.25" then "cis-1.23" else "cis-1.6"}") ++ cfg.extraFlags )}"; ExecStopPost = let diff --git a/nixos/modules/services/cluster/spark/default.nix b/nixos/modules/services/cluster/spark/default.nix index 7a3f768471c2..c4ebd3424392 100644 --- a/nixos/modules/services/cluster/spark/default.nix +++ b/nixos/modules/services/cluster/spark/default.nix @@ -2,20 +2,19 @@ let cfg = config.services.spark; in -with lib; { options = { services.spark = { master = { - enable = mkEnableOption "Spark master service"; - bind = mkOption { - type = types.str; + enable = lib.mkEnableOption "Spark master service"; + bind = lib.mkOption { + type = lib.types.str; description = "Address the spark master binds to."; default = "127.0.0.1"; example = "0.0.0.0"; }; - restartIfChanged = mkOption { - type = types.bool; + restartIfChanged = lib.mkOption { + type = lib.types.bool; description = '' Automatically restart master service on config change. This can be set to false to defer restarts on clusters running critical applications. @@ -24,8 +23,8 @@ with lib; ''; default = true; }; - extraEnvironment = mkOption { - type = types.attrsOf types.str; + extraEnvironment = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = "Extra environment variables to pass to spark master. See spark-standalone documentation."; default = {}; example = { @@ -35,19 +34,19 @@ with lib; }; }; worker = { - enable = mkEnableOption "Spark worker service"; - workDir = mkOption { - type = types.path; + enable = lib.mkEnableOption "Spark worker service"; + workDir = lib.mkOption { + type = lib.types.path; description = "Spark worker work dir."; default = "/var/lib/spark"; }; - master = mkOption { - type = types.str; + master = lib.mkOption { + type = lib.types.str; description = "Address of the spark master."; default = "127.0.0.1:7077"; }; - restartIfChanged = mkOption { - type = types.bool; + restartIfChanged = lib.mkOption { + type = lib.types.bool; description = '' Automatically restart worker service on config change. This can be set to false to defer restarts on clusters running critical applications. @@ -56,8 +55,8 @@ with lib; ''; default = true; }; - extraEnvironment = mkOption { - type = types.attrsOf types.str; + extraEnvironment = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = "Extra environment variables to pass to spark worker."; default = {}; example = { @@ -66,18 +65,18 @@ with lib; }; }; }; - confDir = mkOption { - type = types.path; + confDir = lib.mkOption { + type = lib.types.path; description = "Spark configuration directory. Spark will use the configuration files (spark-defaults.conf, spark-env.sh, log4j.properties, etc) from this directory."; default = "${cfg.package}/conf"; - defaultText = literalExpression ''"''${package}/conf"''; + defaultText = lib.literalExpression ''"''${package}/conf"''; }; - logDir = mkOption { - type = types.path; + logDir = lib.mkOption { + type = lib.types.path; description = "Spark log directory."; default = "/var/log/spark"; }; - package = mkPackageOption pkgs "spark" { + package = lib.mkPackageOption pkgs "spark" { example = '' spark.overrideAttrs (super: rec { pname = "spark"; diff --git a/nixos/modules/services/computing/boinc/client.nix b/nixos/modules/services/computing/boinc/client.nix index f5d7ab8d8cb2..01608d33d8d1 100644 --- a/nixos/modules/services/computing/boinc/client.nix +++ b/nixos/modules/services/computing/boinc/client.nix @@ -1,10 +1,7 @@ {config, lib, pkgs, ...}: - -with lib; - let cfg = config.services.boinc; - allowRemoteGuiRpcFlag = optionalString cfg.allowRemoteGuiRpc "--allow_remote_gui_rpc"; + allowRemoteGuiRpcFlag = lib.optionalString cfg.allowRemoteGuiRpc "--allow_remote_gui_rpc"; fhsEnv = pkgs.buildFHSEnv { name = "boinc-fhs-env"; @@ -16,8 +13,8 @@ let in { options.services.boinc = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the BOINC distributed computing client. If this @@ -27,20 +24,20 @@ in ''; }; - package = mkPackageOption pkgs "boinc" { + package = lib.mkPackageOption pkgs "boinc" { example = "boinc-headless"; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/boinc"; description = '' The directory in which to store BOINC's configuration and data files. ''; }; - allowRemoteGuiRpc = mkOption { - type = types.bool; + allowRemoteGuiRpc = lib.mkOption { + type = lib.types.bool; default = false; description = '' If set to true, any remote host can connect to and control this BOINC @@ -52,10 +49,10 @@ in ''; }; - extraEnvPackages = mkOption { - type = types.listOf types.package; + extraEnvPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "[ pkgs.virtualbox ]"; + example = lib.literalExpression "[ pkgs.virtualbox ]"; description = '' Additional packages to make available in the environment in which BOINC will run. Common choices are: @@ -77,7 +74,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [cfg.package]; users.users.boinc = { @@ -108,6 +105,6 @@ in }; meta = { - maintainers = with lib.maintainers; [kierdavis]; + maintainers = with lib.maintainers; [ ]; }; } diff --git a/nixos/modules/services/computing/foldingathome/client.nix b/nixos/modules/services/computing/foldingathome/client.nix index 8d330fd8717b..71fc58669d33 100644 --- a/nixos/modules/services/computing/foldingathome/client.nix +++ b/nixos/modules/services/computing/foldingathome/client.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.foldingathome; @@ -11,19 +10,19 @@ let in { imports = [ - (mkRenamedOptionModule [ "services" "foldingAtHome" ] [ "services" "foldingathome" ]) - (mkRenamedOptionModule [ "services" "foldingathome" "nickname" ] [ "services" "foldingathome" "user" ]) - (mkRemovedOptionModule [ "services" "foldingathome" "config" ] '' + (lib.mkRenamedOptionModule [ "services" "foldingAtHome" ] [ "services" "foldingathome" ]) + (lib.mkRenamedOptionModule [ "services" "foldingathome" "nickname" ] [ "services" "foldingathome" "user" ]) + (lib.mkRemovedOptionModule [ "services" "foldingathome" "config" ] '' Use services.foldingathome.extraArgs instead '') ]; options.services.foldingathome = { - enable = mkEnableOption "Folding@home client"; + enable = lib.mkEnableOption "Folding@home client"; - package = mkPackageOption pkgs "fahclient" { }; + package = lib.mkPackageOption pkgs "fahclient" { }; - user = mkOption { - type = types.nullOr types.str; + user = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The user associated with the reported computation results. This will @@ -31,8 +30,8 @@ in ''; }; - team = mkOption { - type = types.int; + team = lib.mkOption { + type = lib.types.int; default = 236565; description = '' The team ID associated with the reported computation results. This @@ -42,8 +41,8 @@ in ''; }; - daemonNiceLevel = mkOption { - type = types.ints.between (-20) 19; + daemonNiceLevel = lib.mkOption { + type = lib.types.ints.between (-20) 19; default = 0; description = '' Daemon process priority for FAHClient. @@ -51,8 +50,8 @@ in ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Extra startup options for the FAHClient. Run @@ -61,7 +60,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.foldingathome = { description = "Folding@home client"; after = [ "network.target" ]; diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix index 360a72677ce0..f4944d3ce318 100644 --- a/nixos/modules/services/computing/slurm/slurm.nix +++ b/nixos/modules/services/computing/slurm/slurm.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.slurm; @@ -15,8 +12,8 @@ let ClusterName=${cfg.clusterName} StateSaveLocation=${cfg.stateSaveLocation} SlurmUser=${cfg.user} - ${optionalString (cfg.controlMachine != null) "controlMachine=${cfg.controlMachine}"} - ${optionalString (cfg.controlAddr != null) "controlAddr=${cfg.controlAddr}"} + ${lib.optionalString (cfg.controlMachine != null) "controlMachine=${cfg.controlMachine}"} + ${lib.optionalString (cfg.controlAddr != null) "controlAddr=${cfg.controlAddr}"} ${toString (map (x: "NodeName=${x}\n") cfg.nodeName)} ${toString (map (x: "PartitionName=${x}\n") cfg.partitionName)} PlugStackConfig=${plugStackConfig}/plugstack.conf @@ -26,7 +23,7 @@ let plugStackConfig = pkgs.writeTextDir "plugstack.conf" '' - ${optionalString cfg.enableSrunX11 "optional ${pkgs.slurm-spank-x11}/lib/x11.so"} + ${lib.optionalString cfg.enableSrunX11 "optional ${pkgs.slurm-spank-x11}/lib/x11.so"} ${cfg.extraPlugstackConfig} ''; @@ -56,15 +53,15 @@ in ###### interface - meta.maintainers = [ maintainers.markuskowa ]; + meta.maintainers = [ lib.maintainers.markuskowa ]; options = { services.slurm = { server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the slurm control daemon. @@ -76,29 +73,29 @@ in }; dbdserver = { - enable = mkEnableOption "SlurmDBD service"; + enable = lib.mkEnableOption "SlurmDBD service"; - dbdHost = mkOption { - type = types.str; + dbdHost = lib.mkOption { + type = lib.types.str; default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; + defaultText = lib.literalExpression "config.networking.hostName"; description = '' Hostname of the machine where `slurmdbd` is running (i.e. name returned by `hostname -s`). ''; }; - storageUser = mkOption { - type = types.str; + storageUser = lib.mkOption { + type = lib.types.str; default = cfg.user; - defaultText = literalExpression "config.${opt.user}"; + defaultText = lib.literalExpression "config.${opt.user}"; description = '' Database user name. ''; }; - storagePassFile = mkOption { - type = with types; nullOr str; + storagePassFile = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Path to file with database password. The content of this will be used to @@ -106,8 +103,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra configuration for `slurmdbd.conf` See also: @@ -117,11 +114,11 @@ in }; client = { - enable = mkEnableOption "slurm client daemon"; + enable = lib.mkEnableOption "slurm client daemon"; }; - enableStools = mkOption { - type = types.bool; + enableStools = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to provide a slurm.conf file. @@ -131,14 +128,14 @@ in ''; }; - package = mkPackageOption pkgs "slurm" { + package = lib.mkPackageOption pkgs "slurm" { example = "slurm-full"; } // { default = pkgs.slurm.override { enableX11 = ! cfg.enableSrunX11; }; }; - controlMachine = mkOption { - type = types.nullOr types.str; + controlMachine = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = null; description = '' @@ -148,10 +145,10 @@ in ''; }; - controlAddr = mkOption { - type = types.nullOr types.str; + controlAddr = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = cfg.controlMachine; - defaultText = literalExpression "config.${opt.controlMachine}"; + defaultText = lib.literalExpression "config.${opt.controlMachine}"; example = null; description = '' Name that ControlMachine should be referred to in establishing a @@ -159,8 +156,8 @@ in ''; }; - clusterName = mkOption { - type = types.str; + clusterName = lib.mkOption { + type = lib.types.str; default = "default"; example = "myCluster"; description = '' @@ -168,10 +165,10 @@ in ''; }; - nodeName = mkOption { - type = types.listOf types.str; + nodeName = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; - example = literalExpression ''[ "linux[1-32] CPUs=1 State=UNKNOWN" ];''; + example = lib.literalExpression ''[ "linux[1-32] CPUs=1 State=UNKNOWN" ];''; description = '' Name that SLURM uses to refer to a node (or base partition for BlueGene systems). Typically this would be the string that "/bin/hostname -s" @@ -179,19 +176,19 @@ in ''; }; - partitionName = mkOption { - type = types.listOf types.str; + partitionName = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; - example = literalExpression ''[ "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP" ];''; + example = lib.literalExpression ''[ "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP" ];''; description = '' Name by which the partition may be referenced. Note that now you have to write the partition's parameters after the name. ''; }; - enableSrunX11 = mkOption { + enableSrunX11 = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' If enabled srun will accept the option "--x11" to allow for X11 forwarding from within an interactive session or a batch job. This activates the @@ -207,8 +204,8 @@ in ''; }; - procTrackType = mkOption { - type = types.str; + procTrackType = lib.mkOption { + type = lib.types.str; default = "proctrack/linuxproc"; description = '' Plugin to be used for process tracking on a job step basis. @@ -217,16 +214,16 @@ in ''; }; - stateSaveLocation = mkOption { - type = types.str; + stateSaveLocation = lib.mkOption { + type = lib.types.str; default = "/var/spool/slurmctld"; description = '' Directory into which the Slurm controller, slurmctld, saves its state. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = defaultUser; description = '' Set this option when you want to run the slurmctld daemon @@ -236,34 +233,34 @@ in ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Extra configuration options that will be added verbatim at the end of the slurm configuration file. ''; }; - extraPlugstackConfig = mkOption { + extraPlugstackConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Extra configuration that will be added to the end of `plugstack.conf`. ''; }; - extraCgroupConfig = mkOption { + extraCgroupConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Extra configuration for `cgroup.conf`. This file is used when `procTrackType=proctrack/cgroup`. ''; }; - extraConfigPaths = mkOption { - type = with types; listOf path; + extraConfigPaths = lib.mkOption { + type = with lib.types; listOf path; default = []; description = '' Slurm expects config files for plugins in the same path @@ -273,11 +270,11 @@ in ''; }; - etcSlurm = mkOption { - type = types.path; + etcSlurm = lib.mkOption { + type = lib.types.path; internal = true; default = etcSlurm; - defaultText = literalMD '' + defaultText = lib.literalMD '' Directory created from generated config files and `config.${opt.extraConfigPaths}`. ''; @@ -292,11 +289,11 @@ in }; imports = [ - (mkRemovedOptionModule [ "services" "slurm" "dbdserver" "storagePass" ] '' + (lib.mkRemovedOptionModule [ "services" "slurm" "dbdserver" "storagePass" ] '' This option has been removed so that the database password is not exposed via the nix store. Use services.slurm.dbdserver.storagePassFile to provide the database password. '') - (mkRemovedOptionModule [ "services" "slurm" "dbdserver" "configFile" ] '' + (lib.mkRemovedOptionModule [ "services" "slurm" "dbdserver" "configFile" ] '' This option has been removed. Use services.slurm.dbdserver.storagePassFile and services.slurm.dbdserver.extraConfig instead. '') @@ -312,7 +309,7 @@ in builder = pkgs.writeText "builder.sh" '' source $stdenv/setup mkdir -p $out/bin - find ${getBin cfg.package}/bin -type f -executable | while read EXE + find ${lib.getBin cfg.package}/bin -type f -executable | while read EXE do exename="$(basename $EXE)" wrappername="$out/bin/$exename" @@ -329,21 +326,21 @@ in done mkdir -p $out/share - ln -s ${getBin cfg.package}/share/man $out/share/man + ln -s ${lib.getBin cfg.package}/share/man $out/share/man ''; }; - in mkIf ( cfg.enableStools || + in lib.mkIf ( cfg.enableStools || cfg.client.enable || cfg.server.enable || cfg.dbdserver.enable ) { environment.systemPackages = [ wrappedSlurm ]; - services.munge.enable = mkDefault true; + services.munge.enable = lib.mkDefault true; # use a static uid as default to ensure it is the same on all nodes - users.users.slurm = mkIf (cfg.user == defaultUser) { + users.users.slurm = lib.mkIf (cfg.user == defaultUser) { name = defaultUser; group = "slurm"; uid = config.ids.uids.slurm; @@ -351,7 +348,7 @@ in users.groups.slurm.gid = config.ids.uids.slurm; - systemd.services.slurmd = mkIf (cfg.client.enable) { + systemd.services.slurmd = lib.mkIf (cfg.client.enable) { path = with pkgs; [ wrappedSlurm coreutils ] ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; @@ -375,13 +372,13 @@ in }; }; - systemd.tmpfiles.rules = mkIf cfg.client.enable [ + systemd.tmpfiles.rules = lib.mkIf cfg.client.enable [ "d /var/spool/slurmd 755 root root -" ]; - services.openssh.settings.X11Forwarding = mkIf cfg.client.enable (mkDefault true); + services.openssh.settings.X11Forwarding = lib.mkIf cfg.client.enable (lib.mkDefault true); - systemd.services.slurmctld = mkIf (cfg.server.enable) { + systemd.services.slurmctld = lib.mkIf (cfg.server.enable) { path = with pkgs; [ wrappedSlurm munge coreutils ] ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; @@ -405,7 +402,7 @@ in systemd.services.slurmdbd = let # slurm strips the last component off the path configPath = "$RUNTIME_DIRECTORY/slurmdbd.conf"; - in mkIf (cfg.dbdserver.enable) { + in lib.mkIf (cfg.dbdserver.enable) { path = with pkgs; [ wrappedSlurm munge coreutils ]; wantedBy = [ "multi-user.target" ]; @@ -414,7 +411,7 @@ in preStart = '' install -m 600 -o ${cfg.user} -T ${slurmdbdConf} ${configPath} - ${optionalString (cfg.dbdserver.storagePassFile != null) '' + ${lib.optionalString (cfg.dbdserver.storagePassFile != null) '' echo "StoragePass=$(cat ${cfg.dbdserver.storagePassFile})" \ >> ${configPath} ''} diff --git a/nixos/modules/services/computing/torque/mom.nix b/nixos/modules/services/computing/torque/mom.nix index 6747bd4b0d5a..8bc5fc134fcb 100644 --- a/nixos/modules/services/computing/torque/mom.nix +++ b/nixos/modules/services/computing/torque/mom.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.torque.mom; @@ -17,10 +14,10 @@ in options = { services.torque.mom = { - enable = mkEnableOption "torque computing node"; + enable = lib.mkEnableOption "torque computing node"; - serverNode = mkOption { - type = types.str; + serverNode = lib.mkOption { + type = lib.types.str; description = "Hostname running pbs server."; }; @@ -28,7 +25,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.torque ]; systemd.services.torque-mom-init = { diff --git a/nixos/modules/services/computing/torque/server.nix b/nixos/modules/services/computing/torque/server.nix index 8d923fc04d46..27be2c65b7e0 100644 --- a/nixos/modules/services/computing/torque/server.nix +++ b/nixos/modules/services/computing/torque/server.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.torque.server; torque = pkgs.torque; @@ -11,13 +8,13 @@ in services.torque.server = { - enable = mkEnableOption "torque server"; + enable = lib.mkEnableOption "torque server"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.torque ]; systemd.services.torque-server-init = { diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix index a4a9eee672cf..300e4e72a01e 100644 --- a/nixos/modules/services/continuous-integration/buildbot/master.nix +++ b/nixos/modules/services/continuous-integration/buildbot/master.nix @@ -1,9 +1,5 @@ # NixOS module for Buildbot continuous integration server. - { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.buildbot-master; opt = options.services.buildbot-master; @@ -11,27 +7,27 @@ let package = pkgs.python3.pkgs.toPythonModule cfg.package; python = package.pythonModule; - escapeStr = escape [ "'" ]; + escapeStr = lib.escape [ "'" ]; defaultMasterCfg = pkgs.writeText "master.cfg" '' from buildbot.plugins import * ${cfg.extraImports} factory = util.BuildFactory() c = BuildmasterConfig = dict( - workers = [${concatStringsSep "," cfg.workers}], + workers = [${lib.concatStringsSep "," cfg.workers}], protocols = { 'pb': {'port': ${toString cfg.pbPort} } }, title = '${escapeStr cfg.title}', titleURL = '${escapeStr cfg.titleUrl}', buildbotURL = '${escapeStr cfg.buildbotUrl}', db = dict(db_url='${escapeStr cfg.dbUrl}'), www = dict(port=${toString cfg.port}), - change_source = [ ${concatStringsSep "," cfg.changeSource} ], - schedulers = [ ${concatStringsSep "," cfg.schedulers} ], - builders = [ ${concatStringsSep "," cfg.builders} ], - services = [ ${concatStringsSep "," cfg.reporters} ], - configurators = [ ${concatStringsSep "," cfg.configurators} ], + change_source = [ ${lib.concatStringsSep "," cfg.changeSource} ], + schedulers = [ ${lib.concatStringsSep "," cfg.schedulers} ], + builders = [ ${lib.concatStringsSep "," cfg.builders} ], + services = [ ${lib.concatStringsSep "," cfg.reporters} ], + configurators = [ ${lib.concatStringsSep "," cfg.configurators} ], ) - for step in [ ${concatStringsSep "," cfg.factorySteps} ]: + for step in [ ${lib.concatStringsSep "," cfg.factorySteps} ]: factory.addStep(step) ${cfg.extraConfig} @@ -62,8 +58,8 @@ in { options = { services.buildbot-master = { - factorySteps = mkOption { - type = types.listOf types.str; + factorySteps = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Factory Steps"; default = []; example = [ @@ -72,8 +68,8 @@ in { ]; }; - changeSource = mkOption { - type = types.listOf types.str; + changeSource = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "List of Change Sources."; default = []; example = [ @@ -81,8 +77,8 @@ in { ]; }; - configurators = mkOption { - type = types.listOf types.str; + configurators = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Configurator Steps, see https://docs.buildbot.net/latest/manual/configuration/configurators.html"; default = []; example = [ @@ -90,35 +86,35 @@ in { ]; }; - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the Buildbot continuous integration server."; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; description = "Extra configuration to append to master.cfg"; default = "c['buildbotNetUsageData'] = None"; }; - extraImports = mkOption { - type = types.str; + extraImports = lib.mkOption { + type = lib.types.str; description = "Extra python imports to prepend to master.cfg"; default = ""; example = "from buildbot.process.project import Project"; }; - masterCfg = mkOption { - type = types.path; + masterCfg = lib.mkOption { + type = lib.types.path; description = "Optionally pass master.cfg path. Other options in this configuration will be ignored."; default = defaultMasterCfg; - defaultText = literalMD ''generated configuration file''; + defaultText = lib.literalMD ''generated configuration file''; example = "/etc/nixos/buildbot/master.cfg"; }; - schedulers = mkOption { - type = types.listOf types.str; + schedulers = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "List of Schedulers."; default = [ "schedulers.SingleBranchScheduler(name='all', change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=['runtests'])" @@ -126,60 +122,60 @@ in { ]; }; - builders = mkOption { - type = types.listOf types.str; + builders = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "List of Builders."; default = [ "util.BuilderConfig(name='runtests',workernames=['example-worker'],factory=factory)" ]; }; - workers = mkOption { - type = types.listOf types.str; + workers = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "List of Workers."; default = [ "worker.Worker('example-worker', 'pass')" ]; }; - reporters = mkOption { + reporters = lib.mkOption { default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = "List of reporter objects used to present build status to various users."; }; - user = mkOption { + user = lib.mkOption { default = "buildbot"; - type = types.str; + type = lib.types.str; description = "User the buildbot server should execute under."; }; - group = mkOption { + group = lib.mkOption { default = "buildbot"; - type = types.str; + type = lib.types.str; description = "Primary group of buildbot user."; }; - extraGroups = mkOption { - type = types.listOf types.str; + extraGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "List of extra groups that the buildbot user should be a part of."; }; - home = mkOption { + home = lib.mkOption { default = "/home/buildbot"; - type = types.path; + type = lib.types.path; description = "Buildbot home directory."; }; - buildbotDir = mkOption { + buildbotDir = lib.mkOption { default = "${cfg.home}/master"; - defaultText = literalExpression ''"''${config.${opt.home}}/master"''; - type = types.path; + defaultText = lib.literalExpression ''"''${config.${opt.home}}/master"''; + type = lib.types.path; description = "Specifies the Buildbot directory."; }; - pbPort = mkOption { + pbPort = lib.mkOption { default = 9989; - type = types.either types.str types.int; + type = lib.types.either lib.types.str lib.types.int; example = "'tcp:9990:interface=127.0.0.1'"; description = '' The buildmaster will listen on a TCP port of your choosing @@ -193,69 +189,69 @@ in { ''; }; - listenAddress = mkOption { + listenAddress = lib.mkOption { default = "0.0.0.0"; - type = types.str; + type = lib.types.str; description = "Specifies the bind address on which the buildbot HTTP interface listens."; }; - buildbotUrl = mkOption { + buildbotUrl = lib.mkOption { default = "http://localhost:8010/"; - type = types.str; + type = lib.types.str; description = "Specifies the Buildbot URL."; }; - title = mkOption { + title = lib.mkOption { default = "Buildbot"; - type = types.str; + type = lib.types.str; description = "Specifies the Buildbot Title."; }; - titleUrl = mkOption { + titleUrl = lib.mkOption { default = "Buildbot"; - type = types.str; + type = lib.types.str; description = "Specifies the Buildbot TitleURL."; }; - dbUrl = mkOption { + dbUrl = lib.mkOption { default = "sqlite:///state.sqlite"; - type = types.str; + type = lib.types.str; description = "Specifies the database connection string."; }; - port = mkOption { + port = lib.mkOption { default = 8010; - type = types.port; + type = lib.types.port; description = "Specifies port number on which the buildbot HTTP interface listens."; }; - package = mkPackageOption pkgs "buildbot-full" { + package = lib.mkPackageOption pkgs "buildbot-full" { example = "buildbot"; }; - packages = mkOption { + packages = lib.mkOption { default = [ pkgs.git ]; - defaultText = literalExpression "[ pkgs.git ]"; - type = types.listOf types.package; + defaultText = lib.literalExpression "[ pkgs.git ]"; + type = lib.types.listOf lib.types.package; description = "Packages to add to PATH for the buildbot process."; }; - pythonPackages = mkOption { - type = types.functionTo (types.listOf types.package); + pythonPackages = lib.mkOption { + type = lib.types.functionTo (lib.types.listOf lib.types.package); default = pythonPackages: with pythonPackages; [ ]; - defaultText = literalExpression "pythonPackages: with pythonPackages; [ ]"; + defaultText = lib.literalExpression "pythonPackages: with pythonPackages; [ ]"; description = "Packages to add the to the PYTHONPATH of the buildbot process."; - example = literalExpression "pythonPackages: with pythonPackages; [ requests ]"; + example = lib.literalExpression "pythonPackages: with pythonPackages; [ requests ]"; }; }; }; - config = mkIf cfg.enable { - users.groups = optionalAttrs (cfg.group == "buildbot") { + config = lib.mkIf cfg.enable { + users.groups = lib.optionalAttrs (cfg.group == "buildbot") { buildbot = { }; }; - users.users = optionalAttrs (cfg.user == "buildbot") { + users.users = lib.optionalAttrs (cfg.user == "buildbot") { buildbot = { description = "Buildbot User."; isNormalUser = true; @@ -298,8 +294,8 @@ in { }; imports = [ - (mkRenamedOptionModule [ "services" "buildbot-master" "bpPort" ] [ "services" "buildbot-master" "pbPort" ]) - (mkRemovedOptionModule [ "services" "buildbot-master" "status" ] '' + (lib.mkRenamedOptionModule [ "services" "buildbot-master" "bpPort" ] [ "services" "buildbot-master" "pbPort" ]) + (lib.mkRemovedOptionModule [ "services" "buildbot-master" "status" ] '' Since Buildbot 0.9.0, status targets are deprecated and ignored. Review your configuration and migrate to reporters (available at services.buildbot-master.reporters). '') diff --git a/nixos/modules/services/continuous-integration/github-runner/service.nix b/nixos/modules/services/continuous-integration/github-runner/service.nix index fccdcc116a21..ab2ebb7a498d 100644 --- a/nixos/modules/services/continuous-integration/github-runner/service.nix +++ b/nixos/modules/services/continuous-integration/github-runner/service.nix @@ -19,7 +19,9 @@ with lib; ]) ); - config.systemd.services = flip mapAttrs' config.services.github-runners (name: cfg: + config.systemd.services = + let enabledRunners = filterAttrs (_: cfg: cfg.enable) config.services.github-runners; + in (flip mapAttrs' enabledRunners (name: cfg: let svcName = "github-runner-${name}"; systemdDir = "github-runner/${name}"; @@ -151,9 +153,10 @@ with lib; # Always clean workDir find -H "$WORK_DIRECTORY" -mindepth 1 -delete ''; - configureRunner = writeScript "configure" '' + configureRunner = writeScript "configure" /*bash*/'' if [[ -e "${newConfigTokenPath}" ]]; then echo "Configuring GitHub Actions Runner" + # shellcheck disable=SC2054 # don't complain about commas in --labels args=( --unattended --disableupdate @@ -295,5 +298,5 @@ with lib; cfg.serviceOverrides ]; } - ); + )); } diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix index b516c3d6192c..189aaf86dd2d 100644 --- a/nixos/modules/services/continuous-integration/hydra/default.nix +++ b/nixos/modules/services/continuous-integration/hydra/default.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.hydra; @@ -18,10 +15,9 @@ let env = { NIX_REMOTE = "daemon"; - SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; # Remove in 16.03 PGPASSFILE = "${baseDir}/pgpass"; - NIX_REMOTE_SYSTEMS = concatStringsSep ":" cfg.buildMachinesFiles; - } // optionalAttrs (cfg.smtpHost != null) { + NIX_REMOTE_SYSTEMS = lib.concatStringsSep ":" cfg.buildMachinesFiles; + } // lib.optionalAttrs (cfg.smtpHost != null) { EMAIL_SENDER_TRANSPORT = "SMTP"; EMAIL_SENDER_TRANSPORT_host = cfg.smtpHost; } // hydraEnv // cfg.extraEnv; @@ -31,7 +27,7 @@ let XDG_CACHE_HOME = "${baseDir}/www/.cache"; COLUMNS = "80"; PGPASSFILE = "${baseDir}/pgpass-www"; # grrr - } // (optionalAttrs cfg.debugServer { DBIC_TRACE = "1"; }); + } // (lib.optionalAttrs cfg.debugServer { DBIC_TRACE = "1"; }); localDB = "dbi:Pg:dbname=hydra;user=hydra;"; @@ -39,7 +35,7 @@ let hydra-package = let - makeWrapperArgs = concatStringsSep " " (mapAttrsToList (key: value: "--set-default \"${key}\" \"${value}\"") hydraEnv); + makeWrapperArgs = lib.concatStringsSep " " (lib.mapAttrsToList (key: value: "--set-default \"${key}\" \"${value}\"") hydraEnv); in pkgs.buildEnv rec { name = "hydra-env"; nativeBuildInputs = [ pkgs.makeWrapper ]; @@ -51,7 +47,7 @@ let fi mkdir -p "$out/bin" - for path in ${concatStringsSep " " paths}; do + for path in ${lib.concatStringsSep " " paths}; do if [ -d "$path/bin" ]; then cd "$path/bin" for prg in *; do @@ -75,16 +71,16 @@ in services.hydra = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to run Hydra services. ''; }; - dbi = mkOption { - type = types.str; + dbi = lib.mkOption { + type = lib.types.str; default = localDB; example = "dbi:Pg:dbname=hydra;host=postgres.example.org;user=foo;"; description = '' @@ -97,17 +93,17 @@ in ''; }; - package = mkPackageOption pkgs "hydra_unstable" { }; + package = lib.mkPackageOption pkgs "hydra" { }; - hydraURL = mkOption { - type = types.str; + hydraURL = lib.mkOption { + type = lib.types.str; description = '' The base URL for the Hydra webserver instance. Used for links in emails. ''; }; - listenHost = mkOption { - type = types.str; + listenHost = lib.mkOption { + type = lib.types.str; default = "*"; example = "localhost"; description = '' @@ -116,39 +112,39 @@ in ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 3000; description = '' TCP port the web server should listen to. ''; }; - minimumDiskFree = mkOption { - type = types.int; + minimumDiskFree = lib.mkOption { + type = lib.types.int; default = 0; description = '' Threshold of minimum disk space (GiB) to determine if the queue runner should run or not. ''; }; - minimumDiskFreeEvaluator = mkOption { - type = types.int; + minimumDiskFreeEvaluator = lib.mkOption { + type = lib.types.int; default = 0; description = '' Threshold of minimum disk space (GiB) to determine if the evaluator should run or not. ''; }; - notificationSender = mkOption { - type = types.str; + notificationSender = lib.mkOption { + type = lib.types.str; description = '' Sender email address used for email notifications. ''; }; - smtpHost = mkOption { - type = types.nullOr types.str; + smtpHost = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "localhost"; description = '' @@ -156,73 +152,73 @@ in ''; }; - tracker = mkOption { - type = types.str; + tracker = lib.mkOption { + type = lib.types.str; default = ""; description = '' Piece of HTML that is included on all pages. ''; }; - logo = mkOption { - type = types.nullOr types.path; + logo = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to a file containing the logo of your Hydra instance. ''; }; - debugServer = mkOption { - type = types.bool; + debugServer = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to run the server in debug mode."; }; - maxServers = mkOption { - type = types.int; + maxServers = lib.mkOption { + type = lib.types.int; default = 25; description = "Maximum number of starman workers to spawn."; }; - minSpareServers = mkOption { - type = types.int; + minSpareServers = lib.mkOption { + type = lib.types.int; default = 4; description = "Minimum number of spare starman workers to keep."; }; - maxSpareServers = mkOption { - type = types.int; + maxSpareServers = lib.mkOption { + type = lib.types.int; default = 5; description = "Maximum number of spare starman workers to keep."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; description = "Extra lines for the Hydra configuration."; }; - extraEnv = mkOption { - type = types.attrsOf types.str; + extraEnv = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = {}; description = "Extra environment variables for Hydra."; }; - gcRootsDir = mkOption { - type = types.path; + gcRootsDir = lib.mkOption { + type = lib.types.path; default = "/nix/var/nix/gcroots/hydra"; description = "Directory that holds Hydra garbage collector roots."; }; - buildMachinesFiles = mkOption { - type = types.listOf types.path; - default = optional (config.nix.buildMachines != []) "/etc/nix/machines"; - defaultText = literalExpression ''optional (config.nix.buildMachines != []) "/etc/nix/machines"''; + buildMachinesFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = lib.optional (config.nix.buildMachines != []) "/etc/nix/machines"; + defaultText = lib.literalExpression ''lib.optional (config.nix.buildMachines != []) "/etc/nix/machines"''; example = [ "/etc/nix/machines" "/var/lib/hydra/provisioner/machines" ]; description = "List of files containing build machines."; }; - useSubstitutes = mkOption { - type = types.bool; + useSubstitutes = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to use binary caches for downloading store paths. Note that @@ -241,7 +237,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.maxServers != 0 && cfg.maxSpareServers != 0 && cfg.minSpareServers != 0; @@ -249,7 +245,7 @@ in } { assertion = cfg.minSpareServers < cfg.maxSpareServers; - message = "services.hydra.minSpareServers cannot be bigger than servives.hydra.maxSpareServers"; + message = "services.hydra.minSpareServers cannot be bigger than services.hydra.maxSpareServers"; } ]; @@ -287,7 +283,7 @@ in base_uri = ${cfg.hydraURL} notification_sender = ${cfg.notificationSender} max_servers = ${toString cfg.maxServers} - ${optionalString (cfg.logo != null) '' + ${lib.optionalString (cfg.logo != null) '' hydra_logo = ${cfg.logo} ''} gc_roots_dir = ${cfg.gcRootsDir} @@ -298,14 +294,14 @@ in environment.variables = hydraEnv; - nix.settings = mkMerge [ + nix.settings = lib.mkMerge [ { keep-outputs = true; keep-derivations = true; trusted-users = [ "hydra-queue-runner" ]; } - (mkIf (versionOlder (getVersion config.nix.package.out) "2.4pre") + (lib.mkIf (lib.versionOlder (lib.getVersion config.nix.package.out) "2.4pre") { # The default (`true') slows Nix down a lot since the build farm # has so many GC roots. @@ -314,10 +310,15 @@ in ) ]; + systemd.slices.system-hydra = { + description = "Hydra CI Server Slice"; + documentation = [ "file://${cfg.package}/share/doc/hydra/index.html" "https://nixos.org/hydra/manual/" ]; + }; + systemd.services.hydra-init = { wantedBy = [ "multi-user.target" ]; - requires = optional haveLocalDB "postgresql.service"; - after = optional haveLocalDB "postgresql.service"; + requires = lib.optional haveLocalDB "postgresql.service"; + after = lib.optional haveLocalDB "postgresql.service"; environment = env // { HYDRA_DBI = "${env.HYDRA_DBI};application_name=hydra-init"; }; @@ -340,7 +341,7 @@ in ${baseDir}/build-logs \ ${baseDir}/runcommand-logs - ${optionalString haveLocalDB '' + ${lib.optionalString haveLocalDB '' if ! [ -e ${baseDir}/.db-created ]; then runuser -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createuser hydra runuser -u ${config.services.postgresql.superUser} ${config.services.postgresql.package}/bin/createdb -- -O hydra hydra @@ -374,6 +375,7 @@ in serviceConfig.User = "hydra"; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; + serviceConfig.Slice = "system-hydra.slice"; }; systemd.services.hydra-server = @@ -388,10 +390,11 @@ in { ExecStart = "@${hydra-package}/bin/hydra-server hydra-server -f -h '${cfg.listenHost}' " + "-p ${toString cfg.port} --min_spare_servers ${toString cfg.minSpareServers} --max_spare_servers ${toString cfg.maxSpareServers} " - + "--max_servers ${toString cfg.maxServers} --max_requests 100 ${optionalString cfg.debugServer "-d"}"; + + "--max_servers ${toString cfg.maxServers} --max_requests 100 ${lib.optionalString cfg.debugServer "-d"}"; User = "hydra-www"; PermissionsStartOnly = true; Restart = "always"; + Slice = "system-hydra.slice"; }; }; @@ -411,6 +414,7 @@ in ExecStopPost = "${hydra-package}/bin/hydra-queue-runner --unlock"; User = "hydra-queue-runner"; Restart = "always"; + Slice = "system-hydra.slice"; # Ensure we can get core dumps. LimitCORE = "infinity"; @@ -433,6 +437,7 @@ in User = "hydra"; Restart = "always"; WorkingDirectory = baseDir; + Slice = "system-hydra.slice"; }; }; @@ -445,6 +450,7 @@ in serviceConfig = { ExecStart = "@${hydra-package}/bin/hydra-update-gc-roots hydra-update-gc-roots"; User = "hydra"; + Slice = "system-hydra.slice"; }; startAt = "2,14:15"; }; @@ -458,6 +464,7 @@ in serviceConfig = { ExecStart = "@${hydra-package}/bin/hydra-send-stats hydra-send-stats"; User = "hydra"; + Slice = "system-hydra.slice"; }; }; @@ -466,6 +473,7 @@ in requires = [ "hydra-init.service" ]; after = [ "hydra-init.service" ]; restartTriggers = [ hydraConf ]; + path = [ pkgs.zstd ]; environment = env // { PGPASSFILE = "${baseDir}/pgpass-queue-runner"; HYDRA_DBI = "${env.HYDRA_DBI};application_name=hydra-notify"; @@ -476,6 +484,7 @@ in User = "hydra-queue-runner"; Restart = "always"; RestartSec = 5; + Slice = "system-hydra.slice"; }; }; @@ -494,23 +503,32 @@ in fi ''; startAt = "*:0/5"; + serviceConfig.Slice = "system-hydra.slice"; }; # Periodically compress build logs. The queue runner compresses # logs automatically after a step finishes, but this doesn't work # if the queue runner is stopped prematurely. systemd.services.hydra-compress-logs = - { path = [ pkgs.bzip2 ]; + { path = [ pkgs.bzip2 pkgs.zstd ]; script = '' - find /var/lib/hydra/build-logs -type f -name "*.drv" -mtime +3 -size +0c | xargs -r bzip2 -v -f + set -eou pipefail + compression=$(sed -nr 's/compress_build_logs_compression = ()/\1/p' ${baseDir}/hydra.conf) + if [[ $compression == "" ]]; then + compression="bzip2" + elif [[ $compression == zstd ]]; then + compression="zstd --rm" + fi + find ${baseDir}/build-logs -type f -name "*.drv" -mtime +3 -size +0c | xargs -r "$compression" --force --quiet ''; startAt = "Sun 01:45"; + serviceConfig.Slice = "system-hydra.slice"; }; - services.postgresql.enable = mkIf haveLocalDB true; + services.postgresql.enable = lib.mkIf haveLocalDB true; - services.postgresql.identMap = optionalString haveLocalDB + services.postgresql.identMap = lib.optionalString haveLocalDB '' hydra-users hydra hydra hydra-users hydra-queue-runner hydra @@ -520,7 +538,7 @@ in hydra-users postgres postgres ''; - services.postgresql.authentication = optionalString haveLocalDB + services.postgresql.authentication = lib.optionalString haveLocalDB '' local hydra all ident map=hydra-users ''; diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index a23120739b7f..cba1a07ed789 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -1,38 +1,37 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.jenkins; jenkinsUrl = "http://${cfg.listenAddress}:${toString cfg.port}${cfg.prefix}"; in { options = { services.jenkins = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the jenkins continuous integration server. ''; }; - user = mkOption { + user = lib.mkOption { default = "jenkins"; - type = types.str; + type = lib.types.str; description = '' User the jenkins server should execute under. ''; }; - group = mkOption { + group = lib.mkOption { default = "jenkins"; - type = types.str; + type = lib.types.str; description = '' If the default user "jenkins" is configured then this is the primary group of that user. ''; }; - extraGroups = mkOption { - type = types.listOf types.str; + extraGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "wheel" "dialout" ]; description = '' @@ -40,38 +39,38 @@ in { ''; }; - home = mkOption { + home = lib.mkOption { default = "/var/lib/jenkins"; - type = types.path; + type = lib.types.path; description = '' The path to use as JENKINS_HOME. If the default user "jenkins" is configured then this is the home of the "jenkins" user. ''; }; - listenAddress = mkOption { + listenAddress = lib.mkOption { default = "0.0.0.0"; example = "localhost"; - type = types.str; + type = lib.types.str; description = '' Specifies the bind address on which the jenkins HTTP interface listens. The default is the wildcard address. ''; }; - port = mkOption { + port = lib.mkOption { default = 8080; - type = types.port; + type = lib.types.port; description = '' Specifies port number on which the jenkins HTTP interface listens. The default is 8080. ''; }; - prefix = mkOption { + prefix = lib.mkOption { default = ""; example = "/jenkins"; - type = types.str; + type = lib.types.str; description = '' Specifies a urlPrefix to use with jenkins. If the example /jenkins is given, the jenkins server will be @@ -79,20 +78,20 @@ in { ''; }; - package = mkPackageOption pkgs "jenkins" { }; + package = lib.mkPackageOption pkgs "jenkins" { }; - packages = mkOption { + packages = lib.mkOption { default = [ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]; - defaultText = literalExpression "[ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]"; - type = types.listOf types.package; + defaultText = lib.literalExpression "[ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]"; + type = lib.types.listOf lib.types.package; description = '' Packages to add to PATH for the jenkins process. ''; }; - environment = mkOption { + environment = lib.mkOption { default = { }; - type = with types; attrsOf str; + type = with lib.types; attrsOf str; description = '' Additional environment variables to be passed to the jenkins process. As a base environment, jenkins receives NIX_PATH from @@ -104,9 +103,9 @@ in { ''; }; - plugins = mkOption { + plugins = lib.mkOption { default = null; - type = types.nullOr (types.attrsOf types.package); + type = lib.types.nullOr (lib.types.attrsOf lib.types.package); description = '' A set of plugins to activate. Note that this will completely remove and replace any previously installed plugins. If you @@ -115,13 +114,13 @@ in { `null`. You can generate this set with a tool such as `jenkinsPlugins2nix`. ''; - example = literalExpression '' + example = lib.literalExpression '' import path/to/jenkinsPlugins2nix-generated-plugins.nix { inherit (pkgs) fetchurl stdenv; } ''; }; - extraOptions = mkOption { - type = types.listOf types.str; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "--debug=9" ]; description = '' @@ -129,8 +128,8 @@ in { ''; }; - extraJavaOptions = mkOption { - type = types.listOf types.str; + extraJavaOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "-Xmx80m" ]; description = '' @@ -138,8 +137,8 @@ in { ''; }; - withCLI = mkOption { - type = types.bool; + withCLI = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to make the CLI available. @@ -152,25 +151,25 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment = { # server references the dejavu fonts systemPackages = [ pkgs.dejavu_fonts - ] ++ optional cfg.withCLI cfg.package; + ] ++ lib.optional cfg.withCLI cfg.package; variables = {} - // optionalAttrs cfg.withCLI { + // lib.optionalAttrs cfg.withCLI { # Make it more convenient to use the `jenkins-cli`. JENKINS_URL = jenkinsUrl; }; }; - users.groups = optionalAttrs (cfg.group == "jenkins") { + users.groups = lib.optionalAttrs (cfg.group == "jenkins") { jenkins.gid = config.ids.gids.jenkins; }; - users.users = optionalAttrs (cfg.user == "jenkins") { + users.users = lib.optionalAttrs (cfg.user == "jenkins") { jenkins = { description = "jenkins user"; createHome = true; @@ -205,14 +204,14 @@ in { preStart = let replacePlugins = - optionalString (cfg.plugins != null) ( - let pluginCmds = lib.attrsets.mapAttrsToList + lib.optionalString (cfg.plugins != null) ( + let pluginCmds = lib.mapAttrsToList (n: v: "cp ${v} ${cfg.home}/plugins/${n}.jpi") cfg.plugins; in '' rm -r ${cfg.home}/plugins || true mkdir -p ${cfg.home}/plugins - ${lib.strings.concatStringsSep "\n" pluginCmds} + ${lib.concatStringsSep "\n" pluginCmds} ''); in '' rm -rf ${cfg.home}/war @@ -221,11 +220,11 @@ in { # For reference: https://wiki.jenkins.io/display/JENKINS/JenkinsLinuxStartupScript script = '' - ${pkgs.jdk17}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \ + ${pkgs.jdk17}/bin/java ${lib.concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \ --httpPort=${toString cfg.port} \ --prefix=${cfg.prefix} \ -Djava.awt.headless=true \ - ${concatStringsSep " " cfg.extraOptions} + ${lib.concatStringsSep " " cfg.extraOptions} ''; postStart = '' @@ -236,7 +235,7 @@ in { serviceConfig = { User = cfg.user; - StateDirectory = mkIf (hasPrefix "/var/lib/jenkins" cfg.home) "jenkins"; + StateDirectory = lib.mkIf (lib.hasPrefix "/var/lib/jenkins" cfg.home) "jenkins"; # For (possible) socket use RuntimeDirectory = "jenkins"; }; diff --git a/nixos/modules/services/continuous-integration/jenkins/job-builder.nix b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix index 6400da13d3a8..ccad25cb92a7 100644 --- a/nixos/modules/services/continuous-integration/jenkins/job-builder.nix +++ b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let jenkinsCfg = config.services.jenkins; cfg = config.services.jenkins.jobBuilder; @@ -9,7 +6,7 @@ let in { options = { services.jenkins.jobBuilder = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' the Jenkins Job Builder (JJB) service. It allows defining jobs for Jenkins in a declarative manner. @@ -24,17 +21,17 @@ in { ''; - accessUser = mkOption { + accessUser = lib.mkOption { default = "admin"; - type = types.str; + type = lib.types.str; description = '' User id in Jenkins used to reload config. ''; }; - accessToken = mkOption { + accessToken = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' User token in Jenkins used to reload config. WARNING: This token will be world readable in the Nix store. To keep @@ -42,10 +39,10 @@ in { ''; }; - accessTokenFile = mkOption { + accessTokenFile = lib.mkOption { default = "${config.services.jenkins.home}/secrets/initialAdminPassword"; - defaultText = literalExpression ''"''${config.services.jenkins.home}/secrets/initialAdminPassword"''; - type = types.str; + defaultText = lib.literalExpression ''"''${config.services.jenkins.home}/secrets/initialAdminPassword"''; + type = lib.types.str; example = "/run/keys/jenkins-job-builder-access-token"; description = '' File containing the API token for the {option}`accessUser` @@ -53,9 +50,9 @@ in { ''; }; - yamlJobs = mkOption { + yamlJobs = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; example = '' - job: name: jenkins-job-test-1 @@ -67,10 +64,10 @@ in { ''; }; - jsonJobs = mkOption { + jsonJobs = lib.mkOption { default = [ ]; - type = types.listOf types.str; - example = literalExpression '' + type = lib.types.listOf lib.types.str; + example = lib.literalExpression '' [ ''' [ { "job": @@ -87,10 +84,10 @@ in { ''; }; - nixJobs = mkOption { + nixJobs = lib.mkOption { default = [ ]; - type = types.listOf types.attrs; - example = literalExpression '' + type = lib.types.listOf lib.types.attrs; + example = lib.literalExpression '' [ { job = { name = "jenkins-job-test-3"; builders = [ @@ -110,7 +107,7 @@ in { }; }; - config = mkIf (jenkinsCfg.enable && cfg.enable) { + config = lib.mkIf (jenkinsCfg.enable && cfg.enable) { assertions = [ { assertion = if cfg.accessUser != "" @@ -213,7 +210,7 @@ in { # Create / update jobs mkdir -p ${jobBuilderOutputDir} - for inputFile in ${yamlJobsFile} ${concatStringsSep " " jsonJobsFiles}; do + for inputFile in ${yamlJobsFile} ${lib.concatStringsSep " " jsonJobsFiles}; do HOME="${jenkinsCfg.home}" "${pkgs.jenkins-job-builder}/bin/jenkins-jobs" --ignore-cache test --config-xml -o "${jobBuilderOutputDir}" "$inputFile" done @@ -237,7 +234,7 @@ in { jobdir="${jenkinsCfg.home}/$jenkinsjobname" rm -rf "$jobdir" done - '' + (optionalString (cfg.accessUser != "") reloadScript); + '' + (lib.optionalString (cfg.accessUser != "") reloadScript); serviceConfig = { Type = "oneshot"; User = jenkinsCfg.user; diff --git a/nixos/modules/services/continuous-integration/jenkins/slave.nix b/nixos/modules/services/continuous-integration/jenkins/slave.nix index c0599a65b480..d5a6b93a6cf8 100644 --- a/nixos/modules/services/continuous-integration/jenkins/slave.nix +++ b/nixos/modules/services/continuous-integration/jenkins/slave.nix @@ -1,6 +1,7 @@ { config, lib, pkgs, ... }: -with lib; + let + inherit (lib) mkIf mkOption types; cfg = config.services.jenkinsSlave; masterCfg = config.services.jenkins; in { @@ -47,16 +48,16 @@ in { ''; }; - javaPackage = mkPackageOption pkgs "jdk" { }; + javaPackage = lib.mkPackageOption pkgs "jdk" { }; }; }; config = mkIf (cfg.enable && !masterCfg.enable) { - users.groups = optionalAttrs (cfg.group == "jenkins") { + users.groups = lib.optionalAttrs (cfg.group == "jenkins") { jenkins.gid = config.ids.gids.jenkins; }; - users.users = optionalAttrs (cfg.user == "jenkins") { + users.users = lib.optionalAttrs (cfg.user == "jenkins") { jenkins = { description = "jenkins user"; createHome = true; diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix index e007bfce77ab..22c9cfd91823 100644 --- a/nixos/modules/services/databases/couchdb.nix +++ b/nixos/modules/services/databases/couchdb.nix @@ -1,7 +1,4 @@ { config, options, lib, pkgs, ... }: - -with lib; - let cfg = config.services.couchdb; opt = options.services.couchdb; @@ -11,7 +8,7 @@ let database_dir = ${cfg.databaseDir} uri_file = ${cfg.uriFile} view_index_dir = ${cfg.viewIndexDir} - '' + (optionalString (cfg.adminPass != null) '' + '' + (lib.optionalString (cfg.adminPass != null) '' [admins] ${cfg.adminUser} = ${cfg.adminPass} '' + '' @@ -34,12 +31,12 @@ in { services.couchdb = { - enable = mkEnableOption "CouchDB Server"; + enable = lib.mkEnableOption "CouchDB Server"; - package = mkPackageOption pkgs "couchdb3" { }; + package = lib.mkPackageOption pkgs "couchdb3" { }; - adminUser = mkOption { - type = types.str; + adminUser = lib.mkOption { + type = lib.types.str; default = "admin"; description = '' Couchdb (i.e. fauxton) account with permission for all dbs and @@ -47,8 +44,8 @@ in { ''; }; - adminPass = mkOption { - type = types.nullOr types.str; + adminPass = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Couchdb (i.e. fauxton) account with permission for all dbs and @@ -56,16 +53,16 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "couchdb"; description = '' User account under which couchdb runs. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "couchdb"; description = '' Group account under which couchdb runs. @@ -74,8 +71,8 @@ in { # couchdb options: https://docs.couchdb.org/en/latest/config/index.html - databaseDir = mkOption { - type = types.path; + databaseDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/couchdb"; description = '' Specifies location of CouchDB database files (*.couch named). This @@ -84,8 +81,8 @@ in { ''; }; - uriFile = mkOption { - type = types.path; + uriFile = lib.mkOption { + type = lib.types.path; default = "/run/couchdb/couchdb.uri"; description = '' This file contains the full URI that can be used to access this @@ -96,8 +93,8 @@ in { ''; }; - viewIndexDir = mkOption { - type = types.path; + viewIndexDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/couchdb"; description = '' Specifies location of CouchDB view index files. This location should @@ -106,49 +103,49 @@ in { ''; }; - bindAddress = mkOption { - type = types.str; + bindAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Defines the IP address by which CouchDB will be accessible. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5984; description = '' Defined the port number to listen. ''; }; - logFile = mkOption { - type = types.path; + logFile = lib.mkOption { + type = lib.types.path; default = "/var/log/couchdb.log"; description = '' Specifies the location of file for logging output. ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra configuration. Overrides any other configuration. ''; }; - argsFile = mkOption { - type = types.path; + argsFile = lib.mkOption { + type = lib.types.path; default = "${cfg.package}/etc/vm.args"; - defaultText = literalExpression ''"config.${opt.package}/etc/vm.args"''; + defaultText = lib.literalExpression ''"config.${opt.package}/etc/vm.args"''; description = '' vm.args configuration. Overrides Couchdb's Erlang VM parameters file. ''; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; description = '' Configuration file for persisting runtime changes. File needs to be readable and writable from couchdb user/group. @@ -161,11 +158,11 @@ in { ###### implementation - config = mkIf config.services.couchdb.enable { + config = lib.mkIf config.services.couchdb.enable { environment.systemPackages = [ cfg.package ]; - services.couchdb.configFile = mkDefault "/var/lib/couchdb/local.ini"; + services.couchdb.configFile = lib.mkDefault "/var/lib/couchdb/local.ini"; systemd.tmpfiles.rules = [ "d '${dirOf cfg.uriFile}' - ${cfg.user} ${cfg.group} - -" diff --git a/nixos/modules/services/databases/dgraph.nix b/nixos/modules/services/databases/dgraph.nix index 00a11d6b686e..20bc56df85a4 100644 --- a/nixos/modules/services/databases/dgraph.nix +++ b/nixos/modules/services/databases/dgraph.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.dgraph; settingsFormat = pkgs.formats.json {}; @@ -53,11 +50,11 @@ in { options = { services.dgraph = { - enable = mkEnableOption "Dgraph native GraphQL database with a graph backend"; + enable = lib.mkEnableOption "Dgraph native GraphQL database with a graph backend"; package = lib.mkPackageOption pkgs "dgraph" { }; - settings = mkOption { + settings = lib.mkOption { type = settingsFormat.type; default = {}; description = '' @@ -66,15 +63,15 @@ in }; alpha = { - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' The host which dgraph alpha will be run on. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 7080; description = '' The port which to run dgraph alpha on. @@ -84,15 +81,15 @@ in }; zero = { - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' The host which dgraph zero will be run on. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5080; description = '' The port which to run dgraph zero on. @@ -103,9 +100,9 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.dgraph.settings = { - badger.compression = mkDefault "zstd:3"; + badger.compression = lib.mkDefault "zstd:3"; }; systemd.services.dgraph-zero = { diff --git a/nixos/modules/services/databases/dragonflydb.nix b/nixos/modules/services/databases/dragonflydb.nix index 220605c8b475..9024b584abc3 100644 --- a/nixos/modules/services/databases/dragonflydb.nix +++ b/nixos/modules/services/databases/dragonflydb.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dragonflydb; dragonflydb = pkgs.dragonflydb; @@ -25,22 +22,22 @@ in options = { services.dragonflydb = { - enable = mkEnableOption "DragonflyDB"; + enable = lib.mkEnableOption "DragonflyDB"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "dragonfly"; description = "The user to run DragonflyDB as"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 6379; description = "The TCP port to accept connections."; }; - bind = mkOption { - type = with types; nullOr str; + bind = lib.mkOption { + type = with lib.types; nullOr str; default = "127.0.0.1"; description = '' The IP interface to bind to. @@ -48,15 +45,15 @@ in ''; }; - requirePass = mkOption { - type = with types; nullOr str; + requirePass = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Password for database"; example = "letmein!"; }; - maxMemory = mkOption { - type = with types; nullOr ints.unsigned; + maxMemory = lib.mkOption { + type = with lib.types; nullOr ints.unsigned; default = null; description = '' The maximum amount of memory to use for storage (in bytes). @@ -64,8 +61,8 @@ in ''; }; - memcachePort = mkOption { - type = with types; nullOr port; + memcachePort = lib.mkOption { + type = with lib.types; nullOr port; default = null; description = '' To enable memcached compatible API on this port. @@ -73,8 +70,8 @@ in ''; }; - keysOutputLimit = mkOption { - type = types.ints.unsigned; + keysOutputLimit = lib.mkOption { + type = lib.types.ints.unsigned; default = 8192; description = '' Maximum number of returned keys in keys command. @@ -83,14 +80,14 @@ in ''; }; - dbNum = mkOption { - type = with types; nullOr ints.unsigned; + dbNum = lib.mkOption { + type = with lib.types; nullOr ints.unsigned; default = null; description = "Maximum number of supported databases for `select`"; }; - cacheMode = mkOption { - type = with types; nullOr bool; + cacheMode = lib.mkOption { + type = with lib.types; nullOr bool; default = null; description = '' Once this mode is on, Dragonfly will evict items least likely to be stumbled @@ -102,14 +99,14 @@ in ###### implementation - config = mkIf config.services.dragonflydb.enable { + config = lib.mkIf config.services.dragonflydb.enable { - users.users = optionalAttrs (cfg.user == "dragonfly") { + users.users = lib.optionalAttrs (cfg.user == "dragonfly") { dragonfly.description = "DragonflyDB server user"; dragonfly.isSystemUser = true; dragonfly.group = "dragonfly"; }; - users.groups = optionalAttrs (cfg.user == "dragonfly") { dragonfly = { }; }; + users.groups = lib.optionalAttrs (cfg.user == "dragonfly") { dragonfly = { }; }; environment.systemPackages = [ dragonflydb ]; @@ -120,7 +117,7 @@ in after = [ "network.target" ]; serviceConfig = { - ExecStart = "${dragonflydb}/bin/dragonfly --alsologtostderr ${builtins.concatStringsSep " " (attrsets.mapAttrsToList (n: v: "--${n} ${strings.escapeShellArg v}") settings)}"; + ExecStart = "${dragonflydb}/bin/dragonfly --alsologtostderr ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "--${n} ${lib.escapeShellArg v}") settings)}"; User = cfg.user; diff --git a/nixos/modules/services/databases/etcd.nix b/nixos/modules/services/databases/etcd.nix index ebc905ad08f6..b10fdb801c50 100644 --- a/nixos/modules/services/databases/etcd.nix +++ b/nixos/modules/services/databases/etcd.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.etcd; opt = options.services.etcd; @@ -9,98 +6,98 @@ let in { options.services.etcd = { - enable = mkOption { + enable = lib.mkOption { description = "Whether to enable etcd."; default = false; - type = types.bool; + type = lib.types.bool; }; - package = mkPackageOption pkgs "etcd" { }; + package = lib.mkPackageOption pkgs "etcd" { }; - name = mkOption { + name = lib.mkOption { description = "Etcd unique node name."; default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; - type = types.str; + defaultText = lib.literalExpression "config.networking.hostName"; + type = lib.types.str; }; - advertiseClientUrls = mkOption { + advertiseClientUrls = lib.mkOption { description = "Etcd list of this member's client URLs to advertise to the rest of the cluster."; default = cfg.listenClientUrls; - defaultText = literalExpression "config.${opt.listenClientUrls}"; - type = types.listOf types.str; + defaultText = lib.literalExpression "config.${opt.listenClientUrls}"; + type = lib.types.listOf lib.types.str; }; - listenClientUrls = mkOption { + listenClientUrls = lib.mkOption { description = "Etcd list of URLs to listen on for client traffic."; default = ["http://127.0.0.1:2379"]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; }; - listenPeerUrls = mkOption { + listenPeerUrls = lib.mkOption { description = "Etcd list of URLs to listen on for peer traffic."; default = ["http://127.0.0.1:2380"]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; }; - initialAdvertisePeerUrls = mkOption { + initialAdvertisePeerUrls = lib.mkOption { description = "Etcd list of this member's peer URLs to advertise to rest of the cluster."; default = cfg.listenPeerUrls; - defaultText = literalExpression "config.${opt.listenPeerUrls}"; - type = types.listOf types.str; + defaultText = lib.literalExpression "config.${opt.listenPeerUrls}"; + type = lib.types.listOf lib.types.str; }; - initialCluster = mkOption { + initialCluster = lib.mkOption { description = "Etcd initial cluster configuration for bootstrapping."; default = ["${cfg.name}=http://127.0.0.1:2380"]; - defaultText = literalExpression ''["''${config.${opt.name}}=http://127.0.0.1:2380"]''; - type = types.listOf types.str; + defaultText = lib.literalExpression ''["''${config.${opt.name}}=http://127.0.0.1:2380"]''; + type = lib.types.listOf lib.types.str; }; - initialClusterState = mkOption { + initialClusterState = lib.mkOption { description = "Etcd initial cluster configuration for bootstrapping."; default = "new"; - type = types.enum ["new" "existing"]; + type = lib.types.enum ["new" "existing"]; }; - initialClusterToken = mkOption { + initialClusterToken = lib.mkOption { description = "Etcd initial cluster token for etcd cluster during bootstrap."; default = "etcd-cluster"; - type = types.str; + type = lib.types.str; }; - discovery = mkOption { + discovery = lib.mkOption { description = "Etcd discovery url"; default = ""; - type = types.str; + type = lib.types.str; }; - clientCertAuth = mkOption { + clientCertAuth = lib.mkOption { description = "Whether to use certs for client authentication"; default = false; - type = types.bool; + type = lib.types.bool; }; - trustedCaFile = mkOption { + trustedCaFile = lib.mkOption { description = "Certificate authority file to use for clients"; default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; }; - certFile = mkOption { + certFile = lib.mkOption { description = "Cert file to use for clients"; default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; }; - keyFile = mkOption { + keyFile = lib.mkOption { description = "Key file to use for clients"; default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open etcd ports in the firewall. @@ -110,41 +107,41 @@ in { ''; }; - peerCertFile = mkOption { + peerCertFile = lib.mkOption { description = "Cert file to use for peer to peer communication"; default = cfg.certFile; - defaultText = literalExpression "config.${opt.certFile}"; - type = types.nullOr types.path; + defaultText = lib.literalExpression "config.${opt.certFile}"; + type = lib.types.nullOr lib.types.path; }; - peerKeyFile = mkOption { + peerKeyFile = lib.mkOption { description = "Key file to use for peer to peer communication"; default = cfg.keyFile; - defaultText = literalExpression "config.${opt.keyFile}"; - type = types.nullOr types.path; + defaultText = lib.literalExpression "config.${opt.keyFile}"; + type = lib.types.nullOr lib.types.path; }; - peerTrustedCaFile = mkOption { + peerTrustedCaFile = lib.mkOption { description = "Certificate authority file to use for peer to peer communication"; default = cfg.trustedCaFile; - defaultText = literalExpression "config.${opt.trustedCaFile}"; - type = types.nullOr types.path; + defaultText = lib.literalExpression "config.${opt.trustedCaFile}"; + type = lib.types.nullOr lib.types.path; }; - peerClientCertAuth = mkOption { + peerClientCertAuth = lib.mkOption { description = "Whether to check all incoming peer requests from the cluster for valid client certificates signed by the supplied CA"; default = false; - type = types.bool; + type = lib.types.bool; }; - extraConf = mkOption { + extraConf = lib.mkOption { description = '' Etcd extra configuration. See ''; - type = types.attrsOf types.str; + type = lib.types.attrsOf lib.types.str; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { "CORS" = "*"; "NAME" = "default-name"; @@ -155,14 +152,14 @@ in { ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/etcd"; description = "Etcd data directory."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.settings."10-etcd".${cfg.dataDir}.d = { user = "etcd"; mode = "0700"; @@ -176,14 +173,14 @@ in { wants = [ "network-online.target" ] ++ lib.optional config.networking.firewall.enable "firewall.service"; - environment = (filterAttrs (n: v: v != null) { + environment = (lib.filterAttrs (n: v: v != null) { ETCD_NAME = cfg.name; ETCD_DISCOVERY = cfg.discovery; ETCD_DATA_DIR = cfg.dataDir; - ETCD_ADVERTISE_CLIENT_URLS = concatStringsSep "," cfg.advertiseClientUrls; - ETCD_LISTEN_CLIENT_URLS = concatStringsSep "," cfg.listenClientUrls; - ETCD_LISTEN_PEER_URLS = concatStringsSep "," cfg.listenPeerUrls; - ETCD_INITIAL_ADVERTISE_PEER_URLS = concatStringsSep "," cfg.initialAdvertisePeerUrls; + ETCD_ADVERTISE_CLIENT_URLS = lib.concatStringsSep "," cfg.advertiseClientUrls; + ETCD_LISTEN_CLIENT_URLS = lib.concatStringsSep "," cfg.listenClientUrls; + ETCD_LISTEN_PEER_URLS = lib.concatStringsSep "," cfg.listenPeerUrls; + ETCD_INITIAL_ADVERTISE_PEER_URLS = lib.concatStringsSep "," cfg.initialAdvertisePeerUrls; ETCD_PEER_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth; ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile; ETCD_PEER_CERT_FILE = cfg.peerCertFile; @@ -192,11 +189,11 @@ in { ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile; ETCD_CERT_FILE = cfg.certFile; ETCD_KEY_FILE = cfg.keyFile; - }) // (optionalAttrs (cfg.discovery == ""){ - ETCD_INITIAL_CLUSTER = concatStringsSep "," cfg.initialCluster; + }) // (lib.optionalAttrs (cfg.discovery == ""){ + ETCD_INITIAL_CLUSTER = lib.concatStringsSep "," cfg.initialCluster; ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState; ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken; - }) // (mapAttrs' (n: v: nameValuePair "ETCD_${n}" v) cfg.extraConf); + }) // (lib.mapAttrs' (n: v: lib.nameValuePair "ETCD_${n}" v) cfg.extraConf); unitConfig = { Documentation = "https://github.com/coreos/etcd"; diff --git a/nixos/modules/services/databases/ferretdb.nix b/nixos/modules/services/databases/ferretdb.nix index ab55e22bf214..a7e3fa81c48f 100644 --- a/nixos/modules/services/databases/ferretdb.nix +++ b/nixos/modules/services/databases/ferretdb.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.ferretdb; in @@ -11,11 +8,11 @@ in options = { services.ferretdb = { - enable = mkEnableOption "FerretDB, an Open Source MongoDB alternative"; + enable = lib.mkEnableOption "FerretDB, an Open Source MongoDB alternative"; - package = mkOption { - type = types.package; - example = literalExpression "pkgs.ferretdb"; + package = lib.mkOption { + type = lib.types.package; + example = lib.literalExpression "pkgs.ferretdb"; default = pkgs.ferretdb; defaultText = "pkgs.ferretdb"; description = "FerretDB package to use."; @@ -37,7 +34,7 @@ in }; }; - config = mkIf cfg.enable + config = lib.mkIf cfg.enable { services.ferretdb.settings = { @@ -76,4 +73,3 @@ in }; }; } - diff --git a/nixos/modules/services/databases/firebird.nix b/nixos/modules/services/databases/firebird.nix index 17606218b633..4b2b34ae7b1d 100644 --- a/nixos/modules/services/databases/firebird.nix +++ b/nixos/modules/services/databases/firebird.nix @@ -18,9 +18,6 @@ # however there are no strong reasons to prefer this or the other one AFAIK # Eg superserver is said to be most efficiently using resources according to # https://www.firebirdsql.org/manual/qsg25-classic-or-super.html - -with lib; - let cfg = config.services.firebird; @@ -40,34 +37,34 @@ in services.firebird = { - enable = mkEnableOption "the Firebird super server"; + enable = lib.mkEnableOption "the Firebird super server"; - package = mkPackageOption pkgs "firebird" { + package = lib.mkPackageOption pkgs "firebird" { example = "firebird_3"; extraDescription = '' For SuperServer use override: `pkgs.firebird_3.override { superServer = true; };` ''; }; - port = mkOption { + port = lib.mkOption { default = 3050; - type = types.port; + type = lib.types.port; description = '' Port Firebird uses. ''; }; - user = mkOption { + user = lib.mkOption { default = "firebird"; - type = types.str; + type = lib.types.str; description = '' User account under which firebird runs. ''; }; - baseDir = mkOption { + baseDir = lib.mkOption { default = "/var/lib/firebird"; - type = types.str; + type = lib.types.str; description = '' Location containing data/ and system/ directories. data/ stores the databases, system/ stores the password database security2.fdb. @@ -81,7 +78,7 @@ in ###### implementation - config = mkIf config.services.firebird.enable { + config = lib.mkIf config.services.firebird.enable { environment.systemPackages = [cfg.package]; diff --git a/nixos/modules/services/databases/foundationdb.nix b/nixos/modules/services/databases/foundationdb.nix index 670a149ea5e7..8fc35474b39c 100644 --- a/nixos/modules/services/databases/foundationdb.nix +++ b/nixos/modules/services/databases/foundationdb.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.foundationdb; pkg = cfg.package; @@ -10,10 +7,10 @@ let initialIpAddr = if (cfg.publicAddress != "auto") then cfg.publicAddress else "127.0.0.1"; fdbServers = n: - concatStringsSep "\n" (map (x: "[fdbserver.${toString (x+cfg.listenPortStart)}]") (range 0 (n - 1))); + lib.concatStringsSep "\n" (map (x: "[fdbserver.${toString (x+cfg.listenPortStart)}]") (lib.range 0 (n - 1))); backupAgents = n: - concatStringsSep "\n" (map (x: "[backup_agent.${toString x}]") (range 1 n)); + lib.concatStringsSep "\n" (map (x: "[backup_agent.${toString x}]") (lib.range 1 n)); configFile = pkgs.writeText "foundationdb.conf" '' [general] @@ -32,25 +29,25 @@ let logdir = ${cfg.logDir} logsize = ${cfg.logSize} maxlogssize = ${cfg.maxLogSize} - ${optionalString (cfg.class != null) "class = ${cfg.class}"} + ${lib.optionalString (cfg.class != null) "class = ${cfg.class}"} memory = ${cfg.memory} storage_memory = ${cfg.storageMemory} - ${optionalString (lib.versionAtLeast cfg.package.version "6.1") '' + ${lib.optionalString (lib.versionAtLeast cfg.package.version "6.1") '' trace_format = ${cfg.traceFormat} ''} - ${optionalString (cfg.tls != null) '' + ${lib.optionalString (cfg.tls != null) '' tls_plugin = ${pkg}/libexec/plugins/FDBLibTLS.so tls_certificate_file = ${cfg.tls.certificate} tls_key_file = ${cfg.tls.key} tls_verify_peers = ${cfg.tls.allowedPeers} ''} - ${optionalString (cfg.locality.machineId != null) "locality_machineid=${cfg.locality.machineId}"} - ${optionalString (cfg.locality.zoneId != null) "locality_zoneid=${cfg.locality.zoneId}"} - ${optionalString (cfg.locality.datacenterId != null) "locality_dcid=${cfg.locality.datacenterId}"} - ${optionalString (cfg.locality.dataHall != null) "locality_data_hall=${cfg.locality.dataHall}"} + ${lib.optionalString (cfg.locality.machineId != null) "locality_machineid=${cfg.locality.machineId}"} + ${lib.optionalString (cfg.locality.zoneId != null) "locality_zoneid=${cfg.locality.zoneId}"} + ${lib.optionalString (cfg.locality.datacenterId != null) "locality_dcid=${cfg.locality.datacenterId}"} + ${lib.optionalString (cfg.locality.dataHall != null) "locality_data_hall=${cfg.locality.dataHall}"} ${fdbServers cfg.serverProcesses} @@ -62,30 +59,30 @@ in { options.services.foundationdb = { - enable = mkEnableOption "FoundationDB Server"; + enable = lib.mkEnableOption "FoundationDB Server"; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; description = '' The FoundationDB package to use for this server. This must be specified by the user in order to ensure migrations and upgrades are controlled appropriately. ''; }; - publicAddress = mkOption { - type = types.str; + publicAddress = lib.mkOption { + type = lib.types.str; default = "auto"; description = "Publicly visible IP address of the process. Port is determined by process ID"; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "public"; description = "Publicly visible IP address of the process. Port is determined by process ID"; }; - listenPortStart = mkOption { - type = types.int; + listenPortStart = lib.mkOption { + type = lib.types.int; default = 4500; description = '' Starting port number for database listening sockets. Every FDB process binds to a @@ -94,8 +91,8 @@ in ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open the firewall ports corresponding to FoundationDB processes and coordinators @@ -103,44 +100,44 @@ in ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/foundationdb"; description = "Data directory. All cluster data will be put under here."; }; - logDir = mkOption { - type = types.path; + logDir = lib.mkOption { + type = lib.types.path; default = "/var/log/foundationdb"; description = "Log directory."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "foundationdb"; description = "User account under which FoundationDB runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "foundationdb"; description = "Group account under which FoundationDB runs."; }; - class = mkOption { - type = types.nullOr (types.enum [ "storage" "transaction" "stateless" ]); + class = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "storage" "transaction" "stateless" ]); default = null; description = "Process class"; }; - restartDelay = mkOption { - type = types.int; + restartDelay = lib.mkOption { + type = lib.types.int; default = 10; description = "Number of seconds to wait before restarting servers."; }; - logSize = mkOption { - type = types.str; + logSize = lib.mkOption { + type = lib.types.str; default = "10MiB"; description = '' Roll over to a new log file after the current log file @@ -148,8 +145,8 @@ in ''; }; - maxLogSize = mkOption { - type = types.str; + maxLogSize = lib.mkOption { + type = lib.types.str; default = "100MiB"; description = '' Delete the oldest log file when the total size of all log @@ -158,20 +155,20 @@ in ''; }; - serverProcesses = mkOption { - type = types.int; + serverProcesses = lib.mkOption { + type = lib.types.int; default = 1; description = "Number of fdbserver processes to run."; }; - backupProcesses = mkOption { - type = types.int; + backupProcesses = lib.mkOption { + type = lib.types.int; default = 1; description = "Number of backup_agent processes to run for snapshots."; }; - memory = mkOption { - type = types.str; + memory = lib.mkOption { + type = lib.types.str; default = "8GiB"; description = '' Maximum memory used by the process. The default value is @@ -192,8 +189,8 @@ in ''; }; - storageMemory = mkOption { - type = types.str; + storageMemory = lib.mkOption { + type = lib.types.str; default = "1GiB"; description = '' Maximum memory used for data storage. The default value is @@ -208,29 +205,29 @@ in ''; }; - tls = mkOption { + tls = lib.mkOption { default = null; description = '' FoundationDB Transport Security Layer (TLS) settings. ''; - type = types.nullOr (types.submodule ({ + type = lib.types.nullOr (lib.types.submodule ({ options = { - certificate = mkOption { - type = types.str; + certificate = lib.mkOption { + type = lib.types.str; description = '' Path to the TLS certificate file. This certificate will be offered to, and may be verified by, clients. ''; }; - key = mkOption { - type = types.str; + key = lib.mkOption { + type = lib.types.str; description = "Private key file for the certificate."; }; - allowedPeers = mkOption { - type = types.str; + allowedPeers = lib.mkOption { + type = lib.types.str; default = "Check.Valid=1,Check.Unexpired=1"; description = '' "Peer verification string". This may be used to adjust which TLS @@ -245,7 +242,7 @@ in })); }; - locality = mkOption { + locality = lib.mkOption { default = { machineId = null; zoneId = null; @@ -257,11 +254,11 @@ in FoundationDB locality settings. ''; - type = types.submodule ({ + type = lib.types.submodule ({ options = { - machineId = mkOption { + machineId = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' Machine identifier key. All processes on a machine should share a unique id. By default, processes on a machine determine a unique id to share. @@ -269,9 +266,9 @@ in ''; }; - zoneId = mkOption { + zoneId = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' Zone identifier key. Processes that share a zone id are considered non-unique for the purposes of data replication. @@ -279,9 +276,9 @@ in ''; }; - datacenterId = mkOption { + datacenterId = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' Data center identifier key. All processes physically located in a data center should share the id. If you are depending on data @@ -289,9 +286,9 @@ in ''; }; - dataHall = mkOption { + dataHall = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' Data hall identifier key. All processes physically located in a data hall should share the id. If you are depending on data @@ -302,9 +299,9 @@ in }); }; - extraReadWritePaths = mkOption { + extraReadWritePaths = lib.mkOption { default = [ ]; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; description = '' An extra set of filesystem paths that FoundationDB can read to and write from. By default, FoundationDB runs under a heavily @@ -316,20 +313,20 @@ in ''; }; - pidfile = mkOption { - type = types.path; + pidfile = lib.mkOption { + type = lib.types.path; default = "/run/foundationdb.pid"; description = "Path to pidfile for fdbmonitor."; }; - traceFormat = mkOption { - type = types.enum [ "xml" "json" ]; + traceFormat = lib.mkOption { + type = lib.types.enum [ "xml" "json" ]; default = "xml"; description = "Trace logging format."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = lib.versionOlder cfg.package.version "6.1" -> cfg.traceFormat == "xml"; message = '' @@ -341,7 +338,7 @@ in environment.systemPackages = [ pkg ]; - users.users = optionalAttrs (cfg.user == "foundationdb") { + users.users = lib.optionalAttrs (cfg.user == "foundationdb") { foundationdb = { description = "FoundationDB User"; uid = config.ids.uids.foundationdb; @@ -349,11 +346,11 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "foundationdb") { + users.groups = lib.optionalAttrs (cfg.group == "foundationdb") { foundationdb.gid = config.ids.gids.foundationdb; }; - networking.firewall.allowedTCPPortRanges = mkIf cfg.openFirewall + networking.firewall.allowedTCPPortRanges = lib.mkIf cfg.openFirewall [ { from = cfg.listenPortStart; to = (cfg.listenPortStart + cfg.serverProcesses) - 1; } diff --git a/nixos/modules/services/databases/hbase-standalone.nix b/nixos/modules/services/databases/hbase-standalone.nix index ac37e3932932..d3d2999eaeed 100644 --- a/nixos/modules/services/databases/hbase-standalone.nix +++ b/nixos/modules/services/databases/hbase-standalone.nix @@ -1,7 +1,4 @@ { config, options, lib, pkgs, ... }: - -with lib; - let cfg = config.services.hbase-standalone; opt = options.services.hbase-standalone; @@ -33,7 +30,7 @@ let in { imports = [ - (mkRenamedOptionModule [ "services" "hbase" ] [ "services" "hbase-standalone" ]) + (lib.mkRenamedOptionModule [ "services" "hbase" ] [ "services" "hbase-standalone" ]) ]; ###### interface @@ -41,31 +38,31 @@ in { options = { services.hbase-standalone = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' HBase master in standalone mode with embedded regionserver and zookeper. Do not use this configuration for production nor for evaluating HBase performance ''; - package = mkPackageOption pkgs "hbase" { }; + package = lib.mkPackageOption pkgs "hbase" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "hbase"; description = '' User account under which HBase runs. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "hbase"; description = '' Group account under which HBase runs. ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/hbase"; description = '' Specifies location of HBase database files. This location should be @@ -74,21 +71,21 @@ in { ''; }; - logDir = mkOption { - type = types.path; + logDir = lib.mkOption { + type = lib.types.path; default = "/var/log/hbase"; description = '' Specifies the location of HBase log files. ''; }; - settings = mkOption { + settings = lib.mkOption { type = with lib.types; attrsOf (oneOf [ str int bool ]); default = { "hbase.rootdir" = "file://${cfg.dataDir}/hbase"; "hbase.zookeeper.property.dataDir" = "${cfg.dataDir}/zookeeper"; }; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' { "hbase.rootdir" = "file://''${config.${opt.dataDir}}/hbase"; "hbase.zookeeper.property.dataDir" = "''${config.${opt.dataDir}}/zookeeper"; @@ -104,7 +101,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -" diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix index 6dd4ca3b71cd..9bc0b935d08f 100644 --- a/nixos/modules/services/databases/influxdb.nix +++ b/nixos/modules/services/databases/influxdb.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.influxdb; - configOptions = recursiveUpdate { + configOptions = lib.recursiveUpdate { meta = { bind-address = ":8088"; commit-timeout = "50ms"; @@ -110,36 +107,36 @@ in services.influxdb = { - enable = mkOption { + enable = lib.mkOption { default = false; description = "Whether to enable the influxdb server"; - type = types.bool; + type = lib.types.bool; }; - package = mkPackageOption pkgs "influxdb" { }; + package = lib.mkPackageOption pkgs "influxdb" { }; - user = mkOption { + user = lib.mkOption { default = "influxdb"; description = "User account under which influxdb runs"; - type = types.str; + type = lib.types.str; }; - group = mkOption { + group = lib.mkOption { default = "influxdb"; description = "Group under which influxdb runs"; - type = types.str; + type = lib.types.str; }; - dataDir = mkOption { + dataDir = lib.mkOption { default = "/var/db/influxdb"; description = "Data directory for influxd data files."; - type = types.path; + type = lib.types.path; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = {}; description = "Extra configuration options for influxdb"; - type = types.attrs; + type = lib.types.attrs; }; }; }; @@ -147,7 +144,7 @@ in ###### implementation - config = mkIf config.services.influxdb.enable { + config = lib.mkIf config.services.influxdb.enable { systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" @@ -166,16 +163,16 @@ in postStart = let scheme = if configOptions.http.https-enabled then "-k https" else "http"; - bindAddr = (ba: if hasPrefix ":" ba then "127.0.0.1${ba}" else "${ba}")(toString configOptions.http.bind-address); + bindAddr = (ba: if lib.hasPrefix ":" ba then "127.0.0.1${ba}" else "${ba}")(toString configOptions.http.bind-address); in - mkBefore '' + lib.mkBefore '' until ${pkgs.curl.bin}/bin/curl -s -o /dev/null ${scheme}://${bindAddr}/ping; do sleep 1; done ''; }; - users.users = optionalAttrs (cfg.user == "influxdb") { + users.users = lib.optionalAttrs (cfg.user == "influxdb") { influxdb = { uid = config.ids.uids.influxdb; group = "influxdb"; @@ -183,7 +180,7 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "influxdb") { + users.groups = lib.optionalAttrs (cfg.group == "influxdb") { influxdb.gid = config.ids.gids.influxdb; }; }; diff --git a/nixos/modules/services/databases/influxdb2.nix b/nixos/modules/services/databases/influxdb2.nix index a534cdfbe165..20a94c03994b 100644 --- a/nixos/modules/services/databases/influxdb2.nix +++ b/nixos/modules/services/databases/influxdb2.nix @@ -67,16 +67,16 @@ let inherit (cfg.provision) organizations users; }); - provisioningScript = pkgs.writeShellScript "post-start-provision" '' - set -euo pipefail - export INFLUX_HOST="http://"${escapeShellArg ( + influxHost = "http://${escapeShellArg ( if ! hasAttr "http-bind-address" cfg.settings || hasInfix "0.0.0.0" cfg.settings.http-bind-address then "localhost:8086" else cfg.settings.http-bind-address - )} + )}"; - # Wait for the influxdb server to come online + waitUntilServiceIsReady = pkgs.writeShellScript "wait-until-service-is-ready" '' + set -euo pipefail + export INFLUX_HOST=${influxHost} count=0 while ! influx ping &>/dev/null; do if [ "$count" -eq 300 ]; then @@ -92,6 +92,11 @@ let sleep 0.1 count=$((count++)) done + ''; + + provisioningScript = pkgs.writeShellScript "post-start-provision" '' + set -euo pipefail + export INFLUX_HOST=${influxHost} # Do the initial database setup. Pass /dev/null as configs-path to # avoid saving the token as the active config. @@ -433,6 +438,7 @@ in ZONEINFO = "${pkgs.tzdata}/share/zoneinfo"; }; serviceConfig = { + Type = "exec"; # When credentials are used with systemd before v257 this is necessary to make the service start reliably (see systemd/systemd#33953) ExecStart = "${cfg.package}/bin/influxd --bolt-path \${STATE_DIRECTORY}/influxd.bolt --engine-path \${STATE_DIRECTORY}/engine"; StateDirectory = "influxdb2"; User = "influxdb2"; @@ -447,11 +453,13 @@ in "admin-token:${cfg.provision.initialSetup.tokenFile}" ]; - ExecStartPost = mkIf cfg.provision.enable ( + ExecStartPost = [ + waitUntilServiceIsReady + ] ++ (lib.optionals cfg.provision.enable ( [provisioningScript] ++ # Only the restarter runs with elevated privileges optional anyAuthDefined "+${restarterScript}" - ); + )); }; path = [ diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index 4b2e83e71e20..d7c731def18a 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.mysql; @@ -9,7 +6,7 @@ let isMariaDB = lib.getName cfg.package == lib.getName pkgs.mariadb; isOracle = lib.getName cfg.package == lib.getName pkgs.mysql80; # Oracle MySQL has supported "notify" service type since 8.0 - hasNotify = isMariaDB || (isOracle && versionAtLeast cfg.package.version "8.0"); + hasNotify = isMariaDB || (isOracle && lib.versionAtLeast cfg.package.version "8.0"); mysqldOptions = "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${cfg.package}"; @@ -21,11 +18,11 @@ in { imports = [ - (mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") - (mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") - (mkRemovedOptionModule [ "services" "mysql" "extraOptions" ] "Use services.mysql.settings.mysqld instead.") - (mkRemovedOptionModule [ "services" "mysql" "bind" ] "Use services.mysql.settings.mysqld.bind-address instead.") - (mkRemovedOptionModule [ "services" "mysql" "port" ] "Use services.mysql.settings.mysqld.port instead.") + (lib.mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") + (lib.mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") + (lib.mkRemovedOptionModule [ "services" "mysql" "extraOptions" ] "Use services.mysql.settings.mysqld instead.") + (lib.mkRemovedOptionModule [ "services" "mysql" "bind" ] "Use services.mysql.settings.mysqld.bind-address instead.") + (lib.mkRemovedOptionModule [ "services" "mysql" "port" ] "Use services.mysql.settings.mysqld.port instead.") ]; ###### interface @@ -34,18 +31,18 @@ in services.mysql = { - enable = mkEnableOption "MySQL server"; + enable = lib.mkEnableOption "MySQL server"; - package = mkOption { - type = types.package; - example = literalExpression "pkgs.mariadb"; + package = lib.mkOption { + type = lib.types.package; + example = lib.literalExpression "pkgs.mariadb"; description = '' Which MySQL derivation to use. MariaDB packages are supported too. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "mysql"; description = '' User account under which MySQL runs. @@ -58,8 +55,8 @@ in ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "mysql"; description = '' Group account under which MySQL runs. @@ -72,8 +69,8 @@ in ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; example = "/var/lib/mysql"; description = '' The data directory for MySQL. @@ -85,8 +82,8 @@ in ''; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = configFile; defaultText = '' A configuration file automatically generated by NixOS. @@ -95,7 +92,7 @@ in Override the configuration file used by MySQL. By default, NixOS generates one automatically from {option}`services.mysql.settings`. ''; - example = literalExpression '' + example = lib.literalExpression '' pkgs.writeText "my.cnf" ''' [mysqld] datadir = /var/lib/mysql @@ -107,7 +104,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = {}; description = '' @@ -123,7 +120,7 @@ in `1`, or `0`. See the provided example below. ::: ''; - example = literalExpression '' + example = lib.literalExpression '' { mysqld = { key_buffer_size = "6G"; @@ -139,17 +136,17 @@ in ''; }; - initialDatabases = mkOption { - type = types.listOf (types.submodule { + initialDatabases = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; description = '' The name of the database to create. ''; }; - schema = mkOption { - type = types.nullOr types.path; + schema = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' The initial schema of the database; if null (the default), @@ -163,7 +160,7 @@ in List of database names and their initial schemas that should be used to create databases on the first startup of MySQL. The schema attribute is optional: If not specified, an empty database is created. ''; - example = literalExpression '' + example = lib.literalExpression '' [ { name = "foodatabase"; schema = ./foodatabase.sql; } { name = "bardatabase"; } @@ -171,14 +168,14 @@ in ''; }; - initialScript = mkOption { - type = types.nullOr types.path; + initialScript = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database."; }; - ensureDatabases = mkOption { - type = types.listOf types.str; + ensureDatabases = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Ensures that the specified databases exist. @@ -192,17 +189,17 @@ in ]; }; - ensureUsers = mkOption { - type = types.listOf (types.submodule { + ensureUsers = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; description = '' Name of the user to ensure. ''; }; - ensurePermissions = mkOption { - type = types.attrsOf types.str; + ensurePermissions = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = {}; description = '' Permissions to ensure for the user, specified as attribute set. @@ -216,7 +213,7 @@ in [GRANT syntax](https://mariadb.com/kb/en/library/grant/). The attributes are used as `GRANT ''${attrName} ON ''${attrValue}`. ''; - example = literalExpression '' + example = lib.literalExpression '' { "database.*" = "ALL PRIVILEGES"; "*.*" = "SELECT, LOCK TABLES"; @@ -234,7 +231,7 @@ in option is changed. This means that users created and permissions assigned once through this option or otherwise have to be removed manually. ''; - example = literalExpression '' + example = lib.literalExpression '' [ { name = "nextcloud"; @@ -253,40 +250,40 @@ in }; replication = { - role = mkOption { - type = types.enum [ "master" "slave" "none" ]; + role = lib.mkOption { + type = lib.types.enum [ "master" "slave" "none" ]; default = "none"; description = "Role of the MySQL server instance."; }; - serverId = mkOption { - type = types.int; + serverId = lib.mkOption { + type = lib.types.int; default = 1; description = "Id of the MySQL server instance. This number must be unique for each instance."; }; - masterHost = mkOption { - type = types.str; + masterHost = lib.mkOption { + type = lib.types.str; description = "Hostname of the MySQL master server."; }; - slaveHost = mkOption { - type = types.str; + slaveHost = lib.mkOption { + type = lib.types.str; description = "Hostname of the MySQL slave server."; }; - masterUser = mkOption { - type = types.str; + masterUser = lib.mkOption { + type = lib.types.str; description = "Username of the MySQL replication user."; }; - masterPassword = mkOption { - type = types.str; + masterPassword = lib.mkOption { + type = lib.types.str; description = "Password of the MySQL replication user."; }; - masterPort = mkOption { - type = types.port; + masterPort = lib.mkOption { + type = lib.types.port; default = 3306; description = "Port number on which the MySQL master server runs."; }; @@ -298,30 +295,30 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.mysql.dataDir = - mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" + lib.mkDefault (if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" else "/var/mysql"); - services.mysql.settings.mysqld = mkMerge [ + services.mysql.settings.mysqld = lib.mkMerge [ { datadir = cfg.dataDir; - port = mkDefault 3306; + port = lib.mkDefault 3306; } - (mkIf (cfg.replication.role == "master" || cfg.replication.role == "slave") { + (lib.mkIf (cfg.replication.role == "master" || cfg.replication.role == "slave") { log-bin = "mysql-bin-${toString cfg.replication.serverId}"; log-bin-index = "mysql-bin-${toString cfg.replication.serverId}.index"; relay-log = "mysql-relay-bin"; server-id = cfg.replication.serverId; binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; }) - (mkIf (!isMariaDB) { + (lib.mkIf (!isMariaDB) { plugin-load-add = "auth_socket.so"; }) ]; - users.users = optionalAttrs (cfg.user == "mysql") { + users.users = lib.optionalAttrs (cfg.user == "mysql") { mysql = { description = "MySQL server user"; group = cfg.group; @@ -329,7 +326,7 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "mysql") { + users.groups = lib.optionalAttrs (cfg.group == "mysql") { mysql.gid = config.ids.gids.mysql; }; @@ -380,7 +377,7 @@ in # The super user account to use on *first* run of MySQL server superUser = if isMariaDB then cfg.user else "root"; in '' - ${optionalString (!hasNotify) '' + ${lib.optionalString (!hasNotify) '' # Wait until the MySQL server is available for use while [ ! -e /run/mysqld/mysqld.sock ] do @@ -397,13 +394,13 @@ in echo "GRANT ALL PRIVILEGES ON *.* TO '${cfg.user}'@'localhost' WITH GRANT OPTION;" ) | ${cfg.package}/bin/mysql -u ${superUser} -N - ${concatMapStrings (database: '' + ${lib.concatMapStrings (database: '' # Create initial databases if ! test -e "${cfg.dataDir}/${database.name}"; then echo "Creating initial database: ${database.name}" ( echo 'create database `${database.name}`;' - ${optionalString (database.schema != null) '' + ${lib.optionalString (database.schema != null) '' echo 'use `${database.name}`;' # TODO: this silently falls through if database.schema does not exist, @@ -420,7 +417,7 @@ in fi '') cfg.initialDatabases} - ${optionalString (cfg.replication.role == "master") + ${lib.optionalString (cfg.replication.role == "master") '' # Set up the replication master @@ -431,7 +428,7 @@ in ) | ${cfg.package}/bin/mysql -u ${superUser} -N ''} - ${optionalString (cfg.replication.role == "slave") + ${lib.optionalString (cfg.replication.role == "slave") '' # Set up the replication slave @@ -441,7 +438,7 @@ in ) | ${cfg.package}/bin/mysql -u ${superUser} -N ''} - ${optionalString (cfg.initialScript != null) + ${lib.optionalString (cfg.initialScript != null) '' # Execute initial script # using toString to avoid copying the file to nix store if given as path instead of string, @@ -452,25 +449,25 @@ in rm ${cfg.dataDir}/mysql_init fi - ${optionalString (cfg.ensureDatabases != []) '' + ${lib.optionalString (cfg.ensureDatabases != []) '' ( - ${concatMapStrings (database: '' + ${lib.concatMapStrings (database: '' echo "CREATE DATABASE IF NOT EXISTS \`${database}\`;" '') cfg.ensureDatabases} ) | ${cfg.package}/bin/mysql -N ''} - ${concatMapStrings (user: + ${lib.concatMapStrings (user: '' ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};" - ${concatStringsSep "\n" (mapAttrsToList (database: permission: '' + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (database: permission: '' echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';" '') user.ensurePermissions)} ) | ${cfg.package}/bin/mysql -N '') cfg.ensureUsers} ''; - serviceConfig = mkMerge [ + serviceConfig = lib.mkMerge [ { Type = if hasNotify then "notify" else "simple"; Restart = "on-abort"; @@ -506,7 +503,7 @@ in # System Call Filtering SystemCallArchitectures = "native"; } - (mkIf (cfg.dataDir == "/var/lib/mysql") { + (lib.mkIf (cfg.dataDir == "/var/lib/mysql") { StateDirectory = "mysql"; StateDirectoryMode = "0700"; }) diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix index c3f1872e0822..c4e19a47ac7f 100644 --- a/nixos/modules/services/databases/neo4j.nix +++ b/nixos/modules/services/databases/neo4j.nix @@ -1,34 +1,31 @@ { config, options, lib, pkgs, ... }: - -with lib; - let cfg = config.services.neo4j; opt = options.services.neo4j; certDirOpt = options.services.neo4j.directories.certificates; - isDefaultPathOption = opt: isOption opt && opt.type == types.path && opt.highestPrio >= 1500; + isDefaultPathOption = opt: lib.isOption opt && opt.type == lib.types.path && opt.highestPrio >= 1500; - sslPolicies = mapAttrsToList ( + sslPolicies = lib.mapAttrsToList ( name: conf: '' - dbms.ssl.policy.${name}.allow_key_generation=${boolToString conf.allowKeyGeneration} + dbms.ssl.policy.${name}.allow_key_generation=${lib.boolToString conf.allowKeyGeneration} dbms.ssl.policy.${name}.base_directory=${conf.baseDirectory} - ${optionalString (conf.ciphers != null) '' - dbms.ssl.policy.${name}.ciphers=${concatStringsSep "," conf.ciphers} + ${lib.optionalString (conf.ciphers != null) '' + dbms.ssl.policy.${name}.ciphers=${lib.concatStringsSep "," conf.ciphers} ''} dbms.ssl.policy.${name}.client_auth=${conf.clientAuth} - ${if length (splitString "/" conf.privateKey) > 1 then + ${if lib.length (lib.splitString "/" conf.privateKey) > 1 then "dbms.ssl.policy.${name}.private_key=${conf.privateKey}" else "dbms.ssl.policy.${name}.private_key=${conf.baseDirectory}/${conf.privateKey}" } - ${if length (splitString "/" conf.privateKey) > 1 then + ${if lib.length (lib.splitString "/" conf.privateKey) > 1 then "dbms.ssl.policy.${name}.public_certificate=${conf.publicCertificate}" else "dbms.ssl.policy.${name}.public_certificate=${conf.baseDirectory}/${conf.publicCertificate}" } dbms.ssl.policy.${name}.revoked_dir=${conf.revokedDir} - dbms.ssl.policy.${name}.tls_versions=${concatStringsSep "," conf.tlsVersions} - dbms.ssl.policy.${name}.trust_all=${boolToString conf.trustAll} + dbms.ssl.policy.${name}.tls_versions=${lib.concatStringsSep "," conf.tlsVersions} + dbms.ssl.policy.${name}.trust_all=${lib.boolToString conf.trustAll} dbms.ssl.policy.${name}.trusted_dir=${conf.trustedDir} '' ) cfg.ssl.policies; @@ -36,8 +33,8 @@ let serverConfig = pkgs.writeText "neo4j.conf" '' # General server.default_listen_address=${cfg.defaultListenAddress} - server.databases.default_to_read_only=${boolToString cfg.readOnly} - ${optionalString (cfg.workerCount > 0) '' + server.databases.default_to_read_only=${lib.boolToString cfg.readOnly} + ${lib.optionalString (cfg.workerCount > 0) '' dbms.threads.worker_count=${toString cfg.workerCount} ''} @@ -45,7 +42,7 @@ let # dbms.directories.certificates=${cfg.directories.certificates} server.directories.plugins=${cfg.directories.plugins} server.directories.lib=${cfg.package}/share/neo4j/lib - ${optionalString (cfg.constrainLoadCsv) '' + ${lib.optionalString (cfg.constrainLoadCsv) '' server.directories.import=${cfg.directories.imports} ''} @@ -55,25 +52,23 @@ let server.directories.run=${cfg.directories.home}/run # HTTP Connector - ${optionalString (cfg.http.enable) '' - server.http.enabled=${boolToString cfg.http.enable} - server.http.listen_address=${cfg.http.listenAddress} - server.http.advertised_address=${cfg.http.listenAddress} - ''} + server.http.enabled=${lib.boolToString cfg.http.enable} + server.http.listen_address=${cfg.http.listenAddress} + server.http.advertised_address=${cfg.http.listenAddress} # HTTPS Connector - server.https.enabled=${boolToString cfg.https.enable} + server.https.enabled=${lib.boolToString cfg.https.enable} server.https.listen_address=${cfg.https.listenAddress} server.https.advertised_address=${cfg.https.listenAddress} # BOLT Connector - server.bolt.enabled=${boolToString cfg.bolt.enable} + server.bolt.enabled=${lib.boolToString cfg.bolt.enable} server.bolt.listen_address=${cfg.bolt.listenAddress} server.bolt.advertised_address=${cfg.bolt.listenAddress} server.bolt.tls_level=${cfg.bolt.tlsLevel} # SSL Policies - ${concatStringsSep "\n" sslPolicies} + ${lib.concatStringsSep "\n" sslPolicies} # Default retention policy from neo4j.conf db.tx_log.rotation.retention_policy=1 days @@ -101,33 +96,33 @@ let in { imports = [ - (mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "defaultListenAddress" ]) - (mkRenamedOptionModule [ "services" "neo4j" "listenAddress" ] [ "services" "neo4j" "defaultListenAddress" ]) - (mkRenamedOptionModule [ "services" "neo4j" "enableBolt" ] [ "services" "neo4j" "bolt" "enable" ]) - (mkRenamedOptionModule [ "services" "neo4j" "enableHttps" ] [ "services" "neo4j" "https" "enable" ]) - (mkRenamedOptionModule [ "services" "neo4j" "certDir" ] [ "services" "neo4j" "directories" "certificates" ]) - (mkRenamedOptionModule [ "services" "neo4j" "dataDir" ] [ "services" "neo4j" "directories" "home" ]) - (mkRemovedOptionModule [ "services" "neo4j" "port" ] "Use services.neo4j.http.listenAddress instead.") - (mkRemovedOptionModule [ "services" "neo4j" "boltPort" ] "Use services.neo4j.bolt.listenAddress instead.") - (mkRemovedOptionModule [ "services" "neo4j" "httpsPort" ] "Use services.neo4j.https.listenAddress instead.") - (mkRemovedOptionModule [ "services" "neo4j" "shell" "enabled" ] "shell.enabled was removed upstream") - (mkRemovedOptionModule [ "services" "neo4j" "udc" "enabled" ] "udc.enabled was removed upstream") + (lib.mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "defaultListenAddress" ]) + (lib.mkRenamedOptionModule [ "services" "neo4j" "listenAddress" ] [ "services" "neo4j" "defaultListenAddress" ]) + (lib.mkRenamedOptionModule [ "services" "neo4j" "enableBolt" ] [ "services" "neo4j" "bolt" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "neo4j" "enableHttps" ] [ "services" "neo4j" "https" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "neo4j" "certDir" ] [ "services" "neo4j" "directories" "certificates" ]) + (lib.mkRenamedOptionModule [ "services" "neo4j" "dataDir" ] [ "services" "neo4j" "directories" "home" ]) + (lib.mkRemovedOptionModule [ "services" "neo4j" "port" ] "Use services.neo4j.http.listenAddress instead.") + (lib.mkRemovedOptionModule [ "services" "neo4j" "boltPort" ] "Use services.neo4j.bolt.listenAddress instead.") + (lib.mkRemovedOptionModule [ "services" "neo4j" "httpsPort" ] "Use services.neo4j.https.listenAddress instead.") + (lib.mkRemovedOptionModule [ "services" "neo4j" "shell" "enabled" ] "shell.enabled was removed upstream") + (lib.mkRemovedOptionModule [ "services" "neo4j" "udc" "enabled" ] "udc.enabled was removed upstream") ]; ###### interface options.services.neo4j = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable Neo4j Community Edition. ''; }; - constrainLoadCsv = mkOption { - type = types.bool; + constrainLoadCsv = lib.mkOption { + type = lib.types.bool; default = true; description = '' Sets the root directory for file URLs used with the Cypher @@ -141,8 +136,8 @@ in { ''; }; - defaultListenAddress = mkOption { - type = types.str; + defaultListenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Default network interface to listen for incoming connections. To @@ -155,8 +150,8 @@ in { ''; }; - extraServerConfig = mkOption { - type = types.lines; + extraServerConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra configuration for Neo4j Community server. Refer to the @@ -165,18 +160,18 @@ in { ''; }; - package = mkPackageOption pkgs "neo4j" { }; + package = lib.mkPackageOption pkgs "neo4j" { }; - readOnly = mkOption { - type = types.bool; + readOnly = lib.mkOption { + type = lib.types.bool; default = false; description = '' Only allow read operations from this Neo4j instance. ''; }; - workerCount = mkOption { - type = types.ints.between 0 44738; + workerCount = lib.mkOption { + type = lib.types.ints.between 0 44738; default = 0; description = '' Number of Neo4j worker threads, where the default of @@ -186,8 +181,8 @@ in { }; bolt = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable the BOLT connector for Neo4j. Setting this option to @@ -196,8 +191,8 @@ in { ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = ":7687"; description = '' Neo4j listen address for BOLT traffic. The listen address is @@ -205,8 +200,8 @@ in { ''; }; - sslPolicy = mkOption { - type = types.str; + sslPolicy = lib.mkOption { + type = lib.types.str; default = "legacy"; description = '' Neo4j SSL policy for BOLT traffic. @@ -223,8 +218,8 @@ in { ''; }; - tlsLevel = mkOption { - type = types.enum [ "REQUIRED" "OPTIONAL" "DISABLED" ]; + tlsLevel = lib.mkOption { + type = lib.types.enum [ "REQUIRED" "OPTIONAL" "DISABLED" ]; default = "OPTIONAL"; description = '' SSL/TSL requirement level for BOLT traffic. @@ -233,10 +228,10 @@ in { }; directories = { - certificates = mkOption { - type = types.path; + certificates = lib.mkOption { + type = lib.types.path; default = "${cfg.directories.home}/certificates"; - defaultText = literalExpression ''"''${config.${opt.directories.home}}/certificates"''; + defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/certificates"''; description = '' Directory for storing certificates to be used by Neo4j for TLS connections. @@ -256,10 +251,10 @@ in { ''; }; - data = mkOption { - type = types.path; + data = lib.mkOption { + type = lib.types.path; default = "${cfg.directories.home}/data"; - defaultText = literalExpression ''"''${config.${opt.directories.home}}/data"''; + defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/data"''; description = '' Path of the data directory. You must not configure more than one Neo4j installation to use the same data directory. @@ -270,8 +265,8 @@ in { ''; }; - home = mkOption { - type = types.path; + home = lib.mkOption { + type = lib.types.path; default = "/var/lib/neo4j"; description = '' Path of the Neo4j home directory. Other default directories are @@ -281,10 +276,10 @@ in { ''; }; - imports = mkOption { - type = types.path; + imports = lib.mkOption { + type = lib.types.path; default = "${cfg.directories.home}/import"; - defaultText = literalExpression ''"''${config.${opt.directories.home}}/import"''; + defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/import"''; description = '' The root directory for file URLs used with the Cypher `LOAD CSV` clause. Only meaningful when @@ -297,10 +292,10 @@ in { ''; }; - plugins = mkOption { - type = types.path; + plugins = lib.mkOption { + type = lib.types.path; default = "${cfg.directories.home}/plugins"; - defaultText = literalExpression ''"''${config.${opt.directories.home}}/plugins"''; + defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/plugins"''; description = '' Path of the database plugin directory. Compiled Java JAR files that contain database procedures will be loaded if they are placed in @@ -314,8 +309,8 @@ in { }; http = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable the HTTP connector for Neo4j. Setting this option to @@ -324,8 +319,8 @@ in { ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = ":7474"; description = '' Neo4j listen address for HTTP traffic. The listen address is @@ -335,8 +330,8 @@ in { }; https = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable the HTTPS connector for Neo4j. Setting this option to @@ -345,8 +340,8 @@ in { ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = ":7473"; description = '' Neo4j listen address for HTTPS traffic. The listen address is @@ -354,8 +349,8 @@ in { ''; }; - sslPolicy = mkOption { - type = types.str; + sslPolicy = lib.mkOption { + type = lib.types.str; default = "legacy"; description = '' Neo4j SSL policy for HTTPS traffic. @@ -370,8 +365,8 @@ in { }; shell = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable a remote shell server which Neo4j Shell clients can log in to. @@ -380,12 +375,12 @@ in { }; }; - ssl.policies = mkOption { - type = with types; attrsOf (submodule ({ name, config, options, ... }: { + ssl.policies = lib.mkOption { + type = with lib.types; attrsOf (submodule ({ name, config, options, ... }: { options = { - allowKeyGeneration = mkOption { - type = types.bool; + allowKeyGeneration = lib.mkOption { + type = lib.types.bool; default = false; description = '' Allows the generation of a private key and associated self-signed @@ -402,10 +397,10 @@ in { ''; }; - baseDirectory = mkOption { - type = types.path; + baseDirectory = lib.mkOption { + type = lib.types.path; default = "${cfg.directories.certificates}/${name}"; - defaultText = literalExpression ''"''${config.${opt.directories.certificates}}/''${name}"''; + defaultText = lib.literalExpression ''"''${config.${opt.directories.certificates}}/''${name}"''; description = '' The mandatory base directory for cryptographic objects of this policy. This path is only automatically generated when this @@ -420,8 +415,8 @@ in { ''; }; - ciphers = mkOption { - type = types.nullOr (types.listOf types.str); + ciphers = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; description = '' Restrict the allowed ciphers of this policy to those defined @@ -429,16 +424,16 @@ in { ''; }; - clientAuth = mkOption { - type = types.enum [ "NONE" "OPTIONAL" "REQUIRE" ]; + clientAuth = lib.mkOption { + type = lib.types.enum [ "NONE" "OPTIONAL" "REQUIRE" ]; default = "REQUIRE"; description = '' The client authentication stance for this policy. ''; }; - privateKey = mkOption { - type = types.str; + privateKey = lib.mkOption { + type = lib.types.str; default = "private.key"; description = '' The name of private PKCS #8 key file for this policy to be found @@ -447,8 +442,8 @@ in { ''; }; - publicCertificate = mkOption { - type = types.str; + publicCertificate = lib.mkOption { + type = lib.types.str; default = "public.crt"; description = '' The name of public X.509 certificate (chain) file in PEM format @@ -462,10 +457,10 @@ in { ''; }; - revokedDir = mkOption { - type = types.path; + revokedDir = lib.mkOption { + type = lib.types.path; default = "${config.baseDirectory}/revoked"; - defaultText = literalExpression ''"''${config.${options.baseDirectory}}/revoked"''; + defaultText = lib.literalExpression ''"''${config.${options.baseDirectory}}/revoked"''; description = '' Path to directory of CRLs (Certificate Revocation Lists) in PEM format. Must be an absolute path. The existence of this @@ -478,8 +473,8 @@ in { ''; }; - tlsVersions = mkOption { - type = types.listOf types.str; + tlsVersions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "TLSv1.2" ]; description = '' Restrict the TLS protocol versions of this policy to those @@ -487,8 +482,8 @@ in { ''; }; - trustAll = mkOption { - type = types.bool; + trustAll = lib.mkOption { + type = lib.types.bool; default = false; description = '' Makes this policy trust all remote parties. Enabling this is not @@ -498,10 +493,10 @@ in { ''; }; - trustedDir = mkOption { - type = types.path; + trustedDir = lib.mkOption { + type = lib.types.path; default = "${config.baseDirectory}/trusted"; - defaultText = literalExpression ''"''${config.${options.baseDirectory}}/trusted"''; + defaultText = lib.literalExpression ''"''${config.${options.baseDirectory}}/trusted"''; description = '' Path to directory of X.509 certificates in PEM format for trusted parties. Must be an absolute path. The existence of this @@ -518,8 +513,8 @@ in { ''; }; - directoriesToCreate = mkOption { - type = types.listOf types.path; + directoriesToCreate = lib.mkOption { + type = lib.types.listOf lib.types.path; internal = true; readOnly = true; description = '' @@ -532,9 +527,9 @@ in { }; - config.directoriesToCreate = optionals + config.directoriesToCreate = lib.optionals (certDirOpt.highestPrio >= 1500 && options.baseDirectory.highestPrio >= 1500) - (map (opt: opt.value) (filter isDefaultPathOption (attrValues options))); + (map (opt: opt.value) (lib.filter isDefaultPathOption (lib.attrValues options))); })); default = {}; @@ -555,22 +550,22 @@ in { config = let # Assertion helpers - policyNameList = attrNames cfg.ssl.policies; + policyNameList = lib.attrNames cfg.ssl.policies; validPolicyNameList = [ "legacy" ] ++ policyNameList; - validPolicyNameString = concatStringsSep ", " validPolicyNameList; + validPolicyNameString = lib.concatStringsSep ", " validPolicyNameList; # Capture various directories left at their default so they can be created. - defaultDirectoriesToCreate = map (opt: opt.value) (filter isDefaultPathOption (attrValues options.services.neo4j.directories)); - policyDirectoriesToCreate = concatMap (pol: pol.directoriesToCreate) (attrValues cfg.ssl.policies); + defaultDirectoriesToCreate = map (opt: opt.value) (lib.filter isDefaultPathOption (lib.attrValues options.services.neo4j.directories)); + policyDirectoriesToCreate = lib.concatMap (pol: pol.directoriesToCreate) (lib.attrValues cfg.ssl.policies); in - mkIf cfg.enable { + lib.mkIf cfg.enable { assertions = [ - { assertion = !elem "legacy" policyNameList; + { assertion = !lib.elem "legacy" policyNameList; message = "The policy 'legacy' is special to Neo4j, and its name is reserved."; } - { assertion = elem cfg.bolt.sslPolicy validPolicyNameList; + { assertion = lib.elem cfg.bolt.sslPolicy validPolicyNameList; message = "Invalid policy assigned: `services.neo4j.bolt.sslPolicy = \"${cfg.bolt.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; } - { assertion = elem cfg.https.sslPolicy validPolicyNameList; + { assertion = lib.elem cfg.https.sslPolicy validPolicyNameList; message = "Invalid policy assigned: `services.neo4j.https.sslPolicy = \"${cfg.https.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; } ]; @@ -595,7 +590,7 @@ in { mkdir -m 0700 -p ${cfg.directories.home}/{conf,logs} # Create other sub-directories and policy directories that have been left at their default. - ${concatMapStringsSep "\n" ( + ${lib.concatMapStringsSep "\n" ( dir: '' mkdir -m 0700 -p ${dir} '') (defaultDirectoriesToCreate ++ policyDirectoriesToCreate)} diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix index feb974cdf6d3..20b1f03021f0 100644 --- a/nixos/modules/services/databases/openldap.nix +++ b/nixos/modules/services/databases/openldap.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.openldap; openldap = cfg.package; @@ -23,22 +21,22 @@ let merge = lib.mergeEqualOption; }; # We don't coerce to lists of single values, as some values must be unique - in types.either singleLdapValueType (types.listOf singleLdapValueType); + in lib.types.either singleLdapValueType (lib.types.listOf singleLdapValueType); ldapAttrsType = let options = { - attrs = mkOption { - type = types.attrsOf ldapValueType; + attrs = lib.mkOption { + type = lib.types.attrsOf ldapValueType; default = {}; description = "Attributes of the parent entry."; }; - children = mkOption { + children = lib.mkOption { # Hide the child attributes, to avoid infinite recursion in e.g. documentation # Actual Nix evaluation is lazy, so this is not an issue there type = let hiddenOptions = lib.mapAttrs (name: attr: attr // { visible = false; }) options; - in types.attrsOf (types.submodule { options = hiddenOptions; }); + in lib.types.attrsOf (lib.types.submodule { options = hiddenOptions; }); default = {}; description = "Child entries of the current entry, with recursively the same structure."; example = lib.literalExpression '' @@ -56,15 +54,15 @@ let } ''; }; - includes = mkOption { - type = types.listOf types.path; + includes = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' LDIF files to include after the parent's attributes but before its children. ''; }; }; - in types.submodule { inherit options; }; + in lib.types.submodule { inherit options; }; valueToLdif = attr: values: let listValues = if lib.isList values then values else lib.singleton values; @@ -85,13 +83,13 @@ let in { options = { services.openldap = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the ldap server."; }; - package = mkPackageOption pkgs "openldap" { + package = lib.mkPackageOption pkgs "openldap" { extraDescription = '' This can be used to, for example, set an OpenLDAP package with custom overrides to enable modules or other @@ -99,26 +97,26 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "openldap"; description = "User account under which slapd runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "openldap"; description = "Group account under which slapd runs."; }; - urlList = mkOption { - type = types.listOf types.str; + urlList = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "ldap:///" ]; description = "URL list slapd should listen on."; example = [ "ldaps:///" ]; }; - settings = mkOption { + settings = lib.mkOption { type = ldapAttrsType; description = "Configuration for OpenLDAP, in OLC format"; example = lib.literalExpression '' @@ -165,8 +163,8 @@ in { }; # This option overrides settings - configDir = mkOption { - type = types.nullOr types.path; + configDir = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Use this config directory instead of generating one from the @@ -175,8 +173,8 @@ in { example = "/var/lib/openldap/slapd.d"; }; - mutableConfig = mkOption { - type = types.bool; + mutableConfig = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to allow writable on-line configuration. If @@ -186,8 +184,8 @@ in { ''; }; - declarativeContents = mkOption { - type = with types; attrsOf lines; + declarativeContents = lib.mkOption { + type = with lib.types; attrsOf lines; default = {}; description = '' Declarative contents for the LDAP database, in LDIF format by suffix. @@ -225,8 +223,8 @@ in { meta.maintainers = with lib.maintainers; [ kwohlfahrt ]; config = let - dbSettings = mapAttrs' (name: { attrs, ... }: nameValuePair attrs.olcSuffix attrs) - (filterAttrs (name: { attrs, ... }: (hasPrefix "olcDatabase=" name) && attrs ? olcSuffix) cfg.settings.children); + dbSettings = lib.mapAttrs' (name: { attrs, ... }: lib.nameValuePair attrs.olcSuffix attrs) + (lib.filterAttrs (name: { attrs, ... }: (lib.hasPrefix "olcDatabase=" name) && attrs ? olcSuffix) cfg.settings.children); settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings)); writeConfig = pkgs.writeShellScript "openldap-config" '' set -euo pipefail @@ -241,32 +239,32 @@ in { chmod -R ${if cfg.mutableConfig then "u+rw" else "u+r-w"} ${configDir} ''; - contentsFiles = mapAttrs (dn: ldif: pkgs.writeText "${dn}.ldif" ldif) cfg.declarativeContents; + contentsFiles = lib.mapAttrs (dn: ldif: pkgs.writeText "${dn}.ldif" ldif) cfg.declarativeContents; writeContents = pkgs.writeShellScript "openldap-load" '' set -euo pipefail rm -rf $2/* ${openldap}/bin/slapadd -F ${configDir} -b $1 -l $3 ''; - in mkIf cfg.enable { + in lib.mkIf cfg.enable { assertions = [{ assertion = (cfg.declarativeContents != {}) -> cfg.configDir == null; message = '' - Declarative DB contents (${attrNames cfg.declarativeContents}) are not + Declarative DB contents (${lib.attrNames cfg.declarativeContents}) are not supported with user-managed configuration. ''; }] ++ (map (dn: { - assertion = (getAttr dn dbSettings) ? "olcDbDirectory"; + assertion = (lib.getAttr dn dbSettings) ? "olcDbDirectory"; # olcDbDirectory is necessary to prepopulate database using `slapadd`. message = '' Declarative DB ${dn} does not exist in `services.openldap.settings`, or does not have `olcDbDirectory` configured. ''; - }) (attrNames cfg.declarativeContents)) ++ (mapAttrsToList (dn: { olcDbDirectory ? null, ... }: { + }) (lib.attrNames cfg.declarativeContents)) ++ (lib.mapAttrsToList (dn: { olcDbDirectory ? null, ... }: { # For forward compatibility with `DynamicUser`, and to avoid accidentally clobbering # directories with `declarativeContents`. assertion = (olcDbDirectory != null) -> - ((hasPrefix "/var/lib/openldap/" olcDbDirectory) && (olcDbDirectory != "/var/lib/openldap/")); + ((lib.hasPrefix "/var/lib/openldap/" olcDbDirectory) && (olcDbDirectory != "/var/lib/openldap/")); message = '' Database ${dn} has `olcDbDirectory` (${olcDbDirectory}) that is not a subdirectory of `/var/lib/openldap/`. @@ -303,8 +301,8 @@ in { "!${pkgs.coreutils}/bin/mkdir -p ${configDir}" "+${pkgs.coreutils}/bin/chown $USER ${configDir}" ] ++ (lib.optional (cfg.configDir == null) writeConfig) - ++ (mapAttrsToList (dn: content: lib.escapeShellArgs [ - writeContents dn (getAttr dn dbSettings).olcDbDirectory content + ++ (lib.mapAttrsToList (dn: content: lib.escapeShellArgs [ + writeContents dn (lib.getAttr dn dbSettings).olcDbDirectory content ]) contentsFiles) ++ [ "${openldap}/bin/slaptest -u -F ${configDir}" ]; ExecStart = lib.escapeShellArgs ([ @@ -317,7 +315,7 @@ in { NotifyAccess = "all"; RuntimeDirectory = "openldap"; StateDirectory = ["openldap"] - ++ (map ({olcDbDirectory, ... }: removePrefix "/var/lib/" olcDbDirectory) (attrValues dbSettings)); + ++ (map ({olcDbDirectory, ... }: lib.removePrefix "/var/lib/" olcDbDirectory) (lib.attrValues dbSettings)); StateDirectoryMode = "700"; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; diff --git a/nixos/modules/services/databases/opentsdb.nix b/nixos/modules/services/databases/opentsdb.nix index e104c42f8b24..90268daec1d7 100644 --- a/nixos/modules/services/databases/opentsdb.nix +++ b/nixos/modules/services/databases/opentsdb.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.opentsdb; @@ -15,36 +12,36 @@ in { services.opentsdb = { - enable = mkEnableOption "OpenTSDB"; + enable = lib.mkEnableOption "OpenTSDB"; - package = mkPackageOption pkgs "opentsdb" { }; + package = lib.mkPackageOption pkgs "opentsdb" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "opentsdb"; description = '' User account under which OpenTSDB runs. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "opentsdb"; description = '' Group account under which OpenTSDB runs. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 4242; description = '' Which port OpenTSDB listens on. ''; }; - config = mkOption { - type = types.lines; + config = lib.mkOption { + type = lib.types.lines; default = '' tsd.core.auto_create_metrics = true tsd.http.request.enable_chunked = true @@ -60,7 +57,7 @@ in { ###### implementation - config = mkIf config.services.opentsdb.enable { + config = lib.mkIf config.services.opentsdb.enable { systemd.services.opentsdb = { description = "OpenTSDB Server"; diff --git a/nixos/modules/services/databases/pgmanage.nix b/nixos/modules/services/databases/pgmanage.nix index c405162ed87e..fe3d1b5bfb9d 100644 --- a/nixos/modules/services/databases/pgmanage.nix +++ b/nixos/modules/services/databases/pgmanage.nix @@ -1,7 +1,4 @@ { lib, pkgs, config, ... } : - -with lib; - let cfg = config.services.pgmanage; @@ -16,7 +13,7 @@ let super_only = ${builtins.toJSON cfg.superOnly} - ${optionalString (cfg.loginGroup != null) "login_group = ${cfg.loginGroup}"} + ${lib.optionalString (cfg.loginGroup != null) "login_group = ${cfg.loginGroup}"} login_timeout = ${toString cfg.loginTimeout} @@ -24,7 +21,7 @@ let sql_root = ${cfg.sqlRoot} - ${optionalString (cfg.tls != null) '' + ${lib.optionalString (cfg.tls != null) '' tls_cert = ${cfg.tls.cert} tls_key = ${cfg.tls.key} ''} @@ -35,8 +32,8 @@ let pgmanageConnectionsFile = pkgs.writeTextFile { name = "pgmanage-connections.conf"; - text = concatStringsSep "\n" - (mapAttrsToList (name : conn : "${name}: ${conn}") cfg.connections); + text = lib.concatStringsSep "\n" + (lib.mapAttrsToList (name : conn : "${name}: ${conn}") cfg.connections); }; pgmanage = "pgmanage"; @@ -44,12 +41,12 @@ let in { options.services.pgmanage = { - enable = mkEnableOption "PostgreSQL Administration for the web"; + enable = lib.mkEnableOption "PostgreSQL Administration for the web"; - package = mkPackageOption pkgs "pgmanage" { }; + package = lib.mkPackageOption pkgs "pgmanage" { }; - connections = mkOption { - type = types.attrsOf types.str; + connections = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = {}; example = { nuc-server = "hostaddr=192.168.0.100 port=5432 dbname=postgres"; @@ -68,8 +65,8 @@ in { ''; }; - allowCustomConnections = mkOption { - type = types.bool; + allowCustomConnections = lib.mkOption { + type = lib.types.bool; default = false; description = '' This tells pgmanage whether or not to allow anyone to use a custom @@ -77,16 +74,16 @@ in { ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = '' This tells pgmanage what port to listen on for browser requests. ''; }; - localOnly = mkOption { - type = types.bool; + localOnly = lib.mkOption { + type = lib.types.bool; default = true; description = '' This tells pgmanage whether or not to set the listening socket to local @@ -94,8 +91,8 @@ in { ''; }; - superOnly = mkOption { - type = types.bool; + superOnly = lib.mkOption { + type = lib.types.bool; default = true; description = '' This tells pgmanage whether or not to only allow super users to @@ -106,8 +103,8 @@ in { ''; }; - loginGroup = mkOption { - type = types.nullOr types.str; + loginGroup = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' This tells pgmanage to only allow users in a certain PostgreSQL group to @@ -116,8 +113,8 @@ in { ''; }; - loginTimeout = mkOption { - type = types.int; + loginTimeout = lib.mkOption { + type = lib.types.int; default = 3600; description = '' Number of seconds of inactivity before user is automatically logged @@ -125,8 +122,8 @@ in { ''; }; - sqlRoot = mkOption { - type = types.str; + sqlRoot = lib.mkOption { + type = lib.types.str; default = "/var/lib/pgmanage"; description = '' This tells pgmanage where to put the SQL file history. All tabs are saved @@ -135,15 +132,15 @@ in { ''; }; - tls = mkOption { - type = types.nullOr (types.submodule { + tls = lib.mkOption { + type = lib.types.nullOr (lib.types.submodule { options = { - cert = mkOption { - type = types.str; + cert = lib.mkOption { + type = lib.types.str; description = "TLS certificate"; }; - key = mkOption { - type = types.str; + key = lib.mkOption { + type = lib.types.str; description = "TLS key"; }; }; @@ -162,8 +159,8 @@ in { ''; }; - logLevel = mkOption { - type = types.enum ["error" "warn" "notice" "info"]; + logLevel = lib.mkOption { + type = lib.types.enum ["error" "warn" "notice" "info"]; default = "error"; description = '' Verbosity of logs @@ -171,7 +168,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.pgmanage = { description = "pgmanage - PostgreSQL Administration for the web"; wants = [ "postgresql.service" ]; @@ -181,7 +178,7 @@ in { User = pgmanage; Group = pgmanage; ExecStart = "${cfg.package}/sbin/pgmanage -c ${confFile}" + - optionalString cfg.localOnly " --local-only=true"; + lib.optionalString cfg.localOnly " --local-only=true"; }; }; users = { diff --git a/nixos/modules/services/databases/postgresql.md b/nixos/modules/services/databases/postgresql.md index e76f127335c7..5108f040e968 100644 --- a/nixos/modules/services/databases/postgresql.md +++ b/nixos/modules/services/databases/postgresql.md @@ -187,7 +187,7 @@ $ nix-instantiate --eval -A postgresql_13.psqlSchema ``` For an upgrade, a script like this can be used to simplify the process: ```nix -{ config, pkgs, ... }: +{ config, lib, pkgs, ... }: { environment.systemPackages = [ (let @@ -196,6 +196,7 @@ For an upgrade, a script like this can be used to simplify the process: newPostgres = pkgs.postgresql_13.withPackages (pp: [ # pp.plv8 ]); + cfg = config.services.postgresql; in pkgs.writeScriptBin "upgrade-pg-cluster" '' set -eux # XXX it's perhaps advisable to stop all services that depend on postgresql @@ -205,12 +206,12 @@ For an upgrade, a script like this can be used to simplify the process: export NEWBIN="${newPostgres}/bin" - export OLDDATA="${config.services.postgresql.dataDir}" - export OLDBIN="${config.services.postgresql.package}/bin" + export OLDDATA="${cfg.dataDir}" + export OLDBIN="${cfg.package}/bin" install -d -m 0700 -o postgres -g postgres "$NEWDATA" cd "$NEWDATA" - sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" + sudo -u postgres $NEWBIN/initdb -D "$NEWDATA" ${lib.escapeShellArgs cfg.initdbArgs} sudo -u postgres $NEWBIN/pg_upgrade \ --old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \ @@ -362,3 +363,7 @@ postgresql.withJIT.pname ``` evaluates to `"foobar"`. + +## Notable differences to upstream {#module-services-postgres-upstream-deviation} + +- To avoid circular dependencies between default and -dev outputs, the output of the `pg_config` system view has been removed. diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index 55b3dd282ec4..ceaccde813a0 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -7,6 +7,7 @@ let concatStringsSep const elem + escapeShellArgs filterAttrs isString literalExpression @@ -545,7 +546,7 @@ in rm -f ${cfg.dataDir}/*.conf # Initialise the database. - initdb -U ${cfg.superUser} ${concatStringsSep " " cfg.initdbArgs} + initdb -U ${cfg.superUser} ${escapeShellArgs cfg.initdbArgs} # See postStart! touch "${cfg.dataDir}/.first_startup" diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index 7a3f408aa98e..43829b13c6c0 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -72,7 +72,28 @@ in { defaultText = literalExpression '' if name == "" then "redis" else "redis-''${name}" ''; - description = "The username and groupname for redis-server."; + description = '' + User account under which this instance of redis-server runs. + + ::: {.note} + If left as the default value this user will automatically be + created on system activation, otherwise you are responsible for + ensuring the user exists before the redis service starts. + ''; + }; + + group = mkOption { + type = types.str; + default = config.user; + defaultText = literalExpression "config.user"; + description = '' + Group account under which this instance of redis-server runs. + + ::: {.note} + If left as the default value this group will automatically be + created on system activation, otherwise you are responsible for + ensuring the group exists before the redis service starts. + ''; }; port = mkOption { @@ -337,7 +358,7 @@ in { redisConfStore = redisConfig conf.settings; in '' touch "${redisConfVar}" "${redisConfRun}" - chown '${conf.user}' "${redisConfVar}" "${redisConfRun}" + chown '${conf.user}':'${conf.group}' "${redisConfVar}" "${redisConfRun}" chmod 0600 "${redisConfVar}" "${redisConfRun}" if [ ! -s ${redisConfVar} ]; then echo 'include "${redisConfRun}"' > "${redisConfVar}" @@ -353,7 +374,7 @@ in { Type = "notify"; # User and group User = conf.user; - Group = conf.user; + Group = conf.group; # Runtime directory and mode RuntimeDirectory = redisName name; RuntimeDirectoryMode = "0750"; diff --git a/nixos/modules/services/databases/rethinkdb.nix b/nixos/modules/services/databases/rethinkdb.nix index c764d6c21c6c..1b85fd1bb7bd 100644 --- a/nixos/modules/services/databases/rethinkdb.nix +++ b/nixos/modules/services/databases/rethinkdb.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.rethinkdb; rethinkdb = cfg.package; @@ -15,41 +12,41 @@ in services.rethinkdb = { - enable = mkEnableOption "RethinkDB server"; + enable = lib.mkEnableOption "RethinkDB server"; - #package = mkOption { + #package = lib.mkOption { # default = pkgs.rethinkdb; # description = "Which RethinkDB derivation to use."; #}; - user = mkOption { + user = lib.mkOption { default = "rethinkdb"; description = "User account under which RethinkDB runs."; }; - group = mkOption { + group = lib.mkOption { default = "rethinkdb"; description = "Group which rethinkdb user belongs to."; }; - dbpath = mkOption { + dbpath = lib.mkOption { default = "/var/db/rethinkdb"; description = "Location where RethinkDB stores its data, 1 data directory per instance."; }; - pidpath = mkOption { + pidpath = lib.mkOption { default = "/run/rethinkdb"; description = "Location where each instance's pid file is located."; }; - #cfgpath = mkOption { + #cfgpath = lib.mkOption { # default = "/etc/rethinkdb/instances.d"; # description = "Location where RethinkDB stores it config files, 1 config file per instance."; #}; # TODO: currently not used by our implementation. - #instances = mkOption { - # type = types.attrsOf types.str; + #instances = lib.mkOption { + # type = lib.types.attrsOf lib.types.str; # default = {}; # description = "List of named RethinkDB instances in our cluster."; #}; @@ -59,7 +56,7 @@ in }; ###### implementation - config = mkIf config.services.rethinkdb.enable { + config = lib.mkIf config.services.rethinkdb.enable { environment.systemPackages = [ rethinkdb ]; @@ -93,13 +90,13 @@ in ''; }; - users.users.rethinkdb = mkIf (cfg.user == "rethinkdb") + users.users.rethinkdb = lib.mkIf (cfg.user == "rethinkdb") { name = "rethinkdb"; description = "RethinkDB server user"; isSystemUser = true; }; - users.groups = optionalAttrs (cfg.group == "rethinkdb") (singleton + users.groups = lib.optionalAttrs (cfg.group == "rethinkdb") (lib.singleton { name = "rethinkdb"; }); diff --git a/nixos/modules/services/databases/surrealdb.nix b/nixos/modules/services/databases/surrealdb.nix index 2118312d5a1b..b88129ebc6f4 100644 --- a/nixos/modules/services/databases/surrealdb.nix +++ b/nixos/modules/services/databases/surrealdb.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.surrealdb; @@ -8,12 +6,12 @@ in { options = { services.surrealdb = { - enable = mkEnableOption "SurrealDB, a scalable, distributed, collaborative, document-graph database, for the realtime web"; + enable = lib.mkEnableOption "SurrealDB, a scalable, distributed, collaborative, document-graph database, for the realtime web"; - package = mkPackageOption pkgs "surrealdb" { }; + package = lib.mkPackageOption pkgs "surrealdb" { }; - dbPath = mkOption { - type = types.str; + dbPath = lib.mkOption { + type = lib.types.str; description = '' The path that surrealdb will write data to. Use null for in-memory. Can be one of "memory", "file://:path", "tikv://:addr". @@ -22,8 +20,8 @@ in { example = "memory"; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; description = '' The host that surrealdb will connect to. ''; @@ -31,8 +29,8 @@ in { example = "127.0.0.1"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; description = '' The port that surrealdb will connect to. ''; @@ -40,8 +38,8 @@ in { example = 8000; }; - extraFlags = mkOption { - type = types.listOf types.str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "--allow-all" "--auth" "--user root" "--pass root" ]; description = '' @@ -52,7 +50,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Used to connect to the running service environment.systemPackages = [ cfg.package ] ; @@ -63,7 +61,7 @@ in { after = [ "network.target" ]; serviceConfig = { - ExecStart = "${cfg.package}/bin/surreal start --bind ${cfg.host}:${toString cfg.port} ${escapeShellArgs cfg.extraFlags} -- ${cfg.dbPath}"; + ExecStart = "${cfg.package}/bin/surreal start --bind ${cfg.host}:${toString cfg.port} ${lib.escapeShellArgs cfg.extraFlags} -- ${cfg.dbPath}"; DynamicUser = true; Restart = "on-failure"; StateDirectory = "surrealdb"; diff --git a/nixos/modules/services/databases/tigerbeetle.md b/nixos/modules/services/databases/tigerbeetle.md index 12d920e7bcc7..7cf3bedda5e0 100644 --- a/nixos/modules/services/databases/tigerbeetle.md +++ b/nixos/modules/services/databases/tigerbeetle.md @@ -35,3 +35,10 @@ Note that the TigerBeetle module won't open any firewall ports automatically, so A complete list of options for TigerBeetle can be found [here](#opt-services.tigerbeetle.enable). +## Upgrading {#module-services-tigerbeetle-upgrading} + +Usually, TigerBeetle's [upgrade process](https://docs.tigerbeetle.com/operating/upgrading) only requires replacing the binary used for the servers. +This is not directly possible with NixOS since the new binary will be located at a different place in the Nix store. + +However, since TigerBeetle is managed through systemd on NixOS, the only action you need to take when upgrading is to make sure the version of TigerBeetle you're upgrading to supports upgrades from the version you're currently running. +This information will be on the [release notes](https://github.com/tigerbeetle/tigerbeetle/releases) for the version you're upgrading to. diff --git a/nixos/modules/services/databases/tigerbeetle.nix b/nixos/modules/services/databases/tigerbeetle.nix index a9c7a24250a6..7b512055e44e 100644 --- a/nixos/modules/services/databases/tigerbeetle.nix +++ b/nixos/modules/services/databases/tigerbeetle.nix @@ -42,8 +42,8 @@ in }; cacheGridSize = mkOption { - type = types.strMatching "[0-9]+(K|M|G)B"; - default = "1GB"; + type = types.strMatching "[0-9]+(K|M|G)iB"; + default = "1GiB"; description = '' The grid cache size. The grid cache acts like a page cache for TigerBeetle. @@ -97,16 +97,26 @@ in ''; serviceConfig = { - Type = "exec"; - - DynamicUser = true; - ProtectHome = true; DevicePolicy = "closed"; - + DynamicUser = true; + ExecStart = "${lib.getExe cfg.package} start --cache-grid=${cfg.cacheGridSize} --addresses=${lib.escapeShellArg (builtins.concatStringsSep "," cfg.addresses)} ${replicaDataPath}"; + LockPersonality = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; StateDirectory = "tigerbeetle"; StateDirectoryMode = 700; - - ExecStart = "${lib.getExe cfg.package} start --cache-grid=${cfg.cacheGridSize} --addresses=${lib.escapeShellArg (builtins.concatStringsSep "," cfg.addresses)} ${replicaDataPath}"; + Type = "exec"; }; }; diff --git a/nixos/modules/services/desktop-managers/lomiri.nix b/nixos/modules/services/desktop-managers/lomiri.nix index 2d3cecfe9e43..75834eab0cd8 100644 --- a/nixos/modules/services/desktop-managers/lomiri.nix +++ b/nixos/modules/services/desktop-managers/lomiri.nix @@ -16,7 +16,6 @@ in { libayatana-common ubports-click ]) ++ (with pkgs.lomiri; [ - content-hub hfd-service history-service libusermetrics @@ -24,6 +23,8 @@ in { lomiri-calculator-app lomiri-camera-app lomiri-clock-app + lomiri-content-hub + lomiri-docviewer-app lomiri-download-manager lomiri-filemanager-app lomiri-gallery-app @@ -43,13 +44,15 @@ in { telephony-service teleports ]); - variables = { - # To override the keyboard layouts in Lomiri - NIXOS_XKB_LAYOUTS = config.services.xserver.xkb.layout; - }; + + # To override the default keyboard layout in Lomiri + etc.${pkgs.lomiri.lomiri.passthru.etcLayoutsFile}.text = lib.strings.replaceStrings [","] ["\n"] config.services.xserver.xkb.layout; + }; + + hardware = { + bluetooth.enable = lib.mkDefault true; }; - hardware.pulseaudio.enable = lib.mkDefault true; networking.networkmanager.enable = lib.mkDefault true; systemd.packages = with pkgs.lomiri; [ @@ -87,6 +90,8 @@ in { ayatana-indicator-messages ayatana-indicator-power ayatana-indicator-session + ] ++ lib.optionals config.hardware.bluetooth.enable [ + ayatana-indicator-bluetooth ] ++ lib.optionals (config.hardware.pulseaudio.enable || config.services.pipewire.pulse.enable) [ ayatana-indicator-sound ]) ++ (with pkgs.lomiri; [ @@ -124,7 +129,7 @@ in { environment.pathsToLink = [ # Configs for inter-app data exchange system - "/share/content-hub/peers" + "/share/lomiri-content-hub/peers" # Configs for inter-app URL requests "/share/lomiri-url-dispatcher/urls" # Splash screens & other images for desktop apps launched via lomiri-app-launch @@ -189,10 +194,6 @@ in { }; users.groups.usermetrics = { }; - - # TODO content-hub cannot pass files between applications without asking AA for permissions. And alot of the Lomiri stack is designed with AA availability in mind. This might be a requirement to be closer to upstream? - # But content-hub currently fails to pass files between applications even with AA enabled, and we can get away without AA in many places. Let's see how this develops before requiring this for good. - # security.apparmor.enable = true; }; meta.maintainers = lib.teams.lomiri.members; diff --git a/nixos/modules/services/desktop-managers/plasma6.nix b/nixos/modules/services/desktop-managers/plasma6.nix index 3b36d3a905d0..eca4862b16f1 100644 --- a/nixos/modules/services/desktop-managers/plasma6.nix +++ b/nixos/modules/services/desktop-managers/plasma6.nix @@ -12,7 +12,7 @@ activationScript = '' # will be rebuilt automatically - rm -fv $HOME/.cache/ksycoca* + rm -fv "$HOME/.cache/ksycoca"* ''; in { options = { @@ -58,6 +58,7 @@ in { ]; qt.enable = true; + programs.xwayland.enable = true; environment.systemPackages = with kdePackages; let requiredPackages = [ qtwayland # Hack? To make everything run on Wayland @@ -87,7 +88,6 @@ in { # Core Plasma parts kwin - pkgs.xwayland kscreen libkscreen kscreenlocker @@ -143,10 +143,16 @@ in { kate khelpcenter dolphin + baloo-widgets # baloo information in Dolphin dolphin-plugins spectacle ffmpegthumbs krdp + xwaylandvideobridge # exposes Wayland windows to X11 screen capture + ] ++ lib.optionals config.services.flatpak.enable [ + # Since PackageKit Nix support is not there yet, + # only install discover if flatpak is enabled. + discover ]; in requiredPackages @@ -239,12 +245,20 @@ in { systemd.services."drkonqi-coredump-processor@".wantedBy = ["systemd-coredump@.service"]; xdg.icons.enable = true; + xdg.icons.fallbackCursorThemes = mkDefault ["breeze_cursors"]; xdg.portal.enable = true; - xdg.portal.extraPortals = [kdePackages.xdg-desktop-portal-kde]; - xdg.portal.configPackages = mkDefault [kdePackages.xdg-desktop-portal-kde]; + xdg.portal.extraPortals = [ + kdePackages.kwallet + kdePackages.xdg-desktop-portal-kde + pkgs.xdg-desktop-portal-gtk + ]; + xdg.portal.configPackages = mkDefault [kdePackages.plasma-workspace]; services.pipewire.enable = mkDefault true; + # Enable screen reader by default + services.orca.enable = mkDefault true; + services.displayManager = { sessionPackages = [kdePackages.plasma-workspace]; defaultSession = mkDefault "plasma"; diff --git a/nixos/modules/services/desktops/accountsservice.nix b/nixos/modules/services/desktops/accountsservice.nix index ae2ecb5ffeb7..4c407ca3828a 100644 --- a/nixos/modules/services/desktops/accountsservice.nix +++ b/nixos/modules/services/desktops/accountsservice.nix @@ -1,23 +1,17 @@ # AccountsService daemon. - { config, lib, pkgs, ... }: - -with lib; - { - meta = { - maintainers = teams.freedesktop.members; + maintainers = lib.teams.freedesktop.members; }; ###### interface - options = { services.accounts-daemon = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable AccountsService, a DBus service for accessing @@ -29,10 +23,8 @@ with lib; }; - ###### implementation - - config = mkIf config.services.accounts-daemon.enable { + config = lib.mkIf config.services.accounts-daemon.enable { environment.systemPackages = [ pkgs.accountsservice ]; @@ -43,14 +35,14 @@ with lib; systemd.packages = [ pkgs.accountsservice ]; - systemd.services.accounts-daemon = recursiveUpdate { + systemd.services.accounts-daemon = lib.recursiveUpdate { wantedBy = [ "graphical.target" ]; # Accounts daemon looks for dbus interfaces in $XDG_DATA_DIRS/accountsservice environment.XDG_DATA_DIRS = "${config.system.path}/share"; - } (optionalAttrs (!config.users.mutableUsers) { + } (lib.optionalAttrs (!config.users.mutableUsers) { environment.NIXOS_USERS_PURE = "true"; }); }; diff --git a/nixos/modules/services/desktops/bamf.nix b/nixos/modules/services/desktops/bamf.nix index 13de3a44328f..d9c46e94d9e0 100644 --- a/nixos/modules/services/desktops/bamf.nix +++ b/nixos/modules/services/desktops/bamf.nix @@ -1,25 +1,21 @@ # Bamf - { config, lib, pkgs, ... }: - -with lib; - { meta = with lib; { - maintainers = with maintainers; [ ] ++ teams.pantheon.members; + maintainers = with lib.maintainers; [ ] ++ lib.teams.pantheon.members; }; ###### interface options = { services.bamf = { - enable = mkEnableOption "bamf"; + enable = lib.mkEnableOption "bamf"; }; }; ###### implementation - config = mkIf config.services.bamf.enable { + config = lib.mkIf config.services.bamf.enable { services.dbus.packages = [ pkgs.bamf ]; systemd.packages = [ pkgs.bamf ]; diff --git a/nixos/modules/services/desktops/blueman.nix b/nixos/modules/services/desktops/blueman.nix index 28c2daa7191d..4f02d288e2df 100644 --- a/nixos/modules/services/desktops/blueman.nix +++ b/nixos/modules/services/desktops/blueman.nix @@ -1,20 +1,17 @@ # blueman service { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.blueman; in { ###### interface options = { services.blueman = { - enable = mkEnableOption "blueman, a bluetooth manager"; + enable = lib.mkEnableOption "blueman, a bluetooth manager"; }; }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.blueman ]; diff --git a/nixos/modules/services/desktops/cpupower-gui.nix b/nixos/modules/services/desktops/cpupower-gui.nix index f66afc0a3dc1..ceed84da840e 100644 --- a/nixos/modules/services/desktops/cpupower-gui.nix +++ b/nixos/modules/services/desktops/cpupower-gui.nix @@ -1,13 +1,10 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.cpupower-gui; in { options = { services.cpupower-gui = { - enable = mkOption { + enable = lib.mkOption { type = lib.types.bool; default = false; example = true; @@ -20,7 +17,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.cpupower-gui ]; services.dbus.packages = [ pkgs.cpupower-gui ]; systemd.user = { diff --git a/nixos/modules/services/desktops/deepin/app-services.nix b/nixos/modules/services/desktops/deepin/app-services.nix index 4702274df374..7d99bd11802f 100644 --- a/nixos/modules/services/desktops/deepin/app-services.nix +++ b/nixos/modules/services/desktops/deepin/app-services.nix @@ -1,11 +1,8 @@ { config, pkgs, lib, ... }: - -with lib; - { meta = { - maintainers = teams.deepin.members; + maintainers = lib.teams.deepin.members; }; ###### interface @@ -14,7 +11,7 @@ with lib; services.deepin.app-services = { - enable = mkEnableOption "service collection of DDE applications, including dconfig-center"; + enable = lib.mkEnableOption "service collection of DDE applications, including dconfig-center"; }; @@ -23,7 +20,7 @@ with lib; ###### implementation - config = mkIf config.services.deepin.app-services.enable { + config = lib.mkIf config.services.deepin.app-services.enable { users.groups.dde-dconfig-daemon = { }; users.users.dde-dconfig-daemon = { diff --git a/nixos/modules/services/desktops/deepin/dde-api.nix b/nixos/modules/services/desktops/deepin/dde-api.nix index 36f9881fc766..89889b3530c9 100644 --- a/nixos/modules/services/desktops/deepin/dde-api.nix +++ b/nixos/modules/services/desktops/deepin/dde-api.nix @@ -1,11 +1,8 @@ { config, pkgs, lib, ... }: - -with lib; - { meta = { - maintainers = teams.deepin.members; + maintainers = lib.teams.deepin.members; }; ###### interface @@ -14,7 +11,7 @@ with lib; services.deepin.dde-api = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' the DDE API, which provides some dbus interfaces that is used for screen zone detecting, thumbnail generating, and sound playing in Deepin Desktop Environment ''; @@ -26,7 +23,7 @@ with lib; ###### implementation - config = mkIf config.services.deepin.dde-api.enable { + config = lib.mkIf config.services.deepin.dde-api.enable { environment.systemPackages = [ pkgs.deepin.dde-api ]; diff --git a/nixos/modules/services/desktops/dleyna-renderer.nix b/nixos/modules/services/desktops/dleyna-renderer.nix index 7f88605f627c..f36f1fbb1a4e 100644 --- a/nixos/modules/services/desktops/dleyna-renderer.nix +++ b/nixos/modules/services/desktops/dleyna-renderer.nix @@ -1,14 +1,11 @@ # dleyna-renderer service. { config, lib, pkgs, ... }: - -with lib; - { ###### interface options = { services.dleyna-renderer = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable dleyna-renderer service, a DBus service @@ -20,7 +17,7 @@ with lib; ###### implementation - config = mkIf config.services.dleyna-renderer.enable { + config = lib.mkIf config.services.dleyna-renderer.enable { environment.systemPackages = [ pkgs.dleyna-renderer ]; services.dbus.packages = [ pkgs.dleyna-renderer ]; diff --git a/nixos/modules/services/desktops/dleyna-server.nix b/nixos/modules/services/desktops/dleyna-server.nix index 9a131a5e700f..812110281ae4 100644 --- a/nixos/modules/services/desktops/dleyna-server.nix +++ b/nixos/modules/services/desktops/dleyna-server.nix @@ -1,14 +1,11 @@ # dleyna-server service. { config, lib, pkgs, ... }: - -with lib; - { ###### interface options = { services.dleyna-server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable dleyna-server service, a DBus service @@ -20,7 +17,7 @@ with lib; ###### implementation - config = mkIf config.services.dleyna-server.enable { + config = lib.mkIf config.services.dleyna-server.enable { environment.systemPackages = [ pkgs.dleyna-server ]; services.dbus.packages = [ pkgs.dleyna-server ]; diff --git a/nixos/modules/services/desktops/flatpak.nix b/nixos/modules/services/desktops/flatpak.nix index b386bafcfe6f..da07f602b3a0 100644 --- a/nixos/modules/services/desktops/flatpak.nix +++ b/nixos/modules/services/desktops/flatpak.nix @@ -1,8 +1,5 @@ # flatpak service. { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.flatpak; in { @@ -14,15 +11,15 @@ in { ###### interface options = { services.flatpak = { - enable = mkEnableOption "flatpak"; + enable = lib.mkEnableOption "flatpak"; - package = mkPackageOption pkgs "flatpak" { }; + package = lib.mkPackageOption pkgs "flatpak" { }; }; }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = (config.xdg.portal.enable == true); diff --git a/nixos/modules/services/desktops/gnome/gnome-settings-daemon.nix b/nixos/modules/services/desktops/gnome/gnome-settings-daemon.nix index 30b35f669092..21e7c3b58713 100644 --- a/nixos/modules/services/desktops/gnome/gnome-settings-daemon.nix +++ b/nixos/modules/services/desktops/gnome/gnome-settings-daemon.nix @@ -32,15 +32,15 @@ in config = lib.mkIf cfg.enable { environment.systemPackages = [ - pkgs.gnome.gnome-settings-daemon + pkgs.gnome-settings-daemon ]; services.udev.packages = [ - pkgs.gnome.gnome-settings-daemon + pkgs.gnome-settings-daemon ]; systemd.packages = [ - pkgs.gnome.gnome-settings-daemon + pkgs.gnome-settings-daemon ]; systemd.user.targets."gnome-session-x11-services".wants = [ diff --git a/nixos/modules/services/desktops/gsignond.nix b/nixos/modules/services/desktops/gsignond.nix index 465acd73fa64..c21d3f0aafd8 100644 --- a/nixos/modules/services/desktops/gsignond.nix +++ b/nixos/modules/services/desktops/gsignond.nix @@ -1,15 +1,11 @@ # Accounts-SSO gSignOn daemon - { config, lib, pkgs, ... }: - -with lib; - let package = pkgs.gsignond.override { plugins = config.services.gsignond.plugins; }; in { - meta.maintainers = teams.pantheon.members; + meta.maintainers = lib.teams.pantheon.members; ###### interface @@ -17,8 +13,8 @@ in services.gsignond = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable gSignOn daemon, a DBus service @@ -26,8 +22,8 @@ in ''; }; - plugins = mkOption { - type = types.listOf types.package; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; description = '' What plugins to use with the gSignOn daemon. @@ -37,7 +33,7 @@ in }; ###### implementation - config = mkIf config.services.gsignond.enable { + config = lib.mkIf config.services.gsignond.enable { environment.etc."gsignond.conf".source = "${package}/etc/gsignond.conf"; services.dbus.packages = [ package ]; }; diff --git a/nixos/modules/services/desktops/neard.nix b/nixos/modules/services/desktops/neard.nix index 5459d2e5a1e5..21a69a34001f 100644 --- a/nixos/modules/services/desktops/neard.nix +++ b/nixos/modules/services/desktops/neard.nix @@ -1,19 +1,69 @@ -# neard service. -{ config, lib, pkgs, ... }: - -with lib; - { - ###### interface - options = { - services.neard = { - enable = mkEnableOption "neard, an NFC daemon"; + config, + lib, + pkgs, + ... +}: + +let + inherit (lib) + mkEnableOption + mkIf + mkOption + types + ; + cfg = config.services.neard; + format = pkgs.formats.ini { }; + configFile = format.generate "neard.conf" cfg.settings; +in +{ + options.services.neard = { + enable = mkEnableOption "neard, an NFC daemon"; + + settings = mkOption { + type = types.submodule { + freeformType = format.type; + options = { + General = { + ConstantPoll = mkOption { + type = types.bool; + default = false; + description = '' + Enable constant polling. Constant polling will automatically trigger a new + polling loop whenever a tag or a device is no longer in the RF field. + ''; + }; + + DefaultPowered = mkOption { + type = types.bool; + default = true; + description = '' + Automatically turn an adapter on when being discovered. + ''; + }; + + ResetOnError = mkOption { + type = types.bool; + default = true; + description = '' + Power cycle the adapter when getting a driver error from the kernel. + ''; + }; + }; + }; + }; + default = {}; + description = '' + Neard INI-style configuration file as a Nix attribute set. + + See the upstream [configuration file](https://github.com/linux-nfc/neard/blob/master/src/main.conf). + ''; }; }; + config = mkIf cfg.enable { + environment.etc."neard/main.conf".source = configFile; - ###### implementation - config = mkIf config.services.neard.enable { environment.systemPackages = [ pkgs.neard ]; services.dbus.packages = [ pkgs.neard ]; diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix index bf57d1255774..532c64c0f424 100644 --- a/nixos/modules/services/desktops/pipewire/pipewire.nix +++ b/nixos/modules/services/desktops/pipewire/pipewire.nix @@ -19,7 +19,7 @@ let ''; cfg = config.services.pipewire; enable32BitAlsaPlugins = cfg.alsa.support32Bit - && pkgs.stdenv.isx86_64 + && pkgs.stdenv.hostPlatform.isx86_64 && pkgs.pkgsi686Linux.pipewire != null; # The package doesn't output to $out/lib/pipewire directly so that the diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix index c924801bcd8b..cccb892cecf7 100644 --- a/nixos/modules/services/desktops/pipewire/wireplumber.nix +++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix @@ -215,17 +215,6 @@ in } ''; - systemwideConfigPkg = pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/90-nixos-systemwide.conf" '' - # When running system-wide, we don't have logind to call ReserveDevice, - # And bluetooth logind integration needs to be disabled - wireplumber.profiles = { - main = { - support.reserve-device = disabled - monitor.bluez.seat-monitoring = disabled - } - } - ''; - extraConfigPkg = pkgs.buildEnv { name = "wireplumber-extra-config"; paths = mapConfigToFiles cfg.extraConfig; @@ -240,8 +229,7 @@ in configPackages = cfg.configPackages ++ [ extraConfigPkg extraScriptsPkg ] - ++ optional (!pwUsedForAudio) pwNotForAudioConfigPkg - ++ optional pwCfg.systemWide systemwideConfigPkg; + ++ optional (!pwUsedForAudio) pwNotForAudioConfigPkg; configs = pkgs.buildEnv { name = "wireplumber-configs"; diff --git a/nixos/modules/services/desktops/profile-sync-daemon.nix b/nixos/modules/services/desktops/profile-sync-daemon.nix index 6206295272fc..48b29a59135c 100644 --- a/nixos/modules/services/desktops/profile-sync-daemon.nix +++ b/nixos/modules/services/desktops/profile-sync-daemon.nix @@ -1,19 +1,16 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.psd; in { - options.services.psd = with types; { - enable = mkOption { + options.services.psd = with lib.types; { + enable = lib.mkOption { type = bool; default = false; description = '' Whether to enable the Profile Sync daemon. ''; }; - resyncTimer = mkOption { + resyncTimer = lib.mkOption { type = str; default = "1h"; example = "1h 30min"; @@ -27,7 +24,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd = { user = { services = { diff --git a/nixos/modules/services/desktops/system-config-printer.nix b/nixos/modules/services/desktops/system-config-printer.nix index 55f27b0e6534..6a8ff8dd19c6 100644 --- a/nixos/modules/services/desktops/system-config-printer.nix +++ b/nixos/modules/services/desktops/system-config-printer.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - { ###### interface @@ -10,7 +7,7 @@ with lib; services.system-config-printer = { - enable = mkEnableOption "system-config-printer, a service for CUPS administration used by printing interfaces"; + enable = lib.mkEnableOption "system-config-printer, a service for CUPS administration used by printing interfaces"; }; @@ -19,7 +16,7 @@ with lib; ###### implementation - config = mkIf config.services.system-config-printer.enable { + config = lib.mkIf config.services.system-config-printer.enable { services.dbus.packages = [ pkgs.system-config-printer diff --git a/nixos/modules/services/desktops/system76-scheduler.nix b/nixos/modules/services/desktops/system76-scheduler.nix index b021ae6bfbfa..b8f80276ef76 100644 --- a/nixos/modules/services/desktops/system76-scheduler.nix +++ b/nixos/modules/services/desktops/system76-scheduler.nix @@ -95,8 +95,8 @@ in { package = mkOption { type = types.package; - default = config.boot.kernelPackages.system76-scheduler; - defaultText = literalExpression "config.boot.kernelPackages.system76-scheduler"; + default = pkgs.system76-scheduler; + defaultText = literalExpression "pkgs.system76-scheduler"; description = "Which System76-Scheduler package to use."; }; @@ -252,7 +252,7 @@ in { # No custom settings: just use stock configuration with a fix for Pipewire "system76-scheduler/config.kdl".source = "${cfg.package}/data/config.kdl"; "system76-scheduler/process-scheduler/00-dist.kdl".source = "${cfg.package}/data/pop_os.kdl"; - "system76-scheduler/process-scheduler/01-fix-pipewire-paths.kdl".source = ../../../../pkgs/os-specific/linux/system76-scheduler/01-fix-pipewire-paths.kdl; + "system76-scheduler/process-scheduler/01-fix-pipewire-paths.kdl".source = ../../../../pkgs/by-name/sy/system76-scheduler/01-fix-pipewire-paths.kdl; }) (let diff --git a/nixos/modules/services/desktops/telepathy.nix b/nixos/modules/services/desktops/telepathy.nix index b5f6a5fcbcfd..8f8adf7f4f83 100644 --- a/nixos/modules/services/desktops/telepathy.nix +++ b/nixos/modules/services/desktops/telepathy.nix @@ -1,13 +1,9 @@ # Telepathy daemon. - { config, lib, pkgs, ... }: - -with lib; - { meta = { - maintainers = teams.gnome.members; + maintainers = lib.teams.gnome.members; }; ###### interface @@ -16,8 +12,8 @@ with lib; services.telepathy = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable Telepathy service, a communications framework @@ -32,7 +28,7 @@ with lib; ###### implementation - config = mkIf config.services.telepathy.enable { + config = lib.mkIf config.services.telepathy.enable { environment.systemPackages = [ pkgs.telepathy-mission-control ]; diff --git a/nixos/modules/services/desktops/tumbler.nix b/nixos/modules/services/desktops/tumbler.nix index f5341df2f7a4..a52767301949 100644 --- a/nixos/modules/services/desktops/tumbler.nix +++ b/nixos/modules/services/desktops/tumbler.nix @@ -1,9 +1,5 @@ # Tumbler - { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.tumbler; @@ -13,13 +9,13 @@ in { imports = [ - (mkRemovedOptionModule + (lib.mkRemovedOptionModule [ "services" "tumbler" "package" ] "") ]; meta = with lib; { - maintainers = with maintainers; [ ] ++ teams.pantheon.members; + maintainers = with lib.maintainers; [ ] ++ lib.teams.pantheon.members; }; ###### interface @@ -28,7 +24,7 @@ in services.tumbler = { - enable = mkEnableOption "Tumbler, A D-Bus thumbnailer service"; + enable = lib.mkEnableOption "Tumbler, A D-Bus thumbnailer service"; }; @@ -37,7 +33,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs.xfce; [ tumbler diff --git a/nixos/modules/services/development/athens.nix b/nixos/modules/services/development/athens.nix index 55ec065f1689..ddd4699fea2a 100644 --- a/nixos/modules/services/development/athens.nix +++ b/nixos/modules/services/development/athens.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.athens; - athensConfig = flip recursiveUpdate cfg.extraConfig ( + athensConfig = lib.flip lib.recursiveUpdate cfg.extraConfig ( { GoBinary = "${cfg.goBinary}/bin/go"; GoEnv = cfg.goEnv; @@ -157,21 +154,21 @@ in }; options.services.athens = { - enable = mkEnableOption "Go module datastore and proxy"; + enable = lib.mkEnableOption "Go module datastore and proxy"; - package = mkOption { + package = lib.mkOption { default = pkgs.athens; - defaultText = literalExpression "pkgs.athens"; + defaultText = lib.literalExpression "pkgs.athens"; example = "pkgs.athens"; description = "Which athens derivation to use"; - type = types.package; + type = lib.types.package; }; - goBinary = mkOption { - type = types.package; + goBinary = lib.mkOption { + type = lib.types.package; default = pkgs.go; - defaultText = literalExpression "pkgs.go"; - example = "pkgs.go_1_21"; + defaultText = lib.literalExpression "pkgs.go"; + example = "pkgs.go_1_23"; description = '' The Go package used by Athens at runtime. @@ -181,15 +178,15 @@ in ''; }; - goEnv = mkOption { - type = types.enum [ "development" "production" ]; + goEnv = lib.mkOption { + type = lib.types.enum [ "development" "production" ]; description = "Specifies the type of environment to run. One of 'development' or 'production'."; default = "development"; example = "production"; }; - goBinaryEnvVars = mkOption { - type = types.attrs; + goBinaryEnvVars = lib.mkOption { + type = lib.types.attrs; description = "Environment variables to pass to the Go binary."; example = '' { "GOPROXY" = "direct", "GODEBUG" = "true" } @@ -197,15 +194,15 @@ in default = { }; }; - goGetWorkers = mkOption { - type = types.int; + goGetWorkers = lib.mkOption { + type = lib.types.int; description = "Number of workers concurrently downloading modules."; default = 10; example = 32; }; - goGetDir = mkOption { - type = types.nullOr types.path; + goGetDir = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' Temporary directory that Athens will use to fetch modules from VCS prior to persisting @@ -218,14 +215,14 @@ in example = "/tmp/athens"; }; - protocolWorkers = mkOption { - type = types.int; + protocolWorkers = lib.mkOption { + type = lib.types.int; description = "Number of workers concurrently serving protocol paths."; default = 30; }; - logLevel = mkOption { - type = types.nullOr (types.enum [ "panic" "fatal" "error" "warning" "info" "debug" "trace" ]); + logLevel = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "panic" "fatal" "error" "warning" "info" "debug" "trace" ]); description = '' Log level for Athens. Supports all logrus log levels (https://github.com/Sirupsen/logrus#level-logging)". @@ -234,8 +231,8 @@ in example = "debug"; }; - cloudRuntime = mkOption { - type = types.enum [ "GCP" "none" ]; + cloudRuntime = lib.mkOption { + type = lib.types.enum [ "GCP" "none" ]; description = '' Specifies the Cloud Provider on which the Proxy/registry is running. ''; @@ -243,24 +240,24 @@ in example = "GCP"; }; - enablePprof = mkOption { - type = types.bool; + enablePprof = lib.mkOption { + type = lib.types.bool; description = "Enable pprof endpoints."; default = false; }; - pprofPort = mkOption { - type = types.port; + pprofPort = lib.mkOption { + type = lib.types.port; description = "Port number for pprof endpoints."; default = 3301; example = 443; }; - filterFile = mkOption { - type = types.nullOr types.path; + filterFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = ''Filename for the include exclude filter.''; default = null; - example = literalExpression '' + example = lib.literalExpression '' pkgs.writeText "filterFile" ''' - github.com/azure + github.com/azure/azure-sdk-for-go @@ -269,42 +266,42 @@ in ''; }; - robotsFile = mkOption { - type = types.nullOr types.path; + robotsFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = ''Provides /robots.txt for net crawlers.''; default = null; - example = literalExpression ''pkgs.writeText "robots.txt" "# my custom robots.txt ..."''; + example = lib.literalExpression ''pkgs.writeText "robots.txt" "# my custom robots.txt ..."''; }; - timeout = mkOption { - type = types.int; + timeout = lib.mkOption { + type = lib.types.int; description = "Timeout for external network calls in seconds."; default = 300; example = 3; }; - storageType = mkOption { - type = types.enum [ "memory" "disk" "mongo" "gcp" "minio" "s3" "azureblob" "external" ]; + storageType = lib.mkOption { + type = lib.types.enum [ "memory" "disk" "mongo" "gcp" "minio" "s3" "azureblob" "external" ]; description = "Specifies the type of storage backend to use."; default = "disk"; }; - tlsCertFile = mkOption { - type = types.nullOr types.path; + tlsCertFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "Path to the TLS certificate file."; default = null; example = "/etc/ssl/certs/athens.crt"; }; - tlsKeyFile = mkOption { - type = types.nullOr types.path; + tlsKeyFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "Path to the TLS key file."; default = null; example = "/etc/ssl/certs/athens.key"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 3000; description = '' Port number Athens listens on. @@ -312,8 +309,8 @@ in example = 443; }; - unixSocket = mkOption { - type = types.nullOr types.path; + unixSocket = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' Path to the unix socket file. If set, Athens will listen on the unix socket instead of TCP socket. @@ -322,8 +319,8 @@ in example = "/run/athens.sock"; }; - globalEndpoint = mkOption { - type = types.str; + globalEndpoint = lib.mkOption { + type = lib.types.str; description = '' Endpoint for a package registry in case of a proxy cache miss. ''; @@ -331,8 +328,8 @@ in example = "http://upstream-athens.example.com:3000"; }; - basicAuthUser = mkOption { - type = types.nullOr types.str; + basicAuthUser = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Username for basic auth. ''; @@ -340,8 +337,8 @@ in example = "user"; }; - basicAuthPass = mkOption { - type = types.nullOr types.str; + basicAuthPass = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Password for basic auth. Warning: this is stored in plain text in the config file. ''; @@ -349,16 +346,16 @@ in example = "swordfish"; }; - forceSSL = mkOption { - type = types.bool; + forceSSL = lib.mkOption { + type = lib.types.bool; description = '' Force SSL redirects for incoming requests. ''; default = false; }; - validatorHook = mkOption { - type = types.nullOr types.str; + validatorHook = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Endpoint to validate modules against. @@ -368,8 +365,8 @@ in example = "https://validation.example.com"; }; - pathPrefix = mkOption { - type = types.nullOr types.str; + pathPrefix = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Sets basepath for all routes. ''; @@ -377,8 +374,8 @@ in example = "/athens"; }; - netrcPath = mkOption { - type = types.nullOr types.path; + netrcPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' Path to the .netrc file. ''; @@ -386,8 +383,8 @@ in example = "/home/user/.netrc"; }; - githubToken = mkOption { - type = types.nullOr types.str; + githubToken = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Creates .netrc file with the given token to be used for GitHub. Warning: this is stored in plain text in the config file. @@ -396,8 +393,8 @@ in example = "ghp_1234567890"; }; - hgrcPath = mkOption { - type = types.nullOr types.path; + hgrcPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = '' Path to the .hgrc file. ''; @@ -405,16 +402,16 @@ in example = "/home/user/.hgrc"; }; - traceExporter = mkOption { - type = types.nullOr (types.enum [ "jaeger" "datadog" ]); + traceExporter = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "jaeger" "datadog" ]); description = '' Trace exporter to use. ''; default = null; }; - traceExporterURL = mkOption { - type = types.nullOr types.str; + traceExporterURL = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' URL endpoint that traces will be sent to. ''; @@ -422,14 +419,14 @@ in example = "http://localhost:14268"; }; - statsExporter = mkOption { - type = types.nullOr (types.enum [ "prometheus" ]); + statsExporter = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "prometheus" ]); description = "Stats exporter to use."; default = null; }; - sumDBs = mkOption { - type = types.listOf types.str; + sumDBs = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of fully qualified URLs that Athens will proxy that the go command can use a checksum verifier. @@ -437,8 +434,8 @@ in default = [ "https://sum.golang.org" ]; }; - noSumPatterns = mkOption { - type = types.listOf types.str; + noSumPatterns = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of patterns that Athens sum db proxy will return a 403 for. ''; @@ -446,8 +443,8 @@ in example = [ "github.com/mycompany/*" ]; }; - downloadMode = mkOption { - type = types.oneOf [ (types.enum [ "sync" "async" "redirect" "async_redirect" "none" ]) (types.strMatching "^file:.*$|^custom:.*$") ]; + downloadMode = lib.mkOption { + type = lib.types.oneOf [ (lib.types.enum [ "sync" "async" "redirect" "async_redirect" "none" ]) (lib.types.strMatching "^file:.*$|^custom:.*$") ]; description = '' Defines how Athens behaves when a module@version is not found in storage. There are 7 options: @@ -470,8 +467,8 @@ in default = "async_redirect"; }; - networkMode = mkOption { - type = types.enum [ "strict" "offline" "fallback" ]; + networkMode = lib.mkOption { + type = lib.types.enum [ "strict" "offline" "fallback" ]; description = '' Configures how Athens will return the results of the /list endpoint as it can be assembled from both its own @@ -490,30 +487,30 @@ in default = "strict"; }; - downloadURL = mkOption { - type = types.str; + downloadURL = lib.mkOption { + type = lib.types.str; description = "URL used if DownloadMode is set to redirect."; default = "https://proxy.golang.org"; }; - singleFlightType = mkOption { - type = types.enum [ "memory" "etcd" "redis" "redis-sentinel" "gcp" "azureblob" ]; + singleFlightType = lib.mkOption { + type = lib.types.enum [ "memory" "etcd" "redis" "redis-sentinel" "gcp" "azureblob" ]; description = '' Determines what mechanism Athens uses to manage concurrency flowing into the Athens backend. ''; default = "memory"; }; - indexType = mkOption { - type = types.enum [ "none" "memory" "mysql" "postgres" ]; + indexType = lib.mkOption { + type = lib.types.enum [ "none" "memory" "mysql" "postgres" ]; description = '' Type of index backend Athens will use. ''; default = "none"; }; - shutdownTimeout = mkOption { - type = types.int; + shutdownTimeout = lib.mkOption { + type = lib.types.int; description = '' Number of seconds to wait for the server to shutdown gracefully. ''; @@ -523,42 +520,42 @@ in singleFlight = { etcd = { - endpoints = mkOption { - type = types.listOf types.str; + endpoints = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "URLs that determine all distributed etcd servers."; default = [ ]; example = [ "localhost:2379" ]; }; }; redis = { - endpoint = mkOption { - type = types.str; + endpoint = lib.mkOption { + type = lib.types.str; description = "URL of the redis server."; default = ""; example = "localhost:6379"; }; - password = mkOption { - type = types.str; + password = lib.mkOption { + type = lib.types.str; description = "Password for the redis server. Warning: this is stored in plain text in the config file."; default = ""; example = "swordfish"; }; lockConfig = { - ttl = mkOption { - type = types.int; + ttl = lib.mkOption { + type = lib.types.int; description = "TTL for the lock in seconds."; default = 900; example = 1; }; - timeout = mkOption { - type = types.int; + timeout = lib.mkOption { + type = lib.types.int; description = "Timeout for the lock in seconds."; default = 15; example = 1; }; - maxRetries = mkOption { - type = types.int; + maxRetries = lib.mkOption { + type = lib.types.int; description = "Maximum number of retries for the lock."; default = 10; example = 1; @@ -567,40 +564,40 @@ in }; redisSentinel = { - endpoints = mkOption { - type = types.listOf types.str; + endpoints = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "URLs that determine all distributed redis servers."; default = [ ]; example = [ "localhost:26379" ]; }; - masterName = mkOption { - type = types.str; + masterName = lib.mkOption { + type = lib.types.str; description = "Name of the sentinel master server."; default = ""; example = "redis-1"; }; - sentinelPassword = mkOption { - type = types.str; + sentinelPassword = lib.mkOption { + type = lib.types.str; description = "Password for the sentinel server. Warning: this is stored in plain text in the config file."; default = ""; example = "swordfish"; }; lockConfig = { - ttl = mkOption { - type = types.int; + ttl = lib.mkOption { + type = lib.types.int; description = "TTL for the lock in seconds."; default = 900; example = 1; }; - timeout = mkOption { - type = types.int; + timeout = lib.mkOption { + type = lib.types.int; description = "Timeout for the lock in seconds."; default = 15; example = 1; }; - maxRetries = mkOption { - type = types.int; + maxRetries = lib.mkOption { + type = lib.types.int; description = "Maximum number of retries for the lock."; default = 10; example = 1; @@ -611,8 +608,8 @@ in storage = { cdn = { - endpoint = mkOption { - type = types.nullOr types.str; + endpoint = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "hostname of the CDN server."; example = "cdn.example.com"; default = null; @@ -620,65 +617,65 @@ in }; disk = { - rootPath = mkOption { - type = types.nullOr types.path; + rootPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "Athens disk root folder."; default = "/var/lib/athens"; }; }; gcp = { - projectID = mkOption { - type = types.nullOr types.str; + projectID = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "GCP project ID."; example = "my-project"; default = null; }; - bucket = mkOption { - type = types.nullOr types.str; + bucket = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "GCP backend storage bucket."; example = "my-bucket"; default = null; }; - jsonKey = mkOption { - type = types.nullOr types.str; + jsonKey = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Base64 encoded GCP service account key. Warning: this is stored in plain text in the config file."; default = null; }; }; minio = { - endpoint = mkOption { - type = types.nullOr types.str; + endpoint = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Endpoint of the minio storage backend."; example = "minio.example.com:9001"; default = null; }; - key = mkOption { - type = types.nullOr types.str; + key = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Access key id for the minio storage backend."; example = "minio"; default = null; }; - secret = mkOption { - type = types.nullOr types.str; + secret = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Secret key for the minio storage backend. Warning: this is stored in plain text in the config file."; example = "minio123"; default = null; }; - enableSSL = mkOption { - type = types.bool; + enableSSL = lib.mkOption { + type = lib.types.bool; description = "Enable SSL for the minio storage backend."; default = false; }; - bucket = mkOption { - type = types.nullOr types.str; + bucket = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Bucket name for the minio storage backend."; example = "gomods"; default = null; }; - region = mkOption { - type = types.nullOr types.str; + region = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Region for the minio storage backend."; example = "us-east-1"; default = null; @@ -686,108 +683,108 @@ in }; mongo = { - url = mkOption { - type = types.nullOr types.str; + url = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "URL of the mongo database."; example = "mongodb://localhost:27017"; default = null; }; - defaultDBName = mkOption { - type = types.nullOr types.str; + defaultDBName = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Name of the mongo database."; example = "athens"; default = null; }; - certPath = mkOption { - type = types.nullOr types.path; + certPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "Path to the certificate file for the mongo database."; example = "/etc/ssl/mongo.pem"; default = null; }; - insecure = mkOption { - type = types.bool; + insecure = lib.mkOption { + type = lib.types.bool; description = "Allow insecure connections to the mongo database."; default = false; }; }; s3 = { - region = mkOption { - type = types.nullOr types.str; + region = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Region of the S3 storage backend."; example = "eu-west-3"; default = null; }; - key = mkOption { - type = types.nullOr types.str; + key = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Access key id for the S3 storage backend."; example = "minio"; default = null; }; - secret = mkOption { - type = types.str; + secret = lib.mkOption { + type = lib.types.str; description = "Secret key for the S3 storage backend. Warning: this is stored in plain text in the config file."; default = ""; }; - token = mkOption { - type = types.nullOr types.str; + token = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Token for the S3 storage backend. Warning: this is stored in plain text in the config file."; default = null; }; - bucket = mkOption { - type = types.nullOr types.str; + bucket = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Bucket name for the S3 storage backend."; example = "gomods"; default = null; }; - forcePathStyle = mkOption { - type = types.bool; + forcePathStyle = lib.mkOption { + type = lib.types.bool; description = "Force path style for the S3 storage backend."; default = false; }; - useDefaultConfiguration = mkOption { - type = types.bool; + useDefaultConfiguration = lib.mkOption { + type = lib.types.bool; description = "Use default configuration for the S3 storage backend."; default = false; }; - credentialsEndpoint = mkOption { - type = types.str; + credentialsEndpoint = lib.mkOption { + type = lib.types.str; description = "Credentials endpoint for the S3 storage backend."; default = ""; }; - awsContainerCredentialsRelativeURI = mkOption { - type = types.nullOr types.str; + awsContainerCredentialsRelativeURI = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Container relative url (used by fargate)."; default = null; }; - endpoint = mkOption { - type = types.nullOr types.str; + endpoint = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Endpoint for the S3 storage backend."; default = null; }; }; azureblob = { - accountName = mkOption { - type = types.nullOr types.str; + accountName = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Account name for the Azure Blob storage backend."; default = null; }; - accountKey = mkOption { - type = types.nullOr types.str; + accountKey = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Account key for the Azure Blob storage backend. Warning: this is stored in plain text in the config file."; default = null; }; - containerName = mkOption { - type = types.nullOr types.str; + containerName = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Container name for the Azure Blob storage backend."; default = null; }; }; external = { - url = mkOption { - type = types.nullOr types.str; + url = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "URL of the backend storage layer."; example = "https://athens.example.com"; default = null; @@ -797,44 +794,44 @@ in index = { mysql = { - protocol = mkOption { - type = types.str; + protocol = lib.mkOption { + type = lib.types.str; description = "Protocol for the MySQL database."; default = "tcp"; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; description = "Host for the MySQL database."; default = "localhost"; }; - port = mkOption { - type = types.int; + port = lib.mkOption { + type = lib.types.int; description = "Port for the MySQL database."; default = 3306; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = "User for the MySQL database."; default = "root"; }; - password = mkOption { - type = types.nullOr types.str; + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Password for the MySQL database. Warning: this is stored in plain text in the config file."; default = null; }; - database = mkOption { - type = types.str; + database = lib.mkOption { + type = lib.types.str; description = "Database name for the MySQL database."; default = "athens"; }; params = { - parseTime = mkOption { - type = types.nullOr types.str; + parseTime = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Parse time for the MySQL database."; default = "true"; }; - timeout = mkOption { - type = types.nullOr types.str; + timeout = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Timeout for the MySQL database."; default = "30s"; }; @@ -842,39 +839,39 @@ in }; postgres = { - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; description = "Host for the Postgres database."; default = "localhost"; }; - port = mkOption { - type = types.int; + port = lib.mkOption { + type = lib.types.int; description = "Port for the Postgres database."; default = 5432; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = "User for the Postgres database."; default = "postgres"; }; - password = mkOption { - type = types.nullOr types.str; + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Password for the Postgres database. Warning: this is stored in plain text in the config file."; default = null; }; - database = mkOption { - type = types.str; + database = lib.mkOption { + type = lib.types.str; description = "Database name for the Postgres database."; default = "athens"; }; params = { - connect_timeout = mkOption { - type = types.nullOr types.str; + connect_timeout = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "Connect timeout for the Postgres database."; default = "30s"; }; - sslmode = mkOption { - type = types.nullOr types.str; + sslmode = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = "SSL mode for the Postgres database."; default = "disable"; }; @@ -882,8 +879,8 @@ in }; }; - extraConfig = mkOption { - type = types.attrs; + extraConfig = lib.mkOption { + type = lib.types.attrs; description = '' Extra configuration options for the athens config file. ''; @@ -891,7 +888,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.athens = { description = "Athens Go module proxy"; documentation = [ "https://docs.gomods.io" ]; @@ -918,8 +915,8 @@ in ProtectHome = "read-only"; ProtectSystem = "full"; - ReadWritePaths = mkIf (cfg.storage.disk.rootPath != null && (! hasPrefix "/var/lib/" cfg.storage.disk.rootPath)) [ cfg.storage.disk.rootPath ]; - StateDirectory = mkIf (hasPrefix "/var/lib/" cfg.storage.disk.rootPath) [ (removePrefix "/var/lib/" cfg.storage.disk.rootPath) ]; + ReadWritePaths = lib.mkIf (cfg.storage.disk.rootPath != null && (! lib.hasPrefix "/var/lib/" cfg.storage.disk.rootPath)) [ cfg.storage.disk.rootPath ]; + StateDirectory = lib.mkIf (lib.hasPrefix "/var/lib/" cfg.storage.disk.rootPath) [ (lib.removePrefix "/var/lib/" cfg.storage.disk.rootPath) ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; @@ -928,8 +925,8 @@ in }; networking.firewall = { - allowedTCPPorts = optionals (cfg.unixSocket == null) [ cfg.port ] - ++ optionals cfg.enablePprof [ cfg.pprofPort ]; + allowedTCPPorts = lib.optionals (cfg.unixSocket == null) [ cfg.port ] + ++ lib.optionals cfg.enablePprof [ cfg.pprofPort ]; }; }; diff --git a/nixos/modules/services/development/distccd.nix b/nixos/modules/services/development/distccd.nix index 916c0905034c..7eb9789b5c38 100644 --- a/nixos/modules/services/development/distccd.nix +++ b/nixos/modules/services/development/distccd.nix @@ -1,17 +1,14 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.distccd; in { options = { services.distccd = { - enable = mkEnableOption "distccd, a distributed C/C++ compiler"; + enable = lib.mkEnableOption "distccd, a distributed C/C++ compiler"; - allowedClients = mkOption { - type = types.listOf types.str; + allowedClients = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "127.0.0.1" ]; example = [ "127.0.0.1" "192.168.0.0/24" "10.0.0.0/24" ]; description = '' @@ -23,16 +20,16 @@ in ''; }; - jobTimeout = mkOption { - type = types.nullOr types.int; + jobTimeout = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' Maximum duration, in seconds, of a single compilation request. ''; }; - logLevel = mkOption { - type = types.nullOr (types.enum [ "critical" "error" "warning" "notice" "info" "debug" ]); + logLevel = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "critical" "error" "warning" "notice" "info" "debug" ]); default = "warning"; description = '' Set the minimum severity of error that will be included in the log @@ -41,35 +38,35 @@ in ''; }; - maxJobs = mkOption { - type = types.nullOr types.int; + maxJobs = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' - Maximum number of tasks distccd should execute at any time. + Maximum number of tasks distccd should execute at lib.any time. ''; }; - nice = mkOption { - type = types.nullOr types.int; + nice = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' Niceness of the compilation tasks. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Opens the specified TCP port for distcc. ''; }; - package = mkPackageOption pkgs "distcc" { }; + package = lib.mkPackageOption pkgs "distcc" { }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 3632; description = '' The TCP port which distccd will listen on. @@ -77,9 +74,9 @@ in }; stats = { - enable = mkEnableOption "statistics reporting via HTTP server"; - port = mkOption { - type = types.port; + enable = lib.mkEnableOption "statistics reporting via HTTP server"; + port = lib.mkOption { + type = lib.types.port; default = 3633; description = '' The TCP port which the distccd statistics HTTP server will listen @@ -88,8 +85,8 @@ in }; }; - zeroconf = mkOption { - type = types.bool; + zeroconf = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to register via mDNS/DNS-SD @@ -98,10 +95,10 @@ in }; }; - config = mkIf cfg.enable { - networking.firewall = mkIf cfg.openFirewall { + config = lib.mkIf cfg.enable { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ] - ++ optionals cfg.stats.enable [ cfg.stats.port ]; + ++ lib.optionals cfg.stats.enable [ cfg.stats.port ]; }; systemd.services.distccd = { @@ -124,14 +121,14 @@ in --daemon \ --enable-tcp-insecure \ --port ${toString cfg.port} \ - ${optionalString (cfg.jobTimeout != null) "--job-lifetime ${toString cfg.jobTimeout}"} \ - ${optionalString (cfg.logLevel != null) "--log-level ${cfg.logLevel}"} \ - ${optionalString (cfg.maxJobs != null) "--jobs ${toString cfg.maxJobs}"} \ - ${optionalString (cfg.nice != null) "--nice ${toString cfg.nice}"} \ - ${optionalString cfg.stats.enable "--stats"} \ - ${optionalString cfg.stats.enable "--stats-port ${toString cfg.stats.port}"} \ - ${optionalString cfg.zeroconf "--zeroconf"} \ - ${concatMapStrings (c: "--allow ${c} ") cfg.allowedClients} + ${lib.optionalString (cfg.jobTimeout != null) "--job-lifetime ${toString cfg.jobTimeout}"} \ + ${lib.optionalString (cfg.logLevel != null) "--log-level ${cfg.logLevel}"} \ + ${lib.optionalString (cfg.maxJobs != null) "--jobs ${toString cfg.maxJobs}"} \ + ${lib.optionalString (cfg.nice != null) "--nice ${toString cfg.nice}"} \ + ${lib.optionalString cfg.stats.enable "--stats"} \ + ${lib.optionalString cfg.stats.enable "--stats-port ${toString cfg.stats.port}"} \ + ${lib.optionalString cfg.zeroconf "--zeroconf"} \ + ${lib.concatMapStrings (c: "--allow ${c} ") cfg.allowedClients} ''; }; }; diff --git a/nixos/modules/services/development/hoogle.nix b/nixos/modules/services/development/hoogle.nix index 1747ef391290..0a09a339e2be 100644 --- a/nixos/modules/services/development/hoogle.nix +++ b/nixos/modules/services/development/hoogle.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.hoogle; @@ -14,21 +11,21 @@ let in { options.services.hoogle = { - enable = mkEnableOption "Haskell documentation server"; + enable = lib.mkEnableOption "Haskell documentation server"; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = '' Port number Hoogle will be listening to. ''; }; - packages = mkOption { - type = types.functionTo (types.listOf types.package); + packages = lib.mkOption { + type = lib.types.functionTo (lib.types.listOf lib.types.package); default = hp: []; - defaultText = literalExpression "hp: []"; - example = literalExpression "hp: with hp; [ text lens ]"; + defaultText = lib.literalExpression "hp: []"; + example = lib.literalExpression "hp: with hp; [ text lens ]"; description = '' The Haskell packages to generate documentation for. @@ -38,27 +35,27 @@ in { ''; }; - haskellPackages = mkOption { + haskellPackages = lib.mkOption { description = "Which haskell package set to use."; - type = types.attrs; + type = lib.types.attrs; default = pkgs.haskellPackages; - defaultText = literalExpression "pkgs.haskellPackages"; + defaultText = lib.literalExpression "pkgs.haskellPackages"; }; - home = mkOption { - type = types.str; + home = lib.mkOption { + type = lib.types.str; description = "Url for hoogle logo"; default = "https://hoogle.haskell.org"; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; description = "Set the host to bind on."; default = "127.0.0.1"; }; - extraOptions = mkOption { - type = types.listOf types.str; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "--no-security-headers" ]; description = '' @@ -68,7 +65,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.hoogle = { description = "Haskell documentation server"; @@ -78,7 +75,7 @@ in { Restart = "always"; ExecStart = '' ${hoogleEnv}/bin/hoogle server --local --port ${toString cfg.port} --home ${cfg.home} --host ${cfg.host} \ - ${concatStringsSep " " cfg.extraOptions} + ${lib.concatStringsSep " " cfg.extraOptions} ''; DynamicUser = true; diff --git a/nixos/modules/services/development/jupyter/default.nix b/nixos/modules/services/development/jupyter/default.nix index 561ea86ea18b..d9687fdbf713 100644 --- a/nixos/modules/services/development/jupyter/default.nix +++ b/nixos/modules/services/development/jupyter/default.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.jupyter; @@ -21,13 +18,13 @@ let ''; in { - meta.maintainers = with maintainers; [ aborsu ]; + meta.maintainers = with lib.maintainers; [ aborsu ]; options.services.jupyter = { - enable = mkEnableOption "Jupyter development server"; + enable = lib.mkEnableOption "Jupyter development server"; - ip = mkOption { - type = types.str; + ip = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' IP address Jupyter will be listening on. @@ -37,10 +34,10 @@ in { # NOTE: We don't use top-level jupyter because we don't # want to pass in JUPYTER_PATH but use .environment instead, # saving a rebuild. - package = mkPackageOption pkgs [ "python3" "pkgs" "notebook" ] { }; + package = lib.mkPackageOption pkgs [ "python3" "pkgs" "notebook" ] { }; - command = mkOption { - type = types.str; + command = lib.mkOption { + type = lib.types.str; default = "jupyter-notebook"; example = "jupyter-lab"; description = '' @@ -49,24 +46,24 @@ in { ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8888; description = '' Port number Jupyter will be listening on. ''; }; - notebookDir = mkOption { - type = types.str; + notebookDir = lib.mkOption { + type = lib.types.str; default = "~/"; description = '' Root directory for notebooks. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "jupyter"; description = '' Name of the user used to run the jupyter service. @@ -76,8 +73,8 @@ in { example = "aborsu"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "jupyter"; description = '' Name of the group used to run the jupyter service. @@ -86,8 +83,8 @@ in { example = "users"; }; - password = mkOption { - type = types.str; + password = lib.mkOption { + type = lib.types.str; description = '' Password to use with notebook. Can be generated using: @@ -102,21 +99,21 @@ in { example = "'sha1:1b961dc713fb:88483270a63e57d18d43cf337e629539de1436ba'"; }; - notebookConfig = mkOption { - type = types.lines; + notebookConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Raw jupyter config. ''; }; - kernels = mkOption { - type = types.nullOr (types.attrsOf(types.submodule (import ./kernel-options.nix { + kernels = lib.mkOption { + type = lib.types.nullOr (lib.types.attrsOf(lib.types.submodule (import ./kernel-options.nix { inherit lib pkgs; }))); default = null; - example = literalExpression '' + example = lib.literalExpression '' { python3 = let env = (pkgs.python3.withPackages (pythonPackages: with pythonPackages; [ @@ -153,8 +150,8 @@ in { }; }; - config = mkMerge [ - (mkIf cfg.enable { + config = lib.mkMerge [ + (lib.mkIf cfg.enable { systemd.services.jupyter = { description = "Jupyter development server"; @@ -183,12 +180,12 @@ in { }; }; }) - (mkIf (cfg.enable && (cfg.group == "jupyter")) { + (lib.mkIf (cfg.enable && (cfg.group == "jupyter")) { users.groups.jupyter = {}; }) - (mkIf (cfg.enable && (cfg.user == "jupyter")) { + (lib.mkIf (cfg.enable && (cfg.user == "jupyter")) { users.extraUsers.jupyter = { - extraGroups = [ cfg.group ]; + inherit (cfg) group; home = "/var/lib/jupyter"; createHome = true; isSystemUser = true; diff --git a/nixos/modules/services/development/jupyter/kernel-options.nix b/nixos/modules/services/development/jupyter/kernel-options.nix index 8a91125e6cce..421e1a0cf51d 100644 --- a/nixos/modules/services/development/jupyter/kernel-options.nix +++ b/nixos/modules/services/development/jupyter/kernel-options.nix @@ -1,17 +1,14 @@ # Options that can be used for creating a jupyter kernel. { lib, pkgs }: - -with lib; - { freeformType = (pkgs.formats.json { }).type; options = { - displayName = mkOption { - type = types.str; + displayName = lib.mkOption { + type = lib.types.str; default = ""; - example = literalExpression '' + example = lib.literalExpression '' "Python 3" "Python 3 for Data Science" ''; @@ -20,8 +17,8 @@ with lib; ''; }; - argv = mkOption { - type = types.listOf types.str; + argv = lib.mkOption { + type = lib.types.listOf lib.types.str; example = [ "{customEnv.interpreter}" "-m" @@ -34,16 +31,16 @@ with lib; ''; }; - language = mkOption { - type = types.str; + language = lib.mkOption { + type = lib.types.str; example = "python"; description = '' Language of the environment. Typically the name of the binary. ''; }; - env = mkOption { - type = types.attrsOf types.str; + env = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = { }; example = { OMP_NUM_THREADS = "1"; }; description = '' @@ -51,27 +48,27 @@ with lib; ''; }; - logo32 = mkOption { - type = types.nullOr types.path; + logo32 = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; - example = literalExpression ''"''${env.sitePackages}/ipykernel/resources/logo-32x32.png"''; + example = lib.literalExpression ''"''${env.sitePackages}/ipykernel/resources/logo-32x32.png"''; description = '' Path to 32x32 logo png. ''; }; - logo64 = mkOption { - type = types.nullOr types.path; + logo64 = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; - example = literalExpression ''"''${env.sitePackages}/ipykernel/resources/logo-64x64.png"''; + example = lib.literalExpression ''"''${env.sitePackages}/ipykernel/resources/logo-64x64.png"''; description = '' Path to 64x64 logo png. ''; }; - extraPaths = mkOption { - type = types.attrsOf types.path; + extraPaths = lib.mkOption { + type = lib.types.attrsOf lib.types.path; default = { }; - example = literalExpression ''"{ examples = ''${env.sitePack}/IRkernel/kernelspec/kernel.js"; }''; + example = lib.literalExpression ''"{ examples = ''${env.sitePack}/IRkernel/kernelspec/kernel.js"; }''; description = '' Extra paths to link in kernel directory ''; diff --git a/nixos/modules/services/development/jupyterhub/default.nix b/nixos/modules/services/development/jupyterhub/default.nix index d9a37ad915d4..196d4aafabd4 100644 --- a/nixos/modules/services/development/jupyterhub/default.nix +++ b/nixos/modules/services/development/jupyterhub/default.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.jupyterhub; @@ -27,13 +24,13 @@ let ${cfg.extraConfig} ''; in { - meta.maintainers = with maintainers; [ costrouc ]; + meta.maintainers = with lib.maintainers; [ costrouc ]; options.services.jupyterhub = { - enable = mkEnableOption "Jupyterhub development server"; + enable = lib.mkEnableOption "Jupyterhub development server"; - authentication = mkOption { - type = types.str; + authentication = lib.mkOption { + type = lib.types.str; default = "jupyterhub.auth.PAMAuthenticator"; description = '' Jupyterhub authentication to use @@ -43,8 +40,8 @@ in { ''; }; - spawner = mkOption { - type = types.str; + spawner = lib.mkOption { + type = lib.types.str; default = "systemdspawner.SystemdSpawner"; description = '' Jupyterhub spawner to use @@ -54,8 +51,8 @@ in { ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra contents appended to the jupyterhub configuration @@ -72,13 +69,13 @@ in { ''; }; - jupyterhubEnv = mkOption { - type = types.package; + jupyterhubEnv = lib.mkOption { + type = lib.types.package; default = pkgs.python3.withPackages (p: with p; [ jupyterhub jupyterhub-systemdspawner ]); - defaultText = literalExpression '' + defaultText = lib.literalExpression '' pkgs.python3.withPackages (p: with p; [ jupyterhub jupyterhub-systemdspawner @@ -94,13 +91,13 @@ in { ''; }; - jupyterlabEnv = mkOption { - type = types.package; + jupyterlabEnv = lib.mkOption { + type = lib.types.package; default = pkgs.python3.withPackages (p: with p; [ jupyterhub jupyterlab ]); - defaultText = literalExpression '' + defaultText = lib.literalExpression '' pkgs.python3.withPackages (p: with p; [ jupyterhub jupyterlab @@ -117,13 +114,13 @@ in { ''; }; - kernels = mkOption { - type = types.nullOr (types.attrsOf(types.submodule (import ../jupyter/kernel-options.nix { + kernels = lib.mkOption { + type = lib.types.nullOr (lib.types.attrsOf(lib.types.submodule (import ../jupyter/kernel-options.nix { inherit lib pkgs; }))); default = null; - example = literalExpression '' + example = lib.literalExpression '' { python3 = let env = (pkgs.python3.withPackages (pythonPackages: with pythonPackages; [ @@ -156,24 +153,24 @@ in { ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8000; description = '' Port number Jupyterhub will be listening on ''; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = '' Bind IP JupyterHub will be listening on ''; }; - stateDirectory = mkOption { - type = types.str; + stateDirectory = lib.mkOption { + type = lib.types.str; default = "jupyterhub"; description = '' Directory for jupyterhub state (token + database) @@ -181,8 +178,8 @@ in { }; }; - config = mkMerge [ - (mkIf cfg.enable { + config = lib.mkMerge [ + (lib.mkIf cfg.enable { systemd.services.jupyterhub = { description = "Jupyterhub development server"; diff --git a/nixos/modules/services/development/livebook.nix b/nixos/modules/services/development/livebook.nix index 859083635201..ca227e2ad22c 100644 --- a/nixos/modules/services/development/livebook.nix +++ b/nixos/modules/services/development/livebook.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.livebook; in @@ -10,12 +8,12 @@ in # either has access to all the data or none at all), the decision # was made to run this as a user service. If that changes in the # future, this can be changed to a system service. - enableUserService = mkEnableOption "a user service for Livebook"; + enableUserService = lib.mkEnableOption "a user service for Livebook"; - package = mkPackageOption pkgs "livebook" { }; + package = lib.mkPackageOption pkgs "livebook" { }; - environment = mkOption { - type = with types; attrsOf (nullOr (oneOf [ bool int str ])); + environment = lib.mkOption { + type = with lib.types; attrsOf (nullOr (oneOf [ bool int str ])); default = { }; description = '' Environment variables to set. @@ -37,18 +35,18 @@ in variables specified in this option. ''; - example = literalExpression '' + example = lib.literalExpression '' { LIVEBOOK_PORT = 8080; } ''; }; - environmentFile = mkOption { - type = with types; nullOr types.path; + environmentFile = lib.mkOption { + type = with lib.types; nullOr lib.types.path; default = null; description = '' - Additional dnvironment file as defined in {manpage}`systemd.exec(5)`. + Additional environment file as defined in {manpage}`systemd.exec(5)`. Secrets like {env}`LIVEBOOK_PASSWORD` (which is used to specify the password needed to access the livebook site) or {env}`LIVEBOOK_COOKIE` @@ -72,17 +70,17 @@ in example = "/var/lib/livebook.env"; }; - extraPackages = mkOption { - type = with types; listOf package; + extraPackages = lib.mkOption { + type = with lib.types; listOf package; default = [ ]; description = '' Extra packages to make available to the Livebook service. ''; - example = literalExpression "with pkgs; [ gcc gnumake ]"; + example = lib.literalExpression "with pkgs; [ gcc gnumake ]"; }; }; - config = mkIf cfg.enableUserService { + config = lib.mkIf cfg.enableUserService { systemd.user.services.livebook = { serviceConfig = { Restart = "always"; @@ -97,8 +95,8 @@ in # stuck running a `cat /dev/urandom | tr | fold` pipeline. IgnoreSIGPIPE = false; }; - environment = mapAttrs (name: value: - if isBool value then boolToString value else toString value) + environment = lib.mapAttrs (name: value: + if lib.isBool value then lib.boolToString value else toString value) cfg.environment; path = [ pkgs.bash ] ++ cfg.extraPackages; wantedBy = [ "default.target" ]; diff --git a/nixos/modules/services/development/rstudio-server/default.nix b/nixos/modules/services/development/rstudio-server/default.nix index 0126e105b3d3..70f665b09e31 100644 --- a/nixos/modules/services/development/rstudio-server/default.nix +++ b/nixos/modules/services/development/rstudio-server/default.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.rstudio-server; @@ -18,41 +15,41 @@ let in { - meta.maintainers = with maintainers; [ jbedo cfhammill ]; + meta.maintainers = with lib.maintainers; [ jbedo cfhammill ]; options.services.rstudio-server = { - enable = mkEnableOption "RStudio server"; + enable = lib.mkEnableOption "RStudio server"; - serverWorkingDir = mkOption { - type = types.str; + serverWorkingDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/rstudio-server"; description = '' Default working directory for server (server-working-dir in rserver.conf). ''; }; - listenAddr = mkOption { - type = types.str; + listenAddr = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Address to listen on (www-address in rserver.conf). ''; }; - package = mkPackageOption pkgs "rstudio-server" { + package = lib.mkPackageOption pkgs "rstudio-server" { example = "rstudioServerWrapper.override { packages = [ pkgs.rPackages.ggplot2 ]; }"; }; - rserverExtraConfig = mkOption { - type = types.str; + rserverExtraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = '' Extra contents for rserver.conf. ''; }; - rsessionExtraConfig = mkOption { - type = types.str; + rsessionExtraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = '' Extra contents for resssion.conf. @@ -61,7 +58,7 @@ in }; - config = mkIf cfg.enable + config = lib.mkIf cfg.enable { systemd.services.rstudio-server = { description = "Rstudio server"; diff --git a/nixos/modules/services/development/zammad.nix b/nixos/modules/services/development/zammad.nix index 0659c48e815e..43ae9a34b404 100644 --- a/nixos/modules/services/development/zammad.nix +++ b/nixos/modules/services/development/zammad.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.zammad; settingsFormat = pkgs.formats.yaml { }; - filterNull = filterAttrs (_: v: v != null); + filterNull = lib.filterAttrs (_: v: v != null); serviceConfig = { Type = "simple"; Restart = "always"; @@ -29,88 +26,88 @@ in options = { services.zammad = { - enable = mkEnableOption "Zammad, a web-based, open source user support/ticketing solution"; + enable = lib.mkEnableOption "Zammad, a web-based, open source user support/ticketing solution"; - package = mkPackageOption pkgs "zammad" { }; + package = lib.mkPackageOption pkgs "zammad" { }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/zammad"; description = '' Path to a folder that will contain Zammad working directory. ''; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; example = "192.168.23.42"; description = "Host address."; }; - openPorts = mkOption { - type = types.bool; + openPorts = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to open firewall ports for Zammad"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 3000; description = "Web service port."; }; - websocketPort = mkOption { - type = types.port; + websocketPort = lib.mkOption { + type = lib.types.port; default = 6042; description = "Websocket service port."; }; redis = { - createLocally = mkOption { - type = types.bool; + createLocally = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to create a local redis automatically."; }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = "zammad"; description = '' Name of the redis server. Only used if `createLocally` is set to true. ''; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' Redis server address. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 6379; description = "Port of the redis server."; }; }; database = { - type = mkOption { - type = types.enum [ "PostgreSQL" "MySQL" ]; + type = lib.mkOption { + type = lib.types.enum [ "PostgreSQL" "MySQL" ]; default = "PostgreSQL"; example = "MySQL"; description = "Database engine to use."; }; - host = mkOption { - type = types.nullOr types.str; + host = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = { PostgreSQL = "/run/postgresql"; MySQL = "localhost"; }.${cfg.database.type}; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' { PostgreSQL = "/run/postgresql"; MySQL = "localhost"; @@ -121,28 +118,28 @@ in ''; }; - port = mkOption { - type = types.nullOr types.port; + port = lib.mkOption { + type = lib.types.nullOr lib.types.port; default = null; description = "Database port. Use `null` for default port."; }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = "zammad"; description = '' Database name. ''; }; - user = mkOption { - type = types.nullOr types.str; + user = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "zammad"; description = "Database user."; }; - passwordFile = mkOption { - type = types.nullOr types.path; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/run/keys/zammad-dbpassword"; description = '' @@ -150,16 +147,16 @@ in ''; }; - createLocally = mkOption { - type = types.bool; + createLocally = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to create a local database automatically."; }; - settings = mkOption { + settings = lib.mkOption { type = settingsFormat.type; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { } ''; @@ -171,8 +168,8 @@ in }; }; - secretKeyBaseFile = mkOption { - type = types.nullOr types.path; + secretKeyBaseFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/run/keys/secret_key_base"; description = '' @@ -197,10 +194,10 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.zammad.database.settings = { - production = mapAttrs (_: v: mkDefault v) (filterNull { + production = lib.mapAttrs (_: v: lib.mkDefault v) (filterNull { adapter = { PostgreSQL = "postgresql"; MySQL = "mysql2"; @@ -215,7 +212,7 @@ in }); }; - networking.firewall.allowedTCPPorts = mkIf cfg.openPorts [ + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openPorts [ config.services.zammad.port config.services.zammad.websocketPort ]; @@ -243,9 +240,9 @@ in } ]; - services.mysql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") { + services.mysql = lib.optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") { enable = true; - package = mkDefault pkgs.mariadb; + package = lib.mkDefault pkgs.mariadb; ensureDatabases = [ cfg.database.name ]; ensureUsers = [ { @@ -255,7 +252,7 @@ in ]; }; - services.postgresql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "PostgreSQL") { + services.postgresql = lib.optionalAttrs (cfg.database.createLocally && cfg.database.type == "PostgreSQL") { enable = true; ensureDatabases = [ cfg.database.name ]; ensureUsers = [ @@ -266,7 +263,7 @@ in ]; }; - services.redis = optionalAttrs cfg.redis.createLocally { + services.redis = lib.optionalAttrs cfg.redis.createLocally { servers."${cfg.redis.name}" = { enable = true; port = cfg.redis.port; @@ -282,7 +279,7 @@ in after = [ "network.target" "postgresql.service" - ] ++ optionals cfg.redis.createLocally [ + ] ++ lib.optionals cfg.redis.createLocally [ "redis-${cfg.redis.name}.service" ]; requires = [ @@ -301,13 +298,13 @@ in # config file cp ${databaseConfig} ./config/database.yml chmod -R +w . - ${optionalString (cfg.database.passwordFile != null) '' + ${lib.optionalString (cfg.database.passwordFile != null) '' { echo -n " password: " cat ${cfg.database.passwordFile} } >> ./config/database.yml ''} - ${optionalString (cfg.secretKeyBaseFile != null) '' + ${lib.optionalString (cfg.secretKeyBaseFile != null) '' { echo "production: " echo -n " secret_key_base: " @@ -317,7 +314,7 @@ in if [ `${config.services.postgresql.package}/bin/psql \ --host ${cfg.database.host} \ - ${optionalString + ${lib.optionalString (cfg.database.port != null) "--port ${toString cfg.database.port}"} \ --username ${cfg.database.user} \ diff --git a/nixos/modules/services/display-managers/greetd.nix b/nixos/modules/services/display-managers/greetd.nix index 118a3e1df378..9774b6a4d12e 100644 --- a/nixos/modules/services/display-managers/greetd.nix +++ b/nixos/modules/services/display-managers/greetd.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.greetd; tty = "tty${toString cfg.vt}"; @@ -8,13 +6,13 @@ let in { options.services.greetd = { - enable = mkEnableOption "greetd, a minimal and flexible login manager daemon"; + enable = lib.mkEnableOption "greetd, a minimal and flexible login manager daemon"; - package = mkPackageOption pkgs [ "greetd" "greetd" ] { }; + package = lib.mkPackageOption pkgs [ "greetd" "greetd" ] { }; - settings = mkOption { + settings = lib.mkOption { type = settingsFormat.type; - example = literalExpression '' + example = lib.literalExpression '' { default_session = { command = "''${pkgs.greetd.greetd}/bin/agreety --cmd sway"; @@ -27,8 +25,8 @@ in ''; }; - greeterManagesPlymouth = mkOption { - type = types.bool; + greeterManagesPlymouth = lib.mkOption { + type = lib.types.bool; internal = true; default = false; description = '' @@ -38,18 +36,18 @@ in ''; }; - vt = mkOption { - type = types.int; + vt = lib.mkOption { + type = lib.types.int; default = 1; description = '' The virtual console (tty) that greetd should use. This option also disables getty on that tty. ''; }; - restart = mkOption { - type = types.bool; + restart = lib.mkOption { + type = lib.types.bool; default = !(cfg.settings ? initial_session); - defaultText = literalExpression "!(config.services.greetd.settings ? initial_session)"; + defaultText = lib.literalExpression "!(config.services.greetd.settings ? initial_session)"; description = '' Whether to restart greetd when it terminates (e.g. on failure). This is usually desirable so a user can always log in, but should be disabled when using 'settings.initial_session' (autologin), @@ -57,15 +55,15 @@ in ''; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - services.greetd.settings.terminal.vt = mkDefault cfg.vt; - services.greetd.settings.default_session.user = mkDefault "greeter"; + services.greetd.settings.terminal.vt = lib.mkDefault cfg.vt; + services.greetd.settings.default_session.user = lib.mkDefault "greeter"; security.pam.services.greetd = { allowNullPassword = true; startSession = true; - enableGnomeKeyring = mkDefault config.services.gnome.gnome-keyring.enable; + enableGnomeKeyring = lib.mkDefault config.services.gnome.gnome-keyring.enable; }; # This prevents nixos-rebuild from killing greetd by activating getty again @@ -95,7 +93,7 @@ in serviceConfig = { ExecStart = "${pkgs.greetd.greetd}/bin/greetd --config ${settingsFormat.generate "greetd.toml" cfg.settings}"; - Restart = mkIf cfg.restart "on-success"; + Restart = lib.mkIf cfg.restart "on-success"; # Defaults from greetd upstream configuration IgnoreSIGPIPE = false; @@ -128,5 +126,5 @@ in users.groups.greeter = { }; }; - meta.maintainers = with maintainers; [ queezle ]; + meta.maintainers = with lib.maintainers; [ queezle ]; } diff --git a/nixos/modules/services/display-managers/ly.nix b/nixos/modules/services/display-managers/ly.nix index 5d42467a6cd8..9475f183a16d 100644 --- a/nixos/modules/services/display-managers/ly.nix +++ b/nixos/modules/services/display-managers/ly.nix @@ -96,6 +96,7 @@ in security.pam.services.ly = { startSession = true; unixAuth = true; + enableGnomeKeyring = lib.mkDefault config.services.gnome.gnome-keyring.enable; }; environment = { diff --git a/nixos/modules/services/display-managers/sddm.nix b/nixos/modules/services/display-managers/sddm.nix index 54356f7bb617..ca46d627101a 100644 --- a/nixos/modules/services/display-managers/sddm.nix +++ b/nixos/modules/services/display-managers/sddm.nix @@ -8,6 +8,7 @@ let sddm = cfg.package.override (old: { withWayland = cfg.wayland.enable; + withLayerShellQt = cfg.wayland.compositor == "kwin"; extraPackages = old.extraPackages or [ ] ++ cfg.extraPackages; }); @@ -43,11 +44,8 @@ let DefaultSession = optionalString (config.services.displayManager.defaultSession != null) "${config.services.displayManager.defaultSession}.desktop"; DisplayServer = if cfg.wayland.enable then "wayland" else "x11"; - } // optionalAttrs (cfg.wayland.compositor == "kwin") { - GreeterEnvironment = concatStringsSep " " [ - "LANG=C.UTF-8" - "QT_WAYLAND_SHELL_INTEGRATION=layer-shell" - ]; + } // optionalAttrs (cfg.wayland.enable && cfg.wayland.compositor == "kwin") { + GreeterEnvironment = "QT_WAYLAND_SHELL_INTEGRATION=layer-shell"; InputMethod = ""; # needed if we are using --inputmethod with kwin }; diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix index 98d8506e6727..ee1951e26222 100644 --- a/nixos/modules/services/editors/emacs.nix +++ b/nixos/modules/services/editors/emacs.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.emacs; @@ -18,8 +15,8 @@ in { options.services.emacs = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable a user service for the Emacs daemon. Use `emacsclient` to connect to the @@ -28,8 +25,8 @@ in ''; }; - install = mkOption { - type = types.bool; + install = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to install a user service for the Emacs daemon. Once @@ -43,10 +40,10 @@ in }; - package = mkPackageOption pkgs "emacs" { }; + package = lib.mkPackageOption pkgs "emacs" { }; - defaultEditor = mkOption { - type = types.bool; + defaultEditor = lib.mkOption { + type = lib.types.bool; default = false; description = '' When enabled, configures emacsclient to be the default editor @@ -54,17 +51,17 @@ in ''; }; - startWithGraphical = mkOption { - type = types.bool; + startWithGraphical = lib.mkOption { + type = lib.types.bool; default = config.services.xserver.enable; - defaultText = literalExpression "config.services.xserver.enable"; + defaultText = lib.literalExpression "config.services.xserver.enable"; description = '' Start emacs with the graphical session instead of any session. Without this, emacs clients will not be able to create frames in the graphical session. ''; }; }; - config = mkIf (cfg.enable || cfg.install) { + config = lib.mkIf (cfg.enable || cfg.install) { systemd.user.services.emacs = { description = "Emacs: the extensible, self-documenting text editor"; @@ -75,16 +72,16 @@ in Restart = "always"; }; - unitConfig = optionalAttrs cfg.startWithGraphical { + unitConfig = lib.optionalAttrs cfg.startWithGraphical { After = "graphical-session.target"; }; - } // optionalAttrs cfg.enable { + } // lib.optionalAttrs cfg.enable { wantedBy = if cfg.startWithGraphical then [ "graphical-session.target" ] else [ "default.target" ]; }; environment.systemPackages = [ cfg.package editorScript ]; - environment.variables.EDITOR = mkIf cfg.defaultEditor (mkOverride 900 "emacseditor"); + environment.variables.EDITOR = lib.mkIf cfg.defaultEditor (lib.mkOverride 900 "emacseditor"); }; meta.doc = ./emacs.md; diff --git a/nixos/modules/services/editors/haste.nix b/nixos/modules/services/editors/haste.nix index f2a40e62e718..cf5bde6a5865 100644 --- a/nixos/modules/services/editors/haste.nix +++ b/nixos/modules/services/editors/haste.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let pkg = pkgs.haste-server; cfg = config.services.haste-server; @@ -10,10 +7,10 @@ let in { options.services.haste-server = { - enable = mkEnableOption "haste-server"; - openFirewall = mkEnableOption "firewall passthrough for haste-server"; + enable = lib.mkEnableOption "haste-server"; + openFirewall = lib.mkEnableOption "firewall passthrough for haste-server"; - settings = mkOption { + settings = lib.mkOption { description = '' Configuration for haste-server. For documentation see [project readme](https://github.com/toptal/haste-server#settings) @@ -22,21 +19,21 @@ in }; }; - config = mkIf (cfg.enable) { - networking.firewall.allowedTCPPorts = mkIf (cfg.openFirewall) [ cfg.settings.port ]; + config = lib.mkIf (cfg.enable) { + networking.firewall.allowedTCPPorts = lib.mkIf (cfg.openFirewall) [ cfg.settings.port ]; services.haste-server = { settings = { - host = mkDefault "::"; - port = mkDefault 7777; + host = lib.mkDefault "::"; + port = lib.mkDefault 7777; - keyLength = mkDefault 10; - maxLength = mkDefault 400000; + keyLength = lib.mkDefault 10; + maxLength = lib.mkDefault 400000; - staticMaxAge = mkDefault 86400; - recompressStaticAssets = mkDefault false; + staticMaxAge = lib.mkDefault 86400; + recompressStaticAssets = lib.mkDefault false; - logging = mkDefault [ + logging = lib.mkDefault [ { level = "verbose"; type = "Console"; @@ -44,25 +41,25 @@ in } ]; - keyGenerator = mkDefault { + keyGenerator = lib.mkDefault { type = "phonetic"; }; rateLimits = { categories = { normal = { - totalRequests = mkDefault 500; - every = mkDefault 60000; + totalRequests = lib.mkDefault 500; + every = lib.mkDefault 60000; }; }; }; - storage = mkDefault { + storage = lib.mkDefault { type = "file"; }; documents = { - about = mkDefault "${pkg}/share/haste-server/about.md"; + about = lib.mkDefault "${pkg}/share/haste-server/about.md"; }; }; }; diff --git a/nixos/modules/services/editors/infinoted.nix b/nixos/modules/services/editors/infinoted.nix index 2a7f1d45c2d8..b6e353b637e8 100644 --- a/nixos/modules/services/editors/infinoted.nix +++ b/nixos/modules/services/editors/infinoted.nix @@ -1,33 +1,30 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.infinoted; in { options.services.infinoted = { - enable = mkEnableOption "infinoted"; + enable = lib.mkEnableOption "infinoted"; - package = mkPackageOption pkgs "libinfinity" { }; + package = lib.mkPackageOption pkgs "libinfinity" { }; - keyFile = mkOption { - type = types.nullOr types.path; + keyFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Private key to use for TLS ''; }; - certificateFile = mkOption { - type = types.nullOr types.path; + certificateFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Server certificate to use for TLS ''; }; - certificateChain = mkOption { - type = types.nullOr types.path; + certificateChain = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Chain of CA-certificates to which our `certificateFile` is relative. @@ -35,48 +32,48 @@ in { ''; }; - securityPolicy = mkOption { - type = types.enum ["no-tls" "allow-tls" "require-tls"]; + securityPolicy = lib.mkOption { + type = lib.types.enum ["no-tls" "allow-tls" "require-tls"]; default = "require-tls"; description = '' How strictly to enforce clients connection with TLS. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 6523; description = '' Port to listen on ''; }; - rootDirectory = mkOption { - type = types.path; + rootDirectory = lib.mkOption { + type = lib.types.path; default = "/var/lib/infinoted/documents/"; description = '' Root of the directory structure to serve ''; }; - plugins = mkOption { - type = types.listOf types.str; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "note-text" "note-chat" "logging" "autosave" ]; description = '' Plugins to enable ''; }; - passwordFile = mkOption { - type = types.nullOr types.path; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File to read server-wide password from ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = '' [autosave] interval=10 @@ -86,16 +83,16 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "infinoted"; description = '' What to call the dedicated user under which infinoted is run ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "infinoted"; description = '' What to call the primary group of the dedicated user under which infinoted is run @@ -103,15 +100,15 @@ in { }; }; - config = mkIf (cfg.enable) { - users.users = optionalAttrs (cfg.user == "infinoted") + config = lib.mkIf (cfg.enable) { + users.users = lib.optionalAttrs (cfg.user == "infinoted") { infinoted = { description = "Infinoted user"; group = cfg.group; isSystemUser = true; }; }; - users.groups = optionalAttrs (cfg.group == "infinoted") + users.groups = lib.optionalAttrs (cfg.group == "infinoted") { infinoted = { }; }; @@ -134,14 +131,14 @@ in { install -o ${cfg.user} -g ${cfg.group} -m 0600 /dev/null /var/lib/infinoted/infinoted.conf cat >>/var/lib/infinoted/infinoted.conf < ''; - example = literalExpression '' + example = lib.literalExpression '' options = { db_user = "odoo"; db_password="odoo"; @@ -45,18 +42,18 @@ in ''; }; - domain = mkOption { - type = with types; nullOr str; + domain = lib.mkOption { + type = with lib.types; nullOr str; description = "Domain to host Odoo with nginx"; default = null; }; }; }; - config = mkIf (cfg.enable) (let + config = lib.mkIf (cfg.enable) (let cfgFile = format.generate "odoo.cfg" cfg.settings; in { - services.nginx = mkIf (cfg.domain != null) { + services.nginx = lib.mkIf (cfg.domain != null) { upstreams = { odoo.servers = { "127.0.0.1:8069" = {}; @@ -98,7 +95,7 @@ in data_dir = "/var/lib/private/odoo/data"; proxy_mode = cfg.domain != null; } // (lib.optionalAttrs (cfg.addons != []) { - addons_path = concatMapStringsSep "," escapeShellArg cfg.addons; + addons_path = lib.concatMapStringsSep "," lib.escapeShellArg cfg.addons; }); users.users.odoo = { @@ -137,7 +134,7 @@ in echo "pre-start: auto-init" INITIALIZED="${cfg.settings.options.data_dir}/.odoo.initialized" if [ ! -e "$INITIALIZED" ]; then - ${cfg.package}/bin/odoo --init=INIT --database=odoo --db_user=odoo --stop-after-init ${concatStringsSep " " cfg.autoInitExtraFlags} + ${cfg.package}/bin/odoo --init=INIT --database=odoo --db_user=odoo --stop-after-init ${lib.concatStringsSep " " cfg.autoInitExtraFlags} touch "$INITIALIZED" fi '') diff --git a/nixos/modules/services/games/crossfire-server.nix b/nixos/modules/services/games/crossfire-server.nix index 314b4bad9a29..91a684873c2a 100644 --- a/nixos/modules/services/games/crossfire-server.nix +++ b/nixos/modules/services/games/crossfire-server.nix @@ -1,21 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.crossfire-server; serverPort = 13327; in { options.services.crossfire-server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, the Crossfire game server will be started at boot. ''; }; - package = mkPackageOption pkgs "crossfire-server" { + package = lib.mkPackageOption pkgs "crossfire-server" { extraDescription = '' ::: {.note} This will also be used for map/arch data, if you don't change {option}`dataDir` @@ -23,10 +20,10 @@ in { ''; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "${cfg.package}/share/crossfire"; - defaultText = literalExpression ''"''${config.services.crossfire.package}/share/crossfire"''; + defaultText = lib.literalExpression ''"''${config.services.crossfire.package}/share/crossfire"''; description = '' Where to load readonly data from -- maps, archetypes, treasure tables, and the like. If you plan to edit the data on the live server (rather @@ -36,8 +33,8 @@ in { ''; }; - stateDir = mkOption { - type = types.str; + stateDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/crossfire"; description = '' Where to store runtime data (save files, persistent items, etc). @@ -49,16 +46,16 @@ in { ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to open ports in the firewall for the server. ''; }; - configFiles = mkOption { - type = types.attrsOf types.str; + configFiles = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = '' Text to append to the corresponding configuration files. Note that the files given in the example are *not* the complete set of files available @@ -70,7 +67,7 @@ in { overwrite the example files that come with the server, rather than being appended to them as the other configuration files are. ''; - example = literalExpression '' + example = lib.literalExpression '' { dm_file = ''' admin:secret_password:localhost @@ -101,7 +98,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.crossfire = { description = "Crossfire server daemon user"; home = cfg.stateDir; @@ -120,8 +117,8 @@ in { (name: value: lib.attrsets.nameValuePair "crossfire/${name}" { mode = "0644"; text = - (optionalString (!elem name ["motd" "news" "rules"]) - (fileContents "${cfg.package}/etc/crossfire/${name}")) + (lib.optionalString (!lib.elem name ["motd" "news" "rules"]) + (lib.fileContents "${cfg.package}/etc/crossfire/${name}")) + "\n${value}"; }) ({ ban_file = ""; @@ -129,9 +126,9 @@ in { exp_table = ""; forbid = ""; metaserver2 = ""; - motd = fileContents "${cfg.package}/etc/crossfire/motd"; - news = fileContents "${cfg.package}/etc/crossfire/news"; - rules = fileContents "${cfg.package}/etc/crossfire/rules"; + motd = lib.fileContents "${cfg.package}/etc/crossfire/motd"; + news = lib.fileContents "${cfg.package}/etc/crossfire/news"; + rules = lib.fileContents "${cfg.package}/etc/crossfire/rules"; settings = ""; stat_bonus = ""; } // cfg.configFiles); @@ -141,7 +138,7 @@ in { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - serviceConfig = mkMerge [ + serviceConfig = lib.mkMerge [ { ExecStart = "${cfg.package}/bin/crossfire-server -conf /etc/crossfire -local '${cfg.stateDir}' -data '${cfg.dataDir}'"; Restart = "always"; @@ -149,7 +146,7 @@ in { Group = "crossfire"; WorkingDirectory = cfg.stateDir; } - (mkIf (cfg.stateDir == "/var/lib/crossfire") { + (lib.mkIf (cfg.stateDir == "/var/lib/crossfire") { StateDirectory = "crossfire"; }) ]; @@ -170,7 +167,7 @@ in { ''; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ serverPort ]; }; }; diff --git a/nixos/modules/services/games/deliantra-server.nix b/nixos/modules/services/games/deliantra-server.nix index 401a453ba932..0bb9cea92c7e 100644 --- a/nixos/modules/services/games/deliantra-server.nix +++ b/nixos/modules/services/games/deliantra-server.nix @@ -1,21 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.deliantra-server; serverPort = 13327; in { options.services.deliantra-server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, the Deliantra game server will be started at boot. ''; }; - package = mkPackageOption pkgs "deliantra-server" { + package = lib.mkPackageOption pkgs "deliantra-server" { extraDescription = '' ::: {.note} This will also be used for map/arch data, if you don't change {option}`dataDir` @@ -23,10 +20,10 @@ in { ''; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "${pkgs.deliantra-data}"; - defaultText = literalExpression ''"''${pkgs.deliantra-data}"''; + defaultText = lib.literalExpression ''"''${pkgs.deliantra-data}"''; description = '' Where to store readonly data (maps, archetypes, sprites, etc). Note that if you plan to use the live map editor (rather than editing @@ -36,8 +33,8 @@ in { ''; }; - stateDir = mkOption { - type = types.str; + stateDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/deliantra"; description = '' Where to store runtime data (save files, persistent items, etc). @@ -49,16 +46,16 @@ in { ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to open ports in the firewall for the server. ''; }; - configFiles = mkOption { - type = types.attrsOf types.str; + configFiles = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = '' Contents of the server configuration files. These will be appended to the example configurations the server comes with and overwrite any @@ -67,7 +64,7 @@ in { The example here is not comprehensive. See the files in /etc/deliantra-server after enabling this module for full documentation. ''; - example = literalExpression '' + example = lib.literalExpression '' { dm_file = ''' admin:secret_password:localhost @@ -92,7 +89,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.deliantra = { description = "Deliantra server daemon user"; home = cfg.stateDir; @@ -113,8 +110,8 @@ in { text = # Deliantra doesn't come with a motd file, but respects it if present # in /etc. - (optionalString (name != "motd") - (fileContents "${cfg.package}/etc/deliantra-server/${name}")) + (lib.optionalString (name != "motd") + (lib.fileContents "${cfg.package}/etc/deliantra-server/${name}")) + "\n${value}"; }) ({ motd = ""; @@ -134,7 +131,7 @@ in { DELIANTRA_CONFDIR="/etc/deliantra-server"; }; - serviceConfig = mkMerge [ + serviceConfig = lib.mkMerge [ { ExecStart = "${cfg.package}/bin/deliantra-server"; Restart = "always"; @@ -142,7 +139,7 @@ in { Group = "deliantra"; WorkingDirectory = cfg.stateDir; } - (mkIf (cfg.stateDir == "/var/lib/deliantra") { + (lib.mkIf (cfg.stateDir == "/var/lib/deliantra") { StateDirectory = "deliantra"; }) ]; @@ -163,7 +160,7 @@ in { ''; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ serverPort ]; }; }; diff --git a/nixos/modules/services/games/factorio.nix b/nixos/modules/services/games/factorio.nix index 3dce60163a0e..a9a4f386e060 100644 --- a/nixos/modules/services/games/factorio.nix +++ b/nixos/modules/services/games/factorio.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.factorio; name = "Factorio"; @@ -37,7 +34,7 @@ let autosave_only_on_server = true; non_blocking_saving = cfg.nonBlockingSaving; } // cfg.extraSettings; - serverSettingsString = builtins.toJSON (filterAttrsRecursive (n: v: v != null) serverSettings); + serverSettingsString = builtins.toJSON (lib.filterAttrsRecursive (n: v: v != null) serverSettings); serverSettingsFile = pkgs.writeText "server-settings.json" serverSettingsString; serverAdminsFile = pkgs.writeText "server-adminlist.json" (builtins.toJSON cfg.admins); modDir = pkgs.factorio-utils.mkModDirDrv cfg.mods cfg.mods-dat; @@ -45,25 +42,25 @@ in { options = { services.factorio = { - enable = mkEnableOption name; - port = mkOption { - type = types.port; + enable = lib.mkEnableOption name; + port = lib.mkOption { + type = lib.types.port; default = 34197; description = '' The port to which the service should bind. ''; }; - bind = mkOption { - type = types.str; + bind = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = '' The address to which the service should bind. ''; }; - admins = mkOption { - type = types.listOf types.str; + admins = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "username" ]; description = '' @@ -71,15 +68,15 @@ in ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to automatically open the specified UDP port in the firewall. ''; }; - saveName = mkOption { - type = types.str; + saveName = lib.mkOption { + type = lib.types.str; default = "default"; description = '' The name of the savegame that will be used by the server. @@ -88,8 +85,8 @@ in a new map with default settings will be generated before starting the service. ''; }; - loadLatestSave = mkOption { - type = types.bool; + loadLatestSave = lib.mkOption { + type = lib.types.bool; default = false; description = '' Load the latest savegame on startup. This overrides saveName, in that the latest @@ -104,10 +101,10 @@ in # TODO XXX The server tries to copy a newly created config file over the old one # on shutdown, but fails, because it's in the nix store. When is this needed? # Can an admin set options in-game and expect to have them persisted? - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = configFile; - defaultText = literalExpression "configFile"; + defaultText = lib.literalExpression "configFile"; description = '' The server's configuration file. @@ -116,8 +113,8 @@ in customizations. ''; }; - extraSettingsFile = mkOption { - type = types.nullOr types.path; + extraSettingsFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File, which is dynamically applied to server-settings.json before @@ -133,8 +130,8 @@ in ``` ''; }; - stateDirName = mkOption { - type = types.str; + stateDirName = lib.mkOption { + type = lib.types.str; default = "factorio"; description = '' Name of the directory under /var/lib holding the server's data. @@ -142,8 +139,8 @@ in The configuration and map will be stored here. ''; }; - mods = mkOption { - type = types.listOf types.package; + mods = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; description = '' Mods the server should install and activate. @@ -154,8 +151,8 @@ in derivations via nixos-channel. Until then, this is for experts only. ''; }; - mods-dat = mkOption { - type = types.nullOr types.path; + mods-dat = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Mods settings can be changed by specifying a dat file, in the [mod @@ -163,44 +160,44 @@ in format](https://wiki.factorio.com/Mod_settings_file_format). ''; }; - game-name = mkOption { - type = types.nullOr types.str; + game-name = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "Factorio Game"; description = '' Name of the game as it will appear in the game listing. ''; }; - description = mkOption { - type = types.nullOr types.str; + description = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = ""; description = '' Description of the game that will appear in the listing. ''; }; - extraSettings = mkOption { - type = types.attrs; + extraSettings = lib.mkOption { + type = lib.types.attrs; default = {}; example = { admins = [ "username" ];}; description = '' Extra game configuration that will go into server-settings.json ''; }; - public = mkOption { - type = types.bool; + public = lib.mkOption { + type = lib.types.bool; default = false; description = '' Game will be published on the official Factorio matching server. ''; }; - lan = mkOption { - type = types.bool; + lan = lib.mkOption { + type = lib.types.bool; default = false; description = '' Game will be broadcast on LAN. ''; }; - username = mkOption { - type = types.nullOr types.str; + username = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Your factorio.com login credentials. Required for games with visibility public. @@ -208,11 +205,11 @@ in This option is insecure. Use extraSettingsFile instead. ''; }; - package = mkPackageOption pkgs "factorio-headless" { + package = lib.mkPackageOption pkgs "factorio-headless" { example = "factorio-headless-experimental"; }; - password = mkOption { - type = types.nullOr types.str; + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Your factorio.com login credentials. Required for games with visibility public. @@ -220,15 +217,15 @@ in This option is insecure. Use extraSettingsFile instead. ''; }; - token = mkOption { - type = types.nullOr types.str; + token = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Authentication token. May be used instead of 'password' above. ''; }; - game-password = mkOption { - type = types.nullOr types.str; + game-password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Game password. @@ -236,23 +233,23 @@ in This option is insecure. Use extraSettingsFile instead. ''; }; - requireUserVerification = mkOption { - type = types.bool; + requireUserVerification = lib.mkOption { + type = lib.types.bool; default = true; description = '' When set to true, the server will only allow clients that have a valid factorio.com account. ''; }; - autosave-interval = mkOption { - type = types.nullOr types.int; + autosave-interval = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 10; description = '' Autosave interval in minutes. ''; }; - nonBlockingSaving = mkOption { - type = types.bool; + nonBlockingSaving = lib.mkOption { + type = lib.types.bool; default = false; description = '' Highly experimental feature, enable only at your own risk of losing your saves. @@ -263,7 +260,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.factorio = { description = "Factorio headless server"; wantedBy = [ "multi-user.target" ]; @@ -276,9 +273,9 @@ in "${cfg.package}/bin/factorio" "--config=${cfg.configFile}" "--create=${mkSavePath cfg.saveName}" - (optionalString (cfg.mods != []) "--mod-directory=${modDir}") + (lib.optionalString (cfg.mods != []) "--mod-directory=${modDir}") ]) - + (optionalString (cfg.extraSettingsFile != null) ("\necho ${lib.strings.escapeShellArg serverSettingsString}" + + (lib.optionalString (cfg.extraSettingsFile != null) ("\necho ${lib.strings.escapeShellArg serverSettingsString}" + " \"$(cat ${cfg.extraSettingsFile})\" | ${lib.getExe pkgs.jq} -s add" + " > ${stateDir}/server-settings.json")); @@ -293,15 +290,15 @@ in "--config=${cfg.configFile}" "--port=${toString cfg.port}" "--bind=${cfg.bind}" - (optionalString (!cfg.loadLatestSave) "--start-server=${mkSavePath cfg.saveName}") + (lib.optionalString (!cfg.loadLatestSave) "--start-server=${mkSavePath cfg.saveName}") "--server-settings=${ if (cfg.extraSettingsFile != null) then "${stateDir}/server-settings.json" else serverSettingsFile }" - (optionalString cfg.loadLatestSave "--start-server-load-latest") - (optionalString (cfg.mods != []) "--mod-directory=${modDir}") - (optionalString (cfg.admins != []) "--server-adminlist=${serverAdminsFile}") + (lib.optionalString cfg.loadLatestSave "--start-server-load-latest") + (lib.optionalString (cfg.mods != []) "--mod-directory=${modDir}") + (lib.optionalString (cfg.admins != []) "--server-adminlist=${serverAdminsFile}") ]; # Sandboxing @@ -320,6 +317,6 @@ in }; }; - networking.firewall.allowedUDPPorts = optional cfg.openFirewall cfg.port; + networking.firewall.allowedUDPPorts = lib.optional cfg.openFirewall cfg.port; }; } diff --git a/nixos/modules/services/games/freeciv.nix b/nixos/modules/services/games/freeciv.nix index e4c05af3caba..fc73824e6920 100644 --- a/nixos/modules/services/games/freeciv.nix +++ b/nixos/modules/services/games/freeciv.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.freeciv; inherit (config.users) groups; @@ -16,31 +15,31 @@ let generate = name: value: let mkParam = k: v: if v == null then [] - else if isBool v then optional v ("--"+k) + else if lib.isBool v then lib.optional v ("--"+k) else [("--"+k) v]; - mkParams = k: v: map (mkParam k) (if isList v then v else [v]); - in escapeShellArgs (concatLists (concatLists (mapAttrsToList mkParams value))); + mkParams = k: v: map (mkParam k) (if lib.isList v then v else [v]); + in lib.escapeShellArgs (lib.concatLists (lib.concatLists (lib.mapAttrsToList mkParams value))); }; in { options = { services.freeciv = { - enable = mkEnableOption ''freeciv''; - settings = mkOption { + enable = lib.mkEnableOption ''freeciv''; + settings = lib.mkOption { description = '' Parameters of freeciv-server. ''; default = {}; - type = types.submodule { + type = lib.types.submodule { freeformType = argsFormat.type; - options.Announce = mkOption { - type = types.enum ["IPv4" "IPv6" "none"]; + options.Announce = lib.mkOption { + type = lib.types.enum ["IPv4" "IPv6" "none"]; default = "none"; description = "Announce game in LAN using given protocol."; }; - options.auth = mkEnableOption "server authentication"; - options.Database = mkOption { - type = types.nullOr types.str; + options.auth = lib.mkEnableOption "server authentication"; + options.Database = lib.mkOption { + type = lib.types.nullOr lib.types.str; apply = pkgs.writeText "auth.conf"; default = '' [fcdb] @@ -49,34 +48,34 @@ in ''; description = "Enable database connection with given configuration."; }; - options.debug = mkOption { - type = types.ints.between 0 3; + options.debug = lib.mkOption { + type = lib.types.ints.between 0 3; default = 0; description = "Set debug log level."; }; - options.exit-on-end = mkEnableOption "exit instead of restarting when a game ends"; - options.Guests = mkEnableOption "guests to login if auth is enabled"; - options.Newusers = mkEnableOption "new users to login if auth is enabled"; - options.port = mkOption { - type = types.port; + options.exit-on-end = lib.mkEnableOption "exit instead of restarting when a game ends"; + options.Guests = lib.mkEnableOption "guests to login if auth is enabled"; + options.Newusers = lib.mkEnableOption "new users to login if auth is enabled"; + options.port = lib.mkOption { + type = lib.types.port; default = 5556; description = "Listen for clients on given port"; }; - options.quitidle = mkOption { - type = types.nullOr types.int; + options.quitidle = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = "Quit if no players for given time in seconds."; }; - options.read = mkOption { - type = types.lines; + options.read = lib.mkOption { + type = lib.types.lines; apply = v: pkgs.writeTextDir "read.serv" v + "/read"; default = '' /fcdb lua sqlite_createdb() ''; description = "Startup script."; }; - options.saves = mkOption { - type = types.nullOr types.str; + options.saves = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "/var/lib/freeciv/saves/"; description = '' Save games to given directory, @@ -86,10 +85,10 @@ in }; }; }; - openFirewall = mkEnableOption "opening the firewall for the port listening for clients"; + openFirewall = lib.mkEnableOption "opening the firewall for the port listening for clients"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.groups.freeciv = {}; # Use with: # journalctl -u freeciv.service -f -o cat & @@ -119,8 +118,8 @@ in set -eux savedir=$(date +%Y-%m-%d_%H-%M-%S) '' + "${pkgs.freeciv}/bin/freeciv-server" - + " " + optionalString (cfg.settings.saves != null) - (concatStringsSep " " [ "--saves" "${escapeShellArg cfg.settings.saves}/$savedir" ]) + + " " + lib.optionalString (cfg.settings.saves != null) + (lib.concatStringsSep " " [ "--saves" "${lib.escapeShellArg cfg.settings.saves}/$savedir" ]) + " " + argsFormat.generate "freeciv-server" (cfg.settings // { saves = null; })); DynamicUser = true; # Create rootDir in the host's mount namespace. @@ -152,7 +151,7 @@ in NoNewPrivileges = true; PrivateDevices = true; PrivateMounts = true; - PrivateNetwork = mkDefault false; + PrivateNetwork = lib.mkDefault false; PrivateTmp = true; PrivateUsers = true; ProtectClock = true; @@ -180,7 +179,7 @@ in SystemCallErrorNumber = "EPERM"; }; }; - networking.firewall = mkIf cfg.openFirewall + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.settings.port ]; }; }; meta.maintainers = with lib.maintainers; [ julm ]; diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix index 00af8dce6603..bc56feffb748 100644 --- a/nixos/modules/services/games/minecraft-server.nix +++ b/nixos/modules/services/games/minecraft-server.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.minecraft-server; @@ -13,13 +10,13 @@ let whitelistFile = pkgs.writeText "whitelist.json" (builtins.toJSON - (mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist)); + (lib.mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist)); - cfgToString = v: if builtins.isBool v then boolToString v else toString v; + cfgToString = v: if builtins.isBool v then lib.boolToString v else toString v; serverPropertiesFile = pkgs.writeText "server.properties" ('' # server.properties managed by NixOS configuration - '' + concatStringsSep "\n" (mapAttrsToList + '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: "${n}=${cfgToString v}") cfg.serverProperties)); stopScript = pkgs.writeShellScript "minecraft-server-stop" '' @@ -51,8 +48,8 @@ in { options = { services.minecraft-server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, start a Minecraft Server. The server @@ -61,8 +58,8 @@ in { ''; }; - declarative = mkOption { - type = types.bool; + declarative = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to use a declarative Minecraft server configuration. @@ -73,8 +70,8 @@ in { ''; }; - eula = mkOption { - type = types.bool; + eula = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether you agree to @@ -84,29 +81,29 @@ in { ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/minecraft"; description = '' Directory to store Minecraft database and other state/data files. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to open ports in the firewall for the server. ''; }; - whitelist = mkOption { + whitelist = lib.mkOption { type = let - minecraftUUID = types.strMatching + minecraftUUID = lib.types.strMatching "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // { description = "Minecraft UUID"; }; - in types.attrsOf minecraftUUID; + in lib.types.attrsOf minecraftUUID; default = {}; description = '' Whitelisted players, only has an effect when @@ -118,7 +115,7 @@ in { You can use to get a Minecraft UUID for a username. ''; - example = literalExpression '' + example = lib.literalExpression '' { username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"; @@ -126,10 +123,10 @@ in { ''; }; - serverProperties = mkOption { - type = with types; attrsOf (oneOf [ bool int str ]); + serverProperties = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ bool int str ]); default = {}; - example = literalExpression '' + example = lib.literalExpression '' { server-port = 43000; difficulty = 3; @@ -150,12 +147,12 @@ in { ''; }; - package = mkPackageOption pkgs "minecraft-server" { + package = lib.mkPackageOption pkgs "minecraft-server" { example = "minecraft-server_1_12_2"; }; - jvmOpts = mkOption { - type = types.separatedString " "; + jvmOpts = lib.mkOption { + type = lib.types.separatedString " "; default = "-Xmx2048M -Xms2048M"; # Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script example = "-Xms4092M -Xmx4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing " @@ -166,7 +163,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.minecraft = { description = "Minecraft server service user"; @@ -259,11 +256,11 @@ in { ''); }; - networking.firewall = mkIf cfg.openFirewall (if cfg.declarative then { + networking.firewall = lib.mkIf cfg.openFirewall (if cfg.declarative then { allowedUDPPorts = [ serverPort ]; allowedTCPPorts = [ serverPort ] - ++ optional (queryPort != null) queryPort - ++ optional (rconPort != null) rconPort; + ++ lib.optional (queryPort != null) queryPort + ++ lib.optional (rconPort != null) rconPort; } else { allowedUDPPorts = [ defaultServerPort ]; allowedTCPPorts = [ defaultServerPort ]; diff --git a/nixos/modules/services/games/minetest-server.nix b/nixos/modules/services/games/minetest-server.nix index 7fa687d2c7ed..98613e4391ef 100644 --- a/nixos/modules/services/games/minetest-server.nix +++ b/nixos/modules/services/games/minetest-server.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let CONTAINS_NEWLINE_RE = ".*\n.*"; # The following values are reserved as complete option values: @@ -53,14 +50,14 @@ in { options = { services.minetest-server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "If enabled, starts a Minetest Server."; }; - gameId = mkOption { - type = types.nullOr types.str; + gameId = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Id of the game to use. To list available games run @@ -70,8 +67,8 @@ in ''; }; - world = mkOption { - type = types.nullOr types.path; + world = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Name of the world to use. To list available worlds run @@ -81,8 +78,8 @@ in ''; }; - configPath = mkOption { - type = types.nullOr types.path; + configPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to the config to use. @@ -92,8 +89,8 @@ in ''; }; - config = mkOption { - type = types.attrsOf types.anything; + config = lib.mkOption { + type = lib.types.attrsOf lib.types.anything; default = {}; description = '' Settings to add to the minetest config file. @@ -102,8 +99,8 @@ in ''; }; - logPath = mkOption { - type = types.nullOr types.path; + logPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to logfile for logging. @@ -113,8 +110,8 @@ in ''; }; - port = mkOption { - type = types.nullOr types.int; + port = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' Port number to bind to. @@ -123,8 +120,8 @@ in ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Additional command line flags to pass to the minetest executable. @@ -133,7 +130,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.minetest = { description = "Minetest Server Service user"; home = "/var/lib/minetest"; diff --git a/nixos/modules/services/games/teeworlds.nix b/nixos/modules/services/games/teeworlds.nix index b9ed49937a7f..f12647149573 100644 --- a/nixos/modules/services/games/teeworlds.nix +++ b/nixos/modules/services/games/teeworlds.nix @@ -1,13 +1,10 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.teeworlds; register = cfg.register; bool = b: if b != null && b then "1" else "0"; - optionalSetting = s: setting: optionalString (s != null) "${setting} ${s}"; + optionalSetting = s: setting: lib.optionalString (s != null) "${setting} ${s}"; lookup = attrs: key: default: if attrs ? key then attrs."${key}" else default; inactivePenaltyOptions = { @@ -86,33 +83,33 @@ let sv_vote_kick_bantime ${toString cfg.game.voteKickBanTime} sv_vote_kick_min ${toString cfg.game.voteKickMinimumPlayers} - ${concatStringsSep "\n" cfg.extraOptions} + ${lib.concatStringsSep "\n" cfg.extraOptions} ''; in { options = { services.teeworlds = { - enable = mkEnableOption "Teeworlds Server"; + enable = lib.mkEnableOption "Teeworlds Server"; - package = mkPackageOption pkgs "teeworlds-server" { }; + package = lib.mkPackageOption pkgs "teeworlds-server" { }; - openPorts = mkOption { - type = types.bool; + openPorts = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to open firewall ports for Teeworlds."; }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = "unnamed server"; description = '' Name of the server. ''; }; - register = mkOption { - type = types.bool; + register = lib.mkOption { + type = lib.types.bool; example = true; default = false; description = '' @@ -120,40 +117,40 @@ in ''; }; - motd = mkOption { - type = types.nullOr types.str; + motd = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The server's message of the day text. ''; }; - password = mkOption { - type = types.nullOr types.str; + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Password to connect to the server. ''; }; - rconPassword = mkOption { - type = types.nullOr types.str; + rconPassword = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Password to access the remote console. If not set, a randomly generated one is displayed in the server log. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8303; description = '' Port the server will listen on. ''; }; - extraOptions = mkOption { - type = types.listOf types.str; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Extra configuration lines for the {file}`teeworlds.cfg`. See [Teeworlds Documentation](https://www.teeworlds.com/?page=docs&wiki=server_settings). @@ -162,32 +159,32 @@ in }; server = { - bindAddr = mkOption { - type = types.nullOr types.str; + bindAddr = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The address the server will bind to. ''; }; - enableHighBandwidth = mkOption { - type = types.bool; + enableHighBandwidth = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable high bandwidth mode on LAN servers. This will double the amount of bandwidth required for running the server. ''; }; - hostName = mkOption { - type = types.nullOr types.str; + hostName = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Hostname for the server. ''; }; - inactivePenalty = mkOption { - type = types.enum [ "spectator" "spectator/kick" "kick" ]; + inactivePenalty = lib.mkOption { + type = lib.types.enum [ "spectator" "spectator/kick" "kick" ]; example = "spectator"; default = "spectator/kick"; description = '' @@ -201,48 +198,48 @@ in ''; }; - kickInactiveSpectators = mkOption { - type = types.bool; + kickInactiveSpectators = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to kick inactive spectators. ''; }; - inactiveTime = mkOption { - type = types.ints.unsigned; + inactiveTime = lib.mkOption { + type = lib.types.ints.unsigned; default = 3; description = '' The amount of minutes a client has to idle before it is considered inactive. ''; }; - maxClients = mkOption { - type = types.ints.unsigned; + maxClients = lib.mkOption { + type = lib.types.ints.unsigned; default = 12; description = '' The maximum amount of clients that can be connected to the server at the same time. ''; }; - maxClientsPerIP = mkOption { - type = types.ints.unsigned; + maxClientsPerIP = lib.mkOption { + type = lib.types.ints.unsigned; default = 12; description = '' The maximum amount of clients with the same IP address that can be connected to the server at the same time. ''; }; - skillLevel = mkOption { - type = types.enum [ "casual" "normal" "competitive" ]; + skillLevel = lib.mkOption { + type = lib.types.enum [ "casual" "normal" "competitive" ]; default = "normal"; description = '' The skill level shown in the server browser. ''; }; - enableSpamProtection = mkOption { - type = types.bool; + enableSpamProtection = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable chat spam protection. @@ -251,8 +248,8 @@ in }; game = { - gameType = mkOption { - type = types.str; + gameType = lib.mkOption { + type = lib.types.str; example = "ctf"; default = "dm"; description = '' @@ -262,8 +259,8 @@ in ''; }; - map = mkOption { - type = types.str; + map = lib.mkOption { + type = lib.types.str; example = "ctf5"; default = "dm1"; description = '' @@ -271,16 +268,16 @@ in ''; }; - swapTeams = mkOption { - type = types.bool; + swapTeams = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to swap teams each round. ''; }; - enableReadyMode = mkOption { - type = types.bool; + enableReadyMode = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable "ready mode"; where players can pause/unpause the game @@ -288,24 +285,24 @@ in ''; }; - playerSlots = mkOption { - type = types.ints.unsigned; + playerSlots = lib.mkOption { + type = lib.types.ints.unsigned; default = 8; description = '' The amount of slots to reserve for players (as opposed to spectators). ''; }; - enablePowerups = mkOption { - type = types.bool; + enablePowerups = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to allow powerups such as the ninja. ''; }; - scoreLimit = mkOption { - type = types.ints.unsigned; + scoreLimit = lib.mkOption { + type = lib.types.ints.unsigned; example = 400; default = 20; description = '' @@ -313,24 +310,24 @@ in ''; }; - restrictSpectators = mkOption { - type = types.bool; + restrictSpectators = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to restrict access to information such as health, ammo and armour in spectator mode. ''; }; - enableTeamDamage = mkOption { - type = types.bool; + enableTeamDamage = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable team damage; whether to allow team mates to inflict damage on one another. ''; }; - timeLimit = mkOption { - type = types.ints.unsigned; + timeLimit = lib.mkOption { + type = lib.types.ints.unsigned; default = 0; description = '' Time limit of the game. In cases of equal points, there will be sudden death. @@ -338,8 +335,8 @@ in ''; }; - tournamentMode = mkOption { - type = types.enum [ "disable" "enable" "restrictSpectators" ]; + tournamentMode = lib.mkOption { + type = lib.types.enum [ "disable" "enable" "restrictSpectators" ]; default = "disable"; description = '' Whether to enable tournament mode. In tournament mode, players join as spectators. @@ -347,35 +344,62 @@ in ''; }; - enableVoteKick = mkOption { - type = types.bool; + enableVoteKick = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable voting to kick players. ''; }; - voteKickBanTime = mkOption { - type = types.ints.unsigned; + voteKickBanTime = lib.mkOption { + type = lib.types.ints.unsigned; default = 5; description = '' The amount of minutes that a player is banned for if they get kicked by a vote. ''; }; - voteKickMinimumPlayers = mkOption { - type = types.ints.unsigned; + voteKickMinimumPlayers = lib.mkOption { + type = lib.types.ints.unsigned; default = 5; description = '' The minimum amount of players required to start a kick vote. ''; }; }; + + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/var/lib/teeworlds/teeworlds.env"; + description = '' + Environment file as defined in {manpage}`systemd.exec(5)`. + + Secrets may be passed to the service without adding them to the world-readable + Nix store, by specifying placeholder variables as the option value in Nix and + setting these variables accordingly in the environment file. + + ``` + # snippet of teeworlds-related config + services.teeworlds.password = "$TEEWORLDS_PASSWORD"; + ``` + + ``` + # content of the environment file + TEEWORLDS_PASSWORD=verysecretpassword + ``` + + Note that this file needs to be available on the host on which + `teeworlds` is running. + ''; + }; + }; }; - config = mkIf cfg.enable { - networking.firewall = mkIf cfg.openPorts { + config = lib.mkIf cfg.enable { + networking.firewall = lib.mkIf cfg.openPorts { allowedUDPPorts = [ cfg.port ]; }; @@ -386,7 +410,15 @@ in serviceConfig = { DynamicUser = true; - ExecStart = "${cfg.package}/bin/teeworlds_srv -f ${teeworldsConf}"; + RuntimeDirectory = "teeworlds"; + RuntimeDirectoryMode = "0700"; + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + ExecStartPre = '' + ${pkgs.envsubst}/bin/envsubst \ + -i ${teeworldsConf} \ + -o /run/teeworlds/teeworlds.yaml + ''; + ExecStart = "${lib.getExe cfg.package} -f /run/teeworlds/teeworlds.yaml"; # Hardening CapabilityBoundingSet = false; diff --git a/nixos/modules/services/games/terraria.nix b/nixos/modules/services/games/terraria.nix index 4c32cc92a1b9..144186dc7701 100644 --- a/nixos/modules/services/games/terraria.nix +++ b/nixos/modules/services/games/terraria.nix @@ -1,13 +1,10 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.terraria; opt = options.services.terraria; worldSizeMap = { small = 1; medium = 2; large = 3; }; - valFlag = name: val: optionalString (val != null) "-${name} \"${escape ["\\" "\""] (toString val)}\""; - boolFlag = name: val: optionalString val "-${name}"; + valFlag = name: val: lib.optionalString (val != null) "-${name} \"${lib.escape ["\\" "\""] (toString val)}\""; + boolFlag = name: val: lib.optionalString val "-${name}"; flags = [ (valFlag "port" cfg.port) (valFlag "maxPlayers" cfg.maxPlayers) @@ -46,8 +43,8 @@ in { options = { services.terraria = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, starts a Terraria server. The server can be connected to via `tmux -S ''${config.${opt.dataDir}}/terraria.sock attach` @@ -55,40 +52,40 @@ in ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 7777; description = '' Specifies the port to listen on. ''; }; - maxPlayers = mkOption { - type = types.ints.u8; + maxPlayers = lib.mkOption { + type = lib.types.ints.u8; default = 255; description = '' Sets the max number of players (between 1 and 255). ''; }; - password = mkOption { - type = types.nullOr types.str; + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Sets the server password. Leave `null` for no password. ''; }; - messageOfTheDay = mkOption { - type = types.nullOr types.str; + messageOfTheDay = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Set the server message of the day text. ''; }; - worldPath = mkOption { - type = types.nullOr types.path; + worldPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' The path to the world file (`.wld`) which should be loaded. @@ -97,8 +94,8 @@ in ''; }; - autoCreatedWorldSize = mkOption { - type = types.enum [ "small" "medium" "large" ]; + autoCreatedWorldSize = lib.mkOption { + type = lib.types.enum [ "small" "medium" "large" ]; default = "medium"; description = '' Specifies the size of the auto-created world if `worldPath` does not @@ -106,34 +103,34 @@ in ''; }; - banListPath = mkOption { - type = types.nullOr types.path; + banListPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' The path to the ban list. ''; }; - secure = mkOption { - type = types.bool; + secure = lib.mkOption { + type = lib.types.bool; default = false; description = "Adds additional cheat protection to the server."; }; - noUPnP = mkOption { - type = types.bool; + noUPnP = lib.mkOption { + type = lib.types.bool; default = false; description = "Disables automatic Universal Plug and Play."; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to open ports in the firewall"; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/terraria"; example = "/srv/terraria"; description = "Path to variable state data directory for terraria."; @@ -141,7 +138,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.terraria = { description = "Terraria server service user"; group = "terraria"; @@ -165,12 +162,12 @@ in Type = "forking"; GuessMainPID = true; UMask = 007; - ExecStart = "${tmuxCmd} new -d ${pkgs.terraria-server}/bin/TerrariaServer ${concatStringsSep " " flags}"; + ExecStart = "${tmuxCmd} new -d ${pkgs.terraria-server}/bin/TerrariaServer ${lib.concatStringsSep " " flags}"; ExecStop = "${stopScript} $MAINPID"; }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; allowedUDPPorts = [ cfg.port ]; }; diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix index 581b6cb40136..357f692801b4 100644 --- a/nixos/modules/services/hardware/acpid.nix +++ b/nixos/modules/services/hardware/acpid.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.acpid; @@ -34,7 +31,7 @@ let echo "event=${handler.event}" > $fn echo "action=${pkgs.writeShellScriptBin "${name}.sh" handler.action }/bin/${name}.sh '%e'" >> $fn ''; - in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // cfg.handlers)) + in lib.concatStringsSep "\n" (lib.mapAttrsToList f (canonicalHandlers // cfg.handlers)) } ''; @@ -48,25 +45,25 @@ in services.acpid = { - enable = mkEnableOption "the ACPI daemon"; + enable = lib.mkEnableOption "the ACPI daemon"; - logEvents = mkOption { - type = types.bool; + logEvents = lib.mkOption { + type = lib.types.bool; default = false; description = "Log all event activity."; }; - handlers = mkOption { - type = types.attrsOf (types.submodule { + handlers = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { options = { - event = mkOption { - type = types.str; - example = literalExpression ''"button/power.*" "button/lid.*" "ac_adapter.*" "button/mute.*" "button/volumedown.*" "cd/play.*" "cd/next.*"''; + event = lib.mkOption { + type = lib.types.str; + example = lib.literalExpression ''"button/power.*" "button/lid.*" "ac_adapter.*" "button/mute.*" "button/volumedown.*" "cd/play.*" "cd/next.*"''; description = "Event type."; }; - action = mkOption { - type = types.lines; + action = lib.mkOption { + type = lib.types.lines; description = "Shell commands to execute when the event is triggered."; }; }; @@ -101,20 +98,20 @@ in }; }; - powerEventCommands = mkOption { - type = types.lines; + powerEventCommands = lib.mkOption { + type = lib.types.lines; default = ""; description = "Shell commands to execute on a button/power.* event."; }; - lidEventCommands = mkOption { - type = types.lines; + lidEventCommands = lib.mkOption { + type = lib.types.lines; default = ""; description = "Shell commands to execute on a button/lid.* event."; }; - acEventCommands = mkOption { - type = types.lines; + acEventCommands = lib.mkOption { + type = lib.types.lines; default = ""; description = "Shell commands to execute on an ac_adapter.* event."; }; @@ -126,7 +123,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.acpid = { description = "ACPI Daemon"; @@ -135,12 +132,12 @@ in wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = escapeShellArgs + ExecStart = lib.escapeShellArgs ([ "${pkgs.acpid}/bin/acpid" "--foreground" "--netlink" "--confdir" "${acpiConfDir}" - ] ++ optional cfg.logEvents "--logevents" + ] ++ lib.optional cfg.logEvents "--logevents" ); }; unitConfig = { diff --git a/nixos/modules/services/hardware/auto-cpufreq.nix b/nixos/modules/services/hardware/auto-cpufreq.nix index f61fa38be175..ed24c656c543 100644 --- a/nixos/modules/services/hardware/auto-cpufreq.nix +++ b/nixos/modules/services/hardware/auto-cpufreq.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.auto-cpufreq; cfgFilename = "auto-cpufreq.conf"; @@ -9,9 +8,9 @@ let in { options = { services.auto-cpufreq = { - enable = mkEnableOption "auto-cpufreq daemon"; + enable = lib.mkEnableOption "auto-cpufreq daemon"; - settings = mkOption { + settings = lib.mkOption { description = '' Configuration for `auto-cpufreq`. @@ -19,12 +18,12 @@ in { ''; default = {}; - type = types.submodule { freeformType = format.type; }; + type = lib.types.submodule { freeformType = format.type; }; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.auto-cpufreq ]; systemd = { diff --git a/nixos/modules/services/hardware/bolt.nix b/nixos/modules/services/hardware/bolt.nix index 729273f94f12..f005d24e0883 100644 --- a/nixos/modules/services/hardware/bolt.nix +++ b/nixos/modules/services/hardware/bolt.nix @@ -1,15 +1,12 @@ { config, lib, pkgs, ...}: - -with lib; - let cfg = config.services.hardware.bolt; in { options = { services.hardware.bolt = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable Bolt, a userspace daemon to enable @@ -19,11 +16,11 @@ in ''; }; - package = mkPackageOption pkgs "bolt" { }; + package = lib.mkPackageOption pkgs "bolt" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; services.udev.packages = [ cfg.package ]; systemd.packages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/brltty.nix b/nixos/modules/services/hardware/brltty.nix index bdec5d79be96..c4ded927345d 100644 --- a/nixos/modules/services/hardware/brltty.nix +++ b/nixos/modules/services/hardware/brltty.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.brltty; @@ -22,15 +19,15 @@ in { options = { - services.brltty.enable = mkOption { - type = types.bool; + services.brltty.enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the BRLTTY daemon."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.brltty = { description = "BRLTTY daemon user"; group = "brltty"; diff --git a/nixos/modules/services/hardware/fancontrol.nix b/nixos/modules/services/hardware/fancontrol.nix index f9fc8593f852..06c217b4d3c9 100644 --- a/nixos/modules/services/hardware/fancontrol.nix +++ b/nixos/modules/services/hardware/fancontrol.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.fancontrol; configFile = pkgs.writeText "fancontrol.conf" cfg.config; @@ -9,10 +6,10 @@ let in { options.hardware.fancontrol = { - enable = mkEnableOption "software fan control (requires fancontrol.config)"; + enable = lib.mkEnableOption "software fan control (requires fancontrol.config)"; - config = mkOption { - type = types.lines; + config = lib.mkOption { + type = lib.types.lines; description = "Required fancontrol configuration file content. See {manpage}`pwmconfig(8)` from the lm_sensors package."; example = '' # Configuration file generated by pwmconfig @@ -29,7 +26,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.fancontrol = { documentation = [ "man:fancontrol(8)" ]; @@ -51,5 +48,5 @@ in }; - meta.maintainers = [ maintainers.evils ]; + meta.maintainers = [ lib.maintainers.evils ]; } diff --git a/nixos/modules/services/hardware/freefall.nix b/nixos/modules/services/hardware/freefall.nix index 4ac7c54d4d8a..fe017bb17f7e 100644 --- a/nixos/modules/services/hardware/freefall.nix +++ b/nixos/modules/services/hardware/freefall.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, utils, ... }: - -with lib; - let cfg = config.services.freefall; @@ -10,18 +7,18 @@ in { options.services.freefall = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to protect HP/Dell laptop hard drives (not SSDs) in free fall. ''; }; - package = mkPackageOption pkgs "freefall" { }; + package = lib.mkPackageOption pkgs "freefall" { }; - devices = mkOption { - type = types.listOf types.str; + devices = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "/dev/sda" ]; description = '' Device paths to all internal spinning hard drives. @@ -35,7 +32,7 @@ in { mkService = dev: assert dev != ""; let dev' = utils.escapeSystemdPath dev; in - nameValuePair "freefall-${dev'}" { + lib.nameValuePair "freefall-${dev'}" { description = "Free-fall protection for ${dev}"; after = [ "${dev'}.device" ]; wantedBy = [ "${dev'}.device" ]; @@ -46,7 +43,7 @@ in { }; }; - in mkIf cfg.enable { + in lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix index bdbd0ac2440b..09a55ad28052 100644 --- a/nixos/modules/services/hardware/fwupd.nix +++ b/nixos/modules/services/hardware/fwupd.nix @@ -1,15 +1,11 @@ # fwupd daemon. - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.fwupd; format = pkgs.formats.ini { - listToValue = l: lib.concatStringsSep ";" (map (s: generators.mkValueStringDefault {} s) l); - mkKeyValue = generators.mkKeyValueDefault {} "="; + listToValue = l: lib.concatStringsSep ";" (map (s: lib.generators.mkValueStringDefault {} s) l); + mkKeyValue = lib.generators.mkKeyValueDefault {} "="; }; customEtc = { @@ -26,13 +22,13 @@ let originalEtc = let - mkEtcFile = n: nameValuePair n { source = "${cfg.package}/etc/${n}"; }; - in listToAttrs (map mkEtcFile cfg.package.filesInstalledToEtc); + mkEtcFile = n: lib.nameValuePair n { source = "${cfg.package}/etc/${n}"; }; + in lib.listToAttrs (map mkEtcFile cfg.package.filesInstalledToEtc); extraTrustedKeys = let mkName = p: "pki/fwupd/${baseNameOf (toString p)}"; - mkEtcFile = p: nameValuePair (mkName p) { source = p; }; - in listToAttrs (map mkEtcFile cfg.extraTrustedKeys); + mkEtcFile = p: lib.nameValuePair (mkName p) { source = p; }; + in lib.listToAttrs (map mkEtcFile cfg.extraTrustedKeys); enableRemote = base: remote: { "fwupd/remotes.d/${remote}.conf" = { @@ -42,7 +38,7 @@ let ''; }; }; - remotes = (foldl' + remotes = (lib.foldl' (configFiles: remote: configFiles // (enableRemote cfg.package remote)) {} cfg.extraRemotes @@ -61,8 +57,8 @@ in { ###### interface options = { services.fwupd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable fwupd, a DBus service that allows @@ -70,17 +66,17 @@ in { ''; }; - extraTrustedKeys = mkOption { - type = types.listOf types.path; + extraTrustedKeys = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; - example = literalExpression "[ /etc/nixos/fwupd/myfirmware.pem ]"; + example = lib.literalExpression "[ /etc/nixos/fwupd/myfirmware.pem ]"; description = '' Installing a public key allows firmware signed with a matching private key to be recognized as trusted, which may require less authentication to install than for untrusted files. By default trusted firmware can be upgraded (but not downgraded) without the user or administrator password. Only very few keys are installed by default. ''; }; - extraRemotes = mkOption { - type = with types; listOf str; + extraRemotes = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "lvfs-testing" ]; description = '' @@ -88,14 +84,14 @@ in { ''; }; - package = mkPackageOption pkgs "fwupd" { }; + package = lib.mkPackageOption pkgs "fwupd" { }; - daemonSettings = mkOption { - type = types.submodule { + daemonSettings = lib.mkOption { + type = lib.types.submodule { freeformType = format.type.nestedTypes.elemType; options = { - DisabledDevices = mkOption { - type = types.listOf types.str; + DisabledDevices = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "2082b5e0-7a64-478a-b1b2-e3404fab6dad" ]; description = '' @@ -103,8 +99,8 @@ in { ''; }; - DisabledPlugins = mkOption { - type = types.listOf types.str; + DisabledPlugins = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "udev" ]; description = '' @@ -112,8 +108,8 @@ in { ''; }; - EspLocation = mkOption { - type = types.path; + EspLocation = lib.mkOption { + type = lib.types.path; default = config.boot.loader.efi.efiSysMountPoint; defaultText = lib.literalExpression "config.boot.loader.efi.efiSysMountPoint"; description = '' @@ -122,9 +118,9 @@ in { ''; }; - TestDevices = mkOption { + TestDevices = lib.mkOption { internal = true; - type = types.bool; + type = lib.types.bool; default = false; description = '' Create virtual test devices and remote for validating daemon flows. @@ -139,8 +135,8 @@ in { ''; }; - uefiCapsuleSettings = mkOption { - type = types.submodule { + uefiCapsuleSettings = lib.mkOption { + type = lib.types.submodule { freeformType = format.type.nestedTypes.elemType; }; default = {}; @@ -152,15 +148,15 @@ in { }; imports = [ - (mkRenamedOptionModule [ "services" "fwupd" "blacklistDevices"] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ]) - (mkRenamedOptionModule [ "services" "fwupd" "blacklistPlugins"] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ]) - (mkRenamedOptionModule [ "services" "fwupd" "disabledDevices" ] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ]) - (mkRenamedOptionModule [ "services" "fwupd" "disabledPlugins" ] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ]) - (mkRemovedOptionModule [ "services" "fwupd" "enableTestRemote" ] "This option was removed after being removed upstream. It only provided a method for testing fwupd functionality, and should not have been exposed for use outside of nix tests.") + (lib.mkRenamedOptionModule [ "services" "fwupd" "blacklistDevices"] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ]) + (lib.mkRenamedOptionModule [ "services" "fwupd" "blacklistPlugins"] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ]) + (lib.mkRenamedOptionModule [ "services" "fwupd" "disabledDevices" ] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ]) + (lib.mkRenamedOptionModule [ "services" "fwupd" "disabledPlugins" ] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ]) + (lib.mkRemovedOptionModule [ "services" "fwupd" "enableTestRemote" ] "This option was removed after being removed upstream. It only provided a method for testing fwupd functionality, and should not have been exposed for use outside of nix tests.") ]; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Disable test related plug-ins implicitly so that users do not have to care about them. services.fwupd.daemonSettings = { EspLocation = config.boot.loader.efi.efiSysMountPoint; diff --git a/nixos/modules/services/hardware/illum.nix b/nixos/modules/services/hardware/illum.nix index 7f7a85000234..61ab24a5de7c 100644 --- a/nixos/modules/services/hardware/illum.nix +++ b/nixos/modules/services/hardware/illum.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.illum; in { @@ -10,9 +7,9 @@ in { services.illum = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Enable illum, a daemon for controlling screen brightness with brightness buttons. ''; @@ -22,7 +19,7 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.illum = { description = "Backlight Adjustment Service"; diff --git a/nixos/modules/services/hardware/interception-tools.nix b/nixos/modules/services/hardware/interception-tools.nix index e69c05841ee0..d60e7ca59547 100644 --- a/nixos/modules/services/hardware/interception-tools.nix +++ b/nixos/modules/services/hardware/interception-tools.nix @@ -1,29 +1,26 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.interception-tools; in { options.services.interception-tools = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the interception tools service."; }; - plugins = mkOption { - type = types.listOf types.package; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.package; default = [ pkgs.interception-tools-plugins.caps2esc ]; - defaultText = literalExpression "[ pkgs.interception-tools-plugins.caps2esc ]"; + defaultText = lib.literalExpression "[ pkgs.interception-tools-plugins.caps2esc ]"; description = '' A list of interception tools plugins that will be made available to use inside the udevmon configuration. ''; }; - udevmonConfig = mkOption { - type = types.either types.str types.path; + udevmonConfig = lib.mkOption { + type = lib.types.either lib.types.str lib.types.path; default = '' - JOB: "intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE" DEVICE: @@ -43,7 +40,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.interception-tools = { description = "Interception tools"; path = [ pkgs.bash pkgs.interception-tools ] ++ cfg.plugins; diff --git a/nixos/modules/services/hardware/iptsd.nix b/nixos/modules/services/hardware/iptsd.nix index 3a299c2428df..bfd4b3522792 100644 --- a/nixos/modules/services/hardware/iptsd.nix +++ b/nixos/modules/services/hardware/iptsd.nix @@ -18,15 +18,15 @@ in { type = lib.types.submodule { freeformType = format.type; options = { - Touch = { + Touchscreen = { DisableOnPalm = lib.mkOption { default = false; - description = "Ignore all touch inputs if a palm was registered on the display."; + description = "Ignore all touchscreen inputs if a palm was registered on the display."; type = lib.types.bool; }; DisableOnStylus = lib.mkOption { default = false; - description = "Ignore all touch inputs if a stylus is in proximity."; + description = "Ignore all touchscreen inputs if a stylus is in proximity."; type = lib.types.bool; }; }; @@ -43,6 +43,10 @@ in { }; config = lib.mkIf cfg.enable { + warnings = lib.optional (lib.hasAttr "Touch" cfg.config) '' + The option `services.iptsd.config.Touch` has been renamed to `services.iptsd.config.Touchscreen`. + ''; + systemd.packages = [ pkgs.iptsd ]; environment.etc."iptsd.conf".source = configFile; systemd.services."iptsd@".restartTriggers = [ configFile ]; diff --git a/nixos/modules/services/hardware/irqbalance.nix b/nixos/modules/services/hardware/irqbalance.nix index c79e0eb83ece..42878725cca3 100644 --- a/nixos/modules/services/hardware/irqbalance.nix +++ b/nixos/modules/services/hardware/irqbalance.nix @@ -1,17 +1,14 @@ # { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.irqbalance; in { - options.services.irqbalance.enable = mkEnableOption "irqbalance daemon"; + options.services.irqbalance.enable = lib.mkEnableOption "irqbalance daemon"; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.irqbalance ]; diff --git a/nixos/modules/services/hardware/joycond.nix b/nixos/modules/services/hardware/joycond.nix index 106c19243c49..b6d2b8328af7 100644 --- a/nixos/modules/services/hardware/joycond.nix +++ b/nixos/modules/services/hardware/joycond.nix @@ -1,19 +1,15 @@ { config, lib, pkgs, ... }: - let cfg = config.services.joycond; in - -with lib; - { options.services.joycond = { - enable = mkEnableOption "support for Nintendo Pro Controllers and Joycons"; + enable = lib.mkEnableOption "support for Nintendo Pro Controllers and Joycons"; - package = mkPackageOption pkgs "joycond" { }; + package = lib.mkPackageOption pkgs "joycond" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; services.udev.packages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/kanata.nix b/nixos/modules/services/hardware/kanata.nix index 60fb33881f25..7557b1ae55f9 100644 --- a/nixos/modules/services/hardware/kanata.nix +++ b/nixos/modules/services/hardware/kanata.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, utils, ... }: - -with lib; - let cfg = config.services.kanata; @@ -9,8 +6,8 @@ let keyboard = { name, config, ... }: { options = { - devices = mkOption { - type = types.listOf types.str; + devices = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "/dev/input/by-id/usb-0000_0000-event-kbd" ]; description = '' @@ -20,8 +17,8 @@ let input devices are keyboards and intercept them all. ''; }; - config = mkOption { - type = types.lines; + config = lib.mkOption { + type = lib.types.lines; example = '' (defsrc caps) @@ -36,8 +33,8 @@ let ${upstreamDoc} ''; }; - extraDefCfg = mkOption { - type = types.lines; + extraDefCfg = lib.mkOption { + type = lib.types.lines; default = ""; example = "danger-enable-cmd yes"; description = '' @@ -48,8 +45,8 @@ let ${upstreamDoc} ''; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = mkConfig name config; defaultText = "A config file generated by values from other kanata module options."; @@ -63,13 +60,13 @@ let overrides all other kanata module options. ${upstreamDoc} ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = "Extra command line arguments passed to kanata."; }; - port = mkOption { - type = types.nullOr types.port; + port = lib.mkOption { + type = lib.types.nullOr lib.types.port; default = null; example = 6666; description = '' @@ -83,12 +80,12 @@ let mkDevices = devices: let - devicesString = pipe devices [ + devicesString = lib.pipe devices [ (map (device: "\"" + device + "\"")) - (concatStringsSep " ") + (lib.concatStringsSep " ") ]; in - optionalString ((length devices) > 0) "linux-dev (${devicesString})"; + lib.optionalString ((lib.length devices) > 0) "linux-dev (${devicesString})"; mkConfig = name: keyboard: pkgs.writeTextFile { name = "${mkName name}-config.kdb"; @@ -105,19 +102,19 @@ let # at build time. I think this is a good balance between module # complexity and functionality. checkPhase = '' - ${getExe cfg.package} --cfg "$target" --check --debug + ${lib.getExe cfg.package} --cfg "$target" --check --debug ''; }; - mkService = name: keyboard: nameValuePair (mkName name) { + mkService = name: keyboard: lib.nameValuePair (mkName name) { wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "notify"; ExecStart = '' - ${getExe cfg.package} \ + ${lib.getExe cfg.package} \ --cfg ${keyboard.configFile} \ --symlink-path ''${RUNTIME_DIRECTORY}/${name} \ - ${optionalString (keyboard.port != null) "--port ${toString keyboard.port}"} \ + ${lib.optionalString (keyboard.port != null) "--port ${toString keyboard.port}"} \ ${utils.escapeSystemdExecArgs keyboard.extraArgs} ''; @@ -135,7 +132,7 @@ let ]; CapabilityBoundingSet = [ "" ]; DevicePolicy = "closed"; - IPAddressAllow = optional (keyboard.port != null) "localhost"; + IPAddressAllow = lib.optional (keyboard.port != null) "localhost"; IPAddressDeny = [ "any" ]; LockPersonality = true; MemoryDenyWriteExecute = true; @@ -150,7 +147,7 @@ let ProtectKernelModules = true; ProtectKernelTunables = true; ProtectProc = "invisible"; - RestrictAddressFamilies = [ "AF_UNIX" ] ++ optional (keyboard.port != null) "AF_INET"; + RestrictAddressFamilies = [ "AF_UNIX" ] ++ lib.optional (keyboard.port != null) "AF_INET"; RestrictNamespaces = true; RestrictRealtime = true; SystemCallArchitectures = [ "native" ]; @@ -165,8 +162,8 @@ let in { options.services.kanata = { - enable = mkEnableOption "kanata, a tool to improve keyboard comfort and usability with advanced customization"; - package = mkPackageOption pkgs "kanata" { + enable = lib.mkEnableOption "kanata, a tool to improve keyboard comfort and usability with advanced customization"; + package = lib.mkPackageOption pkgs "kanata" { example = [ "kanata-with-cmd" ]; extraDescription = '' ::: {.note} @@ -175,26 +172,26 @@ in ::: ''; }; - keyboards = mkOption { - type = types.attrsOf (types.submodule keyboard); + keyboards = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule keyboard); default = { }; description = "Keyboard configurations."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { warnings = let - keyboardsWithEmptyDevices = filterAttrs (name: keyboard: keyboard.devices == [ ]) cfg.keyboards; - existEmptyDevices = length (attrNames keyboardsWithEmptyDevices) > 0; - moreThanOneKeyboard = length (attrNames cfg.keyboards) > 1; + keyboardsWithEmptyDevices = lib.filterAttrs (name: keyboard: keyboard.devices == [ ]) cfg.keyboards; + existEmptyDevices = lib.length (lib.attrNames keyboardsWithEmptyDevices) > 0; + moreThanOneKeyboard = lib.length (lib.attrNames cfg.keyboards) > 1; in - optional (existEmptyDevices && moreThanOneKeyboard) "One device can only be intercepted by one kanata instance. Setting services.kanata.keyboards.${head (attrNames keyboardsWithEmptyDevices)}.devices = [ ] and using more than one services.kanata.keyboards may cause a race condition."; + lib.optional (existEmptyDevices && moreThanOneKeyboard) "One device can only be intercepted by one kanata instance. Setting services.kanata.keyboards.${lib.head (lib.attrNames keyboardsWithEmptyDevices)}.devices = [ ] and using more than one services.kanata.keyboards may cause a race condition."; hardware.uinput.enable = true; - systemd.services = mapAttrs' mkService cfg.keyboards; + systemd.services = lib.mapAttrs' mkService cfg.keyboards; }; - meta.maintainers = with maintainers; [ linj ]; + meta.maintainers = with lib.maintainers; [ linj ]; } diff --git a/nixos/modules/services/hardware/keyd.nix b/nixos/modules/services/hardware/keyd.nix index 2aee7817c6f3..92b62fe2e977 100644 --- a/nixos/modules/services/hardware/keyd.nix +++ b/nixos/modules/services/hardware/keyd.nix @@ -1,12 +1,11 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.keyd; keyboardOptions = { ... }: { options = { - ids = mkOption { - type = types.listOf types.str; + ids = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "*" ]; example = [ "*" "-0123:0456" ]; description = '' @@ -14,7 +13,7 @@ let ''; }; - settings = mkOption { + settings = lib.mkOption { type = (pkgs.formats.ini { }).type; default = { }; example = { @@ -37,8 +36,8 @@ let ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = '' [control+shift] @@ -55,19 +54,19 @@ let in { imports = [ - (mkRemovedOptionModule [ "services" "keyd" "ids" ] + (lib.mkRemovedOptionModule [ "services" "keyd" "ids" ] ''Use keyboards..ids instead. If you don't need a multi-file configuration, just add keyboards.default before the ids. See https://github.com/NixOS/nixpkgs/pull/243271.'') - (mkRemovedOptionModule [ "services" "keyd" "settings" ] + (lib.mkRemovedOptionModule [ "services" "keyd" "settings" ] ''Use keyboards..settings instead. If you don't need a multi-file configuration, just add keyboards.default before the settings. See https://github.com/NixOS/nixpkgs/pull/243271.'') ]; options.services.keyd = { - enable = mkEnableOption "keyd, a key remapping daemon"; + enable = lib.mkEnableOption "keyd, a key remapping daemon"; - keyboards = mkOption { - type = types.attrsOf (types.submodule keyboardOptions); + keyboards = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule keyboardOptions); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { default = { ids = [ "*" ]; @@ -93,16 +92,16 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Creates separate files in the `/etc/keyd/` directory for each key in the dictionary - environment.etc = mapAttrs' + environment.etc = lib.mapAttrs' (name: options: - nameValuePair "keyd/${name}.conf" { + lib.nameValuePair "keyd/${name}.conf" { text = '' [ids] - ${concatStringsSep "\n" options.ids} + ${lib.concatStringsSep "\n" options.ids} - ${generators.toINI {} options.settings} + ${lib.generators.toINI {} options.settings} ${options.extraConfig} ''; }) @@ -116,7 +115,7 @@ in wantedBy = [ "multi-user.target" ]; - restartTriggers = mapAttrsToList + restartTriggers = lib.mapAttrsToList (name: options: config.environment.etc."keyd/${name}.conf".source ) diff --git a/nixos/modules/services/hardware/libinput.nix b/nixos/modules/services/hardware/libinput.nix index d79055cb8d83..e8169af40637 100644 --- a/nixos/modules/services/hardware/libinput.nix +++ b/nixos/modules/services/hardware/libinput.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.libinput; xorgBool = v: if v then "on" else "off"; mkConfigForDevice = deviceType: { - dev = mkOption { - type = types.nullOr types.str; + dev = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "/dev/input/event0"; description = '' @@ -17,8 +14,8 @@ let cfg = config.services.libinput; ''; }; - accelProfile = mkOption { - type = types.enum [ "flat" "adaptive" "custom" ]; + accelProfile = lib.mkOption { + type = lib.types.enum [ "flat" "adaptive" "custom" ]; default = "adaptive"; example = "flat"; description = '' @@ -36,8 +33,8 @@ let cfg = config.services.libinput; ''; }; - accelSpeed = mkOption { - type = types.nullOr types.str; + accelSpeed = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "-0.5"; description = '' @@ -46,8 +43,8 @@ let cfg = config.services.libinput; ''; }; - accelPointsFallback = mkOption { - type = types.nullOr (types.listOf types.number); + accelPointsFallback = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.number); default = null; example = [ 0.0 1.0 2.4 2.5 ]; description = '' @@ -56,8 +53,8 @@ let cfg = config.services.libinput; ''; }; - accelPointsMotion = mkOption { - type = types.nullOr (types.listOf types.number); + accelPointsMotion = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.number); default = null; example = [ 0.0 1.0 2.4 2.5 ]; description = '' @@ -66,8 +63,8 @@ let cfg = config.services.libinput; ''; }; - accelPointsScroll = mkOption { - type = types.nullOr (types.listOf types.number); + accelPointsScroll = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.number); default = null; example = [ 0.0 1.0 2.4 2.5 ]; description = '' @@ -76,8 +73,8 @@ let cfg = config.services.libinput; ''; }; - accelStepFallback = mkOption { - type = types.nullOr types.number; + accelStepFallback = lib.mkOption { + type = lib.types.nullOr lib.types.number; default = null; example = 0.1; description = '' @@ -87,8 +84,8 @@ let cfg = config.services.libinput; ''; }; - accelStepMotion = mkOption { - type = types.nullOr types.number; + accelStepMotion = lib.mkOption { + type = lib.types.nullOr lib.types.number; default = null; example = 0.1; description = '' @@ -98,8 +95,8 @@ let cfg = config.services.libinput; ''; }; - accelStepScroll = mkOption { - type = types.nullOr types.number; + accelStepScroll = lib.mkOption { + type = lib.types.nullOr lib.types.number; default = null; example = 0.1; description = '' @@ -109,8 +106,8 @@ let cfg = config.services.libinput; ''; }; - buttonMapping = mkOption { - type = types.nullOr types.str; + buttonMapping = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "1 6 3 4 5 0 7"; description = '' @@ -123,8 +120,8 @@ let cfg = config.services.libinput; ''; }; - calibrationMatrix = mkOption { - type = types.nullOr types.str; + calibrationMatrix = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "0.5 0 0 0 0.8 0.1 0 0 1"; description = '' @@ -133,8 +130,8 @@ let cfg = config.services.libinput; ''; }; - clickMethod = mkOption { - type = types.nullOr (types.enum [ "none" "buttonareas" "clickfinger" ]); + clickMethod = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "none" "buttonareas" "clickfinger" ]); default = null; example = "buttonareas"; description = '' @@ -145,14 +142,14 @@ let cfg = config.services.libinput; ''; }; - leftHanded = mkOption { - type = types.bool; + leftHanded = lib.mkOption { + type = lib.types.bool; default = false; description = "Enables left-handed button orientation, i.e. swapping left and right buttons."; }; - middleEmulation = mkOption { - type = types.bool; + middleEmulation = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enables middle button emulation. When enabled, pressing the left and right buttons @@ -160,14 +157,14 @@ let cfg = config.services.libinput; ''; }; - naturalScrolling = mkOption { - type = types.bool; + naturalScrolling = lib.mkOption { + type = lib.types.bool; default = false; description = "Enables or disables natural scrolling behavior."; }; - scrollButton = mkOption { - type = types.nullOr types.int; + scrollButton = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 1; description = '' @@ -176,8 +173,8 @@ let cfg = config.services.libinput; ''; }; - scrollMethod = mkOption { - type = types.enum [ "twofinger" "edge" "button" "none" ]; + scrollMethod = lib.mkOption { + type = lib.types.enum [ "twofinger" "edge" "button" "none" ]; default = "twofinger"; example = "edge"; description = '' @@ -186,8 +183,8 @@ let cfg = config.services.libinput; ''; }; - horizontalScrolling = mkOption { - type = types.bool; + horizontalScrolling = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enables or disables horizontal scrolling. When disabled, this driver will discard any @@ -196,8 +193,8 @@ let cfg = config.services.libinput; ''; }; - sendEventsMode = mkOption { - type = types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ]; + sendEventsMode = lib.mkOption { + type = lib.types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ]; default = "enabled"; example = "disabled"; description = '' @@ -206,24 +203,24 @@ let cfg = config.services.libinput; ''; }; - tapping = mkOption { - type = types.bool; + tapping = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enables or disables tap-to-click behavior. ''; }; - tappingButtonMap = mkOption { - type = types.nullOr (types.enum [ "lrm" "lmr" ]); + tappingButtonMap = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "lrm" "lmr" ]); default = null; description = '' Set the button mapping for 1/2/3-finger taps to left/right/middle or left/middle/right, respectively. ''; }; - tappingDragLock = mkOption { - type = types.bool; + tappingDragLock = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enables or disables drag lock during tapping behavior. When enabled, a finger up during tap- @@ -232,8 +229,8 @@ let cfg = config.services.libinput; ''; }; - transformationMatrix = mkOption { - type = types.nullOr types.str; + transformationMatrix = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "0.5 0 0 0 0.8 0.1 0 0 1"; description = '' @@ -242,16 +239,16 @@ let cfg = config.services.libinput; ''; }; - disableWhileTyping = mkOption { - type = types.bool; + disableWhileTyping = lib.mkOption { + type = lib.types.bool; default = false; description = '' Disable input method while typing. ''; }; - additionalOptions = mkOption { - type = types.lines; + additionalOptions = lib.mkOption { + type = lib.types.lines; default = ""; example = '' @@ -269,28 +266,28 @@ let cfg = config.services.libinput; Identifier "libinput ${deviceType} configuration" MatchDriver "libinput" MatchIs${matchIs} "${xorgBool true}" - ${optionalString (cfg.${deviceType}.dev != null) ''MatchDevicePath "${cfg.${deviceType}.dev}"''} + ${lib.optionalString (cfg.${deviceType}.dev != null) ''MatchDevicePath "${cfg.${deviceType}.dev}"''} Option "AccelProfile" "${cfg.${deviceType}.accelProfile}" - ${optionalString (cfg.${deviceType}.accelSpeed != null) ''Option "AccelSpeed" "${cfg.${deviceType}.accelSpeed}"''} - ${optionalString (cfg.${deviceType}.accelPointsFallback != null) ''Option "AccelPointsFallback" "${toString cfg.${deviceType}.accelPointsFallback}"''} - ${optionalString (cfg.${deviceType}.accelPointsMotion != null) ''Option "AccelPointsMotion" "${toString cfg.${deviceType}.accelPointsMotion}"''} - ${optionalString (cfg.${deviceType}.accelPointsScroll != null) ''Option "AccelPointsScroll" "${toString cfg.${deviceType}.accelPointsScroll}"''} - ${optionalString (cfg.${deviceType}.accelStepFallback != null) ''Option "AccelStepFallback" "${toString cfg.${deviceType}.accelStepFallback}"''} - ${optionalString (cfg.${deviceType}.accelStepMotion != null) ''Option "AccelStepMotion" "${toString cfg.${deviceType}.accelStepMotion}"''} - ${optionalString (cfg.${deviceType}.accelStepScroll != null) ''Option "AccelStepScroll" "${toString cfg.${deviceType}.accelStepScroll}"''} - ${optionalString (cfg.${deviceType}.buttonMapping != null) ''Option "ButtonMapping" "${cfg.${deviceType}.buttonMapping}"''} - ${optionalString (cfg.${deviceType}.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.${deviceType}.calibrationMatrix}"''} - ${optionalString (cfg.${deviceType}.transformationMatrix != null) ''Option "TransformationMatrix" "${cfg.${deviceType}.transformationMatrix}"''} - ${optionalString (cfg.${deviceType}.clickMethod != null) ''Option "ClickMethod" "${cfg.${deviceType}.clickMethod}"''} + ${lib.optionalString (cfg.${deviceType}.accelSpeed != null) ''Option "AccelSpeed" "${cfg.${deviceType}.accelSpeed}"''} + ${lib.optionalString (cfg.${deviceType}.accelPointsFallback != null) ''Option "AccelPointsFallback" "${toString cfg.${deviceType}.accelPointsFallback}"''} + ${lib.optionalString (cfg.${deviceType}.accelPointsMotion != null) ''Option "AccelPointsMotion" "${toString cfg.${deviceType}.accelPointsMotion}"''} + ${lib.optionalString (cfg.${deviceType}.accelPointsScroll != null) ''Option "AccelPointsScroll" "${toString cfg.${deviceType}.accelPointsScroll}"''} + ${lib.optionalString (cfg.${deviceType}.accelStepFallback != null) ''Option "AccelStepFallback" "${toString cfg.${deviceType}.accelStepFallback}"''} + ${lib.optionalString (cfg.${deviceType}.accelStepMotion != null) ''Option "AccelStepMotion" "${toString cfg.${deviceType}.accelStepMotion}"''} + ${lib.optionalString (cfg.${deviceType}.accelStepScroll != null) ''Option "AccelStepScroll" "${toString cfg.${deviceType}.accelStepScroll}"''} + ${lib.optionalString (cfg.${deviceType}.buttonMapping != null) ''Option "ButtonMapping" "${cfg.${deviceType}.buttonMapping}"''} + ${lib.optionalString (cfg.${deviceType}.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.${deviceType}.calibrationMatrix}"''} + ${lib.optionalString (cfg.${deviceType}.transformationMatrix != null) ''Option "TransformationMatrix" "${cfg.${deviceType}.transformationMatrix}"''} + ${lib.optionalString (cfg.${deviceType}.clickMethod != null) ''Option "ClickMethod" "${cfg.${deviceType}.clickMethod}"''} Option "LeftHanded" "${xorgBool cfg.${deviceType}.leftHanded}" Option "MiddleEmulation" "${xorgBool cfg.${deviceType}.middleEmulation}" Option "NaturalScrolling" "${xorgBool cfg.${deviceType}.naturalScrolling}" - ${optionalString (cfg.${deviceType}.scrollButton != null) ''Option "ScrollButton" "${toString cfg.${deviceType}.scrollButton}"''} + ${lib.optionalString (cfg.${deviceType}.scrollButton != null) ''Option "ScrollButton" "${toString cfg.${deviceType}.scrollButton}"''} Option "ScrollMethod" "${cfg.${deviceType}.scrollMethod}" Option "HorizontalScrolling" "${xorgBool cfg.${deviceType}.horizontalScrolling}" Option "SendEventsMode" "${cfg.${deviceType}.sendEventsMode}" Option "Tapping" "${xorgBool cfg.${deviceType}.tapping}" - ${optionalString (cfg.${deviceType}.tappingButtonMap != null) ''Option "TappingButtonMap" "${cfg.${deviceType}.tappingButtonMap}"''} + ${lib.optionalString (cfg.${deviceType}.tappingButtonMap != null) ''Option "TappingButtonMap" "${cfg.${deviceType}.tappingButtonMap}"''} Option "TappingDragLock" "${xorgBool cfg.${deviceType}.tappingDragLock}" Option "DisableWhileTyping" "${xorgBool cfg.${deviceType}.disableWhileTyping}" ${cfg.${deviceType}.additionalOptions} @@ -298,7 +295,7 @@ let cfg = config.services.libinput; in { imports = - (map (option: mkRenamedOptionModule ([ "services" "xserver" "libinput" option ]) [ "services" "libinput" "touchpad" option ]) [ + (map (option: lib.mkRenamedOptionModule ([ "services" "xserver" "libinput" option ]) [ "services" "libinput" "touchpad" option ]) [ "accelProfile" "accelSpeed" "buttonMapping" @@ -318,15 +315,15 @@ in { "disableWhileTyping" "additionalOptions" ]) ++ [ - (mkRenamedOptionModule [ "services" "xserver" "libinput" "enable" ] [ "services" "libinput" "enable" ]) - (mkRenamedOptionModule [ "services" "xserver" "libinput" "mouse" ] [ "services" "libinput" "mouse" ]) - (mkRenamedOptionModule [ "services" "xserver" "libinput" "touchpad" ] [ "services" "libinput" "touchpad" ]) + (lib.mkRenamedOptionModule [ "services" "xserver" "libinput" "enable" ] [ "services" "libinput" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "xserver" "libinput" "mouse" ] [ "services" "libinput" "mouse" ]) + (lib.mkRenamedOptionModule [ "services" "xserver" "libinput" "touchpad" ] [ "services" "libinput" "touchpad" ]) ]; options = { services.libinput = { - enable = mkEnableOption "libinput" // { + enable = lib.mkEnableOption "libinput" // { default = config.services.xserver.enable; defaultText = lib.literalExpression "config.services.xserver.enable"; }; @@ -336,7 +333,7 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.xserver.modules = [ pkgs.xorg.xf86inputlibinput ]; diff --git a/nixos/modules/services/hardware/lirc.nix b/nixos/modules/services/hardware/lirc.nix index 8103dbeb2d48..9942b9a97513 100644 --- a/nixos/modules/services/hardware/lirc.nix +++ b/nixos/modules/services/hardware/lirc.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.lirc; in { @@ -11,10 +8,10 @@ in { options = { services.lirc = { - enable = mkEnableOption "the LIRC daemon, to receive and send infrared signals"; + enable = lib.mkEnableOption "the LIRC daemon, to receive and send infrared signals"; - options = mkOption { - type = types.lines; + options = lib.mkOption { + type = lib.types.lines; example = '' [lircd] nodaemon = False @@ -22,13 +19,13 @@ in { description = "LIRC default options described in man:lircd(8) ({file}`lirc_options.conf`)"; }; - configs = mkOption { - type = types.listOf types.lines; + configs = lib.mkOption { + type = lib.types.listOf lib.types.lines; description = "Configurations for lircd to load, see man:lircd.conf(5) for details ({file}`lircd.conf`)"; }; - extraArguments = mkOption { - type = types.listOf types.str; + extraArguments = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "Extra arguments to lircd."; }; @@ -37,7 +34,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Note: LIRC executables raises a warning, if lirc_options.conf do not exists environment.etc."lirc/lirc_options.conf".text = cfg.options; @@ -82,7 +79,7 @@ in { ExecStart = '' ${pkgs.lirc}/bin/lircd --nodaemon \ - ${escapeShellArgs cfg.extraArguments} \ + ${lib.escapeShellArgs cfg.extraArguments} \ ${configFile} ''; User = "lirc"; diff --git a/nixos/modules/services/hardware/nvidia-container-toolkit/cdi-generate.nix b/nixos/modules/services/hardware/nvidia-container-toolkit/cdi-generate.nix index 360a832e28cb..6a04fa0ff750 100644 --- a/nixos/modules/services/hardware/nvidia-container-toolkit/cdi-generate.nix +++ b/nixos/modules/services/hardware/nvidia-container-toolkit/cdi-generate.nix @@ -13,11 +13,14 @@ inherit hostPath containerPath; options = mountOptions; }; - jqAddMountExpression = ".containerEdits.mounts[.containerEdits.mounts | length] |= . +"; - allJqMounts = lib.concatMap - (mount: - ["${lib.getExe jq} '${jqAddMountExpression} ${builtins.toJSON (mkMount mount)}'"]) - mounts; + mountToCommand = mount: + "additionalMount \"${mount.hostPath}\" \"${mount.containerPath}\" '${builtins.toJSON mount.mountOptions}'"; + mountsToCommands = mounts: + if (builtins.length mounts) == 0 then + "cat" + else + (lib.strings.concatMapStringsSep " | \\\n" + mountToCommand mounts); in writeScriptBin "nvidia-cdi-generator" '' @@ -32,6 +35,18 @@ function cdiGenerate { --nvidia-ctk-path ${lib.getExe' nvidia-container-toolkit "nvidia-ctk"} } -cdiGenerate | \ - ${lib.concatStringsSep " | " allJqMounts} > $RUNTIME_DIRECTORY/nvidia-container-toolkit.json +function additionalMount { + local hostPath="$1" + local containerPath="$2" + local mountOptions="$3" + if [ -e "$hostPath" ]; then + ${lib.getExe jq} ".containerEdits.mounts[.containerEdits.mounts | length] = { \"hostPath\": \"$hostPath\", \"containerPath\": \"$containerPath\", \"options\": $mountOptions }" + else + echo "Mount $hostPath ignored: could not find path in the host machine" >&2 + cat + fi +} + +cdiGenerate | + ${mountsToCommands mounts} > $RUNTIME_DIRECTORY/nvidia-container-toolkit.json '' diff --git a/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix b/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix index 5c0fed35c4c9..450651e8b601 100644 --- a/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix +++ b/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix @@ -71,54 +71,69 @@ /usr/local/nvidia/lib64. ''; }; + + package = lib.mkPackageOption pkgs "nvidia-container-toolkit" { }; }; }; - config = { + config = lib.mkIf config.hardware.nvidia-container-toolkit.enable { + virtualisation.docker = { + daemon.settings = lib.mkIf + (lib.versionAtLeast config.virtualisation.docker.package.version "25") { + features.cdi = true; + }; - virtualisation.docker.daemon.settings = lib.mkIf - (config.hardware.nvidia-container-toolkit.enable && - (lib.versionAtLeast config.virtualisation.docker.package.version "25")) { - features.cdi = true; - }; + rootless.daemon.settings = lib.mkIf + (config.virtualisation.docker.rootless.enable && + (lib.versionAtLeast config.virtualisation.docker.package.version "25")) { + features.cdi = true; + }; + }; - hardware.nvidia-container-toolkit.mounts = let - nvidia-driver = config.hardware.nvidia.package; - in (lib.mkMerge [ - [{ hostPath = pkgs.addDriverRunpath.driverLink; - containerPath = pkgs.addDriverRunpath.driverLink; } - { hostPath = "${lib.getLib nvidia-driver}/etc"; - containerPath = "${lib.getLib nvidia-driver}/etc"; } - { hostPath = "${lib.getLib nvidia-driver}/share"; - containerPath = "${lib.getLib nvidia-driver}/share"; } - { hostPath = "${lib.getLib pkgs.glibc}/lib"; - containerPath = "${lib.getLib pkgs.glibc}/lib"; } - { hostPath = "${lib.getLib pkgs.glibc}/lib64"; - containerPath = "${lib.getLib pkgs.glibc}/lib64"; }] - (lib.mkIf config.hardware.nvidia-container-toolkit.mount-nvidia-executables - [{ hostPath = lib.getExe' nvidia-driver "nvidia-cuda-mps-control"; - containerPath = "/usr/bin/nvidia-cuda-mps-control"; } - { hostPath = lib.getExe' nvidia-driver "nvidia-cuda-mps-server"; - containerPath = "/usr/bin/nvidia-cuda-mps-server"; } - { hostPath = lib.getExe' nvidia-driver "nvidia-debugdump"; - containerPath = "/usr/bin/nvidia-debugdump"; } - { hostPath = lib.getExe' nvidia-driver "nvidia-powerd"; - containerPath = "/usr/bin/nvidia-powerd"; } - { hostPath = lib.getExe' nvidia-driver "nvidia-smi"; - containerPath = "/usr/bin/nvidia-smi"; }]) - # nvidia-docker 1.0 uses /usr/local/nvidia/lib{,64} - # e.g. - # - https://gitlab.com/nvidia/container-images/cuda/-/blob/e3ff10eab3a1424fe394899df0e0f8ca5a410f0f/dist/12.3.1/ubi9/base/Dockerfile#L44 - # - https://github.com/NVIDIA/nvidia-docker/blob/01d2c9436620d7dde4672e414698afe6da4a282f/src/nvidia/volumes.go#L104-L173 - (lib.mkIf config.hardware.nvidia-container-toolkit.mount-nvidia-docker-1-directories - [{ hostPath = "${lib.getLib nvidia-driver}/lib"; - containerPath = "/usr/local/nvidia/lib"; } - { hostPath = "${lib.getLib nvidia-driver}/lib"; - containerPath = "/usr/local/nvidia/lib64"; }]) - ]); + hardware = { + graphics.enable = lib.mkIf (!config.hardware.nvidia.datacenter.enable) true; - systemd.services.nvidia-container-toolkit-cdi-generator = lib.mkIf config.hardware.nvidia-container-toolkit.enable { + nvidia-container-toolkit.mounts = let + nvidia-driver = config.hardware.nvidia.package; + in (lib.mkMerge [ + [{ hostPath = pkgs.addDriverRunpath.driverLink; + containerPath = pkgs.addDriverRunpath.driverLink; } + { hostPath = "${lib.getLib nvidia-driver}/etc"; + containerPath = "${lib.getLib nvidia-driver}/etc"; } + { hostPath = "${lib.getLib nvidia-driver}/share"; + containerPath = "${lib.getLib nvidia-driver}/share"; } + { hostPath = "${lib.getLib pkgs.glibc}/lib"; + containerPath = "${lib.getLib pkgs.glibc}/lib"; } + { hostPath = "${lib.getLib pkgs.glibc}/lib64"; + containerPath = "${lib.getLib pkgs.glibc}/lib64"; }] + (lib.mkIf config.hardware.nvidia-container-toolkit.mount-nvidia-executables + [{ hostPath = lib.getExe' nvidia-driver "nvidia-cuda-mps-control"; + containerPath = "/usr/bin/nvidia-cuda-mps-control"; } + { hostPath = lib.getExe' nvidia-driver "nvidia-cuda-mps-server"; + containerPath = "/usr/bin/nvidia-cuda-mps-server"; } + { hostPath = lib.getExe' nvidia-driver "nvidia-debugdump"; + containerPath = "/usr/bin/nvidia-debugdump"; } + { hostPath = lib.getExe' nvidia-driver "nvidia-powerd"; + containerPath = "/usr/bin/nvidia-powerd"; } + { hostPath = lib.getExe' nvidia-driver "nvidia-smi"; + containerPath = "/usr/bin/nvidia-smi"; }]) + # nvidia-docker 1.0 uses /usr/local/nvidia/lib{,64} + # e.g. + # - https://gitlab.com/nvidia/container-images/cuda/-/blob/e3ff10eab3a1424fe394899df0e0f8ca5a410f0f/dist/12.3.1/ubi9/base/Dockerfile#L44 + # - https://github.com/NVIDIA/nvidia-docker/blob/01d2c9436620d7dde4672e414698afe6da4a282f/src/nvidia/volumes.go#L104-L173 + (lib.mkIf config.hardware.nvidia-container-toolkit.mount-nvidia-docker-1-directories + [{ hostPath = "${lib.getLib nvidia-driver}/lib"; + containerPath = "/usr/local/nvidia/lib"; } + { hostPath = "${lib.getLib nvidia-driver}/lib"; + containerPath = "/usr/local/nvidia/lib64"; }]) + ]); + }; + + services.xserver.videoDrivers = lib.mkIf + (!config.hardware.nvidia.datacenter.enable) [ "nvidia" ]; + + systemd.services.nvidia-container-toolkit-cdi-generator = { description = "Container Device Interface (CDI) for Nvidia generator"; wantedBy = [ "multi-user.target" ]; after = [ "systemd-udev-settle.service" ]; @@ -129,6 +144,7 @@ let script = pkgs.callPackage ./cdi-generate.nix { inherit (config.hardware.nvidia-container-toolkit) mounts; + nvidia-container-toolkit = config.hardware.nvidia-container-toolkit.package; nvidia-driver = config.hardware.nvidia.package; deviceNameStrategy = config.hardware.nvidia-container-toolkit.device-name-strategy; }; diff --git a/nixos/modules/services/hardware/openrgb.nix b/nixos/modules/services/hardware/openrgb.nix index 4dc521aa9780..0e06f9720ac1 100644 --- a/nixos/modules/services/hardware/openrgb.nix +++ b/nixos/modules/services/hardware/openrgb.nix @@ -1,21 +1,18 @@ { pkgs, lib, config, ... }: - -with lib; - let cfg = config.services.hardware.openrgb; in { options.services.hardware.openrgb = { - enable = mkEnableOption "OpenRGB server, for RGB lighting control"; + enable = lib.mkEnableOption "OpenRGB server, for RGB lighting control"; - package = mkPackageOption pkgs "openrgb" { }; + package = lib.mkPackageOption pkgs "openrgb" { }; - motherboard = mkOption { - type = types.nullOr (types.enum [ "amd" "intel" ]); + motherboard = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "amd" "intel" ]); default = if config.hardware.cpu.intel.updateMicrocode then "intel" else if config.hardware.cpu.amd.updateMicrocode then "amd" else null; - defaultText = literalMD '' + defaultText = lib.literalMD '' if config.hardware.cpu.intel.updateMicrocode then "intel" else if config.hardware.cpu.amd.updateMicrocode then "amd" else null; @@ -23,15 +20,15 @@ in { description = "CPU family of motherboard. Allows for addition motherboard i2c support."; }; - server.port = mkOption { - type = types.port; + server.port = lib.mkOption { + type = lib.types.port; default = 6742; description = "Set server port of openrgb."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; services.udev.packages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix index 17bab2c5bf20..df98c1fd208d 100644 --- a/nixos/modules/services/hardware/pcscd.nix +++ b/nixos/modules/services/hardware/pcscd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.pcscd; cfgFile = pkgs.writeText "reader.conf" config.services.pcscd.readerConfig; @@ -18,17 +15,17 @@ let in { options.services.pcscd = { - enable = mkEnableOption "PCSC-Lite daemon, to access smart cards using SCard API (PC/SC)"; + enable = lib.mkEnableOption "PCSC-Lite daemon, to access smart cards using SCard API (PC/SC)"; - plugins = mkOption { - type = types.listOf types.package; - defaultText = literalExpression "[ pkgs.ccid ]"; - example = literalExpression "[ pkgs.pcsc-cyberjack ]"; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.package; + defaultText = lib.literalExpression "[ pkgs.ccid ]"; + example = lib.literalExpression "[ pkgs.pcsc-cyberjack ]"; description = "Plugin packages to be used for PCSC-Lite."; }; - readerConfig = mkOption { - type = types.lines; + readerConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = '' FRIENDLYNAME "Some serial reader" @@ -43,14 +40,14 @@ in ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = "Extra command line arguments to be passed to the PCSC daemon."; }; }; - config = mkIf config.services.pcscd.enable { + config = lib.mkIf config.services.pcscd.enable { environment.etc."reader.conf".source = cfgFile; environment.systemPackages = [ package ]; diff --git a/nixos/modules/services/hardware/pommed.nix b/nixos/modules/services/hardware/pommed.nix index 9cdb2d4d1af8..c5efb76d6eec 100644 --- a/nixos/modules/services/hardware/pommed.nix +++ b/nixos/modules/services/hardware/pommed.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.hardware.pommed; defaultConf = "${pkgs.pommed_light}/etc/pommed.conf.mactel"; in { @@ -10,8 +7,8 @@ in { services.hardware.pommed = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to use the pommed tool to handle Apple laptop @@ -19,8 +16,8 @@ in { ''; }; - configFile = mkOption { - type = types.nullOr types.path; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' The path to the {file}`pommed.conf` file. Leave @@ -35,7 +32,7 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.polkit pkgs.pommed_light ]; environment.etc."pommed.conf".source = diff --git a/nixos/modules/services/hardware/rasdaemon.nix b/nixos/modules/services/hardware/rasdaemon.nix index 3fe75984b3fb..ac3c675a7fbe 100644 --- a/nixos/modules/services/hardware/rasdaemon.nix +++ b/nixos/modules/services/hardware/rasdaemon.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.rasdaemon; @@ -10,16 +7,16 @@ in { options.hardware.rasdaemon = { - enable = mkEnableOption "RAS logging daemon"; + enable = lib.mkEnableOption "RAS logging daemon"; - record = mkOption { - type = types.bool; + record = lib.mkOption { + type = lib.types.bool; default = true; description = "record events via sqlite3, required for ras-mc-ctl"; }; - mainboard = mkOption { - type = types.lines; + mainboard = lib.mkOption { + type = lib.types.lines; default = ""; description = "Custom mainboard description, see {manpage}`ras-mc-ctl(8)` for more details."; example = '' @@ -37,8 +34,8 @@ in # TODO, accept `rasdaemon.labels = " ";` or `rasdaemon.labels = { dell = " "; asrock = " "; };' - labels = mkOption { - type = types.lines; + labels = lib.mkOption { + type = lib.types.lines; default = ""; description = "Additional memory module label descriptions to be placed in /etc/ras/dimm_labels.d/labels"; example = '' @@ -54,8 +51,8 @@ in ''; }; - config = mkOption { - type = types.lines; + config = lib.mkOption { + type = lib.types.lines; default = ""; description = '' rasdaemon configuration, currently only used for CE PFA @@ -69,17 +66,17 @@ in ''; }; - extraModules = mkOption { - type = types.listOf types.str; + extraModules = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "extra kernel modules to load"; example = [ "i7core_edac" ]; }; - testing = mkEnableOption "error injection infrastructure"; + testing = lib.mkEnableOption "error injection infrastructure"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.etc = { "ras/mainboard" = { @@ -97,14 +94,14 @@ in }; }; environment.systemPackages = [ pkgs.rasdaemon ] - ++ optionals (cfg.testing) (with pkgs.error-inject; [ + ++ lib.optionals (cfg.testing) (with pkgs.error-inject; [ edac-inject mce-inject aer-inject ]); boot.initrd.kernelModules = cfg.extraModules - ++ optionals (cfg.testing) [ + ++ lib.optionals (cfg.testing) [ # edac_core and amd64_edac should get loaded automatically # i7core_edac may not be, and may not be required, but should load successfully "edac_core" @@ -114,7 +111,7 @@ in "aer-inject" ]; - boot.kernelPatches = optionals (cfg.testing) [{ + boot.kernelPatches = lib.optionals (cfg.testing) [{ name = "rasdaemon-tests"; patch = null; extraConfig = '' @@ -139,10 +136,10 @@ in wantedBy = [ "multi-user.target" ]; serviceConfig = { - StateDirectory = optionalString (cfg.record) "rasdaemon"; + StateDirectory = lib.optionalString (cfg.record) "rasdaemon"; ExecStart = "${pkgs.rasdaemon}/bin/rasdaemon --foreground" - + optionalString (cfg.record) " --record"; + + lib.optionalString (cfg.record) " --record"; ExecStop = "${pkgs.rasdaemon}/bin/rasdaemon --disable"; Restart = "on-abort"; @@ -152,7 +149,7 @@ in # and everything seems to be enabled without this... }; }; - ras-mc-ctl = mkIf (cfg.labels != "") { + ras-mc-ctl = lib.mkIf (cfg.labels != "") { description = "register DIMM labels on startup"; documentation = [ "man:ras-mc-ctl(8)" ]; wantedBy = [ "multi-user.target" ]; @@ -165,6 +162,6 @@ in }; }; - meta.maintainers = [ maintainers.evils ]; + meta.maintainers = [ lib.maintainers.evils ]; } diff --git a/nixos/modules/services/hardware/ratbagd.nix b/nixos/modules/services/hardware/ratbagd.nix index 4398e8d582ea..c7a6e9093b47 100644 --- a/nixos/modules/services/hardware/ratbagd.nix +++ b/nixos/modules/services/hardware/ratbagd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.ratbagd; in @@ -10,15 +7,15 @@ in options = { services.ratbagd = { - enable = mkEnableOption "ratbagd for configuring gaming mice"; + enable = lib.mkEnableOption "ratbagd for configuring gaming mice"; - package = mkPackageOption pkgs "libratbag" { }; + package = lib.mkPackageOption pkgs "libratbag" { }; }; }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Give users access to the "ratbagctl" tool environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix index b6b36b6b60f4..98207ada78c3 100644 --- a/nixos/modules/services/hardware/sane.nix +++ b/nixos/modules/services/hardware/sane.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let pkg = config.hardware.sane.backends-package.override { @@ -32,7 +29,7 @@ let LD_LIBRARY_PATH = [ "/etc/sane-libs" ]; }; - backends = [ pkg netConf ] ++ optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends; + backends = [ pkg netConf ] ++ lib.optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends; saneConfig = pkgs.mkSaneConfig { paths = backends; inherit (config.hardware.sane) disabledDefaultBackends; }; enabled = config.hardware.sane.enable || config.services.saned.enable; @@ -45,8 +42,8 @@ in options = { - hardware.sane.enable = mkOption { - type = types.bool; + hardware.sane.enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable support for SANE scanners. @@ -57,21 +54,21 @@ in ''; }; - hardware.sane.backends-package = mkOption { - type = types.package; + hardware.sane.backends-package = lib.mkOption { + type = lib.types.package; default = pkgs.sane-backends; - defaultText = literalExpression "pkgs.sane-backends"; + defaultText = lib.literalExpression "pkgs.sane-backends"; description = "Backends driver package to use."; }; - hardware.sane.snapshot = mkOption { - type = types.bool; + hardware.sane.snapshot = lib.mkOption { + type = lib.types.bool; default = false; description = "Use a development snapshot of SANE scanner drivers."; }; - hardware.sane.extraBackends = mkOption { - type = types.listOf types.path; + hardware.sane.extraBackends = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' Packages providing extra SANE backends to enable. @@ -82,11 +79,11 @@ in vendors/devices). ::: ''; - example = literalExpression "[ pkgs.hplipWithPlugin pkgs.sane-airscan ]"; + example = lib.literalExpression "[ pkgs.hplipWithPlugin pkgs.sane-airscan ]"; }; - hardware.sane.disabledDefaultBackends = mkOption { - type = types.listOf types.str; + hardware.sane.disabledDefaultBackends = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "v4l" ]; description = '' @@ -95,14 +92,14 @@ in ''; }; - hardware.sane.configDir = mkOption { - type = types.str; + hardware.sane.configDir = lib.mkOption { + type = lib.types.str; internal = true; description = "The value of SANE_CONFIG_DIR."; }; - hardware.sane.netConf = mkOption { - type = types.lines; + hardware.sane.netConf = lib.mkOption { + type = lib.types.lines; default = ""; example = "192.168.0.16"; description = '' @@ -110,8 +107,8 @@ in ''; }; - hardware.sane.drivers.scanSnap.enable = mkOption { - type = types.bool; + hardware.sane.drivers.scanSnap.enable = lib.mkOption { + type = lib.types.bool; default = false; example = true; description = '' @@ -121,7 +118,7 @@ in ''; }; - hardware.sane.drivers.scanSnap.package = mkPackageOption pkgs [ "sane-drivers" "epjitsu" ] { + hardware.sane.drivers.scanSnap.package = lib.mkPackageOption pkgs [ "sane-drivers" "epjitsu" ] { extraDescription = '' Useful if you want to extract the driver files yourself. @@ -130,8 +127,8 @@ in ''; }; - hardware.sane.openFirewall = mkOption { - type = types.bool; + hardware.sane.openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open ports needed for discovery of scanners on the local network, e.g. @@ -139,8 +136,8 @@ in ''; }; - services.saned.enable = mkOption { - type = types.bool; + services.saned.enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable saned network daemon for remote connection to scanners. @@ -151,8 +148,8 @@ in ''; }; - services.saned.extraConfig = mkOption { - type = types.lines; + services.saned.extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = "192.168.0.0/24"; description = '' @@ -165,9 +162,9 @@ in ###### implementation - config = mkMerge [ - (mkIf enabled { - hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d"; + config = lib.mkMerge [ + (lib.mkIf enabled { + hardware.sane.configDir = lib.mkDefault "${saneConfig}/etc/sane.d"; environment.systemPackages = backends; environment.sessionVariables = env; @@ -176,19 +173,19 @@ in services.udev.packages = backends; users.groups.scanner.gid = config.ids.gids.scanner; - networking.firewall.allowedUDPPorts = mkIf config.hardware.sane.openFirewall [ 8612 ]; + networking.firewall.allowedUDPPorts = lib.mkIf config.hardware.sane.openFirewall [ 8612 ]; systemd.tmpfiles.rules = [ "d /var/lock/sane 0770 root scanner - -" ]; }) - (mkIf config.services.saned.enable { + (lib.mkIf config.services.saned.enable { networking.firewall.connectionTrackingModules = [ "sane" ]; systemd.services."saned@" = { description = "Scanner Service"; - environment = mapAttrs (name: val: toString val) env; + environment = lib.mapAttrs (name: val: toString val) env; serviceConfig = { User = "scanner"; Group = "scanner"; @@ -211,7 +208,7 @@ in users.users.scanner = { uid = config.ids.uids.scanner; group = "scanner"; - extraGroups = [ "lp" ] ++ optionals config.services.avahi.enable [ "avahi" ]; + extraGroups = [ "lp" ] ++ lib.optionals config.services.avahi.enable [ "avahi" ]; }; }) ]; diff --git a/nixos/modules/services/hardware/spacenavd.nix b/nixos/modules/services/hardware/spacenavd.nix index 69ca6f102efe..c09439356998 100644 --- a/nixos/modules/services/hardware/spacenavd.nix +++ b/nixos/modules/services/hardware/spacenavd.nix @@ -1,18 +1,15 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.spacenavd; in { options = { hardware.spacenavd = { - enable = mkEnableOption "spacenavd to support 3DConnexion devices"; + enable = lib.mkEnableOption "spacenavd to support 3DConnexion devices"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.spacenavd = { description = "Daemon for the Spacenavigator 6DOF mice by 3Dconnexion"; wantedBy = [ "graphical.target" ]; diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix index e414b9647c9b..24bb20b0146d 100644 --- a/nixos/modules/services/hardware/tcsd.nix +++ b/nixos/modules/services/hardware/tcsd.nix @@ -1,8 +1,5 @@ # tcsd daemon. - { config, options, pkgs, lib, ... }: - -with lib; let cfg = config.services.tcsd; @@ -37,9 +34,9 @@ in services.tcsd = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to enable tcsd, a Trusted Computing management service that provides TCG Software Stack (TSS). The tcsd daemon is @@ -48,21 +45,21 @@ in ''; }; - user = mkOption { + user = lib.mkOption { default = "tss"; - type = types.str; + type = lib.types.str; description = "User account under which tcsd runs."; }; - group = mkOption { + group = lib.mkOption { default = "tss"; - type = types.str; + type = lib.types.str; description = "Group account under which tcsd runs."; }; - stateDir = mkOption { + stateDir = lib.mkOption { default = "/var/lib/tpm"; - type = types.path; + type = lib.types.path; description = '' The location of the system persistent storage file. The system persistent storage file holds keys and data across @@ -70,22 +67,22 @@ in ''; }; - firmwarePCRs = mkOption { + firmwarePCRs = lib.mkOption { default = "0,1,2,3,4,5,6,7"; - type = types.str; + type = lib.types.str; description = "PCR indices used in the TPM for firmware measurements."; }; - kernelPCRs = mkOption { + kernelPCRs = lib.mkOption { default = "8,9,10,11,12"; - type = types.str; + type = lib.types.str; description = "PCR indices used in the TPM for kernel measurements."; }; - platformCred = mkOption { + platformCred = lib.mkOption { default = "${cfg.stateDir}/platform.cert"; - defaultText = literalExpression ''"''${config.${opt.stateDir}}/platform.cert"''; - type = types.path; + defaultText = lib.literalExpression ''"''${config.${opt.stateDir}}/platform.cert"''; + type = lib.types.path; description = '' Path to the platform credential for your TPM. Your TPM manufacturer may have provided you with a set of credentials @@ -96,19 +93,19 @@ in on this process. ''; }; - conformanceCred = mkOption { + conformanceCred = lib.mkOption { default = "${cfg.stateDir}/conformance.cert"; - defaultText = literalExpression ''"''${config.${opt.stateDir}}/conformance.cert"''; - type = types.path; + defaultText = lib.literalExpression ''"''${config.${opt.stateDir}}/conformance.cert"''; + type = lib.types.path; description = '' Path to the conformance credential for your TPM. See also the platformCred option''; }; - endorsementCred = mkOption { + endorsementCred = lib.mkOption { default = "${cfg.stateDir}/endorsement.cert"; - defaultText = literalExpression ''"''${config.${opt.stateDir}}/endorsement.cert"''; - type = types.path; + defaultText = lib.literalExpression ''"''${config.${opt.stateDir}}/endorsement.cert"''; + type = lib.types.path; description = '' Path to the endorsement credential for your TPM. See also the platformCred option''; @@ -119,7 +116,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.trousers ]; @@ -150,13 +147,13 @@ in }; }; - users.users = optionalAttrs (cfg.user == "tss") { + users.users = lib.optionalAttrs (cfg.user == "tss") { tss = { group = "tss"; isSystemUser = true; }; }; - users.groups = optionalAttrs (cfg.group == "tss") { tss = {}; }; + users.groups = lib.optionalAttrs (cfg.group == "tss") { tss = {}; }; }; } diff --git a/nixos/modules/services/hardware/thermald.nix b/nixos/modules/services/hardware/thermald.nix index fb7cf3735a7e..d7f706f1ef05 100644 --- a/nixos/modules/services/hardware/thermald.nix +++ b/nixos/modules/services/hardware/thermald.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.thermald; in @@ -9,24 +6,24 @@ in ###### interface options = { services.thermald = { - enable = mkEnableOption "thermald, the temperature management daemon"; + enable = lib.mkEnableOption "thermald, the temperature management daemon"; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable debug logging. ''; }; - ignoreCpuidCheck = mkOption { - type = types.bool; + ignoreCpuidCheck = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to ignore the cpuid check to allow running on unsupported platforms"; }; - configFile = mkOption { - type = types.nullOr types.path; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' The thermald manual configuration file. @@ -37,12 +34,12 @@ in ''; }; - package = mkPackageOption pkgs "thermald" { }; + package = lib.mkPackageOption pkgs "thermald" { }; }; }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.dbus.packages = [ cfg.package ]; systemd.services.thermald = { @@ -53,8 +50,8 @@ in ExecStart = '' ${cfg.package}/sbin/thermald \ --no-daemon \ - ${optionalString cfg.debug "--loglevel=debug"} \ - ${optionalString cfg.ignoreCpuidCheck "--ignore-cpuid-check"} \ + ${lib.optionalString cfg.debug "--loglevel=debug"} \ + ${lib.optionalString cfg.ignoreCpuidCheck "--ignore-cpuid-check"} \ ${if cfg.configFile != null then "--config-file ${cfg.configFile}" else "--adaptive"} \ --dbus-enable ''; diff --git a/nixos/modules/services/hardware/thinkfan.nix b/nixos/modules/services/hardware/thinkfan.nix index 37c9fef03d78..9733fbe5aa15 100644 --- a/nixos/modules/services/hardware/thinkfan.nix +++ b/nixos/modules/services/hardware/thinkfan.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.thinkfan; @@ -10,13 +7,13 @@ let thinkfan = pkgs.thinkfan.override { inherit (cfg) smartSupport; }; # fan-speed and temperature levels - levelType = with types; + levelType = with lib.types; let - tuple = ts: mkOptionType { + tuple = ts: lib.mkOptionType { name = "tuple"; - merge = mergeOneOption; - check = xs: all id (zipListsWith (t: x: t.check x) ts xs); - description = "tuple of" + concatMapStrings (t: " (${t.description})") ts; + merge = lib.mergeOneOption; + check = xs: lib.all lib.id (lib.zipListsWith (t: x: t.check x) ts xs); + description = "tuple of" + lib.concatMapStrings (t: " (${t.description})") ts; }; level = ints.unsigned; special = enum [ "level auto" "level full-speed" "level disengaged" ]; @@ -24,11 +21,11 @@ let tuple [ (either level special) level level ]; # sensor or fan config - sensorType = name: types.submodule { - freeformType = types.attrsOf settingsFormat.type; + sensorType = name: lib.types.submodule { + freeformType = lib.types.attrsOf settingsFormat.type; options = { - type = mkOption { - type = types.enum [ "hwmon" "atasmart" "tpacpi" "nvml" ]; + type = lib.mkOption { + type = lib.types.enum [ "hwmon" "atasmart" "tpacpi" "nvml" ]; description = '' The ${name} type, can be `hwmon` for standard ${name}s, @@ -41,8 +38,8 @@ let `nvml` for the (proprietary) nVidia driver. ''; }; - query = mkOption { - type = types.str; + query = lib.mkOption { + type = lib.types.str; description = '' The query string used to match one or more ${name}s: can be a fullpath to the temperature file (single ${name}) or a fullpath @@ -54,8 +51,8 @@ let ::: ''; }; - indices = mkOption { - type = with types; nullOr (listOf ints.unsigned); + indices = lib.mkOption { + type = with lib.types; nullOr (listOf ints.unsigned); default = null; description = '' A list of ${name}s to pick in case multiple ${name}s match the query. @@ -65,9 +62,9 @@ let ::: ''; }; - } // optionalAttrs (name == "sensor") { - correction = mkOption { - type = with types; nullOr (listOf int); + } // lib.optionalAttrs (name == "sensor") { + correction = lib.mkOption { + type = with lib.types; nullOr (listOf int); default = null; description = '' A list of values to be added to the temperature of each sensor, @@ -79,7 +76,7 @@ let # removes NixOS special and unused attributes sensorToConf = { type, query, ... }@args: - (filterAttrs (k: v: v != null && !(elem k ["type" "query"])) args) + (lib.filterAttrs (k: v: v != null && !(lib.elem k ["type" "query"])) args) // { "${type}" = query; }; syntaxNote = name: '' @@ -103,8 +100,8 @@ in { services.thinkfan = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable thinkfan, a fan control program. @@ -117,8 +114,8 @@ in { relatedPackages = [ "thinkfan" ]; }; - smartSupport = mkOption { - type = types.bool; + smartSupport = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to build thinkfan with S.M.A.R.T. support to read temperatures @@ -126,8 +123,8 @@ in { ''; }; - sensors = mkOption { - type = types.listOf (sensorType "sensor"); + sensors = lib.mkOption { + type = lib.types.listOf (sensorType "sensor"); default = [ { type = "tpacpi"; query = "/proc/acpi/ibm/thermal"; @@ -140,8 +137,8 @@ in { ''; }; - fans = mkOption { - type = types.listOf (sensorType "fan"); + fans = lib.mkOption { + type = lib.types.listOf (sensorType "fan"); default = [ { type = "tpacpi"; query = "/proc/acpi/ibm/fan"; @@ -154,8 +151,8 @@ in { ''; }; - levels = mkOption { - type = types.listOf levelType; + levels = lib.mkOption { + type = lib.types.listOf levelType; default = [ [0 0 55] [1 48 60] @@ -177,8 +174,8 @@ in { ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "-b" "0" ]; description = '' @@ -187,8 +184,8 @@ in { ''; }; - settings = mkOption { - type = types.attrsOf settingsFormat.type; + settings = lib.mkOption { + type = lib.types.attrsOf settingsFormat.type; default = { }; description = '' Thinkfan settings. Use this option to configure thinkfan @@ -203,11 +200,11 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ thinkfan ]; - services.thinkfan.settings = mapAttrs (k: v: mkDefault v) { + services.thinkfan.settings = lib.mapAttrs (k: v: lib.mkDefault v) { sensors = map sensorToConf cfg.sensors; fans = map sensorToConf cfg.fans; levels = cfg.levels; @@ -216,7 +213,7 @@ in { systemd.packages = [ thinkfan ]; systemd.services = { - thinkfan.environment.THINKFAN_ARGS = escapeShellArgs ([ "-c" configFile ] ++ cfg.extraArgs); + thinkfan.environment.THINKFAN_ARGS = lib.escapeShellArgs ([ "-c" configFile ] ++ cfg.extraArgs); thinkfan.serviceConfig = { Restart = "on-failure"; RestartSec = "30s"; diff --git a/nixos/modules/services/hardware/throttled.nix b/nixos/modules/services/hardware/throttled.nix index 143dc83a1d8b..30f10b3361a6 100644 --- a/nixos/modules/services/hardware/throttled.nix +++ b/nixos/modules/services/hardware/throttled.nix @@ -1,23 +1,20 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.throttled; in { options = { services.throttled = { - enable = mkEnableOption "fix for Intel CPU throttling"; + enable = lib.mkEnableOption "fix for Intel CPU throttling"; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = "Alternative configuration"; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.packages = [ pkgs.throttled ]; # The upstream package has this in Install, but that's not enough, see the NixOS manual systemd.services.throttled.wantedBy = [ "multi-user.target" ]; @@ -31,6 +28,6 @@ in { # Kernel 5.9 spams warnings whenever userspace writes to CPU MSRs. # See https://github.com/erpalma/throttled/issues/215 hardware.cpu.x86.msr.settings.allow-writes = - mkIf (versionAtLeast config.boot.kernelPackages.kernel.version "5.9") "on"; + lib.mkIf (lib.versionAtLeast config.boot.kernelPackages.kernel.version "5.9") "on"; }; } diff --git a/nixos/modules/services/hardware/tlp.nix b/nixos/modules/services/hardware/tlp.nix index 148a88e2030f..53e232a32912 100644 --- a/nixos/modules/services/hardware/tlp.nix +++ b/nixos/modules/services/hardware/tlp.nix @@ -1,14 +1,13 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.tlp; enableRDW = config.networking.networkmanager.enable; tlp = pkgs.tlp.override { inherit enableRDW; }; # TODO: Use this for having proper parameters in the future - mkTlpConfig = tlpConfig: generators.toKeyValue { - mkKeyValue = generators.mkKeyValueDefault { + mkTlpConfig = tlpConfig: lib.generators.toKeyValue { + mkKeyValue = lib.generators.mkKeyValueDefault { mkValueString = val: - if isList val then "\"" + (toString val) + "\"" + if lib.isList val then "\"" + (toString val) + "\"" else toString val; } "="; } tlpConfig; @@ -17,13 +16,13 @@ in ###### interface options = { services.tlp = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the TLP power management daemon."; }; - settings = mkOption {type = with types; attrsOf (oneOf [bool int float str (listOf str)]); + settings = lib.mkOption {type = with lib.types; attrsOf (oneOf [bool int float str (listOf str)]); default = {}; example = { SATA_LINKPWR_ON_BAT = "med_power_with_dipm"; @@ -34,8 +33,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Verbatim additional configuration variables for TLP. @@ -46,10 +45,10 @@ in }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { hardware.cpu.x86.msr.enable = true; - warnings = optional (cfg.extraConfig != "") '' + warnings = lib.optional (cfg.extraConfig != "") '' Using config.services.tlp.extraConfig is deprecated and will become unsupported in a future release. Use config.services.tlp.settings instead. ''; @@ -63,7 +62,7 @@ in environment.etc = { "tlp.conf".text = (mkTlpConfig cfg.settings) + cfg.extraConfig; - } // optionalAttrs enableRDW { + } // lib.optionalAttrs enableRDW { "NetworkManager/dispatcher.d/99tlp-rdw-nm".source = "${tlp}/usr/lib/NetworkManager/dispatcher.d/99tlp-rdw-nm"; }; diff --git a/nixos/modules/services/hardware/triggerhappy.nix b/nixos/modules/services/hardware/triggerhappy.nix index 89f8754c0e68..d2137971b3a7 100644 --- a/nixos/modules/services/hardware/triggerhappy.nix +++ b/nixos/modules/services/hardware/triggerhappy.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.triggerhappy; @@ -9,9 +6,9 @@ let socket = "/run/thd.socket"; configFile = pkgs.writeText "triggerhappy.conf" '' - ${concatMapStringsSep "\n" + ${lib.concatMapStringsSep "\n" ({ keys, event, cmd, ... }: - ''${concatMapStringsSep "+" (x: "KEY_" + x) keys} ${toString { press = 1; hold = 2; release = 0; }.${event}} ${cmd}'' + ''${lib.concatMapStringsSep "+" (x: "KEY_" + x) keys} ${toString { press = 1; hold = 2; release = 0; }.${event}} ${cmd}'' ) cfg.bindings} ${cfg.extraConfig} @@ -20,19 +17,19 @@ let bindingCfg = { ... }: { options = { - keys = mkOption { - type = types.listOf types.str; + keys = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "List of keys to match. Key names as defined in linux/input-event-codes.h"; }; - event = mkOption { - type = types.enum ["press" "hold" "release"]; + event = lib.mkOption { + type = lib.types.enum ["press" "hold" "release"]; default = "press"; description = "Event to match."; }; - cmd = mkOption { - type = types.str; + cmd = lib.mkOption { + type = lib.types.str; description = "What to run."; }; @@ -49,16 +46,16 @@ in services.triggerhappy = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the {command}`triggerhappy` hotkey daemon. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "nobody"; example = "root"; description = '' @@ -66,8 +63,8 @@ in ''; }; - bindings = mkOption { - type = types.listOf (types.submodule bindingCfg); + bindings = lib.mkOption { + type = lib.types.listOf (lib.types.submodule bindingCfg); default = []; example = lib.literalExpression '' [ { keys = ["PLAYPAUSE"]; cmd = "''${pkgs.mpc-cli}/bin/mpc -q toggle"; } ] @@ -77,8 +74,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Literal contents to append to the end of {command}`triggerhappy` configuration file. @@ -92,7 +89,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.sockets.triggerhappy = { description = "Triggerhappy Socket"; @@ -104,7 +101,7 @@ in wantedBy = [ "multi-user.target" ]; description = "Global hotkey daemon"; serviceConfig = { - ExecStart = "${pkgs.triggerhappy}/bin/thd ${optionalString (cfg.user != "root") "--user ${cfg.user}"} --socket ${socket} --triggers ${configFile} --deviceglob /dev/input/event*"; + ExecStart = "${pkgs.triggerhappy}/bin/thd ${lib.optionalString (cfg.user != "root") "--user ${cfg.user}"} --socket ${socket} --triggers ${configFile} --deviceglob /dev/input/event*"; }; }; diff --git a/nixos/modules/services/hardware/tuxedo-rs.nix b/nixos/modules/services/hardware/tuxedo-rs.nix index 506454c1cadf..cfdc1c64d118 100644 --- a/nixos/modules/services/hardware/tuxedo-rs.nix +++ b/nixos/modules/services/hardware/tuxedo-rs.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.hardware.tuxedo-rs; @@ -9,13 +6,13 @@ in { options = { hardware.tuxedo-rs = { - enable = mkEnableOption "Rust utilities for interacting with hardware from TUXEDO Computers"; + enable = lib.mkEnableOption "Rust utilities for interacting with hardware from TUXEDO Computers"; - tailor-gui.enable = mkEnableOption "tailor-gui, an alternative to TUXEDO Control Center, written in Rust"; + tailor-gui.enable = lib.mkEnableOption "tailor-gui, an alternative to TUXEDO Control Center, written in Rust"; }; }; - config = mkIf cfg.enable (mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { hardware.tuxedo-keyboard.enable = true; @@ -40,10 +37,10 @@ in environment.systemPackages = [ pkgs.tuxedo-rs ]; } - (mkIf cfg.tailor-gui.enable { + (lib.mkIf cfg.tailor-gui.enable { environment.systemPackages = [ pkgs.tailor-gui ]; }) ]); - meta.maintainers = with maintainers; [ mrcjkb ]; + meta.maintainers = with lib.maintainers; [ mrcjkb ]; } diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index 67956fdd6c76..a532f629efd0 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let udev = config.systemd.package; @@ -42,7 +39,7 @@ let udevRulesFor = { name, udevPackages, udevPath, udev, systemd, binPackages, initrdBin ? null }: pkgs.runCommand name { preferLocalBuild = true; allowSubstitutes = false; - packages = unique (map toString udevPackages); + packages = lib.unique (map toString udevPackages); } '' mkdir -p $out @@ -70,8 +67,8 @@ let --replace \"/bin/mount \"${pkgs.util-linux}/bin/mount \ --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \ --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename 2>/dev/null - ${optionalString (initrdBin != null) '' - substituteInPlace $i --replace '/run/current-system/systemd' "${removeSuffix "/bin" initrdBin}" + ${lib.optionalString (initrdBin != null) '' + substituteInPlace $i --replace '/run/current-system/systemd' "${lib.removeSuffix "/bin" initrdBin}" ''} done @@ -137,7 +134,7 @@ let # If auto-configuration is disabled, then remove # udev's 80-drivers.rules file, which contains rules for # automatically calling modprobe. - ${optionalString (!config.boot.hardwareScan) '' + ${lib.optionalString (!config.boot.hardwareScan) '' ln -s /dev/null $out/80-drivers.rules ''} ''; @@ -145,7 +142,7 @@ let hwdbBin = pkgs.runCommand "hwdb.bin" { preferLocalBuild = true; allowSubstitutes = false; - packages = unique (map toString ([udev] ++ cfg.packages)); + packages = lib.unique (map toString ([udev] ++ cfg.packages)); } '' mkdir -p etc/udev/hwdb.d @@ -191,8 +188,8 @@ in ###### interface options = { - boot.hardwareScan = mkOption { - type = types.bool; + boot.hardwareScan = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to try to load kernel modules for all detected hardware. @@ -203,12 +200,12 @@ in }; services.udev = { - enable = mkEnableOption "udev, a device manager for the Linux kernel" // { + enable = lib.mkEnableOption "udev, a device manager for the Linux kernel" // { default = true; }; - packages = mkOption { - type = types.listOf types.path; + packages = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' List of packages containing {command}`udev` rules. @@ -217,11 +214,11 @@ in {file}`«pkg»/lib/udev/rules.d` will be included. ''; - apply = map getBin; + apply = map lib.getBin; }; - path = mkOption { - type = types.listOf types.path; + path = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' Packages added to the {env}`PATH` environment variable when @@ -232,12 +229,12 @@ in ''; }; - extraRules = mkOption { + extraRules = lib.mkOption { default = ""; example = '' ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="0825", ENV{PULSE_IGNORE}="1" ''; - type = types.lines; + type = lib.types.lines; description = '' Additional {command}`udev` rules. They'll be written into file {file}`99-local.rules`. Thus they are @@ -245,14 +242,14 @@ in ''; }; - extraHwdb = mkOption { + extraHwdb = lib.mkOption { default = ""; example = '' evdev:input:b0003v05AFp8277* KEYBOARD_KEY_70039=leftalt KEYBOARD_KEY_700e2=leftctrl ''; - type = types.lines; + type = lib.types.lines; description = '' Additional {command}`hwdb` files. They'll be written into file {file}`99-local.hwdb`. Thus they are @@ -262,8 +259,8 @@ in }; - hardware.firmware = mkOption { - type = types.listOf types.package; + hardware.firmware = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; description = '' List of packages containing firmware files. Such files @@ -282,9 +279,9 @@ in }; }; - networking.usePredictableInterfaceNames = mkOption { + networking.usePredictableInterfaceNames = lib.mkOption { default = true; - type = types.bool; + type = lib.types.bool; description = '' Whether to assign [predictable names to network interfaces](https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/). If enabled, interfaces @@ -300,8 +297,8 @@ in boot.initrd.services.udev = { - packages = mkOption { - type = types.listOf types.path; + packages = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' *This will only be used when systemd is used in stage 1.* @@ -314,8 +311,8 @@ in ''; }; - binPackages = mkOption { - type = types.listOf types.path; + binPackages = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' *This will only be used when systemd is used in stage 1.* @@ -323,15 +320,15 @@ in Packages to search for binaries that are referenced by the udev rules in stage 1. This list always contains /bin of the initrd. ''; - apply = map getBin; + apply = map lib.getBin; }; - rules = mkOption { + rules = lib.mkOption { default = ""; example = '' SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1D:60:B9:6D:4F", KERNEL=="eth*", NAME="my_fast_network_card" ''; - type = types.lines; + type = lib.types.lines; description = '' {command}`udev` rules to include in the initrd *only*. They'll be written into file @@ -347,7 +344,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.extraRules = nixosRules; @@ -355,9 +352,9 @@ in services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.util-linux udev ]; - boot.kernelParams = mkIf (!config.networking.usePredictableInterfaceNames) [ "net.ifnames=0" ]; + boot.kernelParams = lib.mkIf (!config.networking.usePredictableInterfaceNames) [ "net.ifnames=0" ]; - boot.initrd.extraUdevRulesCommands = mkIf (!config.boot.initrd.systemd.enable && config.boot.initrd.services.udev.rules != "") + boot.initrd.extraUdevRulesCommands = lib.mkIf (!config.boot.initrd.systemd.enable && config.boot.initrd.services.udev.rules != "") '' cat <<'EOF' > $out/99-local.rules ${config.boot.initrd.services.udev.rules} @@ -397,7 +394,7 @@ in # Insert initrd rules boot.initrd.services.udev.packages = [ initrdUdevRules - (mkIf (config.boot.initrd.services.udev.rules != "") (pkgs.writeTextFile { + (lib.mkIf (config.boot.initrd.services.udev.rules != "") (pkgs.writeTextFile { name = "initrd-udev-rules"; destination = "/etc/udev/rules.d/99-local.rules"; text = config.boot.initrd.services.udev.rules; @@ -437,12 +434,12 @@ in ''; systemd.services.systemd-udevd = - { restartTriggers = cfg.packages; + { restartTriggers = [ config.environment.etc."udev/rules.d".source ]; }; }; imports = [ - (mkRenamedOptionModule [ "services" "udev" "initrdRules" ] [ "boot" "initrd" "services" "udev" "rules" ]) + (lib.mkRenamedOptionModule [ "services" "udev" "initrdRules" ] [ "boot" "initrd" "services" "udev" "rules" ]) ]; } diff --git a/nixos/modules/services/hardware/udisks2.nix b/nixos/modules/services/hardware/udisks2.nix index 46a72b961501..e52aa5a58df2 100644 --- a/nixos/modules/services/hardware/udisks2.nix +++ b/nixos/modules/services/hardware/udisks2.nix @@ -1,13 +1,11 @@ # Udisks daemon. { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.udisks2; settingsFormat = pkgs.formats.ini { - listToValue = concatMapStringsSep "," (generators.mkValueStringDefault {}); + listToValue = lib.concatMapStringsSep "," (lib.generators.mkValueStringDefault {}); }; - configFiles = mapAttrs (name: value: (settingsFormat.generate name value)) (mapAttrs' (name: value: nameValuePair name value ) config.services.udisks2.settings); + configFiles = lib.mapAttrs (name: value: (settingsFormat.generate name value)) (lib.mapAttrs' (name: value: lib.nameValuePair name value ) config.services.udisks2.settings); in { @@ -18,10 +16,10 @@ in services.udisks2 = { - enable = mkEnableOption "udisks2, a DBus service that allows applications to query and manipulate storage devices"; + enable = lib.mkEnableOption "udisks2, a DBus service that allows applications to query and manipulate storage devices"; - mountOnMedia = mkOption { - type = types.bool; + mountOnMedia = lib.mkOption { + type = lib.types.bool; default = false; description = '' When enabled, instructs udisks2 to mount removable drives under `/media/` directory, instead of the @@ -30,9 +28,9 @@ in ''; }; - settings = mkOption rec { - type = types.attrsOf settingsFormat.type; - apply = recursiveUpdate default; + settings = lib.mkOption rec { + type = lib.types.attrsOf settingsFormat.type; + apply = lib.recursiveUpdate default; default = { "udisks2.conf" = { udisks2 = { @@ -44,7 +42,7 @@ in }; }; }; - example = literalExpression '' + example = lib.literalExpression '' { "WDC-WD10EZEX-60M2NA0-WD-WCC3F3SJ0698.conf" = { ATA = { @@ -67,14 +65,14 @@ in ###### implementation - config = mkIf config.services.udisks2.enable { + config = lib.mkIf config.services.udisks2.enable { environment.systemPackages = [ pkgs.udisks2 ]; - environment.etc = (mapAttrs' (name: value: nameValuePair "udisks2/${name}" { source = value; } ) configFiles) // ( + environment.etc = (lib.mapAttrs' (name: value: lib.nameValuePair "udisks2/${name}" { source = value; } ) configFiles) // ( let libblockdev = pkgs.udisks2.libblockdev; - majorVer = versions.major libblockdev.version; + majorVer = lib.versions.major libblockdev.version; in { # We need to make sure /etc/libblockdev/@major_ver@/conf.d is populated to avoid # warnings @@ -87,11 +85,11 @@ in services.dbus.packages = [ pkgs.udisks2 ]; systemd.tmpfiles.rules = [ "d /var/lib/udisks2 0755 root root -" ] - ++ optional cfg.mountOnMedia "D! /media 0755 root root -"; + ++ lib.optional cfg.mountOnMedia "D! /media 0755 root root -"; services.udev.packages = [ pkgs.udisks2 ]; - services.udev.extraRules = optionalString cfg.mountOnMedia '' + services.udev.extraRules = lib.optionalString cfg.mountOnMedia '' ENV{ID_FS_USAGE}=="filesystem", ENV{UDISKS_FILESYSTEM_SHARED}="1" ''; diff --git a/nixos/modules/services/hardware/undervolt.nix b/nixos/modules/services/hardware/undervolt.nix index 23bc848b2398..1fce225db366 100644 --- a/nixos/modules/services/hardware/undervolt.nix +++ b/nixos/modules/services/hardware/undervolt.nix @@ -1,12 +1,10 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.services.undervolt; mkPLimit = limit: window: if (limit == null && window == null) then null - else assert asserts.assertMsg (limit != null && window != null) "Both power limit and window must be set"; + else assert lib.asserts.assertMsg (limit != null && window != null) "Both power limit and window must be set"; "${toString limit} ${toString window}"; cliArgs = lib.cli.toGNUCommandLine {} { inherit (cfg) @@ -34,96 +32,96 @@ let in { options.services.undervolt = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' Undervolting service for Intel CPUs. Warning: This service is not endorsed by Intel and may permanently damage your hardware. Use at your own risk ''; - verbose = mkOption { - type = types.bool; + verbose = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable verbose logging. ''; }; - package = mkPackageOption pkgs "undervolt" { }; + package = lib.mkPackageOption pkgs "undervolt" { }; - coreOffset = mkOption { - type = types.nullOr types.int; + coreOffset = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The amount of voltage in mV to offset the CPU cores by. ''; }; - gpuOffset = mkOption { - type = types.nullOr types.int; + gpuOffset = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The amount of voltage in mV to offset the GPU by. ''; }; - uncoreOffset = mkOption { - type = types.nullOr types.int; + uncoreOffset = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The amount of voltage in mV to offset uncore by. ''; }; - analogioOffset = mkOption { - type = types.nullOr types.int; + analogioOffset = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The amount of voltage in mV to offset analogio by. ''; }; - temp = mkOption { - type = types.nullOr types.int; + temp = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The temperature target in Celsius degrees. ''; }; - tempAc = mkOption { - type = types.nullOr types.int; + tempAc = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The temperature target on AC power in Celsius degrees. ''; }; - tempBat = mkOption { - type = types.nullOr types.int; + tempBat = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' The temperature target on battery power in Celsius degrees. ''; }; - turbo = mkOption { - type = types.nullOr types.int; + turbo = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' Changes the Intel Turbo feature status (1 is disabled and 0 is enabled). ''; }; - p1.limit = mkOption { - type = with types; nullOr int; + p1.limit = lib.mkOption { + type = with lib.types; nullOr int; default = null; description = '' The P1 Power Limit in Watts. Both limit and window must be set. ''; }; - p1.window = mkOption { - type = with types; nullOr (oneOf [ float int ]); + p1.window = lib.mkOption { + type = with lib.types; nullOr (oneOf [ float int ]); default = null; description = '' The P1 Time Window in seconds. @@ -131,16 +129,16 @@ in ''; }; - p2.limit = mkOption { - type = with types; nullOr int; + p2.limit = lib.mkOption { + type = with lib.types; nullOr int; default = null; description = '' The P2 Power Limit in Watts. Both limit and window must be set. ''; }; - p2.window = mkOption { - type = with types; nullOr (oneOf [ float int ]); + p2.window = lib.mkOption { + type = with lib.types; nullOr (oneOf [ float int ]); default = null; description = '' The P2 Time Window in seconds. @@ -148,8 +146,8 @@ in ''; }; - useTimer = mkOption { - type = types.bool; + useTimer = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to set a timer that applies the undervolt settings every 30s. @@ -160,7 +158,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { hardware.cpu.x86.msr.enable = true; environment.systemPackages = [ cfg.package ]; @@ -179,7 +177,7 @@ in }; }; - systemd.timers.undervolt = mkIf cfg.useTimer { + systemd.timers.undervolt = lib.mkIf cfg.useTimer { description = "Undervolt timer to ensure voltage settings are always applied"; partOf = [ "undervolt.service" ]; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/hardware/upower.nix b/nixos/modules/services/hardware/upower.nix index 3d0edb0467ea..43604b17e848 100644 --- a/nixos/modules/services/hardware/upower.nix +++ b/nixos/modules/services/hardware/upower.nix @@ -1,9 +1,5 @@ # Upower daemon. - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.upower; @@ -18,8 +14,8 @@ in services.upower = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable Upower, a DBus service that provides power @@ -27,10 +23,10 @@ in ''; }; - package = mkPackageOption pkgs "upower" { }; + package = lib.mkPackageOption pkgs "upower" { }; - enableWattsUpPro = mkOption { - type = types.bool; + enableWattsUpPro = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable the Watts Up Pro device. @@ -47,8 +43,8 @@ in ''; }; - noPollBatteries = mkOption { - type = types.bool; + noPollBatteries = lib.mkOption { + type = lib.types.bool; default = false; description = '' Don't poll the kernel for battery level changes. @@ -59,8 +55,8 @@ in ''; }; - ignoreLid = mkOption { - type = types.bool; + ignoreLid = lib.mkOption { + type = lib.types.bool; default = false; description = '' Do we ignore the lid state @@ -73,8 +69,8 @@ in ''; }; - usePercentageForPolicy = mkOption { - type = types.bool; + usePercentageForPolicy = lib.mkOption { + type = lib.types.bool; default = true; description = '' Policy for warnings and action based on battery levels @@ -87,9 +83,9 @@ in ''; }; - percentageLow = mkOption { - type = types.ints.unsigned; - default = 10; + percentageLow = lib.mkOption { + type = lib.types.ints.unsigned; + default = 20; description = '' When `usePercentageForPolicy` is `true`, the levels at which UPower will consider the @@ -105,9 +101,9 @@ in ''; }; - percentageCritical = mkOption { - type = types.ints.unsigned; - default = 3; + percentageCritical = lib.mkOption { + type = lib.types.ints.unsigned; + default = 5; description = '' When `usePercentageForPolicy` is `true`, the levels at which UPower will consider the @@ -123,8 +119,8 @@ in ''; }; - percentageAction = mkOption { - type = types.ints.unsigned; + percentageAction = lib.mkOption { + type = lib.types.ints.unsigned; default = 2; description = '' When `usePercentageForPolicy` is @@ -141,8 +137,8 @@ in ''; }; - timeLow = mkOption { - type = types.ints.unsigned; + timeLow = lib.mkOption { + type = lib.types.ints.unsigned; default = 1200; description = '' When `usePercentageForPolicy` is @@ -155,8 +151,8 @@ in ''; }; - timeCritical = mkOption { - type = types.ints.unsigned; + timeCritical = lib.mkOption { + type = lib.types.ints.unsigned; default = 300; description = '' When `usePercentageForPolicy` is @@ -169,8 +165,8 @@ in ''; }; - timeAction = mkOption { - type = types.ints.unsigned; + timeAction = lib.mkOption { + type = lib.types.ints.unsigned; default = 120; description = '' When `usePercentageForPolicy` is @@ -183,8 +179,8 @@ in ''; }; - criticalPowerAction = mkOption { - type = types.enum [ "PowerOff" "Hibernate" "HybridSleep" ]; + criticalPowerAction = lib.mkOption { + type = lib.types.enum [ "PowerOff" "Hibernate" "HybridSleep" ]; default = "HybridSleep"; description = '' The action to take when `timeAction` or @@ -200,7 +196,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; @@ -210,7 +206,7 @@ in systemd.packages = [ cfg.package ]; - environment.etc."UPower/UPower.conf".text = generators.toINI {} { + environment.etc."UPower/UPower.conf".text = lib.generators.toINI {} { UPower = { EnableWattsUpPro = cfg.enableWattsUpPro; NoPollBatteries = cfg.noPollBatteries; diff --git a/nixos/modules/services/hardware/usbmuxd.nix b/nixos/modules/services/hardware/usbmuxd.nix index 891619934eb6..c1b76ddce3b7 100644 --- a/nixos/modules/services/hardware/usbmuxd.nix +++ b/nixos/modules/services/hardware/usbmuxd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let defaultUserGroup = "usbmux"; @@ -14,8 +11,8 @@ in { options.services.usbmuxd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable the usbmuxd ("USB multiplexing daemon") service. This daemon is @@ -25,35 +22,35 @@ in ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = defaultUserGroup; description = '' The user usbmuxd should use to run after startup. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = defaultUserGroup; description = '' The group usbmuxd should use to run after startup. ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = pkgs.usbmuxd; - defaultText = literalExpression "pkgs.usbmuxd"; + defaultText = lib.literalExpression "pkgs.usbmuxd"; description = "Which package to use for the usbmuxd daemon."; relatedPackages = [ "usbmuxd" "usbmuxd2" ]; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == defaultUserGroup) { + users.users = lib.optionalAttrs (cfg.user == defaultUserGroup) { ${cfg.user} = { description = "usbmuxd user"; group = cfg.group; @@ -61,7 +58,7 @@ in }; }; - users.groups = optionalAttrs (cfg.group == defaultUserGroup) { + users.groups = lib.optionalAttrs (cfg.group == defaultUserGroup) { ${cfg.group} = { }; }; diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix index 6ffe314d4574..c7b28b910515 100644 --- a/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixos/modules/services/home-automation/home-assistant.nix @@ -655,6 +655,7 @@ in { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; User = "hass"; Group = "hass"; + WorkingDirectory = cfg.configDir; Restart = "on-failure"; RestartForceExitStatus = "100"; SuccessExitStatus = "100"; diff --git a/nixos/modules/services/home-automation/matter-server.nix b/nixos/modules/services/home-automation/matter-server.nix index 08a68db71386..8a59815eec66 100644 --- a/nixos/modules/services/home-automation/matter-server.nix +++ b/nixos/modules/services/home-automation/matter-server.nix @@ -3,9 +3,6 @@ , config , ... }: - -with lib; - let cfg = config.services.matter-server; storageDir = "matter-server"; @@ -16,24 +13,24 @@ in { meta.maintainers = with lib.maintainers; [ leonm1 ]; - options.services.matter-server = with types; { - enable = mkEnableOption "Matter-server"; + options.services.matter-server = with lib.types; { + enable = lib.mkEnableOption "Matter-server"; - package = mkPackageOption pkgs "python-matter-server" { }; + package = lib.mkPackageOption pkgs "python-matter-server" { }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5580; description = "Port to expose the matter-server service on."; }; - logLevel = mkOption { - type = types.enum [ "critical" "error" "warning" "info" "debug" ]; + logLevel = lib.mkOption { + type = lib.types.enum [ "critical" "error" "warning" "info" "debug" ]; default = "info"; description = "Verbosity of logs from the matter-server"; }; - extraArgs = mkOption { + extraArgs = lib.mkOption { type = listOf str; default = []; description = '' @@ -43,7 +40,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.matter-server = { after = [ "network-online.target" ]; before = [ "home-assistant.service" ]; @@ -52,13 +49,13 @@ in description = "Matter Server"; environment.HOME = storagePath; serviceConfig = { - ExecStart = (concatStringsSep " " [ + ExecStart = (lib.concatStringsSep " " [ "${cfg.package}/bin/matter-server" "--port" (toString cfg.port) "--vendorid" vendorId "--storage-path" storagePath "--log-level" "${cfg.logLevel}" - "${escapeShellArgs cfg.extraArgs}" + "${lib.escapeShellArgs cfg.extraArgs}" ]); # Start with a clean root filesystem, and allowlist what the container # is permitted to access. @@ -103,7 +100,7 @@ in RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; - SystemCallFilter = concatStringsSep " " [ + SystemCallFilter = lib.concatStringsSep " " [ "~" # Blocklist "@clock" "@cpu-emulation" diff --git a/nixos/modules/services/home-automation/zigbee2mqtt.nix b/nixos/modules/services/home-automation/zigbee2mqtt.nix index f1d150487379..5a9fb0eaebc1 100644 --- a/nixos/modules/services/home-automation/zigbee2mqtt.nix +++ b/nixos/modules/services/home-automation/zigbee2mqtt.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.zigbee2mqtt; @@ -10,28 +7,28 @@ let in { - meta.maintainers = with maintainers; [ sweber hexa ]; + meta.maintainers = with lib.maintainers; [ sweber hexa ]; imports = [ # Remove warning before the 21.11 release - (mkRenamedOptionModule [ "services" "zigbee2mqtt" "config" ] [ "services" "zigbee2mqtt" "settings" ]) + (lib.mkRenamedOptionModule [ "services" "zigbee2mqtt" "config" ] [ "services" "zigbee2mqtt" "settings" ]) ]; options.services.zigbee2mqtt = { - enable = mkEnableOption "zigbee2mqtt service"; + enable = lib.mkEnableOption "zigbee2mqtt service"; - package = mkPackageOption pkgs "zigbee2mqtt" { }; + package = lib.mkPackageOption pkgs "zigbee2mqtt" { }; - dataDir = mkOption { + dataDir = lib.mkOption { description = "Zigbee2mqtt data directory"; default = "/var/lib/zigbee2mqtt"; - type = types.path; + type = lib.types.path; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { homeassistant = config.services.home-assistant.enable; permit_join = true; @@ -48,21 +45,21 @@ in }; }; - config = mkIf (cfg.enable) { + config = lib.mkIf (cfg.enable) { # preset config values services.zigbee2mqtt.settings = { - homeassistant = mkDefault config.services.home-assistant.enable; - permit_join = mkDefault false; + homeassistant = lib.mkDefault config.services.home-assistant.enable; + permit_join = lib.mkDefault false; mqtt = { - base_topic = mkDefault "zigbee2mqtt"; - server = mkDefault "mqtt://localhost:1883"; + base_topic = lib.mkDefault "zigbee2mqtt"; + server = lib.mkDefault "mqtt://localhost:1883"; }; - serial.port = mkDefault "/dev/ttyACM0"; + serial.port = lib.mkDefault "/dev/ttyACM0"; # reference device/group configuration, that is kept in a separate file # to prevent it being overwritten in the units ExecStartPre script - devices = mkDefault "devices.yaml"; - groups = mkDefault "groups.yaml"; + devices = lib.mkDefault "devices.yaml"; + groups = lib.mkDefault "groups.yaml"; }; systemd.services.zigbee2mqtt = { diff --git a/nixos/modules/services/home-automation/zwave-js.nix b/nixos/modules/services/home-automation/zwave-js.nix index 2138719ec6fa..4ce792624269 100644 --- a/nixos/modules/services/home-automation/zwave-js.nix +++ b/nixos/modules/services/home-automation/zwave-js.nix @@ -1,35 +1,32 @@ {config, pkgs, lib, ...}: - -with lib; - let cfg = config.services.zwave-js; mergedConfigFile = "/run/zwave-js/config.json"; settingsFormat = pkgs.formats.json {}; in { options.services.zwave-js = { - enable = mkEnableOption "the zwave-js server on boot"; + enable = lib.mkEnableOption "the zwave-js server on boot"; - package = mkPackageOption pkgs "zwave-js-server" { }; + package = lib.mkPackageOption pkgs "zwave-js-server" { }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 3000; description = '' Port for the server to listen on. ''; }; - serialPort = mkOption { - type = types.path; + serialPort = lib.mkOption { + type = lib.types.path; description = '' Serial port device path for Z-Wave controller. ''; example = "/dev/ttyUSB0"; }; - secretsConfigFile = mkOption { - type = types.path; + secretsConfigFile = lib.mkOption { + type = lib.types.path; description = '' JSON file containing secret keys. A dummy example: @@ -62,14 +59,14 @@ in { example = "/secrets/zwave-js-keys.json"; }; - settings = mkOption { + settings = lib.mkOption { type = lib.types.submodule { freeformType = settingsFormat.type; options = { storage = { - cacheDir = mkOption { - type = types.path; + cacheDir = lib.mkOption { + type = lib.types.path; default = "/var/cache/zwave-js"; readOnly = true; description = "Cache directory"; @@ -94,7 +91,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.zwave-js = let configFile = settingsFormat.generate "zwave-js-config.json" cfg.settings; in { @@ -110,7 +107,7 @@ in { "--config ${mergedConfigFile}" "--port ${toString cfg.port}" cfg.serialPort - (escapeShellArgs cfg.extraFlags) + (lib.escapeShellArgs cfg.extraFlags) ]; Restart = "on-failure"; User = "zwave-js"; diff --git a/nixos/modules/services/logging/SystemdJournal2Gelf.nix b/nixos/modules/services/logging/SystemdJournal2Gelf.nix index 7c50e9e2c42f..5b2f05f8c0f1 100644 --- a/nixos/modules/services/logging/SystemdJournal2Gelf.nix +++ b/nixos/modules/services/logging/SystemdJournal2Gelf.nix @@ -1,22 +1,19 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.SystemdJournal2Gelf; in { options = { services.SystemdJournal2Gelf = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable SystemdJournal2Gelf. ''; }; - graylogServer = mkOption { - type = types.str; + graylogServer = lib.mkOption { + type = lib.types.str; example = "graylog2.example.com:11201"; description = '' Host and port of your graylog2 input. This should be a GELF @@ -24,8 +21,8 @@ in ''; }; - extraOptions = mkOption { - type = types.separatedString " "; + extraOptions = lib.mkOption { + type = lib.types.separatedString " "; default = ""; description = '' Any extra flags to pass to SystemdJournal2Gelf. Note that @@ -33,12 +30,12 @@ in ''; }; - package = mkPackageOption pkgs "systemd-journal2gelf" { }; + package = lib.mkPackageOption pkgs "systemd-journal2gelf" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.SystemdJournal2Gelf = { description = "SystemdJournal2Gelf"; after = [ "network.target" ]; diff --git a/nixos/modules/services/logging/awstats.nix b/nixos/modules/services/logging/awstats.nix index a5b0e6347b2b..d6d1fd64bd52 100644 --- a/nixos/modules/services/logging/awstats.nix +++ b/nixos/modules/services/logging/awstats.nix @@ -1,29 +1,26 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.awstats; package = pkgs.awstats; configOpts = {name, config, ...}: { options = { - type = mkOption{ - type = types.enum [ "mail" "web" ]; + type = lib.mkOption{ + type = lib.types.enum [ "mail" "web" ]; default = "web"; example = "mail"; description = '' The type of log being collected. ''; }; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; default = name; description = "The domain name to collect stats for."; example = "example.com"; }; - logFile = mkOption { - type = types.str; + logFile = lib.mkOption { + type = lib.types.str; example = "/var/log/nginx/access.log"; description = '' The log file to be scanned. @@ -35,8 +32,8 @@ let ''; }; - logFormat = mkOption { - type = types.str; + logFormat = lib.mkOption { + type = lib.types.str; default = "1"; description = '' The log format being used. @@ -48,8 +45,8 @@ let ''; }; - hostAliases = mkOption { - type = types.listOf types.str; + hostAliases = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "www.example.org" ]; description = '' @@ -57,10 +54,10 @@ let ''; }; - extraConfig = mkOption { - type = types.attrsOf types.str; + extraConfig = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { "ValidHTTPCodes" = "404"; } @@ -69,44 +66,44 @@ let }; webService = { - enable = mkEnableOption "awstats web service"; + enable = lib.mkEnableOption "awstats web service"; - hostname = mkOption { - type = types.str; + hostname = lib.mkOption { + type = lib.types.str; default = config.domain; description = "The hostname the web service appears under."; }; - urlPrefix = mkOption { - type = types.str; + urlPrefix = lib.mkOption { + type = lib.types.str; default = "/awstats"; description = "The URL prefix under which the awstats pages appear."; }; }; }; }; - webServices = filterAttrs (name: value: value.webService.enable) cfg.configs; + webServices = lib.filterAttrs (name: value: value.webService.enable) cfg.configs; in { imports = [ - (mkRemovedOptionModule [ "services" "awstats" "service" "enable" ] "Please enable per domain with `services.awstats.configs..webService.enable`") - (mkRemovedOptionModule [ "services" "awstats" "service" "urlPrefix" ] "Please set per domain with `services.awstats.configs..webService.urlPrefix`") - (mkRenamedOptionModule [ "services" "awstats" "vardir" ] [ "services" "awstats" "dataDir" ]) + (lib.mkRemovedOptionModule [ "services" "awstats" "service" "enable" ] "Please enable per domain with `services.awstats.configs..webService.enable`") + (lib.mkRemovedOptionModule [ "services" "awstats" "service" "urlPrefix" ] "Please set per domain with `services.awstats.configs..webService.urlPrefix`") + (lib.mkRenamedOptionModule [ "services" "awstats" "vardir" ] [ "services" "awstats" "dataDir" ]) ]; options.services.awstats = { - enable = mkEnableOption "awstats, a real-time logfile analyzer"; + enable = lib.mkEnableOption "awstats, a real-time logfile analyzer"; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/awstats"; description = "The directory where awstats data will be stored."; }; - configs = mkOption { - type = types.attrsOf (types.submodule configOpts); + configs = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule configOpts); default = {}; - example = literalExpression '' + example = lib.literalExpression '' { "mysite" = { domain = "example.com"; @@ -117,8 +114,8 @@ in description = "Attribute set of domains to collect stats for."; }; - updateAt = mkOption { - type = types.nullOr types.str; + updateAt = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "hourly"; description = '' @@ -129,18 +126,18 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ package.bin ]; - environment.etc = mapAttrs' (name: opts: - nameValuePair "awstats/awstats.${name}.conf" { + environment.etc = lib.mapAttrs' (name: opts: + lib.nameValuePair "awstats/awstats.${name}.conf" { source = pkgs.runCommand "awstats.${name}.conf" { preferLocalBuild = true; } ('' sed \ '' # set up mail stats - + optionalString (opts.type == "mail") + + lib.optionalString (opts.type == "mail") '' -e 's|^\(LogType\)=.*$|\1=M|' \ -e 's|^\(LevelForBrowsersDetection\)=.*$|\1=0|' \ @@ -187,7 +184,7 @@ in '' + # extra config - concatStringsSep "\n" (mapAttrsToList (n: v: '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: '' -e 's|^\(${n}\)=.*$|\1="${v}"|' \ '') opts.extraConfig) + @@ -199,11 +196,11 @@ in # create data directory with the correct permissions systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 755 root root - -" ] ++ - mapAttrsToList (name: opts: "d '${cfg.dataDir}/${name}' 755 root root - -") cfg.configs ++ + lib.mapAttrsToList (name: opts: "d '${cfg.dataDir}/${name}' 755 root root - -") cfg.configs ++ [ "Z '${cfg.dataDir}' 755 root root - -" ]; # nginx options - services.nginx.virtualHosts = mapAttrs'(name: opts: { + services.nginx.virtualHosts = lib.mapAttrs'(name: opts: { name = opts.webService.hostname; value = { locations = { @@ -224,10 +221,10 @@ in }) webServices; # update awstats - systemd.services = mkIf (cfg.updateAt != null) (mapAttrs' (name: opts: - nameValuePair "awstats-${name}-update" { + systemd.services = lib.mkIf (cfg.updateAt != null) (lib.mapAttrs' (name: opts: + lib.nameValuePair "awstats-${name}-update" { description = "update awstats for ${name}"; - script = optionalString (opts.type == "mail") + script = lib.optionalString (opts.type == "mail") '' if [[ -f "${cfg.dataDir}/${name}-cursor" ]]; then CURSOR="$(cat "${cfg.dataDir}/${name}-cursor" | tr -d '\n')" diff --git a/nixos/modules/services/logging/fluentd.nix b/nixos/modules/services/logging/fluentd.nix index bbf905eca06b..fed5cacac37e 100644 --- a/nixos/modules/services/logging/fluentd.nix +++ b/nixos/modules/services/logging/fluentd.nix @@ -1,29 +1,26 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.fluentd; - pluginArgs = concatStringsSep " " (map (x: "-p ${x}") cfg.plugins); + pluginArgs = lib.concatStringsSep " " (map (x: "-p ${x}") cfg.plugins); in { ###### interface options = { services.fluentd = { - enable = mkEnableOption "fluentd, a data/log collector"; + enable = lib.mkEnableOption "fluentd, a data/log collector"; - config = mkOption { - type = types.lines; + config = lib.mkOption { + type = lib.types.lines; default = ""; description = "Fluentd config."; }; - package = mkPackageOption pkgs "fluentd" { }; + package = lib.mkPackageOption pkgs "fluentd" { }; - plugins = mkOption { - type = types.listOf types.path; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' A list of plugin paths to pass into fluentd. It will make plugins defined in ruby files @@ -36,7 +33,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.fluentd = with pkgs; { description = "Fluentd Daemon"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/logging/graylog.nix b/nixos/modules/services/logging/graylog.nix index caeac16815f4..ff1860e99a75 100644 --- a/nixos/modules/services/logging/graylog.nix +++ b/nixos/modules/services/logging/graylog.nix @@ -1,17 +1,14 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.graylog; confFile = pkgs.writeText "graylog.conf" '' - is_master = ${boolToString cfg.isMaster} + is_master = ${lib.boolToString cfg.isMaster} node_id_file = ${cfg.nodeIdFile} password_secret = ${cfg.passwordSecret} root_username = ${cfg.rootUsername} root_password_sha2 = ${cfg.rootPasswordSha2} - elasticsearch_hosts = ${concatStringsSep "," cfg.elasticsearchHosts} + elasticsearch_hosts = ${lib.concatStringsSep "," cfg.elasticsearchHosts} message_journal_dir = ${cfg.messageJournalDir} mongodb_uri = ${cfg.mongodbUri} plugin_dir = /var/lib/graylog/plugins @@ -34,49 +31,49 @@ in services.graylog = { - enable = mkEnableOption "Graylog, a log management solution"; + enable = lib.mkEnableOption "Graylog, a log management solution"; - package = mkOption { - type = types.package; - default = if versionOlder config.system.stateVersion "23.05" then pkgs.graylog-3_3 else pkgs.graylog-5_1; - defaultText = literalExpression (if versionOlder config.system.stateVersion "23.05" then "pkgs.graylog-3_3" else "pkgs.graylog-5_1"); + 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."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "graylog"; description = "User account under which graylog runs"; }; - isMaster = mkOption { - type = types.bool; + isMaster = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether this is the master instance of your Graylog cluster"; }; - nodeIdFile = mkOption { - type = types.str; + nodeIdFile = lib.mkOption { + type = lib.types.str; default = "/var/lib/graylog/server/node-id"; description = "Path of the file containing the graylog node-id"; }; - passwordSecret = mkOption { - type = types.str; + passwordSecret = lib.mkOption { + type = lib.types.str; description = '' You MUST set a secret to secure/pepper the stored user passwords here. Use at least 64 characters. Generate one by using for example: pwgen -N 1 -s 96 ''; }; - rootUsername = mkOption { - type = types.str; + rootUsername = lib.mkOption { + type = lib.types.str; default = "admin"; description = "Name of the default administrator user"; }; - rootPasswordSha2 = mkOption { - type = types.str; + rootPasswordSha2 = lib.mkOption { + type = lib.types.str; example = "e3c652f0ba0b4801205814f8b6bc49672c4c74e25b497770bb89b22cdeb4e952"; description = '' You MUST specify a hash password for the root user (which you only need to initially set up the @@ -88,40 +85,40 @@ in ''; }; - elasticsearchHosts = mkOption { - type = types.listOf types.str; - example = literalExpression ''[ "http://node1:9200" "http://user:password@node2:19200" ]''; + elasticsearchHosts = lib.mkOption { + type = lib.types.listOf lib.types.str; + example = lib.literalExpression ''[ "http://node1:9200" "http://user:password@node2:19200" ]''; description = "List of valid URIs of the http ports of your elastic nodes. If one or more of your elasticsearch hosts require authentication, include the credentials in each node URI that requires authentication"; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/graylog/data"; description = "Directory used to store Graylog server state."; }; - messageJournalDir = mkOption { - type = types.str; + messageJournalDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/graylog/data/journal"; description = "The directory which will be used to store the message journal. The directory must be exclusively used by Graylog and must not contain any other files than the ones created by Graylog itself"; }; - mongodbUri = mkOption { - type = types.str; + mongodbUri = lib.mkOption { + type = lib.types.str; default = "mongodb://localhost/graylog"; description = "MongoDB connection string. See http://docs.mongodb.org/manual/reference/connection-string/ for details"; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Any other configuration options you might want to add"; }; - plugins = mkOption { + plugins = lib.mkOption { description = "Extra graylog plugins"; default = [ ]; - type = types.listOf types.package; + type = lib.types.listOf lib.types.package; }; }; @@ -130,16 +127,16 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = mkIf (cfg.user == "graylog") { + users.users = lib.mkIf (cfg.user == "graylog") { graylog = { isSystemUser = true; group = "graylog"; description = "Graylog server daemon user"; }; }; - users.groups = mkIf (cfg.user == "graylog") { graylog = {}; }; + users.groups = lib.mkIf (cfg.user == "graylog") { graylog = {}; }; systemd.tmpfiles.rules = [ "d '${cfg.messageJournalDir}' - ${cfg.user} - - -" diff --git a/nixos/modules/services/logging/heartbeat.nix b/nixos/modules/services/logging/heartbeat.nix index 1a264cebf6a2..a9fa644d550d 100644 --- a/nixos/modules/services/logging/heartbeat.nix +++ b/nixos/modules/services/logging/heartbeat.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.heartbeat; @@ -18,32 +15,32 @@ in services.heartbeat = { - enable = mkEnableOption "heartbeat, uptime monitoring"; + enable = lib.mkEnableOption "heartbeat, uptime monitoring"; - package = mkPackageOption pkgs "heartbeat" { + package = lib.mkPackageOption pkgs "heartbeat" { example = "heartbeat7"; }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = "heartbeat"; description = "Name of the beat"; }; - tags = mkOption { - type = types.listOf types.str; + tags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "Tags to place on the shipped log messages"; }; - stateDir = mkOption { - type = types.str; + stateDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/heartbeat"; description = "The state directory. heartbeat's own logs and other data are stored here."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = '' heartbeat.monitors: - type: http @@ -56,7 +53,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.rules = [ "d '${cfg.stateDir}' - nobody nogroup - -" diff --git a/nixos/modules/services/logging/journalbeat.nix b/nixos/modules/services/logging/journalbeat.nix index e7d726ab1f61..5c35e84f88e0 100644 --- a/nixos/modules/services/logging/journalbeat.nix +++ b/nixos/modules/services/logging/journalbeat.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.journalbeat; @@ -18,24 +15,24 @@ in services.journalbeat = { - enable = mkEnableOption "journalbeat"; + enable = lib.mkEnableOption "journalbeat"; - package = mkPackageOption pkgs "journalbeat" { }; + package = lib.mkPackageOption pkgs "journalbeat" { }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = "journalbeat"; description = "Name of the beat"; }; - tags = mkOption { - type = types.listOf types.str; + tags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "Tags to place on the shipped log messages"; }; - stateDir = mkOption { - type = types.str; + stateDir = lib.mkOption { + type = lib.types.str; default = "journalbeat"; description = '' Directory below `/var/lib/` to store journalbeat's @@ -44,8 +41,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Any other configuration options you want to add"; }; @@ -53,11 +50,11 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { - assertion = !hasPrefix "/" cfg.stateDir; + assertion = !lib.hasPrefix "/" cfg.stateDir; message = "The option services.journalbeat.stateDir shouldn't be an absolute directory." + " It should be a directory relative to /var/lib/."; diff --git a/nixos/modules/services/logging/journalwatch.nix b/nixos/modules/services/logging/journalwatch.nix index 48fd992ffb65..ab75ed656c19 100644 --- a/nixos/modules/services/logging/journalwatch.nix +++ b/nixos/modules/services/logging/journalwatch.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.journalwatch; user = "journalwatch"; @@ -15,7 +13,7 @@ let priority = ${toString cfg.priority} mail_from = ${cfg.mailFrom} '' - + optionalString (cfg.mailTo != null) '' + + lib.optionalString (cfg.mailTo != null) '' mail_to = ${cfg.mailTo} '' + cfg.extraConfig); @@ -27,7 +25,7 @@ let ''; # empty line at the end needed to to separate the blocks - mkPatterns = filterBlocks: concatStringsSep "\n" (map (block: '' + mkPatterns = filterBlocks: lib.concatStringsSep "\n" (map (block: '' ${block.match} ${block.filters} @@ -48,18 +46,18 @@ let in { options = { services.journalwatch = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, periodically check the journal with journalwatch and report the results by mail. ''; }; - package = mkPackageOption pkgs "journalwatch" { }; + package = lib.mkPackageOption pkgs "journalwatch" { }; - priority = mkOption { - type = types.int; + priority = lib.mkOption { + type = lib.types.int; default = 6; description = '' Lowest priority of message to be considered. @@ -73,33 +71,33 @@ in { # HACK: this is a workaround for journalwatch's usage of socket.getfqdn() which always returns localhost if # there's an alias for the localhost on a separate line in /etc/hosts, or take for ages if it's not present and # then return something right-ish in the direction of /etc/hostname. Just bypass it completely. - mailFrom = mkOption { - type = types.str; + mailFrom = lib.mkOption { + type = lib.types.str; default = "journalwatch@${config.networking.hostName}"; - defaultText = literalExpression ''"journalwatch@''${config.networking.hostName}"''; + defaultText = lib.literalExpression ''"journalwatch@''${config.networking.hostName}"''; description = '' Mail address to send journalwatch reports from. ''; }; - mailTo = mkOption { - type = types.nullOr types.str; + mailTo = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Mail address to send journalwatch reports to. ''; }; - mailBinary = mkOption { - type = types.path; + mailBinary = lib.mkOption { + type = lib.types.path; default = "/run/wrappers/bin/sendmail"; description = '' Sendmail-compatible binary to be used to send the messages. ''; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = '' Extra lines to be added verbatim to the journalwatch/config configuration file. @@ -108,11 +106,11 @@ in { ''; }; - filterBlocks = mkOption { - type = types.listOf (types.submodule { + filterBlocks = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - match = mkOption { - type = types.str; + match = lib.mkOption { + type = lib.types.str; example = "SYSLOG_IDENTIFIER = systemd"; description = '' Syntax: `field = value` @@ -125,8 +123,8 @@ in { ''; }; - filters = mkOption { - type = types.str; + filters = lib.mkOption { + type = lib.types.str; example = '' (Stopped|Stopping|Starting|Started) .* (Reached target|Stopped target) .* @@ -190,8 +188,8 @@ in { ''; }; - interval = mkOption { - type = types.str; + interval = lib.mkOption { + type = lib.types.str; default = "hourly"; description = '' How often to run journalwatch. @@ -199,8 +197,8 @@ in { The format is described in systemd.time(7). ''; }; - accuracy = mkOption { - type = types.str; + accuracy = lib.mkOption { + type = lib.types.str; default = "10min"; description = '' The time window around the interval in which the journalwatch run will be scheduled. @@ -211,7 +209,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.${user} = { isSystemUser = true; @@ -242,7 +240,7 @@ in { # requires a relative directory name to create beneath /var/lib StateDirectory = user; StateDirectoryMode = "0750"; - ExecStart = "${getExe cfg.package} mail"; + ExecStart = "${lib.getExe cfg.package} mail"; # lowest CPU and IO priority, but both still in best-effort class to prevent starvation Nice=19; IOSchedulingPriority=7; diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix index bda7f9a607e1..d937a523c866 100644 --- a/nixos/modules/services/logging/logcheck.nix +++ b/nixos/modules/services/logging/logcheck.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.logcheck; @@ -22,7 +19,7 @@ let flags = "-r ${rulesDir} -c ${configFile} -L ${logFiles} -${levelFlag} -m ${cfg.mailTo}"; - levelFlag = getAttrFromPath [cfg.level] + levelFlag = lib.getAttrFromPath [cfg.level] { paranoid = "p"; server = "s"; workstation = "w"; @@ -43,7 +40,7 @@ let }; writeIgnoreCronRule = name: {level, user, regex, cmdline, ...}: - let escapeRegex = escape (stringToCharacters "\\[]{}()^$?*+|."); + let escapeRegex = lib.escape (lib.stringToCharacters "\\[]{}()^$?*+|."); cmdline_ = builtins.unsafeDiscardStringContext cmdline; re = if regex != "" then regex else if cmdline_ == "" then ".*" else escapeRegex cmdline_; in writeIgnoreRule "cron-${name}" { @@ -53,9 +50,9 @@ let ''; }; - levelOption = mkOption { + levelOption = lib.mkOption { default = "server"; - type = types.enum [ "workstation" "server" "paranoid" ]; + type = lib.types.enum [ "workstation" "server" "paranoid" ]; description = '' Set the logcheck level. ''; @@ -65,9 +62,9 @@ let options = { level = levelOption; - regex = mkOption { + regex = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Regex specifying which log lines to ignore. ''; @@ -77,25 +74,25 @@ let ignoreCronOptions = { options = { - user = mkOption { + user = lib.mkOption { default = "root"; - type = types.str; + type = lib.types.str; description = '' User that runs the cronjob. ''; }; - cmdline = mkOption { + cmdline = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Command line for the cron job. Will be turned into a regex for the logcheck ignore rule. ''; }; - timeArgs = mkOption { + timeArgs = lib.mkOption { default = null; - type = types.nullOr (types.str); + type = lib.types.nullOr (lib.types.str); example = "02 06 * * *"; description = '' "min hr dom mon dow" crontab time args, to auto-create a cronjob too. @@ -109,20 +106,20 @@ in { options = { services.logcheck = { - enable = mkEnableOption "logcheck cron job, to mail anomalies in the system logfiles to the administrator"; + enable = lib.mkEnableOption "logcheck cron job, to mail anomalies in the system logfiles to the administrator"; - user = mkOption { + user = lib.mkOption { default = "logcheck"; - type = types.str; + type = lib.types.str; description = '' Username for the logcheck user. ''; }; - timeOfDay = mkOption { + timeOfDay = lib.mkOption { default = "*"; example = "6"; - type = types.str; + type = lib.types.str; description = '' Time of day to run logcheck. A logcheck will be scheduled at xx:02 each day. Leave default (*) to run every hour. Of course when nothing special was logged, @@ -130,68 +127,68 @@ in ''; }; - mailTo = mkOption { + mailTo = lib.mkOption { default = "root"; example = "you@domain.com"; - type = types.str; + type = lib.types.str; description = '' Email address to send reports to. ''; }; - level = mkOption { + level = lib.mkOption { default = "server"; - type = types.str; + type = lib.types.str; description = '' Set the logcheck level. Either "workstation", "server", or "paranoid". ''; }; - config = mkOption { + config = lib.mkOption { default = "FQDN=1"; - type = types.lines; + type = lib.types.lines; description = '' Config options that you would like in logcheck.conf. ''; }; - files = mkOption { + files = lib.mkOption { default = [ "/var/log/messages" ]; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; example = [ "/var/log/messages" "/var/log/mail" ]; description = '' Which log files to check. ''; }; - extraRulesDirs = mkOption { + extraRulesDirs = lib.mkOption { default = []; example = [ "/etc/logcheck" ]; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; description = '' Directories with extra rules. ''; }; - ignore = mkOption { + ignore = lib.mkOption { default = {}; description = '' This option defines extra ignore rules. ''; - type = with types; attrsOf (submodule ignoreOptions); + type = with lib.types; attrsOf (submodule ignoreOptions); }; - ignoreCron = mkOption { + ignoreCron = lib.mkOption { default = {}; description = '' This option defines extra ignore rules for cronjobs. ''; - type = with types; attrsOf (submodule ignoreCronOptions); + type = with lib.types; attrsOf (submodule ignoreCronOptions); }; - extraGroups = mkOption { + extraGroups = lib.mkOption { default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "postdrop" "mongodb" ]; description = '' Extra groups for the logcheck user, for example to be able to use sendmail, @@ -202,12 +199,12 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.logcheck.extraRulesDirs = - mapAttrsToList writeIgnoreRule cfg.ignore - ++ mapAttrsToList writeIgnoreCronRule cfg.ignoreCron; + lib.mapAttrsToList writeIgnoreRule cfg.ignore + ++ lib.mapAttrsToList writeIgnoreCronRule cfg.ignoreCron; - users.users = optionalAttrs (cfg.user == "logcheck") { + users.users = lib.optionalAttrs (cfg.user == "logcheck") { logcheck = { group = "logcheck"; isSystemUser = true; @@ -216,7 +213,7 @@ in extraGroups = cfg.extraGroups; }; }; - users.groups = optionalAttrs (cfg.user == "logcheck") { + users.groups = lib.optionalAttrs (cfg.user == "logcheck") { logcheck = {}; }; @@ -236,7 +233,7 @@ in mkCron = name: {user, cmdline, timeArgs, ...}: '' ${timeArgs} ${user} ${cmdline} ''; - in mapAttrsToList mkCron (filterAttrs withTime cfg.ignoreCron) + in lib.mapAttrsToList mkCron (lib.filterAttrs withTime cfg.ignoreCron) ++ [ cronJob ]; }; } diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix index 9344277fc1e0..1c161e167be8 100644 --- a/nixos/modules/services/logging/logrotate.nix +++ b/nixos/modules/services/logging/logrotate.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, utils, ... }: - -with lib; - let cfg = config.services.logrotate; @@ -10,24 +7,24 @@ let else if builtins.elem n [ "frequency" ] then "${v}\n" else if builtins.elem n [ "firstaction" "lastaction" "prerotate" "postrotate" "preremove" ] then "${n}\n ${v}\n endscript\n" - else if isInt v then "${n} ${toString v}\n" + else if lib.isInt v then "${n} ${toString v}\n" else if v == true then "${n}\n" else if v == false then "no${n}\n" else "${n} ${v}\n"; - generateSection = indent: settings: concatStringsSep (fixedWidthString indent " " "") ( - filter (x: x != null) (mapAttrsToList generateLine settings) + generateSection = indent: settings: lib.concatStringsSep (lib.fixedWidthString indent " " "") ( + lib.filter (x: x != null) (lib.mapAttrsToList generateLine settings) ); # generateSection includes a final newline hence weird closing brace mkConf = settings: if settings.global or false then generateSection 0 settings else '' - ${concatMapStringsSep "\n" (files: ''"${files}"'') (toList settings.files)} { + ${lib.concatMapStringsSep "\n" (files: ''"${files}"'') (lib.toList settings.files)} { ${generateSection 2 settings}} ''; - settings = sortProperties (attrValues (filterAttrs (_: settings: settings.enable) ( - foldAttrs recursiveUpdate { } [ + settings = lib.sortProperties (lib.attrValues (lib.filterAttrs (_: settings: settings.enable) ( + lib.foldAttrs lib.recursiveUpdate { } [ { header = { enable = true; @@ -43,10 +40,10 @@ let ))); configFile = pkgs.writeTextFile { name = "logrotate.conf"; - text = concatStringsSep "\n" ( + text = lib.concatStringsSep "\n" ( map mkConf settings ); - checkPhase = optionalString cfg.checkConfig '' + checkPhase = lib.optionalString cfg.checkConfig '' # logrotate --debug also checks that users specified in config # file exist, but we only have sandboxed users here so brown these # out. according to man page that means su, create and createolddir. @@ -83,24 +80,26 @@ let }; mailOption = - optionalString (foldr (n: a: a || (n.mail or false) != false) false (attrValues cfg.settings)) + lib.optionalString (lib.foldr (n: a: a || (n.mail or false) != false) false (lib.attrValues cfg.settings)) "--mail=${pkgs.mailutils}/bin/mail"; in { imports = [ - (mkRemovedOptionModule [ "services" "logrotate" "config" ] "Modify services.logrotate.settings.header instead") - (mkRemovedOptionModule [ "services" "logrotate" "extraConfig" ] "Modify services.logrotate.settings.header instead") - (mkRemovedOptionModule [ "services" "logrotate" "paths" ] "Add attributes to services.logrotate.settings instead") + (lib.mkRemovedOptionModule [ "services" "logrotate" "config" ] "Modify services.logrotate.settings.header instead") + (lib.mkRemovedOptionModule [ "services" "logrotate" "extraConfig" ] "Modify services.logrotate.settings.header instead") + (lib.mkRemovedOptionModule [ "services" "logrotate" "paths" ] "Add attributes to services.logrotate.settings instead") ]; options = { services.logrotate = { - enable = mkEnableOption "the logrotate systemd service" // { - default = foldr (n: a: a || n.enable) false (attrValues cfg.settings); - defaultText = literalExpression "cfg.settings != {}"; + enable = lib.mkEnableOption "the logrotate systemd service" // { + default = lib.foldr (n: a: a || n.enable) false (lib.attrValues cfg.settings); + defaultText = lib.literalExpression "cfg.settings != {}"; }; - settings = mkOption { + allowNetworking = lib.mkEnableOption "network access for logrotate"; + + settings = lib.mkOption { default = { }; description = '' logrotate freeform settings: each attribute here will define its own section, @@ -111,7 +110,7 @@ in as logrotate config directives, refer to for details. ''; - example = literalExpression '' + example = lib.literalExpression '' { # global options header = { @@ -138,24 +137,24 @@ in }; }; ''; - type = types.attrsOf (types.submodule ({ name, ... }: { - freeformType = with types; attrsOf (nullOr (oneOf [ int bool str ])); + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { + freeformType = with lib.types; attrsOf (nullOr (oneOf [ int bool str ])); options = { - enable = mkEnableOption "setting individual kill switch" // { + enable = lib.mkEnableOption "setting individual kill switch" // { default = true; }; - global = mkOption { - type = types.bool; + global = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether this setting is a global option or not: set to have these settings apply to all files settings with a higher priority. ''; }; - files = mkOption { - type = with types; either str (listOf str); + files = lib.mkOption { + type = with lib.types; either str (listOf str); default = name; defaultText = '' The attrset name if not specified @@ -168,8 +167,8 @@ in ''; }; - frequency = mkOption { - type = types.nullOr types.str; + frequency = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' How often to rotate the logs. Defaults to previously set global setting, @@ -177,8 +176,8 @@ in ''; }; - priority = mkOption { - type = types.int; + priority = lib.mkOption { + type = lib.types.int; default = 1000; description = '' Order of this logrotate block in relation to the others. The semantics are @@ -190,8 +189,8 @@ in })); }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = configFile; defaultText = '' A configuration file automatically generated by NixOS. @@ -200,7 +199,7 @@ in Override the configuration file used by logrotate. By default, NixOS generates one automatically from [](#opt-services.logrotate.settings). ''; - example = literalExpression '' + example = lib.literalExpression '' pkgs.writeText "logrotate.conf" ''' missingok "/var/log/*.log" { @@ -211,8 +210,8 @@ in ''; }; - checkConfig = mkOption { - type = types.bool; + checkConfig = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether the config should be checked at build time. @@ -240,15 +239,61 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.logrotate = { description = "Logrotate Service"; + documentation = [ + "man:logrotate(8)" + "man:logrotate(5)" + ]; startAt = "hourly"; serviceConfig = { - Restart = "no"; - User = "root"; - ExecStart = "${pkgs.logrotate}/sbin/logrotate ${utils.escapeSystemdExecArgs cfg.extraArgs} ${mailOption} ${cfg.configFile}"; + Type = "oneshot"; + ExecStart = "${lib.getExe pkgs.logrotate} ${utils.escapeSystemdExecArgs cfg.extraArgs} ${mailOption} ${cfg.configFile}"; + + # performance + Nice = 19; + IOSchedulingClass = "best-effort"; + IOSchedulingPriority = 7; + + # hardening + CapabilityBoundingSet = [ + "CAP_CHOWN" + "CAP_DAC_OVERRIDE" + "CAP_KILL" + "CAP_SETUID" + "CAP_SETGID" + ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "full"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = false; # can create sgid directories + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged @resources" + "@chown @setuid" + ]; + UMask = "0027"; + } // lib.optionalAttrs (!cfg.allowNetworking) { + PrivateNetwork = true; # e.g. mail delivery + RestrictAddressFamilies = "none"; }; }; systemd.services.logrotate-checkconf = { diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix index 53e2e91d6212..31f0eef77c46 100644 --- a/nixos/modules/services/logging/logstash.nix +++ b/nixos/modules/services/logging/logstash.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.logstash; ops = lib.optionalString; @@ -38,8 +35,8 @@ in { imports = [ - (mkRenamedOptionModule [ "services" "logstash" "address" ] [ "services" "logstash" "listenAddress" ]) - (mkRemovedOptionModule [ "services" "logstash" "enableWeb" ] "The web interface was removed from logstash") + (lib.mkRenamedOptionModule [ "services" "logstash" "address" ] [ "services" "logstash" "listenAddress" ]) + (lib.mkRemovedOptionModule [ "services" "logstash" "enableWeb" ] "The web interface was removed from logstash") ]; ###### interface @@ -48,23 +45,23 @@ in services.logstash = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable logstash."; }; - package = mkPackageOption pkgs "logstash" { }; + package = lib.mkPackageOption pkgs "logstash" { }; - plugins = mkOption { - type = types.listOf types.path; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.path; default = [ ]; - example = literalExpression "[ pkgs.logstash-contrib ]"; + example = lib.literalExpression "[ pkgs.logstash-contrib ]"; description = "The paths to find other logstash plugins in."; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/logstash"; description = '' A path to directory writable by logstash that it uses to store data. @@ -72,35 +69,35 @@ in ''; }; - logLevel = mkOption { - type = types.enum [ "debug" "info" "warn" "error" "fatal" ]; + logLevel = lib.mkOption { + type = lib.types.enum [ "debug" "info" "warn" "error" "fatal" ]; default = "warn"; description = "Logging verbosity level."; }; - filterWorkers = mkOption { - type = types.int; + filterWorkers = lib.mkOption { + type = lib.types.int; default = 1; description = "The quantity of filter workers to run."; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Address on which to start webserver."; }; - port = mkOption { - type = types.str; + port = lib.mkOption { + type = lib.types.str; default = "9292"; description = "Port on which to start webserver."; }; - inputConfig = mkOption { - type = types.lines; + inputConfig = lib.mkOption { + type = lib.types.lines; default = "generator { }"; description = "Logstash input configuration."; - example = literalExpression '' + example = lib.literalExpression '' ''' # Read from journal pipe { @@ -111,8 +108,8 @@ in ''; }; - filterConfig = mkOption { - type = types.lines; + filterConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "logstash filter configuration."; example = '' @@ -129,8 +126,8 @@ in ''; }; - outputConfig = mkOption { - type = types.lines; + outputConfig = lib.mkOption { + type = lib.types.lines; default = "stdout { codec => rubydebug }"; description = "Logstash output configuration."; example = '' @@ -139,8 +136,8 @@ in ''; }; - extraSettings = mkOption { - type = types.lines; + extraSettings = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra Logstash settings in YAML format."; example = '' @@ -151,8 +148,8 @@ in ''; }; - extraJvmOptions = mkOption { - type = types.lines; + extraJvmOptions = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra JVM options, one per line (jvm.options format)."; example = '' @@ -167,17 +164,17 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.logstash = { description = "Logstash Daemon"; wantedBy = [ "multi-user.target" ]; path = [ pkgs.bash ]; serviceConfig = { ExecStartPre = ''${pkgs.coreutils}/bin/mkdir -p "${cfg.dataDir}" ; ${pkgs.coreutils}/bin/chmod 700 "${cfg.dataDir}"''; - ExecStart = concatStringsSep " " (filter (s: stringLength s != 0) [ + ExecStart = lib.concatStringsSep " " (lib.filter (s: lib.stringLength s != 0) [ "${cfg.package}/bin/logstash" "-w ${toString cfg.filterWorkers}" - (concatMapStringsSep " " (x: "--path.plugins ${x}") cfg.plugins) + (lib.concatMapStringsSep " " (x: "--path.plugins ${x}") cfg.plugins) "${verbosityFlag}" "-f ${logstashConf}" "--path.settings ${logstashSettingsDir}" diff --git a/nixos/modules/services/logging/promtail.nix b/nixos/modules/services/logging/promtail.nix index 9eccd34cef23..644a93214516 100644 --- a/nixos/modules/services/logging/promtail.nix +++ b/nixos/modules/services/logging/promtail.nix @@ -80,7 +80,7 @@ in { PrivateUsers = true; SupplementaryGroups = lib.optional (allowSystemdJournal) "systemd-journal"; - } // (optionalAttrs (!pkgs.stdenv.isAarch64) { # FIXME: figure out why this breaks on aarch64 + } // (optionalAttrs (!pkgs.stdenv.hostPlatform.isAarch64) { # FIXME: figure out why this breaks on aarch64 SystemCallFilter = "@system-service"; }); }; diff --git a/nixos/modules/services/logging/rsyslogd.nix b/nixos/modules/services/logging/rsyslogd.nix index 25b6eec5056c..88a8ff840682 100644 --- a/nixos/modules/services/logging/rsyslogd.nix +++ b/nixos/modules/services/logging/rsyslogd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.rsyslogd; @@ -36,8 +33,8 @@ in services.rsyslogd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable syslogd. Note that systemd also logs @@ -45,8 +42,8 @@ in ''; }; - defaultConfig = mkOption { - type = types.lines; + defaultConfig = lib.mkOption { + type = lib.types.lines; default = defaultConf; description = '' The default {file}`syslog.conf` file configures a @@ -55,8 +52,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = "news.* -/var/log/news"; description = '' @@ -65,8 +62,8 @@ in ''; }; - extraParams = mkOption { - type = types.listOf types.str; + extraParams = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "-m 0" ]; description = '' @@ -81,7 +78,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.rsyslog ]; diff --git a/nixos/modules/services/logging/syslog-ng.nix b/nixos/modules/services/logging/syslog-ng.nix index 14e18d3f0eef..d9d4b0cdb94a 100644 --- a/nixos/modules/services/logging/syslog-ng.nix +++ b/nixos/modules/services/logging/syslog-ng.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.syslog-ng; @@ -17,7 +14,7 @@ let syslogngOptions = [ "--foreground" - "--module-path=${concatStringsSep ":" (["${cfg.package}/lib/syslog-ng"] ++ cfg.extraModulePaths)}" + "--module-path=${lib.concatStringsSep ":" (["${cfg.package}/lib/syslog-ng"] ++ cfg.extraModulePaths)}" "--cfgfile=${syslogngConfig}" "--control=${ctrlSocket}" "--persist-file=${persistFile}" @@ -26,23 +23,23 @@ let in { imports = [ - (mkRemovedOptionModule [ "services" "syslog-ng" "serviceName" ] "") - (mkRemovedOptionModule [ "services" "syslog-ng" "listenToJournal" ] "") + (lib.mkRemovedOptionModule [ "services" "syslog-ng" "serviceName" ] "") + (lib.mkRemovedOptionModule [ "services" "syslog-ng" "listenToJournal" ] "") ]; options = { services.syslog-ng = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the syslog-ng daemon. ''; }; - package = mkPackageOption pkgs "syslogng" { }; - extraModulePaths = mkOption { - type = types.listOf types.str; + package = lib.mkPackageOption pkgs "syslogng" { }; + extraModulePaths = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' A list of paths that should be included in syslog-ng's @@ -50,15 +47,15 @@ in { end in `/lib/syslog-ng` ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Configuration added to the end of `syslog-ng.conf`. ''; }; - configHeader = mkOption { - type = types.lines; + configHeader = lib.mkOption { + type = lib.types.lines; default = '' @version: 4.4 @include "scl.conf" @@ -71,7 +68,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.syslog-ng = { description = "syslog-ng daemon"; preStart = "mkdir -p /{var,run}/syslog-ng"; @@ -82,7 +79,7 @@ in { PIDFile = pidFile; StandardOutput = "null"; Restart = "on-failure"; - ExecStart = "${cfg.package}/sbin/syslog-ng ${concatStringsSep " " syslogngOptions}"; + ExecStart = "${cfg.package}/sbin/syslog-ng ${lib.concatStringsSep " " syslogngOptions}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; }; }; diff --git a/nixos/modules/services/logging/syslogd.nix b/nixos/modules/services/logging/syslogd.nix index 8674fad69658..ad2d09b5a8de 100644 --- a/nixos/modules/services/logging/syslogd.nix +++ b/nixos/modules/services/logging/syslogd.nix @@ -1,13 +1,10 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.syslogd; syslogConf = pkgs.writeText "syslog.conf" '' - ${optionalString (cfg.tty != "") "kern.warning;*.err;authpriv.none /dev/${cfg.tty}"} + ${lib.optionalString (cfg.tty != "") "kern.warning;*.err;authpriv.none /dev/${cfg.tty}"} ${cfg.defaultConfig} ${cfg.extraConfig} ''; @@ -36,8 +33,8 @@ in services.syslogd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable syslogd. Note that systemd also logs @@ -45,8 +42,8 @@ in ''; }; - tty = mkOption { - type = types.str; + tty = lib.mkOption { + type = lib.types.str; default = "tty10"; description = '' The tty device on which syslogd will print important log @@ -54,8 +51,8 @@ in ''; }; - defaultConfig = mkOption { - type = types.lines; + defaultConfig = lib.mkOption { + type = lib.types.lines; default = defaultConf; description = '' The default {file}`syslog.conf` file configures a @@ -64,16 +61,16 @@ in ''; }; - enableNetworkInput = mkOption { - type = types.bool; + enableNetworkInput = lib.mkOption { + type = lib.types.bool; default = false; description = '' Accept logging through UDP. Option -r of syslogd(8). ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = "news.* -/var/log/news"; description = '' @@ -82,8 +79,8 @@ in ''; }; - extraParams = mkOption { - type = types.listOf types.str; + extraParams = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "-m 0" ]; description = '' @@ -98,7 +95,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = !config.services.rsyslogd.enable; @@ -108,7 +105,7 @@ in environment.systemPackages = [ pkgs.sysklogd ]; - services.syslogd.extraParams = optional cfg.enableNetworkInput "-r"; + services.syslogd.extraParams = lib.optional cfg.enableNetworkInput "-r"; # FIXME: restarting syslog seems to break journal logging. systemd.services.syslog = diff --git a/nixos/modules/services/logging/ulogd.nix b/nixos/modules/services/logging/ulogd.nix index 5bd51ef88fe5..9d1d8e61231d 100644 --- a/nixos/modules/services/logging/ulogd.nix +++ b/nixos/modules/services/logging/ulogd.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.ulogd; settingsFormat = pkgs.formats.ini { listsAsDuplicateKeys = true; }; @@ -8,9 +6,9 @@ let in { options = { services.ulogd = { - enable = mkEnableOption "ulogd, a userspace logging daemon for netfilter/iptables related logging"; + enable = lib.mkEnableOption "ulogd, a userspace logging daemon for netfilter/iptables related logging"; - settings = mkOption { + settings = lib.mkOption { example = { global.stack = [ "log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU" @@ -35,8 +33,8 @@ in { "Configuration for ulogd. See {file}`/share/doc/ulogd/` in `pkgs.ulogd.doc`."; }; - logLevel = mkOption { - type = types.enum [ 1 3 5 7 8 ]; + logLevel = lib.mkOption { + type = lib.types.enum [ 1 3 5 7 8 ]; default = 5; description = "Log level (1 = debug, 3 = info, 5 = notice, 7 = error, 8 = fatal)"; @@ -44,7 +42,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.ulogd = { description = "Ulogd Daemon"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/logging/vector.nix b/nixos/modules/services/logging/vector.nix index 129a38b1d20f..c68d546bb96c 100644 --- a/nixos/modules/services/logging/vector.nix +++ b/nixos/modules/services/logging/vector.nix @@ -1,24 +1,22 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.vector; in { options.services.vector = { - enable = mkEnableOption "Vector, a high-performance observability data pipeline"; + enable = lib.mkEnableOption "Vector, a high-performance observability data pipeline"; - package = mkPackageOption pkgs "vector" { }; + package = lib.mkPackageOption pkgs "vector" { }; - journaldAccess = mkOption { - type = types.bool; + journaldAccess = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable Vector to access journald. ''; }; - settings = mkOption { + settings = lib.mkOption { type = (pkgs.formats.json { }).type; default = { }; description = '' @@ -27,7 +25,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # for cli usage environment.systemPackages = [ pkgs.vector ]; @@ -49,14 +47,14 @@ in ''; in { - ExecStart = "${getExe cfg.package} --config ${validateConfig conf}"; + ExecStart = "${lib.getExe cfg.package} --config ${validateConfig conf}"; DynamicUser = true; Restart = "always"; StateDirectory = "vector"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; AmbientCapabilities = "CAP_NET_BIND_SERVICE"; # This group is required for accessing journald. - SupplementaryGroups = mkIf cfg.journaldAccess "systemd-journal"; + SupplementaryGroups = lib.mkIf cfg.journaldAccess "systemd-journal"; }; unitConfig = { StartLimitIntervalSec = 10; diff --git a/nixos/modules/services/mail/automx2.nix b/nixos/modules/services/mail/automx2.nix new file mode 100644 index 000000000000..2cfb5f491341 --- /dev/null +++ b/nixos/modules/services/mail/automx2.nix @@ -0,0 +1,108 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.automx2; + format = pkgs.formats.json { }; +in +{ + options = { + services.automx2 = { + enable = lib.mkEnableOption "automx2"; + + package = lib.mkPackageOption pkgs [ + "python3Packages" + "automx2" + ] { }; + + domain = lib.mkOption { + type = lib.types.str; + example = "example.com"; + description = '' + E-Mail-Domain for which mail client autoconfig/autoconfigure should be set up. + The `autoconfig` and `autodiscover` subdomains are automatically prepended and set up with ACME. + The names of those domains are hardcoded in the mail clients and are not configurable. + ''; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 4243; + description = "Port used by automx2."; + }; + + settings = lib.mkOption { + inherit (format) type; + description = '' + Bootstrap json to populate database. + See [docs](https://rseichter.github.io/automx2/#_sqlite) for details. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + services.nginx = { + enable = true; + virtualHosts = { + "autoconfig.${cfg.domain}" = { + enableACME = true; + forceSSL = true; + serverAliases = [ "autodiscover.${cfg.domain}" ]; + locations = { + "/".proxyPass = "http://127.0.0.1:${toString cfg.port}/"; + "/initdb".extraConfig = '' + # Limit access to clients connecting from localhost + allow 127.0.0.1; + deny all; + ''; + }; + }; + }; + }; + + systemd.services.automx2 = { + after = [ "network.target" ]; + postStart = '' + sleep 3 + ${lib.getExe pkgs.curl} -X POST --json @${format.generate "automx2.json" cfg.settings} http://127.0.0.1:${toString cfg.port}/initdb/ + ''; + serviceConfig = { + Environment = [ + "AUTOMX2_CONF=${pkgs.writeText "automx2-conf" '' + [automx2] + loglevel = WARNING + db_uri = sqlite:///:memory: + proxy_count = 1 + ''}" + "FLASK_APP=automx2.server:app" + "FLASK_CONFIG=production" + ]; + ExecStart = "${ + pkgs.python3.buildEnv.override { extraLibs = [ cfg.package ]; } + }/bin/flask run --host=127.0.0.1 --port=${toString cfg.port}"; + Restart = "always"; + StateDirectory = "automx2"; + User = "automx2"; + WorkingDirectory = "/var/lib/automx2"; + }; + unitConfig = { + Description = "MUA configuration service"; + Documentation = "https://rseichter.github.io/automx2/"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + users = { + groups.automx2 = { }; + users.automx2 = { + group = "automx2"; + isSystemUser = true; + }; + }; + }; +} diff --git a/nixos/modules/services/mail/clamsmtp.nix b/nixos/modules/services/mail/clamsmtp.nix index 5bcf8ecdde1a..d40ed7bf6e2d 100644 --- a/nixos/modules/services/mail/clamsmtp.nix +++ b/nixos/modules/services/mail/clamsmtp.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.clamsmtp; clamdSocket = "/run/clamav/clamd.ctl"; # See services/security/clamav.nix @@ -9,17 +7,17 @@ in ##### interface options = { services.clamsmtp = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable clamsmtp."; }; - instances = mkOption { + instances = lib.mkOption { description = "Instances of clamsmtp to run."; - type = types.listOf (types.submodule { options = { - action = mkOption { - type = types.enum [ "bounce" "drop" "pass" ]; + type = lib.types.listOf (lib.types.submodule { options = { + action = lib.mkOption { + type = lib.types.enum [ "bounce" "drop" "pass" ]; default = "drop"; description = '' Action to take when a virus is detected. @@ -29,8 +27,8 @@ in ''; }; - header = mkOption { - type = types.str; + header = lib.mkOption { + type = lib.types.str; default = ""; example = "X-Virus-Scanned: ClamAV using ClamSMTP"; description = '' @@ -39,8 +37,8 @@ in ''; }; - keepAlives = mkOption { - type = types.int; + keepAlives = lib.mkOption { + type = lib.types.int; default = 0; description = '' Number of seconds to wait between each NOOP sent to the sending @@ -51,8 +49,8 @@ in ''; }; - listen = mkOption { - type = types.str; + listen = lib.mkOption { + type = lib.types.str; example = "127.0.0.1:10025"; description = '' Address to wait for incoming SMTP connections on. See @@ -60,8 +58,8 @@ in ''; }; - quarantine = mkOption { - type = types.bool; + quarantine = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to quarantine files that contain viruses by leaving them @@ -69,22 +67,22 @@ in ''; }; - maxConnections = mkOption { - type = types.int; + maxConnections = lib.mkOption { + type = lib.types.int; default = 64; description = "Maximum number of connections to accept at once."; }; - outAddress = mkOption { - type = types.str; + outAddress = lib.mkOption { + type = lib.types.str; description = '' Address of the SMTP server to send email to once it has been scanned. ''; }; - tempDirectory = mkOption { - type = types.str; + tempDirectory = lib.mkOption { + type = lib.types.str; default = "/tmp"; description = '' Temporary directory that needs to be accessible to both clamd @@ -92,20 +90,20 @@ in ''; }; - timeout = mkOption { - type = types.int; + timeout = lib.mkOption { + type = lib.types.int; default = 180; description = "Time-out for network connections."; }; - transparentProxy = mkOption { - type = types.bool; + transparentProxy = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable clamsmtp's transparent proxy support."; }; - virusAction = mkOption { - type = with types; nullOr path; + virusAction = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' Command to run when a virus is found. Please see VIRUS ACTION in @@ -113,8 +111,8 @@ in ''; }; - xClient = mkOption { - type = types.bool; + xClient = lib.mkOption { + type = lib.types.bool; default = false; description = '' Send the XCLIENT command to the receiving server, for forwarding @@ -143,19 +141,19 @@ in TimeOut: ${toString conf.timeout} TransparentProxy: ${if conf.transparentProxy then "on" else "off"} User: clamav - ${optionalString (conf.virusAction != null) "VirusAction: ${conf.virusAction}"} + ${lib.optionalString (conf.virusAction != null) "VirusAction: ${conf.virusAction}"} XClient: ${if conf.xClient then "on" else "off"} ''; in - mkIf cfg.enable { + lib.mkIf cfg.enable { assertions = [ { assertion = config.services.clamav.daemon.enable; message = "clamsmtp requires clamav to be enabled"; } ]; - systemd.services = listToAttrs (imap1 (i: conf: - nameValuePair "clamsmtp-${toString i}" { + systemd.services = lib.listToAttrs (lib.imap1 (i: conf: + lib.nameValuePair "clamsmtp-${toString i}" { description = "ClamSMTP instance ${toString i}"; wantedBy = [ "multi-user.target" ]; script = "exec ${pkgs.clamsmtp}/bin/clamsmtpd -f ${configfile conf}"; diff --git a/nixos/modules/services/mail/davmail.nix b/nixos/modules/services/mail/davmail.nix index 46ddaedd4bf6..00e1ecb3852b 100644 --- a/nixos/modules/services/mail/davmail.nix +++ b/nixos/modules/services/mail/davmail.nix @@ -1,39 +1,36 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.davmail; - configType = with types; + configType = with lib.types; oneOf [ (attrsOf configType) str int bool ] // { description = "davmail config type (str, int, bool or attribute set thereof)"; }; - toStr = val: if isBool val then boolToString val else toString val; + toStr = val: if lib.isBool val then lib.boolToString val else toString val; - linesForAttrs = attrs: concatMap (name: let value = attrs.${name}; in - if isAttrs value + linesForAttrs = attrs: lib.concatMap (name: let value = attrs.${name}; in + if lib.isAttrs value then map (line: name + "." + line) (linesForAttrs value) else [ "${name}=${toStr value}" ] - ) (attrNames attrs); + ) (lib.attrNames attrs); - configFile = pkgs.writeText "davmail.properties" (concatStringsSep "\n" (linesForAttrs cfg.config)); + configFile = pkgs.writeText "davmail.properties" (lib.concatStringsSep "\n" (linesForAttrs cfg.config)); in { options.services.davmail = { - enable = mkEnableOption "davmail, an MS Exchange gateway"; + enable = lib.mkEnableOption "davmail, an MS Exchange gateway"; - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; description = "Outlook Web Access URL to access the exchange server, i.e. the base webmail URL."; example = "https://outlook.office365.com/EWS/Exchange.asmx"; }; - config = mkOption { + config = lib.mkOption { type = configType; default = {}; description = '' @@ -42,7 +39,7 @@ in and for details on supported values. ''; - example = literalExpression '' + example = lib.literalExpression '' { davmail.allowRemote = true; davmail.imapPort = 55555; @@ -56,10 +53,10 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.davmail.config = { - davmail = mapAttrs (name: mkDefault) { + davmail = lib.mapAttrs (name: lib.mkDefault) { server = true; disableUpdateCheck = true; logFilePath = "/var/log/davmail/davmail.log"; @@ -73,10 +70,10 @@ in smtpPort = 1025; }; log4j = { - logger.davmail = mkDefault "WARN"; - logger.httpclient.wire = mkDefault "WARN"; - logger.org.apache.commons.httpclient = mkDefault "WARN"; - rootLogger = mkDefault "WARN"; + logger.davmail = lib.mkDefault "WARN"; + logger.httpclient.wire = lib.mkDefault "WARN"; + logger.org.apache.commons.httpclient = lib.mkDefault "WARN"; + rootLogger = lib.mkDefault "WARN"; }; }; diff --git a/nixos/modules/services/mail/dkimproxy-out.nix b/nixos/modules/services/mail/dkimproxy-out.nix index 48ccf2dda601..1d6a143dc836 100644 --- a/nixos/modules/services/mail/dkimproxy-out.nix +++ b/nixos/modules/services/mail/dkimproxy-out.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.dkimproxy-out; keydir = "/var/lib/dkimproxy-out"; @@ -11,8 +9,8 @@ in ##### interface options = { services.dkimproxy-out = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable dkimproxy_out. @@ -22,26 +20,26 @@ in ''; }; - listen = mkOption { - type = types.str; + listen = lib.mkOption { + type = lib.types.str; example = "127.0.0.1:10027"; description = "Address:port DKIMproxy should listen on."; }; - relay = mkOption { - type = types.str; + relay = lib.mkOption { + type = lib.types.str; example = "127.0.0.1:10028"; description = "Address:port DKIMproxy should forward mail to."; }; - domains = mkOption { - type = with types; listOf str; + domains = lib.mkOption { + type = with lib.types; listOf str; example = [ "example.org" "example.com" ]; description = "List of domains DKIMproxy can sign for."; }; - selector = mkOption { - type = types.str; + selector = lib.mkOption { + type = lib.types.str; example = "selector1"; description = '' The selector to use for DKIM key identification. @@ -53,8 +51,8 @@ in ''; }; - keySize = mkOption { - type = types.int; + keySize = lib.mkOption { + type = lib.types.int; default = 2048; description = '' Size of the RSA key to use to sign outgoing emails. Note that the @@ -75,7 +73,7 @@ in listen ${cfg.listen} relay ${cfg.relay} - domain ${concatStringsSep "," cfg.domains} + domain ${lib.concatStringsSep "," cfg.domains} selector ${cfg.selector} signature dkim(c=relaxed/relaxed) @@ -83,7 +81,7 @@ in keyfile ${privkey} ''; in - mkIf cfg.enable { + lib.mkIf cfg.enable { users.groups.dkimproxy-out = {}; users.users.dkimproxy-out = { description = "DKIMproxy_out daemon"; diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix index b81fe2652402..76bcc0af7e8b 100644 --- a/nixos/modules/services/mail/dspam.nix +++ b/nixos/modules/services/mail/dspam.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dspam; @@ -19,7 +16,7 @@ let SystemLog on UserLog on - ${optionalString (cfg.domainSocket != null) '' + ${lib.optionalString (cfg.domainSocket != null) '' ServerDomainSocketPath "${cfg.domainSocket}" ClientHost "${cfg.domainSocket}" ''} @@ -35,44 +32,44 @@ in { services.dspam = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the dspam spam filter."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "dspam"; description = "User for the dspam daemon."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "dspam"; description = "Group for the dspam daemon."; }; - storageDriver = mkOption { - type = types.str; + storageDriver = lib.mkOption { + type = lib.types.str; default = "hash"; description = "Storage driver backend to use for dspam."; }; - domainSocket = mkOption { - type = types.nullOr types.path; + domainSocket = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = defaultSock; description = "Path to local domain socket which is used for communication with the daemon. Set to null to disable UNIX socket."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Additional dspam configuration."; }; - maintenanceInterval = mkOption { - type = types.nullOr types.str; + maintenanceInterval = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "If set, maintenance script will be run at specified (in systemd.timer format) interval"; }; @@ -84,16 +81,16 @@ in { ###### implementation - config = mkIf cfg.enable (mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { - users.users = optionalAttrs (cfg.user == "dspam") { + users.users = lib.optionalAttrs (cfg.user == "dspam") { dspam = { group = cfg.group; uid = config.ids.uids.dspam; }; }; - users.groups = optionalAttrs (cfg.group == "dspam") { + users.groups = lib.optionalAttrs (cfg.group == "dspam") { dspam.gid = config.ids.gids.dspam; }; @@ -111,8 +108,8 @@ in { ExecStart = "${dspam}/bin/dspam --daemon --nofork"; User = cfg.user; Group = cfg.group; - RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam"; - RuntimeDirectoryMode = optional (cfg.domainSocket == defaultSock) "0750"; + RuntimeDirectory = lib.optional (cfg.domainSocket == defaultSock) "dspam"; + RuntimeDirectoryMode = lib.optional (cfg.domainSocket == defaultSock) "0750"; StateDirectory = "dspam"; StateDirectoryMode = "0750"; LogsDirectory = "dspam"; @@ -124,7 +121,7 @@ in { }; } - (mkIf (cfg.maintenanceInterval != null) { + (lib.mkIf (cfg.maintenanceInterval != null) { systemd.timers.dspam-maintenance = { description = "Timer for dspam maintenance script"; wantedBy = [ "timers.target" ]; diff --git a/nixos/modules/services/mail/goeland.nix b/nixos/modules/services/mail/goeland.nix index 158b9ef982cc..42f64b3632b5 100644 --- a/nixos/modules/services/mail/goeland.nix +++ b/nixos/modules/services/mail/goeland.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.goeland; tomlFormat = pkgs.formats.toml { }; in { options.services.goeland = { - enable = mkEnableOption "goeland, an alternative to rss2email"; + enable = lib.mkEnableOption "goeland, an alternative to rss2email"; - settings = mkOption { + settings = lib.mkOption { description = '' Configuration of goeland. See the [example config file](https://github.com/slurdge/goeland/blob/master/cmd/asset/config.default.toml) for the available options. @@ -18,14 +15,14 @@ in default = { }; type = tomlFormat.type; }; - schedule = mkOption { - type = types.str; + schedule = lib.mkOption { + type = lib.types.str; default = "12h"; example = "Mon, 00:00:00"; description = "How often to run goeland, in systemd time format."; }; - stateDir = mkOption { - type = types.path; + stateDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/goeland"; description = '' The data directory for goeland where the database will reside if using the unseen filter. @@ -36,17 +33,17 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.goeland.settings.database = "${cfg.stateDir}/goeland.db"; systemd.services.goeland = { - serviceConfig = let confFile = tomlFormat.generate "config.toml" cfg.settings; in mkMerge [ + serviceConfig = let confFile = tomlFormat.generate "config.toml" cfg.settings; in lib.mkMerge [ { ExecStart = "${pkgs.goeland}/bin/goeland run -c ${confFile}"; User = "goeland"; Group = "goeland"; } - (mkIf (cfg.stateDir == "/var/lib/goeland") { + (lib.mkIf (cfg.stateDir == "/var/lib/goeland") { StateDirectory = "goeland"; StateDirectoryMode = "0750"; }) @@ -61,7 +58,7 @@ in }; users.groups.goeland = { }; - warnings = optionals (hasAttr "password" cfg.settings.email) [ + warnings = lib.optionals (lib.hasAttr "password" cfg.settings.email) [ '' It is not recommended to set the "services.goeland.settings.email.password" option as it will be in cleartext in the Nix store. @@ -70,5 +67,5 @@ in ]; }; - meta.maintainers = with maintainers; [ sweenu ]; + meta.maintainers = with lib.maintainers; [ sweenu ]; } diff --git a/nixos/modules/services/mail/listmonk.nix b/nixos/modules/services/mail/listmonk.nix index 482bc42696f9..82c94ad4bb8f 100644 --- a/nixos/modules/services/mail/listmonk.nix +++ b/nixos/modules/services/mail/listmonk.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.listmonk; tomlFormat = pkgs.formats.toml { }; @@ -11,7 +9,7 @@ let lib.replaceStrings [ "'" ] [ "''" ] (builtins.toJSON value) }' WHERE key = '${key}';"; updateDatabaseConfigSQL = pkgs.writeText "update-database-config.sql" - (concatStringsSep "\n" (mapAttrsToList setDatabaseOption + (lib.concatStringsSep "\n" (lib.mapAttrsToList setDatabaseOption (if (cfg.database.settings != null) then cfg.database.settings else @@ -27,53 +25,53 @@ let "${pkgs.postgresql}/bin/psql -d listmonk -f ${updateDatabaseConfigSQL}"} ''; - databaseSettingsOpts = with types; { + databaseSettingsOpts = with lib.types; { freeformType = oneOf [ (listOf str) (listOf (attrsOf anything)) str int bool ]; options = { - "app.notify_emails" = mkOption { + "app.notify_emails" = lib.mkOption { type = listOf str; default = [ ]; description = "Administrator emails for system notifications"; }; - "privacy.exportable" = mkOption { + "privacy.exportable" = lib.mkOption { type = listOf str; default = [ "profile" "subscriptions" "campaign_views" "link_clicks" ]; description = "List of fields which can be exported through an automatic export request"; }; - "privacy.domain_blocklist" = mkOption { + "privacy.domain_blocklist" = lib.mkOption { type = listOf str; default = [ ]; description = "E-mail addresses with these domains are disallowed from subscribing."; }; - smtp = mkOption { + smtp = lib.mkOption { type = listOf (submodule { - freeformType = with types; attrsOf anything; + freeformType = with lib.types; attrsOf anything; options = { - enabled = mkEnableOption "this SMTP server for listmonk"; - host = mkOption { - type = types.str; + enabled = lib.mkEnableOption "this SMTP server for listmonk"; + host = lib.mkOption { + type = lib.types.str; description = "Hostname for the SMTP server"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; description = "Port for the SMTP server"; }; - max_conns = mkOption { - type = types.int; + max_conns = lib.mkOption { + type = lib.types.int; description = "Maximum number of simultaneous connections, defaults to 1"; default = 1; }; - tls_type = mkOption { - type = types.enum [ "none" "STARTTLS" "TLS" ]; + tls_type = lib.mkOption { + type = lib.types.enum [ "none" "STARTTLS" "TLS" ]; description = "Type of TLS authentication with the SMTP server"; }; }; @@ -83,14 +81,14 @@ let }; # TODO: refine this type based on the smtp one. - "bounce.mailboxes" = mkOption { + "bounce.mailboxes" = lib.mkOption { type = listOf - (submodule { freeformType = with types; listOf (attrsOf anything); }); + (submodule { freeformType = with lib.types; listOf (attrsOf anything); }); default = [ ]; description = "List of bounce mailboxes"; }; - messengers = mkOption { + messengers = lib.mkOption { type = listOf str; default = [ ]; description = @@ -102,23 +100,23 @@ in { ###### interface options = { services.listmonk = { - enable = mkEnableOption "Listmonk, this module assumes a reverse proxy to be set"; + enable = lib.mkEnableOption "Listmonk, this module assumes a reverse proxy to be set"; database = { - createLocally = mkOption { - type = types.bool; + createLocally = lib.mkOption { + type = lib.types.bool; default = false; description = "Create the PostgreSQL database and database user locally."; }; - settings = mkOption { + settings = lib.mkOption { default = null; - type = with types; nullOr (submodule databaseSettingsOpts); + type = with lib.types; nullOr (submodule databaseSettingsOpts); description = "Dynamic settings in the PostgreSQL database, set by a SQL script, see for details."; }; - mutableSettings = mkOption { - type = types.bool; + mutableSettings = lib.mkOption { + type = lib.types.bool; default = true; description = '' Database settings will be reset to the value set in this module if this is not enabled. @@ -126,16 +124,16 @@ in { ''; }; }; - package = mkPackageOption pkgs "listmonk" {}; - settings = mkOption { - type = types.submodule { freeformType = tomlFormat.type; }; + package = lib.mkPackageOption pkgs "listmonk" {}; + settings = lib.mkOption { + type = lib.types.submodule { freeformType = tomlFormat.type; }; description = '' Static settings set in the config.toml, see for details. You can set secrets using the secretFile option with environment variables following . ''; }; - secretFile = mkOption { - type = types.nullOr types.str; + secretFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "A file containing secrets as environment variables. See for details on supported values."; @@ -144,24 +142,24 @@ in { }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Default parameters from https://github.com/knadh/listmonk/blob/master/config.toml.sample - services.listmonk.settings."app".address = mkDefault "localhost:9000"; - services.listmonk.settings."db" = mkMerge [ + services.listmonk.settings."app".address = lib.mkDefault "localhost:9000"; + services.listmonk.settings."db" = lib.mkMerge [ ({ - max_open = mkDefault 25; - max_idle = mkDefault 25; - max_lifetime = mkDefault "300s"; + max_open = lib.mkDefault 25; + max_idle = lib.mkDefault 25; + max_lifetime = lib.mkDefault "300s"; }) - (mkIf cfg.database.createLocally { - host = mkDefault "/run/postgresql"; - port = mkDefault 5432; - user = mkDefault "listmonk"; - database = mkDefault "listmonk"; + (lib.mkIf cfg.database.createLocally { + host = lib.mkDefault "/run/postgresql"; + port = lib.mkDefault 5432; + user = lib.mkDefault "listmonk"; + database = lib.mkDefault "listmonk"; }) ]; - services.postgresql = mkIf cfg.database.createLocally { + services.postgresql = lib.mkIf cfg.database.createLocally { enable = true; ensureUsers = [{ @@ -175,11 +173,11 @@ in { systemd.services.listmonk = { description = "Listmonk - newsletter and mailing list manager"; after = [ "network.target" ] - ++ optional cfg.database.createLocally "postgresql.service"; + ++ lib.optional cfg.database.createLocally "postgresql.service"; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "exec"; - EnvironmentFile = mkIf (cfg.secretFile != null) [ cfg.secretFile ]; + EnvironmentFile = lib.mkIf (cfg.secretFile != null) [ cfg.secretFile ]; ExecStartPre = [ # StateDirectory cannot be used when DynamicUser = true is set this way. # Indeed, it will try to create all the folders and realize one of them already exist. diff --git a/nixos/modules/services/mail/maddy.nix b/nixos/modules/services/mail/maddy.nix index 7c67d4e6135e..ab0e1f40f5b0 100644 --- a/nixos/modules/services/mail/maddy.nix +++ b/nixos/modules/services/mail/maddy.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let name = "maddy"; @@ -138,11 +135,11 @@ in { options = { services.maddy = { - enable = mkEnableOption "Maddy, a free an open source mail server"; + enable = lib.mkEnableOption "Maddy, a free an open source mail server"; - user = mkOption { + user = lib.mkOption { default = "maddy"; - type = with types; uniq str; + type = with lib.types; uniq str; description = '' User account under which maddy runs. @@ -154,9 +151,9 @@ in { ''; }; - group = mkOption { + group = lib.mkOption { default = "maddy"; - type = with types; uniq str; + type = with lib.types; uniq str; description = '' Group account under which maddy runs. @@ -168,26 +165,26 @@ in { ''; }; - hostname = mkOption { + hostname = lib.mkOption { default = "localhost"; - type = with types; uniq str; + type = with lib.types; uniq str; example = ''example.com''; description = '' Hostname to use. It should be FQDN. ''; }; - primaryDomain = mkOption { + primaryDomain = lib.mkOption { default = "localhost"; - type = with types; uniq str; + type = with lib.types; uniq str; example = ''mail.example.com''; description = '' Primary MX domain to use. It should be FQDN. ''; }; - localDomains = mkOption { - type = with types; listOf str; + localDomains = lib.mkOption { + type = with lib.types; listOf str; default = ["$(primary_domain)"]; example = [ "$(primary_domain)" @@ -199,8 +196,8 @@ in { ''; }; - config = mkOption { - type = with types; nullOr lines; + config = lib.mkOption { + type = with lib.types; nullOr lines; default = defaultConfig; description = '' Server configuration, see @@ -215,8 +212,8 @@ in { }; tls = { - loader = mkOption { - type = with types; nullOr (enum [ "off" "file" "acme" ]); + loader = lib.mkOption { + type = with lib.types; nullOr (enum [ "off" "file" "acme" ]); default = "off"; description = '' TLS certificates are obtained by modules called "certificate @@ -237,18 +234,18 @@ in { ''; }; - certificates = mkOption { - type = with types; listOf (submodule { + certificates = lib.mkOption { + type = with lib.types; listOf (submodule { options = { - keyPath = mkOption { - type = types.path; + keyPath = lib.mkOption { + type = lib.types.path; example = "/etc/ssl/mx1.example.org.key"; description = '' Path to the private key used for TLS. ''; }; - certPath = mkOption { - type = types.path; + certPath = lib.mkOption { + type = lib.types.path; example = "/etc/ssl/mx1.example.org.crt"; description = '' Path to the certificate used for TLS. @@ -269,8 +266,8 @@ in { ''; }; - extraConfig = mkOption { - type = with types; nullOr lines; + extraConfig = lib.mkOption { + type = with lib.types; nullOr lines; description = '' Arguments for the specified certificate loader. @@ -284,16 +281,16 @@ in { }; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open the configured incoming and outgoing mail server ports. ''; }; - ensureAccounts = mkOption { - type = with types; listOf str; + ensureAccounts = lib.mkOption { + type = with lib.types; listOf str; default = []; description = '' List of IMAP accounts which get automatically created. Note that for @@ -307,7 +304,7 @@ in { ]; }; - ensureCredentials = mkOption { + ensureCredentials = lib.mkOption { default = {}; description = '' List of user accounts which get automatically created if they don't @@ -319,10 +316,10 @@ in { "user1@localhost".passwordFile = /secrets/user1-localhost; "user2@localhost".passwordFile = /secrets/user2-localhost; }; - type = types.attrsOf (types.submodule { + type = lib.types.attrsOf (lib.types.submodule { options = { - passwordFile = mkOption { - type = types.path; + passwordFile = lib.mkOption { + type = lib.types.path; example = "/path/to/file"; default = null; description = '' @@ -335,7 +332,7 @@ in { }; secrets = lib.mkOption { - type = with types; listOf path; + type = with lib.types; listOf path; description = '' A list of files containing the various secrets. Should be in the format expected by systemd's `EnvironmentFile` directory. Secrets can be @@ -347,7 +344,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { @@ -387,17 +384,17 @@ in { }; maddy-ensure-accounts = { script = '' - ${optionalString (cfg.ensureAccounts != []) '' - ${concatMapStrings (account: '' + ${lib.optionalString (cfg.ensureAccounts != []) '' + ${lib.concatMapStrings (account: '' if ! ${pkgs.maddy}/bin/maddyctl imap-acct list | grep "${account}"; then ${pkgs.maddy}/bin/maddyctl imap-acct create ${account} fi '') cfg.ensureAccounts} ''} - ${optionalString (cfg.ensureCredentials != {}) '' - ${concatStringsSep "\n" (mapAttrsToList (name: cfg: '' + ${lib.optionalString (cfg.ensureCredentials != {}) '' + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: cfg: '' if ! ${pkgs.maddy}/bin/maddyctl creds list | grep "${name}"; then - ${pkgs.maddy}/bin/maddyctl creds create --password $(cat ${escapeShellArg cfg.passwordFile}) ${name} + ${pkgs.maddy}/bin/maddyctl creds create --password $(cat ${lib.escapeShellArg cfg.passwordFile}) ${name} fi '') cfg.ensureCredentials)} ''} @@ -422,9 +419,9 @@ in { hostname ${cfg.hostname} ${if (cfg.tls.loader == "file") then '' - tls file ${concatStringsSep " " ( + tls file ${lib.concatStringsSep " " ( map (x: x.certPath + " " + x.keyPath - ) cfg.tls.certificates)} ${optionalString (cfg.tls.extraConfig != "") '' + ) cfg.tls.certificates)} ${lib.optionalString (cfg.tls.extraConfig != "") '' { ${cfg.tls.extraConfig} } ''} '' else if (cfg.tls.loader == "acme") then '' @@ -441,7 +438,7 @@ in { ''; }; - users.users = optionalAttrs (cfg.user == name) { + users.users = lib.optionalAttrs (cfg.user == name) { ${name} = { isSystemUser = true; group = cfg.group; @@ -449,11 +446,11 @@ in { }; }; - users.groups = optionalAttrs (cfg.group == name) { + users.groups = lib.optionalAttrs (cfg.group == name) { ${cfg.group} = { }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ 25 143 587 ]; }; diff --git a/nixos/modules/services/mail/mail.nix b/nixos/modules/services/mail/mail.nix index fcc7ff6db91b..afa5b242b298 100644 --- a/nixos/modules/services/mail/mail.nix +++ b/nixos/modules/services/mail/mail.nix @@ -1,7 +1,4 @@ { config, options, lib, ... }: - -with lib; - { ###### interface @@ -10,8 +7,8 @@ with lib; services.mail = { - sendmailSetuidWrapper = mkOption { - type = types.nullOr options.security.wrappers.type.nestedTypes.elemType; + sendmailSetuidWrapper = lib.mkOption { + type = lib.types.nullOr options.security.wrappers.type.nestedTypes.elemType; default = null; internal = true; description = '' @@ -25,7 +22,7 @@ with lib; ###### implementation - config = mkIf (config.services.mail.sendmailSetuidWrapper != null) { + config = lib.mkIf (config.services.mail.sendmailSetuidWrapper != null) { security.wrappers.sendmail = config.services.mail.sendmailSetuidWrapper; diff --git a/nixos/modules/services/mail/mailhog.nix b/nixos/modules/services/mail/mailhog.nix index 455e5095495e..93400167a209 100644 --- a/nixos/modules/services/mail/mailhog.nix +++ b/nixos/modules/services/mail/mailhog.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.mailhog; @@ -21,40 +18,40 @@ in ###### interface imports = [ - (mkRemovedOptionModule [ "services" "mailhog" "user" ] "") + (lib.mkRemovedOptionModule [ "services" "mailhog" "user" ] "") ]; options = { services.mailhog = { - enable = mkEnableOption "MailHog, web and API based SMTP testing"; + enable = lib.mkEnableOption "MailHog, web and API based SMTP testing"; - storage = mkOption { - type = types.enum [ "maildir" "memory" ]; + storage = lib.mkOption { + type = lib.types.enum [ "maildir" "memory" ]; default = "memory"; description = "Store mails on disk or in memory."; }; - apiPort = mkOption { - type = types.port; + apiPort = lib.mkOption { + type = lib.types.port; default = 8025; description = "Port on which the API endpoint will listen."; }; - smtpPort = mkOption { - type = types.port; + smtpPort = lib.mkOption { + type = lib.types.port; default = 1025; description = "Port on which the SMTP endpoint will listen."; }; - uiPort = mkOption { - type = types.port; + uiPort = lib.mkOption { + type = lib.types.port; default = 8025; description = "Port on which the HTTP UI will listen."; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "List of additional arguments to pass to the MailHog process."; }; @@ -64,7 +61,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.mailhog = { description = "MailHog - Web and API based SMTP testing"; diff --git a/nixos/modules/services/mail/mailman.nix b/nixos/modules/services/mail/mailman.nix index b55a7422702f..95b77da250b2 100644 --- a/nixos/modules/services/mail/mailman.nix +++ b/nixos/modules/services/mail/mailman.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.mailman; @@ -33,6 +30,10 @@ let ENGINE = "haystack.backends.whoosh_backend.WhooshEngine"; PATH = "/var/lib/mailman-web/fulltext-index"; }; + } // lib.optionalAttrs cfg.enablePostfix { + EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"; + EMAIL_HOST = "127.0.0.1"; + EMAIL_PORT = 25; } // cfg.webSettings; webSettingsJSON = pkgs.writeText "settings.json" (builtins.toJSON webSettings); @@ -44,7 +45,7 @@ let transport_file_type: hash ''; - mailmanCfg = lib.generators.toINI {} (recursiveUpdate cfg.settings { + mailmanCfg = lib.generators.toINI {} (lib.recursiveUpdate cfg.settings { webservice.admin_pass = "#NIXOS_MAILMAN_REST_API_PASS_SECRET#"; }); @@ -68,15 +69,15 @@ in { ###### interface imports = [ - (mkRenamedOptionModule [ "services" "mailman" "hyperkittyBaseUrl" ] + (lib.mkRenamedOptionModule [ "services" "mailman" "hyperkittyBaseUrl" ] [ "services" "mailman" "hyperkitty" "baseUrl" ]) - (mkRemovedOptionModule [ "services" "mailman" "hyperkittyApiKey" ] '' + (lib.mkRemovedOptionModule [ "services" "mailman" "hyperkittyApiKey" ] '' The Hyperkitty API key is now generated on first run, and not stored in the world-readable Nix store. To continue using Hyperkitty, you must set services.mailman.hyperkitty.enable = true. '') - (mkRemovedOptionModule [ "services" "mailman" "package" ] '' + (lib.mkRemovedOptionModule [ "services" "mailman" "package" ] '' Didn't have an effect for several years. '') ]; @@ -85,38 +86,38 @@ in { services.mailman = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable Mailman on this host. Requires an active MTA on the host (e.g. Postfix)."; }; ldap = { - enable = mkEnableOption "LDAP auth"; - serverUri = mkOption { - type = types.str; + enable = lib.mkEnableOption "LDAP auth"; + serverUri = lib.mkOption { + type = lib.types.str; example = "ldaps://ldap.host"; description = '' LDAP host to connect against. ''; }; - bindDn = mkOption { - type = types.str; + bindDn = lib.mkOption { + type = lib.types.str; example = "cn=root,dc=nixos,dc=org"; description = '' Service account to bind against. ''; }; - bindPasswordFile = mkOption { - type = types.str; + bindPasswordFile = lib.mkOption { + type = lib.types.str; example = "/run/secrets/ldap-bind"; description = '' Path to the file containing the bind password of the service account defined by [](#opt-services.mailman.ldap.bindDn). ''; }; - superUserGroup = mkOption { - type = types.nullOr types.str; + superUserGroup = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "cn=admin,ou=groups,dc=nixos,dc=org"; description = '' @@ -124,15 +125,15 @@ in { ''; }; userSearch = { - query = mkOption { - type = types.str; + query = lib.mkOption { + type = lib.types.str; example = "(&(objectClass=inetOrgPerson)(|(uid=%(user)s)(mail=%(user)s)))"; description = '' Query to find a user in the LDAP database. ''; }; - ou = mkOption { - type = types.str; + ou = lib.mkOption { + type = lib.types.str; example = "ou=users,dc=nixos,dc=org"; description = '' Organizational unit to look up a user. @@ -140,27 +141,27 @@ in { }; }; groupSearch = { - type = mkOption { - type = types.enum [ + type = lib.mkOption { + type = lib.types.enum [ "posixGroup" "groupOfNames" "memberDNGroup" "nestedMemberDNGroup" "nestedGroupOfNames" "groupOfUniqueNames" "nestedGroupOfUniqueNames" "activeDirectoryGroup" "nestedActiveDirectoryGroup" "organizationalRoleGroup" "nestedOrganizationalRoleGroup" ]; default = "posixGroup"; - apply = v: "${toUpper (substring 0 1 v)}${substring 1 (stringLength v) v}Type"; + apply = v: "${lib.toUpper (lib.substring 0 1 v)}${lib.substring 1 (lib.stringLength v) v}Type"; description = '' Type of group to perform a group search against. ''; }; - query = mkOption { - type = types.str; + query = lib.mkOption { + type = lib.types.str; example = "(objectClass=groupOfNames)"; description = '' Query to find a group associated to a user in the LDAP database. ''; }; - ou = mkOption { - type = types.str; + ou = lib.mkOption { + type = lib.types.str; example = "ou=groups,dc=nixos,dc=org"; description = '' Organizational unit to look up a group. @@ -168,30 +169,30 @@ in { }; }; attrMap = { - username = mkOption { + username = lib.mkOption { default = "uid"; - type = types.str; + type = lib.types.str; description = '' LDAP-attribute that corresponds to the `username`-attribute in mailman. ''; }; - firstName = mkOption { + firstName = lib.mkOption { default = "givenName"; - type = types.str; + type = lib.types.str; description = '' LDAP-attribute that corresponds to the `firstName`-attribute in mailman. ''; }; - lastName = mkOption { + lastName = lib.mkOption { default = "sn"; - type = types.str; + type = lib.types.str; description = '' LDAP-attribute that corresponds to the `lastName`-attribute in mailman. ''; }; - email = mkOption { + email = lib.mkOption { default = "mail"; - type = types.str; + type = lib.types.str; description = '' LDAP-attribute that corresponds to the `email`-attribute in mailman. ''; @@ -199,8 +200,8 @@ in { }; }; - enablePostfix = mkOption { - type = types.bool; + enablePostfix = lib.mkOption { + type = lib.types.bool; default = true; example = false; description = '' @@ -213,8 +214,8 @@ in { ''; }; - siteOwner = mkOption { - type = types.str; + siteOwner = lib.mkOption { + type = lib.types.str; example = "postmaster@example.org"; description = '' Certain messages that must be delivered to a human, but which can't @@ -223,8 +224,8 @@ in { ''; }; - webHosts = mkOption { - type = types.listOf types.str; + webHosts = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' The list of hostnames and/or IP addresses from which the Mailman Web @@ -235,60 +236,60 @@ in { ''; }; - webUser = mkOption { - type = types.str; + webUser = lib.mkOption { + type = lib.types.str; default = "mailman-web"; description = '' User to run mailman-web as ''; }; - webSettings = mkOption { - type = types.attrs; + webSettings = lib.mkOption { + type = lib.types.attrs; default = {}; description = '' Overrides for the default mailman-web Django settings. ''; }; - restApiPassFile = mkOption { + restApiPassFile = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' Path to the file containing the value for `MAILMAN_REST_API_PASS`. ''; }; serve = { - enable = mkEnableOption "automatic nginx and uwsgi setup for mailman-web"; + enable = lib.mkEnableOption "automatic nginx and uwsgi setup for mailman-web"; - virtualRoot = mkOption { + virtualRoot = lib.mkOption { default = "/"; example = lib.literalExpression "/lists"; - type = types.str; + type = lib.types.str; description = '' Path to mount the mailman-web django application on. ''; }; }; - extraPythonPackages = mkOption { + extraPythonPackages = lib.mkOption { description = "Packages to add to the python environment used by mailman and mailman-web"; - type = types.listOf types.package; + type = lib.types.listOf lib.types.package; default = []; }; - settings = mkOption { + settings = lib.mkOption { description = "Settings for mailman.cfg"; - type = types.attrsOf (types.attrsOf types.str); + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); default = {}; }; hyperkitty = { - enable = mkEnableOption "the Hyperkitty archiver for Mailman"; + enable = lib.mkEnableOption "the Hyperkitty archiver for Mailman"; - baseUrl = mkOption { - type = types.str; + baseUrl = lib.mkOption { + type = lib.types.str; default = "http://localhost:18507/archives/"; description = '' Where can Mailman connect to Hyperkitty's internal API, preferably on @@ -302,7 +303,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.mailman.settings = { mailman.site_owner = lib.mkDefault cfg.siteOwner; @@ -336,14 +337,13 @@ in { inherit (config.services) postfix; requirePostfixHash = optionPath: dataFile: - with lib; let expected = "hash:/var/lib/mailman/data/${dataFile}"; - value = attrByPath optionPath [] postfix; + value = lib.attrByPath optionPath [] postfix; in - { assertion = postfix.enable -> isList value && elem expected value; + { assertion = postfix.enable -> lib.isList value && lib.elem expected value; message = '' - services.postfix.${concatStringsSep "." optionPath} must contain + services.postfix.${lib.concatStringsSep "." optionPath} must contain "${expected}". See . ''; @@ -408,7 +408,7 @@ in { config.read_file(f) MAILMAN_REST_API_PASS = config['webservice']['admin_pass'] - ${optionalString (cfg.ldap.enable) '' + ${lib.optionalString (cfg.ldap.enable) '' import ldap from django_auth_ldap.config import LDAPSearch, ${cfg.ldap.groupSearch.type} AUTH_LDAP_SERVER_URI = "${cfg.ldap.serverUri}" @@ -421,11 +421,11 @@ in { AUTH_LDAP_GROUP_SEARCH = LDAPSearch("${cfg.ldap.groupSearch.ou}", ldap.SCOPE_SUBTREE, "${cfg.ldap.groupSearch.query}") AUTH_LDAP_USER_ATTR_MAP = { - ${concatStrings (flip mapAttrsToList cfg.ldap.attrMap (key: value: '' + ${lib.concatStrings (lib.flip lib.mapAttrsToList cfg.ldap.attrMap (key: value: '' "${key}": "${value}", ''))} } - ${optionalString (cfg.ldap.superUserGroup != null) '' + ${lib.optionalString (cfg.ldap.superUserGroup != null) '' AUTH_LDAP_USER_FLAGS_BY_GROUP = { "is_superuser": "${cfg.ldap.superUserGroup}" } @@ -437,15 +437,15 @@ in { ''} ''; - services.nginx = mkIf (cfg.serve.enable && cfg.webHosts != []) { - enable = mkDefault true; + services.nginx = lib.mkIf (cfg.serve.enable && cfg.webHosts != []) { + enable = lib.mkDefault true; virtualHosts = lib.genAttrs cfg.webHosts (webHost: { locations = { ${cfg.serve.virtualRoot}.extraConfig = "uwsgi_pass unix:/run/mailman-web.socket;"; - "${removeSuffix "/" cfg.serve.virtualRoot}/static/".alias = webSettings.STATIC_ROOT + "/"; + "${lib.removeSuffix "/" cfg.serve.virtualRoot}/static/".alias = webSettings.STATIC_ROOT + "/"; }; }); - proxyTimeout = mkDefault "120s"; + proxyTimeout = lib.mkDefault "120s"; }; environment.systemPackages = [ (pkgs.buildEnv { @@ -483,7 +483,7 @@ in { ++ lib.optional cfg.enablePostfix "postfix-setup.service" ++ lib.optional withPostgresql "postgresql.service"; restartTriggers = [ mailmanCfgFile ]; - requires = optional withPostgresql "postgresql.service"; + requires = lib.optional withPostgresql "postgresql.service"; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = "${mailmanEnv}/bin/mailman start"; @@ -505,8 +505,8 @@ in { before = [ "mailman.service" "mailman-web-setup.service" "mailman-uwsgi.service" "hyperkitty.service" ]; requiredBy = [ "mailman.service" "mailman-web-setup.service" "mailman-uwsgi.service" "hyperkitty.service" ]; path = with pkgs; [ jq ]; - after = optional withPostgresql "postgresql.service"; - requires = optional withPostgresql "postgresql.service"; + after = lib.optional withPostgresql "postgresql.service"; + requires = lib.optional withPostgresql "postgresql.service"; serviceConfig.RemainAfterExit = true; serviceConfig.Type = "oneshot"; script = '' @@ -569,7 +569,7 @@ in { }; }; - mailman-uwsgi = mkIf cfg.serve.enable (let + mailman-uwsgi = lib.mkIf cfg.serve.enable (let uwsgiConfig.uwsgi = { type = "normal"; plugins = ["python3"]; @@ -585,9 +585,9 @@ in { uwsgiConfigFile = pkgs.writeText "uwsgi-mailman.json" (builtins.toJSON uwsgiConfig); in { wantedBy = ["multi-user.target"]; - after = optional withPostgresql "postgresql.service"; + after = lib.optional withPostgresql "postgresql.service"; requires = ["mailman-uwsgi.socket" "mailman-web-setup.service"] - ++ optional withPostgresql "postgresql.service"; + ++ lib.optional withPostgresql "postgresql.service"; restartTriggers = [ config.environment.etc."mailman3/settings.py".source ]; serviceConfig = { # Since the mailman-web settings.py obstinately creates a logs @@ -625,7 +625,7 @@ in { Restart = "on-failure"; }; }; - } // flip lib.mapAttrs' { + } // lib.flip lib.mapAttrs' { "minutely" = "minutely"; "quarter_hourly" = "*:00/15"; "hourly" = "hourly"; diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix index 80fd6d9f4e57..ea0a7ad3144b 100644 --- a/nixos/modules/services/mail/mlmmj.nix +++ b/nixos/modules/services/mail/mlmmj.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let concatMapLines = f: l: lib.concatStringsSep "\n" (map f l); @@ -53,38 +50,38 @@ in services.mlmmj = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable mlmmj"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "mlmmj"; description = "mailinglist local user"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "mlmmj"; description = "mailinglist local group"; }; - listDomain = mkOption { - type = types.str; + listDomain = lib.mkOption { + type = lib.types.str; default = "localhost"; description = "Set the mailing list domain"; }; - mailLists = mkOption { - type = types.listOf types.str; + mailLists = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "The collection of hosted maillists"; }; - maintInterval = mkOption { - type = types.str; + maintInterval = lib.mkOption { + type = lib.types.str; default = "20min"; description = '' Time interval between mlmmj-maintd runs, see @@ -98,7 +95,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.${cfg.user} = { description = "mlmmj user"; diff --git a/nixos/modules/services/mail/nullmailer.nix b/nixos/modules/services/mail/nullmailer.nix index 55a85a354452..eb982ad00bd7 100644 --- a/nixos/modules/services/mail/nullmailer.nix +++ b/nixos/modules/services/mail/nullmailer.nix @@ -1,42 +1,39 @@ { config, lib, pkgs, ... }: - -with lib; - { options = { services.nullmailer = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable nullmailer daemon."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "nullmailer"; description = '' User to use to run nullmailer-send. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "nullmailer"; description = '' Group to use to run nullmailer-send. ''; }; - setSendmail = mkOption { - type = types.bool; + setSendmail = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to set the system sendmail to nullmailer's."; }; - remotesFile = mkOption { - type = types.nullOr types.str; + remotesFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Path to the `remotes` control file. This file contains a @@ -48,8 +45,8 @@ with lib; }; config = { - adminaddr = mkOption { - type = types.nullOr types.str; + adminaddr = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' If set, all recipients to users at either "localhost" (the literal string) @@ -61,16 +58,16 @@ with lib; ''; }; - allmailfrom = mkOption { - type = types.nullOr types.str; + allmailfrom = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' If set, content will override the envelope sender on all messages. ''; }; - defaultdomain = mkOption { - type = types.nullOr types.str; + defaultdomain = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The content of this attribute is appended to any host name that @@ -80,8 +77,8 @@ with lib; ''; }; - defaulthost = mkOption { - type = types.nullOr types.str; + defaulthost = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The content of this attribute is appended to any address that @@ -90,8 +87,8 @@ with lib; ''; }; - doublebounceto = mkOption { - type = types.nullOr types.str; + doublebounceto = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' If the original sender was empty (the original message was a @@ -100,8 +97,8 @@ with lib; ''; }; - helohost = mkOption { - type = types.nullOr types.str; + helohost = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Sets the environment variable $HELOHOST which is used by the @@ -110,8 +107,8 @@ with lib; ''; }; - idhost = mkOption { - type = types.nullOr types.str; + idhost = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The content of this attribute is used when building the message-id @@ -119,8 +116,8 @@ with lib; ''; }; - maxpause = mkOption { - type = with types; nullOr (oneOf [ str int ]); + maxpause = lib.mkOption { + type = with lib.types; nullOr (oneOf [ str int ]); default = null; description = '' The maximum time to pause between successive queue runs, in seconds. @@ -128,8 +125,8 @@ with lib; ''; }; - me = mkOption { - type = types.nullOr types.str; + me = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The fully-qualifiled host name of the computer running nullmailer. @@ -137,8 +134,8 @@ with lib; ''; }; - pausetime = mkOption { - type = with types; nullOr (oneOf [ str int ]); + pausetime = lib.mkOption { + type = with lib.types; nullOr (oneOf [ str int ]); default = null; description = '' The minimum time to pause between successive queue runs when there @@ -150,8 +147,8 @@ with lib; ''; }; - remotes = mkOption { - type = types.nullOr types.str; + remotes = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' A list of remote servers to which to send each message. Each line @@ -167,8 +164,8 @@ with lib; ''; }; - sendtimeout = mkOption { - type = with types; nullOr (oneOf [ str int ]); + sendtimeout = lib.mkOption { + type = with lib.types; nullOr (oneOf [ str int ]); default = null; description = '' The time to wait for a remote module listed above to complete sending @@ -183,7 +180,7 @@ with lib; config = let cfg = config.services.nullmailer; - in mkIf cfg.enable { + in lib.mkIf cfg.enable { assertions = [ { assertion = cfg.config.remotes == null || cfg.remotesFile == null; @@ -194,10 +191,10 @@ with lib; environment = { systemPackages = [ pkgs.nullmailer ]; etc = let - validAttrs = lib.mapAttrs (_: toString) (filterAttrs (_: value: value != null) cfg.config); + validAttrs = lib.mapAttrs (_: toString) (lib.filterAttrs (_: value: value != null) cfg.config); in - (foldl' (as: name: as // { "nullmailer/${name}".text = validAttrs.${name}; }) {} (attrNames validAttrs)) - // optionalAttrs (cfg.remotesFile != null) { "nullmailer/remotes".source = cfg.remotesFile; }; + (lib.foldl' (as: name: as // { "nullmailer/${name}".text = validAttrs.${name}; }) {} (lib.attrNames validAttrs)) + // lib.optionalAttrs (cfg.remotesFile != null) { "nullmailer/remotes".source = cfg.remotesFile; }; }; users = { @@ -234,7 +231,7 @@ with lib; }; }; - services.mail.sendmailSetuidWrapper = mkIf cfg.setSendmail { + services.mail.sendmailSetuidWrapper = lib.mkIf cfg.setSendmail { program = "sendmail"; source = "${pkgs.nullmailer}/bin/sendmail"; owner = cfg.user; diff --git a/nixos/modules/services/mail/offlineimap.nix b/nixos/modules/services/mail/offlineimap.nix index f1517232c48d..6566a3cee11e 100644 --- a/nixos/modules/services/mail/offlineimap.nix +++ b/nixos/modules/services/mail/offlineimap.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.offlineimap; in { options.services.offlineimap = { - enable = mkEnableOption "OfflineIMAP, a software to dispose your mailbox(es) as a local Maildir(s)"; + enable = lib.mkEnableOption "OfflineIMAP, a software to dispose your mailbox(es) as a local Maildir(s)"; - install = mkOption { - type = types.bool; + install = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to install a user service for Offlineimap. Once @@ -22,28 +19,28 @@ in { ''; }; - package = mkPackageOption pkgs "offlineimap" { }; + package = lib.mkPackageOption pkgs "offlineimap" { }; - path = mkOption { - type = types.listOf types.path; + path = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; - example = literalExpression "[ pkgs.pass pkgs.bash pkgs.notmuch ]"; + example = lib.literalExpression "[ pkgs.pass pkgs.bash pkgs.notmuch ]"; description = "List of derivations to put in Offlineimap's path."; }; - onCalendar = mkOption { - type = types.str; + onCalendar = lib.mkOption { + type = lib.types.str; default = "*:0/3"; # every 3 minutes description = "How often is offlineimap started. Default is '*:0/3' meaning every 3 minutes. See systemd.time(7) for more information about the format."; }; - timeoutStartSec = mkOption { - type = types.str; + timeoutStartSec = lib.mkOption { + type = lib.types.str; default = "120sec"; # Kill if still alive after 2 minutes description = "How long waiting for offlineimap before killing it. Default is '120sec' meaning every 2 minutes. See systemd.time(7) for more information about the format."; }; }; - config = mkIf (cfg.enable || cfg.install) { + config = lib.mkIf (cfg.enable || cfg.install) { systemd.user.services.offlineimap = { description = "Offlineimap: a software to dispose your mailbox(es) as a local Maildir(s)"; serviceConfig = { @@ -62,6 +59,6 @@ in { # start immediately after computer is started: Persistent = "true"; }; - } // optionalAttrs cfg.enable { wantedBy = [ "default.target" ]; }; + } // lib.optionalAttrs cfg.enable { wantedBy = [ "default.target" ]; }; }; } diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix index 0460764ef094..dd29e5035089 100644 --- a/nixos/modules/services/mail/opendkim.nix +++ b/nixos/modules/services/mail/opendkim.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.opendkim; @@ -15,11 +12,11 @@ let "-d" cfg.domains "-k" keyFile "-s" cfg.selector - ] ++ optionals (cfg.configFile != null) [ "-x" cfg.configFile ]; + ] ++ lib.optionals (cfg.configFile != null) [ "-x" cfg.configFile ]; in { imports = [ - (mkRenamedOptionModule [ "services" "opendkim" "keyFile" ] [ "services" "opendkim" "keyPath" ]) + (lib.mkRenamedOptionModule [ "services" "opendkim" "keyFile" ] [ "services" "opendkim" "keyPath" ]) ]; ###### interface @@ -28,34 +25,34 @@ in { services.opendkim = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the OpenDKIM sender authentication system."; }; - socket = mkOption { - type = types.str; + socket = lib.mkOption { + type = lib.types.str; default = defaultSock; description = "Socket which is used for communication with OpenDKIM."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "opendkim"; description = "User for the daemon."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "opendkim"; description = "Group for the daemon."; }; - domains = mkOption { - type = types.str; + domains = lib.mkOption { + type = lib.types.str; default = "csl:${config.networking.hostName}"; - defaultText = literalExpression ''"csl:''${config.networking.hostName}"''; + defaultText = lib.literalExpression ''"csl:''${config.networking.hostName}"''; example = "csl:example.com,mydomain.net"; description = '' Local domains set (see `opendkim(8)` for more information on datasets). @@ -63,8 +60,8 @@ in { ''; }; - keyPath = mkOption { - type = types.path; + keyPath = lib.mkOption { + type = lib.types.path; description = '' The path that opendkim should put its generated private keys into. The DNS settings will be found in this directory with the name selector.txt. @@ -72,13 +69,13 @@ in { default = "/var/lib/opendkim/keys"; }; - selector = mkOption { - type = types.str; + selector = lib.mkOption { + type = lib.types.str; description = "Selector to use when signing."; }; - configFile = mkOption { - type = types.nullOr types.path; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = "Additional opendkim configuration."; }; @@ -90,16 +87,16 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == "opendkim") { + users.users = lib.optionalAttrs (cfg.user == "opendkim") { opendkim = { group = cfg.group; uid = config.ids.uids.opendkim; }; }; - users.groups = optionalAttrs (cfg.group == "opendkim") { + users.groups = lib.optionalAttrs (cfg.group == "opendkim") { opendkim.gid = config.ids.gids.opendkim; }; @@ -126,10 +123,10 @@ in { ''; serviceConfig = { - ExecStart = "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}"; + ExecStart = "${pkgs.opendkim}/bin/opendkim ${lib.escapeShellArgs args}"; User = cfg.user; Group = cfg.group; - RuntimeDirectory = optional (cfg.socket == defaultSock) "opendkim"; + RuntimeDirectory = lib.optional (cfg.socket == defaultSock) "opendkim"; StateDirectory = "opendkim"; StateDirectoryMode = "0700"; ReadWritePaths = [ cfg.keyPath ]; diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix index 88e7bc0193b5..07cf189fb28e 100644 --- a/nixos/modules/services/mail/opensmtpd.nix +++ b/nixos/modules/services/mail/opensmtpd.nix @@ -1,12 +1,9 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.opensmtpd; conf = pkgs.writeText "smtpd.conf" cfg.serverConfiguration; - args = concatStringsSep " " cfg.extraServerArgs; + args = lib.concatStringsSep " " cfg.extraServerArgs; sendmail = pkgs.runCommand "opensmtpd-sendmail" { preferLocalBuild = true; } '' mkdir -p $out/bin @@ -18,29 +15,29 @@ in { ###### interface imports = [ - (mkRenamedOptionModule [ "services" "opensmtpd" "addSendmailToSystemPath" ] [ "services" "opensmtpd" "setSendmail" ]) + (lib.mkRenamedOptionModule [ "services" "opensmtpd" "addSendmailToSystemPath" ] [ "services" "opensmtpd" "setSendmail" ]) ]; options = { services.opensmtpd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the OpenSMTPD server."; }; - package = mkPackageOption pkgs "opensmtpd" { }; + package = lib.mkPackageOption pkgs "opensmtpd" { }; - setSendmail = mkOption { - type = types.bool; + setSendmail = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to set the system sendmail to OpenSMTPD's."; }; - extraServerArgs = mkOption { - type = types.listOf types.str; + extraServerArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "-v" "-P mta" ]; description = '' @@ -49,8 +46,8 @@ in { ''; }; - serverConfiguration = mkOption { - type = types.lines; + serverConfiguration = lib.mkOption { + type = lib.types.lines; example = '' listen on lo accept for any deliver to lmtp localhost:24 @@ -61,8 +58,8 @@ in { ''; }; - procPackages = mkOption { - type = types.listOf types.package; + procPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; description = '' Packages to search for filters, tables, queues, and schedulers. @@ -78,7 +75,7 @@ in { ###### implementation - config = mkIf cfg.enable rec { + config = lib.mkIf cfg.enable rec { users.groups = { smtpd.gid = config.ids.gids.smtpd; smtpq.gid = config.ids.gids.smtpq; @@ -105,7 +102,7 @@ in { source = "${cfg.package}/bin/smtpctl"; }; - services.mail.sendmailSetuidWrapper = mkIf cfg.setSendmail + services.mail.sendmailSetuidWrapper = lib.mkIf cfg.setSendmail (security.wrappers.smtpctl // { program = "sendmail"; }); systemd.tmpfiles.rules = [ diff --git a/nixos/modules/services/mail/pfix-srsd.nix b/nixos/modules/services/mail/pfix-srsd.nix index 7ad2b20454d0..d4176c509d7a 100644 --- a/nixos/modules/services/mail/pfix-srsd.nix +++ b/nixos/modules/services/mail/pfix-srsd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - { ###### interface @@ -9,25 +6,25 @@ with lib; options = { services.pfix-srsd = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "Whether to run the postfix sender rewriting scheme daemon."; }; - domain = mkOption { + domain = lib.mkOption { description = "The domain for which to enable srs"; - type = types.str; + type = lib.types.str; example = "example.com"; }; - secretsFile = mkOption { + secretsFile = lib.mkOption { description = '' The secret data used to encode the SRS address. to generate, use a command like: `for n in $(seq 5); do dd if=/dev/urandom count=1 bs=1024 status=none | sha256sum | sed 's/ -$//' | sed 's/^/ /'; done` ''; - type = types.path; + type = lib.types.path; default = "/var/lib/pfix-srsd/secrets"; }; }; @@ -35,7 +32,7 @@ with lib; ###### implementation - config = mkIf config.services.pfix-srsd.enable { + config = lib.mkIf config.services.pfix-srsd.enable { environment = { systemPackages = [ pkgs.pfixtools ]; }; diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index 6bb501959f95..244ce49ee63b 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.postfix; @@ -17,32 +14,32 @@ let haveLocalRecipients = cfg.localRecipients != null; clientAccess = - optional (cfg.dnsBlacklistOverrides != "") + lib.optional (cfg.dnsBlacklistOverrides != "") "check_client_access hash:/etc/postfix/client_access"; dnsBl = - optionals (cfg.dnsBlacklists != []) + lib.optionals (cfg.dnsBlacklists != []) (map (s: "reject_rbl_client " + s) cfg.dnsBlacklists); - clientRestrictions = concatStringsSep ", " (clientAccess ++ dnsBl); + clientRestrictions = lib.concatStringsSep ", " (clientAccess ++ dnsBl); mainCf = let - escape = replaceStrings ["$"] ["$$"]; - mkList = items: "\n " + concatStringsSep ",\n " items; + escape = lib.replaceStrings ["$"] ["$$"]; + mkList = items: "\n " + lib.concatStringsSep ",\n " items; mkVal = value: - if isList value then mkList value + if lib.isList value then mkList value else " " + (if value == true then "yes" else if value == false then "no" else toString value); mkEntry = name: value: "${escape name} =${mkVal value}"; in - concatStringsSep "\n" (mapAttrsToList mkEntry cfg.config) + lib.concatStringsSep "\n" (lib.mapAttrsToList mkEntry cfg.config) + "\n" + cfg.extraConfig; masterCfOptions = { options, config, name, ... }: { options = { - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = name; example = "smtp"; description = '' @@ -50,15 +47,15 @@ let ''; }; - type = mkOption { - type = types.enum [ "inet" "unix" "unix-dgram" "fifo" "pass" ]; + type = lib.mkOption { + type = lib.types.enum [ "inet" "unix" "unix-dgram" "fifo" "pass" ]; default = "unix"; example = "inet"; description = "The type of the service"; }; - private = mkOption { - type = types.bool; + private = lib.mkOption { + type = lib.types.bool; example = false; description = '' Whether the service's sockets and storage directory is restricted to @@ -67,14 +64,14 @@ let ''; }; - privileged = mkOption { - type = types.bool; + privileged = lib.mkOption { + type = lib.types.bool; example = true; description = ""; }; - chroot = mkOption { - type = types.bool; + chroot = lib.mkOption { + type = lib.types.bool; example = true; description = '' Whether the service is chrooted to have only access to the @@ -83,8 +80,8 @@ let ''; }; - wakeup = mkOption { - type = types.int; + wakeup = lib.mkOption { + type = lib.types.int; example = 60; description = '' Automatically wake up the service after the specified number of @@ -93,8 +90,8 @@ let ''; }; - wakeupUnusedComponent = mkOption { - type = types.bool; + wakeupUnusedComponent = lib.mkOption { + type = lib.types.bool; example = false; description = '' If set to `false` the component will only be woken @@ -104,8 +101,8 @@ let ''; }; - maxproc = mkOption { - type = types.int; + maxproc = lib.mkOption { + type = lib.types.int; example = 1; description = '' The maximum number of processes to spawn for this service. If the @@ -115,8 +112,8 @@ let ''; }; - command = mkOption { - type = types.str; + command = lib.mkOption { + type = lib.types.str; default = name; example = "smtpd"; description = '' @@ -125,8 +122,8 @@ let ''; }; - args = mkOption { - type = types.listOf types.str; + args = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "-o" "smtp_helo_timeout=5" ]; description = '' @@ -136,8 +133,8 @@ let ''; }; - rawEntry = mkOption { - type = types.listOf types.str; + rawEntry = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; internal = true; description = '' @@ -148,7 +145,7 @@ let config.rawEntry = let mkBool = bool: if bool then "y" else "n"; - mkArg = arg: "${optionalString (hasPrefix "-" arg) "\n "}${arg}"; + mkArg = arg: "${lib.optionalString (lib.hasPrefix "-" arg) "\n "}${arg}"; maybeOption = fun: option: if options.${option}.isDefined then fun config.${option} else "-"; @@ -158,7 +155,7 @@ let wakeupDefined = options.wakeup.isDefined; wakeupUCDefined = options.wakeupUnusedComponent.isDefined; finalValue = toString config.wakeup - + optionalString (wakeupUCDefined && !config.wakeupUnusedComponent) "?"; + + lib.optionalString (wakeupUCDefined && !config.wakeupUnusedComponent) "?"; in if wakeupDefined then finalValue else "-"; in [ @@ -169,7 +166,7 @@ let (maybeOption mkBool "chroot") wakeup (maybeOption toString "maxproc") - (config.command + " " + concatMapStringsSep " " mkArg config.args) + (config.command + " " + lib.concatMapStringsSep " " mkArg config.args) ]; }; @@ -184,47 +181,47 @@ let "# " "" "(yes)" "(yes)" "(no)" "(never)" "(100)" "" "" ]; - masterCf = mapAttrsToList (const (getAttr "rawEntry")) cfg.masterConfig; + masterCf = lib.mapAttrsToList (lib.const (lib.getAttr "rawEntry")) cfg.masterConfig; # A list of the maximum width of the columns across all lines and labels maxWidths = let foldLine = line: acc: let - columnLengths = map stringLength line; - in zipListsWith max acc columnLengths; + columnLengths = map lib.stringLength line; + in lib.zipListsWith lib.max acc columnLengths; # We need to handle the last column specially here, because it's # open-ended (command + args). - lines = [ labels labelDefaults ] ++ (map (l: init l ++ [""]) masterCf); - in foldr foldLine (genList (const 0) (length labels)) lines; + lines = [ labels labelDefaults ] ++ (map (l: lib.init l ++ [""]) masterCf); + in lib.foldr foldLine (lib.genList (lib.const 0) (lib.length labels)) lines; # Pad a string with spaces from the right (opposite of fixedWidthString). pad = width: str: let - padWidth = width - stringLength str; - padding = concatStrings (genList (const " ") padWidth); - in str + optionalString (padWidth > 0) padding; + padWidth = width - lib.stringLength str; + padding = lib.concatStrings (lib.genList (lib.const " ") padWidth); + in str + lib.optionalString (padWidth > 0) padding; # It's + 2 here, because that's the amount of spacing between columns. - fullWidth = foldr (width: acc: acc + width + 2) 0 maxWidths; + fullWidth = lib.foldr (width: acc: acc + width + 2) 0 maxWidths; - formatLine = line: concatStringsSep " " (zipListsWith pad maxWidths line); + formatLine = line: lib.concatStringsSep " " (lib.zipListsWith pad maxWidths line); formattedLabels = let - sep = "# " + concatStrings (genList (const "=") (fullWidth + 5)); + sep = "# " + lib.concatStrings (lib.genList (lib.const "=") (fullWidth + 5)); lines = [ sep (formatLine labels) (formatLine labelDefaults) sep ]; - in concatStringsSep "\n" lines; + in lib.concatStringsSep "\n" lines; - in formattedLabels + "\n" + concatMapStringsSep "\n" formatLine masterCf + "\n" + cfg.extraMasterConf; + in formattedLabels + "\n" + lib.concatMapStringsSep "\n" formatLine masterCf + "\n" + cfg.extraMasterConf; headerCheckOptions = { ... }: { options = { - pattern = mkOption { - type = types.str; + pattern = lib.mkOption { + type = lib.types.str; default = "/^.*/"; example = "/^X-Mailer:/"; description = "A regexp pattern matching the header"; }; - action = mkOption { - type = types.str; + action = lib.mkOption { + type = lib.types.str; default = "DUNNO"; example = "BCC mail@example.com"; description = "The action to be executed when the pattern is matched"; @@ -232,13 +229,13 @@ let }; }; - headerChecks = concatStringsSep "\n" (map (x: "${x.pattern} ${x.action}") cfg.headerChecks) + cfg.extraHeaderChecks; + headerChecks = lib.concatStringsSep "\n" (map (x: "${x.pattern} ${x.action}") cfg.headerChecks) + cfg.extraHeaderChecks; - aliases = let separator = optionalString (cfg.aliasMapType == "hash") ":"; in - optionalString (cfg.postmasterAlias != "") '' + aliases = let separator = lib.optionalString (cfg.aliasMapType == "hash") ":"; in + lib.optionalString (cfg.postmasterAlias != "") '' postmaster${separator} ${cfg.postmasterAlias} '' - + optionalString (cfg.rootAlias != "") '' + + lib.optionalString (cfg.rootAlias != "") '' root${separator} ${cfg.rootAlias} '' + cfg.extraAliases @@ -247,7 +244,7 @@ let aliasesFile = pkgs.writeText "postfix-aliases" aliases; canonicalFile = pkgs.writeText "postfix-canonical" cfg.canonical; virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual; - localRecipientMapFile = pkgs.writeText "postfix-local-recipient-map" (concatMapStrings (x: x + " ACCEPT\n") cfg.localRecipients); + localRecipientMapFile = pkgs.writeText "postfix-local-recipient-map" (lib.concatMapStrings (x: x + " ACCEPT\n") cfg.localRecipients); checkClientAccessFile = pkgs.writeText "postfix-check-client-access" cfg.dnsBlacklistOverrides; mainCfFile = pkgs.writeText "postfix-main.cf" mainCf; masterCfFile = pkgs.writeText "postfix-master.cf" masterCfContent; @@ -264,26 +261,26 @@ in services.postfix = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to run the Postfix mail server."; }; - enableSmtp = mkOption { - type = types.bool; + enableSmtp = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to enable smtp in master.cf."; }; - enableSubmission = mkOption { - type = types.bool; + enableSubmission = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable smtp submission."; }; - enableSubmissions = mkOption { - type = types.bool; + enableSubmissions = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable smtp submission via smtps. @@ -293,8 +290,8 @@ in ''; }; - submissionOptions = mkOption { - type = with types; attrsOf str; + submissionOptions = lib.mkOption { + type = with lib.types; attrsOf str; default = { smtpd_tls_security_level = "encrypt"; smtpd_sasl_auth_enable = "yes"; @@ -311,8 +308,8 @@ in description = "Options for the submission config in master.cf"; }; - submissionsOptions = mkOption { - type = with types; attrsOf str; + submissionsOptions = lib.mkOption { + type = with lib.types; attrsOf str; default = { smtpd_sasl_auth_enable = "yes"; smtpd_client_restrictions = "permit_sasl_authenticated,reject"; @@ -334,26 +331,26 @@ in ''; }; - setSendmail = mkOption { - type = types.bool; + setSendmail = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to set the system sendmail to postfix's."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "postfix"; description = "What to call the Postfix user (must be used only for postfix)."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "postfix"; description = "What to call the Postfix group (must be used only for postfix)."; }; - setgidGroup = mkOption { - type = types.str; + setgidGroup = lib.mkOption { + type = lib.types.str; default = "postdrop"; description = '' How to call postfix setgid group (for postdrop). Should @@ -361,8 +358,8 @@ in ''; }; - networks = mkOption { - type = types.nullOr (types.listOf types.str); + networks = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; example = ["192.168.0.1/24"]; description = '' @@ -372,8 +369,8 @@ in ''; }; - networksStyle = mkOption { - type = types.str; + networksStyle = lib.mkOption { + type = lib.types.str; default = ""; description = '' Name of standard way of trusted network specification to use, @@ -382,8 +379,8 @@ in ''; }; - hostname = mkOption { - type = types.str; + hostname = lib.mkOption { + type = lib.types.str; default = ""; description = '' Hostname to use. Leave blank to use just the hostname of machine. @@ -391,24 +388,24 @@ in ''; }; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; default = ""; description = '' Domain to use. Leave blank to use hostname minus first component. ''; }; - origin = mkOption { - type = types.str; + origin = lib.mkOption { + type = lib.types.str; default = ""; description = '' Origin to use in outgoing e-mail. Leave blank to use hostname. ''; }; - destination = mkOption { - type = types.nullOr (types.listOf types.str); + destination = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; example = ["localhost"]; description = '' @@ -417,8 +414,8 @@ in ''; }; - relayDomains = mkOption { - type = types.nullOr (types.listOf types.str); + relayDomains = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; example = ["localdomain"]; description = '' @@ -426,32 +423,32 @@ in ''; }; - relayHost = mkOption { - type = types.str; + relayHost = lib.mkOption { + type = lib.types.str; default = ""; description = '' Mail relay for outbound mail. ''; }; - relayPort = mkOption { - type = types.int; + relayPort = lib.mkOption { + type = lib.types.int; default = 25; description = '' SMTP port for relay mail relay. ''; }; - lookupMX = mkOption { - type = types.bool; + lookupMX = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether relay specified is just domain whose MX must be used. ''; }; - postmasterAlias = mkOption { - type = types.str; + postmasterAlias = lib.mkOption { + type = lib.types.str; default = "root"; description = '' Who should receive postmaster e-mail. Multiple values can be added by @@ -459,8 +456,8 @@ in ''; }; - rootAlias = mkOption { - type = types.str; + rootAlias = lib.mkOption { + type = lib.types.str; default = ""; description = '' Who should receive root e-mail. Blank for no redirection. @@ -468,23 +465,23 @@ in ''; }; - extraAliases = mkOption { - type = types.lines; + extraAliases = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Additional entries to put verbatim into aliases file, cf. man-page aliases(8). ''; }; - aliasMapType = mkOption { - type = with types; enum [ "hash" "regexp" "pcre" ]; + aliasMapType = lib.mkOption { + type = with lib.types; enum [ "hash" "regexp" "pcre" ]; default = "hash"; example = "regexp"; description = "The format the alias map should have. Use regexp if you want to use regular expressions."; }; - config = mkOption { - type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); + config = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ bool int str (listOf str) ]); description = '' The main.cf configuration file as key value set. ''; @@ -494,37 +491,37 @@ in }; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra lines to be added verbatim to the main.cf configuration file. ''; }; - tlsTrustedAuthorities = mkOption { - type = types.str; + tlsTrustedAuthorities = lib.mkOption { + type = lib.types.str; default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; - defaultText = literalExpression ''"''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"''; + defaultText = lib.literalExpression ''"''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"''; description = '' File containing trusted certification authorities (CA) to verify certificates of mailservers contacted for mail delivery. This basically sets smtp_tls_CAfile and enables opportunistic tls. Defaults to NixOS trusted certification authorities. ''; }; - sslCert = mkOption { - type = types.str; + sslCert = lib.mkOption { + type = lib.types.str; default = ""; description = "SSL certificate to use."; }; - sslKey = mkOption { - type = types.str; + sslKey = lib.mkOption { + type = lib.types.str; default = ""; description = "SSL key to use."; }; - recipientDelimiter = mkOption { - type = types.str; + recipientDelimiter = lib.mkOption { + type = lib.types.str; default = ""; example = "+"; description = '' @@ -532,32 +529,32 @@ in ''; }; - canonical = mkOption { - type = types.lines; + canonical = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Entries for the {manpage}`canonical(5)` table. ''; }; - virtual = mkOption { - type = types.lines; + virtual = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Entries for the virtual alias map, cf. man-page virtual(5). ''; }; - virtualMapType = mkOption { - type = types.enum ["hash" "regexp" "pcre"]; + virtualMapType = lib.mkOption { + type = lib.types.enum ["hash" "regexp" "pcre"]; default = "hash"; description = '' What type of virtual alias map file to use. Use `"regexp"` for regular expressions. ''; }; - localRecipients = mkOption { - type = with types; nullOr (listOf str); + localRecipients = lib.mkOption { + type = with lib.types; nullOr (listOf str); default = null; description = '' List of accepted local users. Specify a bare username, an @@ -569,28 +566,28 @@ in ''; }; - transport = mkOption { + transport = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Entries for the transport map, cf. man-page transport(8). ''; }; - dnsBlacklists = mkOption { + dnsBlacklists = lib.mkOption { default = []; - type = with types; listOf str; + type = with lib.types; listOf str; description = "dns blacklist servers to use with smtpd_client_restrictions"; }; - dnsBlacklistOverrides = mkOption { + dnsBlacklistOverrides = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = "contents of check_client_access for overriding dnsBlacklists"; }; - masterConfig = mkOption { - type = types.attrsOf (types.submodule masterCfOptions); + masterConfig = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule masterCfOptions); default = {}; example = { submission = { @@ -605,48 +602,48 @@ in ''; }; - extraMasterConf = mkOption { - type = types.lines; + extraMasterConf = lib.mkOption { + type = lib.types.lines; default = ""; example = "submission inet n - n - - smtpd"; description = "Extra lines to append to the generated master.cf file."; }; - enableHeaderChecks = mkOption { - type = types.bool; + enableHeaderChecks = lib.mkOption { + type = lib.types.bool; default = false; example = true; description = "Whether to enable postfix header checks"; }; - headerChecks = mkOption { - type = types.listOf (types.submodule headerCheckOptions); + headerChecks = lib.mkOption { + type = lib.types.listOf (lib.types.submodule headerCheckOptions); default = []; example = [ { pattern = "/^X-Spam-Flag:/"; action = "REDIRECT spam@example.com"; } ]; description = "Postfix header checks."; }; - extraHeaderChecks = mkOption { - type = types.lines; + extraHeaderChecks = lib.mkOption { + type = lib.types.lines; default = ""; example = "/^X-Spam-Flag:/ REDIRECT spam@example.com"; description = "Extra lines to /etc/postfix/header_checks file."; }; - aliasFiles = mkOption { - type = types.attrsOf types.path; + aliasFiles = lib.mkOption { + type = lib.types.attrsOf lib.types.path; default = {}; description = "Aliases' tables to be compiled and placed into /var/lib/postfix/conf."; }; - mapFiles = mkOption { - type = types.attrsOf types.path; + mapFiles = lib.mkOption { + type = lib.types.attrsOf lib.types.path; default = {}; description = "Maps to be compiled and placed into /var/lib/postfix/conf."; }; - useSrs = mkOption { - type = types.bool; + useSrs = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable sender rewriting scheme"; }; @@ -658,7 +655,7 @@ in ###### implementation - config = mkIf config.services.postfix.enable (mkMerge [ + config = lib.mkIf config.services.postfix.enable (lib.mkMerge [ { environment = { @@ -670,7 +667,7 @@ in services.pfix-srsd.enable = config.services.postfix.useSrs; - services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail { + services.mail.sendmailSetuidWrapper = lib.mkIf config.services.postfix.setSendmail { program = "sendmail"; source = "${pkgs.postfix}/bin/sendmail"; owner = "root"; @@ -706,7 +703,7 @@ in setgid = true; }; - users.users = optionalAttrs (user == "postfix") + users.users = lib.optionalAttrs (user == "postfix") { postfix = { description = "Postfix mail server user"; uid = config.ids.uids.postfix; @@ -715,10 +712,10 @@ in }; users.groups = - optionalAttrs (group == "postfix") + lib.optionalAttrs (group == "postfix") { ${group}.gid = config.ids.gids.postfix; } - // optionalAttrs (setgidGroup == "postdrop") + // lib.optionalAttrs (setgidGroup == "postdrop") { ${setgidGroup}.gid = config.ids.gids.postdrop; }; @@ -745,11 +742,11 @@ in ln -sf ${mainCfFile} /var/lib/postfix/conf/main.cf ln -sf ${masterCfFile} /var/lib/postfix/conf/master.cf - ${concatStringsSep "\n" (mapAttrsToList (to: from: '' + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (to: from: '' ln -sf ${from} /var/lib/postfix/conf/${to} ${pkgs.postfix}/bin/postalias -o -p /var/lib/postfix/conf/${to} '') cfg.aliasFiles)} - ${concatStringsSep "\n" (mapAttrsToList (to: from: '' + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (to: from: '' ln -sf ${from} /var/lib/postfix/conf/${to} ${pkgs.postfix}/bin/postmap /var/lib/postfix/conf/${to} '') cfg.mapFiles)} @@ -795,7 +792,7 @@ in }; }; - services.postfix.config = (mapAttrs (_: v: mkDefault v) { + services.postfix.config = (lib.mapAttrs (_: v: lib.mkDefault v) { compatibility_level = pkgs.postfix.version; mail_owner = cfg.user; default_privs = "nobody"; @@ -819,39 +816,39 @@ in mail_spool_directory = "/var/spool/mail/"; setgid_group = cfg.setgidGroup; }) - // optionalAttrs (cfg.relayHost != "") { relayhost = if cfg.lookupMX + // lib.optionalAttrs (cfg.relayHost != "") { relayhost = if cfg.lookupMX then "${cfg.relayHost}:${toString cfg.relayPort}" else "[${cfg.relayHost}]:${toString cfg.relayPort}"; } - // optionalAttrs (!config.networking.enableIPv6) { inet_protocols = mkDefault "ipv4"; } - // optionalAttrs (cfg.networks != null) { mynetworks = cfg.networks; } - // optionalAttrs (cfg.networksStyle != "") { mynetworks_style = cfg.networksStyle; } - // optionalAttrs (cfg.hostname != "") { myhostname = cfg.hostname; } - // optionalAttrs (cfg.domain != "") { mydomain = cfg.domain; } - // optionalAttrs (cfg.origin != "") { myorigin = cfg.origin; } - // optionalAttrs (cfg.destination != null) { mydestination = cfg.destination; } - // optionalAttrs (cfg.relayDomains != null) { relay_domains = cfg.relayDomains; } - // optionalAttrs (cfg.recipientDelimiter != "") { recipient_delimiter = cfg.recipientDelimiter; } - // optionalAttrs haveAliases { alias_maps = [ "${cfg.aliasMapType}:/etc/postfix/aliases" ]; } - // optionalAttrs haveTransport { transport_maps = [ "hash:/etc/postfix/transport" ]; } - // optionalAttrs haveVirtual { virtual_alias_maps = [ "${cfg.virtualMapType}:/etc/postfix/virtual" ]; } - // optionalAttrs haveLocalRecipients { local_recipient_maps = [ "hash:/etc/postfix/local_recipients" ] ++ optional haveAliases "$alias_maps"; } - // optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; } - // optionalAttrs cfg.useSrs { + // lib.optionalAttrs (!config.networking.enableIPv6) { inet_protocols = lib.mkDefault "ipv4"; } + // lib.optionalAttrs (cfg.networks != null) { mynetworks = cfg.networks; } + // lib.optionalAttrs (cfg.networksStyle != "") { mynetworks_style = cfg.networksStyle; } + // lib.optionalAttrs (cfg.hostname != "") { myhostname = cfg.hostname; } + // lib.optionalAttrs (cfg.domain != "") { mydomain = cfg.domain; } + // lib.optionalAttrs (cfg.origin != "") { myorigin = cfg.origin; } + // lib.optionalAttrs (cfg.destination != null) { mydestination = cfg.destination; } + // lib.optionalAttrs (cfg.relayDomains != null) { relay_domains = cfg.relayDomains; } + // lib.optionalAttrs (cfg.recipientDelimiter != "") { recipient_delimiter = cfg.recipientDelimiter; } + // lib.optionalAttrs haveAliases { alias_maps = [ "${cfg.aliasMapType}:/etc/postfix/aliases" ]; } + // lib.optionalAttrs haveTransport { transport_maps = [ "hash:/etc/postfix/transport" ]; } + // lib.optionalAttrs haveVirtual { virtual_alias_maps = [ "${cfg.virtualMapType}:/etc/postfix/virtual" ]; } + // lib.optionalAttrs haveLocalRecipients { local_recipient_maps = [ "hash:/etc/postfix/local_recipients" ] ++ lib.optional haveAliases "$alias_maps"; } + // lib.optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; } + // lib.optionalAttrs cfg.useSrs { sender_canonical_maps = [ "tcp:127.0.0.1:10001" ]; sender_canonical_classes = [ "envelope_sender" ]; recipient_canonical_maps = [ "tcp:127.0.0.1:10002" ]; recipient_canonical_classes = [ "envelope_recipient" ]; } - // optionalAttrs cfg.enableHeaderChecks { header_checks = [ "regexp:/etc/postfix/header_checks" ]; } - // optionalAttrs (cfg.tlsTrustedAuthorities != "") { + // lib.optionalAttrs cfg.enableHeaderChecks { header_checks = [ "regexp:/etc/postfix/header_checks" ]; } + // lib.optionalAttrs (cfg.tlsTrustedAuthorities != "") { smtp_tls_CAfile = cfg.tlsTrustedAuthorities; - smtp_tls_security_level = mkDefault "may"; + smtp_tls_security_level = lib.mkDefault "may"; } - // optionalAttrs (cfg.sslCert != "") { + // lib.optionalAttrs (cfg.sslCert != "") { smtp_tls_cert_file = cfg.sslCert; smtp_tls_key_file = cfg.sslKey; - smtp_tls_security_level = mkDefault "may"; + smtp_tls_security_level = lib.mkDefault "may"; smtpd_tls_cert_file = cfg.sslCert; smtpd_tls_key_file = cfg.sslKey; @@ -931,16 +928,16 @@ in scache = { maxproc = 1; }; - } // optionalAttrs cfg.enableSubmission { + } // lib.optionalAttrs cfg.enableSubmission { submission = { type = "inet"; private = false; command = "smtpd"; args = let mkKeyVal = opt: val: [ "-o" (opt + "=" + val) ]; - in concatLists (mapAttrsToList mkKeyVal cfg.submissionOptions); + in lib.concatLists (lib.mapAttrsToList mkKeyVal cfg.submissionOptions); }; - } // optionalAttrs cfg.enableSmtp { + } // lib.optionalAttrs cfg.enableSmtp { smtp_inet = { name = "smtp"; type = "inet"; @@ -952,7 +949,7 @@ in command = "smtp"; args = [ "-o" "smtp_fallback_relay=" ]; }; - } // optionalAttrs cfg.enableSubmissions { + } // lib.optionalAttrs cfg.enableSubmissions { submissions = { type = "inet"; private = false; @@ -964,43 +961,43 @@ in cfg.submissionsOptions.smtpd_tls_security_level == "may"; submissionsOptions = cfg.submissionsOptions // { smtpd_tls_wrappermode = "yes"; - } // optionalAttrs adjustSmtpTlsSecurityLevel { + } // lib.optionalAttrs adjustSmtpTlsSecurityLevel { smtpd_tls_security_level = "encrypt"; }; - in concatLists (mapAttrsToList mkKeyVal submissionsOptions); + in lib.concatLists (lib.mapAttrsToList mkKeyVal submissionsOptions); }; }; } - (mkIf haveAliases { + (lib.mkIf haveAliases { services.postfix.aliasFiles.aliases = aliasesFile; }) - (mkIf haveCanonical { + (lib.mkIf haveCanonical { services.postfix.mapFiles.canonical = canonicalFile; }) - (mkIf haveTransport { + (lib.mkIf haveTransport { services.postfix.mapFiles.transport = transportFile; }) - (mkIf haveVirtual { + (lib.mkIf haveVirtual { services.postfix.mapFiles.virtual = virtualFile; }) - (mkIf haveLocalRecipients { + (lib.mkIf haveLocalRecipients { services.postfix.mapFiles.local_recipients = localRecipientMapFile; }) - (mkIf cfg.enableHeaderChecks { + (lib.mkIf cfg.enableHeaderChecks { services.postfix.mapFiles.header_checks = headerChecksFile; }) - (mkIf (cfg.dnsBlacklists != []) { + (lib.mkIf (cfg.dnsBlacklists != []) { services.postfix.mapFiles.client_access = checkClientAccessFile; }) ]); imports = [ - (mkRemovedOptionModule [ "services" "postfix" "sslCACert" ] + (lib.mkRemovedOptionModule [ "services" "postfix" "sslCACert" ] "services.postfix.sslCACert was replaced by services.postfix.tlsTrustedAuthorities. In case you intend that your server should validate requested client certificates use services.postfix.extraConfig.") - (mkChangedOptionModule [ "services" "postfix" "useDane" ] + (lib.mkChangedOptionModule [ "services" "postfix" "useDane" ] [ "services" "postfix" "config" "smtp_tls_security_level" ] - (config: mkIf config.services.postfix.useDane "dane")) + (config: lib.mkIf config.services.postfix.useDane "dane")) ]; } diff --git a/nixos/modules/services/mail/postfixadmin.nix b/nixos/modules/services/mail/postfixadmin.nix index 87a9f963b195..7523fa4930ab 100644 --- a/nixos/modules/services/mail/postfixadmin.nix +++ b/nixos/modules/services/mail/postfixadmin.nix @@ -1,7 +1,4 @@ { lib, config, pkgs, ... }: - -with lib; - let cfg = config.services.postfixadmin; fpm = config.services.phpfpm.pools.postfixadmin; @@ -10,8 +7,8 @@ let in { options.services.postfixadmin = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable postfixadmin. @@ -22,14 +19,14 @@ in ''; }; - hostName = mkOption { - type = types.str; + hostName = lib.mkOption { + type = lib.types.str; example = "postfixadmin.example.com"; description = "Hostname to use for the nginx vhost"; }; - adminEmail = mkOption { - type = types.str; + adminEmail = lib.mkOption { + type = lib.types.str; example = "postmaster@example.com"; description = '' Defines the Site Admin's email address. @@ -38,8 +35,8 @@ in ''; }; - setupPasswordFile = mkOption { - type = types.path; + setupPasswordFile = lib.mkOption { + type = lib.types.path; description = '' Password file for the admin. Generate with `php -r "echo password_hash('some password here', PASSWORD_DEFAULT);"` @@ -47,16 +44,16 @@ in }; database = { - username = mkOption { - type = types.str; + username = lib.mkOption { + type = lib.types.str; default = "postfixadmin"; description = '' Username for the postgresql connection. If `database.host` is set to `localhost`, a unix user and group of the same name will be created as well. ''; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' Host of the postgresql server. If this is not set to @@ -65,25 +62,25 @@ in permissions. ''; }; - passwordFile = mkOption { - type = types.path; + passwordFile = lib.mkOption { + type = lib.types.path; description = "Password file for the postgresql connection. Must be readable by user `nginx`."; }; - dbname = mkOption { - type = types.str; + dbname = lib.mkOption { + type = lib.types.str; default = "postfixadmin"; description = "Name of the postgresql database"; }; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra configuration for the postfixadmin instance, see postfixadmin's config.inc.php for available options."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.etc."postfixadmin/config.local.php".text = '' > ${dataDir}/etc/sympa.conf cat ${cfg.database.passwordFile} >> ${dataDir}/etc/sympa.conf ''} - ${optionalString (cfg.mta.type == "postfix") '' + ${lib.optionalString (cfg.mta.type == "postfix") '' ${pkgs.postfix}/bin/postmap hash:${dataDir}/virtual.sympa ${pkgs.postfix}/bin/postmap hash:${dataDir}/transport.sympa ''} @@ -478,7 +475,7 @@ in serviceConfig = sympaServiceConfig "task_manager"; }; - systemd.services.wwsympa = mkIf usingNginx { + systemd.services.wwsympa = lib.mkIf usingNginx { wantedBy = [ "multi-user.target" ]; after = [ "sympa.service" ]; serviceConfig = { @@ -499,14 +496,14 @@ in } // commonServiceConfig; }; - services.nginx.enable = mkIf usingNginx true; - services.nginx.virtualHosts = mkIf usingNginx (let - vHosts = unique (remove null (mapAttrsToList (_k: v: v.webHost) cfg.domains)); - hostLocations = host: map (v: v.webLocation) (filter (v: v.webHost == host) (attrValues cfg.domains)); - httpsOpts = optionalAttrs cfg.web.https { forceSSL = mkDefault true; enableACME = mkDefault true; }; + services.nginx.enable = lib.mkIf usingNginx true; + services.nginx.virtualHosts = lib.mkIf usingNginx (let + vHosts = lib.unique (lib.remove null (lib.mapAttrsToList (_k: v: v.webHost) cfg.domains)); + hostLocations = host: map (v: v.webLocation) (lib.filter (v: v.webHost == host) (lib.attrValues cfg.domains)); + httpsOpts = lib.optionalAttrs cfg.web.https { forceSSL = lib.mkDefault true; enableACME = lib.mkDefault true; }; in - genAttrs vHosts (host: { - locations = genAttrs (hostLocations host) (loc: { + lib.genAttrs vHosts (host: { + locations = lib.genAttrs (hostLocations host) (loc: { extraConfig = '' include ${config.services.nginx.package}/conf/fastcgi_params; @@ -517,7 +514,7 @@ in }; } // httpsOpts)); - services.postfix = mkIf (cfg.mta.type == "postfix") { + services.postfix = lib.mkIf (cfg.mta.type == "postfix") { enable = true; recipientDelimiter = "+"; config = { @@ -561,9 +558,9 @@ in }; }; - services.mysql = optionalAttrs mysqlLocal { + services.mysql = lib.optionalAttrs mysqlLocal { enable = true; - package = mkDefault pkgs.mariadb; + package = lib.mkDefault pkgs.mariadb; ensureDatabases = [ cfg.database.name ]; ensureUsers = [ { name = cfg.database.user; @@ -572,7 +569,7 @@ in ]; }; - services.postgresql = optionalAttrs pgsqlLocal { + services.postgresql = lib.optionalAttrs pgsqlLocal { enable = true; ensureDatabases = [ cfg.database.name ]; ensureUsers = [ @@ -584,5 +581,5 @@ in }; - meta.maintainers = with maintainers; [ mmilata sorki ]; + meta.maintainers = with lib.maintainers; [ mmilata sorki ]; } diff --git a/nixos/modules/services/mail/zeyple.nix b/nixos/modules/services/mail/zeyple.nix index 6f6a1799bc0a..2f9164f700fe 100644 --- a/nixos/modules/services/mail/zeyple.nix +++ b/nixos/modules/services/mail/zeyple.nix @@ -1,6 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.services.zeyple; ini = pkgs.formats.ini { }; @@ -16,10 +14,10 @@ let ''; in { options.services.zeyple = { - enable = mkEnableOption "Zeyple, an utility program to automatically encrypt outgoing emails with GPG"; + enable = lib.mkEnableOption "Zeyple, an utility program to automatically encrypt outgoing emails with GPG"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "zeyple"; description = '' User to run Zeyple as. @@ -32,8 +30,8 @@ in { ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "zeyple"; description = '' Group to use to run Zeyple. @@ -46,7 +44,7 @@ in { ''; }; - settings = mkOption { + settings = lib.mkOption { type = ini.type; default = { }; description = '' @@ -56,21 +54,21 @@ in { ''; }; - keys = mkOption { - type = with types; listOf path; + keys = lib.mkOption { + type = with lib.types; listOf path; description = "List of public key files that will be imported by gpg."; }; - rotateLogs = mkOption { - type = types.bool; + rotateLogs = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to enable rotation of log files."; }; }; - config = mkIf cfg.enable { - users.groups = optionalAttrs (cfg.group == "zeyple") { "${cfg.group}" = { }; }; - users.users = optionalAttrs (cfg.user == "zeyple") { + config = lib.mkIf cfg.enable { + users.groups = lib.optionalAttrs (cfg.group == "zeyple") { "${cfg.group}" = { }; }; + users.users = lib.optionalAttrs (cfg.user == "zeyple") { "${cfg.user}" = { isSystemUser = true; group = cfg.group; @@ -78,14 +76,14 @@ in { }; services.zeyple.settings = { - zeyple = mapAttrs (name: mkDefault) { + zeyple = lib.mapAttrs (name: lib.mkDefault) { log_file = "/var/log/zeyple/zeyple.log"; force_encrypt = true; }; - gpg = mapAttrs (name: mkDefault) { home = "${gpgHome}"; }; + gpg = lib.mapAttrs (name: lib.mkDefault) { home = "${gpgHome}"; }; - relay = mapAttrs (name: mkDefault) { + relay = lib.mapAttrs (name: lib.mkDefault) { host = "localhost"; port = 10026; }; @@ -98,7 +96,7 @@ in { mode = "0600"; }; - services.logrotate = mkIf cfg.rotateLogs { + services.logrotate = lib.mkIf cfg.rotateLogs { enable = true; settings.zeyple = { files = cfg.settings.zeyple.log_file; diff --git a/nixos/modules/services/matrix/appservice-discord.nix b/nixos/modules/services/matrix/appservice-discord.nix index 7f3a1ed3e20a..cbe265d35944 100644 --- a/nixos/modules/services/matrix/appservice-discord.nix +++ b/nixos/modules/services/matrix/appservice-discord.nix @@ -1,7 +1,4 @@ { config, options, pkgs, lib, ... }: - -with lib; - let dataDir = "/var/lib/matrix-appservice-discord"; registrationFile = "${dataDir}/discord-registration.yaml"; @@ -13,14 +10,14 @@ let in { options = { services.matrix-appservice-discord = { - enable = mkEnableOption "a bridge between Matrix and Discord"; + enable = lib.mkEnableOption "a bridge between Matrix and Discord"; - package = mkPackageOption pkgs "matrix-appservice-discord" { }; + package = lib.mkPackageOption pkgs "matrix-appservice-discord" { }; - settings = mkOption rec { - # TODO: switch to types.config.json as prescribed by RFC42 once it's implemented - type = types.attrs; - apply = recursiveUpdate default; + settings = lib.mkOption rec { + # TODO: switch to lib.types.config.json as prescribed by RFC42 once it's implemented + type = lib.types.attrs; + apply = lib.recursiveUpdate default; default = { database = { filename = "${dataDir}/discord.db"; @@ -33,7 +30,7 @@ in { botToken = ""; }; }; - example = literalExpression '' + example = lib.literalExpression '' { bridge = { domain = "public-domain.tld"; @@ -55,8 +52,8 @@ in { ''; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File containing environment variables to be passed to the matrix-appservice-discord service, @@ -66,36 +63,36 @@ in { ''; }; - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; default = "http://localhost:${toString cfg.port}"; - defaultText = literalExpression ''"http://localhost:''${toString config.${opt.port}}"''; + defaultText = lib.literalExpression ''"http://localhost:''${toString config.${opt.port}}"''; description = '' The URL where the application service is listening for HS requests. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 9005; # from https://github.com/Half-Shot/matrix-appservice-discord/blob/master/package.json#L11 description = '' Port number on which the bridge should listen for internal communication with the Matrix homeserver. ''; }; - localpart = mkOption { - type = with types; nullOr str; + localpart = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' The user_id localpart to assign to the AS. ''; }; - serviceDependencies = mkOption { - type = with types; listOf str; - default = optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; - defaultText = literalExpression '' - optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit + serviceDependencies = lib.mkOption { + type = with lib.types; listOf str; + default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + defaultText = lib.literalExpression '' + lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ''; description = '' List of Systemd services to require and wait for when starting the application service, @@ -105,7 +102,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.matrix-appservice-discord = { description = "A bridge between Matrix and Discord."; @@ -117,8 +114,8 @@ in { if [ ! -f '${registrationFile}' ]; then ${cfg.package}/bin/matrix-appservice-discord \ --generate-registration \ - --url=${escapeShellArg cfg.url} \ - ${optionalString (cfg.localpart != null) "--localpart=${escapeShellArg cfg.localpart}"} \ + --url=${lib.escapeShellArg cfg.url} \ + ${lib.optionalString (cfg.localpart != null) "--localpart=${lib.escapeShellArg cfg.localpart}"} \ --config='${settingsFile}' \ --file='${registrationFile}' fi @@ -151,5 +148,5 @@ in { }; }; - meta.maintainers = with maintainers; [ pacien ]; + meta.maintainers = with lib.maintainers; [ pacien ]; } diff --git a/nixos/modules/services/matrix/appservice-irc.nix b/nixos/modules/services/matrix/appservice-irc.nix index f4539a90f2e6..ac8d4250b9ac 100644 --- a/nixos/modules/services/matrix/appservice-irc.nix +++ b/nixos/modules/services/matrix/appservice-irc.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.matrix-appservice-irc; @@ -25,29 +22,29 @@ let ''; registrationFile = "/var/lib/matrix-appservice-irc/registration.yml"; in { - options.services.matrix-appservice-irc = with types; { - enable = mkEnableOption "the Matrix/IRC bridge"; + options.services.matrix-appservice-irc = with lib.types; { + enable = lib.mkEnableOption "the Matrix/IRC bridge"; - port = mkOption { + port = lib.mkOption { type = port; description = "The port to listen on"; default = 8009; }; - needBindingCap = mkOption { + needBindingCap = lib.mkOption { type = bool; description = "Whether the daemon needs to bind to ports below 1024 (e.g. for the ident service)"; default = false; }; - passwordEncryptionKeyLength = mkOption { + passwordEncryptionKeyLength = lib.mkOption { type = ints.unsigned; description = "Length of the key to encrypt IRC passwords with"; default = 4096; example = 8192; }; - registrationUrl = mkOption { + registrationUrl = lib.mkOption { type = str; description = '' The URL where the application service is listening for homeserver requests, @@ -56,13 +53,13 @@ in { example = "http://localhost:8009"; }; - localpart = mkOption { + localpart = lib.mkOption { type = str; description = "The user_id localpart to assign to the appservice"; default = "appservice-irc"; }; - settings = mkOption { + settings = lib.mkOption { description = '' Configuration for the appservice, see @@ -73,19 +70,19 @@ in { freeformType = jsonType; options = { - homeserver = mkOption { + homeserver = lib.mkOption { description = "Homeserver configuration"; default = {}; type = submodule { freeformType = jsonType; options = { - url = mkOption { + url = lib.mkOption { type = str; description = "The URL to the home server for client-server API calls"; }; - domain = mkOption { + domain = lib.mkOption { type = str; description = '' The 'domain' part for user IDs on this home server. Usually @@ -96,21 +93,21 @@ in { }; }; - database = mkOption { + database = lib.mkOption { default = {}; description = "Configuration for the database"; type = submodule { freeformType = jsonType; options = { - engine = mkOption { + engine = lib.mkOption { type = str; description = "Which database engine to use"; default = "nedb"; example = "postgres"; }; - connectionString = mkOption { + connectionString = lib.mkOption { type = str; description = "The database connection string"; default = "nedb://var/lib/matrix-appservice-irc/data"; @@ -120,14 +117,14 @@ in { }; }; - ircService = mkOption { + ircService = lib.mkOption { default = {}; description = "IRC bridge configuration"; type = submodule { freeformType = jsonType; options = { - passwordEncryptionKeyPath = mkOption { + passwordEncryptionKeyPath = lib.mkOption { type = str; description = '' Location of the key with which IRC passwords are encrypted @@ -136,10 +133,44 @@ in { default = "/var/lib/matrix-appservice-irc/passkey.pem"; }; - servers = mkOption { + servers = lib.mkOption { type = submodule { freeformType = jsonType; }; description = "IRC servers to connect to"; }; + + mediaProxy = { + signingKeyPath = lib.mkOption { + type = path; + default = "/var/lib/matrix-appservice-irc/media-signingkey.jwk"; + description = '' + Path to the signing key file for authenticated media. + ''; + }; + ttlSeconds = lib.mkOption { + type = ints.unsigned; + default = 3600; + example = 0; + description = '' + Lifetime in seconds, that generated URLs stay valid. + + Set the lifetime to 0 to prevent URLs from becoming invalid. + ''; + }; + bindPort = lib.mkOption { + type = port; + default = 11111; + description = '' + Port that the media proxy binds to. + ''; + }; + publicUrl = lib.mkOption { + type = str; + example = "https://matrix.example.com/media"; + description = '' + URL under which the media proxy is publicly acccessible. + ''; + }; + }; }; }; }; @@ -147,7 +178,8 @@ in { }; }; }; - config = mkIf cfg.enable { + + config = lib.mkIf cfg.enable { systemd.services.matrix-appservice-irc = { description = "Matrix-IRC bridge"; before = [ "matrix-synapse.service" ]; # So the registration can be used by Synapse @@ -184,6 +216,9 @@ in { sed -i "s/^hs_token:.*$/$hs_token/g" ${registrationFile} sed -i "s/^as_token:.*$/$as_token/g" ${registrationFile} fi + if ! [ -f "${cfg.settings.ircService.mediaProxy.signingKeyPath}"]; then + ${lib.getExe pkgs.nodejs} ${pkg}/lib/generate-signing-key.js > "${cfg.settings.ircService.mediaProxy.signingKeyPath}" + fi # Allow synapse access to the registration if ${pkgs.getent}/bin/getent group matrix-synapse > /dev/null; then chgrp matrix-synapse ${registrationFile} @@ -206,7 +241,7 @@ in { User = "matrix-appservice-irc"; Group = "matrix-appservice-irc"; - CapabilityBoundingSet = [ "CAP_CHOWN" ] ++ optional (cfg.needBindingCap) "CAP_NET_BIND_SERVICE"; + CapabilityBoundingSet = [ "CAP_CHOWN" ] ++ lib.optional (cfg.needBindingCap) "CAP_NET_BIND_SERVICE"; AmbientCapabilities = CapabilityBoundingSet; NoNewPrivileges = true; diff --git a/nixos/modules/services/matrix/conduit.nix b/nixos/modules/services/matrix/conduit.nix index b1d9b0424295..c484f67327d8 100644 --- a/nixos/modules/services/matrix/conduit.nix +++ b/nixos/modules/services/matrix/conduit.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.matrix-conduit; @@ -9,67 +6,67 @@ let configFile = format.generate "conduit.toml" cfg.settings; in { - meta.maintainers = with maintainers; [ pstn ]; + meta.maintainers = with lib.maintainers; [ pstn ]; options.services.matrix-conduit = { - enable = mkEnableOption "matrix-conduit"; + enable = lib.mkEnableOption "matrix-conduit"; - extraEnvironment = mkOption { - type = types.attrsOf types.str; + extraEnvironment = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = "Extra Environment variables to pass to the conduit server."; default = {}; example = { RUST_BACKTRACE="yes"; }; }; - package = mkPackageOption pkgs "matrix-conduit" { }; + package = lib.mkPackageOption pkgs "matrix-conduit" { }; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = format.type; options = { - global.server_name = mkOption { - type = types.str; + global.server_name = lib.mkOption { + type = lib.types.str; example = "example.com"; description = "The server_name is the name of this server. It is used as a suffix for user # and room ids."; }; - global.port = mkOption { - type = types.port; + global.port = lib.mkOption { + type = lib.types.port; default = 6167; description = "The port Conduit will be running on. You need to set up a reverse proxy in your web server (e.g. apache or nginx), so all requests to /_matrix on port 443 and 8448 will be forwarded to the Conduit instance running on this port"; }; - global.max_request_size = mkOption { - type = types.ints.positive; + global.max_request_size = lib.mkOption { + type = lib.types.ints.positive; default = 20000000; description = "Max request size in bytes. Don't forget to also change it in the proxy."; }; - global.allow_registration = mkOption { - type = types.bool; + global.allow_registration = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether new users can register on this server."; }; - global.allow_encryption = mkOption { - type = types.bool; + global.allow_encryption = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether new encrypted rooms can be created. Note: existing rooms will continue to work."; }; - global.allow_federation = mkOption { - type = types.bool; + global.allow_federation = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether this server federates with other servers. ''; }; - global.trusted_servers = mkOption { - type = types.listOf types.str; + global.trusted_servers = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "matrix.org" ]; description = "Servers trusted with signing server keys."; }; - global.address = mkOption { - type = types.str; + global.address = lib.mkOption { + type = lib.types.str; default = "::1"; description = "Address to listen on for connections by the reverse proxy/tls terminator."; }; - global.database_path = mkOption { - type = types.str; + global.database_path = lib.mkOption { + type = lib.types.str; default = "/var/lib/matrix-conduit/"; readOnly = true; description = '' @@ -78,8 +75,8 @@ in and is set to be read only. ''; }; - global.database_backend = mkOption { - type = types.enum [ "sqlite" "rocksdb" ]; + global.database_backend = lib.mkOption { + type = lib.types.enum [ "sqlite" "rocksdb" ]; default = "sqlite"; example = "rocksdb"; description = '' @@ -87,8 +84,8 @@ in instance will require manual migration of data. ''; }; - global.allow_check_for_updates = mkOption { - type = types.bool; + global.allow_check_for_updates = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to allow Conduit to automatically contact @@ -109,7 +106,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.conduit = { description = "Conduit Matrix Server"; documentation = [ "https://gitlab.com/famedly/conduit/" ]; diff --git a/nixos/modules/services/matrix/dendrite.nix b/nixos/modules/services/matrix/dendrite.nix index 5152dfadf2e5..fdd91d776254 100644 --- a/nixos/modules/services/matrix/dendrite.nix +++ b/nixos/modules/services/matrix/dendrite.nix @@ -258,7 +258,7 @@ in default = { }; description = '' Configuration for dendrite, see: - + for available options with which to populate settings. ''; }; diff --git a/nixos/modules/services/matrix/hookshot.nix b/nixos/modules/services/matrix/hookshot.nix new file mode 100644 index 000000000000..d6329e91459e --- /dev/null +++ b/nixos/modules/services/matrix/hookshot.nix @@ -0,0 +1,127 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.matrix-hookshot; + settingsFormat = pkgs.formats.yaml { }; + configFile = settingsFormat.generate "matrix-hookshot-config.yml" cfg.settings; +in +{ + options = { + services.matrix-hookshot = { + enable = lib.mkEnableOption "matrix-hookshot, a bridge between Matrix and project management services"; + + package = lib.mkPackageOption pkgs "matrix-hookshot" { }; + + registrationFile = lib.mkOption { + type = lib.types.path; + description = '' + Appservice registration file. + As it contains secret tokens, you may not want to add this to the publicly readable Nix store. + ''; + example = lib.literalExpression '' + pkgs.writeText "matrix-hookshot-registration" \'\' + id: matrix-hookshot + as_token: aaaaaaaaaa + hs_token: aaaaaaaaaa + namespaces: + rooms: [] + users: + - regex: "@_webhooks_.*:foobar" + exclusive: true + + sender_localpart: hookshot + url: "http://localhost:9993" + rate_limited: false + \'\' + ''; + }; + + settings = lib.mkOption { + description = '' + {file}`config.yml` configuration as a Nix attribute set. + + For details please see the [documentation](https://matrix-org.github.io/matrix-hookshot/latest/setup/sample-configuration.html). + ''; + example = { + bridge = { + domain = "example.com"; + url = "http://localhost:8008"; + mediaUrl = "https://example.com"; + port = 9993; + bindAddress = "127.0.0.1"; + }; + listeners = [ + { + port = 9000; + bindAddress = "0.0.0.0"; + resources = [ "webhooks" ]; + } + { + port = 9001; + bindAddress = "localhost"; + resources = [ + "metrics" + "provisioning" + ]; + } + ]; + }; + default = { }; + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + passFile = lib.mkOption { + type = lib.types.path; + default = "/var/lib/matrix-hookshot/passkey.pem"; + description = '' + A passkey used to encrypt tokens stored inside the bridge. + File will be generated if not found. + ''; + }; + }; + }; + }; + + serviceDependencies = lib.mkOption { + type = with lib.types; listOf str; + default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + defaultText = lib.literalExpression '' + lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit + ''; + description = '' + List of Systemd services to require and wait for when starting the application service, + such as the Matrix homeserver if it's running on the same host. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.matrix-hookshot = { + description = "a bridge between Matrix and multiple project management services"; + + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ] ++ cfg.serviceDependencies; + after = [ "network-online.target" ] ++ cfg.serviceDependencies; + + preStart = '' + if [ ! -f '${cfg.settings.passFile}' ]; then + mkdir -p $(dirname '${cfg.settings.passFile}') + ${pkgs.openssl}/bin/openssl genpkey -out '${cfg.settings.passFile}' -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:4096 + fi + ''; + + serviceConfig = { + Type = "simple"; + Restart = "always"; + ExecStart = "${cfg.package}/bin/matrix-hookshot ${configFile} ${cfg.registrationFile}"; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ flandweber ]; +} diff --git a/nixos/modules/services/matrix/mautrix-facebook.nix b/nixos/modules/services/matrix/mautrix-facebook.nix index 4d5217ee4367..0e81b390732a 100644 --- a/nixos/modules/services/matrix/mautrix-facebook.nix +++ b/nixos/modules/services/matrix/mautrix-facebook.nix @@ -1,26 +1,23 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.mautrix-facebook; settingsFormat = pkgs.formats.json {}; settingsFile = settingsFormat.generate "mautrix-facebook-config.json" cfg.settings; - puppetRegex = concatStringsSep + puppetRegex = lib.concatStringsSep ".*" (map - escapeRegex - (splitString + lib.escapeRegex + (lib.splitString "{userid}" cfg.settings.bridge.username_template)); in { options = { services.mautrix-facebook = { - enable = mkEnableOption "Mautrix-Facebook, a Matrix-Facebook hybrid puppeting/relaybot bridge"; + enable = lib.mkEnableOption "Mautrix-Facebook, a Matrix-Facebook hybrid puppeting/relaybot bridge"; - settings = mkOption rec { - apply = recursiveUpdate default; + settings = lib.mkOption rec { + apply = lib.recursiveUpdate default; type = settingsFormat.type; default = { homeserver = { @@ -70,7 +67,7 @@ in { }; }; }; - example = literalExpression '' + example = lib.literalExpression '' { homeserver = { address = "http://localhost:8008"; @@ -93,8 +90,8 @@ in { ''; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File containing environment variables to be passed to the mautrix-facebook service. @@ -103,16 +100,16 @@ in { ''; }; - configurePostgresql = mkOption { - type = types.bool; + configurePostgresql = lib.mkOption { + type = lib.types.bool; default = true; description = '' Enable PostgreSQL and create a user and database for mautrix-facebook. The default `settings` reference this database, if you disable this option you must provide a database URL. ''; }; - registrationData = mkOption { - type = types.attrs; + registrationData = lib.mkOption { + type = lib.types.attrs; default = {}; description = '' Output data for appservice registration. Simply make any desired changes and serialize to JSON. Note that this data contains secrets so think twice before putting it into the nix store. @@ -123,7 +120,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.groups.mautrix-facebook = {}; users.users.mautrix-facebook = { @@ -131,7 +128,7 @@ in { isSystemUser = true; }; - services.postgresql = mkIf cfg.configurePostgresql { + services.postgresql = lib.mkIf cfg.configurePostgresql { ensureDatabases = ["mautrix-facebook"]; ensureUsers = [{ name = "mautrix-facebook"; @@ -143,8 +140,8 @@ in { wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" - ] ++ optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit - ++ optional cfg.configurePostgresql "postgresql.service"; + ] ++ lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit + ++ lib.optional cfg.configurePostgresql "postgresql.service"; after = wants; serviceConfig = { @@ -176,11 +173,11 @@ in { users = [ { exclusive = true; - regex = escapeRegex "@${cfg.settings.appservice.bot_username}:${cfg.settings.homeserver.domain}"; + regex = lib.escapeRegex "@${cfg.settings.appservice.bot_username}:${cfg.settings.homeserver.domain}"; } { exclusive = true; - regex = "@${puppetRegex}:${escapeRegex cfg.settings.homeserver.domain}"; + regex = "@${puppetRegex}:${lib.escapeRegex cfg.settings.homeserver.domain}"; } ]; aliases = []; @@ -196,5 +193,5 @@ in { }; }; - meta.maintainers = with maintainers; [ kevincox ]; + meta.maintainers = with lib.maintainers; [ kevincox ]; } diff --git a/nixos/modules/services/matrix/mautrix-meta.nix b/nixos/modules/services/matrix/mautrix-meta.nix index f0905c3af129..79f7239df9e5 100644 --- a/nixos/modules/services/matrix/mautrix-meta.nix +++ b/nixos/modules/services/matrix/mautrix-meta.nix @@ -69,11 +69,6 @@ in { appservice = { id = ""; - database = { - type = "sqlite3-fk-wal"; - uri = "file:${fullDataDir config}/mautrix-meta.db?_txlock=immediate"; - }; - bot = { username = ""; }; @@ -83,37 +78,43 @@ in { address = "http://${config.settings.appservice.hostname}:${toString config.settings.appservice.port}"; }; - meta = { - mode = ""; + bridge = { + permissions = {}; }; - bridge = { - # Enable encryption by default to make the bridge more secure - encryption = { - allow = true; - default = true; - require = true; + database = { + type = "sqlite3-fk-wal"; + uri = "file:${fullDataDir config}/mautrix-meta.db?_txlock=immediate"; + }; - # Recommended options from mautrix documentation - # for additional security. - delete_keys = { - dont_store_outbound = true; - ratchet_on_decrypt = true; - delete_fully_used_on_decrypt = true; - delete_prev_on_new_session = true; - delete_on_device_delete = true; - periodically_delete_expired = true; - delete_outdated_inbound = true; - }; + # Enable encryption by default to make the bridge more secure + encryption = { + allow = true; + default = true; + require = true; - verification_levels = { - receive = "cross-signed-tofu"; - send = "cross-signed-tofu"; - share = "cross-signed-tofu"; - }; + # Recommended options from mautrix documentation + # for additional security. + delete_keys = { + dont_store_outbound = true; + ratchet_on_decrypt = true; + delete_fully_used_on_decrypt = true; + delete_prev_on_new_session = true; + delete_on_device_delete = true; + periodically_delete_expired = true; + delete_outdated_inbound = true; }; - permissions = {}; + # TODO: This effectively disables encryption. But this is the value provided when a <0.4 config is migrated. Changing it will corrupt the database. + # https://github.com/mautrix/meta/blob/f5440b05aac125b4c95b1af85635a717cbc6dd0e/cmd/mautrix-meta/legacymigrate.go#L24 + # If you wish to encrypt the local database you should set this to an environment variable substitution and reset the bridge or somehow migrate the DB. + pickle_key = "mautrix.bridge.e2ee"; + + verification_levels = { + receive = "cross-signed-tofu"; + send = "cross-signed-tofu"; + share = "cross-signed-tofu"; + }; }; logging = { @@ -124,6 +125,10 @@ in { time_format = " "; }; }; + + network = { + mode = ""; + }; }; defaultText = '' { @@ -261,7 +266,7 @@ in { description = '' Configuration of multiple `mautrix-meta` instances. `services.mautrix-meta.instances.facebook` and `services.mautrix-meta.instances.instagram` - come preconfigured with meta.mode, appservice.id, bot username, display name and avatar. + come preconfigured with network.mode, appservice.id, bot username, display name and avatar. ''; example = '' @@ -283,7 +288,7 @@ in { messenger = { enable = true; settings = { - meta.mode = "messenger"; + network.mode = "messenger"; homeserver.domain = "example.com"; appservice = { id = "messenger"; @@ -313,9 +318,9 @@ in { ''; } { - assertion = builtins.elem cfg.settings.meta.mode [ "facebook" "facebook-tor" "messenger" "instagram" ]; + assertion = builtins.elem cfg.settings.network.mode [ "facebook" "facebook-tor" "messenger" "instagram" ]; message = '' - The option `services.mautrix-meta.instances.${name}.settings.meta.mode` has to be set + The option `services.mautrix-meta.instances.${name}.settings.network.mode` has to be set to one of: facebook, facebook-tor, messenger, instagram. This configures the mode of the bridge. ''; @@ -338,6 +343,24 @@ in { The option `services.mautrix-meta.instances.${name}.settings.appservice.bot.username` has to be set. ''; } + { + assertion = !(cfg.settings ? bridge.disable_xma); + message = '' + The option `bridge.disable_xma` has been moved to `network.disable_xma_always`. Please [migrate your configuration](https://github.com/mautrix/meta/releases/tag/v0.4.0). You may wish to use [the auto-migration code](https://github.com/mautrix/meta/blob/f5440b05aac125b4c95b1af85635a717cbc6dd0e/cmd/mautrix-meta/legacymigrate.go#L23) for reference. + ''; + } + { + assertion = !(cfg.settings ? bridge.displayname_template); + message = '' + The option `bridge.displayname_template` has been moved to `network.displayname_template`. Please [migrate your configuration](https://github.com/mautrix/meta/releases/tag/v0.4.0). You may wish to use [the auto-migration code](https://github.com/mautrix/meta/blob/f5440b05aac125b4c95b1af85635a717cbc6dd0e/cmd/mautrix-meta/legacymigrate.go#L23) for reference. + ''; + } + { + assertion = !(cfg.settings ? meta); + message = '' + The options in `meta` have been moved to `network`. Please [migrate your configuration](https://github.com/mautrix/meta/releases/tag/v0.4.0). You may wish to use [the auto-migration code](https://github.com/mautrix/meta/blob/f5440b05aac125b4c95b1af85635a717cbc6dd0e/cmd/mautrix-meta/legacymigrate.go#L23) for reference. + ''; + } ]) enabledInstances)); users.users = lib.mapAttrs' (name: cfg: lib.nameValuePair "mautrix-meta-${name}" { @@ -518,11 +541,7 @@ in { in { instagram = { settings = { - meta.mode = mkDefault "instagram"; - - bridge = { - username_template = mkDefault "instagram_{{.}}"; - }; + network.mode = mkDefault "instagram"; appservice = { id = mkDefault "instagram"; @@ -532,16 +551,13 @@ in { displayname = mkDefault "Instagram bridge bot"; avatar = mkDefault "mxc://maunium.net/JxjlbZUlCPULEeHZSwleUXQv"; }; + username_template = mkDefault "instagram_{{.}}"; }; }; }; facebook = { settings = { - meta.mode = mkDefault "facebook"; - - bridge = { - username_template = mkDefault "facebook_{{.}}"; - }; + network.mode = mkDefault "facebook"; appservice = { id = mkDefault "facebook"; @@ -551,6 +567,7 @@ in { displayname = mkDefault "Facebook bridge bot"; avatar = mkDefault "mxc://maunium.net/ygtkteZsXnGJLJHRchUwYWak"; }; + username_template = mkDefault "facebook_{{.}}"; }; }; }; @@ -558,5 +575,5 @@ in { } ]; - meta.maintainers = with lib.maintainers; [ rutherther ]; + meta.maintainers = with lib.maintainers; [ ]; } diff --git a/nixos/modules/services/matrix/mautrix-signal.md b/nixos/modules/services/matrix/mautrix-signal.md new file mode 100644 index 000000000000..da65964e1504 --- /dev/null +++ b/nixos/modules/services/matrix/mautrix-signal.md @@ -0,0 +1,32 @@ +# Mautrix-Signal {#module-services-mautrix-signal} + +[Mautrix-Signal](https://github.com/mautrix/signal) is a Matrix-Signal puppeting bridge. + +## Configuration {#module-services-mautrix-signal-configuration} + +1. Set [](#opt-services.mautrix-signal.enable) to `true`. The service will use + SQLite by default. +2. To create your configuration check the default configuration for + [](#opt-services.mautrix-signal.settings). To obtain the complete default + configuration, run + `nix-shell -p mautrix-signal --run "mautrix-signal -c default.yaml -e"`. + +::: {.warning} +Mautrix-Signal allows for some options like `encryption.pickle_key`, +`provisioning.shared_secret`, allow the value `generate` to be set. +Since the configuration file is regenerated on every start of the +service, the generated values would be discarded and might break your +installation. Instead, set those values via +[](#opt-services.mautrix-signal.environmentFile). +::: + +## Migrating from an older configuration {#module-services-mautrix-signal-migrate-configuration} + +With Mautrix-Signal v0.7.0 the configuration has been rearranged. Mautrix-Signal +performs an automatic configuration migration so your pre-0.7.0 configuration +should just continue to work. + +In case you want to update your NixOS configuration, compare the migrated configuration +at `/var/lib/mautrix-signal/config.yaml` with the default configuration +(`nix-shell -p mautrix-signal --run "mautrix-signal -c example.yaml -e"`) and +update your module configuration accordingly. diff --git a/nixos/modules/services/matrix/mautrix-signal.nix b/nixos/modules/services/matrix/mautrix-signal.nix index 0da95b9c8a7b..b4a838612633 100644 --- a/nixos/modules/services/matrix/mautrix-signal.nix +++ b/nixos/modules/services/matrix/mautrix-signal.nix @@ -1,7 +1,8 @@ -{ lib -, config -, pkgs -, ... +{ + lib, + config, + pkgs, + ... }: let cfg = config.services.mautrix-signal; @@ -16,12 +17,22 @@ let optOneOf = lib.lists.findFirst (value: value.condition) (lib.mkIf false null); mkDefaults = lib.mapAttrsRecursive (n: v: lib.mkDefault v); defaultConfig = { + network = { + displayname_template = "{{or .ProfileName .PhoneNumber \"Unknown user\"}}"; + }; + bridge = { + command_prefix = "!signal"; + relay.enabled = true; + permissions."*" = "relay"; + }; + database = { + type = "sqlite3"; + uri = "file:${dataDir}/mautrix-signal.db?_txlock=immediate"; + }; homeserver.address = "http://localhost:8448"; appservice = { hostname = "[::]"; port = appservicePort; - database.type = "sqlite3"; - database.uri = "file:${dataDir}/mautrix-signal.db?_txlock=immediate"; id = "signal"; bot = { username = "signalbot"; @@ -29,16 +40,19 @@ let }; as_token = ""; hs_token = ""; - }; - bridge = { username_template = "signal_{{.}}"; - displayname_template = "{{or .ProfileName .PhoneNumber \"Unknown user\"}}"; - double_puppet_server_map = { }; - login_shared_secret_map = { }; - command_prefix = "!signal"; - permissions."*" = "relay"; - relay.enabled = true; }; + double_puppet = { + servers = { }; + secrets = { }; + }; + # By default, the following keys/secrets are set to `generate`. This would break when the service + # is restarted, since the previously generated configuration will be overwritten everytime. + # If encryption is enabled, it's recommended to set those keys via `environmentFile`. + encryption.pickle_key = ""; + provisioning.shared_secret = ""; + public_media.signing_key = ""; + direct_media.server_key = ""; logging = { min_level = "info"; writers = lib.singleton { @@ -60,38 +74,42 @@ in default = defaultConfig; description = '' {file}`config.yaml` configuration as a Nix attribute set. - Configuration options should match those described in - [example-config.yaml](https://github.com/mautrix/signal/blob/master/example-config.yaml). + Configuration options should match those described in the example configuration. + Get an example configuration by executing `mautrix-signal -c example.yaml --generate-example-config` Secret tokens should be specified using {option}`environmentFile` instead of this world-readable attribute set. ''; example = { - appservice = { - database = { - type = "postgres"; - uri = "postgresql:///mautrix_signal?host=/run/postgresql"; - }; - id = "signal"; - ephemeral_events = false; - }; bridge = { - history_sync = { - request_full_sync = true; - }; private_chat_portal_meta = true; - mute_bridging = true; - encryption = { - allow = true; - default = true; - require = true; - }; - provisioning = { - shared_secret = "disable"; - }; + mute_only_on_create = false; permissions = { "example.com" = "user"; }; }; + database = { + type = "postgres"; + uri = "postgresql:///mautrix_signal?host=/run/postgresql"; + }; + homeserver = { + address = "http://[::1]:8008"; + domain = "my-domain.tld"; + }; + appservice = { + id = "signal"; + ephemeral_events = false; + }; + matrix.message_status_events = true; + provisioning = { + shared_secret = "disable"; + }; + backfill.enabled = true; + encryption = { + allow = true; + default = true; + require = true; + pickle_key = "$ENCRYPTION_PICKLE_KEY"; + }; }; }; @@ -102,16 +120,15 @@ in File containing environment variables to be passed to the mautrix-signal service. If an environment variable `MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET` is set, then its value will be used in the configuration file for the option - `login_shared_secret_map` without leaking it to the store, using the configured + `double_puppet.secrets` without leaking it to the store, using the configured `homeserver.domain` as key. - See [here](https://github.com/mautrix/signal/blob/main/example-config.yaml) - for the documentation of `login_shared_secret_map`. ''; }; serviceDependencies = lib.mkOption { type = with lib.types; listOf str; - default = (lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit) + default = + (lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit) ++ (lib.optional config.services.matrix-conduit.enable "conduit.service"); defaultText = lib.literalExpression '' (optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit) @@ -154,15 +171,18 @@ in }; # Note: this is defined here to avoid the docs depending on `config` - services.mautrix-signal.settings.homeserver = optOneOf (with config.services; [ - (lib.mkIf matrix-synapse.enable (mkDefaults { - domain = matrix-synapse.settings.server_name; - })) - (lib.mkIf matrix-conduit.enable (mkDefaults { - domain = matrix-conduit.settings.global.server_name; - address = "http://localhost:${toString matrix-conduit.settings.global.port}"; - })) - ]); + services.mautrix-signal.settings.homeserver = optOneOf ( + with config.services; + [ + (lib.mkIf matrix-synapse.enable (mkDefaults { + domain = matrix-synapse.settings.server_name; + })) + (lib.mkIf matrix-conduit.enable (mkDefaults { + domain = matrix-conduit.settings.global.server_name; + address = "http://localhost:${toString matrix-conduit.settings.global.port}"; + })) + ] + ); systemd.services.mautrix-signal = { description = "mautrix-signal, a Matrix-Signal puppeting bridge."; @@ -201,7 +221,7 @@ in ${pkgs.yq}/bin/yq -s '.[0].appservice.as_token = .[1].as_token | .[0].appservice.hs_token = .[1].hs_token | .[0] - | if env.MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET then .bridge.login_shared_secret_map.[.homeserver.domain] = env.MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET else . end' \ + | if env.MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET then .double_puppet.secrets.[.homeserver.domain] = env.MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET else . end' \ '${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp' mv '${settingsFile}.tmp' '${settingsFile}' umask $old_umask @@ -240,10 +260,17 @@ in SystemCallErrorNumber = "EPERM"; SystemCallFilter = [ "@system-service" ]; Type = "simple"; - UMask = 0027; + UMask = 27; }; restartTriggers = [ settingsFileUnsubstituted ]; }; }; - meta.maintainers = with lib.maintainers; [ niklaskorz ]; + meta = { + buildDocsInSandbox = false; + doc = ./mautrix-signal.md; + maintainers = with lib.maintainers; [ + niklaskorz + frederictobiasc + ]; + }; } diff --git a/nixos/modules/services/matrix/mautrix-telegram.nix b/nixos/modules/services/matrix/mautrix-telegram.nix index a1ffaf9debe5..16a4046e1d3a 100644 --- a/nixos/modules/services/matrix/mautrix-telegram.nix +++ b/nixos/modules/services/matrix/mautrix-telegram.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let dataDir = "/var/lib/mautrix-telegram"; registrationFile = "${dataDir}/telegram-registration.yaml"; @@ -13,10 +10,10 @@ let in { options = { services.mautrix-telegram = { - enable = mkEnableOption "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge"; + enable = lib.mkEnableOption "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge"; - settings = mkOption rec { - apply = recursiveUpdate default; + settings = lib.mkOption rec { + apply = lib.recursiveUpdate default; inherit (settingsFormat) type; default = { homeserver = { @@ -64,7 +61,7 @@ in { }; }; }; - example = literalExpression '' + example = lib.literalExpression '' { homeserver = { address = "http://localhost:8008"; @@ -95,8 +92,8 @@ in { ''; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File containing environment variables to be passed to the mautrix-telegram service, @@ -120,11 +117,11 @@ in { ''; }; - serviceDependencies = mkOption { - type = with types; listOf str; - default = optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; - defaultText = literalExpression '' - optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit + serviceDependencies = lib.mkOption { + type = with lib.types; listOf str; + default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + defaultText = lib.literalExpression '' + lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ''; description = '' List of Systemd services to require and wait for when starting the application service. @@ -133,7 +130,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.mautrix-telegram = { description = "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge."; @@ -192,5 +189,5 @@ in { }; }; - meta.maintainers = with maintainers; [ pacien vskilet ]; + meta.maintainers = with lib.maintainers; [ pacien vskilet ]; } diff --git a/nixos/modules/services/matrix/mjolnir.nix b/nixos/modules/services/matrix/mjolnir.nix index d01c058e7396..e00dece33cab 100644 --- a/nixos/modules/services/matrix/mjolnir.nix +++ b/nixos/modules/services/matrix/mjolnir.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.mjolnir; @@ -25,8 +23,8 @@ let }; moduleConfigFile = pkgs.writeText "module-config.yaml" ( - generators.toYAML { } (filterAttrs (_: v: v != null) - (fold recursiveUpdate { } [ yamlConfig cfg.settings ]))); + lib.generators.toYAML { } (lib.filterAttrs (_: v: v != null) + (lib.fold lib.recursiveUpdate { } [ yamlConfig cfg.settings ]))); # these config files will be merged one after the other to build the final config configFiles = [ @@ -38,8 +36,8 @@ let # replace all secret strings using replace-secret generateConfig = pkgs.writeShellScript "mjolnir-generate-config" ( let - yqEvalStr = concatImapStringsSep " * " (pos: _: "select(fileIndex == ${toString (pos - 1)})") configFiles; - yqEvalArgs = concatStringsSep " " configFiles; + yqEvalStr = lib.concatImapStringsSep " * " (pos: _: "select(fileIndex == ${toString (pos - 1)})") configFiles; + yqEvalArgs = lib.concatStringsSep " " configFiles; in '' set -euo pipefail @@ -54,10 +52,10 @@ let # e.g. "eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' filea.yaml fileb.yaml" will merge filea.yaml with fileb.yaml ${pkgs.yq-go}/bin/yq eval-all -P '${yqEvalStr}' ${yqEvalArgs} > ${cfg.dataPath}/config/default.yaml - ${optionalString (cfg.accessTokenFile != null) '' + ${lib.optionalString (cfg.accessTokenFile != null) '' ${pkgs.replace-secret}/bin/replace-secret '@ACCESS_TOKEN@' '${cfg.accessTokenFile}' ${cfg.dataPath}/config/default.yaml ''} - ${optionalString (cfg.pantalaimon.passwordFile != null) '' + ${lib.optionalString (cfg.pantalaimon.passwordFile != null) '' ${pkgs.replace-secret}/bin/replace-secret '@PANTALAIMON_PASSWORD@' '${cfg.pantalaimon.passwordFile}' ${cfg.dataPath}/config/default.yaml ''} '' @@ -65,10 +63,10 @@ let in { options.services.mjolnir = { - enable = mkEnableOption "Mjolnir, a moderation tool for Matrix"; + enable = lib.mkEnableOption "Mjolnir, a moderation tool for Matrix"; - homeserverUrl = mkOption { - type = types.str; + homeserverUrl = lib.mkOption { + type = lib.types.str; default = "https://matrix.org"; description = '' Where the homeserver is located (client-server URL). @@ -78,43 +76,43 @@ in ''; }; - accessTokenFile = mkOption { - type = with types; nullOr path; + accessTokenFile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' File containing the matrix access token for the `mjolnir` user. ''; }; - pantalaimon = mkOption { + pantalaimon = lib.mkOption { description = '' `pantalaimon` options (enables E2E Encryption support). This will create a `pantalaimon` instance with the name "mjolnir". ''; default = { }; - type = types.submodule { + type = lib.types.submodule { options = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' ignoring the accessToken. If true, accessToken is ignored and the username/password below will be used instead. The access token of the bot will be stored in the dataPath ''; - username = mkOption { - type = types.str; + username = lib.mkOption { + type = lib.types.str; description = "The username to login with."; }; - passwordFile = mkOption { - type = with types; nullOr path; + passwordFile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' File containing the matrix password for the `mjolnir` user. ''; }; - options = mkOption { - type = types.submodule (import ./pantalaimon-options.nix); + options = lib.mkOption { + type = lib.types.submodule (import ./pantalaimon-options.nix); default = { }; description = '' passthrough additional options to the `pantalaimon` service. @@ -124,16 +122,16 @@ in }; }; - dataPath = mkOption { - type = types.path; + dataPath = lib.mkOption { + type = lib.types.path; default = "/var/lib/mjolnir"; description = '' The directory the bot should store various bits of information in. ''; }; - managementRoom = mkOption { - type = types.str; + managementRoom = lib.mkOption { + type = lib.types.str; default = "#moderators:example.org"; description = '' The room ID where people can use the bot. The bot has no access controls, so @@ -143,10 +141,10 @@ in ''; }; - protectedRooms = mkOption { - type = types.listOf types.str; + protectedRooms = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; - example = literalExpression '' + example = lib.literalExpression '' [ "https://matrix.to/#/#yourroom:example.org" "https://matrix.to/#/#anotherroom:example.org" @@ -157,10 +155,10 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { default = { }; type = (pkgs.formats.yaml { }).type; - example = literalExpression '' + example = lib.literalExpression '' { autojoinOnlyIfManager = true; automaticallyRedactForReasons = [ "spam" "advertising" ]; @@ -172,7 +170,7 @@ in }; }; - config = mkIf config.services.mjolnir.enable { + config = lib.mkIf config.services.mjolnir.enable { assertions = [ { assertion = !(cfg.pantalaimon.enable && cfg.pantalaimon.passwordFile == null); @@ -188,15 +186,15 @@ in } ]; - services.pantalaimon-headless.instances."mjolnir" = mkIf cfg.pantalaimon.enable + services.pantalaimon-headless.instances."mjolnir" = lib.mkIf cfg.pantalaimon.enable { homeserver = cfg.homeserverUrl; } // cfg.pantalaimon.options; systemd.services.mjolnir = { description = "mjolnir - a moderation tool for Matrix"; - wants = [ "network-online.target" ] ++ optionals (cfg.pantalaimon.enable) [ "pantalaimon-mjolnir.service" ]; - after = [ "network-online.target" ] ++ optionals (cfg.pantalaimon.enable) [ "pantalaimon-mjolnir.service" ]; + wants = [ "network-online.target" ] ++ lib.optionals (cfg.pantalaimon.enable) [ "pantalaimon-mjolnir.service" ]; + after = [ "network-online.target" ] ++ lib.optionals (cfg.pantalaimon.enable) [ "pantalaimon-mjolnir.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { @@ -216,10 +214,10 @@ in /* TODO: wait for #102397 to be resolved. Then load secrets from $CREDENTIALS_DIRECTORY+"/NAME" DynamicUser = true; LoadCredential = [] ++ - optionals (cfg.accessTokenFile != null) [ + lib.optionals (cfg.accessTokenFile != null) [ "access_token:${cfg.accessTokenFile}" ] ++ - optionals (cfg.pantalaimon.passwordFile != null) [ + lib.optionals (cfg.pantalaimon.passwordFile != null) [ "pantalaimon_password:${cfg.pantalaimon.passwordFile}" ]; */ @@ -237,6 +235,6 @@ in meta = { doc = ./mjolnir.md; - maintainers = with maintainers; [ jojosch ]; + maintainers = with lib.maintainers; [ jojosch ]; }; } diff --git a/nixos/modules/services/matrix/mx-puppet-discord.nix b/nixos/modules/services/matrix/mx-puppet-discord.nix index 2b3a46193177..c6af1e3ff022 100644 --- a/nixos/modules/services/matrix/mx-puppet-discord.nix +++ b/nixos/modules/services/matrix/mx-puppet-discord.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let dataDir = "/var/lib/mx-puppet-discord"; registrationFile = "${dataDir}/discord-registration.yaml"; @@ -12,13 +9,13 @@ let in { options = { services.mx-puppet-discord = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' mx-puppet-discord is a discord puppeting bridge for matrix. It handles bridging private and group DMs, as well as Guilds (servers) ''; - settings = mkOption rec { - apply = recursiveUpdate default; + settings = lib.mkOption rec { + apply = lib.recursiveUpdate default; inherit (settingsFormat) type; default = { bridge.port = 8434; @@ -45,7 +42,7 @@ in { lineDateFormat = "MMM-D HH:mm:ss.SSS"; }; }; - example = literalExpression '' + example = lib.literalExpression '' { bridge = { bindAddress = "localhost"; @@ -64,11 +61,11 @@ in { sample.config.yaml](https://github.com/matrix-discord/mx-puppet-discord/blob/master/sample.config.yaml). ''; }; - serviceDependencies = mkOption { - type = with types; listOf str; - default = optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; - defaultText = literalExpression '' - optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit + serviceDependencies = lib.mkOption { + type = with lib.types; listOf str; + default = lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + defaultText = lib.literalExpression '' + lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit ''; description = '' List of Systemd services to require and wait for when starting the application service. @@ -77,7 +74,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.mx-puppet-discord = { description = "Matrix to Discord puppeting bridge"; @@ -118,5 +115,5 @@ in { }; }; - meta.maintainers = with maintainers; [ govanify ]; + meta.maintainers = with lib.maintainers; [ govanify ]; } diff --git a/nixos/modules/services/matrix/pantalaimon-options.nix b/nixos/modules/services/matrix/pantalaimon-options.nix index 4243513788b5..b3a663f59931 100644 --- a/nixos/modules/services/matrix/pantalaimon-options.nix +++ b/nixos/modules/services/matrix/pantalaimon-options.nix @@ -1,26 +1,24 @@ { config, lib, name, ... }: - -with lib; { options = { - dataPath = mkOption { - type = types.path; + dataPath = lib.mkOption { + type = lib.types.path; default = "/var/lib/pantalaimon-${name}"; description = '' The directory where `pantalaimon` should store its state such as the database file. ''; }; - logLevel = mkOption { - type = types.enum [ "info" "warning" "error" "debug" ]; + logLevel = lib.mkOption { + type = lib.types.enum [ "info" "warning" "error" "debug" ]; default = "warning"; description = '' Set the log level of the daemon. ''; }; - homeserver = mkOption { - type = types.str; + homeserver = lib.mkOption { + type = lib.types.str; example = "https://matrix.org"; description = '' The URI of the homeserver that the `pantalaimon` proxy should @@ -29,8 +27,8 @@ with lib; ''; }; - ssl = mkOption { - type = types.bool; + ssl = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether or not SSL verification should be enabled for outgoing @@ -38,8 +36,8 @@ with lib; ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' The address where the daemon will listen to client connections @@ -47,18 +45,18 @@ with lib; ''; }; - listenPort = mkOption { - type = types.port; + listenPort = lib.mkOption { + type = lib.types.port; default = 8009; description = '' The port where the daemon will listen to client connections for this homeserver. Note that the listen address/port combination - needs to be unique between different homeservers. + needs to be lib.unique between different homeservers. ''; }; - extraSettings = mkOption { - type = types.attrs; + extraSettings = lib.mkOption { + type = lib.types.attrs; default = { }; description = '' Extra configuration options. See diff --git a/nixos/modules/services/matrix/pantalaimon.nix b/nixos/modules/services/matrix/pantalaimon.nix index 6f3fefdb3430..28fcdcee973f 100644 --- a/nixos/modules/services/matrix/pantalaimon.nix +++ b/nixos/modules/services/matrix/pantalaimon.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.pantalaimon-headless; @@ -12,7 +10,7 @@ let Notifications = false; }; - ${name} = (recursiveUpdate + ${name} = (lib.recursiveUpdate { Homeserver = instanceConfig.homeserver; ListenAddress = instanceConfig.listenAddress; @@ -28,7 +26,7 @@ let }; mkPantalaimonService = name: instanceConfig: - nameValuePair "pantalaimon-${name}" { + lib.nameValuePair "pantalaimon-${name}" { description = "pantalaimon instance ${name} - E2EE aware proxy daemon for matrix clients"; wants = [ "network-online.target" ]; after = [ "network-online.target" ]; @@ -48,9 +46,9 @@ let }; in { - options.services.pantalaimon-headless.instances = mkOption { + options.services.pantalaimon-headless.instances = lib.mkOption { default = { }; - type = types.attrsOf (types.submodule (import ./pantalaimon-options.nix)); + type = lib.types.attrsOf (lib.types.submodule (import ./pantalaimon-options.nix)); description = '' Declarative instance config. @@ -59,12 +57,12 @@ in ''; }; - config = mkIf (config.services.pantalaimon-headless.instances != { }) + config = lib.mkIf (config.services.pantalaimon-headless.instances != { }) { - systemd.services = mapAttrs' mkPantalaimonService config.services.pantalaimon-headless.instances; + systemd.services = lib.mapAttrs' mkPantalaimonService config.services.pantalaimon-headless.instances; }; meta = { - maintainers = with maintainers; [ jojosch ]; + maintainers = with lib.maintainers; [ jojosch ]; }; } diff --git a/nixos/modules/services/matrix/synapse.md b/nixos/modules/services/matrix/synapse.md index 0ce13550d5b2..62967adddb4b 100644 --- a/nixos/modules/services/matrix/synapse.md +++ b/nixos/modules/services/matrix/synapse.md @@ -188,7 +188,7 @@ or [OpenID](https://element-hq.github.io/synapse/latest/openid.html). ## Element (formerly known as Riot) Web Client {#module-services-matrix-element-web} -[Element Web](https://github.com/vector-im/riot-web/) is +[Element Web](https://github.com/element-hq/element-web) is the reference web client for Matrix and developed by the core team at matrix.org. Element was formerly known as Riot.im, see the [Element introductory blog post](https://element.io/blog/welcome-to-element/) @@ -228,6 +228,6 @@ the example, this means that you should not reuse the `myhostname.example.org` virtualHost to also serve Element, but instead serve it on a different subdomain, like `element.example.org` in the example. See the -[Element Important Security Notes](https://github.com/vector-im/element-web/tree/v1.10.0#important-security-notes) +[Element Important Security Notes](https://github.com/element-hq/element-web/tree/v1.10.0#important-security-notes) for more information on this subject. ::: diff --git a/nixos/modules/services/misc/airsonic.nix b/nixos/modules/services/misc/airsonic.nix index d980069608e7..3231fce35dab 100644 --- a/nixos/modules/services/misc/airsonic.nix +++ b/nixos/modules/services/misc/airsonic.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.airsonic; opt = options.services.airsonic; @@ -9,16 +6,16 @@ in { options = { services.airsonic = { - enable = mkEnableOption "Airsonic, the Free and Open Source media streaming server (fork of Subsonic and Libresonic)"; + enable = lib.mkEnableOption "Airsonic, the Free and Open Source media streaming server (fork of Subsonic and Libresonic)"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "airsonic"; description = "User account under which airsonic runs."; }; - home = mkOption { - type = types.path; + home = lib.mkOption { + type = lib.types.path; default = "/var/lib/airsonic"; description = '' The directory where Airsonic will create files. @@ -26,16 +23,16 @@ in { ''; }; - virtualHost = mkOption { - type = types.nullOr types.str; + virtualHost = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost. ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' The host name or IP address on which to bind Airsonic. @@ -47,8 +44,8 @@ in { ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 4040; description = '' The port on which Airsonic will listen for @@ -56,8 +53,8 @@ in { ''; }; - contextPath = mkOption { - type = types.path; + contextPath = lib.mkOption { + type = lib.types.path; default = "/"; description = '' The context path, i.e., the last part of the Airsonic @@ -65,8 +62,8 @@ in { ''; }; - maxMemory = mkOption { - type = types.int; + maxMemory = lib.mkOption { + type = lib.types.int; default = 100; description = '' The memory limit (max Java heap size) in megabytes. @@ -74,10 +71,10 @@ in { ''; }; - transcoders = mkOption { - type = types.listOf types.path; + transcoders = lib.mkOption { + type = lib.types.listOf lib.types.path; default = [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ]; - defaultText = literalExpression ''[ "''${pkgs.ffmpeg.bin}/bin/ffmpeg" ]''; + defaultText = lib.literalExpression ''[ "''${pkgs.ffmpeg.bin}/bin/ffmpeg" ]''; description = '' List of paths to transcoder executables that should be accessible from Airsonic. Symlinks will be created to each executable inside @@ -85,7 +82,7 @@ in { ''; }; - jre = mkPackageOption pkgs "jre8" { + jre = lib.mkPackageOption pkgs "jre8" { extraDescription = '' ::: {.note} Airsonic only supports Java 8, airsonic-advanced requires at least @@ -94,14 +91,14 @@ in { ''; }; - war = mkOption { - type = types.path; + war = lib.mkOption { + type = lib.types.path; default = "${pkgs.airsonic}/webapps/airsonic.war"; - defaultText = literalExpression ''"''${pkgs.airsonic}/webapps/airsonic.war"''; + defaultText = lib.literalExpression ''"''${pkgs.airsonic}/webapps/airsonic.war"''; description = "Airsonic war file to use."; }; - jvmOptions = mkOption { + jvmOptions = lib.mkOption { description = '' Extra command line options for the JVM running AirSonic. Useful for sending jukebox output to non-default alsa @@ -109,7 +106,7 @@ in { ''; default = [ ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "-Djavax.sound.sampled.Clip='#CODEC [plughw:1,0]'" "-Djavax.sound.sampled.Port='#Port CODEC [hw:1]'" @@ -121,7 +118,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.airsonic = { description = "Airsonic Media Server"; after = [ "network.target" ]; @@ -143,7 +140,7 @@ in { -Dserver.port=${toString cfg.port} \ -Dserver.context-path=${cfg.contextPath} \ -Djava.awt.headless=true \ - ${optionalString (cfg.virtualHost != null) + ${lib.optionalString (cfg.virtualHost != null) "-Dserver.use-forward-headers=true"} \ ${toString cfg.jvmOptions} \ -verbose:gc \ @@ -155,7 +152,7 @@ in { }; }; - services.nginx = mkIf (cfg.virtualHost != null) { + services.nginx = lib.mkIf (cfg.virtualHost != null) { enable = true; recommendedProxySettings = true; virtualHosts.${cfg.virtualHost} = { diff --git a/nixos/modules/services/misc/amazon-ssm-agent.nix b/nixos/modules/services/misc/amazon-ssm-agent.nix index 0da10621d0a0..8267f9c42f8c 100644 --- a/nixos/modules/services/misc/amazon-ssm-agent.nix +++ b/nixos/modules/services/misc/amazon-ssm-agent.nix @@ -1,6 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.services.amazon-ssm-agent; @@ -22,16 +20,16 @@ let }; in { imports = [ - (mkRenamedOptionModule [ "services" "ssm-agent" "enable" ] [ "services" "amazon-ssm-agent" "enable" ]) - (mkRenamedOptionModule [ "services" "ssm-agent" "package" ] [ "services" "amazon-ssm-agent" "package" ]) + (lib.mkRenamedOptionModule [ "services" "ssm-agent" "enable" ] [ "services" "amazon-ssm-agent" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "ssm-agent" "package" ] [ "services" "amazon-ssm-agent" "package" ]) ]; options.services.amazon-ssm-agent = { - enable = mkEnableOption "Amazon SSM agent"; - package = mkPackageOption pkgs "amazon-ssm-agent" {}; + enable = lib.mkEnableOption "Amazon SSM agent"; + package = lib.mkPackageOption pkgs "amazon-ssm-agent" {}; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # See https://github.com/aws/amazon-ssm-agent/blob/mainline/packaging/linux/amazon-ssm-agent.service systemd.services.amazon-ssm-agent = { inherit (cfg.package.meta) description; @@ -39,7 +37,12 @@ in { after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - path = [ fake-lsb-release pkgs.coreutils ]; + path = [ + fake-lsb-release + pkgs.coreutils + "/run/wrappers" + "/run/current-system/sw" + ]; serviceConfig = { ExecStart = "${cfg.package}/bin/amazon-ssm-agent"; diff --git a/nixos/modules/services/misc/anki-sync-server.md b/nixos/modules/services/misc/anki-sync-server.md index 5482a4aa0e5f..4796abf25c43 100644 --- a/nixos/modules/services/misc/anki-sync-server.md +++ b/nixos/modules/services/misc/anki-sync-server.md @@ -56,13 +56,3 @@ following options: services.anki-sync-server.openFirewall = true; } ``` - - -## Alternatives {#module-services-anki-sync-server-alternatives} - -The [`ankisyncd` NixOS -module](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/misc/ankisyncd.nix) -provides similar functionality, but using a third-party implementation, -[`anki-sync-server-rs`](https://github.com/ankicommunity/anki-sync-server-rs/). -According to that project's README, it is "no longer maintained", and not -recommended for Anki 2.1.64+. diff --git a/nixos/modules/services/misc/ankisyncd.nix b/nixos/modules/services/misc/ankisyncd.nix deleted file mode 100644 index b999b02534e7..000000000000 --- a/nixos/modules/services/misc/ankisyncd.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.ankisyncd; - - name = "ankisyncd"; - - stateDir = "/var/lib/${name}"; - - toml = pkgs.formats.toml {}; - - configFile = toml.generate "ankisyncd.conf" { - listen = { - host = cfg.host; - port = cfg.port; - }; - paths.root_dir = stateDir; - # encryption.ssl_enable / cert_file / key_file - }; -in - { - options.services.ankisyncd = { - enable = mkEnableOption "ankisyncd, a standalone unofficial anky sync server"; - - package = mkPackageOption pkgs "ankisyncd" { }; - - host = mkOption { - type = types.str; - default = "localhost"; - description = "ankisyncd host"; - }; - - port = mkOption { - type = types.port; - default = 27701; - description = "ankisyncd port"; - }; - - openFirewall = mkOption { - default = false; - type = types.bool; - description = "Whether to open the firewall for the specified port."; - }; - }; - - config = mkIf cfg.enable { - warnings = [ - '' - `services.ankisyncd` has been replaced by `services.anki-sync-server` and will be removed after - 24.05 because anki-sync-server(-rs and python) are not maintained. - '' - ]; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; - - systemd.services.ankisyncd = { - description = "ankisyncd - Anki sync server"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ cfg.package ]; - - serviceConfig = { - Type = "simple"; - DynamicUser = true; - StateDirectory = name; - ExecStart = "${cfg.package}/bin/ankisyncd --config ${configFile}"; - Restart = "always"; - }; - }; - }; - } diff --git a/nixos/modules/services/misc/apache-kafka.nix b/nixos/modules/services/misc/apache-kafka.nix index d1a3d92f2e22..0ed20961c57b 100644 --- a/nixos/modules/services/misc/apache-kafka.nix +++ b/nixos/modules/services/misc/apache-kafka.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.apache-kafka; @@ -17,24 +14,24 @@ let mkPropertyString = let render = { - bool = boolToString; + bool = lib.boolToString; int = toString; - list = concatMapStringsSep "," mkPropertyString; - string = id; + list = lib.concatMapStringsSep "," mkPropertyString; + string = lib.id; }; in v: render.${builtins.typeOf v} v; - stringlySettings = mapAttrs (_: mkPropertyString) - (filterAttrs (_: v: v != null) cfg.settings); + stringlySettings = lib.mapAttrs (_: mkPropertyString) + (lib.filterAttrs (_: v: v != null) cfg.settings); generator = (pkgs.formats.javaProperties {}).generate; in { options.services.apache-kafka = { - enable = mkEnableOption "Apache Kafka event streaming broker"; + enable = lib.mkEnableOption "Apache Kafka event streaming broker"; - settings = mkOption { + settings = lib.mkOption { description = '' [Kafka broker configuration](https://kafka.apache.org/documentation.html#brokerconfigs) {file}`server.properties`. @@ -44,81 +41,81 @@ in { but instead as quoted strings (ie. `settings."broker.id"`, NOT `settings.broker.id`). ''; - type = types.submodule { - freeformType = with types; let + type = lib.types.submodule { + freeformType = with lib.types; let primitive = oneOf [bool int str]; in lazyAttrsOf (nullOr (either primitive (listOf primitive))); options = { - "broker.id" = mkOption { + "broker.id" = lib.mkOption { description = "Broker ID. -1 or null to auto-allocate in zookeeper mode."; default = null; - type = with types; nullOr int; + type = with lib.types; nullOr int; }; - "log.dirs" = mkOption { + "log.dirs" = lib.mkOption { description = "Log file directories."; # Deliberaly leave out old default and use the rewrite opportunity # to have users choose a safer value -- /tmp might be volatile and is a # slightly scary default choice. # default = [ "/tmp/apache-kafka" ]; - type = with types; listOf path; + type = with lib.types; listOf path; }; - "listeners" = mkOption { + "listeners" = lib.mkOption { description = '' Kafka Listener List. See [listeners](https://kafka.apache.org/documentation/#brokerconfigs_listeners). ''; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = [ "PLAINTEXT://localhost:9092" ]; }; }; }; }; - clusterId = mkOption { + clusterId = lib.mkOption { description = '' KRaft mode ClusterId used for formatting log directories. Can be generated with `kafka-storage.sh random-uuid` ''; - type = with types; nullOr str; + type = with lib.types; nullOr str; default = null; }; - configFiles.serverProperties = mkOption { + configFiles.serverProperties = lib.mkOption { description = '' Kafka server.properties configuration file path. Defaults to the rendered `settings`. ''; - type = types.path; + type = lib.types.path; }; - configFiles.log4jProperties = mkOption { + configFiles.log4jProperties = lib.mkOption { description = "Kafka log4j property configuration file path"; - type = types.path; + type = lib.types.path; default = pkgs.writeText "log4j.properties" cfg.log4jProperties; defaultText = ''pkgs.writeText "log4j.properties" cfg.log4jProperties''; }; - formatLogDirs = mkOption { + formatLogDirs = lib.mkOption { description = '' Whether to format log dirs in KRaft mode if all log dirs are unformatted, ie. they contain no meta.properties. ''; - type = types.bool; + type = lib.types.bool; default = false; }; - formatLogDirsIgnoreFormatted = mkOption { + formatLogDirsIgnoreFormatted = lib.mkOption { description = '' Whether to ignore already formatted log dirs when formatting log dirs, instead of failing. Useful when replacing or adding disks. ''; - type = types.bool; + type = lib.types.bool; default = false; }; - log4jProperties = mkOption { + log4jProperties = lib.mkOption { description = "Kafka log4j property configuration."; default = '' log4j.rootLogger=INFO, stdout @@ -127,13 +124,13 @@ in { log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%d] %p %m (%c)%n ''; - type = types.lines; + type = lib.types.lines; }; - jvmOptions = mkOption { + jvmOptions = lib.mkOption { description = "Extra command line options for the JVM running Kafka."; default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "-Djava.net.preferIPv4Stack=true" "-Dcom.sun.management.jmxremote" @@ -141,38 +138,38 @@ in { ]; }; - package = mkPackageOption pkgs "apacheKafka" { }; + package = lib.mkPackageOption pkgs "apacheKafka" { }; - jre = mkOption { + jre = lib.mkOption { description = "The JRE with which to run Kafka"; default = cfg.package.passthru.jre; - defaultText = literalExpression "pkgs.apacheKafka.passthru.jre"; - type = types.package; + defaultText = lib.literalExpression "pkgs.apacheKafka.passthru.jre"; + type = lib.types.package; }; }; imports = [ - (mkRenamedOptionModule + (lib.mkRenamedOptionModule [ "services" "apache-kafka" "brokerId" ] [ "services" "apache-kafka" "settings" ''broker.id'' ]) - (mkRenamedOptionModule + (lib.mkRenamedOptionModule [ "services" "apache-kafka" "logDirs" ] [ "services" "apache-kafka" "settings" ''log.dirs'' ]) - (mkRenamedOptionModule + (lib.mkRenamedOptionModule [ "services" "apache-kafka" "zookeeper" ] [ "services" "apache-kafka" "settings" ''zookeeper.connect'' ]) - (mkRemovedOptionModule [ "services" "apache-kafka" "port" ] + (lib.mkRemovedOptionModule [ "services" "apache-kafka" "port" ] "Please see services.apache-kafka.settings.listeners and its documentation instead") - (mkRemovedOptionModule [ "services" "apache-kafka" "hostname" ] + (lib.mkRemovedOptionModule [ "services" "apache-kafka" "hostname" ] "Please see services.apache-kafka.settings.listeners and its documentation instead") - (mkRemovedOptionModule [ "services" "apache-kafka" "extraProperties" ] + (lib.mkRemovedOptionModule [ "services" "apache-kafka" "extraProperties" ] "Please see services.apache-kafka.settings and its documentation instead") - (mkRemovedOptionModule [ "services" "apache-kafka" "serverProperties" ] + (lib.mkRemovedOptionModule [ "services" "apache-kafka" "serverProperties" ] "Please see services.apache-kafka.settings and its documentation instead") ]; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.apache-kafka.configFiles.serverProperties = generator "server.properties" stringlySettings; users.users.apache-kafka = { @@ -188,11 +185,11 @@ in { description = "Apache Kafka Daemon"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - preStart = mkIf cfg.formatLogDirs + preStart = lib.mkIf cfg.formatLogDirs (if cfg.formatLogDirsIgnoreFormatted then '' ${cfg.package}/bin/kafka-storage.sh format -t "${cfg.clusterId}" -c ${cfg.configFiles.serverProperties} --ignore-formatted '' else '' - if ${concatMapStringsSep " && " (l: ''[ ! -f "${l}/meta.properties" ]'') cfg.settings."log.dirs"}; then + if ${lib.concatMapStringsSep " && " (l: ''[ ! -f "${l}/meta.properties" ]'') cfg.settings."log.dirs"}; then ${cfg.package}/bin/kafka-storage.sh format -t "${cfg.clusterId}" -c ${cfg.configFiles.serverProperties} fi ''); diff --git a/nixos/modules/services/misc/autofs.nix b/nixos/modules/services/misc/autofs.nix index d94fae3edebf..6c3ab8e57df9 100644 --- a/nixos/modules/services/misc/autofs.nix +++ b/nixos/modules/services/misc/autofs.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.autofs; @@ -18,8 +15,8 @@ in services.autofs = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Mount filesystems on demand. Unmount them automatically. @@ -27,9 +24,9 @@ in ''; }; - autoMaster = mkOption { - type = types.str; - example = literalExpression '' + autoMaster = lib.mkOption { + type = lib.types.str; + example = lib.literalExpression '' let mapConf = pkgs.writeText "auto" ''' kernel -ro,soft,intr ftp.kernel.org:/pub/linux @@ -51,14 +48,14 @@ in ''; }; - timeout = mkOption { - type = types.int; + timeout = lib.mkOption { + type = lib.types.int; default = 600; description = "Set the global minimum timeout, in seconds, until directories are unmounted"; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Pass -d and -7 to automount and write log to the system journal. @@ -72,7 +69,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "autofs" ]; @@ -90,7 +87,7 @@ in serviceConfig = { Type = "forking"; PIDFile = "/run/autofs.pid"; - ExecStart = "${pkgs.autofs5}/bin/automount ${optionalString cfg.debug "-d"} -p /run/autofs.pid -t ${builtins.toString cfg.timeout} ${autoMaster}"; + ExecStart = "${pkgs.autofs5}/bin/automount ${lib.optionalString cfg.debug "-d"} -p /run/autofs.pid -t ${builtins.toString cfg.timeout} ${autoMaster}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; }; }; diff --git a/nixos/modules/services/misc/autorandr.nix b/nixos/modules/services/misc/autorandr.nix index 1dbfc4caa31d..f0490d63ad7f 100644 --- a/nixos/modules/services/misc/autorandr.nix +++ b/nixos/modules/services/misc/autorandr.nix @@ -1,32 +1,29 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.autorandr; - hookType = types.lines; + hookType = lib.types.lines; matrixOf = n: m: elemType: - mkOptionType rec { + lib.mkOptionType rec { name = "matrixOf"; description = "${toString n}×${toString m} matrix of ${elemType.description}s"; check = xss: - let listOfSize = l: xs: isList xs && length xs == l; + let listOfSize = l: xs: lib.isList xs && lib.length xs == l; in listOfSize n xss - && all (xs: listOfSize m xs && all elemType.check xs) xss; - merge = mergeOneOption; + && lib.all (xs: listOfSize m xs && lib.all elemType.check xs) xss; + merge = lib.mergeOneOption; getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" "*" ]); getSubModules = elemType.getSubModules; substSubModules = mod: matrixOf n m (elemType.substSubModules mod); - functor = (defaultFunctor name) // { wrapped = elemType; }; + functor = (lib.defaultFunctor name) // { wrapped = elemType; }; }; - profileModule = types.submodule { + profileModule = lib.types.submodule { options = { - fingerprint = mkOption { - type = types.attrsOf types.str; + fingerprint = lib.mkOption { + type = lib.types.attrsOf lib.types.str; description = '' Output name to EDID mapping. Use `autorandr --fingerprint` to get current setup values. @@ -34,13 +31,13 @@ let default = { }; }; - config = mkOption { - type = types.attrsOf configModule; + config = lib.mkOption { + type = lib.types.attrsOf configModule; description = "Per output profile configuration."; default = { }; }; - hooks = mkOption { + hooks = lib.mkOption { type = hooksModule; description = "Profile hook scripts."; default = { }; @@ -48,66 +45,66 @@ let }; }; - configModule = types.submodule { + configModule = lib.types.submodule { options = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; description = "Whether to enable the output."; default = true; }; - crtc = mkOption { - type = types.nullOr types.ints.unsigned; + crtc = lib.mkOption { + type = lib.types.nullOr lib.types.ints.unsigned; description = "Output video display controller."; default = null; example = 0; }; - primary = mkOption { - type = types.bool; + primary = lib.mkOption { + type = lib.types.bool; description = "Whether output should be marked as primary"; default = false; }; - position = mkOption { - type = types.str; + position = lib.mkOption { + type = lib.types.str; description = "Output position"; default = ""; example = "5760x0"; }; - mode = mkOption { - type = types.str; + mode = lib.mkOption { + type = lib.types.str; description = "Output resolution."; default = ""; example = "3840x2160"; }; - rate = mkOption { - type = types.str; + rate = lib.mkOption { + type = lib.types.str; description = "Output framerate."; default = ""; example = "60.00"; }; - gamma = mkOption { - type = types.str; + gamma = lib.mkOption { + type = lib.types.str; description = "Output gamma configuration."; default = ""; example = "1.0:0.909:0.833"; }; - rotate = mkOption { - type = types.nullOr (types.enum [ "normal" "left" "right" "inverted" ]); + rotate = lib.mkOption { + type = lib.types.nullOr (lib.types.enum [ "normal" "left" "right" "inverted" ]); description = "Output rotate configuration."; default = null; example = "left"; }; - transform = mkOption { - type = types.nullOr (matrixOf 3 3 types.float); + transform = lib.mkOption { + type = lib.types.nullOr (matrixOf 3 3 lib.types.float); default = null; - example = literalExpression '' + example = lib.literalExpression '' [ [ 0.6 0.0 0.0 ] [ 0.0 0.6 0.0 ] @@ -121,30 +118,30 @@ let ''; }; - dpi = mkOption { - type = types.nullOr types.ints.positive; + dpi = lib.mkOption { + type = lib.types.nullOr lib.types.ints.positive; description = "Output DPI configuration."; default = null; example = 96; }; - scale = mkOption { - type = types.nullOr (types.submodule { + scale = lib.mkOption { + type = lib.types.nullOr (lib.types.submodule { options = { - method = mkOption { - type = types.enum [ "factor" "pixel" ]; + method = lib.mkOption { + type = lib.types.enum [ "factor" "pixel" ]; description = "Output scaling method."; default = "factor"; example = "pixel"; }; - x = mkOption { - type = types.either types.float types.ints.positive; + x = lib.mkOption { + type = lib.types.either lib.types.float lib.types.ints.positive; description = "Horizontal scaling factor/pixels."; }; - y = mkOption { - type = types.either types.float types.ints.positive; + y = lib.mkOption { + type = lib.types.either lib.types.float lib.types.ints.positive; description = "Vertical scaling factor/pixels."; }; }; @@ -164,7 +161,7 @@ let exclusive. ''; default = null; - example = literalExpression '' + example = lib.literalExpression '' { x = 1.25; y = 1.25; @@ -174,22 +171,22 @@ let }; }; - hooksModule = types.submodule { + hooksModule = lib.types.submodule { options = { - postswitch = mkOption { - type = types.attrsOf hookType; + postswitch = lib.mkOption { + type = lib.types.attrsOf hookType; description = "Postswitch hook executed after mode switch."; default = { }; }; - preswitch = mkOption { - type = types.attrsOf hookType; + preswitch = lib.mkOption { + type = lib.types.attrsOf hookType; description = "Preswitch hook executed before mode switch."; default = { }; }; - predetect = mkOption { - type = types.attrsOf hookType; + predetect = lib.mkOption { + type = lib.types.attrsOf hookType; description = '' Predetect hook executed before autorandr attempts to run xrandr. ''; @@ -199,37 +196,37 @@ let }; hookToFile = folder: name: hook: - nameValuePair "xdg/autorandr/${folder}/${name}" { + lib.nameValuePair "xdg/autorandr/${folder}/${name}" { source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook"; }; profileToFiles = name: profile: with profile; - mkMerge ([ + lib.mkMerge ([ { - "xdg/autorandr/${name}/setup".text = concatStringsSep "\n" - (mapAttrsToList fingerprintToString fingerprint); + "xdg/autorandr/${name}/setup".text = lib.concatStringsSep "\n" + (lib.mapAttrsToList fingerprintToString fingerprint); "xdg/autorandr/${name}/config".text = - concatStringsSep "\n" (mapAttrsToList configToString profile.config); + lib.concatStringsSep "\n" (lib.mapAttrsToList configToString profile.config); } - (mapAttrs' (hookToFile "${name}/postswitch.d") hooks.postswitch) - (mapAttrs' (hookToFile "${name}/preswitch.d") hooks.preswitch) - (mapAttrs' (hookToFile "${name}/predetect.d") hooks.predetect) + (lib.mapAttrs' (hookToFile "${name}/postswitch.d") hooks.postswitch) + (lib.mapAttrs' (hookToFile "${name}/preswitch.d") hooks.preswitch) + (lib.mapAttrs' (hookToFile "${name}/predetect.d") hooks.predetect) ]); fingerprintToString = name: edid: "${name} ${edid}"; configToString = name: config: if config.enable then - concatStringsSep "\n" ([ "output ${name}" ] - ++ optional (config.position != "") "pos ${config.position}" - ++ optional (config.crtc != null) "crtc ${toString config.crtc}" - ++ optional config.primary "primary" - ++ optional (config.dpi != null) "dpi ${toString config.dpi}" - ++ optional (config.gamma != "") "gamma ${config.gamma}" - ++ optional (config.mode != "") "mode ${config.mode}" - ++ optional (config.rate != "") "rate ${config.rate}" - ++ optional (config.rotate != null) "rotate ${config.rotate}" - ++ optional (config.transform != null) ("transform " - + concatMapStringsSep "," toString (flatten config.transform)) - ++ optional (config.scale != null) + lib.concatStringsSep "\n" ([ "output ${name}" ] + ++ lib.optional (config.position != "") "pos ${config.position}" + ++ lib.optional (config.crtc != null) "crtc ${toString config.crtc}" + ++ lib.optional config.primary "primary" + ++ lib.optional (config.dpi != null) "dpi ${toString config.dpi}" + ++ lib.optional (config.gamma != "") "gamma ${config.gamma}" + ++ lib.optional (config.mode != "") "mode ${config.mode}" + ++ lib.optional (config.rate != "") "rate ${config.rate}" + ++ lib.optional (config.rotate != null) "rotate ${config.rotate}" + ++ lib.optional (config.transform != null) ("transform " + + lib.concatMapStringsSep "," toString (lib.flatten config.transform)) + ++ lib.optional (config.scale != null) ((if config.scale.method == "factor" then "scale" else "scale-from") + " ${toString config.scale.x}x${toString config.scale.y}")) else '' @@ -242,11 +239,11 @@ in { options = { services.autorandr = { - enable = mkEnableOption "handling of hotplug and sleep events by autorandr"; + enable = lib.mkEnableOption "handling of hotplug and sleep events by autorandr"; - defaultTarget = mkOption { + defaultTarget = lib.mkOption { default = "default"; - type = types.str; + type = lib.types.str; description = '' Fallback if no monitor layout can be detected. See the docs (https://github.com/phillipberndt/autorandr/blob/v1.0/README.md#how-to-use) @@ -254,23 +251,23 @@ in { ''; }; - ignoreLid = mkOption { + ignoreLid = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "Treat outputs as connected even if their lids are closed"; }; - matchEdid = mkOption { + matchEdid = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "Match displays based on edid instead of name"; }; - hooks = mkOption { + hooks = lib.mkOption { type = hooksModule; description = "Global hook scripts"; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { postswitch = { "notify-i3" = "''${pkgs.i3}/bin/i3-msg restart"; @@ -296,11 +293,11 @@ in { } ''; }; - profiles = mkOption { - type = types.attrsOf profileModule; + profiles = lib.mkOption { + type = lib.types.attrsOf profileModule; description = "Autorandr profiles specification."; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "work" = { fingerprint = { @@ -330,17 +327,17 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.udev.packages = [ pkgs.autorandr ]; environment = { systemPackages = [ pkgs.autorandr ]; - etc = mkMerge ([ - (mapAttrs' (hookToFile "postswitch.d") cfg.hooks.postswitch) - (mapAttrs' (hookToFile "preswitch.d") cfg.hooks.preswitch) - (mapAttrs' (hookToFile "predetect.d") cfg.hooks.predetect) - (mkMerge (mapAttrsToList profileToFiles cfg.profiles)) + etc = lib.mkMerge ([ + (lib.mapAttrs' (hookToFile "postswitch.d") cfg.hooks.postswitch) + (lib.mapAttrs' (hookToFile "preswitch.d") cfg.hooks.preswitch) + (lib.mapAttrs' (hookToFile "predetect.d") cfg.hooks.predetect) + (lib.mkMerge (lib.mapAttrsToList profileToFiles cfg.profiles)) ]); }; @@ -357,8 +354,8 @@ in { --batch \ --change \ --default ${cfg.defaultTarget} \ - ${optionalString cfg.ignoreLid "--ignore-lid"} \ - ${optionalString cfg.matchEdid "--match-edid"} + ${lib.optionalString cfg.ignoreLid "--ignore-lid"} \ + ${lib.optionalString cfg.matchEdid "--match-edid"} ''; Type = "oneshot"; RemainAfterExit = false; @@ -368,5 +365,5 @@ in { }; - meta.maintainers = with maintainers; [ alexnortung ]; + meta.maintainers = with lib.maintainers; [ alexnortung ]; } diff --git a/nixos/modules/services/misc/bazarr.nix b/nixos/modules/services/misc/bazarr.nix index 99343a146a7a..e81b5d2b736e 100644 --- a/nixos/modules/services/misc/bazarr.nix +++ b/nixos/modules/services/misc/bazarr.nix @@ -1,42 +1,39 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.bazarr; in { options = { services.bazarr = { - enable = mkEnableOption "bazarr, a subtitle manager for Sonarr and Radarr"; + enable = lib.mkEnableOption "bazarr, a subtitle manager for Sonarr and Radarr"; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for the bazarr web interface."; }; - listenPort = mkOption { - type = types.port; + listenPort = lib.mkOption { + type = lib.types.port; default = 6767; description = "Port on which the bazarr web interface should listen"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "bazarr"; description = "User account under which bazarr runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "bazarr"; description = "Group under which bazarr runs."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.bazarr = { description = "bazarr"; after = [ "network.target" ]; @@ -58,11 +55,11 @@ in }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.listenPort ]; }; - users.users = mkIf (cfg.user == "bazarr") { + users.users = lib.mkIf (cfg.user == "bazarr") { bazarr = { isSystemUser = true; group = cfg.group; @@ -70,7 +67,7 @@ in }; }; - users.groups = mkIf (cfg.group == "bazarr") { + users.groups = lib.mkIf (cfg.group == "bazarr") { bazarr = {}; }; }; diff --git a/nixos/modules/services/misc/bcg.nix b/nixos/modules/services/misc/bcg.nix index 63c441833d95..98193fcafb3e 100644 --- a/nixos/modules/services/misc/bcg.nix +++ b/nixos/modules/services/misc/bcg.nix @@ -4,13 +4,10 @@ pkgs, ... }: - -with lib; - let cfg = config.services.bcg; configFile = (pkgs.formats.yaml {}).generate "bcg.conf.yaml" ( - filterAttrsRecursive (n: v: v != null) { + lib.filterAttrsRecursive (n: v: v != null) { inherit (cfg) device name mqtt; retain_node_messages = cfg.retainNodeMessages; qos_node_messages = cfg.qosNodeMessages; @@ -25,10 +22,10 @@ in { options = { services.bcg = { - enable = mkEnableOption "BigClown gateway"; - package = mkPackageOption pkgs [ "python3Packages" "bcg" ] { }; - environmentFiles = mkOption { - type = types.listOf types.path; + enable = lib.mkEnableOption "BigClown gateway"; + package = lib.mkPackageOption pkgs [ "python3Packages" "bcg" ] { }; + environmentFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; example = [ "/run/keys/bcg.env" ]; description = '' @@ -38,17 +35,17 @@ in This is useful to avoid putting secrets into the nix store. ''; }; - verbose = mkOption { - type = types.enum ["CRITICAL" "ERROR" "WARNING" "INFO" "DEBUG"]; + verbose = lib.mkOption { + type = lib.types.enum ["CRITICAL" "ERROR" "WARNING" "INFO" "DEBUG"]; default = "WARNING"; description = "Verbosity level."; }; - device = mkOption { - type = types.str; + device = lib.mkOption { + type = lib.types.str; description = "Device name to configure gateway to use."; }; - name = mkOption { - type = with types; nullOr str; + name = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Name for the device. @@ -61,86 +58,86 @@ in ''; }; mqtt = { - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Host where MQTT server is running."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 1883; description = "Port of MQTT server."; }; - username = mkOption { - type = with types; nullOr str; + username = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "MQTT server access username."; }; - password = mkOption { - type = with types; nullOr str; + password = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "MQTT server access password."; }; - cafile = mkOption { - type = with types; nullOr str; + cafile = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Certificate Authority file for MQTT server access."; }; - certfile = mkOption { - type = with types; nullOr str; + certfile = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Certificate file for MQTT server access."; }; - keyfile = mkOption { - type = with types; nullOr str; + keyfile = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Key file for MQTT server access."; }; }; - retainNodeMessages = mkOption { - type = types.bool; + retainNodeMessages = lib.mkOption { + type = lib.types.bool; default = false; description = "Specify that node messages should be retaied in MQTT broker."; }; - qosNodeMessages = mkOption { - type = types.int; + qosNodeMessages = lib.mkOption { + type = lib.types.int; default = 1; description = "Set the guarantee of MQTT message delivery."; }; - baseTopicPrefix = mkOption { - type = types.str; + baseTopicPrefix = lib.mkOption { + type = lib.types.str; default = ""; description = "Topic prefix added to all MQTT messages."; }; - automaticRemoveKitFromNames = mkOption { - type = types.bool; + automaticRemoveKitFromNames = lib.mkOption { + type = lib.types.bool; default = true; description = "Automatically remove kits."; }; - automaticRenameKitNodes = mkOption { - type = types.bool; + automaticRenameKitNodes = lib.mkOption { + type = lib.types.bool; default = true; description = "Automatically rename kit's nodes."; }; - automaticRenameGenericNodes = mkOption { - type = types.bool; + automaticRenameGenericNodes = lib.mkOption { + type = lib.types.bool; default = true; description = "Automatically rename generic nodes."; }; - automaticRenameNodes = mkOption { - type = types.bool; + automaticRenameNodes = lib.mkOption { + type = lib.types.bool; default = true; description = "Automatically rename all nodes."; }; - rename = mkOption { - type = with types; attrsOf str; + rename = lib.mkOption { + type = with lib.types; attrsOf str; default = {}; description = "Rename nodes to different name."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs; [ python3Packages.bcg python3Packages.bch @@ -156,7 +153,7 @@ in wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" ] ++ lib.optional config.services.mosquitto.enable "mosquitto.service"; after = [ "network-online.target" ]; - preStart = mkIf envConfig '' + preStart = lib.mkIf envConfig '' umask 077 ${pkgs.envsubst}/bin/envsubst -i "${configFile}" -o "${finalConfig}" ''; diff --git a/nixos/modules/services/misc/beanstalkd.nix b/nixos/modules/services/misc/beanstalkd.nix index b8f163cbfadf..5f7e4be34daa 100644 --- a/nixos/modules/services/misc/beanstalkd.nix +++ b/nixos/modules/services/misc/beanstalkd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.beanstalkd; pkg = pkgs.beanstalkd; @@ -12,25 +9,25 @@ in options = { services.beanstalkd = { - enable = mkEnableOption "the Beanstalk work queue"; + enable = lib.mkEnableOption "the Beanstalk work queue"; listen = { - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; description = "TCP port that will be used to accept client connections."; default = 11300; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; description = "IP address to listen on."; default = "127.0.0.1"; example = "0.0.0.0"; }; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to open ports in the firewall for the server."; }; @@ -39,9 +36,9 @@ in # implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.listen.port ]; }; diff --git a/nixos/modules/services/misc/bees.nix b/nixos/modules/services/misc/bees.nix index a0fd3cd43d62..0824e0a8835c 100644 --- a/nixos/modules/services/misc/bees.nix +++ b/nixos/modules/services/misc/bees.nix @@ -1,15 +1,12 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.beesd; logLevels = { emerg = 0; alert = 1; crit = 2; err = 3; warning = 4; notice = 5; info = 6; debug = 7; }; - fsOptions = with types; { - options.spec = mkOption { + fsOptions = with lib.types; { + options.spec = lib.mkOption { type = str; description = '' Description of how to identify the filesystem to be duplicated by this @@ -25,8 +22,8 @@ let ''; example = "LABEL=MyBulkDataDrive"; }; - options.hashTableSizeMB = mkOption { - type = types.addCheck types.int (n: mod n 16 == 0); + options.hashTableSizeMB = lib.mkOption { + type = lib.types.addCheck lib.types.int (n: lib.mod n 16 == 0); default = 1024; # 1GB; default from upstream beesd script description = '' Hash table size in MB; must be a multiple of 16. @@ -40,13 +37,13 @@ let will recognize only aligned duplicate blocks of 16KB. ''; }; - options.verbosity = mkOption { - type = types.enum (attrNames logLevels ++ attrValues logLevels); - apply = v: if isString v then logLevels.${v} else v; + options.verbosity = lib.mkOption { + type = lib.types.enum (lib.attrNames logLevels ++ lib.attrValues logLevels); + apply = v: if lib.isString v then logLevels.${v} else v; default = "info"; description = "Log verbosity (syslog keyword/level)."; }; - options.workDir = mkOption { + options.workDir = lib.mkOption { type = str; default = ".beeshome"; description = '' @@ -54,13 +51,13 @@ let the hash table will be stored. ''; }; - options.extraOptions = mkOption { + options.extraOptions = lib.mkOption { type = listOf str; default = [ ]; description = '' Extra command-line options passed to the daemon. See upstream bees documentation. ''; - example = literalExpression '' + example = lib.literalExpression '' [ "--thread-count" "4" ] ''; }; @@ -70,11 +67,11 @@ in { options.services.beesd = { - filesystems = mkOption { - type = with types; attrsOf (submodule fsOptions); + filesystems = lib.mkOption { + type = with lib.types; attrsOf (submodule fsOptions); description = "BTRFS filesystems to run block-level deduplication on."; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { root = { spec = "LABEL=root"; @@ -87,8 +84,8 @@ in }; }; config = { - systemd.services = mapAttrs' - (name: fs: nameValuePair "beesd@${name}" { + systemd.services = lib.mapAttrs' + (name: fs: lib.nameValuePair "beesd@${name}" { description = "Block-level BTRFS deduplication for %i"; after = [ "sysinit.target" ]; @@ -100,11 +97,11 @@ in "idxSizeMB=${toString fs.hashTableSizeMB}" "workDir=${fs.workDir}" ]; - configOptsStr = escapeShellArgs configOpts; + configOptsStr = lib.escapeShellArgs configOpts; in { # Values from https://github.com/Zygo/bees/blob/v0.6.5/scripts/beesd@.service.in - ExecStart = "${pkgs.bees}/bin/bees-service-wrapper run ${configOptsStr} -- --no-timestamps ${escapeShellArgs fs.extraOptions}"; + ExecStart = "${pkgs.bees}/bin/bees-service-wrapper run ${configOptsStr} -- --no-timestamps ${lib.escapeShellArgs fs.extraOptions}"; ExecStopPost = "${pkgs.bees}/bin/bees-service-wrapper cleanup ${configOptsStr}"; CPUAccounting = true; CPUSchedulingPolicy = "batch"; diff --git a/nixos/modules/services/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix index fad4827c6650..76e85a91317c 100644 --- a/nixos/modules/services/misc/bepasty.nix +++ b/nixos/modules/services/misc/bepasty.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let gunicorn = pkgs.python3Packages.gunicorn; bepasty = pkgs.bepasty; @@ -13,20 +11,20 @@ let in { options.services.bepasty = { - enable = mkEnableOption "bepasty, a binary pastebin server"; + enable = lib.mkEnableOption "bepasty, a binary pastebin server"; - servers = mkOption { + servers = lib.mkOption { default = {}; description = '' configure a number of bepasty servers which will be started with gunicorn. ''; - type = with types ; attrsOf (submodule ({ config, ... } : { + type = with lib.types ; attrsOf (submodule ({ config, ... } : { options = { - bind = mkOption { - type = types.str; + bind = lib.mkOption { + type = lib.types.str; description = '' Bind address to be used for this server. ''; @@ -34,16 +32,16 @@ in default = "127.0.0.1:8000"; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; description = '' Path to the directory where the pastes will be saved to ''; default = default_home+"/data"; }; - defaultPermissions = mkOption { - type = types.str; + defaultPermissions = lib.mkOption { + type = lib.types.str; description = '' default permissions for all unauthenticated accesses. ''; @@ -51,8 +49,8 @@ in default = "read"; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; description = '' Extra configuration for bepasty server to be appended on the configuration. @@ -68,8 +66,8 @@ in ''; }; - secretKey = mkOption { - type = types.str; + secretKey = lib.mkOption { + type = lib.types.str; description = '' server secret for safe session cookies, must be set. @@ -81,8 +79,8 @@ in default = ""; }; - secretKeyFile = mkOption { - type = types.nullOr types.str; + secretKeyFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' A file that contains the server secret for safe session cookies, must be set. @@ -94,8 +92,8 @@ in ''; }; - workDir = mkOption { - type = types.str; + workDir = lib.mkOption { + type = lib.types.str; description = '' Path to the working directory (used for config and pidfile). Defaults to the users home directory. @@ -105,7 +103,7 @@ in }; config = { - secretKeyFile = mkDefault ( + secretKeyFile = lib.mkDefault ( if config.secretKey != "" then toString (pkgs.writeTextFile { name = "bepasty-secret-key"; @@ -118,13 +116,13 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ bepasty ]; # creates gunicorn systemd service for each configured server - systemd.services = mapAttrs' (name: server: - nameValuePair ("bepasty-server-${name}-gunicorn") + systemd.services = lib.mapAttrs' (name: server: + lib.nameValuePair ("bepasty-server-${name}-gunicorn") ({ description = "Bepasty Server ${name}"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/misc/calibre-server.nix b/nixos/modules/services/misc/calibre-server.nix index 8e2ce2909239..5fa3c11a48aa 100644 --- a/nixos/modules/services/misc/calibre-server.nix +++ b/nixos/modules/services/misc/calibre-server.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.calibre-server; @@ -9,21 +6,21 @@ let documentationLink = "https://manual.calibre-ebook.com"; generatedDocumentationLink = documentationLink + "/generated/en/calibre-server.html"; - execFlags = (concatStringsSep " " - (mapAttrsToList (k: v: "${k} ${toString v}") (filterAttrs (name: value: value != null) { + execFlags = (lib.concatStringsSep " " + (lib.mapAttrsToList (k: v: "${k} ${toString v}") (lib.filterAttrs (name: value: value != null) { "--listen-on" = cfg.host; "--port" = cfg.port; "--auth-mode" = cfg.auth.mode; "--userdb" = cfg.auth.userDb; - }) ++ [(optionalString (cfg.auth.enable == true) "--enable-auth")]) + }) ++ [(lib.optionalString (cfg.auth.enable == true) "--enable-auth")]) ); in { imports = [ - (mkChangedOptionModule [ "services" "calibre-server" "libraryDir" ] [ "services" "calibre-server" "libraries" ] + (lib.mkChangedOptionModule [ "services" "calibre-server" "libraryDir" ] [ "services" "calibre-server" "libraries" ] (config: - let libraryDir = getAttrFromPath [ "services" "calibre-server" "libraryDir" ] config; + let libraryDir = lib.getAttrFromPath [ "services" "calibre-server" "libraryDir" ] config; in [ libraryDir ] ) ) @@ -32,11 +29,11 @@ in options = { services.calibre-server = { - enable = mkEnableOption "calibre-server (e-book software)"; + enable = lib.mkEnableOption "calibre-server (e-book software)"; package = lib.mkPackageOption pkgs "calibre" { }; - libraries = mkOption { - type = types.listOf types.path; + libraries = lib.mkOption { + type = lib.types.listOf lib.types.path; default = [ "/var/lib/calibre-server" ]; description = '' Make sure each library path is initialized before service startup. @@ -45,20 +42,20 @@ in ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "calibre-server"; description = "The user under which calibre-server runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "calibre-server"; description = "The group under which calibre-server runs."; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; example = "::1"; description = '' @@ -67,9 +64,9 @@ in ''; }; - port = mkOption { + port = lib.mkOption { default = 8080; - type = types.port; + type = lib.types.port; description = '' The port on which to listen for connections. See the [calibre-server documentation](${generatedDocumentationLink}#cmdoption-calibre-server-port) for details. @@ -77,8 +74,8 @@ in }; auth = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Password based authentication to access the server. @@ -86,8 +83,8 @@ in ''; }; - mode = mkOption { - type = types.enum [ "auto" "basic" "digest" ]; + mode = lib.mkOption { + type = lib.types.enum [ "auto" "basic" "digest" ]; default = "auto"; description = '' Choose the type of authentication used. @@ -96,9 +93,9 @@ in ''; }; - userDb = mkOption { + userDb = lib.mkOption { default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; description = '' Choose users database file to use for authentication. Make sure users database file is initialized before service startup. @@ -109,7 +106,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.calibre-server = { description = "Calibre Server"; @@ -125,7 +122,7 @@ in environment.systemPackages = [ pkgs.calibre ]; - users.users = optionalAttrs (cfg.user == "calibre-server") { + users.users = lib.optionalAttrs (cfg.user == "calibre-server") { calibre-server = { home = "/var/lib/calibre-server"; createHome = true; @@ -134,7 +131,7 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "calibre-server") { + users.groups = lib.optionalAttrs (cfg.group == "calibre-server") { calibre-server = { gid = config.ids.gids.calibre-server; }; diff --git a/nixos/modules/services/misc/canto-daemon.nix b/nixos/modules/services/misc/canto-daemon.nix index db51a263aab5..c5a702b79e44 100644 --- a/nixos/modules/services/misc/canto-daemon.nix +++ b/nixos/modules/services/misc/canto-daemon.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.canto-daemon; @@ -13,8 +10,8 @@ in { options = { services.canto-daemon = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the canto RSS daemon."; }; @@ -24,7 +21,7 @@ in { ##### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.canto-daemon = { description = "Canto RSS Daemon"; diff --git a/nixos/modules/services/misc/cfdyndns.nix b/nixos/modules/services/misc/cfdyndns.nix index 506e5f7613c0..a34e5d6d3913 100644 --- a/nixos/modules/services/misc/cfdyndns.nix +++ b/nixos/modules/services/misc/cfdyndns.nix @@ -1,50 +1,47 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.cfdyndns; in { imports = [ - (mkRemovedOptionModule + (lib.mkRemovedOptionModule [ "services" "cfdyndns" "apikey" ] "Use services.cfdyndns.apikeyFile instead.") ]; options = { services.cfdyndns = { - enable = mkEnableOption "Cloudflare Dynamic DNS Client"; + enable = lib.mkEnableOption "Cloudflare Dynamic DNS Client"; - email = mkOption { - type = types.str; + email = lib.mkOption { + type = lib.types.str; description = '' The email address to use to authenticate to CloudFlare. ''; }; - apiTokenFile = mkOption { + apiTokenFile = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The path to a file containing the API Token used to authenticate with CloudFlare. ''; }; - apikeyFile = mkOption { + apikeyFile = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The path to a file containing the API Key used to authenticate with CloudFlare. ''; }; - records = mkOption { + records = lib.mkOption { default = []; example = [ "host.tld" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' The records to update in CloudFlare. ''; @@ -52,7 +49,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.cfdyndns = { description = "CloudFlare Dynamic DNS Client"; after = [ "network.target" ]; @@ -64,14 +61,14 @@ in DynamicUser = true; }; environment = { - CLOUDFLARE_RECORDS="${concatStringsSep "," cfg.records}"; + CLOUDFLARE_RECORDS="${lib.concatStringsSep "," cfg.records}"; }; script = '' - ${optionalString (cfg.apikeyFile != null) '' - export CLOUDFLARE_APIKEY="$(cat ${escapeShellArg cfg.apikeyFile})" + ${lib.optionalString (cfg.apikeyFile != null) '' + export CLOUDFLARE_APIKEY="$(cat ${lib.escapeShellArg cfg.apikeyFile})" export CLOUDFLARE_EMAIL="${cfg.email}" ''} - ${optionalString (cfg.apiTokenFile != null) '' + ${lib.optionalString (cfg.apiTokenFile != null) '' export CLOUDFLARE_APITOKEN=$(${pkgs.systemd}/bin/systemd-creds cat CLOUDFLARE_APITOKEN_FILE) ''} ${pkgs.cfdyndns}/bin/cfdyndns diff --git a/nixos/modules/services/misc/cgminer.nix b/nixos/modules/services/misc/cgminer.nix index dd857124b226..6aa6bc63c99c 100644 --- a/nixos/modules/services/misc/cgminer.nix +++ b/nixos/modules/services/misc/cgminer.nix @@ -1,25 +1,22 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.cgminer; convType = with builtins; - v: if isBool v then boolToString v else toString v; + v: if lib.isBool v then lib.boolToString v else toString v; mergedHwConfig = - mapAttrsToList (n: v: ''"${n}": "${(concatStringsSep "," (map convType v))}"'') - (foldAttrs (n: a: [n] ++ a) [] cfg.hardware); + lib.mapAttrsToList (n: v: ''"${n}": "${(lib.concatStringsSep "," (map convType v))}"'') + (lib.foldAttrs (n: a: [n] ++ a) [] cfg.hardware); mergedConfig = with builtins; - mapAttrsToList (n: v: ''"${n}": ${if isBool v then convType v else ''"${convType v}"''}'') + lib.mapAttrsToList (n: v: ''"${n}": ${if lib.isBool v then convType v else ''"${convType v}"''}'') cfg.config; cgminerConfig = pkgs.writeText "cgminer.conf" '' { - ${concatStringsSep ",\n" mergedHwConfig}, - ${concatStringsSep ",\n" mergedConfig}, + ${lib.concatStringsSep ",\n" mergedHwConfig}, + ${lib.concatStringsSep ",\n" mergedConfig}, "pools": [ - ${concatStringsSep ",\n" + ${lib.concatStringsSep ",\n" (map (v: ''{"url": "${v.url}", "user": "${v.user}", "pass": "${v.pass}"}'') cfg.pools)}] } @@ -31,19 +28,19 @@ in services.cgminer = { - enable = mkEnableOption "cgminer, an ASIC/FPGA/GPU miner for bitcoin and litecoin"; + enable = lib.mkEnableOption "cgminer, an ASIC/FPGA/GPU miner for bitcoin and litecoin"; - package = mkPackageOption pkgs "cgminer" { }; + package = lib.mkPackageOption pkgs "cgminer" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "cgminer"; description = "User account under which cgminer runs"; }; - pools = mkOption { + pools = lib.mkOption { default = []; # Run benchmark - type = types.listOf (types.attrsOf types.str); + type = lib.types.listOf (lib.types.attrsOf lib.types.str); description = "List of pools where to mine"; example = [{ url = "http://p2pool.org:9332"; @@ -52,9 +49,9 @@ in }]; }; - hardware = mkOption { + hardware = lib.mkOption { default = []; # Run without options - type = types.listOf (types.attrsOf (types.either types.str types.int)); + type = lib.types.listOf (lib.types.attrsOf (lib.types.either lib.types.str lib.types.int)); description= "List of config options for every GPU"; example = [ { @@ -79,9 +76,9 @@ in }]; }; - config = mkOption { + config = lib.mkOption { default = {}; - type = types.attrsOf (types.either types.bool types.int); + type = lib.types.attrsOf (lib.types.either lib.types.bool lib.types.int); description = "Additional config"; example = { auto-fan = true; @@ -101,16 +98,16 @@ in ###### implementation - config = mkIf config.services.cgminer.enable { + config = lib.mkIf config.services.cgminer.enable { - users.users = optionalAttrs (cfg.user == "cgminer") { + users.users = lib.optionalAttrs (cfg.user == "cgminer") { cgminer = { isSystemUser = true; group = "cgminer"; description = "Cgminer user"; }; }; - users.groups = optionalAttrs (cfg.user == "cgminer") { + users.groups = lib.optionalAttrs (cfg.user == "cgminer") { cgminer = {}; }; diff --git a/nixos/modules/services/misc/clipcat.nix b/nixos/modules/services/misc/clipcat.nix index fa608e73c7d6..4a46adc0758a 100644 --- a/nixos/modules/services/misc/clipcat.nix +++ b/nixos/modules/services/misc/clipcat.nix @@ -1,18 +1,15 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.clipcat; in { options.services.clipcat= { - enable = mkEnableOption "Clipcat clipboard daemon"; + enable = lib.mkEnableOption "Clipcat clipboard daemon"; - package = mkPackageOption pkgs "clipcat" { }; + package = lib.mkPackageOption pkgs "clipcat" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.clipcat = { enable = true; description = "clipcat daemon"; diff --git a/nixos/modules/services/misc/clipmenu.nix b/nixos/modules/services/misc/clipmenu.nix index 71d36f9ef130..559917b7a2bf 100644 --- a/nixos/modules/services/misc/clipmenu.nix +++ b/nixos/modules/services/misc/clipmenu.nix @@ -1,18 +1,15 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.clipmenu; in { options.services.clipmenu = { - enable = mkEnableOption "clipmenu, the clipboard management daemon"; + enable = lib.mkEnableOption "clipmenu, the clipboard management daemon"; - package = mkPackageOption pkgs "clipmenu" { }; + package = lib.mkPackageOption pkgs "clipmenu" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.clipmenu = { enable = true; description = "Clipboard management daemon"; diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix index 836a1119a577..7744cee32049 100644 --- a/nixos/modules/services/misc/confd.nix +++ b/nixos/modules/services/misc/confd.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.confd; @@ -9,62 +6,62 @@ let backend = "${cfg.backend}" confdir = "${cfg.confDir}" interval = ${toString cfg.interval} - nodes = [ ${concatMapStringsSep "," (s: ''"${s}"'') cfg.nodes}, ] + nodes = [ ${lib.concatMapStringsSep "," (s: ''"${s}"'') cfg.nodes}, ] prefix = "${cfg.prefix}" log-level = "${cfg.logLevel}" - watch = ${boolToString cfg.watch} + watch = ${lib.boolToString cfg.watch} ''; in { options.services.confd = { - enable = mkEnableOption "confd, a service to manage local application configuration files using templates and data from etcd/consul/redis/zookeeper"; + enable = lib.mkEnableOption "confd, a service to manage local application configuration files using templates and data from etcd/consul/redis/zookeeper"; - backend = mkOption { + backend = lib.mkOption { description = "Confd config storage backend to use."; default = "etcd"; - type = types.enum ["etcd" "consul" "redis" "zookeeper"]; + type = lib.types.enum ["etcd" "consul" "redis" "zookeeper"]; }; - interval = mkOption { + interval = lib.mkOption { description = "Confd check interval."; default = 10; - type = types.int; + type = lib.types.int; }; - nodes = mkOption { + nodes = lib.mkOption { description = "Confd list of nodes to connect to."; default = [ "http://127.0.0.1:2379" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; }; - watch = mkOption { + watch = lib.mkOption { description = "Confd, whether to watch etcd config for changes."; default = true; - type = types.bool; + type = lib.types.bool; }; - prefix = mkOption { + prefix = lib.mkOption { description = "The string to prefix to keys."; default = "/"; - type = types.path; + type = lib.types.path; }; - logLevel = mkOption { + logLevel = lib.mkOption { description = "Confd log level."; default = "info"; - type = types.enum ["info" "debug"]; + type = lib.types.enum ["info" "debug"]; }; - confDir = mkOption { + confDir = lib.mkOption { description = "The path to the confd configs."; default = "/etc/confd"; - type = types.path; + type = lib.types.path; }; - package = mkPackageOption pkgs "confd" { }; + package = lib.mkPackageOption pkgs "confd" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.confd = { description = "Confd Service."; wantedBy = [ "multi-user.target" ]; @@ -80,6 +77,6 @@ in { environment.systemPackages = [ cfg.package ]; - services.etcd.enable = mkIf (cfg.backend == "etcd") (mkDefault true); + services.etcd.enable = lib.mkIf (cfg.backend == "etcd") (lib.mkDefault true); }; } diff --git a/nixos/modules/services/misc/cpuminer-cryptonight.nix b/nixos/modules/services/misc/cpuminer-cryptonight.nix index 907b9d90da29..c61c0d7c34bd 100644 --- a/nixos/modules/services/misc/cpuminer-cryptonight.nix +++ b/nixos/modules/services/misc/cpuminer-cryptonight.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.cpuminer-cryptonight; @@ -20,28 +17,28 @@ in options = { services.cpuminer-cryptonight = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the cpuminer cryptonight miner. ''; }; - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; description = "URL of mining server"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = "Username for mining server"; }; - pass = mkOption { - type = types.str; + pass = lib.mkOption { + type = lib.types.str; default = "x"; description = "Password for mining server"; }; - threads = mkOption { - type = types.int; + threads = lib.mkOption { + type = lib.types.int; default = 0; description = "Number of miner threads, defaults to available processors"; }; @@ -49,7 +46,7 @@ in }; - config = mkIf config.services.cpuminer-cryptonight.enable { + config = lib.mkIf config.services.cpuminer-cryptonight.enable { systemd.services.cpuminer-cryptonight = { description = "Cryptonight cpuminer"; diff --git a/nixos/modules/services/misc/devmon.nix b/nixos/modules/services/misc/devmon.nix index e4a3348646b1..13e2ab7f31c2 100644 --- a/nixos/modules/services/misc/devmon.nix +++ b/nixos/modules/services/misc/devmon.nix @@ -1,18 +1,15 @@ { pkgs, config, lib, ... }: - -with lib; - let cfg = config.services.devmon; in { options = { services.devmon = { - enable = mkEnableOption "devmon, an automatic device mounting daemon"; + enable = lib.mkEnableOption "devmon, an automatic device mounting daemon"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.devmon = { description = "devmon automatic device mounting daemon"; wantedBy = [ "default.target" ]; diff --git a/nixos/modules/services/misc/devpi-server.nix b/nixos/modules/services/misc/devpi-server.nix index 92c0c6206c8b..ad72a8ced69a 100644 --- a/nixos/modules/services/misc/devpi-server.nix +++ b/nixos/modules/services/misc/devpi-server.nix @@ -4,7 +4,6 @@ config, ... }: -with lib; let cfg = config.services.devpi-server; @@ -17,17 +16,17 @@ let in { options.services.devpi-server = { - enable = mkEnableOption "Devpi Server"; + enable = lib.mkEnableOption "Devpi Server"; - package = mkPackageOption pkgs "devpi-server" { }; + package = lib.mkPackageOption pkgs "devpi-server" { }; - primaryUrl = mkOption { - type = types.str; + primaryUrl = lib.mkOption { + type = lib.types.str; description = "Url for the primary node. Required option for replica nodes."; }; - replica = mkOption { - type = types.bool; + replica = lib.mkOption { + type = lib.types.bool; default = false; description = '' Run node as a replica. @@ -35,8 +34,8 @@ in ''; }; - secretFile = mkOption { - type = types.nullOr types.path; + secretFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to a shared secret file used for synchronization, @@ -44,24 +43,24 @@ in ''; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' domain/ip address to listen on ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 3141; description = "The port on which Devpi Server will listen."; }; - openFirewall = mkEnableOption "opening the default ports in the firewall for Devpi Server"; + openFirewall = lib.mkEnableOption "opening the default ports in the firewall for Devpi Server"; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.devpi-server = { enable = true; @@ -74,7 +73,7 @@ in # have 0600 permissions. preStart = '' - ${optionalString (!isNull cfg.secretFile) + ${lib.optionalString (!isNull cfg.secretFile) "install -Dm 0600 \${CREDENTIALS_DIRECTORY}/devpi-secret ${runtimeDir}/${secretsFileName}" } @@ -83,7 +82,7 @@ in exit 0 fi ${cfg.package}/bin/devpi-init --serverdir ${serverDir} '' - + strings.optionalString cfg.replica "--role=replica --master-url=${cfg.primaryUrl}"; + + lib.optionalString cfg.replica "--role=replica --master-url=${cfg.primaryUrl}"; serviceConfig = { LoadCredential = lib.mkIf (! isNull cfg.secretFile) [ @@ -112,7 +111,7 @@ in [ "--role=master" ] ); in - "${cfg.package}/bin/devpi-server ${concatStringsSep " " args}"; + "${cfg.package}/bin/devpi-server ${lib.concatStringsSep " " args}"; DynamicUser = true; StateDirectory = stateDirName; RuntimeDirectory = stateDirName; @@ -123,10 +122,10 @@ in }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; - meta.maintainers = [ cafkafk ]; + meta.maintainers = [ lib.maintainers.cafkafk ]; }; } diff --git a/nixos/modules/services/misc/dictd.nix b/nixos/modules/services/misc/dictd.nix index 6660d5e977ff..b11a87f28905 100644 --- a/nixos/modules/services/misc/dictd.nix +++ b/nixos/modules/services/misc/dictd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dictd; in @@ -14,19 +11,19 @@ in services.dictd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the DICT.org dictionary server. ''; }; - DBs = mkOption { - type = types.listOf types.package; + DBs = lib.mkOption { + type = lib.types.listOf lib.types.package; default = with pkgs.dictdDBs; [ wiktionary wordnet ]; - defaultText = literalExpression "with pkgs.dictdDBs; [ wiktionary wordnet ]"; - example = literalExpression "[ pkgs.dictdDBs.nld2eng ]"; + defaultText = lib.literalExpression "with pkgs.dictdDBs; [ wiktionary wordnet ]"; + example = lib.literalExpression "[ pkgs.dictdDBs.nld2eng ]"; description = "List of databases to make available."; }; @@ -40,7 +37,7 @@ in config = let dictdb = pkgs.dictDBCollector { dictlist = map (x: { name = x.name; filename = x; } ) cfg.DBs; }; - in mkIf cfg.enable { + in lib.mkIf cfg.enable { # get the command line client on system path to make some use of the service environment.systemPackages = [ pkgs.dict ]; diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix index 80e749204993..619fbcf92308 100644 --- a/nixos/modules/services/misc/disnix.nix +++ b/nixos/modules/services/misc/disnix.nix @@ -1,8 +1,5 @@ # Disnix server { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.disnix; @@ -17,22 +14,22 @@ in services.disnix = { - enable = mkEnableOption "Disnix"; + enable = lib.mkEnableOption "Disnix"; - enableMultiUser = mkOption { - type = types.bool; + enableMultiUser = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to support multi-user mode by enabling the Disnix D-Bus service"; }; - useWebServiceInterface = mkEnableOption "the DisnixWebService interface running on Apache Tomcat"; + useWebServiceInterface = lib.mkEnableOption "the DisnixWebService interface running on Apache Tomcat"; - package = mkPackageOption pkgs "disnix" {}; + package = lib.mkPackageOption pkgs "disnix" {}; - enableProfilePath = mkEnableOption "exposing the Disnix profiles in the system's PATH"; + enableProfilePath = lib.mkEnableOption "exposing the Disnix profiles in the system's PATH"; - profiles = mkOption { - type = types.listOf types.str; + profiles = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "default" ]; description = "Names of the Disnix profiles to expose in the system's PATH"; }; @@ -42,10 +39,10 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { dysnomia.enable = true; - environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService; + environment.systemPackages = [ pkgs.disnix ] ++ lib.optional cfg.useWebServiceInterface pkgs.DisnixWebService; environment.variables.PATH = lib.optionals cfg.enableProfilePath (map (profileName: "/nix/var/nix/profiles/disnix/${profileName}/bin" ) cfg.profiles); environment.variables.DISNIX_REMOTE_CLIENT = lib.optionalString (cfg.enableMultiUser) "disnix-client"; @@ -54,26 +51,26 @@ in services.tomcat.enable = cfg.useWebServiceInterface; services.tomcat.extraGroups = [ "disnix" ]; - services.tomcat.javaOpts = "${optionalString cfg.useWebServiceInterface "-Djava.library.path=${pkgs.libmatthew_java}/lib/jni"} "; - services.tomcat.sharedLibs = optional cfg.useWebServiceInterface "${pkgs.DisnixWebService}/share/java/DisnixConnection.jar" - ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar"; - services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService; + services.tomcat.javaOpts = "${lib.optionalString cfg.useWebServiceInterface "-Djava.library.path=${pkgs.libmatthew_java}/lib/jni"} "; + services.tomcat.sharedLibs = lib.optional cfg.useWebServiceInterface "${pkgs.DisnixWebService}/share/java/DisnixConnection.jar" + ++ lib.optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar"; + services.tomcat.webapps = lib.optional cfg.useWebServiceInterface pkgs.DisnixWebService; users.groups.disnix.gid = config.ids.gids.disnix; systemd.services = { - disnix = mkIf cfg.enableMultiUser { + disnix = lib.mkIf cfg.enableMultiUser { description = "Disnix server"; wants = [ "dysnomia.target" ]; wantedBy = [ "multi-user.target" ]; after = [ "dbus.service" ] - ++ optional config.services.httpd.enable "httpd.service" - ++ optional config.services.mysql.enable "mysql.service" - ++ optional config.services.postgresql.enable "postgresql.service" - ++ optional config.services.tomcat.enable "tomcat.service" - ++ optional config.services.svnserve.enable "svnserve.service" - ++ optional config.services.mongodb.enable "mongodb.service" - ++ optional config.services.influxdb.enable "influxdb.service"; + ++ lib.optional config.services.httpd.enable "httpd.service" + ++ lib.optional config.services.mysql.enable "mysql.service" + ++ lib.optional config.services.postgresql.enable "postgresql.service" + ++ lib.optional config.services.tomcat.enable "tomcat.service" + ++ lib.optional config.services.svnserve.enable "svnserve.service" + ++ lib.optional config.services.mongodb.enable "mongodb.service" + ++ lib.optional config.services.influxdb.enable "influxdb.service"; restartIfChanged = false; @@ -82,8 +79,8 @@ in environment = { HOME = "/root"; } - // (optionalAttrs (config.environment.variables ? DYSNOMIA_CONTAINERS_PATH) { inherit (config.environment.variables) DYSNOMIA_CONTAINERS_PATH; }) - // (optionalAttrs (config.environment.variables ? DYSNOMIA_MODULES_PATH) { inherit (config.environment.variables) DYSNOMIA_MODULES_PATH; }); + // (lib.optionalAttrs (config.environment.variables ? DYSNOMIA_CONTAINERS_PATH) { inherit (config.environment.variables) DYSNOMIA_CONTAINERS_PATH; }) + // (lib.optionalAttrs (config.environment.variables ? DYSNOMIA_MODULES_PATH) { inherit (config.environment.variables) DYSNOMIA_MODULES_PATH; }); serviceConfig.ExecStart = "${cfg.package}/bin/disnix-service"; }; diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix index 93bf71ea3ecc..99d5e3e1804a 100644 --- a/nixos/modules/services/misc/docker-registry.nix +++ b/nixos/modules/services/misc/docker-registry.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dockerRegistry; @@ -15,7 +12,7 @@ let storage = { cache.blobdescriptor = blobCache; delete.enabled = cfg.enableDelete; - } // (optionalAttrs (cfg.storagePath != null) { filesystem.rootdirectory = cfg.storagePath; }); + } // (lib.optionalAttrs (cfg.storagePath != null) { filesystem.rootdirectory = cfg.storagePath; }); http = { addr = "${cfg.listenAddress}:${builtins.toString cfg.port}"; headers.X-Content-Type-Options = ["nosniff"]; @@ -27,7 +24,7 @@ let }; }; - registryConfig.redis = mkIf cfg.enableRedisCache { + registryConfig.redis = lib.mkIf cfg.enableRedisCache { addr = "${cfg.redisUrl}"; password = "${cfg.redisPassword}"; db = 0; @@ -44,32 +41,32 @@ let configFile = cfg.configFile; in { options.services.dockerRegistry = { - enable = mkEnableOption "Docker Registry"; + enable = lib.mkEnableOption "Docker Registry"; - package = mkPackageOption pkgs "docker-distribution" { + package = lib.mkPackageOption pkgs "docker-distribution" { example = "gitlab-container-registry"; }; - listenAddress = mkOption { + listenAddress = lib.mkOption { description = "Docker registry host or ip to bind to."; default = "127.0.0.1"; - type = types.str; + type = lib.types.str; }; - port = mkOption { + port = lib.mkOption { description = "Docker registry port to bind to."; default = 5000; - type = types.port; + type = lib.types.port; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Opens the port used by the firewall."; }; - storagePath = mkOption { - type = types.nullOr types.path; + storagePath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = "/var/lib/docker-registry"; description = '' Docker registry storage path for the filesystem storage backend. Set to @@ -77,50 +74,50 @@ in { ''; }; - enableDelete = mkOption { - type = types.bool; + enableDelete = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable delete for manifests and blobs."; }; - enableRedisCache = mkEnableOption "redis as blob cache"; + enableRedisCache = lib.mkEnableOption "redis as blob cache"; - redisUrl = mkOption { - type = types.str; + redisUrl = lib.mkOption { + type = lib.types.str; default = "localhost:6379"; description = "Set redis host and port."; }; - redisPassword = mkOption { - type = types.str; + redisPassword = lib.mkOption { + type = lib.types.str; default = ""; description = "Set redis password."; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { description = '' Docker extra registry configuration via environment variables. ''; default = {}; - type = types.attrs; + type = lib.types.attrs; }; configFile = lib.mkOption { - default = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (recursiveUpdate registryConfig cfg.extraConfig)); - defaultText = literalExpression ''pkgs.writeText "docker-registry-config.yml" "# my custom docker-registry-config.yml ..."''; + default = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (lib.recursiveUpdate registryConfig cfg.extraConfig)); + defaultText = lib.literalExpression ''pkgs.writeText "docker-registry-config.yml" "# my custom docker-registry-config.yml ..."''; description = '' Path to CNCF distribution config file. Setting this option will override any configuration applied by the extraConfig option. ''; - type = types.path; + type = lib.types.path; }; - enableGarbageCollect = mkEnableOption "garbage collect"; + enableGarbageCollect = lib.mkEnableOption "garbage collect"; - garbageCollectDates = mkOption { + garbageCollectDates = lib.mkOption { default = "daily"; - type = types.str; + type = lib.types.str; description = '' Specification (in the format described by {manpage}`systemd.time(7)`) of the time at @@ -129,7 +126,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.docker-registry = { description = "Docker Container Registry"; wantedBy = [ "multi-user.target" ]; @@ -141,7 +138,7 @@ in { serviceConfig = { User = "docker-registry"; WorkingDirectory = cfg.storagePath; - AmbientCapabilities = mkIf (cfg.port < 1024) "cap_net_bind_service"; + AmbientCapabilities = lib.mkIf (cfg.port < 1024) "cap_net_bind_service"; }; }; @@ -158,11 +155,11 @@ in { /run/current-system/systemd/bin/systemctl restart docker-registry.service ''; - startAt = optional cfg.enableGarbageCollect cfg.garbageCollectDates; + startAt = lib.optional cfg.enableGarbageCollect cfg.garbageCollectDates; }; users.users.docker-registry = - (optionalAttrs (cfg.storagePath != null) { + (lib.optionalAttrs (cfg.storagePath != null) { createHome = true; home = cfg.storagePath; }) // { @@ -171,7 +168,7 @@ in { }; users.groups.docker-registry = {}; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; }; diff --git a/nixos/modules/services/misc/domoticz.nix b/nixos/modules/services/misc/domoticz.nix index 52443f49f7b3..13e56f2faea5 100644 --- a/nixos/modules/services/misc/domoticz.nix +++ b/nixos/modules/services/misc/domoticz.nix @@ -1,7 +1,4 @@ { lib, pkgs, config, ... }: - -with lib; - let cfg = config.services.domoticz; @@ -12,16 +9,16 @@ in { options = { services.domoticz = { - enable = mkEnableOption pkgDesc; + enable = lib.mkEnableOption pkgDesc; - bind = mkOption { - type = types.str; + bind = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = "IP address to bind to."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = "Port to bind to for HTTP, set to 0 to disable HTTP."; }; @@ -30,7 +27,7 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services."domoticz" = { description = pkgDesc; diff --git a/nixos/modules/services/misc/duckling.nix b/nixos/modules/services/misc/duckling.nix index 77d2a92380b0..ed0b7b37d8c8 100644 --- a/nixos/modules/services/misc/duckling.nix +++ b/nixos/modules/services/misc/duckling.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.duckling; in { options = { services.duckling = { - enable = mkEnableOption "duckling"; + enable = lib.mkEnableOption "duckling"; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = '' Port on which duckling will run. @@ -19,7 +16,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.duckling = { description = "Duckling server service"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/misc/dwm-status.nix b/nixos/modules/services/misc/dwm-status.nix index 081451f2ace9..927561270a79 100644 --- a/nixos/modules/services/misc/dwm-status.nix +++ b/nixos/modules/services/misc/dwm-status.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dwm-status; - order = concatMapStringsSep "," (feature: ''"${feature}"'') cfg.order; + order = lib.concatMapStringsSep "," (feature: ''"${feature}"'') cfg.order; configFile = pkgs.writeText "dwm-status.toml" '' order = [${order}] @@ -22,21 +19,21 @@ in services.dwm-status = { - enable = mkEnableOption "dwm-status user service"; + enable = lib.mkEnableOption "dwm-status user service"; - package = mkPackageOption pkgs "dwm-status" { + package = lib.mkPackageOption pkgs "dwm-status" { example = "dwm-status.override { enableAlsaUtils = false; }"; }; - order = mkOption { - type = types.listOf (types.enum [ "audio" "backlight" "battery" "cpu_load" "network" "time" ]); + order = lib.mkOption { + type = lib.types.listOf (lib.types.enum [ "audio" "backlight" "battery" "cpu_load" "network" "time" ]); description = '' List of enabled features in order. ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra config in TOML format. @@ -50,9 +47,9 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - services.upower.enable = elem "battery" cfg.order; + services.upower.enable = lib.elem "battery" cfg.order; systemd.user.services.dwm-status = { description = "Highly performant and configurable DWM status service"; diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix index 8150b7876221..9f421d7ec375 100644 --- a/nixos/modules/services/misc/dysnomia.nix +++ b/nixos/modules/services/misc/dysnomia.nix @@ -1,16 +1,13 @@ {pkgs, lib, config, ...}: - -with lib; - let cfg = config.dysnomia; printProperties = properties: - concatMapStrings (propertyName: + lib.concatMapStrings (propertyName: let property = properties.${propertyName}; in - if isList property then "${propertyName}=(${lib.concatMapStrings (elem: "\"${toString elem}\" ") (properties.${propertyName})})\n" + if lib.isList property then "${propertyName}=(${lib.concatMapStrings (elem: "\"${toString elem}\" ") (properties.${propertyName})})\n" else "${propertyName}=\"${toString property}\"\n" ) (builtins.attrNames properties); @@ -29,7 +26,7 @@ let mkdir -p $out cd $out - ${concatMapStrings (containerName: + ${lib.concatMapStrings (containerName: let containerProperties = cfg.containers.${containerName}; in @@ -47,7 +44,7 @@ let '' mkdir ${containerName} - ${concatMapStrings (componentName: + ${lib.concatMapStrings (componentName: let component = cfg.components.${containerName}.${componentName}; in @@ -61,7 +58,7 @@ let mkdir -p $out cd $out - ${concatMapStrings (containerName: + ${lib.concatMapStrings (containerName: linkMutableComponents { inherit containerName; } ) (builtins.attrNames cfg.components)} ''; @@ -84,68 +81,68 @@ in options = { dysnomia = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable Dysnomia"; }; - enableAuthentication = mkOption { - type = types.bool; + enableAuthentication = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to publish privacy-sensitive authentication credentials"; }; - package = mkOption { - type = types.path; + package = lib.mkOption { + type = lib.types.path; description = "The Dysnomia package"; }; - properties = mkOption { + properties = lib.mkOption { description = "An attribute set in which each attribute represents a machine property. Optionally, these values can be shell substitutions."; default = {}; - type = types.attrs; + type = lib.types.attrs; }; - containers = mkOption { + containers = lib.mkOption { description = "An attribute set in which each key represents a container and each value an attribute set providing its configuration properties"; default = {}; - type = types.attrsOf types.attrs; + type = lib.types.attrsOf lib.types.attrs; }; - components = mkOption { + components = lib.mkOption { description = "An attribute set in which each key represents a container and each value an attribute set in which each key represents a component and each value a derivation constructing its initial state"; default = {}; - type = types.attrsOf types.attrs; + type = lib.types.attrsOf lib.types.attrs; }; - extraContainerProperties = mkOption { + extraContainerProperties = lib.mkOption { description = "An attribute set providing additional container settings in addition to the default properties"; default = {}; - type = types.attrs; + type = lib.types.attrs; }; - extraContainerPaths = mkOption { + extraContainerPaths = lib.mkOption { description = "A list of paths containing additional container configurations that are added to the search folders"; default = []; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; }; - extraModulePaths = mkOption { + extraModulePaths = lib.mkOption { description = "A list of paths containing additional modules that are added to the search folders"; default = []; - type = types.listOf types.path; + type = lib.types.listOf lib.types.path; }; - enableLegacyModules = mkOption { - type = types.bool; + enableLegacyModules = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to enable Dysnomia legacy process and wrapper modules"; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.etc = { "dysnomia/containers" = { @@ -199,16 +196,16 @@ in "sysvinit-script" "nixos-configuration" ] - ++ optional (dysnomiaFlags.enableApacheWebApplication) "apache-webapplication" - ++ optional (dysnomiaFlags.enableAxis2WebService) "axis2-webservice" - ++ optional (dysnomiaFlags.enableDockerContainer) "docker-container" - ++ optional (dysnomiaFlags.enableEjabberdDump) "ejabberd-dump" - ++ optional (dysnomiaFlags.enableInfluxDatabase) "influx-database" - ++ optional (dysnomiaFlags.enableMySQLDatabase) "mysql-database" - ++ optional (dysnomiaFlags.enablePostgreSQLDatabase) "postgresql-database" - ++ optional (dysnomiaFlags.enableTomcatWebApplication) "tomcat-webapplication" - ++ optional (dysnomiaFlags.enableMongoDatabase) "mongo-database" - ++ optional (dysnomiaFlags.enableSubversionRepository) "subversion-repository"; + ++ lib.optional (dysnomiaFlags.enableApacheWebApplication) "apache-webapplication" + ++ lib.optional (dysnomiaFlags.enableAxis2WebService) "axis2-webservice" + ++ lib.optional (dysnomiaFlags.enableDockerContainer) "docker-container" + ++ lib.optional (dysnomiaFlags.enableEjabberdDump) "ejabberd-dump" + ++ lib.optional (dysnomiaFlags.enableInfluxDatabase) "influx-database" + ++ lib.optional (dysnomiaFlags.enableMySQLDatabase) "mysql-database" + ++ lib.optional (dysnomiaFlags.enablePostgreSQLDatabase) "postgresql-database" + ++ lib.optional (dysnomiaFlags.enableTomcatWebApplication) "tomcat-webapplication" + ++ lib.optional (dysnomiaFlags.enableMongoDatabase) "mongo-database" + ++ lib.optional (dysnomiaFlags.enableSubversionRepository) "subversion-repository"; }; dysnomia.containers = lib.recursiveUpdate ({ diff --git a/nixos/modules/services/misc/errbot.nix b/nixos/modules/services/misc/errbot.nix index b447ba5d438d..1c7135e774e8 100644 --- a/nixos/modules/services/misc/errbot.nix +++ b/nixos/modules/services/misc/errbot.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.errbot; pluginEnv = plugins: pkgs.buildEnv { @@ -17,7 +14,7 @@ let BOT_LOG_LEVEL = logging.${instanceCfg.logLevel} BOT_LOG_FILE = False - BOT_ADMINS = (${concatMapStringsSep "," (name: "'${name}'") instanceCfg.admins}) + BOT_ADMINS = (${lib.concatMapStringsSep "," (name: "'${name}'") instanceCfg.admins}) BOT_IDENTITY = ${builtins.toJSON instanceCfg.identity} @@ -25,48 +22,48 @@ let ''; in { options = { - services.errbot.instances = mkOption { + services.errbot.instances = lib.mkOption { default = {}; description = "Errbot instance configs"; - type = types.attrsOf (types.submodule { + type = lib.types.attrsOf (lib.types.submodule { options = { - dataDir = mkOption { - type = types.nullOr types.path; + dataDir = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = "Data directory for errbot instance."; }; - plugins = mkOption { - type = types.listOf types.package; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; description = "List of errbot plugin derivations."; }; - logLevel = mkOption { - type = types.str; + logLevel = lib.mkOption { + type = lib.types.str; default = "INFO"; description = "Errbot log level"; }; - admins = mkOption { - type = types.listOf types.str; + admins = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = "List of identifiers of errbot admins."; }; - backend = mkOption { - type = types.str; + backend = lib.mkOption { + type = lib.types.str; default = "XMPP"; description = "Errbot backend name."; }; - identity = mkOption { - type = types.attrs; + identity = lib.mkOption { + type = lib.types.attrs; description = "Errbot identity configuration"; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "String to be appended to the config verbatim"; }; @@ -75,14 +72,14 @@ in { }; }; - config = mkIf (cfg.instances != {}) { + config = lib.mkIf (cfg.instances != {}) { users.users.errbot = { group = "errbot"; isSystemUser = true; }; users.groups.errbot = {}; - systemd.services = mapAttrs' (name: instanceCfg: nameValuePair "errbot-${name}" ( + systemd.services = lib.mapAttrs' (name: instanceCfg: lib.nameValuePair "errbot-${name}" ( let dataDir = if instanceCfg.dataDir != null then instanceCfg.dataDir else "/var/lib/errbot/${name}"; diff --git a/nixos/modules/services/misc/etebase-server.nix b/nixos/modules/services/misc/etebase-server.nix index 9b2ba34cc30b..ba45a1703ac2 100644 --- a/nixos/modules/services/misc/etebase-server.nix +++ b/nixos/modules/services/misc/etebase-server.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.etebase-server; @@ -13,24 +10,24 @@ let in { imports = [ - (mkRemovedOptionModule + (lib.mkRemovedOptionModule [ "services" "etebase-server" "customIni" ] "Set the option `services.etebase-server.settings' instead.") - (mkRemovedOptionModule + (lib.mkRemovedOptionModule [ "services" "etebase-server" "database" ] "Set the option `services.etebase-server.settings.database' instead.") - (mkRenamedOptionModule + (lib.mkRenamedOptionModule [ "services" "etebase-server" "secretFile" ] [ "services" "etebase-server" "settings" "secret_file" ]) - (mkRenamedOptionModule + (lib.mkRenamedOptionModule [ "services" "etebase-server" "host" ] [ "services" "etebase-server" "settings" "allowed_hosts" "allowed_host1" ]) ]; options = { services.etebase-server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; example = true; description = '' @@ -43,77 +40,77 @@ in ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = pkgs.etebase-server; - defaultText = literalExpression "pkgs.python3.pkgs.etebase-server"; + defaultText = lib.literalExpression "pkgs.python3.pkgs.etebase-server"; description = "etebase-server package to use."; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/etebase-server"; description = "Directory to store the Etebase server data."; }; - port = mkOption { - type = with types; nullOr port; + port = lib.mkOption { + type = with lib.types; nullOr port; default = 8001; description = "Port to listen on."; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to open ports in the firewall for the server. ''; }; - unixSocket = mkOption { - type = with types; nullOr str; + unixSocket = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "The path to the socket to bind to."; example = "/run/etebase-server/etebase-server.sock"; }; - settings = mkOption { + settings = lib.mkOption { type = lib.types.submodule { freeformType = iniFmt.type; options = { global = { - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to set django's DEBUG flag. ''; }; - secret_file = mkOption { - type = with types; nullOr str; + secret_file = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' The path to a file containing the secret used as django's SECRET_KEY. ''; }; - static_root = mkOption { - type = types.str; + static_root = lib.mkOption { + type = lib.types.str; default = "${cfg.dataDir}/static"; - defaultText = literalExpression ''"''${config.services.etebase-server.dataDir}/static"''; + defaultText = lib.literalExpression ''"''${config.services.etebase-server.dataDir}/static"''; description = "The directory for static files."; }; - media_root = mkOption { - type = types.str; + media_root = lib.mkOption { + type = lib.types.str; default = "${cfg.dataDir}/media"; - defaultText = literalExpression ''"''${config.services.etebase-server.dataDir}/media"''; + defaultText = lib.literalExpression ''"''${config.services.etebase-server.dataDir}/media"''; description = "The media directory."; }; }; allowed_hosts = { - allowed_host1 = mkOption { - type = types.str; + allowed_host1 = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; example = "localhost"; description = '' @@ -122,15 +119,15 @@ in }; }; database = { - engine = mkOption { - type = types.enum [ "django.db.backends.sqlite3" "django.db.backends.postgresql" ]; + engine = lib.mkOption { + type = lib.types.enum [ "django.db.backends.sqlite3" "django.db.backends.postgresql" ]; default = "django.db.backends.sqlite3"; description = "The database engine to use."; }; - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = "${cfg.dataDir}/db.sqlite3"; - defaultText = literalExpression ''"''${config.services.etebase-server.dataDir}/db.sqlite3"''; + defaultText = lib.literalExpression ''"''${config.services.etebase-server.dataDir}/db.sqlite3"''; description = "The database name."; }; }; @@ -154,15 +151,15 @@ in }; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = defaultUser; description = "User under which Etebase server runs."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs; [ (runCommand "etebase-server" { @@ -170,7 +167,7 @@ in } '' makeWrapper ${cfg.package}/bin/etebase-server \ $out/bin/etebase-server \ - --chdir ${escapeShellArg cfg.dataDir} \ + --chdir ${lib.escapeShellArg cfg.dataDir} \ --prefix ETEBASE_EASY_CONFIG_PATH : "${configIni}" '') ]; @@ -217,7 +214,7 @@ in ''; }; - users = optionalAttrs (cfg.user == defaultUser) { + users = lib.optionalAttrs (cfg.user == defaultUser) { users.${defaultUser} = { isSystemUser = true; group = defaultUser; @@ -227,7 +224,7 @@ in groups.${defaultUser} = {}; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; }; diff --git a/nixos/modules/services/misc/etesync-dav.nix b/nixos/modules/services/misc/etesync-dav.nix index ea659c61bd5a..2cccc51d1fbf 100644 --- a/nixos/modules/services/misc/etesync-dav.nix +++ b/nixos/modules/services/misc/etesync-dav.nix @@ -1,40 +1,37 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.etesync-dav; in { options.services.etesync-dav = { - enable = mkEnableOption "etesync-dav, end-to-end encrypted sync for contacts, calendars and tasks"; + enable = lib.mkEnableOption "etesync-dav, end-to-end encrypted sync for contacts, calendars and tasks"; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = "The server host address."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 37358; description = "The server host port."; }; - apiUrl = mkOption { - type = types.str; + apiUrl = lib.mkOption { + type = lib.types.str; default = "https://api.etesync.com/"; description = "The url to the etesync API."; }; - openFirewall = mkOption { + openFirewall = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "Whether to open the firewall for the specified port."; }; - sslCertificate = mkOption { - type = types.nullOr types.path; + sslCertificate = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/var/etesync.crt"; description = '' @@ -43,8 +40,8 @@ in ''; }; - sslCertificateKey = mkOption { - type = types.nullOr types.path; + sslCertificateKey = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/var/etesync.key"; description = '' @@ -54,8 +51,8 @@ in }; }; - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + config = lib.mkIf cfg.enable { + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; systemd.services.etesync-dav = { description = "etesync-dav - A CalDAV and CardDAV adapter for EteSync"; @@ -75,12 +72,12 @@ in DynamicUser = true; StateDirectory = "etesync-dav"; ExecStart = "${pkgs.etesync-dav}/bin/etesync-dav"; - ExecStartPre = mkIf (cfg.sslCertificate != null || cfg.sslCertificateKey != null) ( + ExecStartPre = lib.mkIf (cfg.sslCertificate != null || cfg.sslCertificateKey != null) ( pkgs.writers.writeBash "etesync-dav-copy-keys" '' - ${optionalString (cfg.sslCertificate != null) '' + ${lib.optionalString (cfg.sslCertificate != null) '' cp ${toString cfg.sslCertificate} $STATE_DIRECTORY/etesync.crt ''} - ${optionalString (cfg.sslCertificateKey != null) '' + ${lib.optionalString (cfg.sslCertificateKey != null) '' cp ${toString cfg.sslCertificateKey} $STATE_DIRECTORY/etesync.key ''} '' diff --git a/nixos/modules/services/misc/evdevremapkeys.nix b/nixos/modules/services/misc/evdevremapkeys.nix index e559dd89dc9f..754bce9f03d2 100644 --- a/nixos/modules/services/misc/evdevremapkeys.nix +++ b/nixos/modules/services/misc/evdevremapkeys.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let format = pkgs.formats.yaml { }; cfg = config.services.evdevremapkeys; @@ -8,9 +6,9 @@ let in { options.services.evdevremapkeys = { - enable = mkEnableOption ''evdevremapkeys, a daemon to remap events on linux input devices''; + enable = lib.mkEnableOption ''evdevremapkeys, a daemon to remap events on linux input devices''; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; description = '' @@ -19,7 +17,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "uinput" ]; services.udev.extraRules = '' KERNEL=="uinput", MODE="0660", GROUP="input" diff --git a/nixos/modules/services/misc/felix.nix b/nixos/modules/services/misc/felix.nix index 0283de128afe..3def12e3adef 100644 --- a/nixos/modules/services/misc/felix.nix +++ b/nixos/modules/services/misc/felix.nix @@ -1,8 +1,5 @@ # Felix server { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.felix; @@ -17,23 +14,23 @@ in services.felix = { - enable = mkEnableOption "the Apache Felix OSGi service"; + enable = lib.mkEnableOption "the Apache Felix OSGi service"; - bundles = mkOption { - type = types.listOf types.package; + bundles = lib.mkOption { + type = lib.types.listOf lib.types.package; default = [ pkgs.felix_remoteshell ]; - defaultText = literalExpression "[ pkgs.felix_remoteshell ]"; + defaultText = lib.literalExpression "[ pkgs.felix_remoteshell ]"; description = "List of bundles that should be activated on startup"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "osgi"; description = "User account under which Apache Felix runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "osgi"; description = "Group account under which Apache Felix runs."; }; @@ -45,7 +42,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.groups.osgi.gid = config.ids.gids.osgi; users.users.osgi = diff --git a/nixos/modules/services/misc/freeswitch.nix b/nixos/modules/services/misc/freeswitch.nix index e90d9838fcb7..eace38229ca5 100644 --- a/nixos/modules/services/misc/freeswitch.nix +++ b/nixos/modules/services/misc/freeswitch.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ...}: -with lib; let cfg = config.services.freeswitch; pkg = cfg.package; @@ -7,7 +6,7 @@ let mkdir -p $out cp -rT ${cfg.configTemplate} $out chmod -R +w $out - ${concatStringsSep "\n" (mapAttrsToList (fileName: filePath: '' + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (fileName: filePath: '' mkdir -p $out/$(dirname ${fileName}) cp ${filePath} $out/${fileName} '') cfg.configDir)} @@ -18,10 +17,10 @@ let in { options = { services.freeswitch = { - enable = mkEnableOption "FreeSWITCH"; - enableReload = mkOption { + enable = lib.mkEnableOption "FreeSWITCH"; + enableReload = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Issue the `reloadxml` command to FreeSWITCH when configuration directory changes (instead of restart). See [FreeSWITCH documentation](https://freeswitch.org/confluence/display/FREESWITCH/Reloading) for more info. @@ -29,21 +28,21 @@ in { See also `systemd.services.*.restartIfChanged`. ''; }; - configTemplate = mkOption { - type = types.path; + configTemplate = lib.mkOption { + type = lib.types.path; default = "${config.services.freeswitch.package}/share/freeswitch/conf/vanilla"; - defaultText = literalExpression ''"''${config.services.freeswitch.package}/share/freeswitch/conf/vanilla"''; - example = literalExpression ''"''${config.services.freeswitch.package}/share/freeswitch/conf/minimal"''; + defaultText = lib.literalExpression ''"''${config.services.freeswitch.package}/share/freeswitch/conf/vanilla"''; + example = lib.literalExpression ''"''${config.services.freeswitch.package}/share/freeswitch/conf/minimal"''; description = '' Configuration template to use. See available templates in [FreeSWITCH repository](https://github.com/signalwire/freeswitch/tree/master/conf). You can also set your own configuration directory. ''; }; - configDir = mkOption { - type = with types; attrsOf path; + configDir = lib.mkOption { + type = with lib.types; attrsOf path; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "freeswitch.xml" = ./freeswitch.xml; "dialplan/default.xml" = pkgs.writeText "dialplan-default.xml" ''' @@ -58,14 +57,14 @@ in { Also check available templates in [FreeSWITCH repository](https://github.com/signalwire/freeswitch/tree/master/conf). ''; }; - package = mkPackageOption pkgs "freeswitch" { }; + package = lib.mkPackageOption pkgs "freeswitch" { }; }; }; - config = mkIf cfg.enable { - environment.etc.freeswitch = mkIf cfg.enableReload { + config = lib.mkIf cfg.enable { + environment.etc.freeswitch = lib.mkIf cfg.enableReload { source = configDirectory; }; - systemd.services.freeswitch-config-reload = mkIf cfg.enableReload { + systemd.services.freeswitch-config-reload = lib.mkIf cfg.enableReload { before = [ "freeswitch.service" ]; wantedBy = [ "multi-user.target" ]; restartTriggers = [ configDirectory ]; diff --git a/nixos/modules/services/misc/fstrim.nix b/nixos/modules/services/misc/fstrim.nix index 10dced2c4e64..f22505841fa3 100644 --- a/nixos/modules/services/misc/fstrim.nix +++ b/nixos/modules/services/misc/fstrim.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.fstrim; @@ -11,10 +8,12 @@ in { options = { services.fstrim = { - enable = mkEnableOption "periodic SSD TRIM of mounted partitions in background"; + enable = (lib.mkEnableOption "periodic SSD TRIM of mounted partitions in background" // { + default = true; + }); - interval = mkOption { - type = types.str; + interval = lib.mkOption { + type = lib.types.str; default = "weekly"; description = '' How often we run fstrim. For most desktop and server systems @@ -28,7 +27,7 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.packages = [ pkgs.util-linux ]; diff --git a/nixos/modules/services/misc/gammu-smsd.nix b/nixos/modules/services/misc/gammu-smsd.nix index b30258333af2..78f4e53815f2 100644 --- a/nixos/modules/services/misc/gammu-smsd.nix +++ b/nixos/modules/services/misc/gammu-smsd.nix @@ -1,6 +1,4 @@ { pkgs, lib, config, ... }: - -with lib; let cfg = config.services.gammu-smsd; @@ -10,7 +8,7 @@ let Connection = ${cfg.device.connection} SynchronizeTime = ${if cfg.device.synchronizeTime then "yes" else "no"} LogFormat = ${cfg.log.format} - ${optionalString (cfg.device.pin != null) "PIN = ${cfg.device.pin}"} + ${lib.optionalString (cfg.device.pin != null) "PIN = ${cfg.device.pin}"} ${cfg.extraConfig.gammu} @@ -18,25 +16,25 @@ let LogFile = ${cfg.log.file} Service = ${cfg.backend.service} - ${optionalString (cfg.backend.service == "files") '' + ${lib.optionalString (cfg.backend.service == "files") '' InboxPath = ${cfg.backend.files.inboxPath} OutboxPath = ${cfg.backend.files.outboxPath} SentSMSPath = ${cfg.backend.files.sentSMSPath} ErrorSMSPath = ${cfg.backend.files.errorSMSPath} ''} - ${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") '' + ${lib.optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") '' Driver = ${cfg.backend.sql.driver} DBDir = ${cfg.backend.sql.database} ''} - ${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") ( + ${lib.optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") ( with cfg.backend; '' Driver = ${sql.driver} - ${optionalString (sql.database!= null) "Database = ${sql.database}"} - ${optionalString (sql.host != null) "Host = ${sql.host}"} - ${optionalString (sql.user != null) "User = ${sql.user}"} - ${optionalString (sql.password != null) "Password = ${sql.password}"} + ${lib.optionalString (sql.database!= null) "Database = ${sql.database}"} + ${lib.optionalString (sql.host != null) "Host = ${sql.host}"} + ${lib.optionalString (sql.user != null) "User = ${sql.user}"} + ${lib.optionalString (sql.password != null) "Password = ${sql.password}"} '')} ${cfg.extraConfig.smsd} @@ -53,42 +51,42 @@ in { options = { services.gammu-smsd = { - enable = mkEnableOption "gammu-smsd daemon"; + enable = lib.mkEnableOption "gammu-smsd daemon"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "smsd"; description = "User that has access to the device"; }; device = { - path = mkOption { - type = types.path; + path = lib.mkOption { + type = lib.types.path; description = "Device node or address of the phone"; example = "/dev/ttyUSB2"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "root"; description = "Owner group of the device"; example = "dialout"; }; - connection = mkOption { - type = types.str; + connection = lib.mkOption { + type = lib.types.str; default = "at"; description = "Protocol which will be used to talk to the phone"; }; - synchronizeTime = mkOption { - type = types.bool; + synchronizeTime = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to set time from computer to the phone during starting connection"; }; - pin = mkOption { - type = types.nullOr types.str; + pin = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "PIN code for the simcard"; }; @@ -96,14 +94,14 @@ in { log = { - file = mkOption { - type = types.str; + file = lib.mkOption { + type = lib.types.str; default = "syslog"; description = "Path to file where information about communication will be stored"; }; - format = mkOption { - type = types.enum [ "nothing" "text" "textall" "textalldate" "errors" "errorsdate" "binary" ]; + format = lib.mkOption { + type = lib.types.enum [ "nothing" "text" "textall" "textalldate" "errors" "errorsdate" "binary" ]; default = "errors"; description = "Determines what will be logged to the LogFile"; }; @@ -111,15 +109,15 @@ in { extraConfig = { - gammu = mkOption { - type = types.lines; + gammu = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra config lines to be added into [gammu] section"; }; - smsd = mkOption { - type = types.lines; + smsd = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra config lines to be added into [smsd] section"; }; @@ -127,70 +125,70 @@ in { backend = { - service = mkOption { - type = types.enum [ "null" "files" "sql" ]; + service = lib.mkOption { + type = lib.types.enum [ "null" "files" "sql" ]; default = "null"; description = "Service to use to store sms data."; }; files = { - inboxPath = mkOption { - type = types.path; + inboxPath = lib.mkOption { + type = lib.types.path; default = "/var/spool/sms/inbox/"; description = "Where the received SMSes are stored"; }; - outboxPath = mkOption { - type = types.path; + outboxPath = lib.mkOption { + type = lib.types.path; default = "/var/spool/sms/outbox/"; description = "Where SMSes to be sent should be placed"; }; - sentSMSPath = mkOption { - type = types.path; + sentSMSPath = lib.mkOption { + type = lib.types.path; default = "/var/spool/sms/sent/"; description = "Where the transmitted SMSes are placed"; }; - errorSMSPath = mkOption { - type = types.path; + errorSMSPath = lib.mkOption { + type = lib.types.path; default = "/var/spool/sms/error/"; description = "Where SMSes with error in transmission is placed"; }; }; sql = { - driver = mkOption { - type = types.enum [ "native_mysql" "native_pgsql" "odbc" "dbi" ]; + driver = lib.mkOption { + type = lib.types.enum [ "native_mysql" "native_pgsql" "odbc" "dbi" ]; description = "DB driver to use"; }; - sqlDialect = mkOption { - type = types.nullOr types.str; + sqlDialect = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "SQL dialect to use (odbc driver only)"; }; - database = mkOption { - type = types.nullOr types.str; + database = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "Database name to store sms data"; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = "Database server address"; }; - user = mkOption { - type = types.nullOr types.str; + user = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "User name used for connection to the database"; }; - password = mkOption { - type = types.nullOr types.str; + password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "User password used for connection to the database"; }; @@ -199,7 +197,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.${cfg.user} = { description = "gammu-smsd user"; isSystemUser = true; @@ -207,7 +205,7 @@ in { }; environment.systemPackages = with cfg.backend; [ gammuPackage ] - ++ optionals (service == "sql" && sql.driver == "sqlite") [ pkgs.sqlite ]; + ++ lib.optionals (service == "sql" && sql.driver == "sqlite") [ pkgs.sqlite ]; systemd.services.gammu-smsd = { description = "gammu-smsd daemon"; @@ -215,29 +213,29 @@ in { wantedBy = [ "multi-user.target" ]; wants = with cfg.backend; [ ] - ++ optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ]; + ++ lib.optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ]; preStart = with cfg.backend; - optionalString (service == "files") (with files; '' + lib.optionalString (service == "files") (with files; '' mkdir -m 755 -p ${inboxPath} ${outboxPath} ${sentSMSPath} ${errorSMSPath} chown ${cfg.user} -R ${inboxPath} chown ${cfg.user} -R ${outboxPath} chown ${cfg.user} -R ${sentSMSPath} chown ${cfg.user} -R ${errorSMSPath} '') - + optionalString (service == "sql" && sql.driver == "sqlite") '' + + lib.optionalString (service == "sql" && sql.driver == "sqlite") '' cat "${gammuPackage}/${initDBDir}/sqlite.sql" \ | ${pkgs.sqlite.bin}/bin/sqlite3 ${sql.database} '' - + (let execPsql = extraArgs: concatStringsSep " " [ - (optionalString (sql.password != null) "PGPASSWORD=${sql.password}") + + (let execPsql = extraArgs: lib.concatStringsSep " " [ + (lib.optionalString (sql.password != null) "PGPASSWORD=${sql.password}") "${config.services.postgresql.package}/bin/psql" - (optionalString (sql.host != null) "-h ${sql.host}") - (optionalString (sql.user != null) "-U ${sql.user}") + (lib.optionalString (sql.host != null) "-h ${sql.host}") + (lib.optionalString (sql.user != null) "-U ${sql.user}") "$extraArgs" "${sql.database}" - ]; in optionalString (service == "sql" && sql.driver == "native_pgsql") '' + ]; in lib.optionalString (service == "sql" && sql.driver == "native_pgsql") '' echo '\i '"${gammuPackage}/${initDBDir}/pgsql.sql" | ${execPsql ""} ''); diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 9fd6014f2c71..ecbc087f739f 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -1127,6 +1127,11 @@ in { environment.systemPackages = [ gitlab-rake gitlab-rails cfg.packages.gitlab-shell ]; + systemd.slices.system-gitlab = { + description = "GitLab DevOps Platform Slice"; + documentation = [ "https://docs.gitlab.com/" ]; + }; + systemd.targets.gitlab = { description = "Common target for all GitLab services."; wantedBy = [ "multi-user.target" ]; @@ -1197,6 +1202,7 @@ in { ''; serviceConfig = { + Slice = "system-gitlab.slice"; User = pgsql.superUser; Type = "oneshot"; RemainAfterExit = true; @@ -1220,6 +1226,9 @@ in { unitConfig = { ConditionPathExists = "!${cfg.registry.certFile}"; }; + serviceConfig = { + Slice = "system-gitlab.slice"; + }; }; # Ensure Docker Registry launches after the certificate generation job @@ -1308,6 +1317,7 @@ in { TimeoutSec = "infinity"; Restart = "on-failure"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + Slice = "system-gitlab.slice"; RemainAfterExit = true; ExecStartPre = let @@ -1424,6 +1434,7 @@ in { TimeoutSec = "infinity"; Restart = "on-failure"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + Slice = "system-gitlab.slice"; RemainAfterExit = true; ExecStart = pkgs.writeShellScript "gitlab-db-config" '' @@ -1480,6 +1491,7 @@ in { TimeoutSec = "infinity"; Restart = "always"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + Slice = "system-gitlab.slice"; ExecStart = utils.escapeSystemdExecArgs ( [ "${cfg.packages.gitlab}/share/gitlab/bin/sidekiq-cluster" @@ -1512,6 +1524,7 @@ in { Restart = "on-failure"; WorkingDirectory = gitlabEnv.HOME; RuntimeDirectory = "gitaly"; + Slice = "system-gitlab.slice"; ExecStart = "${cfg.packages.gitaly}/bin/gitaly ${gitalyToml}"; }; }; @@ -1573,6 +1586,7 @@ in { WorkingDirectory = gitlabEnv.HOME; RuntimeDirectory = "gitlab-pages"; RuntimeDirectoryMode = "0700"; + Slice = "system-gitlab.slice"; }; }; @@ -1596,6 +1610,7 @@ in { TimeoutSec = "infinity"; Restart = "on-failure"; WorkingDirectory = gitlabEnv.HOME; + Slice = "system-gitlab.slice"; ExecStartPre = pkgs.writeShellScript "gitlab-workhorse-pre-start" '' set -o errexit -o pipefail -o nounset shopt -s dotglob nullglob inherit_errexit @@ -1637,6 +1652,7 @@ in { Group = cfg.group; ExecStart = "${cfg.packages.gitlab.rubyEnv}/bin/bundle exec mail_room -c ${cfg.statePath}/config/mail_room.yml"; WorkingDirectory = gitlabEnv.HOME; + Slice = "system-gitlab.slice"; }; }; @@ -1671,6 +1687,7 @@ in { TimeoutSec = "infinity"; Restart = "on-failure"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + Slice = "system-gitlab.slice"; ExecStart = concatStringsSep " " [ "${cfg.packages.gitlab.rubyEnv}/bin/bundle" "exec" "puma" "-e production" @@ -1695,6 +1712,7 @@ in { serviceConfig = { User = cfg.user; Group = cfg.group; + Slice = "system-gitlab.slice"; ExecStart = "${gitlab-rake}/bin/gitlab-rake gitlab:backup:create"; }; }; diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix index 89f72c046755..779a9ac9929d 100644 --- a/nixos/modules/services/misc/gitolite.nix +++ b/nixos/modules/services/misc/gitolite.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.gitolite; # Use writeTextDir to not leak Nix store hash into file name @@ -11,8 +8,8 @@ in { options = { services.gitolite = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable gitolite management under the @@ -22,8 +19,8 @@ in ''; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/gitolite"; description = '' The gitolite home directory used to store all repositories. If left as the default value @@ -33,8 +30,8 @@ in ''; }; - adminPubkey = mkOption { - type = types.str; + adminPubkey = lib.mkOption { + type = lib.types.str; description = '' Initial administrative public key for Gitolite. This should be an SSH Public Key. Note that this key will only be used @@ -43,8 +40,8 @@ in ''; }; - enableGitAnnex = mkOption { - type = types.bool; + enableGitAnnex = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable git-annex support. Uses the `extraGitoliteRc` option @@ -52,18 +49,18 @@ in ''; }; - commonHooks = mkOption { - type = types.listOf types.path; + commonHooks = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' A list of custom git hooks that get copied to `~/.gitolite/hooks/common`. ''; }; - extraGitoliteRc = mkOption { - type = types.lines; + extraGitoliteRc = lib.mkOption { + type = lib.types.lines; default = ""; - example = literalExpression '' + example = lib.literalExpression '' ''' $RC{UMASK} = 0027; $RC{SITE_INFO} = 'This is our private repository host'; @@ -93,24 +90,24 @@ in ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "gitolite"; description = '' Gitolite user account. This is the username of the gitolite endpoint. ''; }; - description = mkOption { - type = types.str; + description = lib.mkOption { + type = lib.types.str; default = "Gitolite user"; description = '' Gitolite user account's description. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "gitolite"; description = '' Primary group of the Gitolite user account. @@ -119,7 +116,7 @@ in }; }; - config = mkIf cfg.enable ( + config = lib.mkIf cfg.enable ( let manageGitoliteRc = cfg.extraGitoliteRc != ""; rcDir = pkgs.runCommand "gitolite-rc" { preferLocalBuild = true; } rcDirScript; @@ -136,18 +133,18 @@ in END cat "$out/gitolite.rc.default" >>"$out/gitolite.rc" '' + - optionalString (cfg.extraGitoliteRc != "") '' - echo -n ${escapeShellArg '' + lib.optionalString (cfg.extraGitoliteRc != "") '' + echo -n ${lib.escapeShellArg '' # Added by NixOS: - ${removeSuffix "\n" cfg.extraGitoliteRc} + ${lib.removeSuffix "\n" cfg.extraGitoliteRc} # per perl rules, this should be the last line in such a file: 1; ''} >>"$out/gitolite.rc" ''; in { - services.gitolite.extraGitoliteRc = optionalString cfg.enableGitAnnex '' + services.gitolite.extraGitoliteRc = lib.optionalString cfg.enableGitAnnex '' # Enable git-annex support: push( @{$RC{ENABLE}}, 'git-annex-shell ua'); ''; @@ -171,8 +168,8 @@ in GITOLITE_RC_DEFAULT = "${rcDir}/gitolite.rc.default"; }; - serviceConfig = mkMerge [ - (mkIf (cfg.dataDir == "/var/lib/gitolite") { + serviceConfig = lib.mkMerge [ + (lib.mkIf (cfg.dataDir == "/var/lib/gitolite") { StateDirectory = "gitolite gitolite/.gitolite gitolite/.gitolite/logs"; StateDirectoryMode = "0750"; }) @@ -236,6 +233,6 @@ in }; environment.systemPackages = [ pkgs.gitolite pkgs.git ] - ++ optional cfg.enableGitAnnex pkgs.git-annex; + ++ lib.optional cfg.enableGitAnnex pkgs.git-annex; }); } diff --git a/nixos/modules/services/misc/gitweb.nix b/nixos/modules/services/misc/gitweb.nix index 8f4869ce5d55..fb31deb8538a 100644 --- a/nixos/modules/services/misc/gitweb.nix +++ b/nixos/modules/services/misc/gitweb.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.gitweb; @@ -10,18 +7,18 @@ in options.services.gitweb = { - projectroot = mkOption { + projectroot = lib.mkOption { default = "/srv/git"; - type = types.path; + type = lib.types.path; description = '' Path to git projects (bare repositories) that should be served by gitweb. Must not end with a slash. ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Verbatim configuration text appended to the generated gitweb.conf file. ''; @@ -32,23 +29,23 @@ in ''; }; - gitwebTheme = mkOption { + gitwebTheme = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Use an alternative theme for gitweb, strongly inspired by GitHub. ''; }; - gitwebConfigFile = mkOption { + gitwebConfigFile = lib.mkOption { default = pkgs.writeText "gitweb.conf" '' # path to git projects (.git) $projectroot = "${cfg.projectroot}"; $highlight_bin = "${pkgs.highlight}/bin/highlight"; ${cfg.extraConfig} ''; - defaultText = literalMD "generated config file"; - type = types.path; + defaultText = lib.literalMD "generated config file"; + type = lib.types.path; readOnly = true; internal = true; }; diff --git a/nixos/modules/services/misc/gogs.nix b/nixos/modules/services/misc/gogs.nix deleted file mode 100644 index e4e23d597237..000000000000 --- a/nixos/modules/services/misc/gogs.nix +++ /dev/null @@ -1,274 +0,0 @@ -{ config, lib, options, pkgs, ... }: - -with lib; - -let - cfg = config.services.gogs; - opt = options.services.gogs; - configFile = pkgs.writeText "app.ini" '' - BRAND_NAME = ${cfg.appName} - RUN_USER = ${cfg.user} - RUN_MODE = prod - - [database] - TYPE = ${cfg.database.type} - HOST = ${cfg.database.host}:${toString cfg.database.port} - NAME = ${cfg.database.name} - USER = ${cfg.database.user} - PASSWORD = #dbpass# - PATH = ${cfg.database.path} - - [repository] - ROOT = ${cfg.repositoryRoot} - - [server] - DOMAIN = ${cfg.domain} - HTTP_ADDR = ${cfg.httpAddress} - HTTP_PORT = ${toString cfg.httpPort} - EXTERNAL_URL = ${cfg.rootUrl} - - [session] - COOKIE_NAME = session - COOKIE_SECURE = ${boolToString cfg.cookieSecure} - - [security] - SECRET_KEY = #secretkey# - INSTALL_LOCK = true - - [log] - ROOT_PATH = ${cfg.stateDir}/log - - ${cfg.extraConfig} - ''; -in - -{ - options = { - services.gogs = { - enable = mkOption { - default = false; - type = types.bool; - description = "Enable Go Git Service."; - }; - - useWizard = mkOption { - default = false; - type = types.bool; - description = "Do not generate a configuration and use Gogs' installation wizard instead. The first registered user will be administrator."; - }; - - stateDir = mkOption { - default = "/var/lib/gogs"; - type = types.str; - description = "Gogs data directory."; - }; - - user = mkOption { - type = types.str; - default = "gogs"; - description = "User account under which Gogs runs."; - }; - - group = mkOption { - type = types.str; - default = "gogs"; - description = "Group account under which Gogs runs."; - }; - - database = { - type = mkOption { - type = types.enum [ "sqlite3" "mysql" "postgres" ]; - example = "mysql"; - default = "sqlite3"; - description = "Database engine to use."; - }; - - host = mkOption { - type = types.str; - default = "127.0.0.1"; - description = "Database host address."; - }; - - port = mkOption { - type = types.port; - default = 3306; - description = "Database host port."; - }; - - name = mkOption { - type = types.str; - default = "gogs"; - description = "Database name."; - }; - - user = mkOption { - type = types.str; - default = "gogs"; - description = "Database user."; - }; - - password = mkOption { - type = types.str; - default = ""; - description = '' - The password corresponding to {option}`database.user`. - Warning: this is stored in cleartext in the Nix store! - Use {option}`database.passwordFile` instead. - ''; - }; - - passwordFile = mkOption { - type = types.nullOr types.path; - default = null; - example = "/run/keys/gogs-dbpassword"; - description = '' - A file containing the password corresponding to - {option}`database.user`. - ''; - }; - - path = mkOption { - type = types.str; - default = "${cfg.stateDir}/data/gogs.db"; - defaultText = literalExpression ''"''${config.${opt.stateDir}}/data/gogs.db"''; - description = "Path to the sqlite3 database file."; - }; - }; - - appName = mkOption { - type = types.str; - default = "Gogs: Go Git Service"; - description = "Application name."; - }; - - repositoryRoot = mkOption { - type = types.str; - default = "${cfg.stateDir}/repositories"; - defaultText = literalExpression ''"''${config.${opt.stateDir}}/repositories"''; - description = "Path to the git repositories."; - }; - - domain = mkOption { - type = types.str; - default = "localhost"; - description = "Domain name of your server."; - }; - - rootUrl = mkOption { - type = types.str; - default = "http://localhost:3000/"; - description = "Full public URL of Gogs server."; - }; - - httpAddress = mkOption { - type = types.str; - default = "0.0.0.0"; - description = "HTTP listen address."; - }; - - httpPort = mkOption { - type = types.port; - default = 3000; - description = "HTTP listen port."; - }; - - cookieSecure = mkOption { - type = types.bool; - default = false; - description = '' - Marks session cookies as "secure" as a hint for browsers to only send - them via HTTPS. This option is recommend, if Gogs is being served over HTTPS. - ''; - }; - - extraConfig = mkOption { - type = types.str; - default = ""; - description = "Configuration lines appended to the generated Gogs configuration file."; - }; - }; - }; - - config = mkIf cfg.enable { - - systemd.services.gogs = { - description = "Gogs (Go Git Service)"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.gogs ]; - - preStart = let - runConfig = "${cfg.stateDir}/custom/conf/app.ini"; - secretKey = "${cfg.stateDir}/custom/conf/secret_key"; - in '' - mkdir -p ${cfg.stateDir} - - # copy custom configuration and generate a random secret key if needed - ${optionalString (cfg.useWizard == false) '' - mkdir -p ${cfg.stateDir}/custom/conf - cp -f ${configFile} ${runConfig} - - if [ ! -e ${secretKey} ]; then - head -c 16 /dev/urandom | base64 > ${secretKey} - fi - - KEY=$(head -n1 ${secretKey}) - DBPASS=$(head -n1 ${cfg.database.passwordFile}) - sed -e "s,#secretkey#,$KEY,g" \ - -e "s,#dbpass#,$DBPASS,g" \ - -i ${runConfig} - ''} - - mkdir -p ${cfg.repositoryRoot} - # update all hooks' binary paths - HOOKS=$(find ${cfg.repositoryRoot} -mindepth 4 -maxdepth 4 -type f -wholename "*git/hooks/*") - if [ "$HOOKS" ] - then - sed -ri 's,/nix/store/[a-z0-9.-]+/bin/gogs,${pkgs.gogs}/bin/gogs,g' $HOOKS - sed -ri 's,/nix/store/[a-z0-9.-]+/bin/env,${pkgs.coreutils}/bin/env,g' $HOOKS - sed -ri 's,/nix/store/[a-z0-9.-]+/bin/bash,${pkgs.bash}/bin/bash,g' $HOOKS - sed -ri 's,/nix/store/[a-z0-9.-]+/bin/perl,${pkgs.perl}/bin/perl,g' $HOOKS - fi - ''; - - serviceConfig = { - Type = "simple"; - User = cfg.user; - Group = cfg.group; - WorkingDirectory = cfg.stateDir; - ExecStart = "${pkgs.gogs}/bin/gogs web"; - Restart = "always"; - UMask = "0027"; - }; - - environment = { - USER = cfg.user; - HOME = cfg.stateDir; - GOGS_WORK_DIR = cfg.stateDir; - }; - }; - - users = mkIf (cfg.user == "gogs") { - users.gogs = { - description = "Go Git Service"; - uid = config.ids.uids.gogs; - group = "gogs"; - home = cfg.stateDir; - createHome = true; - shell = pkgs.bash; - }; - groups.gogs.gid = config.ids.gids.gogs; - }; - - warnings = optional (cfg.database.password != "") - ''config.services.gogs.database.password will be stored as plaintext - in the Nix store. Use database.passwordFile instead.''; - - # Create database passwordFile default when password is configured. - services.gogs.database.passwordFile = - (mkDefault (toString (pkgs.writeTextFile { - name = "gogs-database-password"; - text = cfg.database.password; - }))); - }; -} diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix index fb9b9e19813f..ccfa63d3823d 100644 --- a/nixos/modules/services/misc/gollum.nix +++ b/nixos/modules/services/misc/gollum.nix @@ -4,16 +4,13 @@ pkgs, ... }: - -with lib; - let cfg = config.services.gollum; in { imports = [ - (mkRemovedOptionModule + (lib.mkRemovedOptionModule [ "services" "gollum" @@ -24,35 +21,35 @@ in ]; options.services.gollum = { - enable = mkEnableOption "Gollum, a git-powered wiki service"; + enable = lib.mkEnableOption "Gollum, a git-powered wiki service"; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = "IP address on which the web server will listen."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 4567; description = "Port on which the web server will run."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Content of the configuration file"; }; - math = mkOption { - type = types.bool; + math = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable support for math rendering using KaTeX"; }; - allowUploads = mkOption { - type = types.nullOr ( - types.enum [ + allowUploads = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ "dir" "page" ] @@ -61,9 +58,9 @@ in description = "Enable uploads of external files"; }; - user-icons = mkOption { - type = types.nullOr ( - types.enum [ + user-icons = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ "gravatar" "identicon" ] @@ -72,61 +69,61 @@ in description = "Enable specific user icons for history view"; }; - emoji = mkOption { - type = types.bool; + emoji = lib.mkOption { + type = lib.types.bool; default = false; description = "Parse and interpret emoji tags"; }; - h1-title = mkOption { - type = types.bool; + h1-title = lib.mkOption { + type = lib.types.bool; default = false; description = "Use the first h1 as page title"; }; - no-edit = mkOption { - type = types.bool; + no-edit = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable editing pages"; }; - local-time = mkOption { - type = types.bool; + local-time = lib.mkOption { + type = lib.types.bool; default = false; description = "Use the browser's local timezone instead of the server's for displaying dates."; }; - branch = mkOption { - type = types.str; + branch = lib.mkOption { + type = lib.types.str; default = "master"; example = "develop"; description = "Git branch to serve"; }; - stateDir = mkOption { - type = types.path; + stateDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/gollum"; description = "Specifies the path of the repository directory. If it does not exist, Gollum will create it on startup."; }; - package = mkPackageOption pkgs "gollum" { }; + package = lib.mkPackageOption pkgs "gollum" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "gollum"; description = "Specifies the owner of the wiki directory"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "gollum"; description = "Specifies the owner group of the wiki directory"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users.gollum = mkIf (cfg.user == "gollum") { + users.users.gollum = lib.mkIf (cfg.user == "gollum") { group = cfg.group; description = "Gollum user"; createHome = false; @@ -158,13 +155,13 @@ in --host ${cfg.address} \ --config ${pkgs.writeText "gollum-config.rb" cfg.extraConfig} \ --ref ${cfg.branch} \ - ${optionalString cfg.math "--math"} \ - ${optionalString cfg.emoji "--emoji"} \ - ${optionalString cfg.h1-title "--h1-title"} \ - ${optionalString cfg.no-edit "--no-edit"} \ - ${optionalString cfg.local-time "--local-time"} \ - ${optionalString (cfg.allowUploads != null) "--allow-uploads ${cfg.allowUploads}"} \ - ${optionalString (cfg.user-icons != null) "--user-icons ${cfg.user-icons}"} \ + ${lib.optionalString cfg.math "--math"} \ + ${lib.optionalString cfg.emoji "--emoji"} \ + ${lib.optionalString cfg.h1-title "--h1-title"} \ + ${lib.optionalString cfg.no-edit "--no-edit"} \ + ${lib.optionalString cfg.local-time "--local-time"} \ + ${lib.optionalString (cfg.allowUploads != null) "--allow-uploads ${cfg.allowUploads}"} \ + ${lib.optionalString (cfg.user-icons != null) "--user-icons ${cfg.user-icons}"} \ ${cfg.stateDir} ''; }; diff --git a/nixos/modules/services/misc/gotenberg.nix b/nixos/modules/services/misc/gotenberg.nix index 57932c656d63..ed8629a7fa46 100644 --- a/nixos/modules/services/misc/gotenberg.nix +++ b/nixos/modules/services/misc/gotenberg.nix @@ -244,7 +244,6 @@ in SystemCallFilter = [ "@system-service" - "~@resources" "~@privileged" ]; SystemCallArchitectures = "native"; diff --git a/nixos/modules/services/misc/gpsd.nix b/nixos/modules/services/misc/gpsd.nix index 6f7aec0784a0..76aa151f204a 100644 --- a/nixos/modules/services/misc/gpsd.nix +++ b/nixos/modules/services/misc/gpsd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, utils, ... }: - -with lib; - let uid = config.ids.uids.gpsd; @@ -21,16 +18,16 @@ in { services.gpsd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable `gpsd`, a GPS service daemon. ''; }; - devices = mkOption { - type = types.listOf types.str; + devices = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "/dev/ttyUSB0" ]; description = '' List of devices that `gpsd` should subscribe to. @@ -43,8 +40,8 @@ in { ''; }; - readonly = mkOption { - type = types.bool; + readonly = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable the broken-device-safety, otherwise @@ -60,40 +57,40 @@ in { ''; }; - nowait = mkOption { - type = types.bool; + nowait = lib.mkOption { + type = lib.types.bool; default = false; description = '' don't wait for client connects to poll GPS ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 2947; description = '' The port where to listen for TCP connections. ''; }; - debugLevel = mkOption { - type = types.int; + debugLevel = lib.mkOption { + type = lib.types.int; default = 0; description = '' The debugging level. ''; }; - listenany = mkOption { - type = types.bool; + listenany = lib.mkOption { + type = lib.types.bool; default = false; description = '' Listen on all addresses rather than just loopback. ''; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "-r" "-s" "19200" ]; description = '' @@ -108,7 +105,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.gpsd = { inherit uid; @@ -131,9 +128,9 @@ in { in '' ${pkgs.gpsd}/sbin/gpsd -D "${toString cfg.debugLevel}" \ -S "${toString cfg.port}" \ - ${optionalString cfg.readonly "-b"} \ - ${optionalString cfg.nowait "-n"} \ - ${optionalString cfg.listenany "-G"} \ + ${lib.optionalString cfg.readonly "-b"} \ + ${lib.optionalString cfg.nowait "-n"} \ + ${lib.optionalString cfg.listenany "-G"} \ ${extraArgs} \ ${devices} ''; diff --git a/nixos/modules/services/misc/graphical-desktop.nix b/nixos/modules/services/misc/graphical-desktop.nix index 0b5ef033e38b..7f1e9b39210c 100644 --- a/nixos/modules/services/misc/graphical-desktop.nix +++ b/nixos/modules/services/misc/graphical-desktop.nix @@ -55,6 +55,12 @@ in services.speechd.enable = lib.mkDefault true; + services.pipewire = { + enable = lib.mkDefault true; + pulse.enable = lib.mkDefault true; + alsa.enable = lib.mkDefault true; + }; + systemd.defaultUnit = lib.mkIf (xcfg.autorun || dmcfg.enable) "graphical.target"; xdg = { diff --git a/nixos/modules/services/misc/greenclip.nix b/nixos/modules/services/misc/greenclip.nix index d92cd1854877..ce44ad4f6663 100644 --- a/nixos/modules/services/misc/greenclip.nix +++ b/nixos/modules/services/misc/greenclip.nix @@ -1,18 +1,15 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.greenclip; in { options.services.greenclip = { - enable = mkEnableOption "Greenclip, a clipboard manager"; + enable = lib.mkEnableOption "Greenclip, a clipboard manager"; - package = mkPackageOption pkgs [ "haskellPackages" "greenclip" ] { }; + package = lib.mkPackageOption pkgs [ "haskellPackages" "greenclip" ] { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.greenclip = { enable = true; description = "greenclip daemon"; diff --git a/nixos/modules/services/misc/headphones.nix b/nixos/modules/services/misc/headphones.nix index 31bd61cb4c20..b56322b0cbcc 100644 --- a/nixos/modules/services/misc/headphones.nix +++ b/nixos/modules/services/misc/headphones.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let name = "headphones"; @@ -17,39 +14,39 @@ in options = { services.headphones = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable the headphones server."; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/${name}"; description = "Path where to store data files."; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = "${cfg.dataDir}/config.ini"; - defaultText = literalExpression ''"''${config.${opt.dataDir}}/config.ini"''; + defaultText = lib.literalExpression ''"''${config.${opt.dataDir}}/config.ini"''; description = "Path to config file."; }; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "localhost"; description = "Host to listen on."; }; - port = mkOption { - type = types.ints.u16; + port = lib.mkOption { + type = lib.types.ints.u16; default = 8181; description = "Port to bind to."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = name; description = "User to run the service as"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = name; description = "Group to run the service as"; }; @@ -59,9 +56,9 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == name) { + users.users = lib.optionalAttrs (cfg.user == name) { ${name} = { uid = config.ids.uids.headphones; group = cfg.group; @@ -71,7 +68,7 @@ in }; }; - users.groups = optionalAttrs (cfg.group == name) { + users.groups = lib.optionalAttrs (cfg.group == name) { ${name}.gid = config.ids.gids.headphones; }; diff --git a/nixos/modules/services/misc/heisenbridge.nix b/nixos/modules/services/misc/heisenbridge.nix index 54c298f1b560..d8c5ec80e892 100644 --- a/nixos/modules/services/misc/heisenbridge.nix +++ b/nixos/modules/services/misc/heisenbridge.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.heisenbridge; @@ -23,18 +20,18 @@ let in { options.services.heisenbridge = { - enable = mkEnableOption "the Matrix to IRC bridge"; + enable = lib.mkEnableOption "the Matrix to IRC bridge"; - package = mkPackageOption pkgs "heisenbridge" { }; + package = lib.mkPackageOption pkgs "heisenbridge" { }; - homeserver = mkOption { - type = types.str; + homeserver = lib.mkOption { + type = lib.types.str; description = "The URL to the home server for client-server API calls"; example = "http://localhost:8008"; }; - registrationUrl = mkOption { - type = types.str; + registrationUrl = lib.mkOption { + type = lib.types.str; description = '' The URL where the application service is listening for HS requests, from the Matrix HS perspective.# The default value assumes the bridge runs on the same host as the home server, in the same network. @@ -44,27 +41,27 @@ in defaultText = "http://$${cfg.address}:$${toString cfg.port}"; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; description = "Address to listen on. IPv6 does not seem to be supported."; default = "127.0.0.1"; example = "0.0.0.0"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; description = "The port to listen on"; default = 9898; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; description = "More verbose logging. Recommended during initial setup."; default = false; }; - owner = mkOption { - type = types.nullOr types.str; + owner = lib.mkOption { + type = lib.types.nullOr lib.types.str; description = '' Set owner MXID otherwise first talking local user will claim the bridge ''; @@ -72,10 +69,10 @@ in example = "@admin:example.org"; }; - namespaces = mkOption { + namespaces = lib.mkOption { description = "Configure the 'namespaces' section of the registration.yml for the bridge and the server"; # TODO link to Matrix documentation of the format - type = types.submodule { + type = lib.types.submodule { freeformType = jsonType; }; @@ -91,21 +88,21 @@ in }; }; - identd.enable = mkEnableOption "identd service support"; - identd.port = mkOption { - type = types.port; + identd.enable = lib.mkEnableOption "identd service support"; + identd.port = lib.mkOption { + type = lib.types.port; description = "identd listen port"; default = 113; }; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Heisenbridge is configured over the command line. Append extra arguments here"; default = [ ]; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.heisenbridge = { description = "Matrix<->IRC bridge"; before = [ "matrix-synapse.service" ]; # So the registration file can be used by Synapse @@ -191,7 +188,7 @@ in RemoveIPC = true; UMask = "0077"; - CapabilityBoundingSet = [ "CAP_CHOWN" ] ++ optional (cfg.port < 1024 || (cfg.identd.enable && cfg.identd.port < 1024)) "CAP_NET_BIND_SERVICE"; + CapabilityBoundingSet = [ "CAP_CHOWN" ] ++ lib.optional (cfg.port < 1024 || (cfg.identd.enable && cfg.identd.port < 1024)) "CAP_NET_BIND_SERVICE"; AmbientCapabilities = CapabilityBoundingSet; NoNewPrivileges = true; LockPersonality = true; diff --git a/nixos/modules/services/misc/homepage-dashboard.nix b/nixos/modules/services/misc/homepage-dashboard.nix index 29fda16aa66f..b29a53d2f1cf 100644 --- a/nixos/modules/services/misc/homepage-dashboard.nix +++ b/nixos/modules/services/misc/homepage-dashboard.nix @@ -222,6 +222,7 @@ in environment = { HOMEPAGE_CONFIG_DIR = configDir; + HOMEPAGE_CACHE_DIR = "/var/cache/homepage-dashboard"; PORT = toString cfg.listenPort; LOG_TARGETS = lib.mkIf managedConfig "stdout"; }; @@ -231,6 +232,7 @@ in DynamicUser = true; EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; StateDirectory = lib.mkIf (!managedConfig) "homepage-dashboard"; + CacheDirectory = "homepage-dashboard"; ExecStart = lib.getExe cfg.package; Restart = "on-failure"; }; diff --git a/nixos/modules/services/misc/ihaskell.nix b/nixos/modules/services/misc/ihaskell.nix index 186ff7345ab3..b2ea3e70dede 100644 --- a/nixos/modules/services/misc/ihaskell.nix +++ b/nixos/modules/services/misc/ihaskell.nix @@ -1,7 +1,4 @@ { pkgs, lib, config, ... }: - -with lib; - let cfg = config.services.ihaskell; @@ -14,17 +11,17 @@ in { options = { services.ihaskell = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Autostart an IHaskell notebook service."; }; - extraPackages = mkOption { - type = types.functionTo (types.listOf types.package); + extraPackages = lib.mkOption { + type = lib.types.functionTo (lib.types.listOf lib.types.package); default = haskellPackages: []; - defaultText = literalExpression "haskellPackages: []"; - example = literalExpression '' + defaultText = lib.literalExpression "haskellPackages: []"; + example = lib.literalExpression '' haskellPackages: [ haskellPackages.wreq haskellPackages.lens @@ -39,7 +36,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.ihaskell = { group = config.users.groups.ihaskell.name; diff --git a/nixos/modules/services/misc/input-remapper.nix b/nixos/modules/services/misc/input-remapper.nix index 94c2ece52f98..cf335dacb4ff 100644 --- a/nixos/modules/services/misc/input-remapper.nix +++ b/nixos/modules/services/misc/input-remapper.nix @@ -1,25 +1,22 @@ { pkgs, lib, config, ... }: - -with lib; - let cfg = config.services.input-remapper; in { options = { services.input-remapper = { - enable = mkEnableOption "input-remapper, an easy to use tool to change the mapping of your input device buttons"; - package = mkPackageOption pkgs "input-remapper" { }; - enableUdevRules = mkEnableOption "udev rules added by input-remapper to handle hotplugged devices. Currently disabled by default due to https://github.com/sezanzeb/input-remapper/issues/140"; - serviceWantedBy = mkOption { + enable = lib.mkEnableOption "input-remapper, an easy to use tool to change the mapping of your input device buttons"; + package = lib.mkPackageOption pkgs "input-remapper" { }; + enableUdevRules = lib.mkEnableOption "udev rules added by input-remapper to handle hotplugged devices. Currently disabled by default due to https://github.com/sezanzeb/input-remapper/issues/140"; + serviceWantedBy = lib.mkOption { default = [ "graphical.target" ]; example = [ "multi-user.target" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = "Specifies the WantedBy setting for the input-remapper service."; }; }; }; - config = mkIf cfg.enable { - services.udev.packages = mkIf cfg.enableUdevRules [ cfg.package ]; + config = lib.mkIf cfg.enable { + services.udev.packages = lib.mkIf cfg.enableUdevRules [ cfg.package ]; services.dbus.packages = [ cfg.package ]; systemd.packages = [ cfg.package ]; environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/misc/irkerd.nix b/nixos/modules/services/misc/irkerd.nix index 993d77ba424c..28966c4ae226 100644 --- a/nixos/modules/services/misc/irkerd.nix +++ b/nixos/modules/services/misc/irkerd.nix @@ -1,29 +1,26 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.irkerd; ports = [ 6659 ]; in { options.services.irkerd = { - enable = mkOption { + enable = lib.mkOption { description = "Whether to enable irker, an IRC notification daemon."; default = false; - type = types.bool; + type = lib.types.bool; }; - openPorts = mkOption { + openPorts = lib.mkOption { description = "Open ports in the firewall for irkerd"; default = false; - type = types.bool; + type = lib.types.bool; }; - listenAddress = mkOption { + listenAddress = lib.mkOption { default = "localhost"; example = "0.0.0.0"; - type = types.str; + type = lib.types.str; description = '' Specifies the bind address on which the irker daemon listens. The default is localhost. @@ -33,14 +30,14 @@ in ''; }; - nick = mkOption { + nick = lib.mkOption { default = "irker"; - type = types.str; + type = lib.types.str; description = "Nick to use for irker"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.irkerd = { description = "Internet Relay Chat (IRC) notification daemon"; documentation = [ "man:irkerd(8)" "man:irkerhook(1)" "man:irk(1)" ]; @@ -61,7 +58,7 @@ in }; users.groups.irkerd = {}; - networking.firewall.allowedTCPPorts = mkIf cfg.openPorts ports; - networking.firewall.allowedUDPPorts = mkIf cfg.openPorts ports; + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openPorts ports; + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openPorts ports; }; } diff --git a/nixos/modules/services/misc/jackett.nix b/nixos/modules/services/misc/jackett.nix index a843f400b031..cbac537a58b5 100644 --- a/nixos/modules/services/misc/jackett.nix +++ b/nixos/modules/services/misc/jackett.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.jackett; @@ -9,45 +6,45 @@ in { options = { services.jackett = { - enable = mkEnableOption "Jackett, API support for your favorite torrent trackers"; + enable = lib.mkEnableOption "Jackett, API support for your favorite torrent trackers"; - port = mkOption { + port = lib.mkOption { default = 9117; - type = types.port; + type = lib.types.port; description = '' Port serving the web interface ''; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/jackett/.config/Jackett"; description = "The directory where Jackett stores its data files."; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for the Jackett web interface."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "jackett"; description = "User account under which Jackett runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "jackett"; description = "Group under which Jackett runs."; }; - package = mkPackageOption pkgs "jackett" { }; + package = lib.mkPackageOption pkgs "jackett" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" ]; @@ -66,11 +63,11 @@ in }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; - users.users = mkIf (cfg.user == "jackett") { + users.users = lib.mkIf (cfg.user == "jackett") { jackett = { group = cfg.group; home = cfg.dataDir; @@ -78,7 +75,7 @@ in }; }; - users.groups = mkIf (cfg.group == "jackett") { + users.groups = lib.mkIf (cfg.group == "jackett") { jackett.gid = config.ids.gids.jackett; }; }; diff --git a/nixos/modules/services/misc/jellyseerr.nix b/nixos/modules/services/misc/jellyseerr.nix index 9aab517e0493..e09de7aec50b 100644 --- a/nixos/modules/services/misc/jellyseerr.nix +++ b/nixos/modules/services/misc/jellyseerr.nix @@ -1,30 +1,28 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.services.jellyseerr; in { - meta.maintainers = [ maintainers.camillemndn ]; + meta.maintainers = [ lib.maintainers.camillemndn ]; options.services.jellyseerr = { - enable = mkEnableOption ''Jellyseerr, a requests manager for Jellyfin''; - package = mkPackageOption pkgs "jellyseerr" { }; + enable = lib.mkEnableOption ''Jellyseerr, a requests manager for Jellyfin''; + package = lib.mkPackageOption pkgs "jellyseerr" { }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = ''Open port in the firewall for the Jellyseerr web interface.''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5055; description = ''The port which the Jellyseerr web UI should listen to.''; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.jellyseerr = { description = "Jellyseerr, a requests manager for Jellyfin"; after = [ "network.target" ]; @@ -56,7 +54,7 @@ in }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; }; diff --git a/nixos/modules/services/misc/klipper.nix b/nixos/modules/services/misc/klipper.nix index 5e20b32bc8fd..f0972f8caff4 100644 --- a/nixos/modules/services/misc/klipper.nix +++ b/nixos/modules/services/misc/klipper.nix @@ -1,25 +1,24 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.klipper; format = pkgs.formats.ini { # https://github.com/NixOS/nixpkgs/pull/121613#issuecomment-885241996 listToValue = l: - if builtins.length l == 1 then generators.mkValueStringDefault { } (head l) - else lib.concatMapStrings (s: "\n ${generators.mkValueStringDefault {} s}") l; - mkKeyValue = generators.mkKeyValueDefault { } ":"; + if builtins.length l == 1 then lib.generators.mkValueStringDefault { } (lib.head l) + else lib.concatMapStrings (s: "\n ${lib.generators.mkValueStringDefault {} s}") l; + mkKeyValue = lib.generators.mkKeyValueDefault { } ":"; }; in { ##### interface options = { services.klipper = { - enable = mkEnableOption "Klipper, the 3D printer firmware"; + enable = lib.mkEnableOption "Klipper, the 3D printer firmware"; - package = mkPackageOption pkgs "klipper" { }; + package = lib.mkPackageOption pkgs "klipper" { }; - logFile = mkOption { - type = types.nullOr types.path; + logFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/var/lib/klipper/klipper.log"; description = '' @@ -28,20 +27,20 @@ in ''; }; - inputTTY = mkOption { - type = types.path; + inputTTY = lib.mkOption { + type = lib.types.path; default = "/run/klipper/tty"; description = "Path of the virtual printer symlink to create."; }; - apiSocket = mkOption { - type = types.nullOr types.path; + apiSocket = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = "/run/klipper/api"; description = "Path of the API socket to create."; }; - mutableConfig = mkOption { - type = types.bool; + mutableConfig = lib.mkOption { + type = lib.types.bool; default = false; example = true; description = '' @@ -50,28 +49,28 @@ in ''; }; - mutableConfigFolder = mkOption { - type = types.path; + mutableConfigFolder = lib.mkOption { + type = lib.types.path; default = "/var/lib/klipper"; description = "Path to mutable Klipper config file."; }; - configFile = mkOption { - type = types.nullOr types.path; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to default Klipper config. ''; }; - octoprintIntegration = mkOption { - type = types.bool; + octoprintIntegration = lib.mkOption { + type = lib.types.bool; default = false; description = "Allows Octoprint to control Klipper."; }; - user = mkOption { - type = types.nullOr types.str; + user = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' User account under which Klipper runs. @@ -80,8 +79,8 @@ in ''; }; - group = mkOption { - type = types.nullOr types.str; + group = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Group account under which Klipper runs. @@ -90,8 +89,8 @@ in ''; }; - settings = mkOption { - type = types.nullOr format.type; + settings = lib.mkOption { + type = lib.types.nullOr format.type; default = null; description = '' Configuration for Klipper. See the [documentation](https://www.klipper3d.org/Overview.html#configuration-and-tuning-guides) @@ -99,24 +98,24 @@ in ''; }; - firmwares = mkOption { + firmwares = lib.mkOption { description = "Firmwares klipper should manage"; default = { }; - type = with types; attrsOf + type = with lib.types; attrsOf (submodule { options = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' building of firmware for manual flashing ''; - enableKlipperFlash = mkEnableOption '' + enableKlipperFlash = lib.mkEnableOption '' flashings scripts for firmware. This will add `klipper-flash-$mcu` scripts to your environment which can be called to flash the firmware. Please check the configs at [klipper](https://github.com/Klipper3d/klipper/tree/master/config) whether your board supports flashing via `make flash` ''; - serial = mkOption { - type = types.nullOr path; + serial = lib.mkOption { + type = lib.types.nullOr path; description = "Path to serial port this printer is connected to. Leave `null` to derive it from `service.klipper.settings`."; }; - configFile = mkOption { + configFile = lib.mkOption { type = path; description = "Path to firmware config which is generated using `klipper-genconf`"; }; @@ -127,7 +126,7 @@ in }; ##### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.octoprintIntegration -> config.services.octoprint.enable; @@ -138,7 +137,7 @@ in message = "Option services.klipper.group is not set when services.klipper.user is specified."; } { - assertion = cfg.settings != null -> foldl (a: b: a && b) true (mapAttrsToList (mcu: _: mcu != null -> (hasAttrByPath [ "${mcu}" "serial" ] cfg.settings)) cfg.firmwares); + assertion = cfg.settings != null -> lib.foldl (a: b: a && b) true (lib.mapAttrsToList (mcu: _: mcu != null -> (lib.hasAttrByPath [ "${mcu}" "serial" ] cfg.settings)) cfg.firmwares); message = "Option services.klipper.settings.$mcu.serial must be set when settings.klipper.firmware.$mcu is specified"; } { @@ -147,11 +146,11 @@ in } ]; - environment.etc = mkIf (!cfg.mutableConfig) { + environment.etc = lib.mkIf (!cfg.mutableConfig) { "klipper.cfg".source = if cfg.settings != null then format.generate "klipper.cfg" cfg.settings else cfg.configFile; }; - services.klipper = mkIf cfg.octoprintIntegration { + services.klipper = lib.mkIf cfg.octoprintIntegration { user = config.services.octoprint.user; group = config.services.octoprint.group; }; @@ -159,8 +158,8 @@ in systemd.services.klipper = let klippyArgs = "--input-tty=${cfg.inputTTY}" - + optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}" - + optionalString (cfg.logFile != null) " --logfile=${cfg.logFile}" + + lib.optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}" + + lib.optionalString (cfg.logFile != null) " --logfile=${cfg.logFile}" ; printerConfigPath = if cfg.mutableConfig @@ -211,7 +210,7 @@ in with pkgs; let default = a: b: if a != null then a else b; - firmwares = filterAttrs (n: v: v != null) (mapAttrs + firmwares = lib.filterAttrs (n: v: v != null) (lib.mapAttrs (mcu: { enable, enableKlipperFlash, configFile, serial }: if enable then pkgs.klipper-firmware.override @@ -220,18 +219,18 @@ in firmwareConfig = configFile; } else null) cfg.firmwares); - firmwareFlasher = mapAttrsToList + firmwareFlasher = lib.mapAttrsToList (mcu: firmware: pkgs.klipper-flash.override { mcu = lib.strings.sanitizeDerivationName mcu; klipper-firmware = firmware; flashDevice = default cfg.firmwares."${mcu}".serial cfg.settings."${mcu}".serial; firmwareConfig = cfg.firmwares."${mcu}".configFile; }) - (filterAttrs (mcu: firmware: cfg.firmwares."${mcu}".enableKlipperFlash) firmwares); + (lib.filterAttrs (mcu: firmware: cfg.firmwares."${mcu}".enableKlipperFlash) firmwares); in - [ klipper-genconf ] ++ firmwareFlasher ++ attrValues firmwares; + [ klipper-genconf ] ++ firmwareFlasher ++ lib.attrValues firmwares; }; meta.maintainers = [ - maintainers.cab404 + lib.maintainers.cab404 ]; } diff --git a/nixos/modules/services/misc/languagetool.nix b/nixos/modules/services/misc/languagetool.nix index 2a7e68c9053a..c2921ea0f047 100644 --- a/nixos/modules/services/misc/languagetool.nix +++ b/nixos/modules/services/misc/languagetool.nix @@ -1,19 +1,16 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.languagetool; settingsFormat = pkgs.formats.javaProperties { }; in { options.services.languagetool = { - enable = mkEnableOption "the LanguageTool server, a multilingual spelling, style, and grammar checker that helps correct or paraphrase texts"; + enable = lib.mkEnableOption "the LanguageTool server, a multilingual spelling, style, and grammar checker that helps correct or paraphrase texts"; - package = mkPackageOption pkgs "languagetool" { }; + package = lib.mkPackageOption pkgs "languagetool" { }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8081; example = 8081; description = '' @@ -21,10 +18,10 @@ in ''; }; - public = mkEnableOption "access from anywhere (rather than just localhost)"; + public = lib.mkEnableOption "access from anywhere (rather than just localhost)"; - allowOrigin = mkOption { - type = types.nullOr types.str; + allowOrigin = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "https://my-website.org"; description = '' @@ -34,12 +31,12 @@ in ''; }; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = settingsFormat.type; - options.cacheSize = mkOption { - type = types.ints.unsigned; + options.cacheSize = lib.mkOption { + type = lib.types.ints.unsigned; default = 1000; apply = toString; description = "Number of sentences cached."; @@ -53,22 +50,22 @@ in ''; }; - jrePackage = mkPackageOption pkgs "jre" { }; + jrePackage = lib.mkPackageOption pkgs "jre" { }; - jvmOptions = mkOption { + jvmOptions = lib.mkOption { description = '' Extra command line options for the JVM running languagetool. More information can be found here: https://docs.oracle.com/en/java/javase/19/docs/specs/man/java.html#standard-options-for-java ''; default = [ ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "-Xmx512m" ]; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.languagetool = { description = "LanguageTool HTTP server"; @@ -89,8 +86,8 @@ in ${toString cfg.jvmOptions} \ org.languagetool.server.HTTPServer \ --port ${toString cfg.port} \ - ${optionalString cfg.public "--public"} \ - ${optionalString (cfg.allowOrigin != null) "--allow-origin ${cfg.allowOrigin}"} \ + ${lib.optionalString cfg.public "--public"} \ + ${lib.optionalString (cfg.allowOrigin != null) "--allow-origin ${cfg.allowOrigin}"} \ "--config" ${settingsFormat.generate "languagetool.conf" cfg.settings} ''; }; diff --git a/nixos/modules/services/misc/leaps.nix b/nixos/modules/services/misc/leaps.nix index c6f5a1252332..10d332fb74ad 100644 --- a/nixos/modules/services/misc/leaps.nix +++ b/nixos/modules/services/misc/leaps.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.leaps; stateDir = "/var/lib/leaps/"; @@ -9,27 +6,27 @@ in { options = { services.leaps = { - enable = mkEnableOption "leaps, a pair programming service"; - port = mkOption { - type = types.port; + enable = lib.mkEnableOption "leaps, a pair programming service"; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = "A port where leaps listens for incoming http requests"; }; - address = mkOption { + address = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; example = "127.0.0.1"; description = "Hostname or IP-address to listen to. By default it will listen on all interfaces."; }; - path = mkOption { + path = lib.mkOption { default = "/"; - type = types.path; + type = lib.types.path; description = "Subdirectory used for reverse proxy setups"; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users = { users.leaps = { uid = config.ids.uids.leaps; diff --git a/nixos/modules/services/misc/lidarr.nix b/nixos/modules/services/misc/lidarr.nix index 5f7b5c293a25..fd94f6536b22 100644 --- a/nixos/modules/services/misc/lidarr.nix +++ b/nixos/modules/services/misc/lidarr.nix @@ -1,41 +1,38 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.lidarr; in { options = { services.lidarr = { - enable = mkEnableOption "Lidarr, a Usenet/BitTorrent music downloader"; + enable = lib.mkEnableOption "Lidarr, a Usenet/BitTorrent music downloader"; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/lidarr/.config/Lidarr"; description = "The directory where Lidarr stores its data files."; }; - package = mkPackageOption pkgs "lidarr" { }; + package = lib.mkPackageOption pkgs "lidarr" { }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open ports in the firewall for Lidarr ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "lidarr"; description = '' User account under which Lidarr runs. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "lidarr"; description = '' Group under which Lidarr runs. @@ -44,7 +41,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.settings."10-lidarr".${cfg.dataDir}.d = { inherit (cfg) user group; mode = "0700"; @@ -64,11 +61,11 @@ in }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ 8686 ]; }; - users.users = mkIf (cfg.user == "lidarr") { + users.users = lib.mkIf (cfg.user == "lidarr") { lidarr = { group = cfg.group; home = "/var/lib/lidarr"; @@ -76,7 +73,7 @@ in }; }; - users.groups = mkIf (cfg.group == "lidarr") { + users.groups = lib.mkIf (cfg.group == "lidarr") { lidarr = { gid = config.ids.gids.lidarr; }; diff --git a/nixos/modules/services/misc/lifecycled.nix b/nixos/modules/services/misc/lifecycled.nix index 8b80af392492..c58b4f7525f5 100644 --- a/nixos/modules/services/misc/lifecycled.nix +++ b/nixos/modules/services/misc/lifecycled.nix @@ -1,6 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; let cfg = config.services.lifecycled; @@ -21,17 +19,17 @@ let ''; in { - meta.maintainers = with maintainers; [ cole-h grahamc ]; + meta.maintainers = with lib.maintainers; [ cole-h grahamc ]; options = { services.lifecycled = { - enable = mkEnableOption "lifecycled, a daemon for responding to AWS AutoScaling Lifecycle Hooks"; + enable = lib.mkEnableOption "lifecycled, a daemon for responding to AWS AutoScaling Lifecycle Hooks"; queueCleaner = { - enable = mkEnableOption "lifecycled-queue-cleaner"; + enable = lib.mkEnableOption "lifecycled-queue-cleaner"; - frequency = mkOption { - type = types.str; + frequency = lib.mkOption { + type = lib.types.str; default = "hourly"; description = '' How often to trigger the queue cleaner. @@ -43,8 +41,8 @@ in ''; }; - parallel = mkOption { - type = types.ints.unsigned; + parallel = lib.mkOption { + type = lib.types.ints.unsigned; default = 20; description = '' The number of parallel deletes to run. @@ -52,63 +50,63 @@ in }; }; - instanceId = mkOption { - type = types.nullOr types.str; + instanceId = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The instance ID to listen for events for. ''; }; - snsTopic = mkOption { - type = types.nullOr types.str; + snsTopic = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The SNS topic that receives events. ''; }; - noSpot = mkOption { - type = types.bool; + noSpot = lib.mkOption { + type = lib.types.bool; default = false; description = '' Disable the spot termination listener. ''; }; - handler = mkOption { - type = types.path; + handler = lib.mkOption { + type = lib.types.path; description = '' The script to invoke to handle events. ''; }; - json = mkOption { - type = types.bool; + json = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable JSON logging. ''; }; - cloudwatchGroup = mkOption { - type = types.nullOr types.str; + cloudwatchGroup = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Write logs to a specific Cloudwatch Logs group. ''; }; - cloudwatchStream = mkOption { - type = types.nullOr types.str; + cloudwatchStream = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Write logs to a specific Cloudwatch Logs stream. Defaults to the instance ID. ''; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable debugging information. @@ -117,8 +115,8 @@ in # XXX: Can be removed if / when # https://github.com/buildkite/lifecycled/pull/91 is merged. - awsRegion = mkOption { - type = types.nullOr types.str; + awsRegion = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The region used for accessing AWS services. @@ -129,8 +127,8 @@ in ### Implementation ### - config = mkMerge [ - (mkIf cfg.enable { + config = lib.mkMerge [ + (lib.mkIf cfg.enable { environment.etc."lifecycled".source = configFile; systemd.packages = [ pkgs.lifecycled ]; @@ -140,10 +138,10 @@ in }; }) - (mkIf cfg.queueCleaner.enable { + (lib.mkIf cfg.queueCleaner.enable { systemd.services.lifecycled-queue-cleaner = { description = "Lifecycle Daemon Queue Cleaner"; - environment = optionalAttrs (cfg.awsRegion != null) { AWS_REGION = cfg.awsRegion; }; + environment = lib.optionalAttrs (cfg.awsRegion != null) { AWS_REGION = cfg.awsRegion; }; serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.lifecycled}/bin/lifecycled-queue-cleaner -parallel ${toString cfg.queueCleaner.parallel}"; diff --git a/nixos/modules/services/misc/logkeys.nix b/nixos/modules/services/misc/logkeys.nix index 0fb4fa6cf8de..428ce626b715 100644 --- a/nixos/modules/services/misc/logkeys.nix +++ b/nixos/modules/services/misc/logkeys.nix @@ -1,22 +1,19 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.logkeys; in { options.services.logkeys = { - enable = mkEnableOption "logkeys, a keylogger service"; + enable = lib.mkEnableOption "logkeys, a keylogger service"; - device = mkOption { + device = lib.mkOption { description = "Use the given device as keyboard input event device instead of /dev/input/eventX default."; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = "/dev/input/event15"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.logkeys = { description = "LogKeys Keylogger Daemon"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/misc/mame.nix b/nixos/modules/services/misc/mame.nix index 38b4dd290ed5..ed98ef3ed8a6 100644 --- a/nixos/modules/services/misc/mame.nix +++ b/nixos/modules/services/misc/mame.nix @@ -1,37 +1,34 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.mame; - mame = "mame${lib.optionalString pkgs.stdenv.is64bit "64"}"; + mame = "mame${lib.optionalString pkgs.stdenv.hostPlatform.is64bit "64"}"; in { options = { services.mame = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to setup TUN/TAP Ethernet interface for MAME emulator. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = '' User from which you run MAME binary. ''; }; - hostAddr = mkOption { - type = types.str; + hostAddr = lib.mkOption { + type = lib.types.str; description = '' IP address of the host system. Usually an address of the main network adapter or the adapter through which you get an internet connection. ''; example = "192.168.31.156"; }; - emuAddr = mkOption { - type = types.str; + emuAddr = lib.mkOption { + type = lib.types.str; description = '' IP address of the guest system. The same you set inside guest OS under MAME. Should be on the same subnet as {option}`services.mame.hostAddr`. @@ -41,7 +38,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.mame ]; security.wrappers."${mame}" = { diff --git a/nixos/modules/services/misc/mbpfan.nix b/nixos/modules/services/misc/mbpfan.nix index 1d9b7ae87ca0..3061f68bb6e2 100644 --- a/nixos/modules/services/misc/mbpfan.nix +++ b/nixos/modules/services/misc/mbpfan.nix @@ -1,55 +1,53 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.mbpfan; - verbose = optionalString cfg.verbose "v"; + verbose = lib.optionalString cfg.verbose "v"; format = pkgs.formats.ini {}; cfgfile = format.generate "mbpfan.ini" cfg.settings; in { options.services.mbpfan = { - enable = mkEnableOption "mbpfan, fan controller daemon for Apple Macs and MacBooks"; - package = mkPackageOption pkgs "mbpfan" {}; + enable = lib.mkEnableOption "mbpfan, fan controller daemon for Apple Macs and MacBooks"; + package = lib.mkPackageOption pkgs "mbpfan" {}; - verbose = mkOption { - type = types.bool; + verbose = lib.mkOption { + type = lib.types.bool; default = false; description = "If true, sets the log level to verbose."; }; - aggressive = mkOption { - type = types.bool; + aggressive = lib.mkOption { + type = lib.types.bool; default = true; description = "If true, favors higher default fan speeds."; }; - settings = mkOption { + settings = lib.mkOption { default = {}; description = "INI configuration for Mbpfan."; - type = types.submodule { + type = lib.types.submodule { freeformType = format.type; - options.general.low_temp = mkOption { - type = types.int; + options.general.low_temp = lib.mkOption { + type = lib.types.int; default = (if cfg.aggressive then 55 else 63); - defaultText = literalExpression "55"; + defaultText = lib.literalExpression "55"; description = "If temperature is below this, fans will run at minimum speed."; }; - options.general.high_temp = mkOption { - type = types.int; + options.general.high_temp = lib.mkOption { + type = lib.types.int; default = (if cfg.aggressive then 58 else 66); - defaultText = literalExpression "58"; + defaultText = lib.literalExpression "58"; description = "If temperature is above this, fan speed will gradually increase."; }; - options.general.max_temp = mkOption { - type = types.int; + options.general.max_temp = lib.mkOption { + type = lib.types.int; default = (if cfg.aggressive then 78 else 86); - defaultText = literalExpression "78"; + defaultText = lib.literalExpression "78"; description = "If temperature is above this, fans will run at maximum speed."; }; - options.general.polling_interval = mkOption { - type = types.int; + options.general.polling_interval = lib.mkOption { + type = lib.types.int; default = 1; description = "The polling interval."; }; @@ -58,15 +56,15 @@ in { }; imports = [ - (mkRenamedOptionModule [ "services" "mbpfan" "pollingInterval" ] [ "services" "mbpfan" "settings" "general" "polling_interval" ]) - (mkRenamedOptionModule [ "services" "mbpfan" "maxTemp" ] [ "services" "mbpfan" "settings" "general" "max_temp" ]) - (mkRenamedOptionModule [ "services" "mbpfan" "lowTemp" ] [ "services" "mbpfan" "settings" "general" "low_temp" ]) - (mkRenamedOptionModule [ "services" "mbpfan" "highTemp" ] [ "services" "mbpfan" "settings" "general" "high_temp" ]) - (mkRenamedOptionModule [ "services" "mbpfan" "minFanSpeed" ] [ "services" "mbpfan" "settings" "general" "min_fan1_speed" ]) - (mkRenamedOptionModule [ "services" "mbpfan" "maxFanSpeed" ] [ "services" "mbpfan" "settings" "general" "max_fan1_speed" ]) + (lib.mkRenamedOptionModule [ "services" "mbpfan" "pollingInterval" ] [ "services" "mbpfan" "settings" "general" "polling_interval" ]) + (lib.mkRenamedOptionModule [ "services" "mbpfan" "maxTemp" ] [ "services" "mbpfan" "settings" "general" "max_temp" ]) + (lib.mkRenamedOptionModule [ "services" "mbpfan" "lowTemp" ] [ "services" "mbpfan" "settings" "general" "low_temp" ]) + (lib.mkRenamedOptionModule [ "services" "mbpfan" "highTemp" ] [ "services" "mbpfan" "settings" "general" "high_temp" ]) + (lib.mkRenamedOptionModule [ "services" "mbpfan" "minFanSpeed" ] [ "services" "mbpfan" "settings" "general" "min_fan1_speed" ]) + (lib.mkRenamedOptionModule [ "services" "mbpfan" "maxFanSpeed" ] [ "services" "mbpfan" "settings" "general" "max_fan1_speed" ]) ]; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "coretemp" "applesmc" ]; environment.systemPackages = [ cfg.package ]; environment.etc."mbpfan.conf".source = cfgfile; diff --git a/nixos/modules/services/misc/mediatomb.nix b/nixos/modules/services/misc/mediatomb.nix index 932558e25802..ae9d1fa31be2 100644 --- a/nixos/modules/services/misc/mediatomb.nix +++ b/nixos/modules/services/misc/mediatomb.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let gid = config.ids.gids.mediatomb; @@ -13,19 +10,19 @@ let # configuration on media directory mediaDirectory = { options = { - path = mkOption { - type = types.str; + path = lib.mkOption { + type = lib.types.str; description = '' Absolute directory path to the media directory to index. ''; }; - recursive = mkOption { - type = types.bool; + recursive = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether the indexation must take place recursively or not."; }; - hidden-files = mkOption { - type = types.bool; + hidden-files = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to index the hidden files or not."; }; @@ -39,7 +36,6 @@ let - @@ -55,7 +51,7 @@ let yes yes yes - @@ -66,7 +62,7 @@ let ''; - configText = optionalString (! cfg.customCfg) '' + configText = lib.optionalString (! cfg.customCfg) '' @@ -87,7 +83,7 @@ let - ${optionalString cfg.dsmSupport '' + ${lib.optionalString cfg.dsmSupport '' @@ -95,7 +91,7 @@ let redsonic.com 105 ''} - ${optionalString cfg.tg100Support '' + ${lib.optionalString cfg.tg100Support '' 101 ''} @@ -109,7 +105,7 @@ let - ${concatMapStrings toMediaDirectory cfg.mediaDirectories} + ${lib.concatMapStrings toMediaDirectory cfg.mediaDirectories} ${pkg}/share/${name}/js/common.js @@ -139,10 +135,10 @@ let - ${optionalString cfg.ps3Support '' + ${lib.optionalString cfg.ps3Support '' ''} - ${optionalString cfg.dsmSupport '' + ${lib.optionalString cfg.dsmSupport '' ''} @@ -199,26 +195,26 @@ in { services.mediatomb = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the Gerbera/Mediatomb DLNA server. ''; }; - serverName = mkOption { - type = types.str; + serverName = lib.mkOption { + type = lib.types.str; default = "Gerbera (Mediatomb)"; description = '' How to identify the server on the network. ''; }; - package = mkPackageOption pkgs "gerbera" { }; + package = lib.mkPackageOption pkgs "gerbera" { }; - ps3Support = mkOption { - type = types.bool; + ps3Support = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable ps3 specific tweaks. @@ -226,8 +222,8 @@ in { ''; }; - dsmSupport = mkOption { - type = types.bool; + dsmSupport = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable D-Link DSM 320 specific tweaks. @@ -235,69 +231,69 @@ in { ''; }; - tg100Support = mkOption { - type = types.bool; + tg100Support = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable Telegent TG100 specific tweaks. ''; }; - transcoding = mkOption { - type = types.bool; + transcoding = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable transcoding. ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/${name}"; - defaultText = literalExpression ''"/var/lib/''${config.${opt.package}.pname}"''; + defaultText = lib.literalExpression ''"/var/lib/''${config.${opt.package}.pname}"''; description = '' The directory where Gerbera/Mediatomb stores its state, data, etc. ''; }; - pcDirectoryHide = mkOption { - type = types.bool; + pcDirectoryHide = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to list the top-level directory or not (from upnp client standpoint). ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "mediatomb"; description = "User account under which the service runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "mediatomb"; description = "Group account under which the service runs."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 49152; description = '' The network port to listen on. ''; }; - interface = mkOption { - type = types.str; + interface = lib.mkOption { + type = lib.types.str; default = ""; description = '' A specific interface to bind to. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' If false (the default), this is up to the user to declare the firewall rules. @@ -310,16 +306,16 @@ in { ''; }; - uuid = mkOption { - type = types.str; + uuid = lib.mkOption { + type = lib.types.str; default = "fdfc8a4e-a3ad-4c1d-b43d-a2eedb03a687"; description = '' A unique (on your network) to identify the server by. ''; }; - mediaDirectories = mkOption { - type = with types; listOf (submodule mediaDirectory); + mediaDirectories = lib.mkOption { + type = with lib.types; listOf (submodule mediaDirectory); default = []; description = '' Declare media directories to index. @@ -330,8 +326,8 @@ in { ]; }; - customCfg = mkOption { - type = types.bool; + customCfg = lib.mkOption { + type = lib.types.bool; default = false; description = '' Allow the service to create and use its own config file inside the `dataDir` as @@ -350,9 +346,9 @@ in { ###### implementation config = let binaryCommand = "${pkg}/bin/${name}"; - interfaceFlag = optionalString ( cfg.interface != "") "--interface ${cfg.interface}"; - configFlag = optionalString (! cfg.customCfg) "--config ${pkgs.writeText "config.xml" configText}"; - in mkIf cfg.enable { + interfaceFlag = lib.optionalString ( cfg.interface != "") "--interface ${cfg.interface}"; + configFlag = lib.optionalString (! cfg.customCfg) "--config ${pkgs.writeText "config.xml" configText}"; + in lib.mkIf cfg.enable { systemd.services.mediatomb = { description = "${cfg.serverName} media Server"; # Gerbera might fail if the network interface is not available on startup @@ -365,11 +361,11 @@ in { serviceConfig.Group = cfg.group; }; - users.groups = optionalAttrs (cfg.group == "mediatomb") { + users.groups = lib.optionalAttrs (cfg.group == "mediatomb") { mediatomb.gid = gid; }; - users.users = optionalAttrs (cfg.user == "mediatomb") { + users.users = lib.optionalAttrs (cfg.user == "mediatomb") { mediatomb = { isSystemUser = true; group = cfg.group; @@ -380,11 +376,11 @@ in { }; # Open firewall only if users enable it - networking.firewall = mkMerge [ - (mkIf (cfg.openFirewall && cfg.interface != "") { + networking.firewall = lib.mkMerge [ + (lib.mkIf (cfg.openFirewall && cfg.interface != "") { interfaces."${cfg.interface}" = defaultFirewallRules; }) - (mkIf (cfg.openFirewall && cfg.interface == "") defaultFirewallRules) + (lib.mkIf (cfg.openFirewall && cfg.interface == "") defaultFirewallRules) ]; }; } diff --git a/nixos/modules/services/misc/moonraker.nix b/nixos/modules/services/misc/moonraker.nix index 1461f1048b03..b9ddace19e91 100644 --- a/nixos/modules/services/misc/moonraker.nix +++ b/nixos/modules/services/misc/moonraker.nix @@ -1,5 +1,4 @@ { config, lib, options, pkgs, ... }: -with lib; let cfg = config.services.moonraker; pkg = cfg.package; @@ -7,37 +6,37 @@ let format = pkgs.formats.ini { # https://github.com/NixOS/nixpkgs/pull/121613#issuecomment-885241996 listToValue = l: - if builtins.length l == 1 then generators.mkValueStringDefault {} (head l) - else lib.concatMapStrings (s: "\n ${generators.mkValueStringDefault {} s}") l; - mkKeyValue = generators.mkKeyValueDefault {} ":"; + if builtins.length l == 1 then lib.generators.mkValueStringDefault {} (lib.head l) + else lib.concatMapStrings (s: "\n ${lib.generators.mkValueStringDefault {} s}") l; + mkKeyValue = lib.generators.mkKeyValueDefault {} ":"; }; unifiedConfigDir = cfg.stateDir + "/config"; in { options = { services.moonraker = { - enable = mkEnableOption "Moonraker, an API web server for Klipper"; + enable = lib.mkEnableOption "Moonraker, an API web server for Klipper"; - package = mkPackageOption pkgs "moonraker" { + package = lib.mkPackageOption pkgs "moonraker" { nullable = true; example = "moonraker.override { useGpiod = true; }"; }; - klipperSocket = mkOption { - type = types.path; + klipperSocket = lib.mkOption { + type = lib.types.path; default = config.services.klipper.apiSocket; - defaultText = literalExpression "config.services.klipper.apiSocket"; + defaultText = lib.literalExpression "config.services.klipper.apiSocket"; description = "Path to Klipper's API socket."; }; - stateDir = mkOption { - type = types.path; + stateDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/moonraker"; description = "The directory containing the Moonraker databases."; }; - configDir = mkOption { - type = types.nullOr types.path; + configDir = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Deprecated directory containing client-writable configuration files. @@ -46,32 +45,32 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "moonraker"; description = "User account under which Moonraker runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "moonraker"; description = "Group account under which Moonraker runs."; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; example = "0.0.0.0"; description = "The IP or host to listen on."; }; - port = mkOption { - type = types.ints.unsigned; + port = lib.mkOption { + type = lib.types.ints.unsigned; default = 7125; description = "The port to listen on."; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; example = { @@ -86,8 +85,8 @@ in { ''; }; - allowSystemControl = mkOption { - type = types.bool; + allowSystemControl = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to allow Moonraker to perform system-level operations. @@ -101,12 +100,12 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { warnings = [] - ++ (optional (head (cfg.settings.update_manager.enable_system_updates or [false])) '' + ++ (lib.optional (lib.head (cfg.settings.update_manager.enable_system_updates or [false])) '' Enabling system updates is not supported on NixOS and will lead to non-removable warnings in some clients. '') - ++ (optional (cfg.configDir != null) '' + ++ (lib.optional (cfg.configDir != null) '' services.moonraker.configDir has been deprecated upstream and will be removed. Action: ${ @@ -123,14 +122,14 @@ in { } ]; - users.users = optionalAttrs (cfg.user == "moonraker") { + users.users = lib.optionalAttrs (cfg.user == "moonraker") { moonraker = { group = cfg.group; uid = config.ids.uids.moonraker; }; }; - users.groups = optionalAttrs (cfg.group == "moonraker") { + users.groups = lib.optionalAttrs (cfg.group == "moonraker") { moonraker.gid = config.ids.gids.moonraker; }; @@ -149,7 +148,7 @@ in { config_path = cfg.configDir; }; }); - fullConfig = recursiveUpdate cfg.settings forcedConfig; + fullConfig = lib.recursiveUpdate cfg.settings forcedConfig; in format.generate "moonraker.cfg" fullConfig; systemd.tmpfiles.rules = [ @@ -160,7 +159,7 @@ in { description = "Moonraker, an API web server for Klipper"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ] - ++ optional config.services.klipper.enable "klipper.service"; + ++ lib.optional config.services.klipper.enable "klipper.service"; # Moonraker really wants its own config to be writable... script = '' @@ -211,7 +210,7 @@ in { ''; }; - meta.maintainers = with maintainers; [ + meta.maintainers = with lib.maintainers; [ cab404 vtuan10 zhaofengli diff --git a/nixos/modules/services/misc/mqtt2influxdb.nix b/nixos/modules/services/misc/mqtt2influxdb.nix index d07ce1e66ba3..cefe7acbba2f 100644 --- a/nixos/modules/services/misc/mqtt2influxdb.nix +++ b/nixos/modules/services/misc/mqtt2influxdb.nix @@ -4,12 +4,9 @@ pkgs, ... }: - -with lib; - let cfg = config.services.mqtt2influxdb; - filterNull = filterAttrsRecursive (n: v: v != null); + filterNull = lib.filterAttrsRecursive (n: v: v != null); configFile = (pkgs.formats.yaml {}).generate "mqtt2influxdb.config.yaml" ( filterNull { inherit (cfg) mqtt influxdb; @@ -17,26 +14,26 @@ let } ); - pointType = types.submodule { + pointType = lib.types.submodule { options = { - measurement = mkOption { - type = types.str; + measurement = lib.mkOption { + type = lib.types.str; description = "Name of the measurement"; }; - topic = mkOption { - type = types.str; + topic = lib.mkOption { + type = lib.types.str; description = "MQTT topic to subscribe to."; }; - fields = mkOption { - type = types.submodule { + fields = lib.mkOption { + type = lib.types.submodule { options = { - value = mkOption { - type = types.str; + value = lib.mkOption { + type = lib.types.str; default = "$.payload"; description = "Value to be picked up"; }; - type = mkOption { - type = with types; nullOr str; + type = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Type to be picked up"; }; @@ -44,8 +41,8 @@ let }; description = "Field selector."; }; - tags = mkOption { - type = with types; attrsOf str; + tags = lib.mkOption { + type = with lib.types; attrsOf str; default = {}; description = "Tags applied"; }; @@ -124,10 +121,10 @@ let in { options = { services.mqtt2influxdb = { - enable = mkEnableOption "BigClown MQTT to InfluxDB bridge"; - package = mkPackageOption pkgs ["python3Packages" "mqtt2influxdb"] {}; - environmentFiles = mkOption { - type = types.listOf types.path; + enable = lib.mkEnableOption "BigClown MQTT to InfluxDB bridge"; + package = lib.mkPackageOption pkgs ["python3Packages" "mqtt2influxdb"] {}; + environmentFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; example = [ "/run/keys/mqtt2influxdb.env" ]; description = '' @@ -138,23 +135,23 @@ in { ''; }; mqtt = { - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Host where MQTT server is running."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 1883; description = "MQTT server port."; }; - username = mkOption { - type = with types; nullOr str; + username = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Username used to connect to the MQTT server."; }; - password = mkOption { - type = with types; nullOr str; + password = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' MQTT password. @@ -164,44 +161,44 @@ in { the store. ''; }; - cafile = mkOption { - type = with types; nullOr path; + cafile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = "Certification Authority file for MQTT"; }; - certfile = mkOption { - type = with types; nullOr path; + certfile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = "Certificate file for MQTT"; }; - keyfile = mkOption { - type = with types; nullOr path; + keyfile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = "Key file for MQTT"; }; }; influxdb = { - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "Host where InfluxDB server is running."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8086; description = "InfluxDB server port"; }; - database = mkOption { - type = types.str; + database = lib.mkOption { + type = lib.types.str; description = "Name of the InfluxDB database."; }; - username = mkOption { - type = with types; nullOr str; + username = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = "Username for InfluxDB login."; }; - password = mkOption { - type = with types; nullOr str; + password = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Password for InfluxDB login. @@ -211,26 +208,26 @@ in { the store. ''; }; - ssl = mkOption { - type = types.bool; + ssl = lib.mkOption { + type = lib.types.bool; default = false; description = "Use SSL to connect to the InfluxDB server."; }; - verify_ssl = mkOption { - type = types.bool; + verify_ssl = lib.mkOption { + type = lib.types.bool; default = true; description = "Verify SSL certificate when connecting to the InfluxDB server."; }; }; - points = mkOption { - type = types.listOf pointType; + points = lib.mkOption { + type = lib.types.listOf pointType; default = defaultPoints; description = "Points to bridge from MQTT to InfluxDB."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.bigclown-mqtt2influxdb = let envConfig = cfg.environmentFiles != []; finalConfig = if envConfig @@ -239,7 +236,7 @@ in { in { description = "BigClown MQTT to InfluxDB bridge"; wantedBy = ["multi-user.target"]; - wants = mkIf config.services.mosquitto.enable ["mosquitto.service"]; + wants = lib.mkIf config.services.mosquitto.enable ["mosquitto.service"]; preStart = '' umask 077 ${pkgs.envsubst}/bin/envsubst -i "${configFile}" -o "${finalConfig}" diff --git a/nixos/modules/services/misc/n8n.nix b/nixos/modules/services/misc/n8n.nix index 231470b9937a..623c9a3be8a9 100644 --- a/nixos/modules/services/misc/n8n.nix +++ b/nixos/modules/services/misc/n8n.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.n8n; format = pkgs.formats.json {}; @@ -9,15 +6,15 @@ let in { options.services.n8n = { - enable = mkEnableOption "n8n server"; + enable = lib.mkEnableOption "n8n server"; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for the n8n web interface."; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = {}; description = '' @@ -26,8 +23,8 @@ in ''; }; - webhookUrl = mkOption { - type = types.str; + webhookUrl = lib.mkOption { + type = lib.types.str; default = ""; description = '' WEBHOOK_URL for n8n, in case we're running behind a reverse proxy. @@ -37,7 +34,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.n8n.settings = { # We use this to open the firewall, so we need to know about the default at eval time port = lib.mkDefault 5678; @@ -85,7 +82,7 @@ in }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.settings.port ]; }; }; diff --git a/nixos/modules/services/misc/nitter.nix b/nixos/modules/services/misc/nitter.nix index f8be2aed70c9..40a4b157aee1 100644 --- a/nixos/modules/services/misc/nitter.nix +++ b/nixos/modules/services/misc/nitter.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.nitter; configFile = pkgs.writeText "nitter.conf" '' - ${generators.toINI { + ${lib.generators.toINI { # String values need to be quoted - mkKeyValue = generators.mkKeyValueDefault { + mkKeyValue = lib.generators.mkKeyValueDefault { mkValueString = v: - if isString v then "\"" + (strings.escape ["\""] (toString v)) + "\"" - else generators.mkValueStringDefault {} v; + if lib.isString v then "\"" + (lib.escape ["\""] (toString v)) + "\"" + else lib.generators.mkValueStringDefault {} v; } " = "; } (lib.recursiveUpdate { Server = cfg.server; @@ -47,57 +44,57 @@ in { imports = [ # https://github.com/zedeus/nitter/pull/772 - (mkRemovedOptionModule [ "services" "nitter" "replaceInstagram" ] "Nitter no longer supports this option as Bibliogram has been discontinued.") + (lib.mkRemovedOptionModule [ "services" "nitter" "replaceInstagram" ] "Nitter no longer supports this option as Bibliogram has been discontinued.") ]; options = { services.nitter = { - enable = mkEnableOption "Nitter, an alternative Twitter front-end"; + enable = lib.mkEnableOption "Nitter, an alternative Twitter front-end"; - package = mkPackageOption pkgs "nitter" { }; + package = lib.mkPackageOption pkgs "nitter" { }; server = { - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; example = "127.0.0.1"; description = "The address to listen on."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; example = 8000; description = "The port to listen on."; }; - https = mkOption { - type = types.bool; + https = lib.mkOption { + type = lib.types.bool; default = false; description = "Set secure attribute on cookies. Keep it disabled to enable cookies when not using HTTPS."; }; - httpMaxConnections = mkOption { - type = types.int; + httpMaxConnections = lib.mkOption { + type = lib.types.int; default = 100; description = "Maximum number of HTTP connections."; }; - staticDir = mkOption { - type = types.path; + staticDir = lib.mkOption { + type = lib.types.path; default = "${cfg.package}/share/nitter/public"; - defaultText = literalExpression ''"''${config.services.nitter.package}/share/nitter/public"''; + defaultText = lib.literalExpression ''"''${config.services.nitter.package}/share/nitter/public"''; description = "Path to the static files directory."; }; - title = mkOption { - type = types.str; + title = lib.mkOption { + type = lib.types.str; default = "nitter"; description = "Title of the instance."; }; - hostname = mkOption { - type = types.str; + hostname = lib.mkOption { + type = lib.types.str; default = "localhost"; example = "nitter.net"; description = "Hostname of the instance."; @@ -105,38 +102,38 @@ in }; cache = { - listMinutes = mkOption { - type = types.int; + listMinutes = lib.mkOption { + type = lib.types.int; default = 240; description = "How long to cache list info (not the tweets, so keep it high)."; }; - rssMinutes = mkOption { - type = types.int; + rssMinutes = lib.mkOption { + type = lib.types.int; default = 10; description = "How long to cache RSS queries."; }; - redisHost = mkOption { - type = types.str; + redisHost = lib.mkOption { + type = lib.types.str; default = "localhost"; description = "Redis host."; }; - redisPort = mkOption { - type = types.port; + redisPort = lib.mkOption { + type = lib.types.port; default = 6379; description = "Redis port."; }; - redisConnections = mkOption { - type = types.int; + redisConnections = lib.mkOption { + type = lib.types.int; default = 20; description = "Redis connection pool size."; }; - redisMaxConnections = mkOption { - type = types.int; + redisMaxConnections = lib.mkOption { + type = lib.types.int; default = 30; description = '' Maximum number of connections to Redis. @@ -149,30 +146,30 @@ in }; config = { - base64Media = mkOption { - type = types.bool; + base64Media = lib.mkOption { + type = lib.types.bool; default = false; description = "Use base64 encoding for proxied media URLs."; }; - enableRSS = mkEnableOption "RSS feeds" // { default = true; }; + enableRSS = lib.mkEnableOption "RSS feeds" // { default = true; }; - enableDebug = mkEnableOption "request logs and debug endpoints"; + enableDebug = lib.mkEnableOption "request logs and debug endpoints"; - proxy = mkOption { - type = types.str; + proxy = lib.mkOption { + type = lib.types.str; default = ""; description = "URL to a HTTP/HTTPS proxy."; }; - proxyAuth = mkOption { - type = types.str; + proxyAuth = lib.mkOption { + type = lib.types.str; default = ""; description = "Credentials for proxy."; }; - tokenCount = mkOption { - type = types.int; + tokenCount = lib.mkOption { + type = lib.types.int; default = 10; description = '' Minimum amount of usable tokens. @@ -187,114 +184,114 @@ in }; preferences = { - replaceTwitter = mkOption { - type = types.str; + replaceTwitter = lib.mkOption { + type = lib.types.str; default = ""; example = "nitter.net"; description = "Replace Twitter links with links to this instance (blank to disable)."; }; - replaceYouTube = mkOption { - type = types.str; + replaceYouTube = lib.mkOption { + type = lib.types.str; default = ""; example = "piped.kavin.rocks"; description = "Replace YouTube links with links to this instance (blank to disable)."; }; - replaceReddit = mkOption { - type = types.str; + replaceReddit = lib.mkOption { + type = lib.types.str; default = ""; example = "teddit.net"; description = "Replace Reddit links with links to this instance (blank to disable)."; }; - mp4Playback = mkOption { - type = types.bool; + mp4Playback = lib.mkOption { + type = lib.types.bool; default = true; description = "Enable MP4 video playback."; }; - hlsPlayback = mkOption { - type = types.bool; + hlsPlayback = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable HLS video streaming (requires JavaScript)."; }; - proxyVideos = mkOption { - type = types.bool; + proxyVideos = lib.mkOption { + type = lib.types.bool; default = true; description = "Proxy video streaming through the server (might be slow)."; }; - muteVideos = mkOption { - type = types.bool; + muteVideos = lib.mkOption { + type = lib.types.bool; default = false; description = "Mute videos by default."; }; - autoplayGifs = mkOption { - type = types.bool; + autoplayGifs = lib.mkOption { + type = lib.types.bool; default = true; description = "Autoplay GIFs."; }; - theme = mkOption { - type = types.str; + theme = lib.mkOption { + type = lib.types.str; default = "Nitter"; description = "Instance theme."; }; - infiniteScroll = mkOption { - type = types.bool; + infiniteScroll = lib.mkOption { + type = lib.types.bool; default = false; description = "Infinite scrolling (requires JavaScript, experimental!)."; }; - stickyProfile = mkOption { - type = types.bool; + stickyProfile = lib.mkOption { + type = lib.types.bool; default = true; description = "Make profile sidebar stick to top."; }; - bidiSupport = mkOption { - type = types.bool; + bidiSupport = lib.mkOption { + type = lib.types.bool; default = false; description = "Support bidirectional text (makes clicking on tweets harder)."; }; - hideTweetStats = mkOption { - type = types.bool; + hideTweetStats = lib.mkOption { + type = lib.types.bool; default = false; description = "Hide tweet stats (replies, retweets, likes)."; }; - hideBanner = mkOption { - type = types.bool; + hideBanner = lib.mkOption { + type = lib.types.bool; default = false; description = "Hide profile banner."; }; - hidePins = mkOption { - type = types.bool; + hidePins = lib.mkOption { + type = lib.types.bool; default = false; description = "Hide pinned tweets."; }; - hideReplies = mkOption { - type = types.bool; + hideReplies = lib.mkOption { + type = lib.types.bool; default = false; description = "Hide tweet replies."; }; - squareAvatars = mkOption { - type = types.bool; + squareAvatars = lib.mkOption { + type = lib.types.bool; default = false; description = "Square profile pictures."; }; }; - settings = mkOption { - type = types.attrs; + settings = lib.mkOption { + type = lib.types.attrs; default = {}; description = '' Add settings here to override NixOS module generated settings. @@ -304,8 +301,8 @@ in ''; }; - guestAccounts = mkOption { - type = types.path; + guestAccounts = lib.mkOption { + type = lib.types.path; default = "/var/lib/nitter/guest_accounts.jsonl"; description = '' Path to the guest accounts file. @@ -321,21 +318,21 @@ in ''; }; - redisCreateLocally = mkOption { - type = types.bool; + redisCreateLocally = lib.mkOption { + type = lib.types.bool; default = true; description = "Configure local Redis server for Nitter."; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for Nitter web interface."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = !cfg.redisCreateLocally || (cfg.cache.redisHost == "localhost" && cfg.cache.redisPort == 6379); @@ -397,7 +394,7 @@ in port = cfg.cache.redisPort; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.server.port ]; }; }; diff --git a/nixos/modules/services/misc/nix-ssh-serve.nix b/nixos/modules/services/misc/nix-ssh-serve.nix index f60736c688d9..b0ccf495c7eb 100644 --- a/nixos/modules/services/misc/nix-ssh-serve.nix +++ b/nixos/modules/services/misc/nix-ssh-serve.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.nix.sshServe; command = if cfg.protocol == "ssh" @@ -11,27 +9,27 @@ in { nix.sshServe = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable serving the Nix store as a remote store via SSH."; }; - write = mkOption { - type = types.bool; + write = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable writing to the Nix store as a remote store via SSH. Note: the sshServe user is named nix-ssh and is not a trusted-user. nix-ssh should be added to the {option}`nix.settings.trusted-users` option in most use cases, such as allowing remote building of derivations."; }; - keys = mkOption { - type = types.listOf types.str; + keys = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "ssh-dss AAAAB3NzaC1k... alice@example.org" ]; description = "A list of SSH public keys allowed to access the binary cache via SSH."; }; - protocol = mkOption { - type = types.enum [ "ssh" "ssh-ng" ]; + protocol = lib.mkOption { + type = lib.types.enum [ "ssh" "ssh-ng" ]; default = "ssh"; description = "The specific Nix-over-SSH protocol to use."; }; @@ -40,7 +38,7 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.nix-ssh = { description = "Nix SSH store user"; diff --git a/nixos/modules/services/misc/novacomd.nix b/nixos/modules/services/misc/novacomd.nix index 7cfc68d2b673..52423ff0668f 100644 --- a/nixos/modules/services/misc/novacomd.nix +++ b/nixos/modules/services/misc/novacomd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.novacomd; @@ -10,11 +7,11 @@ in { options = { services.novacomd = { - enable = mkEnableOption "Novacom service for connecting to WebOS devices"; + enable = lib.mkEnableOption "Novacom service for connecting to WebOS devices"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.webos.novacom ]; systemd.services.novacomd = { @@ -27,5 +24,5 @@ in { }; }; - meta.maintainers = with maintainers; [ dtzWill ]; + meta.maintainers = with lib.maintainers; [ dtzWill ]; } diff --git a/nixos/modules/services/misc/ntfy-sh.nix b/nixos/modules/services/misc/ntfy-sh.nix index ae6ab9571d0f..db857a3f1472 100644 --- a/nixos/modules/services/misc/ntfy-sh.nix +++ b/nixos/modules/services/misc/ntfy-sh.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.ntfy-sh; @@ -10,28 +7,28 @@ in { options.services.ntfy-sh = { - enable = mkEnableOption "[ntfy-sh](https://ntfy.sh), a push notification service"; + enable = lib.mkEnableOption "[ntfy-sh](https://ntfy.sh), a push notification service"; - package = mkPackageOption pkgs "ntfy-sh" { }; + package = lib.mkPackageOption pkgs "ntfy-sh" { }; - user = mkOption { + user = lib.mkOption { default = "ntfy-sh"; - type = types.str; + type = lib.types.str; description = "User the ntfy-sh server runs under."; }; - group = mkOption { + group = lib.mkOption { default = "ntfy-sh"; - type = types.str; + type = lib.types.str; description = "Primary group of ntfy-sh user."; }; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = settingsFormat.type; options = { - base-url = mkOption { - type = types.str; + base-url = lib.mkOption { + type = lib.types.str; example = "https://ntfy.example"; description = '' Public facing base URL of the service @@ -49,7 +46,7 @@ in default = { }; - example = literalExpression '' + example = lib.literalExpression '' { listen-http = ":8080"; } @@ -65,7 +62,7 @@ in let configuration = settingsFormat.generate "server.yml" cfg.settings; in - mkIf cfg.enable { + lib.mkIf cfg.enable { # to configure access control via the cli environment = { etc."ntfy/server.yml".source = configuration; @@ -73,10 +70,10 @@ in }; services.ntfy-sh.settings = { - auth-file = mkDefault "/var/lib/ntfy-sh/user.db"; - listen-http = mkDefault "127.0.0.1:2586"; - attachment-cache-dir = mkDefault "/var/lib/ntfy-sh/attachments"; - cache-file = mkDefault "/var/lib/ntfy-sh/cache-file.db"; + auth-file = lib.mkDefault "/var/lib/ntfy-sh/user.db"; + listen-http = lib.mkDefault "127.0.0.1:2586"; + attachment-cache-dir = lib.mkDefault "/var/lib/ntfy-sh/attachments"; + cache-file = lib.mkDefault "/var/lib/ntfy-sh/cache-file.db"; }; systemd.services.ntfy-sh = { @@ -110,11 +107,11 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "ntfy-sh") { + users.groups = lib.optionalAttrs (cfg.group == "ntfy-sh") { ntfy-sh = { }; }; - users.users = optionalAttrs (cfg.user == "ntfy-sh") { + users.users = lib.optionalAttrs (cfg.user == "ntfy-sh") { ntfy-sh = { isSystemUser = true; group = cfg.group; diff --git a/nixos/modules/services/misc/nzbget.nix b/nixos/modules/services/misc/nzbget.nix index c961fe9b2877..a2726d455009 100644 --- a/nixos/modules/services/misc/nzbget.nix +++ b/nixos/modules/services/misc/nzbget.nix @@ -1,46 +1,43 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.nzbget; pkg = pkgs.nzbget; stateDir = "/var/lib/nzbget"; configFile = "${stateDir}/nzbget.conf"; - configOpts = concatStringsSep " " (mapAttrsToList (name: value: "-o ${name}=${escapeShellArg (toStr value)}") cfg.settings); + configOpts = lib.concatStringsSep " " (lib.mapAttrsToList (name: value: "-o ${name}=${lib.escapeShellArg (toStr value)}") cfg.settings); toStr = v: if v == true then "yes" else if v == false then "no" - else if isInt v then toString v + else if lib.isInt v then toString v else v; in { imports = [ - (mkRemovedOptionModule [ "services" "misc" "nzbget" "configFile" ] "The configuration of nzbget is now managed by users through the web interface.") - (mkRemovedOptionModule [ "services" "misc" "nzbget" "dataDir" ] "The data directory for nzbget is now /var/lib/nzbget.") - (mkRemovedOptionModule [ "services" "misc" "nzbget" "openFirewall" ] "The port used by nzbget is managed through the web interface so you should adjust your firewall rules accordingly.") + (lib.mkRemovedOptionModule [ "services" "misc" "nzbget" "configFile" ] "The configuration of nzbget is now managed by users through the web interface.") + (lib.mkRemovedOptionModule [ "services" "misc" "nzbget" "dataDir" ] "The data directory for nzbget is now /var/lib/nzbget.") + (lib.mkRemovedOptionModule [ "services" "misc" "nzbget" "openFirewall" ] "The port used by nzbget is managed through the web interface so you should adjust your firewall rules accordingly.") ]; # interface options = { services.nzbget = { - enable = mkEnableOption "NZBGet, for downloading files from news servers"; + enable = lib.mkEnableOption "NZBGet, for downloading files from news servers"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "nzbget"; description = "User account under which NZBGet runs"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "nzbget"; description = "Group under which NZBGet runs"; }; - settings = mkOption { - type = with types; attrsOf (oneOf [ bool int str ]); + settings = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ bool int str ]); default = {}; description = '' NZBGet configuration, passed via command line using switch -o. Refer to @@ -56,7 +53,7 @@ in # implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.nzbget.settings = { # allows nzbget to run as a "simple" service OutputMode = "loggable"; @@ -100,7 +97,7 @@ in }; }; - users.users = mkIf (cfg.user == "nzbget") { + users.users = lib.mkIf (cfg.user == "nzbget") { nzbget = { home = stateDir; group = cfg.group; @@ -108,7 +105,7 @@ in }; }; - users.groups = mkIf (cfg.group == "nzbget") { + users.groups = lib.mkIf (cfg.group == "nzbget") { nzbget = { gid = config.ids.gids.nzbget; }; diff --git a/nixos/modules/services/misc/nzbhydra2.nix b/nixos/modules/services/misc/nzbhydra2.nix index 8246ea52f978..c71e8a92b727 100644 --- a/nixos/modules/services/misc/nzbhydra2.nix +++ b/nixos/modules/services/misc/nzbhydra2.nix @@ -1,31 +1,28 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.nzbhydra2; in { options = { services.nzbhydra2 = { - enable = mkEnableOption "NZBHydra2, Usenet meta search"; + enable = lib.mkEnableOption "NZBHydra2, Usenet meta search"; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/nzbhydra2"; description = "The directory where NZBHydra2 stores its data files."; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for the NZBHydra2 web interface."; }; - package = mkPackageOption pkgs "nzbhydra2" { }; + package = lib.mkPackageOption pkgs "nzbhydra2" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 nzbhydra2 nzbhydra2 - -" ]; @@ -60,7 +57,7 @@ in { }; }; - networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ 5076 ]; }; + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ 5076 ]; }; users.users.nzbhydra2 = { group = "nzbhydra2"; diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix index 6290a6a7a537..42b2926a7a1e 100644 --- a/nixos/modules/services/misc/octoprint.nix +++ b/nixos/modules/services/misc/octoprint.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.octoprint; @@ -13,7 +10,7 @@ let webcam.ffmpeg = "${pkgs.ffmpeg.bin}/bin/ffmpeg"; }; - fullConfig = recursiveUpdate cfg.extraConfig baseConfig; + fullConfig = lib.recursiveUpdate cfg.extraConfig baseConfig; cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON fullConfig); @@ -29,58 +26,58 @@ in services.octoprint = { - enable = mkEnableOption "OctoPrint, web interface for 3D printers"; + enable = lib.mkEnableOption "OctoPrint, web interface for 3D printers"; - host = mkOption { - type = types.str; + host = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = '' Host to bind OctoPrint to. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5000; description = '' Port to bind OctoPrint to. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for OctoPrint."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "octoprint"; description = "User for the daemon."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "octoprint"; description = "Group for the daemon."; }; - stateDir = mkOption { - type = types.path; + stateDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/octoprint"; description = "State directory of the daemon."; }; - plugins = mkOption { - type = types.functionTo (types.listOf types.package); + plugins = lib.mkOption { + type = lib.types.functionTo (lib.types.listOf lib.types.package); default = plugins: [ ]; - defaultText = literalExpression "plugins: []"; - example = literalExpression "plugins: with plugins; [ themeify stlviewer ]"; + defaultText = lib.literalExpression "plugins: []"; + example = lib.literalExpression "plugins: with plugins; [ themeify stlviewer ]"; description = "Additional plugins to be used. Available plugins are passed through the plugins input."; }; - extraConfig = mkOption { - type = types.attrs; + extraConfig = lib.mkOption { + type = lib.types.attrs; default = { }; description = "Extra options which are added to OctoPrint's YAML configuration file."; }; @@ -91,16 +88,16 @@ in ##### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == "octoprint") { + users.users = lib.optionalAttrs (cfg.user == "octoprint") { octoprint = { group = cfg.group; uid = config.ids.uids.octoprint; }; }; - users.groups = optionalAttrs (cfg.group == "octoprint") { + users.groups = lib.optionalAttrs (cfg.group == "octoprint") { octoprint.gid = config.ids.gids.octoprint; }; @@ -137,6 +134,6 @@ in }; }; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; }; } diff --git a/nixos/modules/services/misc/ollama.nix b/nixos/modules/services/misc/ollama.nix index a1141c784b4d..f9d151927995 100644 --- a/nixos/modules/services/misc/ollama.nix +++ b/nixos/modules/services/misc/ollama.nix @@ -127,8 +127,7 @@ in example = "10.3.0"; description = '' Override what rocm will detect your gpu model as. - For example, make rocm treat your RX 5700 XT (or any other model) - as an RX 6900 XT using a value of `"10.3.0"` (gfx 1030). + For example, if you have an RX 5700 XT, try setting this to `"10.1.0"` (gfx 1010). This sets the value of `HSA_OVERRIDE_GFX_VERSION`. See [ollama's docs]( https://github.com/ollama/ollama/blob/main/docs/gpu.md#amd-radeon diff --git a/nixos/modules/services/misc/ombi.nix b/nixos/modules/services/misc/ombi.nix index 9b2e3cf84e5d..51f3c3e468a5 100644 --- a/nixos/modules/services/misc/ombi.nix +++ b/nixos/modules/services/misc/ombi.nix @@ -1,13 +1,10 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.ombi; in { options = { services.ombi = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' Ombi, a web application that automatically gives your shared Plex or Emby users the ability to request content by themselves! @@ -15,39 +12,39 @@ in { on how to set up a reverse proxy ''; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/ombi"; description = "The directory where Ombi stores its data files."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5000; description = "The port for the Ombi web interface."; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = "Open ports in the firewall for the Ombi web interface."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "ombi"; description = "User account under which Ombi runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "ombi"; description = "Group under which Ombi runs."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" ]; @@ -66,11 +63,11 @@ in { }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; - users.users = mkIf (cfg.user == "ombi") { + users.users = lib.mkIf (cfg.user == "ombi") { ombi = { isSystemUser = true; group = cfg.group; @@ -78,6 +75,6 @@ in { }; }; - users.groups = mkIf (cfg.group == "ombi") { ombi = { }; }; + users.groups = lib.mkIf (cfg.group == "ombi") { ombi = { }; }; }; } diff --git a/nixos/modules/services/misc/open-webui.nix b/nixos/modules/services/misc/open-webui.nix index e2ed7080c922..fd6fa64b9e19 100644 --- a/nixos/modules/services/misc/open-webui.nix +++ b/nixos/modules/services/misc/open-webui.nix @@ -60,6 +60,17 @@ in ''; }; + 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/openWebuiSecrets"; + }; + openFirewall = lib.mkOption { type = types.bool; default = false; @@ -82,10 +93,12 @@ in DATA_DIR = "."; HF_HOME = "."; SENTENCE_TRANSFORMERS_HOME = "."; + WEBUI_URL = "http://localhost:${toString cfg.port}"; } // cfg.environment; serviceConfig = { ExecStart = "${lib.getExe cfg.package} serve --host ${cfg.host} --port ${toString cfg.port}"; + EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile; WorkingDirectory = cfg.stateDir; StateDirectory = "open-webui"; RuntimeDirectory = "open-webui"; diff --git a/nixos/modules/services/misc/osrm.nix b/nixos/modules/services/misc/osrm.nix index a93337dc75e3..8feccbbfa726 100644 --- a/nixos/modules/services/misc/osrm.nix +++ b/nixos/modules/services/misc/osrm.nix @@ -1,59 +1,56 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.osrm; in { options.services.osrm = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable the OSRM service."; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "0.0.0.0"; description = "IP address on which the web server will listen."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5000; description = "Port on which the web server will run."; }; - threads = mkOption { - type = types.int; + threads = lib.mkOption { + type = lib.types.int; default = 4; description = "Number of threads to use."; }; - algorithm = mkOption { - type = types.enum [ "CH" "CoreCH" "MLD" ]; + algorithm = lib.mkOption { + type = lib.types.enum [ "CH" "CoreCH" "MLD" ]; default = "MLD"; description = "Algorithm to use for the data. Must be one of CH, CoreCH, MLD"; }; - extraFlags = mkOption { - type = types.listOf types.str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "--max-table-size 1000" "--max-matching-size 1000" ]; description = "Extra command line arguments passed to osrm-routed"; }; - dataFile = mkOption { - type = types.path; + dataFile = lib.mkOption { + type = lib.types.path; example = "/var/lib/osrm/berlin-latest.osrm"; description = "Data file location"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.osrm = { group = config.users.users.osrm.name; diff --git a/nixos/modules/services/misc/owncast.nix b/nixos/modules/services/misc/owncast.nix index 94f0f4e998c4..debbd90d42a7 100644 --- a/nixos/modules/services/misc/owncast.nix +++ b/nixos/modules/services/misc/owncast.nix @@ -1,57 +1,56 @@ { lib, pkgs, config, ... }: -with lib; let cfg = config.services.owncast; in { options.services.owncast = { - enable = mkEnableOption "owncast, a video live streaming solution"; + enable = lib.mkEnableOption "owncast, a video live streaming solution"; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/owncast"; description = '' The directory where owncast stores its data files. If left as the default value this directory will automatically be created before the owncast server starts, otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership and permissions. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open the appropriate ports in the firewall for owncast. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "owncast"; description = "User account under which owncast runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "owncast"; description = "Group under which owncast runs."; }; - listen = mkOption { - type = types.str; + listen = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; example = "0.0.0.0"; description = "The IP address to bind the owncast web server to."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = '' TCP port where owncast web-gui listens. ''; }; - rtmp-port = mkOption { - type = types.port; + rtmp-port = lib.mkOption { + type = lib.types.port; default = 1935; description = '' TCP port where owncast rtmp service listens. @@ -60,13 +59,13 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.owncast = { description = "A self-hosted live video and web chat server"; wantedBy = [ "multi-user.target" ]; - serviceConfig = mkMerge [ + serviceConfig = lib.mkMerge [ { User = cfg.user; Group = cfg.group; @@ -74,13 +73,13 @@ in { ExecStart = "${pkgs.owncast}/bin/owncast -webserverport ${toString cfg.port} -rtmpport ${toString cfg.rtmp-port} -webserverip ${cfg.listen}"; Restart = "on-failure"; } - (mkIf (cfg.dataDir == "/var/lib/owncast") { + (lib.mkIf (cfg.dataDir == "/var/lib/owncast") { StateDirectory = "owncast"; }) ]; }; - users.users = mkIf (cfg.user == "owncast") { + users.users = lib.mkIf (cfg.user == "owncast") { owncast = { isSystemUser = true; group = cfg.group; @@ -88,10 +87,10 @@ in { }; }; - users.groups = mkIf (cfg.group == "owncast") { owncast = { }; }; + users.groups = lib.mkIf (cfg.group == "owncast") { owncast = { }; }; networking.firewall = - mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.rtmp-port ] ++ optional (cfg.listen != "127.0.0.1") cfg.port; }; + lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.rtmp-port ] ++ lib.optional (cfg.listen != "127.0.0.1") cfg.port; }; }; meta = { maintainers = with lib.maintainers; [ MayNiklas ]; }; diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix index 6d6a49c10bdd..73f09d804f29 100644 --- a/nixos/modules/services/misc/paperless.nix +++ b/nixos/modules/services/misc/paperless.nix @@ -40,8 +40,9 @@ let exec ${cfg.package}/bin/paperless-ngx "$@" ''; - # Secure the services defaultServiceConfig = { + Slice = "system-paperless.slice"; + # Secure the services ReadWritePaths = [ cfg.consumptionDir cfg.dataDir @@ -84,7 +85,7 @@ let }; in { - meta.maintainers = with maintainers; [ erikarvstedt Flakebi leona ]; + meta.maintainers = with maintainers; [ leona SuperSandro2000 erikarvstedt ]; imports = [ (mkRenamedOptionModule [ "services" "paperless-ng" ] [ "services" "paperless" ]) @@ -232,6 +233,11 @@ in config = mkIf cfg.enable { services.redis.servers.paperless.enable = mkIf enableRedis true; + systemd.slices.system-paperless = { + description = "Paperless Document Management System Slice"; + documentation = [ "https://docs.paperless-ngx.com" ]; + }; + systemd.tmpfiles.settings."10-paperless" = let defaultRule = { inherit (cfg) user; diff --git a/nixos/modules/services/misc/portunus.nix b/nixos/modules/services/misc/portunus.nix index a9a069b0c055..20486f0212f7 100644 --- a/nixos/modules/services/misc/portunus.nix +++ b/nixos/modules/services/misc/portunus.nix @@ -1,23 +1,20 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.portunus; in { options.services.portunus = { - enable = mkEnableOption "Portunus, a self-contained user/group management and authentication service for LDAP"; + enable = lib.mkEnableOption "Portunus, a self-contained user/group management and authentication service for LDAP"; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; example = "sso.example.com"; description = "Subdomain which gets reverse proxied to Portunus webserver."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = '' Port where the Portunus webserver should listen on. @@ -26,10 +23,10 @@ in ''; }; - package = mkPackageOption pkgs "portunus" { }; + package = lib.mkPackageOption pkgs "portunus" { }; - seedPath = mkOption { - type = types.nullOr types.path; + seedPath = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to a portunus seed file in json format. @@ -46,26 +43,26 @@ in ''; }; - stateDir = mkOption { - type = types.path; + stateDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/portunus"; description = "Path where Portunus stores its state."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "portunus"; description = "User account under which Portunus runs its webserver."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "portunus"; description = "Group account under which Portunus runs its webserver."; }; dex = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' Dex ldap connector. To activate dex, first a search user must be created in the Portunus web ui @@ -73,15 +70,15 @@ in in the [](#opt-services.dex.environmentFile) setting ''; - oidcClients = mkOption { - type = types.listOf (types.submodule { + oidcClients = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - callbackURL = mkOption { - type = types.str; + callbackURL = lib.mkOption { + type = lib.types.str; description = "URL where the OIDC client should redirect"; }; - id = mkOption { - type = types.str; + id = lib.mkOption { + type = lib.types.str; description = "ID of the OIDC client"; }; }; @@ -105,23 +102,23 @@ in ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 5556; description = "Port where dex should listen on."; }; }; ldap = { - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = pkgs.openldap; defaultText = lib.literalExpression "pkgs.openldap.override { libxcrypt = pkgs.libxcrypt-legacy; }"; description = "The OpenLDAP package to use."; }; - searchUserName = mkOption { - type = types.str; + searchUserName = lib.mkOption { + type = lib.types.str; default = ""; example = "admin"; description = '' @@ -130,8 +127,8 @@ in ''; }; - suffix = mkOption { - type = types.str; + suffix = lib.mkOption { + type = lib.types.str; example = "dc=example,dc=org"; description = '' The DN of the topmost entry in your LDAP directory. @@ -139,8 +136,8 @@ in ''; }; - tls = mkOption { - type = types.bool; + tls = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable LDAPS protocol. @@ -151,21 +148,21 @@ in ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "openldap"; description = "User account under which Portunus runs its LDAP server."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "openldap"; description = "Group account under which Portunus runs its LDAP server."; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.dex.enable -> cfg.ldap.searchUserName != ""; @@ -177,13 +174,13 @@ in environment.systemPackages = [ cfg.ldap.package ]; # allow connecting via ldaps /w certificate without opening ports - networking.hosts = mkIf cfg.ldap.tls { + networking.hosts = lib.mkIf cfg.ldap.tls { "::1" = [ cfg.domain ]; "127.0.0.1" = [ cfg.domain ]; }; services = { - dex = mkIf cfg.dex.enable { + dex = lib.mkIf cfg.dex.enable { enable = true; settings = { issuer = "https://${cfg.domain}/dex"; @@ -219,7 +216,7 @@ in }; }]; - staticClients = forEach cfg.dex.oidcClients (client: { + staticClients = lib.forEach cfg.dex.oidcClients (client: { inherit (client) id; redirectURIs = [ client.callbackURL ]; name = "OIDC for ${client.id}"; @@ -232,7 +229,7 @@ in }; systemd.services = { - dex = mkIf cfg.dex.enable { + dex = lib.mkIf cfg.dex.enable { serviceConfig = { # `dex.service` is super locked down out of the box, but we need some # place to write the SQLite database. This creates $STATE_DIRECTORY below @@ -261,9 +258,9 @@ in PORTUNUS_SLAPD_GROUP = cfg.ldap.group; PORTUNUS_SLAPD_USER = cfg.ldap.user; PORTUNUS_SLAPD_SCHEMA_DIR = "${cfg.ldap.package}/etc/schema"; - } // (optionalAttrs (cfg.seedPath != null) ({ + } // (lib.optionalAttrs (cfg.seedPath != null) ({ PORTUNUS_SEED_PATH = cfg.seedPath; - })) // (optionalAttrs cfg.ldap.tls ( + })) // (lib.optionalAttrs cfg.ldap.tls ( let acmeDirectory = config.security.acme.certs."${cfg.domain}".directory; in @@ -277,14 +274,14 @@ in }; }; - users.users = mkMerge [ - (mkIf (cfg.ldap.user == "openldap") { + users.users = lib.mkMerge [ + (lib.mkIf (cfg.ldap.user == "openldap") { openldap = { group = cfg.ldap.group; isSystemUser = true; }; }) - (mkIf (cfg.user == "portunus") { + (lib.mkIf (cfg.user == "portunus") { portunus = { group = cfg.group; isSystemUser = true; @@ -292,15 +289,15 @@ in }) ]; - users.groups = mkMerge [ - (mkIf (cfg.ldap.user == "openldap") { + users.groups = lib.mkMerge [ + (lib.mkIf (cfg.ldap.user == "openldap") { openldap = { }; }) - (mkIf (cfg.user == "portunus") { + (lib.mkIf (cfg.user == "portunus") { portunus = { }; }) ]; }; - meta.maintainers = [ maintainers.majewsky ] ++ teams.c3d2.members; + meta.maintainers = [ lib.maintainers.majewsky ] ++ lib.teams.c3d2.members; } diff --git a/nixos/modules/services/misc/prowlarr.nix b/nixos/modules/services/misc/prowlarr.nix index c94882a4f72a..e37f0dc36d14 100644 --- a/nixos/modules/services/misc/prowlarr.nix +++ b/nixos/modules/services/misc/prowlarr.nix @@ -34,6 +34,7 @@ in ExecStart = "${lib.getExe cfg.package} -nobrowser -data=/var/lib/prowlarr"; Restart = "on-failure"; }; + environment.HOME = "/var/empty"; }; networking.firewall = mkIf cfg.openFirewall { diff --git a/nixos/modules/services/misc/radicle.nix b/nixos/modules/services/misc/radicle.nix index 3a393bf0f1f2..cd7a2452223a 100644 --- a/nixos/modules/services/misc/radicle.nix +++ b/nixos/modules/services/misc/radicle.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.radicle; @@ -14,18 +13,18 @@ let # Convenient wrapper to run `rad` in the namespaces of `radicle-node.service` rad-system = pkgs.writeShellScriptBin "rad-system" '' set -o allexport - ${toShellVars env} + ${lib.toShellVars env} # Note that --env is not used to preserve host's envvars like $TERM - exec ${getExe' pkgs.util-linux "nsenter"} -a \ - -t "$(${getExe' config.systemd.package "systemctl"} show -P MainPID radicle-node.service)" \ - -S "$(${getExe' config.systemd.package "systemctl"} show -P UID radicle-node.service)" \ - -G "$(${getExe' config.systemd.package "systemctl"} show -P GID radicle-node.service)" \ - ${getExe' cfg.package "rad"} "$@" + exec ${lib.getExe' pkgs.util-linux "nsenter"} -a \ + -t "$(${lib.getExe' config.systemd.package "systemctl"} show -P MainPID radicle-node.service)" \ + -S "$(${lib.getExe' config.systemd.package "systemctl"} show -P UID radicle-node.service)" \ + -G "$(${lib.getExe' config.systemd.package "systemctl"} show -P GID radicle-node.service)" \ + ${lib.getExe' cfg.package "rad"} "$@" ''; commonServiceConfig = serviceName: { environment = env // { - RUST_LOG = mkDefault "info"; + RUST_LOG = lib.mkDefault "info"; }; path = [ pkgs.gitMinimal @@ -41,11 +40,11 @@ let "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - serviceConfig = mkMerge [ + serviceConfig = lib.mkMerge [ { BindReadOnlyPaths = [ "${cfg.configFile}:${env.RAD_HOME}/config.json" - "${if types.path.check cfg.publicKey then cfg.publicKey else pkgs.writeText "radicle.pub" cfg.publicKey}:${env.RAD_HOME}/keys/radicle.pub" + "${if lib.types.path.check cfg.publicKey then cfg.publicKey else pkgs.writeText "radicle.pub" cfg.publicKey}:${env.RAD_HOME}/keys/radicle.pub" ]; KillMode = "process"; StateDirectory = [ "radicle" ]; @@ -107,7 +106,7 @@ let pkgs.gitMinimal cfg.package pkgs.iana-etc - (getLib pkgs.nss) + (lib.getLib pkgs.nss) pkgs.tzdata ]; }; @@ -116,11 +115,11 @@ in { options = { services.radicle = { - enable = mkEnableOption "Radicle Seed Node"; - package = mkPackageOption pkgs "radicle-node" { }; - privateKeyFile = mkOption { + enable = lib.mkEnableOption "Radicle Seed Node"; + package = lib.mkPackageOption pkgs "radicle-node" { }; + privateKeyFile = lib.mkOption { # Note that a key encrypted by systemd-creds is not a path but a str. - type = with types; either path str; + type = with lib.types; either path str; description = '' Absolute file path to an SSH private key, usually generated by `rad auth`. @@ -130,44 +129,44 @@ in and the string after as a path encrypted with `systemd-creds`. ''; }; - publicKey = mkOption { - type = with types; either path str; + publicKey = lib.mkOption { + type = with lib.types; either path str; description = '' An SSH public key (as an absolute file path or directly as a string), usually generated by `rad auth`. ''; }; node = { - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "[::]"; example = "127.0.0.1"; description = "The IP address on which `radicle-node` listens."; }; - listenPort = mkOption { - type = types.port; + listenPort = lib.mkOption { + type = lib.types.port; default = 8776; description = "The port on which `radicle-node` listens."; }; - openFirewall = mkEnableOption "opening the firewall for `radicle-node`"; - extraArgs = mkOption { - type = with types; listOf str; + openFirewall = lib.mkEnableOption "opening the firewall for `radicle-node`"; + extraArgs = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = "Extra arguments for `radicle-node`"; }; }; - configFile = mkOption { - type = types.package; + configFile = lib.mkOption { + type = lib.types.package; internal = true; default = (json.generate "config.json" cfg.settings).overrideAttrs (previousAttrs: { preferLocalBuild = true; # None of the usual phases are run here because runCommandWith uses buildCommand, # so just append to buildCommand what would usually be a checkPhase. - buildCommand = previousAttrs.buildCommand + optionalString cfg.checkConfig '' + buildCommand = previousAttrs.buildCommand + lib.optionalString cfg.checkConfig '' ln -s $out config.json install -D -m 644 /dev/stdin keys/radicle.pub <<<"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBgFMhajUng+Rjj/sCFXI9PzG8BQjru2n7JgUVF1Kbv5 snakeoil" export RAD_HOME=$PWD - ${getExe' pkgs.buildPackages.radicle-node "rad"} config >/dev/null || { + ${lib.getExe' pkgs.buildPackages.radicle-node "rad"} config >/dev/null || { cat -n config.json echo "Invalid config.json according to rad." echo "Please double-check your services.radicle.settings (producing the config.json above)," @@ -177,13 +176,13 @@ in ''; }); }; - checkConfig = mkEnableOption "checking the {file}`config.json` file resulting from {option}`services.radicle.settings`" // { default = true; }; - settings = mkOption { + checkConfig = lib.mkEnableOption "checking the {file}`config.json` file resulting from {option}`services.radicle.settings`" // { default = true; }; + settings = lib.mkOption { description = '' See https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5/tree/radicle/src/node/config.rs#L275 ''; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { web.pinned.repositories = [ "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5" # heartwood @@ -191,27 +190,27 @@ in ]; } ''; - type = types.submodule { + type = lib.types.submodule { freeformType = json.type; }; }; httpd = { - enable = mkEnableOption "Radicle HTTP gateway to radicle-node"; - package = mkPackageOption pkgs "radicle-httpd" { }; - listenAddress = mkOption { - type = types.str; + enable = lib.mkEnableOption "Radicle HTTP gateway to radicle-node"; + package = lib.mkPackageOption pkgs "radicle-httpd" { }; + listenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = "The IP address on which `radicle-httpd` listens."; }; - listenPort = mkOption { - type = types.port; + listenPort = lib.mkOption { + type = lib.types.port; default = 8080; description = "The port on which `radicle-httpd` listens."; }; - nginx = mkOption { + nginx = lib.mkOption { # Type of a single virtual host, or null. - type = types.nullOr (types.submodule ( - recursiveUpdate (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) { + type = lib.types.nullOr (lib.types.submodule ( + lib.recursiveUpdate (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) { options.serverName = { default = "radicle-${config.networking.hostName}.${config.networking.domain}"; defaultText = "radicle-\${config.networking.hostName}.\${config.networking.domain}"; @@ -219,7 +218,7 @@ in } )); default = null; - example = literalExpression '' + example = lib.literalExpression '' { serverAliases = [ "seed.''${config.networking.domain}" @@ -237,8 +236,8 @@ in If this is set to null (the default), no nginx virtual host will be configured. ''; }; - extraArgs = mkOption { - type = with types; listOf str; + extraArgs = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = "Extra arguments for `radicle-httpd`"; }; @@ -246,19 +245,19 @@ in }; }; - config = mkIf cfg.enable (mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { - systemd.services.radicle-node = mkMerge [ + systemd.services.radicle-node = lib.mkMerge [ (commonServiceConfig "radicle-node") { description = "Radicle Node"; documentation = [ "man:radicle-node(1)" ]; serviceConfig = { - ExecStart = "${getExe' cfg.package "radicle-node"} --force --listen ${cfg.node.listenAddress}:${toString cfg.node.listenPort} ${escapeShellArgs cfg.node.extraArgs}"; - Restart = mkDefault "on-failure"; + ExecStart = "${lib.getExe' cfg.package "radicle-node"} --force --listen ${cfg.node.listenAddress}:${toString cfg.node.listenPort} ${lib.escapeShellArgs cfg.node.extraArgs}"; + Restart = lib.mkDefault "on-failure"; RestartSec = "30"; SocketBindAllow = [ "tcp:${toString cfg.node.listenPort}" ]; - SystemCallFilter = mkAfter [ + SystemCallFilter = lib.mkAfter [ # Needed by git upload-pack which calls alarm() and setitimer() when providing a rad clone "@timer" ]; @@ -271,11 +270,11 @@ in { serviceConfig = let keyCred = builtins.split ":" "${cfg.privateKeyFile}"; in - if length keyCred > 1 + if lib.length keyCred > 1 then { LoadCredentialEncrypted = [ cfg.privateKeyFile ]; # Note that neither %d nor ${CREDENTIALS_DIRECTORY} works in BindReadOnlyPaths= - BindReadOnlyPaths = [ "/run/credentials/radicle-node.service/${head keyCred}:${env.RAD_HOME}/keys/radicle" ]; + BindReadOnlyPaths = [ "/run/credentials/radicle-node.service/${lib.head keyCred}:${env.RAD_HOME}/keys/radicle" ]; } else { LoadCredential = [ "radicle:${cfg.privateKeyFile}" ]; @@ -288,7 +287,7 @@ in rad-system ]; - networking.firewall = mkIf cfg.node.openFirewall { + networking.firewall = lib.mkIf cfg.node.openFirewall { allowedTCPPorts = [ cfg.node.listenPort ]; }; @@ -304,19 +303,19 @@ in }; } - (mkIf cfg.httpd.enable (mkMerge [ + (lib.mkIf cfg.httpd.enable (lib.mkMerge [ { - systemd.services.radicle-httpd = mkMerge [ + systemd.services.radicle-httpd = lib.mkMerge [ (commonServiceConfig "radicle-httpd") { description = "Radicle HTTP gateway to radicle-node"; documentation = [ "man:radicle-httpd(1)" ]; serviceConfig = { - ExecStart = "${getExe' cfg.httpd.package "radicle-httpd"} --listen ${cfg.httpd.listenAddress}:${toString cfg.httpd.listenPort} ${escapeShellArgs cfg.httpd.extraArgs}"; - Restart = mkDefault "on-failure"; + ExecStart = "${lib.getExe' cfg.httpd.package "radicle-httpd"} --listen ${cfg.httpd.listenAddress}:${toString cfg.httpd.listenPort} ${lib.escapeShellArgs cfg.httpd.extraArgs}"; + Restart = lib.mkDefault "on-failure"; RestartSec = "10"; SocketBindAllow = [ "tcp:${toString cfg.httpd.listenPort}" ]; - SystemCallFilter = mkAfter [ + SystemCallFilter = lib.mkAfter [ # Needed by git upload-pack which calls alarm() and setitimer() when providing a git clone "@timer" ]; @@ -328,12 +327,12 @@ in ]; } - (mkIf (cfg.httpd.nginx != null) { + (lib.mkIf (cfg.httpd.nginx != null) { services.nginx.virtualHosts.${cfg.httpd.nginx.serverName} = lib.mkMerge [ cfg.httpd.nginx { - forceSSL = mkDefault true; - enableACME = mkDefault true; + forceSSL = lib.mkDefault true; + enableACME = lib.mkDefault true; locations."/" = { proxyPass = "http://${cfg.httpd.listenAddress}:${toString cfg.httpd.listenPort}"; recommendedProxySettings = true; @@ -342,8 +341,8 @@ in ]; services.radicle.settings = { - node.alias = mkDefault cfg.httpd.nginx.serverName; - node.externalAddresses = mkDefault [ + node.alias = lib.mkDefault cfg.httpd.nginx.serverName; + node.externalAddresses = lib.mkDefault [ "${cfg.httpd.nginx.serverName}:${toString cfg.node.listenPort}" ]; }; diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix index af1773dab267..4cd2f35113ec 100644 --- a/nixos/modules/services/misc/redmine.nix +++ b/nixos/modules/services/misc/redmine.nix @@ -74,6 +74,12 @@ in description = "Group under which Redmine is ran."; }; + address = mkOption { + type = types.str; + default = "0.0.0.0"; + description = "IP address Redmine should bind to."; + }; + port = mkOption { type = types.port; default = 3000; @@ -429,7 +435,31 @@ in Group = cfg.group; TimeoutSec = "300"; WorkingDirectory = "${cfg.package}/share/redmine"; - ExecStart="${bundle} exec rails server -u webrick -e production -p ${toString cfg.port} -P '${cfg.stateDir}/redmine.pid'"; + ExecStart="${bundle} exec rails server -u webrick -e production -b ${toString cfg.address} -p ${toString cfg.port} -P '${cfg.stateDir}/redmine.pid'"; + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; + ProtectSystem = "full"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + UMask = 027; }; }; @@ -448,4 +478,5 @@ in }; + meta.maintainers = with lib.maintainers; [ felixsinger ]; } diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix index 3a906f3e714f..5f011dbee4a6 100644 --- a/nixos/modules/services/misc/rippled.nix +++ b/nixos/modules/services/misc/rippled.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.rippled; opt = options.services.rippled; @@ -11,28 +8,28 @@ let dbCfg = db: '' type=${db.type} path=${db.path} - ${optionalString (db.compression != null) ("compression=${b2i db.compression}") } - ${optionalString (db.onlineDelete != null) ("online_delete=${toString db.onlineDelete}")} - ${optionalString (db.advisoryDelete != null) ("advisory_delete=${b2i db.advisoryDelete}")} + ${lib.optionalString (db.compression != null) ("compression=${b2i db.compression}") } + ${lib.optionalString (db.onlineDelete != null) ("online_delete=${toString db.onlineDelete}")} + ${lib.optionalString (db.advisoryDelete != null) ("advisory_delete=${b2i db.advisoryDelete}")} ${db.extraOpts} ''; rippledCfg = '' [server] - ${concatMapStringsSep "\n" (n: "port_${n}") (attrNames cfg.ports)} + ${lib.concatMapStringsSep "\n" (n: "port_${n}") (lib.attrNames cfg.ports)} - ${concatMapStrings (p: '' + ${lib.concatMapStrings (p: '' [port_${p.name}] ip=${p.ip} port=${toString p.port} - protocol=${concatStringsSep "," p.protocol} - ${optionalString (p.user != "") "user=${p.user}"} - ${optionalString (p.password != "") "user=${p.password}"} - admin=${concatStringsSep "," p.admin} - ${optionalString (p.ssl.key != null) "ssl_key=${p.ssl.key}"} - ${optionalString (p.ssl.cert != null) "ssl_cert=${p.ssl.cert}"} - ${optionalString (p.ssl.chain != null) "ssl_chain=${p.ssl.chain}"} - '') (attrValues cfg.ports)} + protocol=${lib.concatStringsSep "," p.protocol} + ${lib.optionalString (p.user != "") "user=${p.user}"} + ${lib.optionalString (p.password != "") "user=${p.password}"} + admin=${lib.concatStringsSep "," p.admin} + ${lib.optionalString (p.ssl.key != null) "ssl_key=${p.ssl.key}"} + ${lib.optionalString (p.ssl.cert != null) "ssl_cert=${p.ssl.cert}"} + ${lib.optionalString (p.ssl.chain != null) "ssl_chain=${p.ssl.chain}"} + '') (lib.attrValues cfg.ports)} [database_path] ${cfg.databasePath} @@ -40,22 +37,22 @@ let [node_db] ${dbCfg cfg.nodeDb} - ${optionalString (cfg.tempDb != null) '' + ${lib.optionalString (cfg.tempDb != null) '' [temp_db] ${dbCfg cfg.tempDb}''} - ${optionalString (cfg.importDb != null) '' + ${lib.optionalString (cfg.importDb != null) '' [import_db] ${dbCfg cfg.importDb}''} [ips] - ${concatStringsSep "\n" cfg.ips} + ${lib.concatStringsSep "\n" cfg.ips} [ips_fixed] - ${concatStringsSep "\n" cfg.ipsFixed} + ${lib.concatStringsSep "\n" cfg.ipsFixed} [validators] - ${concatStringsSep "\n" cfg.validators} + ${lib.concatStringsSep "\n" cfg.validators} [node_size] ${cfg.nodeSize} @@ -70,9 +67,9 @@ let ${toString cfg.validationQuorum} [sntp_servers] - ${concatStringsSep "\n" cfg.sntpServers} + ${lib.concatStringsSep "\n" cfg.sntpServers} - ${optionalString cfg.statsd.enable '' + ${lib.optionalString cfg.statsd.enable '' [insight] server=statsd address=${cfg.statsd.address} @@ -85,70 +82,70 @@ let portOptions = { name, ...}: { options = { - name = mkOption { + name = lib.mkOption { internal = true; default = name; }; - ip = mkOption { + ip = lib.mkOption { default = "127.0.0.1"; description = "Ip where rippled listens."; - type = types.str; + type = lib.types.str; }; - port = mkOption { + port = lib.mkOption { description = "Port where rippled listens."; - type = types.port; + type = lib.types.port; }; - protocol = mkOption { + protocol = lib.mkOption { description = "Protocols expose by rippled."; - type = types.listOf (types.enum ["http" "https" "ws" "wss" "peer"]); + type = lib.types.listOf (lib.types.enum ["http" "https" "ws" "wss" "peer"]); }; - user = mkOption { + user = lib.mkOption { description = "When set, these credentials will be required on HTTP/S requests."; - type = types.str; + type = lib.types.str; default = ""; }; - password = mkOption { + password = lib.mkOption { description = "When set, these credentials will be required on HTTP/S requests."; - type = types.str; + type = lib.types.str; default = ""; }; - admin = mkOption { + admin = lib.mkOption { description = "A comma-separated list of admin IP addresses."; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = ["127.0.0.1"]; }; ssl = { - key = mkOption { + key = lib.mkOption { description = '' Specifies the filename holding the SSL key in PEM format. ''; default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; }; - cert = mkOption { + cert = lib.mkOption { description = '' Specifies the path to the SSL certificate file in PEM format. This is not needed if the chain includes it. ''; default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; }; - chain = mkOption { + chain = lib.mkOption { description = '' If you need a certificate chain, specify the path to the certificate chain here. The chain may include the end certificate. ''; default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; }; }; }; @@ -156,44 +153,44 @@ let dbOptions = { options = { - type = mkOption { + type = lib.mkOption { description = "Rippled database type."; - type = types.enum ["rocksdb" "nudb"]; + type = lib.types.enum ["rocksdb" "nudb"]; default = "rocksdb"; }; - path = mkOption { + path = lib.mkOption { description = "Location to store the database."; - type = types.path; + type = lib.types.path; default = cfg.databasePath; - defaultText = literalExpression "config.${opt.databasePath}"; + defaultText = lib.literalExpression "config.${opt.databasePath}"; }; - compression = mkOption { + compression = lib.mkOption { description = "Whether to enable snappy compression."; - type = types.nullOr types.bool; + type = lib.types.nullOr lib.types.bool; default = null; }; - onlineDelete = mkOption { + onlineDelete = lib.mkOption { description = "Enable automatic purging of older ledger information."; - type = types.nullOr (types.addCheck types.int (v: v > 256)); + type = lib.types.nullOr (lib.types.addCheck lib.types.int (v: v > 256)); default = cfg.ledgerHistory; - defaultText = literalExpression "config.${opt.ledgerHistory}"; + defaultText = lib.literalExpression "config.${opt.ledgerHistory}"; }; - advisoryDelete = mkOption { + advisoryDelete = lib.mkOption { description = '' If set, then require administrative RPC call "can_delete" to enable online deletion of ledger records. ''; - type = types.nullOr types.bool; + type = lib.types.nullOr lib.types.bool; default = null; }; - extraOpts = mkOption { + extraOpts = lib.mkOption { description = "Extra database options."; - type = types.lines; + type = lib.types.lines; default = ""; }; }; @@ -207,13 +204,13 @@ in options = { services.rippled = { - enable = mkEnableOption "rippled, a decentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C++"; + enable = lib.mkEnableOption "rippled, a decentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C++"; - package = mkPackageOption pkgs "rippled" { }; + package = lib.mkPackageOption pkgs "rippled" { }; - ports = mkOption { + ports = lib.mkOption { description = "Ports exposed by rippled"; - type = with types; attrsOf (submodule portOptions); + type = with lib.types; attrsOf (submodule portOptions); default = { rpc = { port = 5005; @@ -235,9 +232,9 @@ in }; }; - nodeDb = mkOption { + nodeDb = lib.mkOption { description = "Rippled main database options."; - type = with types; nullOr (submodule dbOptions); + type = with lib.types; nullOr (submodule dbOptions); default = { type = "rocksdb"; extraOpts = '' @@ -250,28 +247,28 @@ in }; }; - tempDb = mkOption { + tempDb = lib.mkOption { description = "Rippled temporary database options."; - type = with types; nullOr (submodule dbOptions); + type = with lib.types; nullOr (submodule dbOptions); default = null; }; - importDb = mkOption { + importDb = lib.mkOption { description = "Settings for performing a one-time import."; - type = with types; nullOr (submodule dbOptions); + type = with lib.types; nullOr (submodule dbOptions); default = null; }; - nodeSize = mkOption { + nodeSize = lib.mkOption { description = '' Rippled size of the node you are running. "tiny", "small", "medium", "large", and "huge" ''; - type = types.enum ["tiny" "small" "medium" "large" "huge"]; + type = lib.types.enum ["tiny" "small" "medium" "large" "huge"]; default = "small"; }; - ips = mkOption { + ips = lib.mkOption { description = '' List of hostnames or ips where the Ripple protocol is served. For a starter list, you can either copy entries from: @@ -282,11 +279,11 @@ in address. By convention, if known, IPs are listed in from most to least trusted. ''; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = ["r.ripple.com 51235"]; }; - ipsFixed = mkOption { + ipsFixed = lib.mkOption { description = '' List of IP addresses or hostnames to which rippled should always attempt to maintain peer connections with. This is useful for @@ -296,16 +293,16 @@ in A port may optionally be specified after adding a space to the address ''; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = []; }; - validators = mkOption { + validators = lib.mkOption { description = '' List of nodes to always accept as validators. Nodes are specified by domain or public key. ''; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = [ "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1" "n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2" @@ -315,46 +312,46 @@ in ]; }; - databasePath = mkOption { + databasePath = lib.mkOption { description = '' Path to the ripple database. ''; - type = types.path; + type = lib.types.path; default = "/var/lib/rippled"; }; - validationQuorum = mkOption { + validationQuorum = lib.mkOption { description = '' The minimum number of trusted validations a ledger must have before the server considers it fully validated. ''; - type = types.int; + type = lib.types.int; default = 3; }; - ledgerHistory = mkOption { + ledgerHistory = lib.mkOption { description = '' The number of past ledgers to acquire on server startup and the minimum to maintain while running. ''; - type = types.either types.int (types.enum ["full"]); + type = lib.types.either lib.types.int (lib.types.enum ["full"]); default = 1296000; # 1 month }; - fetchDepth = mkOption { + fetchDepth = lib.mkOption { description = '' The number of past ledgers to serve to other peers that request historical ledger data (or "full" for no limit). ''; - type = types.either types.int (types.enum ["full"]); + type = lib.types.either lib.types.int (lib.types.enum ["full"]); default = "full"; }; - sntpServers = mkOption { + sntpServers = lib.mkOption { description = '' IP address or domain of NTP servers to use for time synchronization.; ''; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = [ "time.windows.com" "time.apple.com" @@ -363,40 +360,40 @@ in ]; }; - logLevel = mkOption { + logLevel = lib.mkOption { description = "Logging verbosity."; - type = types.enum ["debug" "error" "info"]; + type = lib.types.enum ["debug" "error" "info"]; default = "error"; }; statsd = { - enable = mkEnableOption "statsd monitoring for rippled"; + enable = lib.mkEnableOption "statsd monitoring for rippled"; - address = mkOption { + address = lib.mkOption { description = "The UDP address and port of the listening StatsD server."; default = "127.0.0.1:8125"; - type = types.str; + type = lib.types.str; }; - prefix = mkOption { + prefix = lib.mkOption { description = "A string prepended to each collected metric."; default = ""; - type = types.str; + type = lib.types.str; }; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Extra lines to be added verbatim to the rippled.cfg configuration file. ''; }; - config = mkOption { + config = lib.mkOption { internal = true; default = pkgs.writeText "rippled.conf" rippledCfg; - defaultText = literalMD "generated config file"; + defaultText = lib.literalMD "generated config file"; }; }; }; @@ -404,7 +401,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.rippled = { description = "Ripple server user"; diff --git a/nixos/modules/services/misc/snapper.nix b/nixos/modules/services/misc/snapper.nix index fc57683de328..42f782bcd6e1 100644 --- a/nixos/modules/services/misc/snapper.nix +++ b/nixos/modules/services/misc/snapper.nix @@ -4,17 +4,14 @@ lib, ... }: - -with lib; - let cfg = config.services.snapper; mkValue = v: - if isList v then + if lib.isList v then "\"${ - concatMapStringsSep " " (escape [ + lib.concatMapStringsSep " " (lib.escape [ "\\" " " ]) v @@ -23,7 +20,7 @@ let "yes" else if v == false then "no" - else if isString v then + else if lib.isString v then "\"${v}\"" else builtins.toJSON v; @@ -33,14 +30,22 @@ let # "it's recommended to always specify the filesystem type" -- man snapper-configs defaultOf = k: if k == "FSTYPE" then null else configOptions.${k}.default or null; - safeStr = types.strMatching "[^\n\"]*" // { + safeStr = lib.types.strMatching "[^\n\"]*" // { description = "string without line breaks or quotes"; descriptionClass = "conjunction"; }; + intOrNumberOrRange = lib.types.either lib.types.ints.unsigned ( + lib.types.strMatching "[[:digit:]]+(\-[[:digit:]]+)?" + // { + description = "string containing either a number or a range"; + descriptionClass = "conjunction"; + } + ); + configOptions = { - SUBVOLUME = mkOption { - type = types.path; + SUBVOLUME = lib.mkOption { + type = lib.types.path; description = '' Path of the subvolume or mount point. This path is a subvolume and has to contain a subvolume named @@ -49,16 +54,16 @@ let ''; }; - FSTYPE = mkOption { - type = types.enum [ "btrfs" ]; + FSTYPE = lib.mkOption { + type = lib.types.enum [ "btrfs" ]; default = "btrfs"; description = '' Filesystem type. Only btrfs is stable and tested. ''; }; - ALLOW_GROUPS = mkOption { - type = types.listOf safeStr; + ALLOW_GROUPS = lib.mkOption { + type = lib.types.listOf safeStr; default = [ ]; description = '' List of groups allowed to operate with the config. @@ -67,8 +72,8 @@ let ''; }; - ALLOW_USERS = mkOption { - type = types.listOf safeStr; + ALLOW_USERS = lib.mkOption { + type = lib.types.listOf safeStr; default = [ ]; example = [ "alice" ]; description = '' @@ -79,64 +84,64 @@ let ''; }; - TIMELINE_CLEANUP = mkOption { - type = types.bool; + TIMELINE_CLEANUP = lib.mkOption { + type = lib.types.bool; default = false; description = '' Defines whether the timeline cleanup algorithm should be run for the config. ''; }; - TIMELINE_CREATE = mkOption { - type = types.bool; + TIMELINE_CREATE = lib.mkOption { + type = lib.types.bool; default = false; description = '' Defines whether hourly snapshots should be created. ''; }; - TIMELINE_LIMIT_HOURLY = mkOption { - type = types.int; + TIMELINE_LIMIT_HOURLY = lib.mkOption { + type = intOrNumberOrRange; default = 10; description = '' Limits for timeline cleanup. ''; }; - TIMELINE_LIMIT_DAILY = mkOption { - type = types.int; + TIMELINE_LIMIT_DAILY = lib.mkOption { + type = intOrNumberOrRange; default = 10; description = '' Limits for timeline cleanup. ''; }; - TIMELINE_LIMIT_WEEKLY = mkOption { - type = types.int; + TIMELINE_LIMIT_WEEKLY = lib.mkOption { + type = intOrNumberOrRange; default = 0; description = '' Limits for timeline cleanup. ''; }; - TIMELINE_LIMIT_MONTHLY = mkOption { - type = types.int; + TIMELINE_LIMIT_MONTHLY = lib.mkOption { + type = intOrNumberOrRange; default = 10; description = '' Limits for timeline cleanup. ''; }; - TIMELINE_LIMIT_QUARTERLY = mkOption { - type = types.int; + TIMELINE_LIMIT_QUARTERLY = lib.mkOption { + type = intOrNumberOrRange; default = 0; description = '' Limits for timeline cleanup. ''; }; - TIMELINE_LIMIT_YEARLY = mkOption { - type = types.int; + TIMELINE_LIMIT_YEARLY = lib.mkOption { + type = intOrNumberOrRange; default = 10; description = '' Limits for timeline cleanup. @@ -148,16 +153,16 @@ in { options.services.snapper = { - snapshotRootOnBoot = mkOption { - type = types.bool; + snapshotRootOnBoot = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to snapshot root on boot ''; }; - snapshotInterval = mkOption { - type = types.str; + snapshotInterval = lib.mkOption { + type = lib.types.str; default = "hourly"; description = '' Snapshot interval. @@ -167,9 +172,9 @@ in ''; }; - persistentTimer = mkOption { + persistentTimer = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; example = true; description = '' Set the `Persistent` option for the @@ -179,8 +184,8 @@ in ''; }; - cleanupInterval = mkOption { - type = types.str; + cleanupInterval = lib.mkOption { + type = lib.types.str; default = "1d"; description = '' Cleanup interval. @@ -190,17 +195,17 @@ in ''; }; - filters = mkOption { - type = types.nullOr types.lines; + filters = lib.mkOption { + type = lib.types.nullOr lib.types.lines; default = null; description = '' Global display difference filter. See man:snapper(8) for more details. ''; }; - configs = mkOption { + configs = lib.mkOption { default = { }; - example = literalExpression '' + example = lib.literalExpression '' { home = { SUBVOLUME = "/home"; @@ -216,14 +221,14 @@ in is valid here, even if NixOS doesn't document it. ''; - type = types.attrsOf ( - types.submodule { - freeformType = types.attrsOf ( - types.oneOf [ - (types.listOf safeStr) - types.bool + type = lib.types.attrsOf ( + lib.types.submodule { + freeformType = lib.types.attrsOf ( + lib.types.oneOf [ + (lib.types.listOf safeStr) + lib.types.bool safeStr - types.number + lib.types.number ] ); @@ -233,7 +238,7 @@ in }; }; - config = mkIf (cfg.configs != { }) ( + config = lib.mkIf (cfg.configs != { }) ( let documentation = [ "man:snapper(8)" @@ -254,11 +259,11 @@ in SNAPPER_CONFIGS="${lib.concatStringsSep " " (builtins.attrNames cfg.configs)}" ''; } - // (mapAttrs' ( + // (lib.mapAttrs' ( name: subvolume: - nameValuePair "snapper/configs/${name}" ({ + lib.nameValuePair "snapper/configs/${name}" ({ text = lib.generators.toKeyValue { inherit mkKeyValue; } ( - filterAttrs (k: v: v != defaultOf k) subvolume + lib.filterAttrs (k: v: v != defaultOf k) subvolume ); }) ) cfg.configs) @@ -324,7 +329,7 @@ in unitConfig.ConditionPathExists = "/etc/snapper/configs/root"; }; - assertions = concatMap ( + assertions = lib.concatMap ( name: let sub = cfg.configs.${name}; @@ -341,16 +346,16 @@ in ++ map (attr: { - assertion = !(hasAttr attr sub); + assertion = !(lib.hasAttr attr sub); message = '' - The option definition `services.snapper.configs.${name}.${attr}' has been renamed to `services.snapper.configs.${name}.${toUpper attr}'. + The option definition `services.snapper.configs.${name}.${attr}' has been renamed to `services.snapper.configs.${name}.${lib.toUpper attr}'. ''; }) [ "fstype" "subvolume" ] - ) (attrNames cfg.configs); + ) (lib.attrNames cfg.configs); } ); diff --git a/nixos/modules/services/misc/tabby.nix b/nixos/modules/services/misc/tabby.nix index d63a6b24ae3d..8fabd10d90fa 100644 --- a/nixos/modules/services/misc/tabby.nix +++ b/nixos/modules/services/misc/tabby.nix @@ -71,7 +71,7 @@ in - nixpkgs.config.cudaSupport - nixpkgs.config.rocmSupport - - if stdenv.isDarwin && stdenv.isAarch64 + - if stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64 IFF multiple acceleration methods are found to be enabled or if you haven't set either `cudaSupport or rocmSupport` you will have to diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix index 7760f1bdadeb..618d369be21f 100644 --- a/nixos/modules/services/misc/taskserver/default.nix +++ b/nixos/modules/services/misc/taskserver/default.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.taskserver; taskd = "${pkgs.taskserver}/bin/taskd"; - mkManualPkiOption = desc: mkOption { - type = types.nullOr types.path; + mkManualPkiOption = desc: lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' ${desc} @@ -46,8 +43,8 @@ let ::: ''; - mkExpireOption = desc: mkOption { - type = types.nullOr types.int; + mkExpireOption = desc: lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 365; apply = val: if val == null then -1 else val; @@ -58,8 +55,8 @@ let }; autoPkiOptions = { - bits = mkOption { - type = types.int; + bits = lib.mkOption { + type = lib.types.int; default = 4096; example = 2048; description = mkAutoDesc "The bit size for generated keys."; @@ -75,20 +72,20 @@ let needToCreateCA = let notFound = path: let - dotted = concatStringsSep "." path; + dotted = lib.concatStringsSep "." path; in throw "Can't find option definitions for path `${dotted}'."; findPkiDefinitions = path: attrs: let mkSublist = key: val: let - newPath = path ++ singleton key; - in if isOption val - then attrByPath newPath (notFound newPath) cfg.pki.manual + newPath = path ++ lib.singleton key; + in if lib.isOption val + then lib.attrByPath newPath (notFound newPath) cfg.pki.manual else findPkiDefinitions newPath val; - in flatten (mapAttrsToList mkSublist attrs); - in all (x: x == null) (findPkiDefinitions [] manualPkiOptions); + in lib.flatten (lib.mapAttrsToList mkSublist attrs); + in lib.all (x: x == null) (findPkiDefinitions [] manualPkiOptions); orgOptions = { ... }: { - options.users = mkOption { - type = types.uniq (types.listOf types.str); + options.users = lib.mkOption { + type = lib.types.uniq (lib.types.listOf lib.types.str); default = []; example = [ "alice" "bob" ]; description = '' @@ -96,8 +93,8 @@ let ''; }; - options.groups = mkOption { - type = types.listOf types.str; + options.groups = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "workers" "slackers" ]; description = '' @@ -137,8 +134,8 @@ let in { options = { services.taskserver = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = let url = "https://nixos.org/manual/nixos/stable/index.html#module-services-taskserver"; @@ -150,26 +147,26 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "taskd"; description = "User for Taskserver."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "taskd"; description = "Group for Taskserver."; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/taskserver"; description = "Data directory for Taskserver."; }; - ciphers = mkOption { - type = types.nullOr (types.separatedString ":"); + ciphers = lib.mkOption { + type = lib.types.nullOr (lib.types.separatedString ":"); default = null; example = "NORMAL:-VERS-SSL3.0"; description = let @@ -180,8 +177,8 @@ in { ''; }; - organisations = mkOption { - type = types.attrsOf (types.submodule orgOptions); + organisations = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule orgOptions); default = {}; example.myShinyOrganisation.users = [ "alice" "bob" ]; example.myShinyOrganisation.groups = [ "staff" "outsiders" ]; @@ -193,24 +190,24 @@ in { ''; }; - confirmation = mkOption { - type = types.bool; + confirmation = lib.mkOption { + type = lib.types.bool; default = true; description = '' Determines whether certain commands are confirmed. ''; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Logs debugging information. ''; }; - extensions = mkOption { - type = types.nullOr types.path; + extensions = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Fully qualified path of the Taskserver extension scripts. @@ -218,32 +215,32 @@ in { ''; }; - ipLog = mkOption { - type = types.bool; + ipLog = lib.mkOption { + type = lib.types.bool; default = false; description = '' Logs the IP addresses of incoming requests. ''; }; - queueSize = mkOption { - type = types.int; + queueSize = lib.mkOption { + type = lib.types.int; default = 10; description = '' Size of the connection backlog, see {manpage}`listen(2)`. ''; }; - requestLimit = mkOption { - type = types.int; + requestLimit = lib.mkOption { + type = lib.types.int; default = 1048576; description = '' Size limit of incoming requests, in bytes. ''; }; - allowedClientIDs = mkOption { - type = with types; either str (listOf str); + allowedClientIDs = lib.mkOption { + type = with lib.types; either str (listOf str); default = []; example = [ "[Tt]ask [2-9]+" ]; description = '' @@ -256,8 +253,8 @@ in { ''; }; - disallowedClientIDs = mkOption { - type = with types; either str (listOf str); + disallowedClientIDs = lib.mkOption { + type = with lib.types; either str (listOf str); default = []; example = [ "[Tt]ask [2-9]+" ]; description = '' @@ -270,8 +267,8 @@ in { ''; }; - listenHost = mkOption { - type = types.str; + listenHost = lib.mkOption { + type = lib.types.str; default = "localhost"; example = "::"; description = '' @@ -279,24 +276,24 @@ in { ''; }; - listenPort = mkOption { - type = types.int; + listenPort = lib.mkOption { + type = lib.types.int; default = 53589; description = '' Port number of the Taskserver. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to open the firewall for the specified Taskserver port. ''; }; - fqdn = mkOption { - type = types.str; + fqdn = lib.mkOption { + type = lib.types.str; default = "localhost"; description = '' The fully qualified domain name of this server, which is also used @@ -304,8 +301,8 @@ in { ''; }; - trust = mkOption { - type = types.enum [ "allow all" "strict" ]; + trust = lib.mkOption { + type = lib.types.enum [ "allow all" "strict" ]; default = "strict"; description = '' Determines how client certificates are validated. @@ -320,8 +317,8 @@ in { pki.manual = manualPkiOptions; pki.auto = autoPkiOptions; - config = mkOption { - type = types.attrs; + config = lib.mkOption { + type = lib.types.attrs; example.client.cert = "/tmp/debugging.cert"; description = '' Configuration options to pass to Taskserver. @@ -340,23 +337,23 @@ in { ''; apply = let mkKey = path: if path == ["server" "listen"] then "server" - else concatStringsSep "." path; + else lib.concatStringsSep "." path; recurse = path: attrs: let mapper = name: val: let newPath = path ++ [ name ]; scalar = if val == true then "true" else if val == false then "false" else toString val; - in if isAttrs val then recurse newPath val + in if lib.isAttrs val then recurse newPath val else [ "${mkKey newPath}=${scalar}" ]; - in concatLists (mapAttrsToList mapper attrs); + in lib.concatLists (lib.mapAttrsToList mapper attrs); in recurse []; }; }; }; imports = [ - (mkRemovedOptionModule ["services" "taskserver" "extraConfig"] '' + (lib.mkRemovedOptionModule ["services" "taskserver" "extraConfig"] '' This option was removed in favor of `services.taskserver.config` with different semantics (it's now a list of attributes instead of lines). @@ -366,11 +363,11 @@ in { '') ]; - config = mkMerge [ - (mkIf cfg.enable { + config = lib.mkMerge [ + (lib.mkIf cfg.enable { environment.systemPackages = [ nixos-taskserver ]; - users.users = optionalAttrs (cfg.user == "taskd") { + users.users = lib.optionalAttrs (cfg.user == "taskd") { taskd = { uid = config.ids.uids.taskd; description = "Taskserver user"; @@ -378,7 +375,7 @@ in { }; }; - users.groups = optionalAttrs (cfg.group == "taskd") { + users.groups = lib.optionalAttrs (cfg.group == "taskd") { taskd.gid = config.ids.gids.taskd; }; @@ -413,7 +410,7 @@ in { } else { cert = "${cfg.pki.manual.server.cert}"; key = "${cfg.pki.manual.server.key}"; - ${mapNullable (_: "crl") cfg.pki.manual.server.crl} = "${cfg.pki.manual.server.crl}"; + ${lib.mapNullable (_: "crl") cfg.pki.manual.server.crl} = "${cfg.pki.manual.server.crl}"; }); ca.cert = if needToCreateCA then "${cfg.dataDir}/keys/ca.cert" @@ -464,8 +461,8 @@ in { serviceConfig = { ExecStart = let - mkCfgFlag = flag: escapeShellArg "--${flag}"; - cfgFlags = concatMapStringsSep " " mkCfgFlag cfg.config; + mkCfgFlag = flag: lib.escapeShellArg "--${flag}"; + cfgFlags = lib.concatMapStringsSep " " mkCfgFlag cfg.config; in "@${taskd} taskd server ${cfgFlags}"; ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID"; Restart = "on-failure"; @@ -477,7 +474,7 @@ in { }; }; }) - (mkIf (cfg.enable && needToCreateCA) { + (lib.mkIf (cfg.enable && needToCreateCA) { systemd.services.taskserver-ca = { wantedBy = [ "taskserver.service" ]; after = [ "taskserver-init.service" ]; @@ -561,7 +558,7 @@ in { ''; }; }) - (mkIf (cfg.enable && cfg.openFirewall) { + (lib.mkIf (cfg.enable && cfg.openFirewall) { networking.firewall.allowedTCPPorts = [ cfg.listenPort ]; }) ]; diff --git a/nixos/modules/services/misc/turn-rs.nix b/nixos/modules/services/misc/turn-rs.nix new file mode 100644 index 000000000000..b591205417fb --- /dev/null +++ b/nixos/modules/services/misc/turn-rs.nix @@ -0,0 +1,86 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.services.turn-rs; + format = pkgs.formats.toml { }; +in +{ + options.services.turn-rs = { + enable = lib.mkEnableOption "turn-rs server"; + package = lib.mkPackageOption pkgs "turn-rs" { }; + + secretFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/turn-rs.env"; + description = '' + Environment variables from this file will be interpolated into the + final config file using envsubst with this syntax: `$ENVIRONMENT` or + `''${VARIABLE}`. + The file should contain lines formatted as `SECRET_VAR=SECRET_VALUE`. + This is useful to avoid putting secrets into the nix store. + ''; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = format.type; + }; + description = "Turn-rs server config file"; + default = { }; + example = { + turn = { + realm = "localhost"; + interfaces = [ + { + transport = "udp"; + bind = "127.0.0.1:3478"; + external = "127.0.0.1:3478"; + } + { + transport = "tcp"; + bind = "127.0.0.1:3478"; + external = "127.0.0.1:3478"; + } + ]; + }; + + auth.static_credentials = { + user1 = "test"; + user2 = "test"; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + services.turn-rs.settings = { + api.bind = lib.mkDefault "127.0.0.1:3000"; + log.level = lib.mkDefault "info"; + }; + + systemd.services.turn-rs = { + enable = true; + wantedBy = [ "multi-user.target" ]; + description = "Turn-rs Server Daemon"; + preStart = + let + configFile = format.generate "turn-rs-config.toml" cfg.settings; + in + '' + ${lib.getExe pkgs.envsubst} -i "${configFile}" -o /run/turn-rs/config.toml + ''; + serviceConfig = { + RuntimeDirectory = "turn-rs"; + EnvironmentFile = lib.optional (cfg.secretFile != null) cfg.secretFile; + ExecStart = "${lib.getExe cfg.package} --config=/run/turn-rs/config.toml"; + DynamicUser = true; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/tzupdate.nix b/nixos/modules/services/misc/tzupdate.nix index be63bb179e42..9e979bb47675 100644 --- a/nixos/modules/services/misc/tzupdate.nix +++ b/nixos/modules/services/misc/tzupdate.nix @@ -30,16 +30,15 @@ in { description = "tzupdate timezone update service"; wants = [ "network-online.target" ]; after = [ "network-online.target" ]; + script = '' + timedatectl set-timezone $(${lib.getExe pkgs.tzupdate} --print-only) + ''; serviceConfig = { Type = "oneshot"; - # We could link directly into pkgs.tzdata, but at least timedatectl seems - # to expect the symlink to point directly to a file in etc. - # Setting the "debian timezone file" to point at /dev/null stops it doing anything. - ExecStart = "${pkgs.tzupdate}/bin/tzupdate -z /etc/zoneinfo -d /dev/null"; }; }; }; - meta.maintainers = [ ]; + meta.maintainers = with lib.maintainers; [ doronbehar ]; } diff --git a/nixos/modules/services/monitoring/datadog-agent.nix b/nixos/modules/services/monitoring/datadog-agent.nix index 5ac98bdf0382..04232b3c9346 100644 --- a/nixos/modules/services/monitoring/datadog-agent.nix +++ b/nixos/modules/services/monitoring/datadog-agent.nix @@ -288,7 +288,7 @@ in { path = [ ]; script = '' export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile}) - ${datadogPkg}/bin/trace-agent -config /etc/datadog-agent/datadog.yaml + ${datadogPkg}/bin/trace-agent --config /etc/datadog-agent/datadog.yaml ''; }); diff --git a/nixos/modules/services/monitoring/gatus.nix b/nixos/modules/services/monitoring/gatus.nix new file mode 100644 index 000000000000..408115f5d514 --- /dev/null +++ b/nixos/modules/services/monitoring/gatus.nix @@ -0,0 +1,132 @@ +{ + pkgs, + lib, + config, + ... +}: +let + cfg = config.services.gatus; + + settingsFormat = pkgs.formats.yaml { }; + + inherit (lib) + getExe + literalExpression + maintainers + mkEnableOption + mkIf + mkOption + mkPackageOption + ; + + inherit (lib.types) + bool + int + nullOr + path + submodule + ; +in +{ + options.services.gatus = { + enable = mkEnableOption "Gatus"; + + package = mkPackageOption pkgs "gatus" { }; + + configFile = mkOption { + type = path; + default = settingsFormat.generate "gatus.yaml" cfg.settings; + defaultText = literalExpression '' + let settingsFormat = pkgs.formats.yaml { }; in settingsFormat.generate "gatus.yaml" cfg.settings; + ''; + description = '' + Path to the Gatus configuration file. + Overrides any configuration made using the `settings` option. + ''; + }; + + environmentFile = mkOption { + type = nullOr path; + default = null; + description = '' + File to load as environment file. + Environmental variables from this file can be interpolated in the configuration file using `''${VARIABLE}`. + This is useful to avoid putting secrets into the nix store. + ''; + }; + + settings = mkOption { + type = submodule { + freeformType = settingsFormat.type; + options = { + web.port = mkOption { + type = int; + default = 8080; + description = '' + The TCP port to serve the Gatus service at. + ''; + }; + }; + }; + + default = { }; + + example = literalExpression '' + { + web.port = 8080; + endpoints = [{ + name = "website"; + url = "https://twin.sh/health"; + interval = "5m"; + conditions = [ + "[STATUS] == 200" + "[BODY].status == UP" + "[RESPONSE_TIME] < 300" + ]; + }]; + } + ''; + + description = '' + Configuration for Gatus. + Supported options can be found at the [docs](https://gatus.io/docs). + ''; + }; + + openFirewall = mkOption { + type = bool; + default = false; + description = '' + Whether to open the firewall for the Gatus web interface. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.gatus = { + description = "Automated developer-oriented status page"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + DynamicUser = true; + User = "gatus"; + Group = "gatus"; + Type = "simple"; + Restart = "on-failure"; + ExecStart = getExe cfg.package; + StateDirectory = "gatus"; + SyslogIdentifier = "gatus"; + EnvironmentFile = lib.optional (cfg.environmentFile != null) cfg.environmentFile; + }; + + environment = { + GATUS_CONFIG_PATH = cfg.configFile; + }; + }; + + networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ cfg.settings.web.port ]; + }; + + meta.maintainers = with maintainers; [ pizzapim ]; +} diff --git a/nixos/modules/services/monitoring/gitwatch.nix b/nixos/modules/services/monitoring/gitwatch.nix new file mode 100644 index 000000000000..80b5f8f7c80a --- /dev/null +++ b/nixos/modules/services/monitoring/gitwatch.nix @@ -0,0 +1,87 @@ +{ + lib, + pkgs, + config, + ... +}: +let + mkSystemdService = + name: cfg: + lib.nameValuePair "gitwatch-${name}" ( + let + getvar = flag: var: lib.optionalString (cfg."${var}" != null) "${flag} ${cfg."${var}"}"; + branch = getvar "-b" "branch"; + remote = getvar "-r" "remote"; + in + rec { + inherit (cfg) enable; + after = [ "network-online.target" ]; + wants = after; + wantedBy = [ "multi-user.target" ]; + description = "gitwatch for ${name}"; + path = with pkgs; [ + gitwatch + git + openssh + ]; + script = '' + if [ -n "${cfg.remote}" ] && ! [ -d "${cfg.path}" ]; then + git clone ${branch} "${cfg.remote}" "${cfg.path}" + fi + gitwatch ${remote} ${branch} ${cfg.path} + ''; + serviceConfig.User = cfg.user; + } + ); +in +{ + options.services.gitwatch = lib.mkOption { + description = '' + A set of git repositories to watch for. See + [gitwatch](https://github.com/gitwatch/gitwatch) for more. + ''; + default = { }; + example = { + my-repo = { + enable = true; + user = "user"; + path = "/home/user/watched-project"; + remote = "git@github.com:me/my-project.git"; + }; + disabled-repo = { + enable = false; + user = "user"; + path = "/home/user/disabled-project"; + remote = "git@github.com:me/my-old-project.git"; + branch = "autobranch"; + }; + }; + type = + with lib.types; + attrsOf (submodule { + options = { + enable = lib.mkEnableOption "watching for repo"; + path = lib.mkOption { + description = "The path to repo in local machine"; + type = str; + }; + user = lib.mkOption { + description = "The name of services's user"; + type = str; + default = "root"; + }; + remote = lib.mkOption { + description = "Optional url of remote repository"; + type = nullOr str; + default = null; + }; + branch = lib.mkOption { + description = "Optional branch in remote repository"; + type = nullOr str; + default = null; + }; + }; + }); + }; + config.systemd.services = lib.mapAttrs' mkSystemdService config.services.gitwatch; +} diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix index 3a8f41f32078..7987f34f1278 100644 --- a/nixos/modules/services/monitoring/graphite.nix +++ b/nixos/modules/services/monitoring/graphite.nix @@ -1,11 +1,8 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.graphite; opt = options.services.graphite; - writeTextOrNull = f: t: mapNullable (pkgs.writeTextDir f) t; + writeTextOrNull = f: t: lib.mapNullable (pkgs.writeTextDir f) t; dataDir = cfg.dataDir; staticDir = cfg.dataDir + "/static"; @@ -20,7 +17,7 @@ let graphiteLocalSettings = pkgs.writeText "graphite_local_settings.py" ( "STATIC_ROOT = '${staticDir}'\n" + - optionalString (config.time.timeZone != null) "TIME_ZONE = '${config.time.timeZone}'\n" + lib.optionalString (config.time.timeZone != null) "TIME_ZONE = '${config.time.timeZone}'\n" + cfg.web.extraConfig ); @@ -32,7 +29,7 @@ let configDir = pkgs.buildEnv { name = "graphite-config"; - paths = lists.filter (el: el != null) [ + paths = lib.lists.filter (el: el != null) [ (writeTextOrNull "carbon.conf" cfg.carbon.config) (writeTextOrNull "storage-aggregation.conf" cfg.carbon.storageAggregation) (writeTextOrNull "storage-schemas.conf" cfg.carbon.storageSchemas) @@ -62,16 +59,16 @@ let in { imports = [ - (mkRemovedOptionModule ["services" "graphite" "api"] "") - (mkRemovedOptionModule ["services" "graphite" "beacon"] "") - (mkRemovedOptionModule ["services" "graphite" "pager"] "") + (lib.mkRemovedOptionModule ["services" "graphite" "api"] "") + (lib.mkRemovedOptionModule ["services" "graphite" "beacon"] "") + (lib.mkRemovedOptionModule ["services" "graphite" "pager"] "") ]; ###### interface options.services.graphite = { - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/db/graphite"; description = '' Data directory for graphite. @@ -79,26 +76,26 @@ in { }; web = { - enable = mkOption { + enable = lib.mkOption { description = "Whether to enable graphite web frontend."; default = false; - type = types.bool; + type = lib.types.bool; }; - listenAddress = mkOption { + listenAddress = lib.mkOption { description = "Graphite web frontend listen address."; default = "127.0.0.1"; - type = types.str; + type = lib.types.str; }; - port = mkOption { + port = lib.mkOption { description = "Graphite web frontend port."; default = 8080; - type = types.port; + type = lib.types.port; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = '' Graphite webapp settings. See: @@ -108,7 +105,7 @@ in { }; carbon = { - config = mkOption { + config = lib.mkOption { description = "Content of carbon configuration file."; default = '' [cache] @@ -121,19 +118,19 @@ in { LOG_UPDATES = False LOG_CACHE_HITS = False ''; - type = types.str; + type = lib.types.str; }; - enableCache = mkOption { + enableCache = lib.mkOption { description = "Whether to enable carbon cache, the graphite storage daemon."; default = false; - type = types.bool; + type = lib.types.bool; }; - storageAggregation = mkOption { + storageAggregation = lib.mkOption { description = "Defines how to aggregate data to lower-precision retentions."; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = '' [all_min] pattern = \.min$ @@ -142,10 +139,10 @@ in { ''; }; - storageSchemas = mkOption { + storageSchemas = lib.mkOption { description = "Defines retention rates for storing metrics."; default = ""; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = '' [apache_busyWorkers] pattern = ^servers\.www.*\.workers\.busyWorkers$ @@ -153,27 +150,27 @@ in { ''; }; - blacklist = mkOption { + blacklist = lib.mkOption { description = "Any metrics received which match one of the expressions will be dropped."; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = "^some\\.noisy\\.metric\\.prefix\\..*"; }; - whitelist = mkOption { + whitelist = lib.mkOption { description = "Only metrics received which match one of the expressions will be persisted."; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = ".*"; }; - rewriteRules = mkOption { + rewriteRules = lib.mkOption { description = '' Regular expression patterns that can be used to rewrite metric names in a search and replace fashion. ''; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = '' [post] _sum$ = @@ -181,16 +178,16 @@ in { ''; }; - enableRelay = mkOption { + enableRelay = lib.mkOption { description = "Whether to enable carbon relay, the carbon replication and sharding service."; default = false; - type = types.bool; + type = lib.types.bool; }; - relayRules = mkOption { + relayRules = lib.mkOption { description = "Relay rules are used to send certain metrics to a certain backend."; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = '' [example] pattern = ^mydata\.foo\..+ @@ -198,16 +195,16 @@ in { ''; }; - enableAggregator = mkOption { + enableAggregator = lib.mkOption { description = "Whether to enable carbon aggregator, the carbon buffering service."; default = false; - type = types.bool; + type = lib.types.bool; }; - aggregationRules = mkOption { + aggregationRules = lib.mkOption { description = "Defines if and how received metrics will be aggregated."; default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; example = '' .applications..all.requests (60) = sum .applications..*.requests .applications..all.latency (60) = avg .applications..*.latency @@ -216,47 +213,47 @@ in { }; seyren = { - enable = mkOption { + enable = lib.mkOption { description = "Whether to enable seyren service."; default = false; - type = types.bool; + type = lib.types.bool; }; - port = mkOption { + port = lib.mkOption { description = "Seyren listening port."; default = 8081; - type = types.port; + type = lib.types.port; }; - seyrenUrl = mkOption { + seyrenUrl = lib.mkOption { default = "http://localhost:${toString cfg.seyren.port}/"; - defaultText = literalExpression ''"http://localhost:''${toString config.${opt.seyren.port}}/"''; + defaultText = lib.literalExpression ''"http://localhost:''${toString config.${opt.seyren.port}}/"''; description = "Host where seyren is accessible."; - type = types.str; + type = lib.types.str; }; - graphiteUrl = mkOption { + graphiteUrl = lib.mkOption { default = "http://${cfg.web.listenAddress}:${toString cfg.web.port}"; - defaultText = literalExpression ''"http://''${config.${opt.web.listenAddress}}:''${toString config.${opt.web.port}}"''; + defaultText = lib.literalExpression ''"http://''${config.${opt.web.listenAddress}}:''${toString config.${opt.web.port}}"''; description = "Host where graphite service runs."; - type = types.str; + type = lib.types.str; }; - mongoUrl = mkOption { + mongoUrl = lib.mkOption { default = "mongodb://${config.services.mongodb.bind_ip}:27017/seyren"; - defaultText = literalExpression ''"mongodb://''${config.services.mongodb.bind_ip}:27017/seyren"''; + defaultText = lib.literalExpression ''"mongodb://''${config.services.mongodb.bind_ip}:27017/seyren"''; description = "Mongodb connection string."; - type = types.str; + type = lib.types.str; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = {}; description = '' Extra seyren configuration. See ''; - type = types.attrsOf types.str; - example = literalExpression '' + type = lib.types.attrsOf lib.types.str; + example = lib.literalExpression '' { GRAPHITE_USERNAME = "user"; GRAPHITE_PASSWORD = "pass"; @@ -268,14 +265,15 @@ in { ###### implementation - config = mkMerge [ - (mkIf cfg.carbon.enableCache { + config = lib.mkMerge [ + (lib.mkIf cfg.carbon.enableCache { systemd.services.carbonCache = let name = "carbon-cache"; in { description = "Graphite Data Storage Backend"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; environment = carbonEnv; serviceConfig = { + Slice = "system-graphite.slice"; RuntimeDirectory = name; ExecStart = "${pkgs.python3Packages.twisted}/bin/twistd ${carbonOpts name}"; User = "graphite"; @@ -290,7 +288,7 @@ in { }; }) - (mkIf cfg.carbon.enableAggregator { + (lib.mkIf cfg.carbon.enableAggregator { systemd.services.carbonAggregator = let name = "carbon-aggregator"; in { enable = cfg.carbon.enableAggregator; description = "Carbon Data Aggregator"; @@ -298,6 +296,7 @@ in { after = [ "network.target" ]; environment = carbonEnv; serviceConfig = { + Slice = "system-graphite.slice"; RuntimeDirectory = name; ExecStart = "${pkgs.python3Packages.twisted}/bin/twistd ${carbonOpts name}"; User = "graphite"; @@ -307,13 +306,14 @@ in { }; }) - (mkIf cfg.carbon.enableRelay { + (lib.mkIf cfg.carbon.enableRelay { systemd.services.carbonRelay = let name = "carbon-relay"; in { description = "Carbon Data Relay"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; environment = carbonEnv; serviceConfig = { + Slice = "system-graphite.slice"; RuntimeDirectory = name; ExecStart = "${pkgs.python3Packages.twisted}/bin/twistd ${carbonOpts name}"; User = "graphite"; @@ -323,13 +323,13 @@ in { }; }) - (mkIf (cfg.carbon.enableCache || cfg.carbon.enableAggregator || cfg.carbon.enableRelay) { + (lib.mkIf (cfg.carbon.enableCache || cfg.carbon.enableAggregator || cfg.carbon.enableRelay) { environment.systemPackages = [ pkgs.python3Packages.carbon ]; }) - (mkIf cfg.web.enable ({ + (lib.mkIf cfg.web.enable ({ systemd.services.graphiteWeb = { description = "Graphite Web Interface"; wantedBy = [ "multi-user.target" ]; @@ -343,7 +343,7 @@ in { ]; }; penvPack = "${penv}/${pkgs.python3.sitePackages}"; - in concatStringsSep ":" [ + in lib.concatStringsSep ":" [ "${graphiteLocalSettingsDir}" "${penvPack}" # explicitly adding pycairo in path because it cannot be imported via buildEnv @@ -363,6 +363,7 @@ in { User = "graphite"; Group = "graphite"; PermissionsStartOnly = true; + Slice = "system-graphite.slice"; }; preStart = '' if ! test -e ${dataDir}/db-created; then @@ -389,7 +390,7 @@ in { environment.systemPackages = [ pkgs.python3Packages.graphite-web ]; })) - (mkIf cfg.seyren.enable { + (lib.mkIf cfg.seyren.enable { systemd.services.seyren = { description = "Graphite Alerting Dashboard"; wantedBy = [ "multi-user.target" ]; @@ -400,6 +401,7 @@ in { WorkingDirectory = dataDir; User = "graphite"; Group = "graphite"; + Slice = "system-graphite.slice"; }; preStart = '' if ! test -e ${dataDir}/db-created; then @@ -409,13 +411,18 @@ in { ''; }; - services.mongodb.enable = mkDefault true; + services.mongodb.enable = lib.mkDefault true; }) - (mkIf ( + (lib.mkIf ( cfg.carbon.enableCache || cfg.carbon.enableAggregator || cfg.carbon.enableRelay || cfg.web.enable || cfg.seyren.enable ) { + systemd.slices.system-graphite = { + description = "Graphite Graphing System Slice"; + documentation = [ "https://graphite.readthedocs.io/en/latest/overview.html" ]; + }; + users.users.graphite = { uid = config.ids.uids.graphite; group = "graphite"; diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix index c47da2cc075d..6e18ef562b8f 100644 --- a/nixos/modules/services/monitoring/netdata.nix +++ b/nixos/modules/services/monitoring/netdata.nix @@ -218,7 +218,6 @@ in { ps.psycopg2 ps.python-ldap ps.netdata-pandas - ps.changefinder ]); services.netdata.configDir.".opt-out-from-anonymous-statistics" = mkIf (!cfg.enableAnalyticsReporting) (pkgs.writeText ".opt-out-from-anonymous-statistics" ""); @@ -374,14 +373,6 @@ in { permissions = "u+rx,g+x,o-rwx"; }; - "logs-management.plugin" = { - source = "${cfg.package}/libexec/netdata/plugins.d/logs-management.plugin.org"; - capabilities = "cap_dac_read_search,cap_syslog+ep"; - owner = cfg.user; - group = cfg.group; - permissions = "u+rx,g+x,o-rwx"; - }; - "slabinfo.plugin" = { source = "${cfg.package}/libexec/netdata/plugins.d/slabinfo.plugin.org"; capabilities = "cap_dac_override+ep"; diff --git a/nixos/modules/services/monitoring/prometheus/exporters.md b/nixos/modules/services/monitoring/prometheus/exporters.md index d291020d3673..23464b9d315e 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.md +++ b/nixos/modules/services/monitoring/prometheus/exporters.md @@ -83,9 +83,6 @@ example: ```nix # nixpkgs/nixos/modules/services/prometheus/exporters/postfix.nix { config, lib, pkgs, options }: - - with lib; - let # for convenience we define cfg here cfg = config.services.prometheus.exporters.postfix; @@ -97,15 +94,15 @@ example: # (and optional overrides for default options). # Note that this attribute is optional. extraOpts = { - telemetryPath = mkOption { - type = types.str; + telemetryPath = lib.mkOption { + type = lib.types.str; default = "/metrics"; description = '' Path under which to expose metrics. ''; }; - logfilePath = mkOption { - type = types.path; + logfilePath = lib.mkOption { + type = lib.types.path; default = /var/log/postfix_exporter_input.log; example = /var/log/mail.log; description = '' @@ -113,8 +110,8 @@ example: This file will be truncated by this exporter! ''; }; - showqPath = mkOption { - type = types.path; + showqPath = lib.mkOption { + type = lib.types.path; default = /var/spool/postfix/public/showq; example = /var/lib/postfix/queue/public/showq; description = '' @@ -136,7 +133,7 @@ example: ${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ --web.telemetry-path ${cfg.telemetryPath} \ - ${concatStringsSep " \\\n " cfg.extraFlags} + ${lib.concatStringsSep " \\\n " cfg.extraFlags} ''; }; }; @@ -156,8 +153,6 @@ information about the change to the exporter definition similar to ```nix { config, lib, pkgs, options }: -with lib; - let cfg = config.services.prometheus.exporters.nginx; in @@ -173,10 +168,10 @@ in }; imports = [ # 'services.prometheus.exporters.nginx.telemetryEndpoint' -> 'services.prometheus.exporters.nginx.telemetryPath' - (mkRenamedOptionModule [ "telemetryEndpoint" ] [ "telemetryPath" ]) + (lib.mkRenamedOptionModule [ "telemetryEndpoint" ] [ "telemetryPath" ]) # removed option 'services.prometheus.exporters.nginx.insecure' - (mkRemovedOptionModule [ "insecure" ] '' + (lib.mkRemovedOptionModule [ "insecure" ] '' This option was replaced by 'prometheus.exporters.nginx.sslVerify' which defaults to true. '') ({ options.warnings = options.warnings; }) diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 7b02e815cdbb..29a30e938e75 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -3,7 +3,7 @@ let inherit (lib) concatStrings foldl foldl' genAttrs literalExpression maintainers mapAttrs mapAttrsToList mkDefault mkEnableOption mkIf mkMerge mkOption - optional types mkOptionDefault flip attrNames; + optional types mkOptionDefault flip attrNames xor; cfg = config.services.prometheus.exporters; @@ -63,7 +63,6 @@ let "nginxlog" "node" "nut" - "openldap" "pgbouncer" "php-fpm" "pihole" @@ -231,14 +230,23 @@ let in mkIf conf.enable { warnings = conf.warnings or []; + assertions = conf.assertions or []; users.users."${name}-exporter" = (mkIf (conf.user == "${name}-exporter" && !enableDynamicUser) { description = "Prometheus ${name} exporter service user"; isSystemUser = true; inherit (conf) group; }); - users.groups = (mkIf (conf.group == "${name}-exporter" && !enableDynamicUser) { - "${name}-exporter" = {}; - }); + users.groups = mkMerge [ + (mkIf (conf.group == "${name}-exporter" && !enableDynamicUser) { + "${name}-exporter" = {}; + }) + (mkIf (name == "smartctl") { + "smartctl-exporter-access" = {}; + }) + ]; + services.udev.extraRules = mkIf (name == "smartctl") '' + ACTION=="add", SUBSYSTEM=="nvme", KERNEL=="nvme[0-9]*", RUN+="${pkgs.acl}/bin/setfacl -m g:smartctl-exporter-access:rw /dev/$kernel" + ''; networking.firewall.extraCommands = mkIf (conf.openFirewall && !nftables) (concatStrings [ "ip46tables -A nixos-fw ${conf.firewallFilter} " "-m comment --comment ${name}-exporter -j nixos-fw-accept" @@ -360,13 +368,6 @@ in Please specify either 'services.prometheus.exporters.nextcloud.passwordFile' or 'services.prometheus.exporters.nextcloud.tokenFile' ''; - } { - assertion = cfg.pgbouncer.enable -> ( - (cfg.pgbouncer.connectionStringFile != null || cfg.pgbouncer.connectionString != "") - ); - message = '' - PgBouncer exporter needs either connectionStringFile or connectionString configured" - ''; } { assertion = cfg.sql.enable -> ( (cfg.sql.configFile == null) != (cfg.sql.configuration == null) @@ -406,7 +407,15 @@ in Please ensure you have either `services.prometheus.exporters.deluge.delugePassword' or `services.prometheus.exporters.deluge.delugePasswordFile' set! ''; - } ] ++ (flip map (attrNames exporterOpts) (exporter: { + } { + assertion = cfg.pgbouncer.enable -> ( + xor (cfg.pgbouncer.connectionEnvFile == null) (cfg.pgbouncer.connectionString == null) + ); + message = '' + Options `services.prometheus.exporters.pgbouncer.connectionEnvFile` and + `services.prometheus.exporters.pgbouncer.connectionString` are mutually exclusive! + ''; + }] ++ (flip map (attrNames exporterOpts) (exporter: { assertion = cfg.${exporter}.firewallFilter != null -> cfg.${exporter}.openFirewall; message = '' The `firewallFilter'-option of exporter ${exporter} doesn't have any effect unless @@ -420,11 +429,6 @@ in Consider using `services.prometheus.exporters.idrac.configuration` instead. '' ) - (mkIf - (cfg.pgbouncer.enable && cfg.pgbouncer.connectionString != "") '' - config.services.prometheus.exporters.pgbouncer.connectionString is insecure. Use connectionStringFile instead. - '' - ) ] ++ config.services.prometheus.exporters.warnings; }] ++ [(mkIf config.services.prometheus.exporters.rtl_433.enable { hardware.rtl-sdr.enable = mkDefault true; diff --git a/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix b/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix index ba438ea74a3b..9028d1fd5a66 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix @@ -21,8 +21,8 @@ in }; leasesPath = mkOption { type = types.path; - default = "/var/lib/misc/dnsmasq.leases"; - example = "/var/lib/dnsmasq/dnsmasq.leases"; + default = "/var/lib/dnsmasq/dnsmasq.leases"; + example = "/var/lib/misc/dnsmasq.leases"; description = '' Path to the `dnsmasq.leases` file. ''; diff --git a/nixos/modules/services/monitoring/prometheus/exporters/openldap.nix b/nixos/modules/services/monitoring/prometheus/exporters/openldap.nix deleted file mode 100644 index bb65bd270933..000000000000 --- a/nixos/modules/services/monitoring/prometheus/exporters/openldap.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.services.prometheus.exporters.openldap; - inherit (lib) mkOption types concatStringsSep; -in { - port = 9330; - extraOpts = { - ldapCredentialFile = mkOption { - type = types.path; - example = "/run/keys/ldap_pass"; - description = '' - Environment file to contain the credentials to authenticate against - `openldap`. - - The file should look like this: - ``` - --- - ldapUser: "cn=monitoring,cn=Monitor" - ldapPass: "secret" - ``` - ''; - }; - protocol = mkOption { - default = "tcp"; - example = "udp"; - type = types.str; - description = '' - Which protocol to use to connect against `openldap`. - ''; - }; - ldapAddr = mkOption { - default = "localhost:389"; - type = types.str; - description = '' - Address of the `openldap`-instance. - ''; - }; - metricsPath = mkOption { - default = "/metrics"; - type = types.str; - description = '' - URL path where metrics should be exposed. - ''; - }; - interval = mkOption { - default = "30s"; - type = types.str; - example = "1m"; - description = '' - Scrape interval of the exporter. - ''; - }; - }; - serviceOpts.serviceConfig = { - ExecStart = '' - ${pkgs.prometheus-openldap-exporter}/bin/openldap_exporter \ - --promAddr ${cfg.listenAddress}:${toString cfg.port} \ - --metrPath ${cfg.metricsPath} \ - --ldapNet ${cfg.protocol} \ - --interval ${cfg.interval} \ - --config ${cfg.ldapCredentialFile} \ - ${concatStringsSep " \\\n " cfg.extraFlags} - ''; - }; -} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix b/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix index 9cd261099a95..5c111687c1d7 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix @@ -7,11 +7,8 @@ let mkPackageOption types optionals - optionalString getExe - getExe' escapeShellArg - escapeShellArgs concatStringsSep ; in @@ -29,8 +26,8 @@ in }; connectionString = mkOption { - type = types.str; - default = ""; + type = types.nullOr types.str; + default = null; example = "postgres://admin:@localhost:6432/pgbouncer?sslmode=require"; description = '' Connection string for accessing pgBouncer. @@ -43,26 +40,28 @@ in auth_file if auth_type other than "any" is used. WARNING: this secret is stored in the world-readable Nix store! - Use {option}`connectionStringFile` instead. + Use [](#opt-services.prometheus.exporters.pgbouncer.connectionEnvFile) if the + URL contains a secret. ''; }; - connectionStringFile = mkOption { - type = types.nullOr types.path; + connectionEnvFile = mkOption { + type = types.nullOr types.str; default = null; - example = "/run/keys/pgBouncer-connection-string"; description = '' - File that contains pgBouncer connection string in format: - postgres://admin:@localhost:6432/pgbouncer?sslmode=require + File that must contain the environment variable + `PGBOUNCER_EXPORTER_CONNECTION_STRING` which is set to the connection + string used by pgbouncer. I.e. the format is supposed to look like this: - NOTE: You MUST keep pgbouncer as database name (special internal db)!!! + ``` + PGBOUNCER_EXPORTER_CONNECTION_STRING="postgres://admin@localhost:6432/pgbouncer?sslmode=require" + ``` - NOTE: ignore_startup_parameters MUST contain "extra_float_digits". + NOTE: You MUST keep pgbouncer as database name (special internal db)! + NOTE: `services.pgbouncer.settings.pgbouncer.ignore_startup_parameters` + MUST contain "extra_float_digits". - NOTE: Admin user (with password or passwordless) MUST exist in the - auth_file if auth_type other than "any" is used. - - {option}`connectionStringFile` takes precedence over {option}`connectionString` + Mutually exclusive with [](#opt-services.prometheus.exporters.pgbouncer.connectionString). ''; }; @@ -126,16 +125,11 @@ in serviceOpts = { after = [ "pgbouncer.service" ]; - script = optionalString (cfg.connectionStringFile != null) '' - connectionString=$(${escapeShellArgs [ - (getExe' pkgs.coreutils "cat") "--" cfg.connectionStringFile - ]}) - '' + concatStringsSep " " ([ + script = concatStringsSep " " ([ "exec -- ${escapeShellArg (getExe cfg.package)}" "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" - "--pgBouncer.connectionString ${if cfg.connectionStringFile != null - then "\"$connectionString\"" - else "${escapeShellArg cfg.connectionString}"}" + ] ++ optionals (cfg.connectionString != null) [ + "--pgBouncer.connectionString ${escapeShellArg cfg.connectionString}" ] ++ optionals (cfg.telemetryPath != null) [ "--web.telemetry-path ${escapeShellArg cfg.telemetryPath}" ] ++ optionals (cfg.pidFile != null) [ @@ -151,5 +145,21 @@ in ] ++ cfg.extraFlags); serviceConfig.RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + serviceConfig.EnvironmentFile = lib.mkIf (cfg.connectionEnvFile != null) [ + cfg.connectionEnvFile + ]; }; + + imports = [ + (lib.mkRemovedOptionModule [ "connectionStringFile" ] '' + As replacement, the option `services.prometheus.exporters.pgbouncer.connectionEnvFile` + has been added. In contrast to `connectionStringFile` it must be an environment file + with the connection string being set to `PGBOUNCER_EXPORTER_CONNECTION_STRING`. + + The change was necessary since the former option wrote the contents of the file + into the cmdline of the exporter making the connection string effectively + world-readable. + '') + ({ options.warnings = options.warnings; options.assertions = options.assertions; }) + ]; } diff --git a/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix b/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix index e3dcc6126ff1..90adfe911a73 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix @@ -58,7 +58,7 @@ in PrivateDevices = lib.mkForce false; ProtectProc = "invisible"; ProcSubset = "pid"; - SupplementaryGroups = [ "disk" ]; + SupplementaryGroups = [ "disk" "smartctl-exporter-access" ]; SystemCallFilter = [ "@system-service" "~@privileged" ]; }; }; diff --git a/nixos/modules/services/monitoring/rustdesk-server.nix b/nixos/modules/services/monitoring/rustdesk-server.nix index ea4dd43cbb35..e757d8fdf054 100644 --- a/nixos/modules/services/monitoring/rustdesk-server.nix +++ b/nixos/modules/services/monitoring/rustdesk-server.nix @@ -86,7 +86,7 @@ in { systemd.slices.system-rustdesk = { enable = true; - description = "Slice designed to contain RustDesk Signal & RustDesk Relay"; + description = "RustDesk Remote Desktop Slice"; }; systemd.targets.rustdesk = { diff --git a/nixos/modules/services/monitoring/scrutiny.nix b/nixos/modules/services/monitoring/scrutiny.nix index c0ead07066ec..37a991674dae 100644 --- a/nixos/modules/services/monitoring/scrutiny.nix +++ b/nixos/modules/services/monitoring/scrutiny.nix @@ -177,6 +177,18 @@ in SCRUTINY_WEB_DATABASE_LOCATION = "/var/lib/scrutiny/scrutiny.db"; SCRUTINY_WEB_SRC_FRONTEND_PATH = "${cfg.package}/share/scrutiny"; }; + postStart = '' + for i in $(seq 300); do + if "${lib.getExe pkgs.curl}" --fail --silent --head "http://${cfg.settings.web.listen.host}:${toString cfg.settings.web.listen.port}" >/dev/null; then + echo "Scrutiny is ready (port is open)" + exit 0 + fi + echo "Waiting for Scrutiny to open port..." + sleep 0.2 + done + echo "Timeout waiting for Scrutiny to open port" >&2 + exit 1 + ''; serviceConfig = { DynamicUser = true; ExecStart = "${getExe cfg.package} start --config ${settingsFormat.generate "scrutiny.yaml" cfg.settings}"; diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index 6fd3b5707ab6..65b6259c12bd 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -269,7 +269,10 @@ in systemd.services.smartd = { description = "S.M.A.R.T. Daemon"; wantedBy = [ "multi-user.target" ]; - serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}"; + serviceConfig = { + Type = "notify"; + ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}"; + }; }; services.systembus-notify.enable = mkDefault ns.enable; diff --git a/nixos/modules/services/monitoring/telegraf.nix b/nixos/modules/services/monitoring/telegraf.nix index 8c51a2838e05..dfff80e1bac2 100644 --- a/nixos/modules/services/monitoring/telegraf.nix +++ b/nixos/modules/services/monitoring/telegraf.nix @@ -61,7 +61,8 @@ in { wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" ]; after = [ "network-online.target" ]; - path = lib.optional (config.services.telegraf.extraConfig.inputs ? procstat) pkgs.procps; + path = lib.optional (config.services.telegraf.extraConfig.inputs ? procstat) pkgs.procps + ++ lib.optional (config.services.telegraf.extraConfig.inputs ? ping) pkgs.iputils; serviceConfig = { EnvironmentFile = config.services.telegraf.environmentFiles; ExecStartPre = lib.optional (config.services.telegraf.environmentFiles != []) diff --git a/nixos/modules/services/monitoring/todesk.nix b/nixos/modules/services/monitoring/todesk.nix new file mode 100644 index 000000000000..807d924abfcf --- /dev/null +++ b/nixos/modules/services/monitoring/todesk.nix @@ -0,0 +1,45 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.todesk; +in +{ + options = { + services.todesk.enable = lib.mkEnableOption "ToDesk daemon"; + services.todesk.package = lib.mkPackageOption pkgs "todesk" { }; + }; + + config = lib.mkIf cfg.enable { + + environment.systemPackages = [ cfg.package ]; + + systemd.services.todeskd = { + description = "ToDesk Daemon Service"; + + wantedBy = [ "multi-user.target" ]; + wants = [ + "network-online.target" + "display-manager.service" + "nss-lookup.target" + ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${cfg.package}/bin/todesk service"; + ExecReload = "${pkgs.coreutils}/bin/kill -SIGINT $MAINPID"; + Restart = "on-failure"; + WorkingDirectory = "/var/lib/todesk"; + PrivateTmp = true; + StateDirectory = "todesk"; + StateDirectoryMode = "0777"; # Desktop application read and write /opt/todesk/config/config.ini. Such a pain! + ProtectSystem = "strict"; + ProtectHome = "read-only"; + RemoveIPC = "yes"; + }; + }; + }; +} diff --git a/nixos/modules/services/monitoring/unpoller.nix b/nixos/modules/services/monitoring/unpoller.nix index 1b4acb5d938f..1cdd8a78ea8f 100644 --- a/nixos/modules/services/monitoring/unpoller.nix +++ b/nixos/modules/services/monitoring/unpoller.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.unpoller; - configFile = pkgs.writeText "unpoller.json" (generators.toJSON {} { + configFile = pkgs.writeText "unpoller.json" (lib.generators.toJSON {} { inherit (cfg) poller influxdb loki prometheus unifi; }); @@ -15,26 +12,26 @@ in { ]; options.services.unpoller = { - enable = mkEnableOption "unpoller"; + enable = lib.mkEnableOption "unpoller"; poller = { - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Turns on line numbers, microsecond logging, and a per-device log. This may be noisy if you have a lot of devices. It adds one line per device. ''; }; - quiet = mkOption { - type = types.bool; + quiet = lib.mkOption { + type = lib.types.bool; default = false; description = '' Turns off per-interval logs. Only startup and error logs will be emitted. ''; }; - plugins = mkOption { - type = with types; listOf str; + plugins = lib.mkOption { + type = with lib.types; listOf str; default = []; description = '' Load additional plugins. @@ -43,22 +40,22 @@ in { }; prometheus = { - disable = mkOption { - type = types.bool; + disable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to disable the prometheus output plugin. ''; }; - http_listen = mkOption { - type = types.str; + http_listen = lib.mkOption { + type = lib.types.str; default = "[::]:9130"; description = '' Bind the prometheus exporter to this IP or hostname. ''; }; - report_errors = mkOption { - type = types.bool; + report_errors = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to report errors. @@ -67,53 +64,53 @@ in { }; influxdb = { - disable = mkOption { - type = types.bool; + disable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to disable the influxdb output plugin. ''; }; - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; default = "http://127.0.0.1:8086"; description = '' URL of the influxdb host. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "unifipoller"; description = '' Username for the influxdb. ''; }; - pass = mkOption { - type = types.path; + pass = lib.mkOption { + type = lib.types.path; default = pkgs.writeText "unpoller-influxdb-default.password" "unifipoller"; - defaultText = literalExpression "unpoller-influxdb-default.password"; + defaultText = lib.literalExpression "unpoller-influxdb-default.password"; description = '' Path of a file containing the password for influxdb. This file needs to be readable by the unifi-poller user. ''; apply = v: "file://${v}"; }; - db = mkOption { - type = types.str; + db = lib.mkOption { + type = lib.types.str; default = "unifi"; description = '' Database name. Database should exist. ''; }; - verify_ssl = mkOption { - type = types.bool; + verify_ssl = lib.mkOption { + type = lib.types.bool; default = true; description = '' Verify the influxdb's certificate. ''; }; - interval = mkOption { - type = types.str; + interval = lib.mkOption { + type = lib.types.str; default = "30s"; description = '' Setting this lower than the Unifi controller's refresh @@ -123,22 +120,22 @@ in { }; loki = { - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; default = ""; description = '' URL of the Loki host. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = ""; description = '' Username for Loki. ''; }; - pass = mkOption { - type = types.path; + pass = lib.mkOption { + type = lib.types.path; default = pkgs.writeText "unpoller-loki-default.password" ""; defaultText = "unpoller-influxdb-default.password"; description = '' @@ -147,29 +144,29 @@ in { ''; apply = v: "file://${v}"; }; - verify_ssl = mkOption { - type = types.bool; + verify_ssl = lib.mkOption { + type = lib.types.bool; default = false; description = '' Verify Loki's certificate. ''; }; - tenant_id = mkOption { - type = types.str; + tenant_id = lib.mkOption { + type = lib.types.str; default = ""; description = '' Tenant ID to use in Loki. ''; }; - interval = mkOption { - type = types.str; + interval = lib.mkOption { + type = lib.types.str; default = "2m"; description = '' How often the events are polled and pushed to Loki. ''; }; - timeout = mkOption { - type = types.str; + timeout = lib.mkOption { + type = lib.types.str; default = "10s"; description = '' Should be increased in case of timeout errors. @@ -179,92 +176,92 @@ in { unifi = let controllerOptions = { - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "unifi"; description = '' Unifi service user name. ''; }; - pass = mkOption { - type = types.path; + pass = lib.mkOption { + type = lib.types.path; default = pkgs.writeText "unpoller-unifi-default.password" "unifi"; - defaultText = literalExpression "unpoller-unifi-default.password"; + defaultText = lib.literalExpression "unpoller-unifi-default.password"; description = '' Path of a file containing the password for the unifi service user. This file needs to be readable by the unifi-poller user. ''; apply = v: "file://${v}"; }; - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; default = "https://unifi:8443"; description = '' URL of the Unifi controller. ''; }; - sites = mkOption { - type = with types; either (enum [ "default" "all" ]) (listOf str); + sites = lib.mkOption { + type = with lib.types; either (enum [ "default" "all" ]) (listOf str); default = "all"; description = '' List of site names for which statistics should be exported. Or the string "default" for the default site or the string "all" for all sites. ''; - apply = toList; + apply = lib.toList; }; - save_ids = mkOption { - type = types.bool; + save_ids = lib.mkOption { + type = lib.types.bool; default = false; description = '' Collect and save data from the intrusion detection system to influxdb and Loki. ''; }; - save_events = mkOption { - type = types.bool; + save_events = lib.mkOption { + type = lib.types.bool; default = false; description = '' Collect and save data from UniFi events to influxdb and Loki. ''; }; - save_alarms = mkOption { - type = types.bool; + save_alarms = lib.mkOption { + type = lib.types.bool; default = false; description = '' Collect and save data from UniFi alarms to influxdb and Loki. ''; }; - save_anomalies = mkOption { - type = types.bool; + save_anomalies = lib.mkOption { + type = lib.types.bool; default = false; description = '' Collect and save data from UniFi anomalies to influxdb and Loki. ''; }; - save_dpi = mkOption { - type = types.bool; + save_dpi = lib.mkOption { + type = lib.types.bool; default = false; description = '' Collect and save data from deep packet inspection. Adds around 150 data points and impacts performance. ''; }; - save_sites = mkOption { - type = types.bool; + save_sites = lib.mkOption { + type = lib.types.bool; default = true; description = '' Collect and save site data. ''; }; - hash_pii = mkOption { - type = types.bool; + hash_pii = lib.mkOption { + type = lib.types.bool; default = false; description = '' Hash, with md5, client names and MAC addresses. This attempts to protect personally identifiable information. ''; }; - verify_ssl = mkOption { - type = types.bool; + verify_ssl = lib.mkOption { + type = lib.types.bool; default = true; description = '' Verify the Unifi controller's certificate. @@ -273,8 +270,8 @@ in { }; in { - dynamic = mkOption { - type = types.bool; + dynamic = lib.mkOption { + type = lib.types.bool; default = false; description = '' Let prometheus select which controller to poll when scraping. @@ -284,18 +281,18 @@ in { defaults = controllerOptions; - controllers = mkOption { - type = with types; listOf (submodule { options = controllerOptions; }); + controllers = lib.mkOption { + type = with lib.types; listOf (submodule { options = controllerOptions; }); default = []; description = '' List of Unifi controllers to poll. Use defaults if empty. ''; - apply = map (flip removeAttrs [ "_module" ]); + apply = map (lib.flip removeAttrs [ "_module" ]); }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.groups.unifi-poller = { }; users.users.unifi-poller = { description = "unifi-poller Service User"; diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix index b86e93a661ca..272f6f38f545 100644 --- a/nixos/modules/services/monitoring/ups.nix +++ b/nixos/modules/services/monitoring/ups.nix @@ -1,13 +1,15 @@ { config, lib, pkgs, ... }: - # TODO: This is not secure, have a look at the file docs/security.txt inside # the project sources. -with lib; - let cfg = config.power.ups; defaultPort = 3493; + envVars = { + NUT_CONFPATH = "/etc/nut"; + NUT_STATEPATH = "/var/lib/nut"; + }; + nutFormat = { type = with lib.types; let @@ -31,24 +33,24 @@ let normalizedValue = lib.mapAttrs (key: val: if lib.isList val - then forEach val (elem: if lib.isList elem then elem else [elem]) + then lib.forEach val (elem: if lib.isList elem then elem else [elem]) else if val == null then [] else [[val]] ) value; - mkValueString = concatMapStringsSep " " (v: - let str = generators.mkValueStringDefault {} v; + mkValueString = lib.concatMapStringsSep " " (v: + let str = lib.generators.mkValueStringDefault {} v; in # Quote the value if it has spaces and isn't already quoted. - if (hasInfix " " str) && !(hasPrefix "\"" str && hasSuffix "\"" str) + if (lib.hasInfix " " str) && !(lib.hasPrefix "\"" str && lib.hasSuffix "\"" str) then "\"${str}\"" else str ); in pkgs.writeText name (lib.generators.toKeyValue { - mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " "; + mkKeyValue = lib.generators.mkKeyValueDefault { inherit mkValueString; } " "; listsAsDuplicateKeys = true; } normalizedValue); @@ -57,7 +59,7 @@ let installSecrets = source: target: secrets: pkgs.writeShellScript "installSecrets.sh" '' install -m0600 -D ${source} "${target}" - ${concatLines (forEach secrets (name: '' + ${lib.concatLines (lib.forEach secrets (name: '' ${pkgs.replace-secret}/bin/replace-secret \ '@${name}@' \ "$CREDENTIALS_DIRECTORY/${name}" \ @@ -71,16 +73,16 @@ let upsdUsers = pkgs.writeText "upsd.users" (let # This looks like INI, but it's not quite because the # 'upsmon' option lacks a '='. See: man upsd.users - userConfig = name: user: concatStringsSep "\n " (concatLists [ + userConfig = name: user: lib.concatStringsSep "\n " (lib.concatLists [ [ "[${name}]" "password = \"@upsdusers_password_${name}@\"" ] - (optional (user.upsmon != null) "upsmon ${user.upsmon}") - (forEach user.actions (action: "actions = ${action}")) - (forEach user.instcmds (instcmd: "instcmds = ${instcmd}")) + (lib.optional (user.upsmon != null) "upsmon ${user.upsmon}") + (lib.forEach user.actions (action: "actions = ${action}")) + (lib.forEach user.instcmds (instcmd: "instcmds = ${instcmd}")) ]); - in concatStringsSep "\n\n" (mapAttrsToList userConfig cfg.users)); + in lib.concatStringsSep "\n\n" (lib.mapAttrsToList userConfig cfg.users)); upsOptions = {name, config, ...}: @@ -88,25 +90,25 @@ let options = { # This can be inferred from the UPS model by looking at # /nix/store/nut/share/driver.list - driver = mkOption { - type = types.str; + driver = lib.mkOption { + type = lib.types.str; description = '' Specify the program to run to talk to this UPS. apcsmart, bestups, and sec are some examples. ''; }; - port = mkOption { - type = types.str; + port = lib.mkOption { + type = lib.types.str; description = '' The serial port to which your UPS is connected. /dev/ttyS0 is usually the first port on Linux boxes, for example. ''; }; - shutdownOrder = mkOption { + shutdownOrder = lib.mkOption { default = 0; - type = types.int; + type = lib.types.int; description = '' When you have multiple UPSes on your system, you usually need to turn them off in a certain order. upsdrvctl shuts down all the @@ -115,9 +117,9 @@ let ''; }; - maxStartDelay = mkOption { + maxStartDelay = lib.mkOption { default = null; - type = types.uniq (types.nullOr types.int); + type = lib.types.uniq (lib.types.nullOr lib.types.int); description = '' This can be set as a global variable above your first UPS definition and it can also be set in a UPS section. This value @@ -127,25 +129,25 @@ let ''; }; - description = mkOption { + description = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Description of the UPS. ''; }; - directives = mkOption { + directives = lib.mkOption { default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' List of configuration directives for this UPS. ''; }; - summary = mkOption { + summary = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Lines which would be added inside ups.conf for handling this UPS. ''; @@ -154,33 +156,33 @@ let }; config = { - directives = mkOrder 10 ([ + directives = lib.mkOrder 10 ([ "driver = ${config.driver}" "port = ${config.port}" ''desc = "${config.description}"'' "sdorder = ${toString config.shutdownOrder}" - ] ++ (optional (config.maxStartDelay != null) + ] ++ (lib.optional (config.maxStartDelay != null) "maxstartdelay = ${toString config.maxStartDelay}") ); summary = - concatStringsSep "\n " + lib.concatStringsSep "\n " (["[${name}]"] ++ config.directives); }; }; listenOptions = { options = { - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; description = '' Address of the interface for `upsd` to listen on. See `man upsd.conf` for details. ''; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = defaultPort; description = '' TCP port for `upsd` to listen on. @@ -192,14 +194,14 @@ let upsdOptions = { options = { - enable = mkOption { - type = types.bool; - defaultText = literalMD "`true` if `mode` is one of `standalone`, `netserver`"; + enable = lib.mkOption { + type = lib.types.bool; + defaultText = lib.literalMD "`true` if `mode` is one of `standalone`, `netserver`"; description = "Whether to enable `upsd`."; }; - listen = mkOption { - type = with types; listOf (submodule listenOptions); + listen = lib.mkOption { + type = with lib.types; listOf (submodule listenOptions); default = []; example = [ { @@ -216,8 +218,8 @@ let ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Additional lines to add to `upsd.conf`. @@ -226,15 +228,15 @@ let }; config = { - enable = mkDefault (elem cfg.mode [ "standalone" "netserver" ]); + enable = lib.mkDefault (lib.elem cfg.mode [ "standalone" "netserver" ]); }; }; monitorOptions = { name, config, ... }: { options = { - system = mkOption { - type = types.str; + system = lib.mkOption { + type = lib.types.str; default = name; description = '' Identifier of the UPS to monitor, in this form: `[@[:]]` @@ -242,8 +244,8 @@ let ''; }; - powerValue = mkOption { - type = types.int; + powerValue = lib.mkOption { + type = lib.types.int; default = 1; description = '' Number of power supplies that the UPS feeds on this system. @@ -251,17 +253,17 @@ let ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; description = '' Username from `upsd.users` for accessing this UPS. See `upsmon.conf` for details. ''; }; - passwordFile = mkOption { - type = types.str; - defaultText = literalMD "power.ups.users.\${user}.passwordFile"; + passwordFile = lib.mkOption { + type = lib.types.str; + defaultText = lib.literalMD "power.ups.users.\${user}.passwordFile"; description = '' The full path to a file containing the password from `upsd.users` for accessing this UPS. The password file @@ -270,8 +272,8 @@ let ''; }; - type = mkOption { - type = types.str; + type = lib.mkOption { + type = lib.types.str; default = "master"; description = '' The relationship with `upsd`. @@ -281,39 +283,41 @@ let }; config = { - passwordFile = mkDefault cfg.users.${config.user}.passwordFile; + passwordFile = lib.mkDefault cfg.users.${config.user}.passwordFile; }; }; upsmonOptions = { options = { - enable = mkOption { - type = types.bool; - defaultText = literalMD "`true` if `mode` is one of `standalone`, `netserver`, `netclient`"; + enable = lib.mkOption { + type = lib.types.bool; + defaultText = lib.literalMD "`true` if `mode` is one of `standalone`, `netserver`, `netclient`"; description = "Whether to enable `upsmon`."; }; - monitor = mkOption { - type = with types; attrsOf (submodule monitorOptions); + monitor = lib.mkOption { + type = with lib.types; attrsOf (submodule monitorOptions); default = {}; description = '' Set of UPS to monitor. See `man upsmon.conf` for details. ''; }; - settings = mkOption { + settings = lib.mkOption { type = nutFormat.type; default = {}; - defaultText = literalMD '' + defaultText = lib.literalMD '' { MINSUPPLIES = 1; - RUN_AS_USER = "root"; + MONITOR = NOTIFYCMD = "''${pkgs.nut}/bin/upssched"; + POWERDOWNFLAG = "/run/killpower"; + RUN_AS_USER = "root"; SHUTDOWNCMD = "''${pkgs.systemd}/bin/shutdown now"; } ''; description = "Additional settings to add to `upsmon.conf`."; - example = literalMD '' + example = lib.literalMD '' { MINSUPPLIES = 2; NOTIFYFLAG = [ @@ -326,29 +330,30 @@ let }; config = { - enable = mkDefault (elem cfg.mode [ "standalone" "netserver" "netclient" ]); + enable = lib.mkDefault (lib.elem cfg.mode [ "standalone" "netserver" "netclient" ]); settings = { + MINSUPPLIES = lib.mkDefault 1; + MONITOR = lib.flip lib.mapAttrsToList cfg.upsmon.monitor (name: monitor: with monitor; [ system powerValue user "\"@upsmon_password_${name}@\"" type ]); + NOTIFYCMD = lib.mkDefault "${pkgs.nut}/bin/upssched"; + POWERDOWNFLAG = lib.mkDefault "/run/killpower"; RUN_AS_USER = "root"; # TODO: replace 'root' by another username. - MINSUPPLIES = mkDefault 1; - NOTIFYCMD = mkDefault "${pkgs.nut}/bin/upssched"; - SHUTDOWNCMD = mkDefault "${pkgs.systemd}/bin/shutdown now"; - MONITOR = flip mapAttrsToList cfg.upsmon.monitor (name: monitor: with monitor; [ system powerValue user "\"@upsmon_password_${name}@\"" type ]); + SHUTDOWNCMD = lib.mkDefault "${pkgs.systemd}/bin/shutdown now"; }; }; }; userOptions = { options = { - passwordFile = mkOption { - type = types.str; + passwordFile = lib.mkOption { + type = lib.types.str; description = '' The full path to a file that contains the user's (clear text) password. The password file is read on service start. ''; }; - actions = mkOption { - type = with types; listOf str; + actions = lib.mkOption { + type = with lib.types; listOf str; default = []; description = '' Allow the user to do certain things with upsd. @@ -356,8 +361,8 @@ let ''; }; - instcmds = mkOption { - type = with types; listOf str; + instcmds = lib.mkOption { + type = with lib.types; listOf str; default = []; description = '' Let the user initiate specific instant commands. Use "ALL" to grant all commands automatically. For the full list of what your UPS supports, use "upscmd -l". @@ -365,8 +370,8 @@ let ''; }; - upsmon = mkOption { - type = with types; nullOr (enum [ "primary" "secondary" ]); + upsmon = lib.mkOption { + type = with lib.types; nullOr (enum [ "primary" "secondary" ]); default = null; description = '' Add the necessary actions for a upsmon process to work. @@ -384,14 +389,14 @@ in # powerManagement.powerDownCommands power.ups = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' support for Power Devices, such as Uninterruptible Power Supplies, Power Distribution Units and Solar Controllers ''; - mode = mkOption { + mode = lib.mkOption { default = "standalone"; - type = types.enum [ "none" "standalone" "netserver" "netclient" ]; + type = lib.types.enum [ "none" "standalone" "netserver" "netclient" ]; description = '' The MODE determines which part of the NUT is to be started, and which configuration files must be modified. @@ -416,25 +421,25 @@ in ''; }; - schedulerRules = mkOption { + schedulerRules = lib.mkOption { example = "/etc/nixos/upssched.conf"; - type = types.str; + type = lib.types.str; description = '' File which contains the rules to handle UPS events. ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = false; description = '' Open ports in the firewall for `upsd`. ''; }; - maxStartDelay = mkOption { + maxStartDelay = lib.mkOption { default = 45; - type = types.int; + type = lib.types.int; description = '' This can be set as a global variable above your first UPS definition and it can also be set in a UPS section. This value @@ -444,23 +449,23 @@ in ''; }; - upsmon = mkOption { + upsmon = lib.mkOption { default = {}; description = '' Options for the `upsmon.conf` configuration file. ''; - type = types.submodule upsmonOptions; + type = lib.types.submodule upsmonOptions; }; - upsd = mkOption { + upsd = lib.mkOption { default = {}; description = '' Options for the `upsd.conf` configuration file. ''; - type = types.submodule upsdOptions; + type = lib.types.submodule upsdOptions; }; - ups = mkOption { + ups = lib.mkOption { default = {}; # see nut/etc/ups.conf.sample description = '' @@ -468,27 +473,27 @@ in monitoring directly. These are usually attached to serial ports, but USB devices are also supported. ''; - type = with types; attrsOf (submodule upsOptions); + type = with lib.types; attrsOf (submodule upsOptions); }; - users = mkOption { + users = lib.mkOption { default = {}; description = '' Users that can access upsd. See `man upsd.users`. ''; - type = with types; attrsOf (submodule userOptions); + type = with lib.types; attrsOf (submodule userOptions); }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ (let - totalPowerValue = foldl' add 0 (map (monitor: monitor.powerValue) (attrValues cfg.upsmon.monitor)); + totalPowerValue = lib.foldl' lib.add 0 (map (monitor: monitor.powerValue) (lib.attrValues cfg.upsmon.monitor)); minSupplies = cfg.upsmon.settings.MINSUPPLIES; - in mkIf cfg.upsmon.enable { + in lib.mkIf cfg.upsmon.enable { assertion = totalPowerValue >= minSupplies; message = '' `power.ups.upsmon`: Total configured power value (${toString totalPowerValue}) must be at least MINSUPPLIES (${toString minSupplies}). @@ -496,17 +501,24 @@ in }) ]; + # For interactive use. environment.systemPackages = [ pkgs.nut ]; + environment.variables = envVars; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = if cfg.upsd.listen == [] then [ defaultPort ] - else unique (forEach cfg.upsd.listen (listen: listen.port)); + else lib.unique (lib.forEach cfg.upsd.listen (listen: listen.port)); + }; + + systemd.slices.system-ups = { + description = "Network UPS Tools (NUT) Slice"; + documentation = [ "https://networkupstools.org/" ]; }; systemd.services.upsmon = let - secrets = mapAttrsToList (name: monitor: "upsmon_password_${name}") cfg.upsmon.monitor; + secrets = lib.mapAttrsToList (name: monitor: "upsmon_password_${name}") cfg.upsmon.monitor; createUpsmonConf = installSecrets upsmonConf "/run/nut/upsmon.conf" secrets; in { enable = cfg.upsmon.enable; @@ -518,14 +530,14 @@ in ExecStartPre = "${createUpsmonConf}"; ExecStart = "${pkgs.nut}/sbin/upsmon"; ExecReload = "${pkgs.nut}/sbin/upsmon -c reload"; - LoadCredential = mapAttrsToList (name: monitor: "upsmon_password_${name}:${monitor.passwordFile}") cfg.upsmon.monitor; + LoadCredential = lib.mapAttrsToList (name: monitor: "upsmon_password_${name}:${monitor.passwordFile}") cfg.upsmon.monitor; + Slice = "system-ups.slice"; }; - environment.NUT_CONFPATH = "/etc/nut"; - environment.NUT_STATEPATH = "/var/lib/nut"; + environment = envVars; }; systemd.services.upsd = let - secrets = mapAttrsToList (name: user: "upsdusers_password_${name}") cfg.users; + secrets = lib.mapAttrsToList (name: user: "upsdusers_password_${name}") cfg.users; createUpsdUsers = installSecrets upsdUsers "/run/nut/upsd.users" secrets; in { enable = cfg.upsd.enable; @@ -538,10 +550,10 @@ in # TODO: replace 'root' by another username. ExecStart = "${pkgs.nut}/sbin/upsd -u root"; ExecReload = "${pkgs.nut}/sbin/upsd -c reload"; - LoadCredential = mapAttrsToList (name: user: "upsdusers_password_${name}:${user.passwordFile}") cfg.users; + LoadCredential = lib.mapAttrsToList (name: user: "upsdusers_password_${name}:${user.passwordFile}") cfg.users; + Slice = "system-ups.slice"; }; - environment.NUT_CONFPATH = "/etc/nut"; - environment.NUT_STATEPATH = "/var/lib/nut"; + environment = envVars; restartTriggers = [ config.environment.etc."nut/upsd.conf".source ]; @@ -557,14 +569,32 @@ in RemainAfterExit = true; # TODO: replace 'root' by another username. ExecStart = "${pkgs.nut}/bin/upsdrvctl -u root start"; + Slice = "system-ups.slice"; }; - environment.NUT_CONFPATH = "/etc/nut"; - environment.NUT_STATEPATH = "/var/lib/nut"; + environment = envVars; restartTriggers = [ config.environment.etc."nut/ups.conf".source ]; }; + systemd.services.ups-killpower = lib.mkIf (cfg.upsmon.settings.POWERDOWNFLAG != null) { + enable = cfg.upsd.enable; + description = "UPS Kill Power"; + wantedBy = [ "shutdown.target" ]; + after = [ "shutdown.target" ]; + before = [ "final.target" ]; + unitConfig = { + ConditionPathExists = cfg.upsmon.settings.POWERDOWNFLAG; + DefaultDependencies = "no"; + }; + environment = envVars; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.nut}/bin/upsdrvctl shutdown"; + Slice = "system-ups.slice"; + }; + }; + environment.etc = { "nut/nut.conf".source = pkgs.writeText "nut.conf" '' @@ -574,11 +604,11 @@ in '' maxstartdelay = ${toString cfg.maxStartDelay} - ${concatStringsSep "\n\n" (forEach (attrValues cfg.ups) (ups: ups.summary))} + ${lib.concatStringsSep "\n\n" (lib.forEach (lib.attrValues cfg.ups) (ups: ups.summary))} ''; "nut/upsd.conf".source = pkgs.writeText "upsd.conf" '' - ${concatStringsSep "\n" (forEach cfg.upsd.listen (listen: "LISTEN ${listen.address} ${toString listen.port}"))} + ${lib.concatStringsSep "\n" (lib.forEach cfg.upsd.listen (listen: "LISTEN ${listen.address} ${toString listen.port}"))} ${cfg.upsd.extraConfig} ''; "nut/upssched.conf".source = cfg.schedulerRules; @@ -586,7 +616,7 @@ in "nut/upsmon.conf".source = "/run/nut/upsmon.conf"; }; - power.ups.schedulerRules = mkDefault "${pkgs.nut}/etc/upssched.conf.sample"; + power.ups.schedulerRules = lib.mkDefault "${pkgs.nut}/etc/upssched.conf.sample"; systemd.tmpfiles.rules = [ "d /var/state/ups -" diff --git a/nixos/modules/services/network-filesystems/ceph.nix b/nixos/modules/services/network-filesystems/ceph.nix index d375434a1bd4..5961731dbf44 100644 --- a/nixos/modules/services/network-filesystems/ceph.nix +++ b/nixos/modules/services/network-filesystems/ceph.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.ceph; # function that translates "camelCaseOptions" to "camel case options", credits to tilpner in #nixos@freenode - expandCamelCase = replaceStrings upperChars (map (s: " ${s}") lowerChars); - expandCamelCaseAttrs = mapAttrs' (name: value: nameValuePair (expandCamelCase name) value); + expandCamelCase = lib.replaceStrings lib.upperChars (map (s: " ${s}") lib.lowerChars); + expandCamelCaseAttrs = lib.mapAttrs' (name: value: lib.nameValuePair (expandCamelCase name) value); makeServices = daemonType: daemonIds: - mkMerge (map (daemonId: + lib.mkMerge (map (daemonId: { "ceph-${daemonType}-${daemonId}" = makeService daemonType daemonId cfg.global.clusterName cfg.${daemonType}.package; }) daemonIds); @@ -18,8 +15,8 @@ let let stateDirectory = "ceph/${if daemonType == "rgw" then "radosgw" else daemonType}/${clusterName}-${daemonId}"; in { enable = true; - description = "Ceph ${builtins.replaceStrings lowerChars upperChars daemonType} daemon ${daemonId}"; - after = [ "network-online.target" "time-sync.target" ] ++ optional (daemonType == "osd") "ceph-mon.target"; + description = "Ceph ${builtins.replaceStrings lib.lowerChars lib.upperChars daemonType} daemon ${daemonId}"; + after = [ "network-online.target" "time-sync.target" ] ++ lib.optional (daemonType == "osd") "ceph-mon.target"; wants = [ "network-online.target" "time-sync.target" ]; partOf = [ "ceph-${daemonType}.target" ]; wantedBy = [ "ceph-${daemonType}.target" ]; @@ -47,11 +44,11 @@ let Group = if daemonType == "osd" then "disk" else "ceph"; ExecStart = ''${ceph.out}/bin/${if daemonType == "rgw" then "radosgw" else "ceph-${daemonType}"} \ -f --cluster ${clusterName} --id ${daemonId}''; - } // optionalAttrs (daemonType == "osd") { + } // lib.optionalAttrs (daemonType == "osd") { ExecStartPre = "${ceph.lib}/libexec/ceph/ceph-osd-prestart.sh --id ${daemonId} --cluster ${clusterName}"; RestartSec = "20s"; PrivateDevices = "no"; # osd needs disk access - } // optionalAttrs ( daemonType == "mon") { + } // lib.optionalAttrs ( daemonType == "mon") { RestartSec = "10"; }; }; @@ -71,11 +68,11 @@ in options.services.ceph = { # Ceph has a monolithic configuration file but different sections for # each daemon, a separate client section and a global section - enable = mkEnableOption "Ceph global configuration"; + enable = lib.mkEnableOption "Ceph global configuration"; global = { - fsid = mkOption { - type = types.str; + fsid = lib.mkOption { + type = lib.types.str; example = '' 433a2193-4f8a-47a0-95d2-209d7ca2cca5 ''; @@ -85,25 +82,25 @@ in ''; }; - clusterName = mkOption { - type = types.str; + clusterName = lib.mkOption { + type = lib.types.str; default = "ceph"; description = '' Name of cluster ''; }; - mgrModulePath = mkOption { - type = types.path; + mgrModulePath = lib.mkOption { + type = lib.types.path; default = "${pkgs.ceph.lib}/lib/ceph/mgr"; - defaultText = literalExpression ''"''${pkgs.ceph.lib}/lib/ceph/mgr"''; + defaultText = lib.literalExpression ''"''${pkgs.ceph.lib}/lib/ceph/mgr"''; description = '' Path at which to find ceph-mgr modules. ''; }; - monInitialMembers = mkOption { - type = with types; nullOr commas; + monInitialMembers = lib.mkOption { + type = with lib.types; nullOr commas; default = null; example = '' node0, node1, node2 @@ -113,8 +110,8 @@ in ''; }; - monHost = mkOption { - type = with types; nullOr commas; + monHost = lib.mkOption { + type = with lib.types; nullOr commas; default = null; example = '' 10.10.0.1, 10.10.0.2, 10.10.0.3 @@ -124,40 +121,40 @@ in ''; }; - maxOpenFiles = mkOption { - type = types.int; + maxOpenFiles = lib.mkOption { + type = lib.types.int; default = 131072; description = '' Max open files for each OSD daemon. ''; }; - authClusterRequired = mkOption { - type = types.enum [ "cephx" "none" ]; + authClusterRequired = lib.mkOption { + type = lib.types.enum [ "cephx" "none" ]; default = "cephx"; description = '' Enables requiring daemons to authenticate with eachother in the cluster. ''; }; - authServiceRequired = mkOption { - type = types.enum [ "cephx" "none" ]; + authServiceRequired = lib.mkOption { + type = lib.types.enum [ "cephx" "none" ]; default = "cephx"; description = '' Enables requiring clients to authenticate with the cluster to access services in the cluster (e.g. radosgw, mds or osd). ''; }; - authClientRequired = mkOption { - type = types.enum [ "cephx" "none" ]; + authClientRequired = lib.mkOption { + type = lib.types.enum [ "cephx" "none" ]; default = "cephx"; description = '' Enables requiring the cluster to authenticate itself to the client. ''; }; - publicNetwork = mkOption { - type = with types; nullOr commas; + publicNetwork = lib.mkOption { + type = with lib.types; nullOr commas; default = null; example = '' 10.20.0.0/24, 192.168.1.0/24 @@ -167,8 +164,8 @@ in ''; }; - clusterNetwork = mkOption { - type = with types; nullOr commas; + clusterNetwork = lib.mkOption { + type = with lib.types; nullOr commas; default = null; example = '' 10.10.0.0/24, 192.168.0.0/24 @@ -178,18 +175,18 @@ in ''; }; - rgwMimeTypesFile = mkOption { - type = with types; nullOr path; + rgwMimeTypesFile = lib.mkOption { + type = with lib.types; nullOr path; default = "${pkgs.mailcap}/etc/mime.types"; - defaultText = literalExpression ''"''${pkgs.mailcap}/etc/mime.types"''; + defaultText = lib.literalExpression ''"''${pkgs.mailcap}/etc/mime.types"''; description = '' Path to mime types used by radosgw. ''; }; }; - extraConfig = mkOption { - type = with types; attrsOf str; + extraConfig = lib.mkOption { + type = with lib.types; attrsOf str; default = {}; example = { "ms bind ipv6" = "true"; @@ -200,9 +197,9 @@ in }; mgr = { - enable = mkEnableOption "Ceph MGR daemon"; - daemons = mkOption { - type = with types; listOf str; + enable = lib.mkEnableOption "Ceph MGR daemon"; + daemons = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "name1" "name2" ]; description = '' @@ -210,9 +207,9 @@ in to the id part in ceph i.e. [ "name1" ] would result in mgr.name1 ''; }; - package = mkPackageOption pkgs "ceph" { }; - extraConfig = mkOption { - type = with types; attrsOf str; + package = lib.mkPackageOption pkgs "ceph" { }; + extraConfig = lib.mkOption { + type = with lib.types; attrsOf str; default = {}; description = '' Extra configuration to add to the global section for manager daemons. @@ -221,9 +218,9 @@ in }; mon = { - enable = mkEnableOption "Ceph MON daemon"; - daemons = mkOption { - type = with types; listOf str; + enable = lib.mkEnableOption "Ceph MON daemon"; + daemons = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "name1" "name2" ]; description = '' @@ -231,9 +228,9 @@ in to the id part in ceph i.e. [ "name1" ] would result in mon.name1 ''; }; - package = mkPackageOption pkgs "ceph" { }; - extraConfig = mkOption { - type = with types; attrsOf str; + package = lib.mkPackageOption pkgs "ceph" { }; + extraConfig = lib.mkOption { + type = with lib.types; attrsOf str; default = {}; description = '' Extra configuration to add to the monitor section. @@ -242,9 +239,9 @@ in }; osd = { - enable = mkEnableOption "Ceph OSD daemon"; - daemons = mkOption { - type = with types; listOf str; + enable = lib.mkEnableOption "Ceph OSD daemon"; + daemons = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "name1" "name2" ]; description = '' @@ -252,9 +249,9 @@ in to the id part in ceph i.e. [ "name1" ] would result in osd.name1 ''; }; - package = mkPackageOption pkgs "ceph" { }; - extraConfig = mkOption { - type = with types; attrsOf str; + package = lib.mkPackageOption pkgs "ceph" { }; + extraConfig = lib.mkOption { + type = with lib.types; attrsOf str; default = { "osd journal size" = "10000"; "osd pool default size" = "3"; @@ -270,9 +267,9 @@ in }; mds = { - enable = mkEnableOption "Ceph MDS daemon"; - daemons = mkOption { - type = with types; listOf str; + enable = lib.mkEnableOption "Ceph MDS daemon"; + daemons = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "name1" "name2" ]; description = '' @@ -280,9 +277,9 @@ in to the id part in ceph i.e. [ "name1" ] would result in mds.name1 ''; }; - package = mkPackageOption pkgs "ceph" { }; - extraConfig = mkOption { - type = with types; attrsOf str; + package = lib.mkPackageOption pkgs "ceph" { }; + extraConfig = lib.mkOption { + type = with lib.types; attrsOf str; default = {}; description = '' Extra configuration to add to the MDS section. @@ -291,10 +288,10 @@ in }; rgw = { - enable = mkEnableOption "Ceph RadosGW daemon"; - package = mkPackageOption pkgs "ceph" { }; - daemons = mkOption { - type = with types; listOf str; + enable = lib.mkEnableOption "Ceph RadosGW daemon"; + package = lib.mkPackageOption pkgs "ceph" { }; + daemons = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "name1" "name2" ]; description = '' @@ -307,11 +304,11 @@ in }; client = { - enable = mkEnableOption "Ceph client configuration"; - extraConfig = mkOption { - type = with types; attrsOf (attrsOf str); + enable = lib.mkEnableOption "Ceph client configuration"; + extraConfig = lib.mkOption { + type = with lib.types; attrsOf (attrsOf str); default = {}; - example = literalExpression '' + example = lib.literalExpression '' { # This would create a section for a radosgw daemon named node0 and related # configuration for it @@ -326,7 +323,7 @@ in }; }; - config = mkIf config.services.ceph.enable { + config = lib.mkIf config.services.ceph.enable { assertions = [ { assertion = cfg.global.fsid != ""; message = "fsid has to be set to a valid uuid for the cluster to function"; @@ -345,22 +342,22 @@ in } ]; - warnings = optional (cfg.global.monInitialMembers == null) + warnings = lib.optional (cfg.global.monInitialMembers == null) "Not setting up a list of members in monInitialMembers requires that you set the host variable for each mon daemon or else the cluster won't function"; environment.etc."ceph/ceph.conf".text = let # Merge the extraConfig set for mgr daemons, as mgr don't have their own section - globalSection = expandCamelCaseAttrs (cfg.global // cfg.extraConfig // optionalAttrs cfg.mgr.enable cfg.mgr.extraConfig); + globalSection = expandCamelCaseAttrs (cfg.global // cfg.extraConfig // lib.optionalAttrs cfg.mgr.enable cfg.mgr.extraConfig); # Remove all name-value pairs with null values from the attribute set to avoid making empty sections in the ceph.conf - globalSection' = filterAttrs (name: value: value != null) globalSection; + globalSection' = lib.filterAttrs (name: value: value != null) globalSection; totalConfig = { global = globalSection'; - } // optionalAttrs (cfg.mon.enable && cfg.mon.extraConfig != {}) { mon = cfg.mon.extraConfig; } - // optionalAttrs (cfg.mds.enable && cfg.mds.extraConfig != {}) { mds = cfg.mds.extraConfig; } - // optionalAttrs (cfg.osd.enable && cfg.osd.extraConfig != {}) { osd = cfg.osd.extraConfig; } - // optionalAttrs (cfg.client.enable && cfg.client.extraConfig != {}) cfg.client.extraConfig; + } // lib.optionalAttrs (cfg.mon.enable && cfg.mon.extraConfig != {}) { mon = cfg.mon.extraConfig; } + // lib.optionalAttrs (cfg.mds.enable && cfg.mds.extraConfig != {}) { mds = cfg.mds.extraConfig; } + // lib.optionalAttrs (cfg.osd.enable && cfg.osd.extraConfig != {}) { osd = cfg.osd.extraConfig; } + // lib.optionalAttrs (cfg.client.enable && cfg.client.extraConfig != {}) cfg.client.extraConfig; in - generators.toINI {} totalConfig; + lib.generators.toINI {} totalConfig; users.users.ceph = { uid = config.ids.uids.ceph; @@ -375,13 +372,13 @@ in systemd.services = let services = [] - ++ optional cfg.mon.enable (makeServices "mon" cfg.mon.daemons) - ++ optional cfg.mds.enable (makeServices "mds" cfg.mds.daemons) - ++ optional cfg.osd.enable (makeServices "osd" cfg.osd.daemons) - ++ optional cfg.rgw.enable (makeServices "rgw" cfg.rgw.daemons) - ++ optional cfg.mgr.enable (makeServices "mgr" cfg.mgr.daemons); + ++ lib.optional cfg.mon.enable (makeServices "mon" cfg.mon.daemons) + ++ lib.optional cfg.mds.enable (makeServices "mds" cfg.mds.daemons) + ++ lib.optional cfg.osd.enable (makeServices "osd" cfg.osd.daemons) + ++ lib.optional cfg.rgw.enable (makeServices "rgw" cfg.rgw.daemons) + ++ lib.optional cfg.mgr.enable (makeServices "mgr" cfg.mgr.daemons); in - mkMerge services; + lib.mkMerge services; systemd.targets = let targets = [ @@ -390,13 +387,13 @@ in wantedBy = [ "multi-user.target" ]; unitConfig.StopWhenUnneeded = true; }; } ] - ++ optional cfg.mon.enable (makeTarget "mon") - ++ optional cfg.mds.enable (makeTarget "mds") - ++ optional cfg.osd.enable (makeTarget "osd") - ++ optional cfg.rgw.enable (makeTarget "rgw") - ++ optional cfg.mgr.enable (makeTarget "mgr"); + ++ lib.optional cfg.mon.enable (makeTarget "mon") + ++ lib.optional cfg.mds.enable (makeTarget "mds") + ++ lib.optional cfg.osd.enable (makeTarget "osd") + ++ lib.optional cfg.rgw.enable (makeTarget "rgw") + ++ lib.optional cfg.mgr.enable (makeTarget "mgr"); in - mkMerge targets; + lib.mkMerge targets; systemd.tmpfiles.settings."10-ceph" = let defaultConfig = { @@ -407,9 +404,9 @@ in "/etc/ceph".d = defaultConfig; "/run/ceph".d = defaultConfig // { mode = "0770"; }; "/var/lib/ceph".d = defaultConfig; - "/var/lib/ceph/mgr".d = mkIf (cfg.mgr.enable) defaultConfig; - "/var/lib/ceph/mon".d = mkIf (cfg.mon.enable) defaultConfig; - "/var/lib/ceph/osd".d = mkIf (cfg.osd.enable) defaultConfig; + "/var/lib/ceph/mgr".d = lib.mkIf (cfg.mgr.enable) defaultConfig; + "/var/lib/ceph/mon".d = lib.mkIf (cfg.mon.enable) defaultConfig; + "/var/lib/ceph/osd".d = lib.mkIf (cfg.osd.enable) defaultConfig; }; }; } diff --git a/nixos/modules/services/network-filesystems/eris-server.nix b/nixos/modules/services/network-filesystems/eris-server.nix index 104676a52c61..7ad190c62f0a 100644 --- a/nixos/modules/services/network-filesystems/eris-server.nix +++ b/nixos/modules/services/network-filesystems/eris-server.nix @@ -53,7 +53,7 @@ in { Add "get" and "put" as query elements to enable those operations. ''; example = [ - "bolt+file:///srv/eris.bolt?get&put" + "badger+file:///var/db/eris.badger?get&put" "coap+tcp://eris.example.com:5683?get" ]; }; diff --git a/nixos/modules/services/network-filesystems/kbfs.nix b/nixos/modules/services/network-filesystems/kbfs.nix index 903cae379986..034fc9576506 100644 --- a/nixos/modules/services/network-filesystems/kbfs.nix +++ b/nixos/modules/services/network-filesystems/kbfs.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let inherit (config.security) wrapperDir; cfg = config.services.kbfs; @@ -12,14 +11,14 @@ in { services.kbfs = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to mount the Keybase filesystem."; }; - enableRedirector = mkOption { - type = types.bool; + enableRedirector = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the Keybase root redirector service, allowing @@ -28,15 +27,15 @@ in { ''; }; - mountPoint = mkOption { - type = types.str; + mountPoint = lib.mkOption { + type = lib.types.str; default = "%h/keybase"; example = "/keybase"; description = "Mountpoint for the Keybase filesystem."; }; - extraFlags = mkOption { - type = types.listOf types.str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "-label kbfs" @@ -52,7 +51,7 @@ in { ###### implementation - config = mkIf cfg.enable (mkMerge [ + config = lib.mkIf cfg.enable (lib.mkMerge [ { # Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/kbfs.service systemd.user.services.kbfs = { @@ -61,7 +60,7 @@ in { # Note that the "Requires" directive will cause a unit to be restarted whenever its dependency is restarted. # Do not issue a hard dependency on keybase, because kbfs can reconnect to a restarted service. # Do not issue a hard dependency on keybase-redirector, because it's ok if it fails (e.g., if it is disabled). - wants = [ "keybase.service" ] ++ optional cfg.enableRedirector "keybase-redirector.service"; + wants = [ "keybase.service" ] ++ lib.optional cfg.enableRedirector "keybase-redirector.service"; path = [ "/run/wrappers" ]; unitConfig.ConditionUser = "!@system"; @@ -89,7 +88,7 @@ in { environment.systemPackages = [ pkgs.kbfs ]; } - (mkIf cfg.enableRedirector { + (lib.mkIf cfg.enableRedirector { security.wrappers."keybase-redirector".source = "${pkgs.kbfs}/bin/redirector"; systemd.tmpfiles.settings."10-kbfs"."/keybase".d = { diff --git a/nixos/modules/services/network-filesystems/kubo.nix b/nixos/modules/services/network-filesystems/kubo.nix index d4ffda7c374e..35efd2ba0a57 100644 --- a/nixos/modules/services/network-filesystems/kubo.nix +++ b/nixos/modules/services/network-filesystems/kubo.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, utils, ... }: -with lib; let cfg = config.services.kubo; @@ -35,11 +34,11 @@ let ''; kuboFlags = utils.escapeSystemdExecArgs ( - optional cfg.autoMount "--mount" ++ - optional cfg.enableGC "--enable-gc" ++ - optional (cfg.serviceFdlimit != null) "--manage-fdlimit=false" ++ - optional (cfg.defaultMode == "offline") "--offline" ++ - optional (cfg.defaultMode == "norouting") "--routing=none" ++ + lib.optional cfg.autoMount "--mount" ++ + lib.optional cfg.enableGC "--enable-gc" ++ + lib.optional (cfg.serviceFdlimit != null) "--manage-fdlimit=false" ++ + lib.optional (cfg.defaultMode == "offline") "--offline" ++ + lib.optional (cfg.defaultMode == "norouting") "--routing=none" ++ cfg.extraFlags ); @@ -99,78 +98,78 @@ in services.kubo = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' the Interplanetary File System (WARNING: may cause severe network degradation). NOTE: after enabling this option and rebuilding your system, you need to log out and back in for the `IPFS_PATH` environment variable to be present in your shell. Until you do that, the CLI tools won't be able to talk to the daemon by default ''; - package = mkPackageOption pkgs "kubo" { }; + package = lib.mkPackageOption pkgs "kubo" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "ipfs"; description = "User under which the Kubo daemon runs"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "ipfs"; description = "Group under which the Kubo daemon runs"; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = - if versionAtLeast config.system.stateVersion "17.09" + if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/ipfs" else "/var/lib/ipfs/.ipfs"; - defaultText = literalExpression '' - if versionAtLeast config.system.stateVersion "17.09" + defaultText = lib.literalExpression '' + if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/ipfs" else "/var/lib/ipfs/.ipfs" ''; description = "The data dir for Kubo"; }; - defaultMode = mkOption { - type = types.enum [ "online" "offline" "norouting" ]; + defaultMode = lib.mkOption { + type = lib.types.enum [ "online" "offline" "norouting" ]; default = "online"; description = "systemd service that is enabled by default"; }; - autoMount = mkOption { - type = types.bool; + autoMount = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether Kubo should try to mount /ipfs and /ipns at startup."; }; - autoMigrate = mkOption { - type = types.bool; + autoMigrate = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether Kubo should try to run the fs-repo-migration at startup."; }; - enableGC = mkOption { - type = types.bool; + enableGC = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable automatic garbage collection"; }; - emptyRepo = mkOption { - type = types.bool; + emptyRepo = lib.mkOption { + type = lib.types.bool; default = true; description = "If set to false, the repo will be initialized with help files"; }; - settings = mkOption { + settings = lib.mkOption { type = lib.types.submodule { freeformType = settingsFormat.type; options = { - Addresses.API = mkOption { - type = types.oneOf [ types.str (types.listOf types.str) ]; + Addresses.API = lib.mkOption { + type = lib.types.oneOf [ lib.types.str (lib.types.listOf lib.types.str) ]; default = [ ]; description = '' Multiaddr or array of multiaddrs describing the address to serve the local HTTP API on. @@ -180,14 +179,14 @@ in ''; }; - Addresses.Gateway = mkOption { - type = types.oneOf [ types.str (types.listOf types.str) ]; + Addresses.Gateway = lib.mkOption { + type = lib.types.oneOf [ lib.types.str (lib.types.listOf lib.types.str) ]; default = "/ip4/127.0.0.1/tcp/8080"; description = "Where the IPFS Gateway can be reached"; }; - Addresses.Swarm = mkOption { - type = types.listOf types.str; + Addresses.Swarm = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "/ip4/0.0.0.0/tcp/4001" "/ip6/::/tcp/4001" @@ -199,14 +198,14 @@ in description = "Where Kubo listens for incoming p2p connections"; }; - Mounts.IPFS = mkOption { - type = types.str; + Mounts.IPFS = lib.mkOption { + type = lib.types.str; default = "/ipfs"; description = "Where to mount the IPFS namespace to"; }; - Mounts.IPNS = mkOption { - type = types.str; + Mounts.IPNS = lib.mkOption { + type = lib.types.str; default = "/ipns"; description = "Where to mount the IPNS namespace to"; }; @@ -230,29 +229,29 @@ in }; - extraFlags = mkOption { - type = types.listOf types.str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Extra flags passed to the Kubo daemon"; default = [ ]; }; - localDiscovery = mkOption { - type = types.bool; + localDiscovery = lib.mkOption { + type = lib.types.bool; description = ''Whether to enable local discovery for the Kubo daemon. This will allow Kubo to scan ports on your local network. Some hosting services will ban you if you do this. ''; default = false; }; - serviceFdlimit = mkOption { - type = types.nullOr types.int; + serviceFdlimit = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = "The fdlimit for the Kubo systemd unit or `null` to have the daemon attempt to manage it"; example = 64 * 1024; }; - startWhenNeeded = mkOption { - type = types.bool; + startWhenNeeded = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to use socket activation to start Kubo when needed."; }; @@ -262,7 +261,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = !builtins.hasAttr "Identity" cfg.settings; @@ -288,14 +287,14 @@ in environment.variables.IPFS_PATH = fakeKuboRepo; # https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes - boot.kernel.sysctl."net.core.rmem_max" = mkDefault 2500000; - boot.kernel.sysctl."net.core.wmem_max" = mkDefault 2500000; + boot.kernel.sysctl."net.core.rmem_max" = lib.mkDefault 2500000; + boot.kernel.sysctl."net.core.wmem_max" = lib.mkDefault 2500000; - programs.fuse = mkIf cfg.autoMount { + programs.fuse = lib.mkIf cfg.autoMount { userAllowOther = true; }; - users.users = mkIf (cfg.user == "ipfs") { + users.users = lib.mkIf (cfg.user == "ipfs") { ipfs = { group = cfg.group; home = cfg.dataDir; @@ -308,7 +307,7 @@ in }; }; - users.groups = mkIf (cfg.group == "ipfs") { + users.groups = lib.mkIf (cfg.group == "ipfs") { ipfs.gid = config.ids.gids.ipfs; }; @@ -316,8 +315,8 @@ in defaultConfig = { inherit (cfg) user group; }; in { ${cfg.dataDir}.d = defaultConfig; - ${cfg.settings.Mounts.IPFS}.d = mkIf (cfg.autoMount) defaultConfig; - ${cfg.settings.Mounts.IPNS}.d = mkIf (cfg.autoMount) defaultConfig; + ${cfg.settings.Mounts.IPFS}.d = lib.mkIf (cfg.autoMount) defaultConfig; + ${cfg.settings.Mounts.IPNS}.d = lib.mkIf (cfg.autoMount) defaultConfig; }; # The hardened systemd unit breaks the fuse-mount function according to documentation in the unit file itself @@ -325,7 +324,7 @@ in then [ cfg.package.systemd_unit ] else [ cfg.package.systemd_unit_hardened ]; - services.kubo.settings = mkIf cfg.autoMount { + services.kubo.settings = lib.mkIf cfg.autoMount { Mounts.FuseAllowOther = lib.mkDefault true; }; @@ -339,7 +338,7 @@ in else # After an unclean shutdown this file may exist which will cause the config command to attempt to talk to the daemon. This will hang forever if systemd is holding our sockets open. rm -vf "$IPFS_PATH/api" - '' + optionalString cfg.autoMigrate '' + '' + lib.optionalString cfg.autoMigrate '' ${pkgs.kubo-migrator}/bin/fs-repo-migrations -to '${cfg.package.repoVersion}' -y '' + '' fi @@ -356,7 +355,7 @@ in # change when the changes are applied. Whyyyyyy..... ipfs --offline config replace - ''; - postStop = mkIf cfg.autoMount '' + postStop = lib.mkIf cfg.autoMount '' # After an unclean shutdown the fuse mounts at cfg.settings.Mounts.IPFS and cfg.settings.Mounts.IPNS are locked umount --quiet '${cfg.settings.Mounts.IPFS}' '${cfg.settings.Mounts.IPNS}' || true ''; @@ -365,11 +364,11 @@ in User = cfg.user; Group = cfg.group; StateDirectory = ""; - ReadWritePaths = optionals (!cfg.autoMount) [ "" cfg.dataDir ]; + ReadWritePaths = lib.optionals (!cfg.autoMount) [ "" cfg.dataDir ]; # Make sure the socket units are started before ipfs.service Sockets = [ "ipfs-gateway.socket" "ipfs-api.socket" ]; - } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; }; - } // optionalAttrs (!cfg.startWhenNeeded) { + } // lib.optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; }; + } // lib.optionalAttrs (!cfg.startWhenNeeded) { wantedBy = [ "default.target" ]; }; @@ -402,31 +401,31 @@ in }; imports = [ - (mkRenamedOptionModule [ "services" "ipfs" "enable" ] [ "services" "kubo" "enable" ]) - (mkRenamedOptionModule [ "services" "ipfs" "package" ] [ "services" "kubo" "package" ]) - (mkRenamedOptionModule [ "services" "ipfs" "user" ] [ "services" "kubo" "user" ]) - (mkRenamedOptionModule [ "services" "ipfs" "group" ] [ "services" "kubo" "group" ]) - (mkRenamedOptionModule [ "services" "ipfs" "dataDir" ] [ "services" "kubo" "dataDir" ]) - (mkRenamedOptionModule [ "services" "ipfs" "defaultMode" ] [ "services" "kubo" "defaultMode" ]) - (mkRenamedOptionModule [ "services" "ipfs" "autoMount" ] [ "services" "kubo" "autoMount" ]) - (mkRenamedOptionModule [ "services" "ipfs" "autoMigrate" ] [ "services" "kubo" "autoMigrate" ]) - (mkRenamedOptionModule [ "services" "ipfs" "ipfsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPFS" ]) - (mkRenamedOptionModule [ "services" "ipfs" "ipnsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPNS" ]) - (mkRenamedOptionModule [ "services" "ipfs" "gatewayAddress" ] [ "services" "kubo" "settings" "Addresses" "Gateway" ]) - (mkRenamedOptionModule [ "services" "ipfs" "apiAddress" ] [ "services" "kubo" "settings" "Addresses" "API" ]) - (mkRenamedOptionModule [ "services" "ipfs" "swarmAddress" ] [ "services" "kubo" "settings" "Addresses" "Swarm" ]) - (mkRenamedOptionModule [ "services" "ipfs" "enableGC" ] [ "services" "kubo" "enableGC" ]) - (mkRenamedOptionModule [ "services" "ipfs" "emptyRepo" ] [ "services" "kubo" "emptyRepo" ]) - (mkRenamedOptionModule [ "services" "ipfs" "extraConfig" ] [ "services" "kubo" "settings" ]) - (mkRenamedOptionModule [ "services" "ipfs" "extraFlags" ] [ "services" "kubo" "extraFlags" ]) - (mkRenamedOptionModule [ "services" "ipfs" "localDiscovery" ] [ "services" "kubo" "localDiscovery" ]) - (mkRenamedOptionModule [ "services" "ipfs" "serviceFdlimit" ] [ "services" "kubo" "serviceFdlimit" ]) - (mkRenamedOptionModule [ "services" "ipfs" "startWhenNeeded" ] [ "services" "kubo" "startWhenNeeded" ]) - (mkRenamedOptionModule [ "services" "kubo" "extraConfig" ] [ "services" "kubo" "settings" ]) - (mkRenamedOptionModule [ "services" "kubo" "gatewayAddress" ] [ "services" "kubo" "settings" "Addresses" "Gateway" ]) - (mkRenamedOptionModule [ "services" "kubo" "apiAddress" ] [ "services" "kubo" "settings" "Addresses" "API" ]) - (mkRenamedOptionModule [ "services" "kubo" "swarmAddress" ] [ "services" "kubo" "settings" "Addresses" "Swarm" ]) - (mkRenamedOptionModule [ "services" "kubo" "ipfsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPFS" ]) - (mkRenamedOptionModule [ "services" "kubo" "ipnsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPNS" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "enable" ] [ "services" "kubo" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "package" ] [ "services" "kubo" "package" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "user" ] [ "services" "kubo" "user" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "group" ] [ "services" "kubo" "group" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "dataDir" ] [ "services" "kubo" "dataDir" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "defaultMode" ] [ "services" "kubo" "defaultMode" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "autoMount" ] [ "services" "kubo" "autoMount" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "autoMigrate" ] [ "services" "kubo" "autoMigrate" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "ipfsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPFS" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "ipnsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPNS" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "gatewayAddress" ] [ "services" "kubo" "settings" "Addresses" "Gateway" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "apiAddress" ] [ "services" "kubo" "settings" "Addresses" "API" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "swarmAddress" ] [ "services" "kubo" "settings" "Addresses" "Swarm" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "enableGC" ] [ "services" "kubo" "enableGC" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "emptyRepo" ] [ "services" "kubo" "emptyRepo" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "extraConfig" ] [ "services" "kubo" "settings" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "extraFlags" ] [ "services" "kubo" "extraFlags" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "localDiscovery" ] [ "services" "kubo" "localDiscovery" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "serviceFdlimit" ] [ "services" "kubo" "serviceFdlimit" ]) + (lib.mkRenamedOptionModule [ "services" "ipfs" "startWhenNeeded" ] [ "services" "kubo" "startWhenNeeded" ]) + (lib.mkRenamedOptionModule [ "services" "kubo" "extraConfig" ] [ "services" "kubo" "settings" ]) + (lib.mkRenamedOptionModule [ "services" "kubo" "gatewayAddress" ] [ "services" "kubo" "settings" "Addresses" "Gateway" ]) + (lib.mkRenamedOptionModule [ "services" "kubo" "apiAddress" ] [ "services" "kubo" "settings" "Addresses" "API" ]) + (lib.mkRenamedOptionModule [ "services" "kubo" "swarmAddress" ] [ "services" "kubo" "settings" "Addresses" "Swarm" ]) + (lib.mkRenamedOptionModule [ "services" "kubo" "ipfsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPFS" ]) + (lib.mkRenamedOptionModule [ "services" "kubo" "ipnsMountDir" ] [ "services" "kubo" "settings" "Mounts" "IPNS" ]) ]; } diff --git a/nixos/modules/services/network-filesystems/litestream/default.nix b/nixos/modules/services/network-filesystems/litestream/default.nix index 87f07b0501be..f4b0281ebbe2 100644 --- a/nixos/modules/services/network-filesystems/litestream/default.nix +++ b/nixos/modules/services/network-filesystems/litestream/default.nix @@ -1,18 +1,15 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.litestream; settingsFormat = pkgs.formats.yaml {}; in { options.services.litestream = { - enable = mkEnableOption "litestream"; + enable = lib.mkEnableOption "litestream"; - package = mkPackageOption pkgs "litestream" { }; + package = lib.mkPackageOption pkgs "litestream" { }; - settings = mkOption { + settings = lib.mkOption { description = '' See the [documentation](https://litestream.io/reference/config/). ''; @@ -31,8 +28,8 @@ in }; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/run/secrets/litestream"; description = '' @@ -61,7 +58,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; environment.etc = { "litestream.yml" = { @@ -74,7 +71,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "networking.target" ]; serviceConfig = { - EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; ExecStart = "${cfg.package}/bin/litestream replicate"; Restart = "always"; User = "litestream"; diff --git a/nixos/modules/services/network-filesystems/moosefs.nix b/nixos/modules/services/network-filesystems/moosefs.nix index 8d29148883ab..2fef0bec378c 100644 --- a/nixos/modules/services/network-filesystems/moosefs.nix +++ b/nixos/modules/services/network-filesystems/moosefs.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.moosefs; @@ -9,14 +6,14 @@ let settingsFormat = let listSep = " "; - allowedTypes = with types; [ bool int float str ]; + allowedTypes = with lib.types; [ bool int float str ]; valueToString = val: - if isList val then concatStringsSep listSep (map (x: valueToString x) val) - else if isBool val then (if val then "1" else "0") + if lib.isList val then lib.concatStringsSep listSep (map (x: valueToString x) val) + else if lib.isBool val then (if val then "1" else "0") else toString val; in { - type = with types; let + type = with lib.types; let valueType = oneOf ([ (listOf valueType) ] ++ allowedTypes) // { @@ -72,24 +69,24 @@ in { options = { services.moosefs = { - masterHost = mkOption { - type = types.str; + masterHost = lib.mkOption { + type = lib.types.str; default = null; description = "IP or DNS name of master host."; }; - runAsUser = mkOption { - type = types.bool; + runAsUser = lib.mkOption { + type = lib.types.bool; default = true; example = true; description = "Run daemons as user moosefs instead of root."; }; - client.enable = mkEnableOption "Moosefs client"; + client.enable = lib.mkEnableOption "Moosefs client"; master = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; description = '' Enable Moosefs master daemon. @@ -99,8 +96,8 @@ in { default = false; }; - exports = mkOption { - type = with types; listOf str; + exports = lib.mkOption { + type = with lib.types; listOf str; default = null; description = "Paths to export (see mfsexports.cfg)."; example = [ @@ -109,18 +106,18 @@ in { ]; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; description = "Whether to automatically open the necessary ports in the firewall."; default = false; }; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = settingsFormat.type; - options.DATA_PATH = mkOption { - type = types.str; + options.DATA_PATH = lib.mkOption { + type = lib.types.str; default = "/var/lib/mfs"; description = "Data storage directory."; }; @@ -131,14 +128,14 @@ in { }; metalogger = { - enable = mkEnableOption "Moosefs metalogger daemon"; + enable = lib.mkEnableOption "Moosefs metalogger daemon"; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = settingsFormat.type; - options.DATA_PATH = mkOption { - type = types.str; + options.DATA_PATH = lib.mkOption { + type = lib.types.str; default = "/var/lib/mfs"; description = "Data storage directory"; }; @@ -149,27 +146,27 @@ in { }; chunkserver = { - enable = mkEnableOption "Moosefs chunkserver daemon"; + enable = lib.mkEnableOption "Moosefs chunkserver daemon"; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; description = "Whether to automatically open the necessary ports in the firewall."; default = false; }; - hdds = mkOption { - type = with types; listOf str; + hdds = lib.mkOption { + type = with lib.types; listOf str; default = null; description = "Mount points to be used by chunkserver for storage (see mfshdd.cfg)."; example = [ "/mnt/hdd1" ]; }; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = settingsFormat.type; - options.DATA_PATH = mkOption { - type = types.str; + options.DATA_PATH = lib.mkOption { + type = lib.types.str; default = "/var/lib/mfs"; description = "Directory for lock file."; }; @@ -183,33 +180,33 @@ in { ###### implementation - config = mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) { + config = lib.mkIf ( cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) { - warnings = [ ( mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ]; + warnings = [ ( lib.mkIf (!cfg.runAsUser) "Running moosefs services as root is not recommended.") ]; # Service settings services.moosefs = { - master.settings = mkIf cfg.master.enable { + master.settings = lib.mkIf cfg.master.enable { WORKING_USER = mfsUser; EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg" - (concatStringsSep "\n" cfg.master.exports)); + (lib.concatStringsSep "\n" cfg.master.exports)); }; - metalogger.settings = mkIf cfg.metalogger.enable { + metalogger.settings = lib.mkIf cfg.metalogger.enable { WORKING_USER = mfsUser; MASTER_HOST = cfg.masterHost; }; - chunkserver.settings = mkIf cfg.chunkserver.enable { + chunkserver.settings = lib.mkIf cfg.chunkserver.enable { WORKING_USER = mfsUser; MASTER_HOST = cfg.masterHost; HDD_CONF_FILENAME = toString ( pkgs.writeText "mfshdd.cfg" - (concatStringsSep "\n" cfg.chunkserver.hdds)); + (lib.concatStringsSep "\n" cfg.chunkserver.hdds)); }; }; # Create system user account for daemons - users = mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) { + users = lib.mkIf ( cfg.runAsUser && ( cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable ) ) { users.moosefs = { isSystemUser = true; description = "moosefs daemon user"; @@ -228,22 +225,22 @@ in { # Ensure storage directories exist systemd.tmpfiles.rules = - optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" - ++ optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" - ++ optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"; + lib.optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" + ++ lib.optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}" + ++ lib.optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${mfsUser} ${mfsUser}"; # Service definitions - systemd.services.mfs-master = mkIf cfg.master.enable + systemd.services.mfs-master = lib.mkIf cfg.master.enable ( systemdService "master" { TimeoutStartSec = 1800; TimeoutStopSec = 1800; Restart = "no"; } masterCfg ); - systemd.services.mfs-metalogger = mkIf cfg.metalogger.enable + systemd.services.mfs-metalogger = lib.mkIf cfg.metalogger.enable ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg ); - systemd.services.mfs-chunkserver = mkIf cfg.chunkserver.enable + systemd.services.mfs-chunkserver = lib.mkIf cfg.chunkserver.enable ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg ); }; } diff --git a/nixos/modules/services/network-filesystems/netatalk.nix b/nixos/modules/services/network-filesystems/netatalk.nix index d7eef33ad96c..e8c97df3151b 100644 --- a/nixos/modules/services/network-filesystems/netatalk.nix +++ b/nixos/modules/services/network-filesystems/netatalk.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.netatalk; settingsFormat = pkgs.formats.ini { }; @@ -10,15 +7,15 @@ in { options = { services.netatalk = { - enable = mkEnableOption "the Netatalk AFP fileserver"; + enable = lib.mkEnableOption "the Netatalk AFP fileserver"; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 548; description = "TCP port to be used for AFP."; }; - settings = mkOption { + settings = lib.mkOption { inherit (settingsFormat) type; default = { }; example = { @@ -38,8 +35,8 @@ in { ''; }; - extmap = mkOption { - type = types.lines; + extmap = lib.mkOption { + type = lib.types.lines; default = ""; description = '' File name extension mappings. @@ -51,14 +48,14 @@ in { }; imports = (map (option: - mkRemovedOptionModule [ "services" "netatalk" option ] + lib.mkRemovedOptionModule [ "services" "netatalk" option ] "This option was removed in favor of `services.netatalk.settings`.") [ "extraConfig" "homes" "volumes" ]); - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.netatalk.settings.Global = { "afp port" = toString cfg.port; diff --git a/nixos/modules/services/network-filesystems/nfsd.nix b/nixos/modules/services/network-filesystems/nfsd.nix index c40bcf28c28f..67597d37813f 100644 --- a/nixos/modules/services/network-filesystems/nfsd.nix +++ b/nixos/modules/services/network-filesystems/nfsd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.nfs.server; @@ -12,8 +9,8 @@ in { imports = [ - (mkRenamedOptionModule [ "services" "nfs" "lockdPort" ] [ "services" "nfs" "server" "lockdPort" ]) - (mkRenamedOptionModule [ "services" "nfs" "statdPort" ] [ "services" "nfs" "server" "statdPort" ]) + (lib.mkRenamedOptionModule [ "services" "nfs" "lockdPort" ] [ "services" "nfs" "server" "lockdPort" ]) + (lib.mkRenamedOptionModule [ "services" "nfs" "statdPort" ] [ "services" "nfs" "server" "statdPort" ]) ]; ###### interface @@ -23,24 +20,24 @@ in services.nfs = { server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the kernel's NFS server. ''; }; - extraNfsdConfig = mkOption { - type = types.str; + extraNfsdConfig = lib.mkOption { + type = lib.types.str; default = ""; description = '' Extra configuration options for the [nfsd] section of /etc/nfs.conf. ''; }; - exports = mkOption { - type = types.lines; + exports = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Contents of the /etc/exports file. See @@ -48,8 +45,8 @@ in ''; }; - hostName = mkOption { - type = types.nullOr types.str; + hostName = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Hostname or address on which NFS requests will be accepted. @@ -58,22 +55,22 @@ in ''; }; - nproc = mkOption { - type = types.int; + nproc = lib.mkOption { + type = lib.types.int; default = 8; description = '' Number of NFS server threads. Defaults to the recommended value of 8. ''; }; - createMountPoints = mkOption { - type = types.bool; + createMountPoints = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to create the mount points in the exports file at startup time."; }; - mountdPort = mkOption { - type = types.nullOr types.int; + mountdPort = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 4002; description = '' @@ -81,8 +78,8 @@ in ''; }; - lockdPort = mkOption { - type = types.nullOr types.int; + lockdPort = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 4001; description = '' @@ -92,8 +89,8 @@ in ''; }; - statdPort = mkOption { - type = types.nullOr types.int; + statdPort = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 4000; description = '' @@ -111,7 +108,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.rpcbind.enable = true; @@ -137,7 +134,7 @@ in '' mkdir -p /var/lib/nfs - ${optionalString cfg.createMountPoints + ${lib.optionalString cfg.createMountPoints '' # create export directories: # skip comments, take first col which may either be a quoted diff --git a/nixos/modules/services/network-filesystems/orangefs/client.nix b/nixos/modules/services/network-filesystems/orangefs/client.nix index 0632a9bc9527..3923289e6f64 100644 --- a/nixos/modules/services/network-filesystems/orangefs/client.nix +++ b/nixos/modules/services/network-filesystems/orangefs/client.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ...} : - -with lib; - let cfg = config.services.orangefs.client; @@ -10,15 +7,15 @@ in { options = { services.orangefs.client = { - enable = mkEnableOption "OrangeFS client daemon"; + enable = lib.mkEnableOption "OrangeFS client daemon"; - extraOptions = mkOption { - type = with types; listOf str; + extraOptions = lib.mkOption { + type = with lib.types; listOf str; default = []; description = "Extra command line options for pvfs2-client."; }; - fileSystems = mkOption { + fileSystems = lib.mkOption { description = '' The orangefs file systems to be mounted. This option is preferred over using {option}`fileSystems` directly since @@ -30,23 +27,23 @@ in { target = "tcp://server:3334/orangefs"; }]; - type = with types; listOf (submodule ({ ... } : { + type = with lib.types; listOf (submodule ({ ... } : { options = { - mountPoint = mkOption { - type = types.str; + mountPoint = lib.mkOption { + type = lib.types.str; default = "/orangefs"; description = "Mount point."; }; - options = mkOption { - type = with types; listOf str; + options = lib.mkOption { + type = with lib.types; listOf str; default = []; description = "Mount options"; }; - target = mkOption { - type = types.str; + target = lib.mkOption { + type = lib.types.str; example = "tcp://server:3334/orangefs"; description = "Target URL"; }; @@ -59,7 +56,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.orangefs ]; boot.supportedFilesystems = [ "pvfs2" ]; @@ -74,7 +71,7 @@ in { ExecStart = '' ${pkgs.orangefs}/bin/pvfs2-client-core \ - --logtype=syslog ${concatStringsSep " " cfg.extraOptions} + --logtype=syslog ${lib.concatStringsSep " " cfg.extraOptions} ''; TimeoutStopSec = "120"; @@ -87,7 +84,7 @@ in { bindsTo = [ "orangefs-client.service" ]; wantedBy = [ "remote-fs.target" ]; type = "pvfs2"; - options = concatStringsSep "," fs.options; + options = lib.concatStringsSep "," fs.options; what = fs.target; where = fs.mountPoint; }) cfg.fileSystems; diff --git a/nixos/modules/services/network-filesystems/orangefs/server.nix b/nixos/modules/services/network-filesystems/orangefs/server.nix index 9fbf37f0d00a..c198d4764559 100644 --- a/nixos/modules/services/network-filesystems/orangefs/server.nix +++ b/nixos/modules/services/network-filesystems/orangefs/server.nix @@ -1,19 +1,16 @@ { config, lib, pkgs, ...} : - -with lib; - let cfg = config.services.orangefs.server; - aliases = mapAttrsToList (alias: url: alias) cfg.servers; + aliases = lib.mapAttrsToList (alias: url: alias) cfg.servers; # Maximum handle number is 2^63 maxHandle = 9223372036854775806; # One range of handles for each meta/data instance - handleStep = maxHandle / (length aliases) / 2; + handleStep = maxHandle / (lib.length aliases) / 2; - fileSystems = mapAttrsToList (name: fs: '' + fileSystems = lib.mapAttrsToList (name: fs: '' Name ${name} ID ${toString fs.id} @@ -22,8 +19,8 @@ let ${fs.extraConfig} - ${concatStringsSep "\n" ( - imap0 (i: alias: + ${lib.concatStringsSep "\n" ( + lib.imap0 (i: alias: let begin = i * handleStep + 3; end = begin + handleStep - 1; @@ -32,10 +29,10 @@ let - ${concatStringsSep "\n" ( - imap0 (i: alias: + ${lib.concatStringsSep "\n" ( + lib.imap0 (i: alias: let - begin = i * handleStep + 3 + (length aliases) * handleStep; + begin = i * handleStep + 3 + (lib.length aliases) * handleStep; end = begin + handleStep - 1; in "Range ${alias} ${toString begin}-${toString end}") aliases )} @@ -56,17 +53,17 @@ let DataStorageSpace ${cfg.dataStorageSpace} MetaDataStorageSpace ${cfg.metadataStorageSpace} - BMIModules ${concatStringsSep "," cfg.BMIModules} + BMIModules ${lib.concatStringsSep "," cfg.BMIModules} ${cfg.extraDefaults} ${cfg.extraConfig} - ${concatStringsSep "\n" (mapAttrsToList (alias: url: "Alias ${alias} ${url}") cfg.servers)} + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (alias: url: "Alias ${alias} ${url}") cfg.servers)} - ${concatStringsSep "\n" fileSystems} + ${lib.concatStringsSep "\n" fileSystems} ''; in { @@ -74,49 +71,49 @@ in { options = { services.orangefs.server = { - enable = mkEnableOption "OrangeFS server"; + enable = lib.mkEnableOption "OrangeFS server"; - logType = mkOption { - type = with types; enum [ "file" "syslog" ]; + logType = lib.mkOption { + type = with lib.types; enum [ "file" "syslog" ]; default = "syslog"; description = "Destination for log messages."; }; - dataStorageSpace = mkOption { - type = types.nullOr types.str; + dataStorageSpace = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "/data/storage"; description = "Directory for data storage."; }; - metadataStorageSpace = mkOption { - type = types.nullOr types.str; + metadataStorageSpace = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "/data/meta"; description = "Directory for meta data storage."; }; - BMIModules = mkOption { - type = with types; listOf str; + BMIModules = lib.mkOption { + type = with lib.types; listOf str; default = [ "bmi_tcp" ]; example = [ "bmi_tcp" "bmi_ib"]; description = "List of BMI modules to load."; }; - extraDefaults = mkOption { - type = types.lines; + extraDefaults = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra config for `` section."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra config for the global section."; }; - servers = mkOption { - type = with types; attrsOf types.str; + servers = lib.mkOption { + type = with lib.types; attrsOf lib.types.str; default = {}; example = { node1 = "tcp://node1:3334"; @@ -125,12 +122,12 @@ in { description = "URLs for storage server including port. The attribute names define the server alias."; }; - fileSystems = mkOption { + fileSystems = lib.mkOption { description = '' These options will create the `` sections of config file. ''; default = { orangefs = {}; }; - example = literalExpression '' + example = lib.literalExpression '' { fs1 = { id = 101; @@ -141,40 +138,40 @@ in { }; } ''; - type = with types; attrsOf (submodule ({ ... } : { + type = with lib.types; attrsOf (submodule ({ ... } : { options = { - id = mkOption { - type = types.int; + id = lib.mkOption { + type = lib.types.int; default = 1; description = "File system ID (must be unique within configuration)."; }; - rootHandle = mkOption { - type = types.int; + rootHandle = lib.mkOption { + type = lib.types.int; default = 3; description = "File system root ID."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra config for `` section."; }; - troveSyncMeta = mkOption { - type = types.bool; + troveSyncMeta = lib.mkOption { + type = lib.types.bool; default = true; description = "Sync meta data."; }; - troveSyncData = mkOption { - type = types.bool; + troveSyncData = lib.mkOption { + type = lib.types.bool; default = false; description = "Sync data."; }; - extraStorageHints = mkOption { - type = types.lines; + extraStorageHints = lib.mkOption { + type = lib.types.lines; default = ""; description = "Extra config for `` section."; }; @@ -186,7 +183,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.orangefs ]; # orangefs daemon will run as user diff --git a/nixos/modules/services/network-filesystems/rsyncd.nix b/nixos/modules/services/network-filesystems/rsyncd.nix index 49bc7caf2ee4..93dc41c3c956 100644 --- a/nixos/modules/services/network-filesystems/rsyncd.nix +++ b/nixos/modules/services/network-filesystems/rsyncd.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.rsyncd; settingsFormat = pkgs.formats.ini { }; @@ -10,15 +7,15 @@ in { options = { services.rsyncd = { - enable = mkEnableOption "the rsync daemon"; + enable = lib.mkEnableOption "the rsync daemon"; - port = mkOption { + port = lib.mkOption { default = 873; - type = types.port; + type = lib.types.port; description = "TCP port the daemon will listen on."; }; - settings = mkOption { + settings = lib.mkOption { inherit (settingsFormat) type; default = { }; example = { @@ -45,9 +42,9 @@ in { ''; }; - socketActivated = mkOption { + socketActivated = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "If enabled Rsync will be socket-activated rather than run persistently."; }; @@ -55,7 +52,7 @@ in { }; imports = (map (option: - mkRemovedOptionModule [ "services" "rsyncd" option ] + lib.mkRemovedOptionModule [ "services" "rsyncd" option ] "This option was removed in favor of `services.rsyncd.settings`.") [ "address" "extraConfig" @@ -64,7 +61,7 @@ in { "group" ]); - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.rsyncd.settings.global.port = toString cfg.port; diff --git a/nixos/modules/services/network-filesystems/samba-wsdd.nix b/nixos/modules/services/network-filesystems/samba-wsdd.nix index f46bf802511a..60ede5a1bda2 100644 --- a/nixos/modules/services/network-filesystems/samba-wsdd.nix +++ b/nixos/modules/services/network-filesystems/samba-wsdd.nix @@ -1,65 +1,62 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.samba-wsdd; in { options = { services.samba-wsdd = { - enable = mkEnableOption '' + enable = lib.mkEnableOption '' Web Services Dynamic Discovery host daemon. This enables (Samba) hosts, like your local NAS device, to be found by Web Service Discovery Clients like Windows ''; - interface = mkOption { - type = types.nullOr types.str; + interface = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "eth0"; description = "Interface or address to use."; }; - hoplimit = mkOption { - type = types.nullOr types.int; + hoplimit = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 2; description = "Hop limit for multicast packets (default = 1)."; }; - openFirewall = mkOption { + openFirewall = lib.mkOption { description = '' Whether to open the required firewall ports in the firewall. ''; default = false; type = lib.types.bool; }; - workgroup = mkOption { - type = types.nullOr types.str; + workgroup = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "HOME"; description = "Set workgroup name (default WORKGROUP)."; }; - hostname = mkOption { - type = types.nullOr types.str; + hostname = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "FILESERVER"; description = "Override (NetBIOS) hostname to be used (default hostname)."; }; - domain = mkOption { - type = types.nullOr types.str; + domain = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = "Set domain name (disables workgroup)."; }; - discovery = mkOption { - type = types.bool; + discovery = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable discovery operation mode."; }; - listen = mkOption { - type = types.str; + listen = lib.mkOption { + type = lib.types.str; default = "/run/wsdd/wsdd.sock"; description = "Listen on path or localhost port in discovery mode."; }; - extraOptions = mkOption { - type = types.listOf types.str; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "--shortlog" ]; example = [ "--verbose" "--no-http" "--ipv4only" "--no-host" ]; description = "Additional wsdd options."; @@ -67,7 +64,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.wsdd ]; @@ -79,13 +76,13 @@ in { DynamicUser = true; Type = "simple"; ExecStart = '' - ${pkgs.wsdd}/bin/wsdd ${optionalString (cfg.interface != null) "--interface '${cfg.interface}'"} \ - ${optionalString (cfg.hoplimit != null) "--hoplimit '${toString cfg.hoplimit}'"} \ - ${optionalString (cfg.workgroup != null) "--workgroup '${cfg.workgroup}'"} \ - ${optionalString (cfg.hostname != null) "--hostname '${cfg.hostname}'"} \ - ${optionalString (cfg.domain != null) "--domain '${cfg.domain}'"} \ - ${optionalString cfg.discovery "--discovery --listen '${cfg.listen}'"} \ - ${escapeShellArgs cfg.extraOptions} + ${pkgs.wsdd}/bin/wsdd ${lib.optionalString (cfg.interface != null) "--interface '${cfg.interface}'"} \ + ${lib.optionalString (cfg.hoplimit != null) "--hoplimit '${toString cfg.hoplimit}'"} \ + ${lib.optionalString (cfg.workgroup != null) "--workgroup '${cfg.workgroup}'"} \ + ${lib.optionalString (cfg.hostname != null) "--hostname '${cfg.hostname}'"} \ + ${lib.optionalString (cfg.domain != null) "--domain '${cfg.domain}'"} \ + ${lib.optionalString cfg.discovery "--discovery --listen '${cfg.listen}'"} \ + ${lib.escapeShellArgs cfg.extraOptions} ''; # Runtime directory and mode RuntimeDirectory = "wsdd"; @@ -121,7 +118,7 @@ in { }; }; - networking.firewall = mkIf cfg.openFirewall { + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ 5357 ]; allowedUDPPorts = [ 3702 ]; }; diff --git a/nixos/modules/services/network-filesystems/samba.md b/nixos/modules/services/network-filesystems/samba.md new file mode 100644 index 000000000000..229320220974 --- /dev/null +++ b/nixos/modules/services/network-filesystems/samba.md @@ -0,0 +1,41 @@ +# Samba {#module-services-samba} + +[Samba](https://www.samba.org/), a SMB/CIFS file, print, and login server for Unix. + +## Basic Usage {#module-services-samba-basic-usage} + +A minimal configuration looks like this: + +```nix +{ + services.samba.enable = true; +} +``` + +This configuration automatically enables `smbd`, `nmbd` and `winbindd` services by default. + +## Configuring {#module-services-samba-configuring} + +Samba configuration is located in the `/etc/samba/smb.conf` file. + +### File share {#module-services-samba-configuring-file-share} + +This configuration will configure Samba to serve a `public` file share +which is read-only and accessible without authentication: + +```nix +{ + services.samba = { + enable = true; + settings = { + "public" = { + "path" = "/public"; + "read only" = "yes"; + "browseable" = "yes"; + "guest ok" = "yes"; + "comment" = "Public samba share."; + }; + }; + }; +} +``` diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index a887f964ca42..e661d3ff33bf 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -1,234 +1,192 @@ { config, lib, pkgs, ... }: - -with lib; - let - - smbToString = x: if builtins.typeOf x == "bool" - then boolToString x - else toString x; - cfg = config.services.samba; - samba = cfg.package; + settingsFormat = pkgs.formats.ini { + listToValue = lib.concatMapStringsSep " " (lib.generators.mkValueStringDefault { }); + }; + # Ensure the global section is always first + globalConfigFile = settingsFormat.generate "smb-global.conf" { global = cfg.settings.global; }; + sharesConfigFile = settingsFormat.generate "smb-shares.conf" (lib.removeAttrs cfg.settings [ "global" ]); - shareConfig = name: - let share = getAttr name cfg.shares; in - "[${name}]\n " + (smbToString ( - map - (key: "${key} = ${smbToString (getAttr key share)}\n") - (attrNames share) - )); - - configFile = pkgs.writeText "smb.conf" - (if cfg.configText != null then cfg.configText else - '' - [global] - security = ${cfg.securityType} - passwd program = /run/wrappers/bin/passwd %u - invalid users = ${smbToString cfg.invalidUsers} - - ${cfg.extraConfig} - - ${smbToString (map shareConfig (attrNames cfg.shares))} - ''); - - # This may include nss_ldap, needed for samba if it has to use ldap. - nssModulesPath = config.system.nssModules.path; - - daemonService = appName: args: - { description = "Samba Service Daemon ${appName}"; - - after = [ (mkIf (cfg.enableNmbd && "${appName}" == "smbd") "samba-nmbd.service") "network.target" ]; - requiredBy = [ "samba.target" ]; - partOf = [ "samba.target" ]; - - environment = { - LD_LIBRARY_PATH = nssModulesPath; - LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; - }; - - serviceConfig = { - ExecStart = "${samba}/sbin/${appName} --foreground --no-process-group ${args}"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - LimitNOFILE = 16384; - PIDFile = "/run/${appName}.pid"; - Type = "notify"; - NotifyAccess = "all"; #may not do anything... - Slice = "system-samba.slice"; - }; - unitConfig.RequiresMountsFor = "/var/lib/samba"; - - restartTriggers = [ configFile ]; - }; + configFile = pkgs.concatText "smb.conf" [ globalConfigFile sharesConfigFile ]; in { + meta = { + doc = ./samba.md; + maintainers = [ lib.maintainers.anthonyroussel ]; + }; + imports = [ - (mkRemovedOptionModule [ "services" "samba" "defaultShare" ] "") - (mkRemovedOptionModule [ "services" "samba" "syncPasswordsByPam" ] "This option has been removed by upstream, see https://bugzilla.samba.org/show_bug.cgi?id=10669#c10") + (lib.mkRemovedOptionModule [ "services" "samba" "defaultShare" ] "") + (lib.mkRemovedOptionModule [ "services" "samba" "syncPasswordsByPam" ] "This option has been removed by upstream, see https://bugzilla.samba.org/show_bug.cgi?id=10669#c10") + + (lib.mkRemovedOptionModule [ "services" "samba" "configText" ] '' + Use services.samba.settings instead. + + This is part of the general move to use structured settings instead of raw + text for config as introduced by RFC0042: + https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md + '') + (lib.mkRemovedOptionModule [ "services" "samba" "extraConfig" ] "Use services.samba.settings instead.") + (lib.mkRenamedOptionModule [ "services" "samba" "invalidUsers" ] [ "services" "samba" "settings" "global" "invalid users" ]) + (lib.mkRenamedOptionModule [ "services" "samba" "securityType" ] [ "services" "samba" "settings" "global" "security" ]) + (lib.mkRenamedOptionModule [ "services" "samba" "shares" ] [ "services" "samba" "settings" ]) + + (lib.mkRenamedOptionModule [ "services" "samba" "enableWinbindd" ] [ "services" "samba" "winbindd" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "samba" "enableNmbd" ] [ "services" "samba" "nmbd" "enable" ]) ]; ###### interface options = { - - # !!! clean up the descriptions. - services.samba = { + enable = lib.mkEnableOption "Samba, the SMB/CIFS protocol"; - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable Samba, which provides file and print - services to Windows clients through the SMB/CIFS protocol. - - ::: {.note} - If you use the firewall consider adding the following: - - services.samba.openFirewall = true; - ::: - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Whether to automatically open the necessary ports in the firewall. - ''; - }; - - enableNmbd = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable Samba's nmbd, which replies to NetBIOS over IP name - service requests. It also participates in the browsing protocols - which make up the Windows "Network Neighborhood" view. - ''; - }; - - enableWinbindd = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable Samba's winbindd, which provides a number of services - to the Name Service Switch capability found in most modern C libraries, - to arbitrary applications via PAM and ntlm_auth and to Samba itself. - ''; - }; - - package = mkPackageOption pkgs "samba" { + package = lib.mkPackageOption pkgs "samba" { example = "samba4Full"; }; - invalidUsers = mkOption { - type = types.listOf types.str; - default = [ "root" ]; - description = '' - List of users who are denied to login via Samba. - ''; + openFirewall = lib.mkEnableOption "opening the default ports in the firewall for Samba"; + + smbd = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to enable Samba's smbd daemon."; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments to pass to the smbd service."; + }; }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional global section and extra section lines go in here. - ''; - example = '' - guest account = nobody - map to guest = bad user - ''; + nmbd = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to enable Samba's nmbd, which replies to NetBIOS over IP name + service requests. It also participates in the browsing protocols + which make up the Windows "Network Neighborhood" view. + ''; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments to pass to the nmbd service."; + }; }; - configText = mkOption { - type = types.nullOr types.lines; - default = null; - description = '' - Verbatim contents of smb.conf. If null (default), use the - autogenerated file from NixOS instead. - ''; + winbindd = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to enable Samba's winbindd, which provides a number of services + to the Name Service Switch capability found in most modern C libraries, + to arbitrary applications via PAM and ntlm_auth and to Samba itself. + ''; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments to pass to the winbindd service."; + }; }; - securityType = mkOption { - type = types.enum [ "auto" "user" "domain" "ads" ]; - default = "user"; - description = "Samba security type"; - }; + nsswins = lib.mkEnableOption '' + WINS NSS (Name Service Switch) plug-in. - nsswins = mkOption { - default = false; - type = types.bool; - description = '' - Whether to enable the WINS NSS (Name Service Switch) plug-in. - Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a. - Windows machine names) by transparently querying the winbindd daemon. - ''; - }; + Enabling it allows applications to resolve WINS/NetBIOS names (a.k.a. + Windows machine names) by transparently querying the winbindd daemon + ''; - shares = mkOption { - default = {}; - description = '' - A set describing shared resources. - See {command}`man smb.conf` for options. - ''; - type = types.attrsOf (types.attrsOf types.unspecified); - example = literalExpression '' - { public = - { path = "/srv/public"; - "read only" = true; - browseable = "yes"; - "guest ok" = "yes"; - comment = "Public samba share."; + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + global.security = lib.mkOption { + type = lib.types.enum [ "auto" "user" "domain" "ads" ]; + default = "user"; + description = "Samba security type."; }; - } + global."invalid users" = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "root" ]; + description = "List of users who are denied to login via Samba."; + }; + global."passwd program" = lib.mkOption { + type = lib.types.str; + default = "/run/wrappers/bin/passwd %u"; + description = "Path to a program that can be used to set UNIX user passwords."; + }; + }; + }; + default = { + "global" = { + "security" = "user"; + "passwd program" = "/run/wrappers/bin/passwd %u"; + "invalid users" = [ "root" ]; + }; + }; + example = { + "global" = { + "security" = "user"; + "passwd program" = "/run/wrappers/bin/passwd %u"; + "invalid users" = [ "root" ]; + }; + "public" = { + "path" = "/srv/public"; + "read only" = "yes"; + "browseable" = "yes"; + "guest ok" = "yes"; + "comment" = "Public samba share."; + }; + }; + description = '' + Configuration file for the Samba suite in ini format. + This file is located in /etc/samba/smb.conf + + Refer to + for all available options. ''; }; - }; - }; - ###### implementation - config = mkMerge + config = lib.mkMerge [ { assertions = - [ { assertion = cfg.nsswins -> cfg.enableWinbindd; - message = "If samba.nsswins is enabled, then samba.enableWinbindd must also be enabled"; + [ { assertion = cfg.nsswins -> cfg.winbindd.enable; + message = "If services.samba.nsswins is enabled, then services.samba.winbindd.enable must also be enabled"; } ]; } - (mkIf cfg.enable { + (lib.mkIf cfg.enable { environment.etc."samba/smb.conf".source = configFile; - system.nssModules = optional cfg.nsswins samba; - system.nssDatabases.hosts = optional cfg.nsswins "wins"; + system.nssModules = lib.optional cfg.nsswins cfg.package; + system.nssDatabases.hosts = lib.optional cfg.nsswins "wins"; systemd = { + slices.system-samba = { + description = "Samba (SMB Networking Protocol) Slice"; + }; targets.samba = { description = "Samba Server"; after = [ "network.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; }; - - slices.system-samba = { - description = "Samba slice"; - }; - - # Refer to https://github.com/samba-team/samba/tree/master/packaging/systemd - # for correct use with systemd - services = { - samba-smbd = daemonService "smbd" ""; - samba-nmbd = mkIf cfg.enableNmbd (daemonService "nmbd" ""); - samba-winbindd = mkIf cfg.enableWinbindd (daemonService "winbindd" ""); - }; tmpfiles.rules = [ "d /var/lock/samba - - - - -" "d /var/log/samba - - - - -" @@ -239,10 +197,116 @@ in security.pam.services.samba = {}; environment.systemPackages = [ cfg.package ]; + # Like other mount* related commands that need the setuid bit, this is + # required too. + security.wrappers."mount.cifs" = { + program = "mount.cifs"; + source = "${lib.getBin pkgs.cifs-utils}/bin/mount.cifs"; + owner = "root"; + group = "root"; + setuid = true; + }; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 139 445 ]; - networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ 137 138 ]; + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 139 445 ]; + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 137 138 ]; + }) + + (lib.mkIf (cfg.enable && cfg.nmbd.enable) { + systemd.services.samba-nmbd = { + description = "Samba NMB Daemon"; + documentation = [ "man:nmbd(8)" "man:samba(7)" "man:smb.conf(5)" ]; + + after = [ + "network.target" + "network-online.target" + ]; + + partOf = [ "samba.target" ]; + wantedBy = [ "samba.target" ]; + wants = [ "network-online.target" ]; + + environment.LD_LIBRARY_PATH = config.system.nssModules.path; + + serviceConfig = { + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStart = "${cfg.package}/sbin/nmbd --foreground --no-process-group ${lib.escapeShellArgs cfg.nmbd.extraArgs}"; + LimitCORE = "infinity"; + PIDFile = "/run/samba/nmbd.pid"; + Slice = "system-samba.slice"; + Type = "notify"; + }; + + unitConfig.RequiresMountsFor = "/var/lib/samba"; + + restartTriggers = [ configFile ]; + }; + }) + + (lib.mkIf (cfg.enable && cfg.smbd.enable) { + systemd.services.samba-smbd = { + description = "Samba SMB Daemon"; + documentation = [ "man:smbd(8)" "man:samba(7)" "man:smb.conf(5)" ]; + + after = [ + "network.target" + "network-online.target" + ] ++ lib.optionals (cfg.nmbd.enable) [ + "samba-nmbd.service" + ] ++ lib.optionals (cfg.winbindd.enable) [ + "samba-winbindd.service" + ]; + + partOf = [ "samba.target" ]; + wantedBy = [ "samba.target" ]; + wants = [ "network-online.target" ]; + + environment.LD_LIBRARY_PATH = config.system.nssModules.path; + + serviceConfig = { + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStart = "${cfg.package}/sbin/smbd --foreground --no-process-group ${lib.escapeShellArgs cfg.smbd.extraArgs}"; + LimitCORE = "infinity"; + LimitNOFILE = 16384; + PIDFile = "/run/samba/smbd.pid"; + Slice = "system-samba.slice"; + Type = "notify"; + }; + + unitConfig.RequiresMountsFor = "/var/lib/samba"; + + restartTriggers = [ configFile ]; + }; + }) + + (lib.mkIf (cfg.enable && cfg.winbindd.enable) { + systemd.services.samba-winbindd = { + description = "Samba Winbind Daemon"; + documentation = [ "man:winbindd(8)" "man:samba(7)" "man:smb.conf(5)" ]; + + after = [ + "network.target" + ] ++ lib.optionals (cfg.nmbd.enable) [ + "samba-nmbd.service" + ]; + + partOf = [ "samba.target" ]; + wantedBy = [ "samba.target" ]; + + environment.LD_LIBRARY_PATH = config.system.nssModules.path; + + serviceConfig = { + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStart = "${cfg.package}/sbin/winbindd --foreground --no-process-group ${lib.escapeShellArgs cfg.winbindd.extraArgs}"; + LimitCORE = "infinity"; + PIDFile = "/run/samba/winbindd.pid"; + Slice = "system-samba.slice"; + Type = "notify"; + }; + + unitConfig.RequiresMountsFor = "/var/lib/samba"; + + restartTriggers = [ configFile ]; + }; }) ]; - } diff --git a/nixos/modules/services/network-filesystems/saunafs.nix b/nixos/modules/services/network-filesystems/saunafs.nix new file mode 100644 index 000000000000..5c3c513c06f7 --- /dev/null +++ b/nixos/modules/services/network-filesystems/saunafs.nix @@ -0,0 +1,287 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.saunafs; + + settingsFormat = + let + listSep = " "; + allowedTypes = with lib.types; [ + bool + int + float + str + ]; + valueToString = + val: + if lib.isList val then + lib.concatStringsSep listSep (map (x: valueToString x) val) + else if lib.isBool val then + (if val then "1" else "0") + else + toString val; + + in + { + type = + let + valueType = + lib.types.oneOf ( + [ + (lib.types.listOf valueType) + ] + ++ allowedTypes + ) + // { + description = "Flat key-value file"; + }; + in + lib.types.attrsOf valueType; + + generate = + name: value: + pkgs.writeText name ( + lib.concatStringsSep "\n" (lib.mapAttrsToList (key: val: "${key} = ${valueToString val}") value) + ); + }; + + initTool = pkgs.writeShellScriptBin "sfsmaster-init" '' + if [ ! -e ${cfg.master.settings.DATA_PATH}/metadata.sfs ]; then + cp --update=none ${pkgs.saunafs}/var/lib/saunafs/metadata.sfs.empty ${cfg.master.settings.DATA_PATH}/metadata.sfs + chmod +w ${cfg.master.settings.DATA_PATH}/metadata.sfs + fi + ''; + + # master config file + masterCfg = settingsFormat.generate "sfsmaster.cfg" cfg.master.settings; + + # metalogger config file + metaloggerCfg = settingsFormat.generate "sfsmetalogger.cfg" cfg.metalogger.settings; + + # chunkserver config file + chunkserverCfg = settingsFormat.generate "sfschunkserver.cfg" cfg.chunkserver.settings; + + # generic template for all daemons + systemdService = name: extraConfig: configFile: { + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ + "network.target" + "network-online.target" + ]; + + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.saunafs}/bin/sfs${name} -c ${configFile} start"; + ExecStop = "${pkgs.saunafs}/bin/sfs${name} -c ${configFile} stop"; + ExecReload = "${pkgs.saunafs}/bin/sfs${name} -c ${configFile} reload"; + } // extraConfig; + }; + +in +{ + ###### interface + + options = { + services.saunafs = { + masterHost = lib.mkOption { + type = lib.types.str; + default = null; + description = "IP or hostname name of master host."; + }; + + sfsUser = lib.mkOption { + type = lib.types.str; + default = "saunafs"; + description = "Run daemons as user."; + }; + + client.enable = lib.mkEnableOption "Saunafs client"; + + master = { + enable = lib.mkOption { + type = lib.types.bool; + description = '' + Enable Saunafs master daemon. + + You need to run `sfsmaster-init` on a freshly installed master server to + initialize the `DATA_PATH` directory. + ''; + default = false; + }; + + exports = lib.mkOption { + type = with lib.types; listOf str; + default = null; + description = "Paths to exports file (see {manpage}`sfsexports.cfg(5)`)."; + example = lib.literalExpression '' + [ "* / rw,alldirs,admin,maproot=0:0" ]; + ''; + }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + description = "Whether to automatically open the necessary ports in the firewall."; + default = false; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options.DATA_PATH = lib.mkOption { + type = lib.types.str; + default = "/var/lib/saunafs/master"; + description = "Data storage directory."; + }; + }; + + description = "Contents of config file ({manpage}`sfsmaster.cfg(5)`)."; + }; + }; + + metalogger = { + enable = lib.mkEnableOption "Saunafs metalogger daemon"; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options.DATA_PATH = lib.mkOption { + type = lib.types.str; + default = "/var/lib/saunafs/metalogger"; + description = "Data storage directory"; + }; + }; + + description = "Contents of metalogger config file (see {manpage}`sfsmetalogger.cfg(5)`)."; + }; + }; + + chunkserver = { + enable = lib.mkEnableOption "Saunafs chunkserver daemon"; + + openFirewall = lib.mkOption { + type = lib.types.bool; + description = "Whether to automatically open the necessary ports in the firewall."; + default = false; + }; + + hdds = lib.mkOption { + type = with lib.types; listOf str; + default = null; + + example = lib.literalExpression '' + [ "/mnt/hdd1" ]; + ''; + + description = '' + Mount points to be used by chunkserver for storage (see {manpage}`sfshdd.cfg(5)`). + + Note, that these mount points must writeable by the user defined by the saunafs user. + ''; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options.DATA_PATH = lib.mkOption { + type = lib.types.str; + default = "/var/lib/saunafs/chunkserver"; + description = "Directory for chunck meta data"; + }; + }; + + description = "Contents of chunkserver config file (see {manpage}`sfschunkserver.cfg(5)`)."; + }; + }; + }; + }; + + ###### implementation + + config = + lib.mkIf (cfg.client.enable || cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable) + { + + warnings = [ + (lib.mkIf (cfg.sfsUser == "root") "Running saunafs services as root is not recommended.") + ]; + + # Service settings + services.saunafs = { + master.settings = lib.mkIf cfg.master.enable { + WORKING_USER = cfg.sfsUser; + EXPORTS_FILENAME = toString ( + pkgs.writeText "sfsexports.cfg" (lib.concatStringsSep "\n" cfg.master.exports) + ); + }; + + metalogger.settings = lib.mkIf cfg.metalogger.enable { + WORKING_USER = cfg.sfsUser; + MASTER_HOST = cfg.masterHost; + }; + + chunkserver.settings = lib.mkIf cfg.chunkserver.enable { + WORKING_USER = cfg.sfsUser; + MASTER_HOST = cfg.masterHost; + HDD_CONF_FILENAME = toString ( + pkgs.writeText "sfshdd.cfg" (lib.concatStringsSep "\n" cfg.chunkserver.hdds) + ); + }; + }; + + # Create system user account for daemons + users = + lib.mkIf + (cfg.sfsUser != "root" && (cfg.master.enable || cfg.metalogger.enable || cfg.chunkserver.enable)) + { + users."${cfg.sfsUser}" = { + isSystemUser = true; + description = "saunafs daemon user"; + group = "saunafs"; + }; + groups."${cfg.sfsUser}" = { }; + }; + + environment.systemPackages = + (lib.optional cfg.client.enable pkgs.saunafs) ++ (lib.optional cfg.master.enable initTool); + + networking.firewall.allowedTCPPorts = + (lib.optionals cfg.master.openFirewall [ + 9419 + 9420 + 9421 + ]) + ++ (lib.optional cfg.chunkserver.openFirewall 9422); + + # Ensure storage directories exist + systemd.tmpfiles.rules = + lib.optional cfg.master.enable "d ${cfg.master.settings.DATA_PATH} 0700 ${cfg.sfsUser} ${cfg.sfsUser} -" + ++ lib.optional cfg.metalogger.enable "d ${cfg.metalogger.settings.DATA_PATH} 0700 ${cfg.sfsUser} ${cfg.sfsUser} -" + ++ lib.optional cfg.chunkserver.enable "d ${cfg.chunkserver.settings.DATA_PATH} 0700 ${cfg.sfsUser} ${cfg.sfsUser} -"; + + # Service definitions + systemd.services.sfs-master = lib.mkIf cfg.master.enable ( + systemdService "master" { + TimeoutStartSec = 1800; + TimeoutStopSec = 1800; + Restart = "no"; + } masterCfg + ); + + systemd.services.sfs-metalogger = lib.mkIf cfg.metalogger.enable ( + systemdService "metalogger" { Restart = "on-abort"; } metaloggerCfg + ); + + systemd.services.sfs-chunkserver = lib.mkIf cfg.chunkserver.enable ( + systemdService "chunkserver" { Restart = "on-abort"; } chunkserverCfg + ); + }; +} diff --git a/nixos/modules/services/network-filesystems/tahoe.nix b/nixos/modules/services/network-filesystems/tahoe.nix index cfda62020a1e..e3296e6f66d5 100644 --- a/nixos/modules/services/network-filesystems/tahoe.nix +++ b/nixos/modules/services/network-filesystems/tahoe.nix @@ -1,57 +1,55 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.tahoe; in { options.services.tahoe = { - introducers = mkOption { + introducers = lib.mkOption { default = {}; - type = with types; attrsOf (submodule { + type = with lib.types; attrsOf (submodule { options = { - nickname = mkOption { - type = types.str; + nickname = lib.mkOption { + type = lib.types.str; description = '' The nickname of this Tahoe introducer. ''; }; - tub.port = mkOption { + tub.port = lib.mkOption { default = 3458; - type = types.port; + type = lib.types.port; description = '' The port on which the introducer will listen. ''; }; - tub.location = mkOption { + tub.location = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The external location that the introducer should listen on. If specified, the port should be included. ''; }; - package = mkPackageOption pkgs "tahoelafs" { }; + package = lib.mkPackageOption pkgs "tahoelafs" { }; }; }); description = '' The Tahoe introducers. ''; }; - nodes = mkOption { + nodes = lib.mkOption { default = {}; - type = with types; attrsOf (submodule { + type = with lib.types; attrsOf (submodule { options = { - nickname = mkOption { - type = types.str; + nickname = lib.mkOption { + type = lib.types.str; description = '' The nickname of this Tahoe node. ''; }; - tub.port = mkOption { + tub.port = lib.mkOption { default = 3457; - type = types.port; + type = lib.types.port; description = '' The port on which the tub will listen. @@ -59,9 +57,9 @@ in system to listen on a different port. ''; }; - tub.location = mkOption { + tub.location = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The external location that the node should listen on. @@ -71,9 +69,9 @@ in If specified, the port should be included. ''; }; - web.port = mkOption { + web.port = lib.mkOption { default = 3456; - type = types.port; + type = lib.types.port; description = '' The port on which the Web server will listen. @@ -81,59 +79,59 @@ in listen on a different port. ''; }; - client.introducer = mkOption { + client.introducer = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The furl for a Tahoe introducer node. Like all furls, keep this safe and don't share it. ''; }; - client.helper = mkOption { + client.helper = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The furl for a Tahoe helper node. Like all furls, keep this safe and don't share it. ''; }; - client.shares.needed = mkOption { + client.shares.needed = lib.mkOption { default = 3; - type = types.int; + type = lib.types.int; description = '' The number of shares required to reconstitute a file. ''; }; - client.shares.happy = mkOption { + client.shares.happy = lib.mkOption { default = 7; - type = types.int; + type = lib.types.int; description = '' The number of distinct storage nodes required to store a file. ''; }; - client.shares.total = mkOption { + client.shares.total = lib.mkOption { default = 10; - type = types.int; + type = lib.types.int; description = '' The number of shares required to store a file. ''; }; - storage.enable = mkEnableOption "storage service"; - storage.reservedSpace = mkOption { + storage.enable = lib.mkEnableOption "storage service"; + storage.reservedSpace = lib.mkOption { default = "1G"; - type = types.str; + type = lib.types.str; description = '' The amount of filesystem space to not use for storage. ''; }; - helper.enable = mkEnableOption "helper service"; - sftpd.enable = mkEnableOption "SFTP service"; - sftpd.port = mkOption { + helper.enable = lib.mkEnableOption "helper service"; + sftpd.enable = lib.mkEnableOption "SFTP service"; + sftpd.port = lib.mkOption { default = null; - type = types.nullOr types.int; + type = lib.types.nullOr lib.types.int; description = '' The port on which the SFTP server will listen. @@ -141,35 +139,35 @@ in daemon to listen on a different port. ''; }; - sftpd.hostPublicKeyFile = mkOption { + sftpd.hostPublicKeyFile = lib.mkOption { default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; description = '' Path to the SSH host public key. ''; }; - sftpd.hostPrivateKeyFile = mkOption { + sftpd.hostPrivateKeyFile = lib.mkOption { default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; description = '' Path to the SSH host private key. ''; }; - sftpd.accounts.file = mkOption { + sftpd.accounts.file = lib.mkOption { default = null; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; description = '' Path to the accounts file. ''; }; - sftpd.accounts.url = mkOption { + sftpd.accounts.url = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' URL of the accounts server. ''; }; - package = mkPackageOption pkgs "tahoelafs" { }; + package = lib.mkPackageOption pkgs "tahoelafs" { }; }; }); description = '' @@ -177,11 +175,11 @@ in ''; }; }; - config = mkMerge [ - (mkIf (cfg.introducers != {}) { + config = lib.mkMerge [ + (lib.mkIf (cfg.introducers != {}) { environment = { - etc = flip mapAttrs' cfg.introducers (node: settings: - nameValuePair "tahoe-lafs/introducer-${node}.cfg" { + etc = lib.flip lib.mapAttrs' cfg.introducers (node: settings: + lib.nameValuePair "tahoe-lafs/introducer-${node}.cfg" { mode = "0444"; text = '' # This configuration is generated by Nix. Edit at your own @@ -190,25 +188,25 @@ in [node] nickname = ${settings.nickname} tub.port = ${toString settings.tub.port} - ${optionalString (settings.tub.location != null) + ${lib.optionalString (settings.tub.location != null) "tub.location = ${settings.tub.location}"} ''; }); # Actually require Tahoe, so that we will have it installed. - systemPackages = flip mapAttrsToList cfg.introducers (node: settings: + systemPackages = lib.flip lib.mapAttrsToList cfg.introducers (node: settings: settings.package ); }; # Open up the firewall. - # networking.firewall.allowedTCPPorts = flip mapAttrsToList cfg.introducers + # networking.firewall.allowedTCPPorts = lib.flip lib.mapAttrsToList cfg.introducers # (node: settings: settings.tub.port); - systemd.services = flip mapAttrs' cfg.introducers (node: settings: + systemd.services = lib.flip lib.mapAttrs' cfg.introducers (node: settings: let pidfile = "/run/tahoe.introducer-${node}.pid"; # This is a directory, but it has no trailing slash. Tahoe commands # get antsy when there's a trailing slash. nodedir = "/var/db/tahoe-lafs/introducer-${node}"; - in nameValuePair "tahoe.introducer-${node}" { + in lib.nameValuePair "tahoe.introducer-${node}" { description = "Tahoe LAFS node ${node}"; wantedBy = [ "multi-user.target" ]; path = [ settings.package ]; @@ -242,16 +240,16 @@ in cp /etc/tahoe-lafs/introducer-"${node}".cfg ${lib.escapeShellArg nodedir}/tahoe.cfg ''; }); - users.users = flip mapAttrs' cfg.introducers (node: _: - nameValuePair "tahoe.introducer-${node}" { + users.users = lib.flip lib.mapAttrs' cfg.introducers (node: _: + lib.nameValuePair "tahoe.introducer-${node}" { description = "Tahoe node user for introducer ${node}"; isSystemUser = true; }); }) - (mkIf (cfg.nodes != {}) { + (lib.mkIf (cfg.nodes != {}) { environment = { - etc = flip mapAttrs' cfg.nodes (node: settings: - nameValuePair "tahoe-lafs/${node}.cfg" { + etc = lib.flip lib.mapAttrs' cfg.nodes (node: settings: + lib.nameValuePair "tahoe-lafs/${node}.cfg" { mode = "0444"; text = '' # This configuration is generated by Nix. Edit at your own @@ -260,16 +258,16 @@ in [node] nickname = ${settings.nickname} tub.port = ${toString settings.tub.port} - ${optionalString (settings.tub.location != null) + ${lib.optionalString (settings.tub.location != null) "tub.location = ${settings.tub.location}"} # This is a Twisted endpoint. Twisted Web doesn't work on # non-TCP. ~ C. web.port = tcp:${toString settings.web.port} [client] - ${optionalString (settings.client.introducer != null) + ${lib.optionalString (settings.client.introducer != null) "introducer.furl = ${settings.client.introducer}"} - ${optionalString (settings.client.helper != null) + ${lib.optionalString (settings.client.helper != null) "helper.furl = ${settings.client.helper}"} shares.needed = ${toString settings.client.shares.needed} @@ -277,41 +275,41 @@ in shares.total = ${toString settings.client.shares.total} [storage] - enabled = ${boolToString settings.storage.enable} + enabled = ${lib.boolToString settings.storage.enable} reserved_space = ${settings.storage.reservedSpace} [helper] - enabled = ${boolToString settings.helper.enable} + enabled = ${lib.boolToString settings.helper.enable} [sftpd] - enabled = ${boolToString settings.sftpd.enable} - ${optionalString (settings.sftpd.port != null) + enabled = ${lib.boolToString settings.sftpd.enable} + ${lib.optionalString (settings.sftpd.port != null) "port = ${toString settings.sftpd.port}"} - ${optionalString (settings.sftpd.hostPublicKeyFile != null) + ${lib.optionalString (settings.sftpd.hostPublicKeyFile != null) "host_pubkey_file = ${settings.sftpd.hostPublicKeyFile}"} - ${optionalString (settings.sftpd.hostPrivateKeyFile != null) + ${lib.optionalString (settings.sftpd.hostPrivateKeyFile != null) "host_privkey_file = ${settings.sftpd.hostPrivateKeyFile}"} - ${optionalString (settings.sftpd.accounts.file != null) + ${lib.optionalString (settings.sftpd.accounts.file != null) "accounts.file = ${settings.sftpd.accounts.file}"} - ${optionalString (settings.sftpd.accounts.url != null) + ${lib.optionalString (settings.sftpd.accounts.url != null) "accounts.url = ${settings.sftpd.accounts.url}"} ''; }); # Actually require Tahoe, so that we will have it installed. - systemPackages = flip mapAttrsToList cfg.nodes (node: settings: + systemPackages = lib.flip lib.mapAttrsToList cfg.nodes (node: settings: settings.package ); }; # Open up the firewall. - # networking.firewall.allowedTCPPorts = flip mapAttrsToList cfg.nodes + # networking.firewall.allowedTCPPorts = lib.flip lib.mapAttrsToList cfg.nodes # (node: settings: settings.tub.port); - systemd.services = flip mapAttrs' cfg.nodes (node: settings: + systemd.services = lib.flip lib.mapAttrs' cfg.nodes (node: settings: let pidfile = "/run/tahoe.${node}.pid"; # This is a directory, but it has no trailing slash. Tahoe commands # get antsy when there's a trailing slash. nodedir = "/var/db/tahoe-lafs/${node}"; - in nameValuePair "tahoe.${node}" { + in lib.nameValuePair "tahoe.${node}" { description = "Tahoe LAFS node ${node}"; wantedBy = [ "multi-user.target" ]; path = [ settings.package ]; @@ -342,8 +340,8 @@ in cp /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${lib.escapeShellArg nodedir}/tahoe.cfg ''; }); - users.users = flip mapAttrs' cfg.nodes (node: _: - nameValuePair "tahoe.${node}" { + users.users = lib.flip lib.mapAttrs' cfg.nodes (node: _: + lib.nameValuePair "tahoe.${node}" { description = "Tahoe node user for node ${node}"; isSystemUser = true; }); diff --git a/nixos/modules/services/network-filesystems/u9fs.nix b/nixos/modules/services/network-filesystems/u9fs.nix index 2233d6f2a60d..346705f5e3d0 100644 --- a/nixos/modules/services/network-filesystems/u9fs.nix +++ b/nixos/modules/services/network-filesystems/u9fs.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.u9fs; in @@ -11,14 +8,14 @@ in services.u9fs = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to run the u9fs 9P server for Unix."; }; - listenStreams = mkOption { - type = types.listOf types.str; + listenStreams = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "564" ]; example = [ "192.168.16.1:564" ]; description = '' @@ -27,14 +24,14 @@ in ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "nobody"; description = "User to run u9fs under."; }; - extraArgs = mkOption { - type = types.str; + extraArgs = lib.mkOption { + type = lib.types.str; default = ""; example = "-a none"; description = '' @@ -47,7 +44,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd = { sockets.u9fs = { diff --git a/nixos/modules/services/network-filesystems/webdav-server-rs.nix b/nixos/modules/services/network-filesystems/webdav-server-rs.nix index 7e83d78db5b0..31f641a82d79 100644 --- a/nixos/modules/services/network-filesystems/webdav-server-rs.nix +++ b/nixos/modules/services/network-filesystems/webdav-server-rs.nix @@ -1,10 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.webdav-server-rs; format = pkgs.formats.toml { }; - settings = recursiveUpdate + settings = lib.recursiveUpdate { server.uid = config.users.users."${cfg.user}".uid; server.gid = config.users.groups."${cfg.group}".gid; @@ -14,27 +12,27 @@ in { options = { services.webdav-server-rs = { - enable = mkEnableOption "WebDAV server"; + enable = lib.mkEnableOption "WebDAV server"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "webdav"; description = "User to run under when setuid is not enabled."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "webdav"; description = "Group to run under when setuid is not enabled."; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable debug mode."; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; description = '' @@ -42,7 +40,7 @@ in options can be found at [here](https://github.com/miquels/webdav-server-rs/blob/master/webdav-server.toml). ''; - example = literalExpression '' + example = lib.literalExpression '' { server.listen = [ "0.0.0.0:4918" "[::]:4918" ]; accounts = { @@ -75,8 +73,8 @@ in ''; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = format.generate "webdav-server.toml" settings; defaultText = "Config file generated from services.webdav-server-rs.settings"; description = '' @@ -88,19 +86,19 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { - assertion = hasAttr cfg.user config.users.users && config.users.users."${cfg.user}".uid != null; + assertion = lib.hasAttr cfg.user config.users.users && config.users.users."${cfg.user}".uid != null; message = "users.users.${cfg.user} and users.users.${cfg.user}.uid must be defined."; } { - assertion = hasAttr cfg.group config.users.groups && config.users.groups."${cfg.group}".gid != null; + assertion = lib.hasAttr cfg.group config.users.groups && config.users.groups."${cfg.group}".gid != null; message = "users.groups.${cfg.group} and users.groups.${cfg.group}.gid must be defined."; } ]; - users.users = optionalAttrs (cfg.user == "webdav") { + users.users = lib.optionalAttrs (cfg.user == "webdav") { webdav = { description = "WebDAV user"; group = cfg.group; @@ -108,7 +106,7 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "webdav") { + users.groups = lib.optionalAttrs (cfg.group == "webdav") { webdav.gid = config.ids.gids.webdav; }; @@ -146,5 +144,5 @@ in }; }; - meta.maintainers = with maintainers; [ pmy ]; + meta.maintainers = with lib.maintainers; [ pmy ]; } diff --git a/nixos/modules/services/network-filesystems/webdav.nix b/nixos/modules/services/network-filesystems/webdav.nix index 7e435fc65253..28f129fc12d2 100644 --- a/nixos/modules/services/network-filesystems/webdav.nix +++ b/nixos/modules/services/network-filesystems/webdav.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.webdav; format = pkgs.formats.yaml { }; @@ -8,21 +6,21 @@ in { options = { services.webdav = { - enable = mkEnableOption "WebDAV server"; + enable = lib.mkEnableOption "WebDAV server"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "webdav"; description = "User account under which WebDAV runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "webdav"; description = "Group under which WebDAV runs."; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; description = '' @@ -36,7 +34,7 @@ in [EnvironmentFile](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#EnvironmentFile=). This prevents adding secrets to the world-readable Nix store. ''; - example = literalExpression '' + example = lib.literalExpression '' { address = "0.0.0.0"; port = 8080; @@ -53,8 +51,8 @@ in ''; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = format.generate "webdav.yaml" cfg.settings; defaultText = "Config file generated from services.webdav.settings"; description = '' @@ -64,8 +62,8 @@ in example = "/etc/webdav/config.yaml"; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Environment file as defined in {manpage}`systemd.exec(5)`. @@ -74,8 +72,8 @@ in }; }; - config = mkIf cfg.enable { - users.users = mkIf (cfg.user == "webdav") { + config = lib.mkIf cfg.enable { + users.users = lib.mkIf (cfg.user == "webdav") { webdav = { description = "WebDAV daemon user"; group = cfg.group; @@ -83,7 +81,7 @@ in }; }; - users.groups = mkIf (cfg.group == "webdav") { + users.groups = lib.mkIf (cfg.group == "webdav") { webdav.gid = config.ids.gids.webdav; }; @@ -96,10 +94,10 @@ in Restart = "on-failure"; User = cfg.user; Group = cfg.group; - EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; }; }; }; - meta.maintainers = with maintainers; [ pmy ]; + meta.maintainers = with lib.maintainers; [ pmy ]; } diff --git a/nixos/modules/services/network-filesystems/xtreemfs.nix b/nixos/modules/services/network-filesystems/xtreemfs.nix index 78a0272c0567..e2cde1903edd 100644 --- a/nixos/modules/services/network-filesystems/xtreemfs.nix +++ b/nixos/modules/services/network-filesystems/xtreemfs.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.xtreemfs; @@ -29,13 +26,13 @@ let dirConfig = pkgs.writeText "xtreemfs-dir-config.properties" '' uuid = ${cfg.dir.uuid} listen.port = ${toString cfg.dir.port} - ${optionalString (cfg.dir.address != "") "listen.address = ${cfg.dir.address}"} + ${lib.optionalString (cfg.dir.address != "") "listen.address = ${cfg.dir.address}"} http_port = ${toString cfg.dir.httpPort} babudb.baseDir = ${home}/dir/database babudb.logDir = ${home}/dir/db-log babudb.sync = ${if cfg.dir.replication.enable then "FDATASYNC" else cfg.dir.syncMode} - ${optionalString cfg.dir.replication.enable "babudb.plugin.0 = ${dirReplicationConfig}"} + ${lib.optionalString cfg.dir.replication.enable "babudb.plugin.0 = ${dirReplicationConfig}"} ${cfg.dir.extraConfig} ''; @@ -51,13 +48,13 @@ let mrcConfig = pkgs.writeText "xtreemfs-mrc-config.properties" '' uuid = ${cfg.mrc.uuid} listen.port = ${toString cfg.mrc.port} - ${optionalString (cfg.mrc.address != "") "listen.address = ${cfg.mrc.address}"} + ${lib.optionalString (cfg.mrc.address != "") "listen.address = ${cfg.mrc.address}"} http_port = ${toString cfg.mrc.httpPort} babudb.baseDir = ${home}/mrc/database babudb.logDir = ${home}/mrc/db-log babudb.sync = ${if cfg.mrc.replication.enable then "FDATASYNC" else cfg.mrc.syncMode} - ${optionalString cfg.mrc.replication.enable "babudb.plugin.0 = ${mrcReplicationConfig}"} + ${lib.optionalString cfg.mrc.replication.enable "babudb.plugin.0 = ${mrcReplicationConfig}"} ${cfg.mrc.extraConfig} ''; @@ -65,14 +62,14 @@ let osdConfig = pkgs.writeText "xtreemfs-osd-config.properties" '' uuid = ${cfg.osd.uuid} listen.port = ${toString cfg.osd.port} - ${optionalString (cfg.osd.address != "") "listen.address = ${cfg.osd.address}"} + ${lib.optionalString (cfg.osd.address != "") "listen.address = ${cfg.osd.address}"} http_port = ${toString cfg.osd.httpPort} object_dir = ${home}/osd/ ${cfg.osd.extraConfig} ''; - optionalDir = optionals cfg.dir.enable ["xtreemfs-dir.service"]; + optionalDir = lib.optionals cfg.dir.enable ["xtreemfs-dir.service"]; systemdOptionalDependencies = { after = [ "network.target" ] ++ optionalDir; @@ -89,10 +86,10 @@ in services.xtreemfs = { - enable = mkEnableOption "XtreemFS"; + enable = lib.mkEnableOption "XtreemFS"; - homeDir = mkOption { - type = types.path; + homeDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/xtreemfs"; description = '' XtreemFS home dir for the xtreemfs user. @@ -100,32 +97,32 @@ in }; dir = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable XtreemFS DIR service. ''; }; - uuid = mkOption { + uuid = lib.mkOption { example = "eacb6bab-f444-4ebf-a06a-3f72d7465e40"; - type = types.str; + type = lib.types.str; description = '' Must be set to a unique identifier, preferably a UUID according to RFC 4122. UUIDs can be generated with `uuidgen` command, found in the `util-linux` package. ''; }; - port = mkOption { + port = lib.mkOption { default = 32638; - type = types.port; + type = lib.types.port; description = '' The port to listen on for incoming connections (TCP). ''; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; example = "127.0.0.1"; default = ""; description = '' @@ -133,16 +130,16 @@ in specified, the service will listen on all interfaces (any). ''; }; - httpPort = mkOption { + httpPort = lib.mkOption { default = 30638; - type = types.port; + type = lib.types.port; description = '' Specifies the listen port for the HTTP service that returns the status page. ''; }; - syncMode = mkOption { - type = types.enum [ "ASYNC" "SYNC_WRITE_METADATA" "SYNC_WRITE" "FDATASYNC" "FSYNC" ]; + syncMode = lib.mkOption { + type = lib.types.enum [ "ASYNC" "SYNC_WRITE_METADATA" "SYNC_WRITE" "FDATASYNC" "FSYNC" ]; default = "FSYNC"; example = "FDATASYNC"; description = '' @@ -160,8 +157,8 @@ in (If xtreemfs.dir.replication.enable is true then FDATASYNC is forced) ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; example = '' # specify whether SSL is required @@ -180,9 +177,9 @@ in ''; }; replication = { - enable = mkEnableOption "XtreemFS DIR replication plugin"; - extraConfig = mkOption { - type = types.lines; + enable = lib.mkEnableOption "XtreemFS DIR replication plugin"; + extraConfig = lib.mkOption { + type = lib.types.lines; example = '' # participants of the replication including this replica babudb.repl.participant.0 = 192.168.0.10 @@ -225,50 +222,50 @@ in }; mrc = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable XtreemFS MRC service. ''; }; - uuid = mkOption { + uuid = lib.mkOption { example = "eacb6bab-f444-4ebf-a06a-3f72d7465e41"; - type = types.str; + type = lib.types.str; description = '' Must be set to a unique identifier, preferably a UUID according to RFC 4122. UUIDs can be generated with `uuidgen` command, found in the `util-linux` package. ''; }; - port = mkOption { + port = lib.mkOption { default = 32636; - type = types.port; + type = lib.types.port; description = '' The port to listen on for incoming connections (TCP). ''; }; - address = mkOption { + address = lib.mkOption { example = "127.0.0.1"; - type = types.str; + type = lib.types.str; default = ""; description = '' If specified, it defines the interface to listen on. If not specified, the service will listen on all interfaces (any). ''; }; - httpPort = mkOption { + httpPort = lib.mkOption { default = 30636; - type = types.port; + type = lib.types.port; description = '' Specifies the listen port for the HTTP service that returns the status page. ''; }; - syncMode = mkOption { + syncMode = lib.mkOption { default = "FSYNC"; - type = types.enum [ "ASYNC" "SYNC_WRITE_METADATA" "SYNC_WRITE" "FDATASYNC" "FSYNC" ]; + type = lib.types.enum [ "ASYNC" "SYNC_WRITE_METADATA" "SYNC_WRITE" "FDATASYNC" "FSYNC" ]; example = "FDATASYNC"; description = '' The sync mode influences how operations are committed to the disk @@ -285,8 +282,8 @@ in (If xtreemfs.mrc.replication.enable is true then FDATASYNC is forced) ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; example = '' osd_check_interval = 300 no_atime = true @@ -323,9 +320,9 @@ in ''; }; replication = { - enable = mkEnableOption "XtreemFS MRC replication plugin"; - extraConfig = mkOption { - type = types.lines; + enable = lib.mkEnableOption "XtreemFS MRC replication plugin"; + extraConfig = lib.mkOption { + type = lib.types.lines; example = '' # participants of the replication including this replica babudb.repl.participant.0 = 192.168.0.10 @@ -368,49 +365,49 @@ in }; osd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable XtreemFS OSD service. ''; }; - uuid = mkOption { + uuid = lib.mkOption { example = "eacb6bab-f444-4ebf-a06a-3f72d7465e42"; - type = types.str; + type = lib.types.str; description = '' Must be set to a unique identifier, preferably a UUID according to RFC 4122. UUIDs can be generated with `uuidgen` command, found in the `util-linux` package. ''; }; - port = mkOption { + port = lib.mkOption { default = 32640; - type = types.port; + type = lib.types.port; description = '' The port to listen on for incoming connections (TCP and UDP). ''; }; - address = mkOption { + address = lib.mkOption { example = "127.0.0.1"; - type = types.str; + type = lib.types.str; default = ""; description = '' If specified, it defines the interface to listen on. If not specified, the service will listen on all interfaces (any). ''; }; - httpPort = mkOption { + httpPort = lib.mkOption { default = 30640; - type = types.port; + type = lib.types.port; description = '' Specifies the listen port for the HTTP service that returns the status page. ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; example = '' local_clock_renewal = 0 remote_time_sync = 30000 @@ -464,7 +461,7 @@ in { gid = config.ids.gids.xtreemfs; }; - systemd.services.xtreemfs-dir = mkIf cfg.dir.enable { + systemd.services.xtreemfs-dir = lib.mkIf cfg.dir.enable { description = "XtreemFS-DIR Server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; @@ -474,7 +471,7 @@ in }; }; - systemd.services.xtreemfs-mrc = mkIf cfg.mrc.enable ({ + systemd.services.xtreemfs-mrc = lib.mkIf cfg.mrc.enable ({ description = "XtreemFS-MRC Server"; serviceConfig = { User = "xtreemfs"; @@ -482,7 +479,7 @@ in }; } // systemdOptionalDependencies); - systemd.services.xtreemfs-osd = mkIf cfg.osd.enable ({ + systemd.services.xtreemfs-osd = lib.mkIf cfg.osd.enable ({ description = "XtreemFS-OSD Server"; serviceConfig = { User = "xtreemfs"; diff --git a/nixos/modules/services/network-filesystems/yandex-disk.nix b/nixos/modules/services/network-filesystems/yandex-disk.nix index de5d42a4bcde..ee9b58b081a3 100644 --- a/nixos/modules/services/network-filesystems/yandex-disk.nix +++ b/nixos/modules/services/network-filesystems/yandex-disk.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.yandex-disk; @@ -20,47 +17,47 @@ in services.yandex-disk = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable Yandex-disk client. See https://disk.yandex.ru/ ''; }; - username = mkOption { + username = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Your yandex.com login name. ''; }; - password = mkOption { + password = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Your yandex.com password. Warning: it will be world-readable in /nix/store. ''; }; - user = mkOption { + user = lib.mkOption { default = null; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; description = '' The user the yandex-disk daemon should run as. ''; }; - directory = mkOption { - type = types.path; + directory = lib.mkOption { + type = lib.types.path; default = "/home/Yandex.Disk"; description = "The directory to use for Yandex.Disk storage"; }; - excludes = mkOption { + excludes = lib.mkOption { default = ""; - type = types.commas; + type = lib.types.commas; example = "data,backup"; description = '' Comma-separated list of directories which are excluded from synchronization. @@ -74,9 +71,9 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = mkIf (cfg.user == null) [ { + users.users = lib.mkIf (cfg.user == null) [ { name = u; uid = config.ids.uids.yandexdisk; group = "nogroup"; diff --git a/nixos/modules/services/networking/3proxy.nix b/nixos/modules/services/networking/3proxy.nix index 865916f7aff5..03c67ed2f6f8 100644 --- a/nixos/modules/services/networking/3proxy.nix +++ b/nixos/modules/services/networking/3proxy.nix @@ -1,21 +1,20 @@ { config, lib, pkgs, ... }: -with lib; let pkg = pkgs._3proxy; cfg = config.services._3proxy; - optionalList = list: if list == [ ] then "*" else concatMapStringsSep "," toString list; + optionalList = list: if list == [ ] then "*" else lib.concatMapStringsSep "," toString list; in { options.services._3proxy = { - enable = mkEnableOption "3proxy"; - confFile = mkOption { - type = types.path; + enable = lib.mkEnableOption "3proxy"; + confFile = lib.mkOption { + type = lib.types.path; example = "/var/lib/3proxy/3proxy.conf"; description = '' Ignore all other 3proxy options and load configuration from this file. ''; }; - usersFile = mkOption { - type = types.nullOr types.path; + usersFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/var/lib/3proxy/3proxy.passwd"; description = '' @@ -40,11 +39,11 @@ in { Consult [documentation](https://github.com/z3APA3A/3proxy/wiki/How-To-%28incomplete%29#USERS) for more information. ''; }; - services = mkOption { - type = types.listOf (types.submodule { + services = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - type = mkOption { - type = types.enum [ + type = lib.mkOption { + type = lib.types.enum [ "proxy" "socks" "pop3p" @@ -68,32 +67,32 @@ in { - `"udppm"`: UDP portmapper. ''; }; - bindAddress = mkOption { - type = types.str; + bindAddress = lib.mkOption { + type = lib.types.str; default = "[::]"; example = "127.0.0.1"; description = '' Address used for service. ''; }; - bindPort = mkOption { - type = types.nullOr types.int; + bindPort = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; example = 3128; description = '' Override default port used for service. ''; }; - maxConnections = mkOption { - type = types.int; + maxConnections = lib.mkOption { + type = lib.types.int; default = 100; example = 1000; description = '' Maximum number of simulationeous connections to this service. ''; }; - auth = mkOption { - type = types.listOf (types.enum [ "none" "iponly" "strong" ]); + auth = lib.mkOption { + type = lib.types.listOf (lib.types.enum [ "none" "iponly" "strong" ]); example = [ "iponly" "strong" ]; description = '' Authentication type. The following values are valid: @@ -122,11 +121,11 @@ in { In this example strong username authentication is not required to access 192.168.0.0/16. ''; }; - acl = mkOption { - type = types.listOf (types.submodule { + acl = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - rule = mkOption { - type = types.enum [ "allow" "deny" ]; + rule = lib.mkOption { + type = lib.types.enum [ "allow" "deny" ]; example = "allow"; description = '' ACL rule. The following values are valid: @@ -135,24 +134,24 @@ in { - `"deny"`: connections not allowed. ''; }; - users = mkOption { - type = types.listOf types.str; + users = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "user1" "user2" "user3" ]; description = '' List of users, use empty list for any. ''; }; - sources = mkOption { - type = types.listOf types.str; + sources = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "127.0.0.1" "192.168.1.0/24" ]; description = '' List of source IP range, use empty list for any. ''; }; - targets = mkOption { - type = types.listOf types.str; + targets = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "127.0.0.1" "192.168.1.0/24" ]; description = '' @@ -162,8 +161,8 @@ in { Hostname is only checked if hostname presents in request. ''; }; - targetPorts = mkOption { - type = types.listOf types.int; + targetPorts = lib.mkOption { + type = lib.types.listOf lib.types.int; default = [ ]; example = [ 80 443 ]; description = '' @@ -173,7 +172,7 @@ in { }; }); default = [ ]; - example = literalExpression '' + example = lib.literalExpression '' [ { rule = "allow"; @@ -192,8 +191,8 @@ in { Use this option to limit user access to resources. ''; }; - extraArguments = mkOption { - type = types.nullOr types.str; + extraArguments = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "-46"; description = '' @@ -201,8 +200,8 @@ in { Consult "Options" section in [documentation](https://github.com/z3APA3A/3proxy/wiki/3proxy.cfg) for available arguments. ''; }; - extraConfig = mkOption { - type = types.nullOr types.lines; + extraConfig = lib.mkOption { + type = lib.types.nullOr lib.types.lines; default = null; description = '' Extra configuration for service. Use this to configure things like bandwidth limiter or ACL-based redirection. @@ -212,7 +211,7 @@ in { }; }); default = [ ]; - example = literalExpression '' + example = lib.literalExpression '' [ { type = "proxy"; @@ -238,15 +237,15 @@ in { Use this option to define 3proxy services. ''; }; - denyPrivate = mkOption { - type = types.bool; + denyPrivate = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to deny access to private IP ranges including loopback. ''; }; - privateRanges = mkOption { - type = types.listOf types.str; + privateRanges = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "0.0.0.0/8" "127.0.0.0/8" @@ -262,11 +261,11 @@ in { What IP ranges to deny access when denyPrivate is set tu true. ''; }; - resolution = mkOption { - type = types.submodule { + resolution = lib.mkOption { + type = lib.types.submodule { options = { - nserver = mkOption { - type = types.listOf types.str; + nserver = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "127.0.0.53" "192.168.1.3:5353/tcp" ]; description = '' @@ -276,20 +275,20 @@ in { default system name resolution functions are used. ''; }; - nscache = mkOption { - type = types.int; + nscache = lib.mkOption { + type = lib.types.int; default = 65535; description = "Set name cache size for IPv4."; }; - nscache6 = mkOption { - type = types.int; + nscache6 = lib.mkOption { + type = lib.types.int; default = 65535; description = "Set name cache size for IPv6."; }; - nsrecord = mkOption { - type = types.attrsOf types.str; + nsrecord = lib.mkOption { + type = lib.types.attrsOf lib.types.str; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "files.local" = "192.168.1.12"; "site.local" = "192.168.1.43"; @@ -304,8 +303,8 @@ in { Use this option to configure name resolution and DNS caching. ''; }; - extraConfig = mkOption { - type = types.nullOr types.lines; + extraConfig = lib.mkOption { + type = lib.types.nullOr lib.types.lines; default = null; description = '' Extra configuration, appended to the 3proxy configuration file. @@ -314,33 +313,33 @@ in { }; }; - config = mkIf cfg.enable { - services._3proxy.confFile = mkDefault (pkgs.writeText "3proxy.conf" '' + config = lib.mkIf cfg.enable { + services._3proxy.confFile = lib.mkDefault (pkgs.writeText "3proxy.conf" '' # log to stdout log - ${concatMapStringsSep "\n" (x: "nserver " + x) cfg.resolution.nserver} + ${lib.concatMapStringsSep "\n" (x: "nserver " + x) cfg.resolution.nserver} nscache ${toString cfg.resolution.nscache} nscache6 ${toString cfg.resolution.nscache6} - ${concatMapStringsSep "\n" (x: "nsrecord " + x) - (mapAttrsToList (name: value: "${name} ${value}") + ${lib.concatMapStringsSep "\n" (x: "nsrecord " + x) + (lib.mapAttrsToList (name: value: "${name} ${value}") cfg.resolution.nsrecord)} - ${optionalString (cfg.usersFile != null) + ${lib.optionalString (cfg.usersFile != null) ''users $"${cfg.usersFile}"'' } - ${concatMapStringsSep "\n" (service: '' - auth ${concatStringsSep " " service.auth} + ${lib.concatMapStringsSep "\n" (service: '' + auth ${lib.concatStringsSep " " service.auth} - ${optionalString (cfg.denyPrivate) + ${lib.optionalString (cfg.denyPrivate) "deny * * ${optionalList cfg.privateRanges}"} - ${concatMapStringsSep "\n" (acl: + ${lib.concatMapStringsSep "\n" (acl: "${acl.rule} ${ - concatMapStringsSep " " optionalList [ + lib.concatMapStringsSep " " optionalList [ acl.users acl.sources acl.targets @@ -350,18 +349,18 @@ in { maxconn ${toString service.maxConnections} - ${optionalString (service.extraConfig != null) service.extraConfig} + ${lib.optionalString (service.extraConfig != null) service.extraConfig} ${service.type} -i${toString service.bindAddress} ${ - optionalString (service.bindPort != null) + lib.optionalString (service.bindPort != null) "-p${toString service.bindPort}" } ${ - optionalString (service.extraArguments != null) service.extraArguments + lib.optionalString (service.extraArguments != null) service.extraArguments } flush '') cfg.services} - ${optionalString (cfg.extraConfig != null) cfg.extraConfig} + ${lib.optionalString (cfg.extraConfig != null) cfg.extraConfig} ''); systemd.services."3proxy" = { description = "Tiny free proxy server"; @@ -377,5 +376,5 @@ in { }; }; - meta.maintainers = with maintainers; [ misuzu ]; + meta.maintainers = with lib.maintainers; [ misuzu ]; } diff --git a/nixos/modules/services/networking/adguardhome.nix b/nixos/modules/services/networking/adguardhome.nix index 5be3e0bea224..dab81ce18b29 100644 --- a/nixos/modules/services/networking/adguardhome.nix +++ b/nixos/modules/services/networking/adguardhome.nix @@ -1,12 +1,9 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.adguardhome; settingsFormat = pkgs.formats.yaml { }; - args = concatStringsSep " " ([ + args = lib.concatStringsSep " " ([ "--no-check-update" "--pidfile /run/AdGuardHome/AdGuardHome.pid" "--work-dir /var/lib/AdGuardHome/" @@ -28,19 +25,19 @@ let checkPhase = "${cfg.package}/bin/adguardhome -c $out --check-config"; }); in { - options.services.adguardhome = with types; { - enable = mkEnableOption "AdGuard Home network-wide ad blocker"; + options.services.adguardhome = with lib.types; { + enable = lib.mkEnableOption "AdGuard Home network-wide ad blocker"; - package = mkOption { + package = lib.mkOption { type = package; default = pkgs.adguardhome; - defaultText = literalExpression "pkgs.adguardhome"; + defaultText = lib.literalExpression "pkgs.adguardhome"; description = '' The package that runs adguardhome. ''; }; - openFirewall = mkOption { + openFirewall = lib.mkOption { default = false; type = bool; description = '' @@ -49,9 +46,9 @@ in { ''; }; - allowDHCP = mkOption { + allowDHCP = lib.mkOption { default = settings.dhcp.enabled or false; - defaultText = literalExpression "config.services.adguardhome.settings.dhcp.enabled or false"; + defaultText = lib.literalExpression "config.services.adguardhome.settings.dhcp.enabled or false"; type = bool; description = '' Allows AdGuard Home to open raw sockets (`CAP_NET_RAW`), which is @@ -63,7 +60,7 @@ in { ''; }; - mutableSettings = mkOption { + mutableSettings = lib.mkOption { default = true; type = bool; description = '' @@ -72,7 +69,7 @@ in { ''; }; - host = mkOption { + host = lib.mkOption { default = "0.0.0.0"; type = str; description = '' @@ -80,7 +77,7 @@ in { ''; }; - port = mkOption { + port = lib.mkOption { default = 3000; type = port; description = '' @@ -88,14 +85,14 @@ in { ''; }; - settings = mkOption { + settings = lib.mkOption { default = null; type = nullOr (submodule { freeformType = settingsFormat.type; options = { - schema_version = mkOption { + schema_version = lib.mkOption { default = cfg.package.schema_version; - defaultText = literalExpression "cfg.package.schema_version"; + defaultText = lib.literalExpression "cfg.package.schema_version"; type = int; description = '' Schema version for the configuration. @@ -121,7 +118,7 @@ in { ''; }; - extraArgs = mkOption { + extraArgs = lib.mkOption { default = [ ]; type = listOf str; description = '' @@ -130,27 +127,27 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.settings != null - -> !(hasAttrByPath [ "bind_host" ] cfg.settings); + -> !(lib.hasAttrByPath [ "bind_host" ] cfg.settings); message = "AdGuard option `settings.bind_host' has been superseded by `services.adguardhome.host'"; } { assertion = cfg.settings != null - -> !(hasAttrByPath [ "bind_port" ] cfg.settings); + -> !(lib.hasAttrByPath [ "bind_port" ] cfg.settings); message = "AdGuard option `settings.bind_port' has been superseded by `services.adguardhome.port'"; } { assertion = settings != null -> cfg.mutableSettings - || hasAttrByPath [ "dns" "bootstrap_dns" ] settings; + || lib.hasAttrByPath [ "dns" "bootstrap_dns" ] settings; message = "AdGuard setting dns.bootstrap_dns needs to be configured for a minimal working configuration"; } { assertion = settings != null -> cfg.mutableSettings - || hasAttrByPath [ "dns" "bootstrap_dns" ] settings - && isList settings.dns.bootstrap_dns; + || lib.hasAttrByPath [ "dns" "bootstrap_dns" ] settings + && lib.isList settings.dns.bootstrap_dns; message = "AdGuard setting dns.bootstrap_dns needs to be a list"; } ]; @@ -164,7 +161,7 @@ in { StartLimitBurst = 10; }; - preStart = optionalString (settings != null) '' + preStart = lib.optionalString (settings != null) '' if [ -e "$STATE_DIRECTORY/AdGuardHome.yaml" ] \ && [ "${toString cfg.mutableSettings}" = "1" ]; then # First run a schema_version update on the existing configuration @@ -185,7 +182,7 @@ in { DynamicUser = true; ExecStart = "${lib.getExe cfg.package} ${args}"; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] - ++ optionals cfg.allowDHCP [ "CAP_NET_RAW" ]; + ++ lib.optionals cfg.allowDHCP [ "CAP_NET_RAW" ]; Restart = "always"; RestartSec = 10; RuntimeDirectory = "AdGuardHome"; @@ -193,6 +190,6 @@ in { }; }; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; }; } diff --git a/nixos/modules/services/networking/alice-lg.nix b/nixos/modules/services/networking/alice-lg.nix index dab2d38ca353..c43f898bd7d3 100644 --- a/nixos/modules/services/networking/alice-lg.nix +++ b/nixos/modules/services/networking/alice-lg.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.alice-lg; settingsFormat = pkgs.formats.ini { }; @@ -9,17 +6,17 @@ in { options = { services.alice-lg = { - enable = mkEnableOption "Alice Looking Glass"; + enable = lib.mkEnableOption "Alice Looking Glass"; - package = mkPackageOption pkgs "alice-lg" { }; + package = lib.mkPackageOption pkgs "alice-lg" { }; - settings = mkOption { + settings = lib.mkOption { type = settingsFormat.type; default = { }; description = '' alice-lg configuration, for configuration options see the example on [github](https://github.com/alice-lg/alice-lg/blob/main/etc/alice-lg/alice.example.conf) ''; - example = literalExpression '' + example = lib.literalExpression '' { server = { # configures the built-in webserver and provides global application settings diff --git a/nixos/modules/services/networking/amuled.nix b/nixos/modules/services/networking/amuled.nix index aa72a047526b..b41d4d629ec5 100644 --- a/nixos/modules/services/networking/amuled.nix +++ b/nixos/modules/services/networking/amuled.nix @@ -1,7 +1,4 @@ { config, lib, options, pkgs, ... }: - -with lib; - let cfg = config.services.amule; opt = options.services.amule; @@ -16,18 +13,18 @@ in services.amule = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to run the AMule daemon. You need to manually run "amuled --ec-config" to configure the service for the first time. ''; }; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/home/${user}/"; - defaultText = literalExpression '' + defaultText = lib.literalExpression '' "/home/''${config.${opt.user}}/" ''; description = '' @@ -35,8 +32,8 @@ in ''; }; - user = mkOption { - type = types.nullOr types.str; + user = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The user the AMule daemon should run as. @@ -50,16 +47,16 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = mkIf (cfg.user == null) [ + users.users = lib.mkIf (cfg.user == null) [ { name = "amule"; description = "AMule daemon"; group = "amule"; uid = config.ids.uids.amule; } ]; - users.groups = mkIf (cfg.user == null) [ + users.groups = lib.mkIf (cfg.user == null) [ { name = "amule"; gid = config.ids.gids.amule; } ]; diff --git a/nixos/modules/services/networking/antennas.nix b/nixos/modules/services/networking/antennas.nix deleted file mode 100644 index e98b81588044..000000000000 --- a/nixos/modules/services/networking/antennas.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let cfg = config.services.antennas; -in - -{ - options = { - services.antennas = { - enable = mkEnableOption "Antennas"; - - tvheadendUrl = mkOption { - type = types.str; - default = "http://localhost:9981"; - description = "URL of Tvheadend."; - }; - - antennasUrl = mkOption { - type = types.str; - default = "http://127.0.0.1:5004"; - description = "URL of Antennas."; - }; - - tunerCount = mkOption { - type = types.int; - default = 6; - description = "Numbers of tuners in tvheadend."; - }; - - deviceUUID = mkOption { - type = types.str; - default = "2f70c0d7-90a3-4429-8275-cbeeee9cd605"; - description = "Device tuner UUID. Change this if you are running multiple instances."; - }; - }; - }; - - config = mkIf cfg.enable { - systemd.services.antennas = { - description = "Antennas HDHomeRun emulator for Tvheadend."; - wantedBy = [ "multi-user.target" ]; - - # Config - environment = { - TVHEADEND_URL = cfg.tvheadendUrl; - ANTENNAS_URL = cfg.antennasUrl; - TUNER_COUNT = toString cfg.tunerCount; - DEVICE_UUID = cfg.deviceUUID; - }; - - serviceConfig = { - ExecStart = "${pkgs.antennas}/bin/antennas"; - - # Hardening - CapabilityBoundingSet = [ "" ]; - DynamicUser = true; - LockPersonality = true; - ProcSubset = "pid"; - PrivateDevices = true; - PrivateUsers = true; - PrivateTmp = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProtectSystem = "strict"; - RestrictNamespaces = true; - RestrictRealtime = true; - }; - }; - }; -} diff --git a/nixos/modules/services/networking/asterisk.nix b/nixos/modules/services/networking/asterisk.nix index 187dd5c3ccab..f165974f2ae7 100644 --- a/nixos/modules/services/networking/asterisk.nix +++ b/nixos/modules/services/networking/asterisk.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.asterisk; @@ -13,7 +10,7 @@ let logdir = "/var/log/asterisk"; # Add filecontents from files of useTheseDefaultConfFiles to confFiles, do not override - defaultConfFiles = subtractLists (attrNames cfg.confFiles) cfg.useTheseDefaultConfFiles; + defaultConfFiles = lib.subtractLists (lib.attrNames cfg.confFiles) cfg.useTheseDefaultConfFiles; allConfFiles = { # Default asterisk.conf file "asterisk.conf".text = '' @@ -48,25 +45,25 @@ let syslog.local0 => notice,warning,error ''; } // - mapAttrs (name: text: { inherit text; }) cfg.confFiles // - listToAttrs (map (x: nameValuePair x { source = cfg.package + "/etc/asterisk/" + x; }) defaultConfFiles); + lib.mapAttrs (name: text: { inherit text; }) cfg.confFiles // + lib.listToAttrs (map (x: lib.nameValuePair x { source = cfg.package + "/etc/asterisk/" + x; }) defaultConfFiles); in { options = { services.asterisk = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the Asterisk PBX server. ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; example = '' [options] verbose=3 @@ -78,10 +75,10 @@ in ''; }; - confFiles = mkOption { + confFiles = lib.mkOption { default = {}; - type = types.attrsOf types.str; - example = literalExpression + type = lib.types.attrsOf lib.types.str; + example = lib.literalExpression '' { "extensions.conf" = ''' @@ -144,9 +141,9 @@ in ''; }; - useTheseDefaultConfFiles = mkOption { + useTheseDefaultConfFiles = lib.mkOption { default = [ "ari.conf" "acl.conf" "agents.conf" "amd.conf" "calendar.conf" "cdr.conf" "cdr_syslog.conf" "cdr_custom.conf" "cel.conf" "cel_custom.conf" "cli_aliases.conf" "confbridge.conf" "dundi.conf" "features.conf" "hep.conf" "iax.conf" "pjsip.conf" "pjsip_wizard.conf" "phone.conf" "phoneprov.conf" "queues.conf" "res_config_sqlite3.conf" "res_parking.conf" "statsd.conf" "udptl.conf" "unistim.conf" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "sip.conf" "dundi.conf" ]; description = ''Sets these config files to the default content. The default value for this option contains all necesscary files to avoid errors at startup. @@ -154,24 +151,24 @@ in ''; }; - extraArguments = mkOption { + extraArguments = lib.mkOption { default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "-vvvddd" "-e" "1024" ]; description = '' Additional command line arguments to pass to Asterisk. ''; }; - package = mkPackageOption pkgs "asterisk" { }; + package = lib.mkPackageOption pkgs "asterisk" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; - environment.etc = mapAttrs' (name: value: - nameValuePair "asterisk/${name}" value + environment.etc = lib.mapAttrs' (name: value: + lib.nameValuePair "asterisk/${name}" value ) allConfFiles; users.users.asterisk = @@ -214,7 +211,7 @@ in ExecStart = let # FIXME: This doesn't account for arguments with spaces - argString = concatStringsSep " " cfg.extraArguments; + argString = lib.concatStringsSep " " cfg.extraArguments; in "${cfg.package}/bin/asterisk -U ${asteriskUser} -C /etc/asterisk/asterisk.conf ${argString} -F"; ExecReload = ''${cfg.package}/bin/asterisk -x "core reload" diff --git a/nixos/modules/services/networking/atftpd.nix b/nixos/modules/services/networking/atftpd.nix index da5e305201f8..ab674d85715c 100644 --- a/nixos/modules/services/networking/atftpd.nix +++ b/nixos/modules/services/networking/atftpd.nix @@ -1,9 +1,5 @@ # NixOS module for atftpd TFTP server - { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.atftpd; @@ -16,19 +12,19 @@ in services.atftpd = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to enable the atftpd TFTP server. By default, the server binds to address 0.0.0.0. ''; }; - extraOptions = mkOption { + extraOptions = lib.mkOption { default = []; - type = types.listOf types.str; - example = literalExpression '' + type = lib.types.listOf lib.types.str; + example = lib.literalExpression '' [ "--bind-address 192.168.9.1" "--verbose=7" ] @@ -38,9 +34,9 @@ in ''; }; - root = mkOption { + root = lib.mkOption { default = "/srv/tftp"; - type = types.path; + type = lib.types.path; description = '' Document root directory for the atftpd. ''; @@ -50,7 +46,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.atftpd = { description = "TFTP Server"; diff --git a/nixos/modules/services/networking/atticd.nix b/nixos/modules/services/networking/atticd.nix new file mode 100644 index 000000000000..3984c434c60e --- /dev/null +++ b/nixos/modules/services/networking/atticd.nix @@ -0,0 +1,234 @@ +{ + lib, + pkgs, + config, + ... +}: + +let + inherit (lib) types; + + cfg = config.services.atticd; + + format = pkgs.formats.toml { }; + + checkedConfigFile = + pkgs.runCommand "checked-attic-server.toml" + { + configFile = format.generate "server.toml" cfg.settings; + } + '' + export ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64="$(${lib.getExe pkgs.openssl} genrsa -traditional 4096 | ${pkgs.coreutils}/bin/base64 -w0)" + export ATTIC_SERVER_DATABASE_URL="sqlite://:memory:" + ${lib.getExe cfg.package} --mode check-config -f $configFile + cat <$configFile >$out + ''; + + atticadmShim = pkgs.writeShellScript "atticadm" '' + if [ -n "$ATTICADM_PWD" ]; then + cd "$ATTICADM_PWD" + if [ "$?" != "0" ]; then + >&2 echo "Warning: Failed to change directory to $ATTICADM_PWD" + fi + fi + + exec ${cfg.package}/bin/atticadm -f ${checkedConfigFile} "$@" + ''; + + atticadmWrapper = pkgs.writeShellScriptBin "atticd-atticadm" '' + exec systemd-run \ + --quiet \ + --pipe \ + --pty \ + --same-dir \ + --wait \ + --collect \ + --service-type=exec \ + --property=EnvironmentFile=${cfg.environmentFile} \ + --property=DynamicUser=yes \ + --property=User=${cfg.user} \ + --property=Environment=ATTICADM_PWD=$(pwd) \ + --working-directory / \ + -- \ + ${atticadmShim} "$@" + ''; + + hasLocalPostgresDB = + let + url = cfg.settings.database.url or ""; + localStrings = [ + "localhost" + "127.0.0.1" + "/run/postgresql" + ]; + hasLocalStrings = lib.any (lib.flip lib.hasInfix url) localStrings; + in + config.services.postgresql.enable && lib.hasPrefix "postgresql://" url && hasLocalStrings; +in +{ + options = { + services.atticd = { + enable = lib.mkEnableOption "the atticd, the Nix Binary Cache server"; + + package = lib.mkPackageOption pkgs "attic-server" { }; + + environmentFile = lib.mkOption { + description = '' + Path to an EnvironmentFile containing required environment + variables: + + - ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64: The base64-encoded RSA PEM PKCS1 of the + RS256 JWT secret. Generate it with `openssl genrsa -traditional 4096 | base64 -w0`. + ''; + type = types.nullOr types.path; + default = null; + }; + + user = lib.mkOption { + description = '' + The group under which attic runs. + ''; + type = types.str; + default = "atticd"; + }; + + group = lib.mkOption { + description = '' + The user under which attic runs. + ''; + type = types.str; + default = "atticd"; + }; + + settings = lib.mkOption { + description = '' + Structured configurations of atticd. + See https://github.com/zhaofengli/attic/blob/main/server/src/config-template.toml + ''; + type = format.type; + default = { }; + }; + + mode = lib.mkOption { + description = '' + Mode in which to run the server. + + 'monolithic' runs all components, and is suitable for single-node deployments. + + 'api-server' runs only the API server, and is suitable for clustering. + + 'garbage-collector' only runs the garbage collector periodically. + + A simple NixOS-based Attic deployment will typically have one 'monolithic' and any number of 'api-server' nodes. + + There are several other supported modes that perform one-off operations, but these are the only ones that make sense to run via the NixOS module. + ''; + type = lib.types.enum [ + "monolithic" + "api-server" + "garbage-collector" + ]; + default = "monolithic"; + }; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.environmentFile != null; + message = '' + is not set. + + Run `openssl genrsa -traditional 4096 | base64 -w0` and create a file with the following contents: + + ATTIC_SERVER_TOKEN_RS256_SECRET="output from command" + + Then, set `services.atticd.environmentFile` to the quoted absolute path of the file. + ''; + } + ]; + + services.atticd.settings = { + chunking = lib.mkDefault { + nar-size-threshold = 65536; + min-size = 16384; # 16 KiB + avg-size = 65536; # 64 KiB + max-size = 262144; # 256 KiB + }; + + database.url = lib.mkDefault "sqlite:///var/lib/atticd/server.db?mode=rwc"; + + # "storage" is internally tagged + # if the user sets something the whole thing must be replaced + storage = lib.mkDefault { + type = "local"; + path = "/var/lib/atticd/storage"; + }; + }; + + systemd.services.atticd = { + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ] ++ lib.optionals hasLocalPostgresDB [ "postgresql.service" ]; + requires = lib.optionals hasLocalPostgresDB [ "postgresql.service" ]; + wants = [ "network-online.target" ]; + + serviceConfig = { + ExecStart = "${lib.getExe cfg.package} -f ${checkedConfigFile} --mode ${cfg.mode}"; + EnvironmentFile = cfg.environmentFile; + StateDirectory = "atticd"; # for usage with local storage and sqlite + DynamicUser = true; + User = cfg.user; + Group = cfg.group; + Restart = "on-failure"; + RestartSec = 10; + + CapabilityBoundingSet = [ "" ]; + DeviceAllow = ""; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = + let + path = cfg.settings.storage.path; + isDefaultStateDirectory = path == "/var/lib/atticd" || lib.hasPrefix "/var/lib/atticd/" path; + in + lib.optionals (cfg.settings.storage.type or "" == "local" && !isDefaultStateDirectory) [ path ]; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@resources" + "~@privileged" + ]; + UMask = "0077"; + }; + }; + + environment.systemPackages = [ + atticadmWrapper + ]; + }; +} diff --git a/nixos/modules/services/networking/autossh.nix b/nixos/modules/services/networking/autossh.nix index 245f2bfc2cf3..f8934845c28e 100644 --- a/nixos/modules/services/networking/autossh.nix +++ b/nixos/modules/services/networking/autossh.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.autossh; @@ -16,21 +13,21 @@ in services.autossh = { - sessions = mkOption { - type = types.listOf (types.submodule { + sessions = lib.mkOption { + type = lib.types.listOf (lib.types.submodule { options = { - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; example = "socks-peer"; description = "Name of the local AutoSSH session"; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; example = "bill"; description = "Name of the user the AutoSSH session should run as"; }; - monitoringPort = mkOption { - type = types.int; + monitoringPort = lib.mkOption { + type = lib.types.int; default = 0; example = 20000; description = '' @@ -39,8 +36,8 @@ in style monitoring ''; }; - extraArguments = mkOption { - type = types.separatedString " "; + extraArguments = lib.mkOption { + type = lib.types.separatedString " "; example = "-N -D4343 bill@socks.example.net"; description = '' Arguments to be passed to AutoSSH and retransmitted to SSH @@ -75,7 +72,7 @@ in ###### implementation - config = mkIf (cfg.sessions != []) { + config = lib.mkIf (cfg.sessions != []) { systemd.services = diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix index 8bb8e71ec3fb..72ccb910982c 100644 --- a/nixos/modules/services/networking/avahi-daemon.nix +++ b/nixos/modules/services/networking/avahi-daemon.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.avahi; @@ -13,15 +10,15 @@ let # a host name from DHCP. In that case, let Avahi take whatever the # current host name is; setting `host-name' to the empty string in # `avahi-daemon.conf' would be invalid. - optionalString (hostName != "") "host-name=${hostName}"} - browse-domains=${concatStringsSep ", " browseDomains} + lib.optionalString (hostName != "") "host-name=${hostName}"} + browse-domains=${lib.concatStringsSep ", " browseDomains} use-ipv4=${yesNo ipv4} use-ipv6=${yesNo ipv6} - ${optionalString (allowInterfaces!=null) "allow-interfaces=${concatStringsSep "," allowInterfaces}"} - ${optionalString (denyInterfaces!=null) "deny-interfaces=${concatStringsSep "," denyInterfaces}"} - ${optionalString (domainName!=null) "domain-name=${domainName}"} + ${lib.optionalString (allowInterfaces!=null) "allow-interfaces=${lib.concatStringsSep "," allowInterfaces}"} + ${lib.optionalString (denyInterfaces!=null) "deny-interfaces=${lib.concatStringsSep "," denyInterfaces}"} + ${lib.optionalString (domainName!=null) "domain-name=${domainName}"} allow-point-to-point=${yesNo allowPointToPoint} - ${optionalString (cacheEntriesMax!=null) "cache-entries-max=${toString cacheEntriesMax}"} + ${lib.optionalString (cacheEntriesMax!=null) "cache-entries-max=${toString cacheEntriesMax}"} [wide-area] enable-wide-area=${yesNo wideArea} @@ -46,8 +43,8 @@ in ]; options.services.avahi = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to run the Avahi daemon, which allows Avahi clients @@ -57,28 +54,28 @@ in ''; }; - package = mkPackageOption pkgs "avahi" { }; + package = lib.mkPackageOption pkgs "avahi" { }; - hostName = mkOption { - type = types.str; + hostName = lib.mkOption { + type = lib.types.str; default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; + defaultText = lib.literalExpression "config.networking.hostName"; description = '' Host name advertised on the LAN. If not set, avahi will use the value of {option}`config.networking.hostName`. ''; }; - domainName = mkOption { - type = types.str; + domainName = lib.mkOption { + type = lib.types.str; default = "local"; description = '' Domain name for all advertisements. ''; }; - browseDomains = mkOption { - type = types.listOf types.str; + browseDomains = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "0pointer.de" "zeroconf.org" ]; description = '' @@ -86,20 +83,20 @@ in ''; }; - ipv4 = mkOption { - type = types.bool; + ipv4 = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to use IPv4."; }; - ipv6 = mkOption { - type = types.bool; + ipv6 = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to use IPv6."; }; - allowInterfaces = mkOption { - type = types.nullOr (types.listOf types.str); + allowInterfaces = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; description = '' List of network interfaces that should be used by the {command}`avahi-daemon`. @@ -108,8 +105,8 @@ in ''; }; - denyInterfaces = mkOption { - type = types.nullOr (types.listOf types.str); + denyInterfaces = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; description = '' List of network interfaces that should be ignored by the @@ -119,8 +116,8 @@ in ''; }; - openFirewall = mkOption { - type = types.bool; + openFirewall = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to open the firewall for UDP port 5353. @@ -128,8 +125,8 @@ in ''; }; - allowPointToPoint = mkOption { - type = types.bool; + allowPointToPoint = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to use POINTTOPOINT interfaces. Might make mDNS unreliable due to usually large @@ -138,22 +135,22 @@ in ''; }; - wideArea = mkOption { - type = types.bool; + wideArea = lib.mkOption { + type = lib.types.bool; default = true; description = "Whether to enable wide-area service discovery."; }; - reflector = mkOption { - type = types.bool; + reflector = lib.mkOption { + type = lib.types.bool; default = false; description = "Reflect incoming mDNS requests to all allowed network interfaces."; }; - extraServiceFiles = mkOption { - type = with types; attrsOf (either str path); + extraServiceFiles = lib.mkOption { + type = with lib.types; attrsOf (either str path); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { ssh = "''${pkgs.avahi}/etc/avahi/services/ssh.service"; smb = ''' @@ -176,26 +173,26 @@ in }; publish = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to allow publishing in general."; }; - userServices = mkOption { - type = types.bool; + userServices = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to publish user services. Will set `addresses=true`."; }; - addresses = mkOption { - type = types.bool; + addresses = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to register mDNS address records for all local IP addresses."; }; - hinfo = mkOption { - type = types.bool; + hinfo = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to register a mDNS HINFO record which contains information about the @@ -203,23 +200,23 @@ in ''; }; - workstation = mkOption { - type = types.bool; + workstation = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to register a service of type "_workstation._tcp" on the local LAN. ''; }; - domain = mkOption { - type = types.bool; + domain = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to announce the locally used domain name for browsing by other hosts."; }; }; - nssmdns4 = mkOption { - type = types.bool; + nssmdns4 = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the mDNS NSS (Name Service Switch) plug-in for IPv4. @@ -228,8 +225,8 @@ in ''; }; - nssmdns6 = mkOption { - type = types.bool; + nssmdns6 = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the mDNS NSS (Name Service Switch) plug-in for IPv6. @@ -243,8 +240,8 @@ in ''; }; - cacheEntriesMax = mkOption { - type = types.nullOr types.int; + cacheEntriesMax = lib.mkOption { + type = lib.types.nullOr lib.types.int; default = null; description = '' Number of resource records to be cached per interface. Use 0 to @@ -252,8 +249,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra config to append to avahi-daemon.conf. @@ -261,7 +258,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.avahi = { description = "avahi-daemon privilege separation user"; home = "/var/empty"; @@ -271,7 +268,7 @@ in users.groups.avahi = { }; - system.nssModules = optional (cfg.nssmdns4 || cfg.nssmdns6) pkgs.nssmdns; + system.nssModules = lib.optional (cfg.nssmdns4 || cfg.nssmdns6) pkgs.nssmdns; system.nssDatabases.hosts = let mdns = if (cfg.nssmdns4 && cfg.nssmdns6) then "mdns" @@ -281,17 +278,17 @@ in "mdns4" else ""; - in optionals (cfg.nssmdns4 || cfg.nssmdns6) (mkMerge [ - (mkBefore [ "${mdns}_minimal [NOTFOUND=return]" ]) # before resolve - (mkAfter [ "${mdns}" ]) # after dns + in lib.optionals (cfg.nssmdns4 || cfg.nssmdns6) (lib.mkMerge [ + (lib.mkBefore [ "${mdns}_minimal [NOTFOUND=return]" ]) # before resolve + (lib.mkAfter [ "${mdns}" ]) # after dns ]); environment.systemPackages = [ cfg.package ]; - environment.etc = (mapAttrs' - (n: v: nameValuePair + environment.etc = (lib.mapAttrs' + (n: v: lib.nameValuePair "avahi/services/${n}.service" - { ${if types.path.check v then "source" else "text"} = v; } + { ${if lib.types.path.check v then "source" else "text"} = v; } ) cfg.extraServiceFiles); @@ -326,6 +323,6 @@ in services.dbus.enable = true; services.dbus.packages = [ cfg.package ]; - networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ 5353 ]; + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 5353 ]; }; } diff --git a/nixos/modules/services/networking/babeld.nix b/nixos/modules/services/networking/babeld.nix index 5a3e92d9c813..538654f90ae4 100644 --- a/nixos/modules/services/networking/babeld.nix +++ b/nixos/modules/services/networking/babeld.nix @@ -1,20 +1,17 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.babeld; - conditionalBoolToString = value: if (isBool value) then (boolToString value) else (toString value); + conditionalBoolToString = value: if (lib.isBool value) then (lib.boolToString value) else (toString value); paramsString = params: - concatMapStringsSep " " (name: "${name} ${conditionalBoolToString (getAttr name params)}") - (attrNames params); + lib.concatMapStringsSep " " (name: "${name} ${conditionalBoolToString (lib.getAttr name params)}") + (lib.attrNames params); interfaceConfig = name: let - interface = getAttr name cfg.interfaces; + interface = lib.getAttr name cfg.interfaces; in "interface ${name} ${paramsString interface}\n"; @@ -22,17 +19,17 @@ let '' skip-kernel-setup true '' - + (optionalString (cfg.interfaceDefaults != null) '' + + (lib.optionalString (cfg.interfaceDefaults != null) '' default ${paramsString cfg.interfaceDefaults} '') - + (concatMapStrings interfaceConfig (attrNames cfg.interfaces)) + + (lib.concatMapStrings interfaceConfig (lib.attrNames cfg.interfaces)) + extraConfig); in { - meta.maintainers = with maintainers; [ hexa ]; + meta.maintainers = with lib.maintainers; [ hexa ]; ###### interface @@ -40,15 +37,15 @@ in services.babeld = { - enable = mkEnableOption "the babeld network routing daemon"; + enable = lib.mkEnableOption "the babeld network routing daemon"; - interfaceDefaults = mkOption { + interfaceDefaults = lib.mkOption { default = null; description = '' A set describing default parameters for babeld interfaces. See {manpage}`babeld(8)` for options. ''; - type = types.nullOr (types.attrsOf types.unspecified); + type = lib.types.nullOr (lib.types.attrsOf lib.types.unspecified); example = { type = "tunnel"; @@ -56,13 +53,13 @@ in }; }; - interfaces = mkOption { + interfaces = lib.mkOption { default = {}; description = '' A set describing babeld interfaces. See {manpage}`babeld(8)` for options. ''; - type = types.attrsOf (types.attrsOf types.unspecified); + type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); example = { enp0s2 = { type = "wired"; @@ -72,9 +69,9 @@ in }; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Options that will be copied to babeld.conf. See {manpage}`babeld(8)` for details. @@ -87,7 +84,7 @@ in ###### implementation - config = mkIf config.services.babeld.enable { + config = lib.mkIf config.services.babeld.enable { boot.kernel.sysctl = { "net.ipv6.conf.all.forwarding" = 1; diff --git a/nixos/modules/services/networking/bee.nix b/nixos/modules/services/networking/bee.nix index 83ce522ba62a..6f3f7af607fb 100644 --- a/nixos/modules/services/networking/bee.nix +++ b/nixos/modules/services/networking/bee.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.bee; format = pkgs.formats.yaml {}; @@ -15,13 +13,13 @@ in { options = { services.bee = { - enable = mkEnableOption "Ethereum Swarm Bee"; + enable = lib.mkEnableOption "Ethereum Swarm Bee"; - package = mkPackageOption pkgs "bee" { + package = lib.mkPackageOption pkgs "bee" { example = "bee-unstable"; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; description = '' Ethereum Swarm Bee configuration. Refer to @@ -30,8 +28,8 @@ in { ''; }; - daemonNiceLevel = mkOption { - type = types.int; + daemonNiceLevel = lib.mkOption { + type = lib.types.int; default = 0; description = '' Daemon process priority for bee. @@ -39,16 +37,16 @@ in { ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "bee"; description = '' User the bee binary should execute under. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "bee"; description = '' Group the bee binary should execute under. @@ -59,14 +57,14 @@ in { ### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ - { assertion = (hasAttr "password" cfg.settings) != true; + { assertion = (lib.hasAttr "password" cfg.settings) != true; message = '' `services.bee.settings.password` is insecure. Use `services.bee.settings.password-file` or `systemd.services.bee.serviceConfig.EnvironmentFile` instead. ''; } - { assertion = (hasAttr "swap-endpoint" cfg.settings) || (cfg.settings.swap-enable or true == false); + { assertion = (lib.hasAttr "swap-endpoint" cfg.settings) || (cfg.settings.swap-enable or true == false); message = '' In a swap-enabled network a working Ethereum blockchain node is required. You must specify one using `services.bee.settings.swap-endpoint`, or disable `services.bee.settings.swap-enable` = false. ''; @@ -119,7 +117,7 @@ After you finish configuration run 'sudo bee-get-addr'." ''; }; - users.users = optionalAttrs (cfg.user == "bee") { + users.users = lib.optionalAttrs (cfg.user == "bee") { bee = { group = cfg.group; home = cfg.settings.data-dir; @@ -128,7 +126,7 @@ After you finish configuration run 'sudo bee-get-addr'." }; }; - users.groups = optionalAttrs (cfg.group == "bee") { + users.groups = lib.optionalAttrs (cfg.group == "bee") { bee = {}; }; }; diff --git a/nixos/modules/services/networking/biboumi.nix b/nixos/modules/services/networking/biboumi.nix index d92290626c31..33cb1d95bc51 100644 --- a/nixos/modules/services/networking/biboumi.nix +++ b/nixos/modules/services/networking/biboumi.nix @@ -1,62 +1,61 @@ { config, lib, pkgs, options, ... }: -with lib; let cfg = config.services.biboumi; inherit (config.environment) etc; rootDir = "/run/biboumi/mnt-root"; stateDir = "/var/lib/biboumi"; settingsFile = pkgs.writeText "biboumi.cfg" ( - generators.toKeyValue { + lib.generators.toKeyValue { mkKeyValue = k: v: - lib.optionalString (v != null) (generators.mkKeyValueDefault {} "=" k v); + lib.optionalString (v != null) (lib.generators.mkKeyValueDefault {} "=" k v); } cfg.settings); need_CAP_NET_BIND_SERVICE = cfg.settings.identd_port != 0 && cfg.settings.identd_port < 1024; in { options = { services.biboumi = { - enable = mkEnableOption "the Biboumi XMPP gateway to IRC"; + enable = lib.mkEnableOption "the Biboumi XMPP gateway to IRC"; - settings = mkOption { + settings = lib.mkOption { description = '' See [biboumi 8.5](https://lab.louiz.org/louiz/biboumi/blob/8.5/doc/biboumi.1.rst) for documentation. ''; default = {}; - type = types.submodule { - freeformType = with types; + type = lib.types.submodule { + freeformType = with lib.types; (attrsOf (nullOr (oneOf [str int bool]))) // { description = "settings option"; }; - options.admin = mkOption { - type = with types; listOf str; + options.admin = lib.mkOption { + type = with lib.types; listOf str; default = []; example = ["admin@example.org"]; - apply = concatStringsSep ":"; + apply = lib.concatStringsSep ":"; description = '' The bare JID of the gateway administrator. This JID will have more privileges than other standard users, for example some administration ad-hoc commands will only be available to that JID. ''; }; - options.ca_file = mkOption { - type = types.path; + options.ca_file = lib.mkOption { + type = lib.types.path; default = "/etc/ssl/certs/ca-certificates.crt"; description = '' Specifies which file should be used as the list of trusted CA when negotiating a TLS session. ''; }; - options.db_name = mkOption { - type = with types; either path str; + options.db_name = lib.mkOption { + type = with lib.types; either path str; default = "${stateDir}/biboumi.sqlite"; description = '' The name of the database to use. ''; example = "postgresql://user:secret@localhost"; }; - options.hostname = mkOption { - type = types.str; + options.hostname = lib.mkOption { + type = lib.types.str; example = "biboumi.example.org"; description = '' The hostname served by the XMPP gateway. @@ -64,24 +63,24 @@ in as an external component. ''; }; - options.identd_port = mkOption { - type = types.port; + options.identd_port = lib.mkOption { + type = lib.types.port; default = 113; example = 0; description = '' The TCP port on which to listen for identd queries. ''; }; - options.log_level = mkOption { - type = types.ints.between 0 3; + options.log_level = lib.mkOption { + type = lib.types.ints.between 0 3; default = 1; description = '' Indicate what type of log messages to write in the logs. 0 is debug, 1 is info, 2 is warning, 3 is error. ''; }; - options.password = mkOption { - type = with types; nullOr str; + options.password = lib.mkOption { + type = with lib.types; nullOr str; description = '' The password used to authenticate the XMPP component to your XMPP server. This password must be configured in the XMPP server, @@ -92,8 +91,8 @@ in if you do not want this password to go into the Nix store. ''; }; - options.persistent_by_default = mkOption { - type = types.bool; + options.persistent_by_default = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether all rooms will be persistent by default: @@ -103,25 +102,25 @@ in “persistent” configuration option to false in order to override this. ''; }; - options.policy_directory = mkOption { - type = types.path; + options.policy_directory = lib.mkOption { + type = lib.types.path; default = "${pkgs.biboumi}/etc/biboumi"; - defaultText = literalExpression ''"''${pkgs.biboumi}/etc/biboumi"''; + defaultText = lib.literalExpression ''"''${pkgs.biboumi}/etc/biboumi"''; description = '' A directory that should contain the policy files, used to customize Botan’s behaviour when negotiating the TLS connections with the IRC servers. ''; }; - options.port = mkOption { - type = types.port; + options.port = lib.mkOption { + type = lib.types.port; default = 5347; description = '' The TCP port to use to connect to the local XMPP component. ''; }; - options.realname_customization = mkOption { - type = types.bool; + options.realname_customization = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether the users will be able to use @@ -129,8 +128,8 @@ in their realname and username. ''; }; - options.realname_from_jid = mkOption { - type = types.bool; + options.realname_from_jid = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether the realname and username of each biboumi @@ -139,8 +138,8 @@ in they used to connect to the IRC server. ''; }; - options.xmpp_server_ip = mkOption { - type = types.str; + options.xmpp_server_ip = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' The IP address to connect to the XMPP server on. @@ -152,8 +151,8 @@ in }; }; - credentialsFile = mkOption { - type = types.path; + credentialsFile = lib.mkOption { + type = lib.types.path; description = '' Path to a configuration file to be merged with the settings. Beware not to surround "=" with spaces when setting biboumi's options in this file. @@ -165,12 +164,12 @@ in example = "/run/keys/biboumi.cfg"; }; - openFirewall = mkEnableOption "opening of the identd port in the firewall"; + openFirewall = lib.mkEnableOption "opening of the identd port in the firewall"; }; }; - config = mkIf cfg.enable { - networking.firewall = mkIf (cfg.openFirewall && cfg.settings.identd_port != 0) + config = lib.mkIf cfg.enable { + networking.firewall = lib.mkIf (cfg.openFirewall && cfg.settings.identd_port != 0) { allowedTCPPorts = [ cfg.settings.identd_port ]; }; systemd.services.biboumi = { @@ -202,7 +201,7 @@ in RootDirectory = rootDir; RootDirectoryStartOnly = true; InaccessiblePaths = [ "-+${rootDir}" ]; - RuntimeDirectory = [ "biboumi" (removePrefix "/run/" rootDir) ]; + RuntimeDirectory = [ "biboumi" (lib.removePrefix "/run/" rootDir) ]; RuntimeDirectoryMode = "700"; StateDirectory = "biboumi"; StateDirectoryMode = "700"; @@ -221,8 +220,8 @@ in ]; # The following options are only for optimizing: # systemd-analyze security biboumi - AmbientCapabilities = [ (optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ]; - CapabilityBoundingSet = [ (optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ]; + AmbientCapabilities = [ (lib.optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ]; + CapabilityBoundingSet = [ (lib.optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ]; # ProtectClock= adds DeviceAllow=char-rtc r DeviceAllow = ""; LockPersonality = true; @@ -230,7 +229,7 @@ in NoNewPrivileges = true; PrivateDevices = true; PrivateMounts = true; - PrivateNetwork = mkDefault false; + PrivateNetwork = lib.mkDefault false; PrivateTmp = true; # PrivateUsers=true breaks AmbientCapabilities=CAP_NET_BIND_SERVICE # See https://bugs.archlinux.org/task/65921 @@ -265,5 +264,5 @@ in }; }; - meta.maintainers = with maintainers; [ julm ]; + meta.maintainers = with lib.maintainers; [ julm ]; } diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix index 6c5c59a88dec..6079062db6c3 100644 --- a/nixos/modules/services/networking/bind.nix +++ b/nixos/modules/services/networking/bind.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.bind; @@ -14,30 +11,30 @@ let bindZoneOptions = { name, config, ... }: { options = { - name = mkOption { - type = types.str; + name = lib.mkOption { + type = lib.types.str; default = name; description = "Name of the zone."; }; - master = mkOption { + master = lib.mkOption { description = "Master=false means slave server"; - type = types.bool; + type = lib.types.bool; }; - file = mkOption { - type = types.either types.str types.path; + file = lib.mkOption { + type = lib.types.either lib.types.str lib.types.path; description = "Zone file resource records contain columns of data, separated by whitespace, that define the record."; }; - masters = mkOption { - type = types.listOf types.str; + masters = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "List of servers for inclusion in stub and secondary zones."; }; - slaves = mkOption { - type = types.listOf types.str; + slaves = lib.mkOption { + type = lib.types.listOf lib.types.str; description = "Addresses who may request zone transfers."; default = [ ]; }; - allowQuery = mkOption { - type = types.listOf types.str; + allowQuery = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' List of address ranges allowed to query this zone. Instead of the address(es), this may instead contain the single string "any". @@ -47,8 +44,8 @@ let ''; default = [ "any" ]; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.lines; description = "Extra zone config to be appended at the end of the zone section."; default = ""; }; @@ -62,16 +59,16 @@ let inet 127.0.0.1 allow {localhost;} keys {"rndc-key";}; }; - acl cachenetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} }; - acl badnetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} }; + acl cachenetworks { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} }; + acl badnetworks { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} }; options { - listen-on { ${concatMapStrings (entry: " ${entry}; ") cfg.listenOn} }; - listen-on-v6 { ${concatMapStrings (entry: " ${entry}; ") cfg.listenOnIpv6} }; + listen-on { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.listenOn} }; + listen-on-v6 { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.listenOnIpv6} }; allow-query { cachenetworks; }; blackhole { badnetworks; }; forward ${cfg.forward}; - forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} }; + forwarders { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.forwarders} }; directory "${cfg.directory}"; pid-file "/run/named/named.pid"; ${cfg.extraOptions} @@ -79,7 +76,7 @@ let ${cfg.extraConfig} - ${ concatMapStrings + ${ lib.concatMapStrings ({ name, file, master ? true, slaves ? [], masters ? [], allowQuery ? [], extraConfig ? "" }: '' zone "${name}" { @@ -88,21 +85,21 @@ let ${ if master then '' allow-transfer { - ${concatMapStrings (ip: "${ip};\n") slaves} + ${lib.concatMapStrings (ip: "${ip};\n") slaves} }; '' else '' masters { - ${concatMapStrings (ip: "${ip};\n") masters} + ${lib.concatMapStrings (ip: "${ip};\n") masters} }; '' } - allow-query { ${concatMapStrings (ip: "${ip}; ") allowQuery}}; + allow-query { ${lib.concatMapStrings (ip: "${ip}; ") allowQuery}}; ${extraConfig} }; '') - (attrValues cfg.zones) } + (lib.attrValues cfg.zones) } ''; in @@ -115,14 +112,14 @@ in services.bind = { - enable = mkEnableOption "BIND domain name server"; + enable = lib.mkEnableOption "BIND domain name server"; - package = mkPackageOption pkgs "bind" { }; + package = lib.mkPackageOption pkgs "bind" { }; - cacheNetworks = mkOption { + cacheNetworks = lib.mkOption { default = [ "127.0.0.0/24" "::1/128" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' What networks are allowed to use us as a resolver. Note that this is for recursive queries -- all networks are @@ -134,64 +131,64 @@ in ''; }; - blockedNetworks = mkOption { + blockedNetworks = lib.mkOption { default = [ ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' What networks are just blocked. ''; }; - ipv4Only = mkOption { + ipv4Only = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Only use ipv4, even if the host supports ipv6. ''; }; - forwarders = mkOption { + forwarders = lib.mkOption { default = config.networking.nameservers; - defaultText = literalExpression "config.networking.nameservers"; - type = types.listOf types.str; + defaultText = lib.literalExpression "config.networking.nameservers"; + type = lib.types.listOf lib.types.str; description = '' List of servers we should forward requests to. ''; }; - forward = mkOption { + forward = lib.mkOption { default = "first"; - type = types.enum ["first" "only"]; + type = lib.types.enum ["first" "only"]; description = '' Whether to forward 'first' (try forwarding but lookup directly if forwarding fails) or 'only'. ''; }; - listenOn = mkOption { + listenOn = lib.mkOption { default = [ "any" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' Interfaces to listen on. ''; }; - listenOnIpv6 = mkOption { + listenOnIpv6 = lib.mkOption { default = [ "any" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' Ipv6 interfaces to listen on. ''; }; - directory = mkOption { - type = types.str; + directory = lib.mkOption { + type = lib.types.str; default = "/run/named"; description = "Working directory of BIND."; }; - zones = mkOption { + zones = lib.mkOption { default = [ ]; - type = with types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (types.submodule bindZoneOptions)); + type = with lib.types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (lib.types.submodule bindZoneOptions)); description = '' List of zones we claim authority over. ''; @@ -206,16 +203,16 @@ in }; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra lines to be added verbatim to the generated named configuration file. ''; }; - extraOptions = mkOption { - type = types.lines; + extraOptions = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra lines to be added verbatim to the options section of the @@ -223,10 +220,10 @@ in ''; }; - configFile = mkOption { - type = types.path; + configFile = lib.mkOption { + type = lib.types.path; default = confFile; - defaultText = literalExpression "confFile"; + defaultText = lib.literalExpression "confFile"; description = '' Overridable config file to use for named. By default, that generated by nixos. @@ -240,9 +237,9 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - networking.resolvconf.useLocalResolver = mkDefault true; + networking.resolvconf.useLocalResolver = lib.mkDefault true; users.users.${bindUser} = { @@ -272,7 +269,7 @@ in serviceConfig = { Type = "forking"; # Set type to forking, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=900788 - ExecStart = "${bindPkg.out}/sbin/named -u ${bindUser} ${optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile}"; + ExecStart = "${bindPkg.out}/sbin/named -u ${bindUser} ${lib.optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile}"; ExecReload = "${bindPkg.out}/sbin/rndc -k '/etc/bind/rndc.key' reload"; ExecStop = "${bindPkg.out}/sbin/rndc -k '/etc/bind/rndc.key' stop"; }; diff --git a/nixos/modules/services/networking/bird-lg.nix b/nixos/modules/services/networking/bird-lg.nix index 0c69b72fec10..f73c0b796e6f 100644 --- a/nixos/modules/services/networking/bird-lg.nix +++ b/nixos/modules/services/networking/bird-lg.nix @@ -1,176 +1,173 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.bird-lg; - stringOrConcat = sep: v: if builtins.isString v then v else concatStringsSep sep v; + stringOrConcat = sep: v: if builtins.isString v then v else lib.concatStringsSep sep v; frontend_args = let fe = cfg.frontend; in { - "--servers" = concatStringsSep "," fe.servers; + "--servers" = lib.concatStringsSep "," fe.servers; "--domain" = fe.domain; "--listen" = fe.listenAddress; "--proxy-port" = fe.proxyPort; "--whois" = fe.whois; "--dns-interface" = fe.dnsInterface; - "--bgpmap-info" = concatStringsSep "," cfg.frontend.bgpMapInfo; + "--bgpmap-info" = lib.concatStringsSep "," cfg.frontend.bgpMapInfo; "--title-brand" = fe.titleBrand; "--navbar-brand" = fe.navbar.brand; "--navbar-brand-url" = fe.navbar.brandURL; "--navbar-all-servers" = fe.navbar.allServers; "--navbar-all-url" = fe.navbar.allServersURL; "--net-specific-mode" = fe.netSpecificMode; - "--protocol-filter" = concatStringsSep "," cfg.frontend.protocolFilter; + "--protocol-filter" = lib.concatStringsSep "," cfg.frontend.protocolFilter; }; proxy_args = let px = cfg.proxy; in { - "--allowed" = concatStringsSep "," px.allowedIPs; + "--allowed" = lib.concatStringsSep "," px.allowedIPs; "--bird" = px.birdSocket; "--listen" = px.listenAddress; "--traceroute_bin" = px.traceroute.binary; - "--traceroute_flags" = concatStringsSep " " px.traceroute.flags; + "--traceroute_flags" = lib.concatStringsSep " " px.traceroute.flags; "--traceroute_raw" = px.traceroute.rawOutput; }; mkArgValue = value: - if isString value - then escapeShellArg value - else if isBool value - then boolToString value + if lib.isString value + then lib.escapeShellArg value + else if lib.isBool value + then lib.boolToString value else toString value; - filterNull = filterAttrs (_: v: v != "" && v != null && v != []); + filterNull = lib.filterAttrs (_: v: v != "" && v != null && v != []); - argsAttrToList = args: mapAttrsToList (name: value: "${name} " + mkArgValue value ) (filterNull args); + argsAttrToList = args: lib.mapAttrsToList (name: value: "${name} " + mkArgValue value ) (filterNull args); in { options = { services.bird-lg = { - package = mkPackageOption pkgs "bird-lg" { }; + package = lib.mkPackageOption pkgs "bird-lg" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "bird-lg"; description = "User to run the service."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "bird-lg"; description = "Group to run the service."; }; frontend = { - enable = mkEnableOption "Bird Looking Glass Frontend Webserver"; + enable = lib.mkEnableOption "Bird Looking Glass Frontend Webserver"; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1:5000"; description = "Address to listen on."; }; - proxyPort = mkOption { - type = types.port; + proxyPort = lib.mkOption { + type = lib.types.port; default = 8000; description = "Port bird-lg-proxy is running on."; }; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; example = "dn42.lantian.pub"; description = "Server name domain suffixes."; }; - servers = mkOption { - type = types.listOf types.str; + servers = lib.mkOption { + type = lib.types.listOf lib.types.str; example = [ "gigsgigscloud" "hostdare" ]; description = "Server name prefixes."; }; - whois = mkOption { - type = types.str; + whois = lib.mkOption { + type = lib.types.str; default = "whois.verisign-grs.com"; description = "Whois server for queries."; }; - dnsInterface = mkOption { - type = types.str; + dnsInterface = lib.mkOption { + type = lib.types.str; default = "asn.cymru.com"; description = "DNS zone to query ASN information."; }; - bgpMapInfo = mkOption { - type = types.listOf types.str; + bgpMapInfo = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "asn" "as-name" "ASName" "descr" ]; description = "Information displayed in bgpmap."; }; - titleBrand = mkOption { - type = types.str; + titleBrand = lib.mkOption { + type = lib.types.str; default = "Bird-lg Go"; description = "Prefix of page titles in browser tabs."; }; - netSpecificMode = mkOption { - type = types.str; + netSpecificMode = lib.mkOption { + type = lib.types.str; default = ""; example = "dn42"; description = "Apply network-specific changes for some networks."; }; - protocolFilter = mkOption { - type = types.listOf types.str; + protocolFilter = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "ospf" ]; description = "Information displayed in bgpmap."; }; - nameFilter = mkOption { - type = types.str; + nameFilter = lib.mkOption { + type = lib.types.str; default = ""; example = "^ospf"; description = "Protocol names to hide in summary tables (RE2 syntax),"; }; - timeout = mkOption { - type = types.int; + timeout = lib.mkOption { + type = lib.types.int; default = 120; description = "Time before request timed out, in seconds."; }; navbar = { - brand = mkOption { - type = types.str; + brand = lib.mkOption { + type = lib.types.str; default = "Bird-lg Go"; description = "Brand to show in the navigation bar ."; }; - brandURL = mkOption { - type = types.str; + brandURL = lib.mkOption { + type = lib.types.str; default = "/"; description = "URL of the brand to show in the navigation bar."; }; - allServers = mkOption { - type = types.str; + allServers = lib.mkOption { + type = lib.types.str; default = "ALL Servers"; description = "Text of 'All server' button in the navigation bar."; }; - allServersURL = mkOption { - type = types.str; + allServersURL = lib.mkOption { + type = lib.types.str; default = "all"; description = "URL of 'All servers' button."; }; }; - extraArgs = mkOption { - type = with types; either lines (listOf str); + extraArgs = lib.mkOption { + type = with lib.types; either lines (listOf str); default = [ ]; description = '' Extra parameters documented [here](https://github.com/xddxdd/bird-lg-go#frontend). @@ -183,50 +180,50 @@ in }; proxy = { - enable = mkEnableOption "Bird Looking Glass Proxy"; + enable = lib.mkEnableOption "Bird Looking Glass Proxy"; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = "127.0.0.1:8000"; description = "Address to listen on."; }; - allowedIPs = mkOption { - type = types.listOf types.str; + allowedIPs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "192.168.25.52" "192.168.25.53" "192.168.0.0/24" ]; description = "List of IPs or networks to allow (default all allowed)."; }; - birdSocket = mkOption { - type = types.str; + birdSocket = lib.mkOption { + type = lib.types.str; default = "/var/run/bird/bird.ctl"; description = "Bird control socket path."; }; traceroute = { - binary = mkOption { - type = types.str; + binary = lib.mkOption { + type = lib.types.str; default = "${pkgs.traceroute}/bin/traceroute"; - defaultText = literalExpression ''"''${pkgs.traceroute}/bin/traceroute"''; + defaultText = lib.literalExpression ''"''${pkgs.traceroute}/bin/traceroute"''; description = "Traceroute's binary path."; }; - flags = mkOption { - type = with types; listOf str; + flags = lib.mkOption { + type = with lib.types; listOf str; default = [ ]; description = "Flags for traceroute process"; }; - rawOutput = mkOption { - type = types.bool; + rawOutput = lib.mkOption { + type = lib.types.bool; default = false; description = "Display traceroute output in raw format."; }; }; - extraArgs = mkOption { - type = with types; either lines (listOf str); + extraArgs = lib.mkOption { + type = with lib.types; either lines (listOf str); default = [ ]; description = '' Extra parameters documented [here](https://github.com/xddxdd/bird-lg-go#proxy). @@ -254,7 +251,7 @@ in ; systemd.services = { - bird-lg-frontend = mkIf cfg.frontend.enable { + bird-lg-frontend = lib.mkIf cfg.frontend.enable { enable = true; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; @@ -270,12 +267,12 @@ in }; script = '' ${cfg.package}/bin/frontend \ - ${concatStringsSep " \\\n " (argsAttrToList frontend_args)} \ + ${lib.concatStringsSep " \\\n " (argsAttrToList frontend_args)} \ ${stringOrConcat " " cfg.frontend.extraArgs} ''; }; - bird-lg-proxy = mkIf cfg.proxy.enable { + bird-lg-proxy = lib.mkIf cfg.proxy.enable { enable = true; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; @@ -291,14 +288,14 @@ in }; script = '' ${cfg.package}/bin/proxy \ - ${concatStringsSep " \\\n " (argsAttrToList proxy_args)} \ + ${lib.concatStringsSep " \\\n " (argsAttrToList proxy_args)} \ ${stringOrConcat " " cfg.proxy.extraArgs} ''; }; }; - users = mkIf (cfg.frontend.enable || cfg.proxy.enable) { - groups."bird-lg" = mkIf (cfg.group == "bird-lg") { }; - users."bird-lg" = mkIf (cfg.user == "bird-lg") { + users = lib.mkIf (cfg.frontend.enable || cfg.proxy.enable) { + groups."bird-lg" = lib.mkIf (cfg.group == "bird-lg") { }; + users."bird-lg" = lib.mkIf (cfg.user == "bird-lg") { description = "Bird Looking Glass user"; extraGroups = lib.optionals (config.services.bird2.enable) [ "bird2" ]; group = cfg.group; diff --git a/nixos/modules/services/networking/birdwatcher.nix b/nixos/modules/services/networking/birdwatcher.nix index 4baab1e60a2d..434f0e2095f3 100644 --- a/nixos/modules/services/networking/birdwatcher.nix +++ b/nixos/modules/services/networking/birdwatcher.nix @@ -1,31 +1,28 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.birdwatcher; in { options = { services.birdwatcher = { - package = mkPackageOption pkgs "birdwatcher" { }; - enable = mkEnableOption "Birdwatcher"; - flags = mkOption { + package = lib.mkPackageOption pkgs "birdwatcher" { }; + enable = lib.mkEnableOption "Birdwatcher"; + flags = lib.mkOption { default = [ ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "-worker-pool-size 16" "-6" ]; description = '' Flags to append to the program call ''; }; - settings = mkOption { - type = types.lines; + settings = lib.mkOption { + type = lib.types.lines; default = { }; description = '' birdwatcher configuration, for configuration options see the example on [github](https://github.com/alice-lg/birdwatcher/blob/master/etc/birdwatcher/birdwatcher.conf) ''; - example = literalExpression '' + example = lib.literalExpression '' [server] allow_from = [] allow_uncached = false @@ -72,7 +69,7 @@ in }; config = - let flagsStr = escapeShellArgs cfg.flags; + let flagsStr = lib.escapeShellArgs cfg.flags; in lib.mkIf cfg.enable { environment.etc."birdwatcher/birdwatcher.conf".source = pkgs.writeTextFile { name = "birdwatcher.conf"; diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix index 20488e5f33fe..3ebbab97b68e 100644 --- a/nixos/modules/services/networking/bitlbee.nix +++ b/nixos/modules/services/networking/bitlbee.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.bitlbee; @@ -46,8 +43,8 @@ in services.bitlbee = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to run the BitlBee IRC to other chat network gateway. @@ -56,8 +53,8 @@ in ''; }; - interface = mkOption { - type = types.str; + interface = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' The interface the BitlBee daemon will be listening to. If `127.0.0.1`, @@ -66,17 +63,17 @@ in ''; }; - portNumber = mkOption { + portNumber = lib.mkOption { default = 6667; - type = types.port; + type = lib.types.port; description = '' Number of the port BitlBee will be listening to. ''; }; - authBackend = mkOption { + authBackend = lib.mkOption { default = "storage"; - type = types.enum [ "storage" "pam" ]; + type = lib.types.enum [ "storage" "pam" ]; description = '' How users are authenticated storage -- save passwords internally @@ -84,9 +81,9 @@ in ''; }; - authMode = mkOption { + authMode = lib.mkOption { default = "Open"; - type = types.enum [ "Open" "Closed" "Registered" ]; + type = lib.types.enum [ "Open" "Closed" "Registered" ]; description = '' The following authentication modes are available: Open -- Accept connections from anyone, use NickServ for user authentication. @@ -95,9 +92,9 @@ in ''; }; - hostName = mkOption { + hostName = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' Normally, BitlBee gets a hostname using getsockname(). If you have a nicer alias for your BitlBee daemon, you can set it here and BitlBee will identify @@ -105,53 +102,53 @@ in ''; }; - plugins = mkOption { - type = types.listOf types.package; + plugins = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "[ pkgs.bitlbee-facebook ]"; + example = lib.literalExpression "[ pkgs.bitlbee-facebook ]"; description = '' The list of bitlbee plugins to install. ''; }; - libpurple_plugins = mkOption { - type = types.listOf types.package; + libpurple_plugins = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "[ pkgs.purple-matrix ]"; + example = lib.literalExpression "[ pkgs.purple-matrix ]"; description = '' The list of libpurple plugins to install. ''; }; - configDir = mkOption { + configDir = lib.mkOption { default = "/var/lib/bitlbee"; - type = types.path; + type = lib.types.path; description = '' Specify an alternative directory to store all the per-user configuration files. ''; }; - protocols = mkOption { + protocols = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = '' This option allows to remove the support of protocol, even if compiled in. If nothing is given, there are no restrictions. ''; }; - extraSettings = mkOption { + extraSettings = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Will be inserted in the Settings section of the config file. ''; }; - extraDefaults = mkOption { + extraDefaults = lib.mkOption { default = ""; - type = types.lines; + type = lib.types.lines; description = '' Will be inserted in the Default section of the config file. ''; @@ -163,8 +160,8 @@ in ###### implementation - config = mkMerge [ - (mkIf config.services.bitlbee.enable { + config = lib.mkMerge [ + (lib.mkIf config.services.bitlbee.enable { systemd.services.bitlbee = { environment.PURPLE_PLUGIN_PATH = purple_plugin_path; description = "BitlBee IRC to other chat networks gateway"; @@ -182,7 +179,7 @@ in environment.systemPackages = [ bitlbeePkg ]; }) - (mkIf (config.services.bitlbee.authBackend == "pam") { + (lib.mkIf (config.services.bitlbee.authBackend == "pam") { security.pam.services.bitlbee = {}; }) ]; diff --git a/nixos/modules/services/networking/blockbook-frontend.nix b/nixos/modules/services/networking/blockbook-frontend.nix index 504c98e9ab8e..6200a098c34a 100644 --- a/nixos/modules/services/networking/blockbook-frontend.nix +++ b/nixos/modules/services/networking/blockbook-frontend.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let eachBlockbook = config.services.blockbook-frontend; @@ -10,24 +7,24 @@ let options = { - enable = mkEnableOption "blockbook-frontend application"; + enable = lib.mkEnableOption "blockbook-frontend application"; - package = mkPackageOption pkgs "blockbook" { }; + package = lib.mkPackageOption pkgs "blockbook" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "blockbook-frontend-${name}"; description = "The user as which to run blockbook-frontend-${name}."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "${config.user}"; description = "The group as which to run blockbook-frontend-${name}."; }; - certFile = mkOption { - type = types.nullOr types.path; + certFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/etc/secrets/blockbook-frontend-${name}/certFile"; description = '' @@ -36,15 +33,15 @@ let ''; }; - configFile = mkOption { - type = with types; nullOr path; + configFile = lib.mkOption { + type = with lib.types; nullOr path; default = null; example = "${config.dataDir}/config.json"; description = "Location of the blockbook configuration file."; }; - coinName = mkOption { - type = types.str; + coinName = lib.mkOption { + type = lib.types.str; default = "Bitcoin"; description = '' See @@ -52,68 +49,68 @@ let ''; }; - cssDir = mkOption { - type = types.path; + cssDir = lib.mkOption { + type = lib.types.path; default = "${config.package}/share/css/"; - defaultText = literalExpression ''"''${package}/share/css/"''; - example = literalExpression ''"''${dataDir}/static/css/"''; + defaultText = lib.literalExpression ''"''${package}/share/css/"''; + example = lib.literalExpression ''"''${dataDir}/static/css/"''; description = '' Location of the dir with {file}`main.css` CSS file. By default, the one shipped with the package is used. ''; }; - dataDir = mkOption { - type = types.path; + dataDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/blockbook-frontend-${name}"; description = "Location of blockbook-frontend-${name} data directory."; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = "Debug mode, return more verbose errors, reload templates on each request."; }; - internal = mkOption { - type = types.nullOr types.str; + internal = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = ":9030"; description = "Internal http server binding `[address]:port`."; }; - messageQueueBinding = mkOption { - type = types.str; + messageQueueBinding = lib.mkOption { + type = lib.types.str; default = "tcp://127.0.0.1:38330"; description = "Message Queue Binding `address:port`."; }; - public = mkOption { - type = types.nullOr types.str; + public = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = ":9130"; description = "Public http server binding `[address]:port`."; }; rpc = { - url = mkOption { - type = types.str; + url = lib.mkOption { + type = lib.types.str; default = "http://127.0.0.1"; description = "URL for JSON-RPC connections."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8030; description = "Port for JSON-RPC connections."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "rpc"; description = "Username for JSON-RPC connections."; }; - password = mkOption { - type = types.str; + password = lib.mkOption { + type = lib.types.str; default = "rpc"; description = '' RPC password for JSON-RPC connections. @@ -122,8 +119,8 @@ let ''; }; - passwordFile = mkOption { - type = types.nullOr types.path; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File containing password of the RPC user. @@ -132,24 +129,24 @@ let }; }; - sync = mkOption { - type = types.bool; + sync = lib.mkOption { + type = lib.types.bool; default = true; description = "Synchronizes until tip, if together with zeromq, keeps index synchronized."; }; - templateDir = mkOption { - type = types.path; + templateDir = lib.mkOption { + type = lib.types.path; default = "${config.package}/share/templates/"; - defaultText = literalExpression ''"''${package}/share/templates/"''; - example = literalExpression ''"''${dataDir}/templates/static/"''; + defaultText = lib.literalExpression ''"''${package}/share/templates/"''; + example = lib.literalExpression ''"''${dataDir}/templates/static/"''; description = "Location of the HTML templates. By default, ones shipped with the package are used."; }; - extraConfig = mkOption { - type = types.attrs; + extraConfig = lib.mkOption { + type = lib.types.attrs; default = {}; - example = literalExpression '' { + example = lib.literalExpression '' { "alternative_estimate_fee" = "whatthefee-disabled"; "alternative_estimate_fee_params" = "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}"; "fiat_rates" = "coingecko"; @@ -174,8 +171,8 @@ let ''; }; - extraCmdLineOptions = mkOption { - type = types.listOf types.str; + extraCmdLineOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "-workers=1" "-dbcache=0" "-logtosderr" ]; description = '' @@ -190,8 +187,8 @@ in # interface options = { - services.blockbook-frontend = mkOption { - type = types.attrsOf (types.submodule blockbookOpts); + services.blockbook-frontend = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule blockbookOpts); default = {}; description = "Specification of one or more blockbook-frontend instances."; }; @@ -199,10 +196,10 @@ in # implementation - config = mkIf (eachBlockbook != {}) { + config = lib.mkIf (eachBlockbook != {}) { - systemd.services = mapAttrs' (blockbookName: cfg: ( - nameValuePair "blockbook-frontend-${blockbookName}" ( + systemd.services = lib.mapAttrs' (blockbookName: cfg: ( + lib.nameValuePair "blockbook-frontend-${blockbookName}" ( let configFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "config.conf" (builtins.toJSON ( { @@ -220,7 +217,7 @@ in preStart = '' ln -sf ${cfg.templateDir} ${cfg.dataDir}/static/ ln -sf ${cfg.cssDir} ${cfg.dataDir}/static/ - ${optionalString (cfg.rpc.passwordFile != null && cfg.configFile == null) '' + ${lib.optionalString (cfg.rpc.passwordFile != null && cfg.configFile == null) '' CONFIGTMP=$(mktemp) ${pkgs.jq}/bin/jq ".rpc_pass = \"$(cat ${cfg.rpc.passwordFile})\"" ${configFile} > $CONFIGTMP mv $CONFIGTMP ${cfg.dataDir}/${blockbookName}-config.json @@ -237,11 +234,11 @@ in "-blockchaincfg=${configFile}" } \ -datadir=${cfg.dataDir} \ - ${optionalString (cfg.sync != false) "-sync"} \ - ${optionalString (cfg.certFile != null) "-certfile=${toString cfg.certFile}"} \ - ${optionalString (cfg.debug != false) "-debug"} \ - ${optionalString (cfg.internal != null) "-internal=${toString cfg.internal}"} \ - ${optionalString (cfg.public != null) "-public=${toString cfg.public}"} \ + ${lib.optionalString (cfg.sync != false) "-sync"} \ + ${lib.optionalString (cfg.certFile != null) "-certfile=${toString cfg.certFile}"} \ + ${lib.optionalString (cfg.debug != false) "-debug"} \ + ${lib.optionalString (cfg.internal != null) "-internal=${toString cfg.internal}"} \ + ${lib.optionalString (cfg.public != null) "-public=${toString cfg.public}"} \ ${toString cfg.extraCmdLineOptions} ''; Restart = "on-failure"; @@ -251,23 +248,23 @@ in } ) )) eachBlockbook; - systemd.tmpfiles.rules = flatten (mapAttrsToList (blockbookName: cfg: [ + systemd.tmpfiles.rules = lib.flatten (lib.mapAttrsToList (blockbookName: cfg: [ "d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -" "d ${cfg.dataDir}/static 0750 ${cfg.user} ${cfg.group} - -" ]) eachBlockbook); - users.users = mapAttrs' (blockbookName: cfg: ( - nameValuePair "blockbook-frontend-${blockbookName}" { + users.users = lib.mapAttrs' (blockbookName: cfg: ( + lib.nameValuePair "blockbook-frontend-${blockbookName}" { name = cfg.user; group = cfg.group; home = cfg.dataDir; isSystemUser = true; })) eachBlockbook; - users.groups = mapAttrs' (instanceName: cfg: ( - nameValuePair "${cfg.group}" { })) eachBlockbook; + users.groups = lib.mapAttrs' (instanceName: cfg: ( + lib.nameValuePair "${cfg.group}" { })) eachBlockbook; }; - meta.maintainers = with maintainers; [ _1000101 ]; + meta.maintainers = with lib.maintainers; [ _1000101 ]; } diff --git a/nixos/modules/services/networking/blocky.nix b/nixos/modules/services/networking/blocky.nix index 4bc6ffa3f46a..1260d9da7ac2 100644 --- a/nixos/modules/services/networking/blocky.nix +++ b/nixos/modules/services/networking/blocky.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.blocky; @@ -10,11 +7,11 @@ let in { options.services.blocky = { - enable = mkEnableOption "blocky, a fast and lightweight DNS proxy as ad-blocker for local network with many features"; + enable = lib.mkEnableOption "blocky, a fast and lightweight DNS proxy as ad-blocker for local network with many features"; - package = mkPackageOption pkgs "blocky" { }; + package = lib.mkPackageOption pkgs "blocky" { }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; description = '' @@ -25,14 +22,14 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.blocky = { description = "A DNS proxy and ad-blocker for the local network"; wantedBy = [ "multi-user.target" ]; serviceConfig = { DynamicUser = true; - ExecStart = "${getExe cfg.package} --config ${configFile}"; + ExecStart = "${lib.getExe cfg.package} --config ${configFile}"; Restart = "on-failure"; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; diff --git a/nixos/modules/services/networking/cgit.nix b/nixos/modules/services/networking/cgit.nix index 910db84a2641..208979364684 100644 --- a/nixos/modules/services/networking/cgit.nix +++ b/nixos/modules/services/networking/cgit.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ...}: - -with lib; - let cfgs = config.services.cgit; - settingType = with types; oneOf [ bool int str ]; - repeatedSettingType = with types; oneOf [ settingType (listOf settingType) ]; + settingType = with lib.types; oneOf [ bool int str ]; + repeatedSettingType = with lib.types; oneOf [ settingType (listOf settingType) ]; - genAttrs' = names: f: listToAttrs (map f names); + genAttrs' = names: f: lib.listToAttrs (map f names); regexEscape = let @@ -20,9 +17,9 @@ let " " # \f / 0x0C ]; in - replaceStrings special (map (c: "\\${c}") special); + lib.replaceStrings special (map (c: "\\${c}") special); - stripLocation = cfg: removeSuffix "/" cfg.nginx.location; + stripLocation = cfg: lib.removeSuffix "/" cfg.nginx.location; regexLocation = cfg: regexEscape (stripLocation cfg); @@ -47,29 +44,29 @@ let # list value as multiple lines (for "readme" for example) cgitrcEntry = name: value: - if isList value then + if lib.isList value then map (cgitrcLine name) value else [ (cgitrcLine name value) ]; mkCgitrc = cfg: pkgs.writeText "cgitrc" '' # global settings - ${concatStringsSep "\n" ( - flatten (mapAttrsToList + ${lib.concatStringsSep "\n" ( + lib.flatten (lib.mapAttrsToList cgitrcEntry ({ virtual-root = cfg.nginx.location; } // cfg.settings) ) ) } - ${optionalString (cfg.scanPath != null) (cgitrcLine "scan-path" cfg.scanPath)} + ${lib.optionalString (cfg.scanPath != null) (cgitrcLine "scan-path" cfg.scanPath)} # repository settings - ${concatStrings ( - mapAttrsToList + ${lib.concatStrings ( + lib.mapAttrsToList (url: settings: '' ${cgitrcLine "repo.url" url} - ${concatStringsSep "\n" ( - mapAttrsToList (name: cgitrcLine "repo.${name}") settings + ${lib.concatStringsSep "\n" ( + lib.mapAttrsToList (name: cgitrcLine "repo.${name}") settings ) } '') @@ -90,32 +87,32 @@ let in { options = { - services.cgit = mkOption { + services.cgit = lib.mkOption { description = "Configure cgit instances."; default = {}; - type = types.attrsOf (types.submodule ({ config, ... }: { + type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: { options = { - enable = mkEnableOption "cgit"; + enable = lib.mkEnableOption "cgit"; - package = mkPackageOption pkgs "cgit" {}; + package = lib.mkPackageOption pkgs "cgit" {}; - nginx.virtualHost = mkOption { + nginx.virtualHost = lib.mkOption { description = "VirtualHost to serve cgit on, defaults to the attribute name."; - type = types.str; + type = lib.types.str; default = config._module.args.name; example = "git.example.com"; }; - nginx.location = mkOption { + nginx.location = lib.mkOption { description = "Location to serve cgit under."; - type = types.str; + type = lib.types.str; default = "/"; example = "/git/"; }; - repos = mkOption { + repos = lib.mkOption { description = "cgit repository settings, see cgitrc(5)"; - type = with types; attrsOf (attrsOf settingType); + type = with lib.types; attrsOf (attrsOf settingType); default = {}; example = { blah = { @@ -125,18 +122,18 @@ in }; }; - scanPath = mkOption { + scanPath = lib.mkOption { description = "A path which will be scanned for repositories."; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; example = "/var/lib/git"; }; - settings = mkOption { + settings = lib.mkOption { description = "cgit configuration, see cgitrc(5)"; - type = types.attrsOf repeatedSettingType; + type = lib.types.attrsOf repeatedSettingType; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { enable-follow-links = true; source-filter = "''${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; @@ -144,21 +141,21 @@ in ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { description = "These lines go to the end of cgitrc verbatim."; - type = types.lines; + type = lib.types.lines; default = ""; }; - user = mkOption { + user = lib.mkOption { description = "User to run the cgit service as."; - type = types.str; + type = lib.types.str; default = "cgit"; }; - group = mkOption { + group = lib.mkOption { description = "Group to run the cgit service as."; - type = types.str; + type = lib.types.str; default = "cgit"; }; }; @@ -166,13 +163,13 @@ in }; }; - config = mkIf (any (cfg: cfg.enable) (attrValues cfgs)) { - assertions = mapAttrsToList (vhost: cfg: { + config = lib.mkIf (lib.any (cfg: cfg.enable) (lib.attrValues cfgs)) { + assertions = lib.mapAttrsToList (vhost: cfg: { assertion = !cfg.enable || (cfg.scanPath == null) != (cfg.repos == {}); message = "Exactly one of services.cgit.${vhost}.scanPath or services.cgit.${vhost}.repos must be set."; }) cfgs; - users = mkMerge (flip mapAttrsToList cfgs (_: cfg: { + users = lib.mkMerge (lib.flip lib.mapAttrsToList cfgs (_: cfg: { users.${cfg.user} = { isSystemUser = true; inherit (cfg) group; @@ -180,23 +177,23 @@ in groups.${cfg.group} = { }; })); - services.fcgiwrap.instances = flip mapAttrs' cfgs (name: cfg: - nameValuePair "cgit-${name}" { + services.fcgiwrap.instances = lib.flip lib.mapAttrs' cfgs (name: cfg: + lib.nameValuePair "cgit-${name}" { process = { inherit (cfg) user group; }; socket = { inherit (config.services.nginx) user group; }; } ); - systemd.services = flip mapAttrs' cfgs (name: cfg: - nameValuePair (fcgiwrapUnitName name) - (mkIf (cfg.repos != { }) { + systemd.services = lib.flip lib.mapAttrs' cfgs (name: cfg: + lib.nameValuePair (fcgiwrapUnitName name) + (lib.mkIf (cfg.repos != { }) { serviceConfig.RuntimeDirectory = fcgiwrapUnitName name; preStart = '' - GIT_PROJECT_ROOT=${escapeShellArg (gitProjectRoot name cfg)} + GIT_PROJECT_ROOT=${lib.escapeShellArg (gitProjectRoot name cfg)} mkdir -p "$GIT_PROJECT_ROOT" cd "$GIT_PROJECT_ROOT" - ${concatLines (flip mapAttrsToList cfg.repos (name: repo: '' - ln -s ${escapeShellArg repo.path} ${escapeShellArg name} + ${lib.concatLines (lib.flip lib.mapAttrsToList cfg.repos (name: repo: '' + ln -s ${lib.escapeShellArg repo.path} ${lib.escapeShellArg name} ''))} ''; } @@ -204,12 +201,12 @@ in services.nginx.enable = true; - services.nginx.virtualHosts = mkMerge (mapAttrsToList (name: cfg: { + services.nginx.virtualHosts = lib.mkMerge (lib.mapAttrsToList (name: cfg: { ${cfg.nginx.virtualHost} = { locations = ( genAttrs' [ "cgit.css" "cgit.png" "favicon.ico" "robots.txt" ] - (fileName: nameValuePair "= ${stripLocation cfg}/${fileName}" { + (fileName: lib.nameValuePair "= ${stripLocation cfg}/${fileName}" { extraConfig = '' alias ${cfg.package}/cgit/${fileName}; ''; diff --git a/nixos/modules/services/networking/chisel-server.nix b/nixos/modules/services/networking/chisel-server.nix index 9c6391701faf..2b585c22f304 100644 --- a/nixos/modules/services/networking/chisel-server.nix +++ b/nixos/modules/services/networking/chisel-server.nix @@ -1,69 +1,66 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.chisel-server; in { options = { services.chisel-server = { - enable = mkEnableOption "Chisel Tunnel Server"; - host = mkOption { + enable = lib.mkEnableOption "Chisel Tunnel Server"; + host = lib.mkOption { description = "Address to listen on, falls back to 0.0.0.0"; - type = with types; nullOr str; + type = with lib.types; nullOr str; default = null; example = "[::1]"; }; - port = mkOption { + port = lib.mkOption { description = "Port to listen on, falls back to 8080"; - type = with types; nullOr port; + type = with lib.types; nullOr port; default = null; }; - authfile = mkOption { + authfile = lib.mkOption { description = "Path to auth.json file"; - type = with types; nullOr path; + type = with lib.types; nullOr path; default = null; }; - keepalive = mkOption { + keepalive = lib.mkOption { description = "Keepalive interval, falls back to 25s"; - type = with types; nullOr str; + type = with lib.types; nullOr str; default = null; example = "5s"; }; - backend = mkOption { + backend = lib.mkOption { description = "HTTP server to proxy normal requests to"; - type = with types; nullOr str; + type = with lib.types; nullOr str; default = null; example = "http://127.0.0.1:8888"; }; - socks5 = mkOption { + socks5 = lib.mkOption { description = "Allow clients access to internal SOCKS5 proxy"; - type = types.bool; + type = lib.types.bool; default = false; }; - reverse = mkOption { + reverse = lib.mkOption { description = "Allow clients reverse port forwarding"; - type = types.bool; + type = lib.types.bool; default = false; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.chisel-server = { description = "Chisel Tunnel Server"; wantedBy = [ "network-online.target" ]; serviceConfig = { - ExecStart = "${pkgs.chisel}/bin/chisel server " + concatStringsSep " " ( - optional (cfg.host != null) "--host ${cfg.host}" - ++ optional (cfg.port != null) "--port ${builtins.toString cfg.port}" - ++ optional (cfg.authfile != null) "--authfile ${cfg.authfile}" - ++ optional (cfg.keepalive != null) "--keepalive ${cfg.keepalive}" - ++ optional (cfg.backend != null) "--backend ${cfg.backend}" - ++ optional cfg.socks5 "--socks5" - ++ optional cfg.reverse "--reverse" + ExecStart = "${pkgs.chisel}/bin/chisel server " + lib.concatStringsSep " " ( + lib.optional (cfg.host != null) "--host ${cfg.host}" + ++ lib.optional (cfg.port != null) "--port ${builtins.toString cfg.port}" + ++ lib.optional (cfg.authfile != null) "--authfile ${cfg.authfile}" + ++ lib.optional (cfg.keepalive != null) "--keepalive ${cfg.keepalive}" + ++ lib.optional (cfg.backend != null) "--backend ${cfg.backend}" + ++ lib.optional cfg.socks5 "--socks5" + ++ lib.optional cfg.reverse "--reverse" ); # Security Hardening @@ -95,5 +92,5 @@ in { }; }; - meta.maintainers = with maintainers; [ clerie ]; + meta.maintainers = with lib.maintainers; [ clerie ]; } diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix index f50031eb2ec4..6aaaf6295068 100644 --- a/nixos/modules/services/networking/cjdns.nix +++ b/nixos/modules/services/networking/cjdns.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let pkg = pkgs.cjdns; @@ -11,28 +8,28 @@ let connectToSubmodule = { ... }: { options = - { password = mkOption { - type = types.str; + { password = lib.mkOption { + type = lib.types.str; description = "Authorized password to the opposite end of the tunnel."; }; - login = mkOption { + login = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = "(optional) name your peer has for you"; }; - peerName = mkOption { + peerName = lib.mkOption { default = ""; - type = types.str; + type = lib.types.str; description = "(optional) human-readable name for peer"; }; - publicKey = mkOption { - type = types.str; + publicKey = lib.mkOption { + type = lib.types.str; description = "Public key at the opposite end of the tunnel."; }; - hostname = mkOption { + hostname = lib.mkOption { default = ""; example = "foobar.hype"; - type = types.str; + type = lib.types.str; description = "Optional hostname to add to /etc/hosts; prevents reverse lookup failures."; }; }; @@ -41,16 +38,16 @@ let # Additional /etc/hosts entries for peers with an associated hostname cjdnsExtraHosts = pkgs.runCommand "cjdns-hosts" {} '' exec >$out - ${concatStringsSep "\n" (mapAttrsToList (k: v: - optionalString (v.hostname != "") + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: + lib.optionalString (v.hostname != "") "echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}") (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))} ''; parseModules = x: - x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; }; + x // { connectTo = lib.mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; }; - cjdrouteConf = builtins.toJSON ( recursiveUpdate { + cjdrouteConf = builtins.toJSON ( lib.recursiveUpdate { admin = { bind = cfg.admin.bind; password = "@CJDNS_ADMIN_PASSWORD@"; @@ -84,8 +81,8 @@ in services.cjdns = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable the cjdns network encryption @@ -95,8 +92,8 @@ in ''; }; - extraConfig = mkOption { - type = types.attrs; + extraConfig = lib.mkOption { + type = lib.types.attrs; default = {}; example = { router.interface.tunDevice = "tun10"; }; description = '' @@ -105,8 +102,8 @@ in ''; }; - confFile = mkOption { - type = types.nullOr types.path; + confFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/etc/cjdroute.conf"; description = '' @@ -114,8 +111,8 @@ in ''; }; - authorizedPasswords = mkOption { - type = types.listOf types.str; + authorizedPasswords = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "snyrfgkqsc98qh1y4s5hbu0j57xw5s0" @@ -129,8 +126,8 @@ in }; admin = { - bind = mkOption { - type = types.str; + bind = lib.mkOption { + type = lib.types.str; default = "127.0.0.1:11234"; description = '' Bind the administration port to this address and port. @@ -139,18 +136,18 @@ in }; UDPInterface = { - bind = mkOption { - type = types.str; + bind = lib.mkOption { + type = lib.types.str; default = ""; example = "192.168.1.32:43211"; description = '' Address and port to bind UDP tunnels to. ''; }; - connectTo = mkOption { - type = types.attrsOf ( types.submodule ( connectToSubmodule ) ); + connectTo = lib.mkOption { + type = lib.types.attrsOf ( lib.types.submodule ( connectToSubmodule ) ); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "192.168.1.1:27313" = { hostname = "homer.hype"; @@ -166,8 +163,8 @@ in }; ETHInterface = { - bind = mkOption { - type = types.str; + bind = lib.mkOption { + type = lib.types.str; default = ""; example = "eth0"; description = '' @@ -176,8 +173,8 @@ in ''; }; - beacon = mkOption { - type = types.int; + beacon = lib.mkOption { + type = lib.types.int; default = 2; description = '' Auto-connect to other cjdns nodes on the same network. @@ -193,10 +190,10 @@ in ''; }; - connectTo = mkOption { - type = types.attrsOf ( types.submodule ( connectToSubmodule ) ); + connectTo = lib.mkOption { + type = lib.types.attrsOf ( lib.types.submodule ( connectToSubmodule ) ); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "01:02:03:04:05:06" = { hostname = "homer.hype"; @@ -212,8 +209,8 @@ in }; }; - addExtraHosts = mkOption { - type = types.bool; + addExtraHosts = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to add cjdns peers with an associated hostname to @@ -226,7 +223,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "tun" ]; @@ -238,7 +235,7 @@ in after = [ "network-online.target" ]; bindsTo = [ "network-online.target" ]; - preStart = optionalString (cfg.confFile == null) '' + preStart = lib.optionalString (cfg.confFile == null) '' [ -e /etc/cjdns.keys ] && source /etc/cjdns.keys if [ -z "$CJDNS_PRIVATE_KEY" ]; then @@ -277,13 +274,13 @@ in CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SETUID"; ProtectSystem = true; # Doesn't work on i686, causing service to fail - MemoryDenyWriteExecute = !pkgs.stdenv.isi686; + MemoryDenyWriteExecute = !pkgs.stdenv.hostPlatform.isi686; ProtectHome = true; PrivateTmp = true; }; }; - networking.hostFiles = mkIf cfg.addExtraHosts [ cjdnsExtraHosts ]; + networking.hostFiles = lib.mkIf cfg.addExtraHosts [ cjdnsExtraHosts ]; assertions = [ { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null ); diff --git a/nixos/modules/services/networking/clatd.nix b/nixos/modules/services/networking/clatd.nix index de6cde4e979c..09f7fdfb6e9e 100644 --- a/nixos/modules/services/networking/clatd.nix +++ b/nixos/modules/services/networking/clatd.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.clatd; @@ -11,16 +9,16 @@ in { options = { services.clatd = { - enable = mkEnableOption "clatd"; + enable = lib.mkEnableOption "clatd"; - package = mkPackageOption pkgs "clatd" { }; + package = lib.mkPackageOption pkgs "clatd" { }; - settings = mkOption { - type = types.submodule ({ name, ... }: { + settings = lib.mkOption { + type = lib.types.submodule ({ name, ... }: { freeformType = settingsFormat.type; }); default = { }; - example = literalExpression '' + example = lib.literalExpression '' { plat-prefix = "64:ff9b::/96"; } @@ -32,7 +30,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.clatd = { description = "464XLAT CLAT daemon"; documentation = [ "man:clatd(8)" ]; diff --git a/nixos/modules/services/networking/cloudflare-dyndns.nix b/nixos/modules/services/networking/cloudflare-dyndns.nix index 9495c8dcaf81..0f035362742e 100644 --- a/nixos/modules/services/networking/cloudflare-dyndns.nix +++ b/nixos/modules/services/networking/cloudflare-dyndns.nix @@ -1,19 +1,16 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.cloudflare-dyndns; in { options = { services.cloudflare-dyndns = { - enable = mkEnableOption "Cloudflare Dynamic DNS Client"; + enable = lib.mkEnableOption "Cloudflare Dynamic DNS Client"; - package = mkPackageOption pkgs "cloudflare-dyndns" { }; + package = lib.mkPackageOption pkgs "cloudflare-dyndns" { }; - apiTokenFile = mkOption { - type = types.nullOr types.str; + apiTokenFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The path to a file containing the CloudFlare API token. @@ -22,16 +19,16 @@ in ''; }; - domains = mkOption { - type = types.listOf types.str; + domains = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' List of domain names to update records for. ''; }; - frequency = mkOption { - type = types.nullOr types.str; + frequency = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "*:0/5"; description = '' Run cloudflare-dyndns with the given frequency (see @@ -40,32 +37,32 @@ in ''; }; - proxied = mkOption { - type = types.bool; + proxied = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether this is a DNS-only record, or also being proxied through CloudFlare. ''; }; - ipv4 = mkOption { - type = types.bool; + ipv4 = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable setting IPv4 A records. ''; }; - ipv6 = mkOption { - type = types.bool; + ipv6 = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable setting IPv6 AAAA records. ''; }; - deleteMissing = mkOption { - type = types.bool; + deleteMissing = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to delete the record when no IP address is found. @@ -74,7 +71,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.cloudflare-dyndns = { description = "CloudFlare Dynamic DNS Client"; after = [ "network.target" ]; @@ -94,12 +91,12 @@ in args = [ "--cache-file /var/lib/cloudflare-dyndns/ip.cache" ] ++ (if cfg.ipv4 then [ "-4" ] else [ "-no-4" ]) ++ (if cfg.ipv6 then [ "-6" ] else [ "-no-6" ]) - ++ optional cfg.deleteMissing "--delete-missing" - ++ optional cfg.proxied "--proxied"; + ++ lib.optional cfg.deleteMissing "--delete-missing" + ++ lib.optional cfg.proxied "--proxied"; in - "${getExe cfg.package} ${toString args}"; + "${lib.getExe cfg.package} ${toString args}"; }; - } // optionalAttrs (cfg.frequency != null) { + } // lib.optionalAttrs (cfg.frequency != null) { startAt = cfg.frequency; }; }; diff --git a/nixos/modules/services/networking/cloudflared.nix b/nixos/modules/services/networking/cloudflared.nix index c0d1012ffb80..7023e79d31f9 100644 --- a/nixos/modules/services/networking/cloudflared.nix +++ b/nixos/modules/services/networking/cloudflared.nix @@ -1,13 +1,10 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.cloudflared; originRequest = { - connectTimeout = mkOption { - type = with types; nullOr str; + connectTimeout = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = "30s"; description = '' @@ -15,8 +12,8 @@ let ''; }; - tlsTimeout = mkOption { - type = with types; nullOr str; + tlsTimeout = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = "10s"; description = '' @@ -24,8 +21,8 @@ let ''; }; - tcpKeepAlive = mkOption { - type = with types; nullOr str; + tcpKeepAlive = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = "30s"; description = '' @@ -33,8 +30,8 @@ let ''; }; - noHappyEyeballs = mkOption { - type = with types; nullOr bool; + noHappyEyeballs = lib.mkOption { + type = with lib.types; nullOr bool; default = null; example = false; description = '' @@ -42,8 +39,8 @@ let ''; }; - keepAliveConnections = mkOption { - type = with types; nullOr int; + keepAliveConnections = lib.mkOption { + type = with lib.types; nullOr int; default = null; example = 100; description = '' @@ -51,8 +48,8 @@ let ''; }; - keepAliveTimeout = mkOption { - type = with types; nullOr str; + keepAliveTimeout = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = "1m30s"; description = '' @@ -60,8 +57,8 @@ let ''; }; - httpHostHeader = mkOption { - type = with types; nullOr str; + httpHostHeader = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = ""; description = '' @@ -69,8 +66,8 @@ let ''; }; - originServerName = mkOption { - type = with types; nullOr str; + originServerName = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = ""; description = '' @@ -78,8 +75,8 @@ let ''; }; - caPool = mkOption { - type = with types; nullOr (either str path); + caPool = lib.mkOption { + type = with lib.types; nullOr (either str path); default = null; example = ""; description = '' @@ -87,8 +84,8 @@ let ''; }; - noTLSVerify = mkOption { - type = with types; nullOr bool; + noTLSVerify = lib.mkOption { + type = with lib.types; nullOr bool; default = null; example = false; description = '' @@ -96,8 +93,8 @@ let ''; }; - disableChunkedEncoding = mkOption { - type = with types; nullOr bool; + disableChunkedEncoding = lib.mkOption { + type = with lib.types; nullOr bool; default = null; example = false; description = '' @@ -105,8 +102,8 @@ let ''; }; - proxyAddress = mkOption { - type = with types; nullOr str; + proxyAddress = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = "127.0.0.1"; description = '' @@ -114,8 +111,8 @@ let ''; }; - proxyPort = mkOption { - type = with types; nullOr int; + proxyPort = lib.mkOption { + type = with lib.types; nullOr int; default = null; example = 0; description = '' @@ -123,8 +120,8 @@ let ''; }; - proxyType = mkOption { - type = with types; nullOr (enum [ "" "socks" ]); + proxyType = lib.mkOption { + type = with lib.types; nullOr (enum [ "" "socks" ]); default = null; example = ""; description = '' @@ -138,32 +135,32 @@ let in { options.services.cloudflared = { - enable = mkEnableOption "Cloudflare Tunnel client daemon (formerly Argo Tunnel)"; + enable = lib.mkEnableOption "Cloudflare Tunnel client daemon (formerly Argo Tunnel)"; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "cloudflared"; description = "User account under which Cloudflared runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "cloudflared"; description = "Group under which cloudflared runs."; }; - package = mkPackageOption pkgs "cloudflared" { }; + package = lib.mkPackageOption pkgs "cloudflared" { }; - tunnels = mkOption { + tunnels = lib.mkOption { description = '' Cloudflare tunnels. ''; - type = types.attrsOf (types.submodule ({ name, ... }: { + type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { options = { inherit originRequest; - credentialsFile = mkOption { - type = types.str; + credentialsFile = lib.mkOption { + type = lib.types.str; description = '' Credential file. @@ -172,8 +169,8 @@ in }; warp-routing = { - enabled = mkOption { - type = with types; nullOr bool; + enabled = lib.mkOption { + type = with lib.types; nullOr bool; default = null; description = '' Enable warp routing. @@ -183,8 +180,8 @@ in }; }; - default = mkOption { - type = types.str; + default = lib.mkOption { + type = lib.types.str; description = '' Catch-all service if no ingress matches. @@ -193,13 +190,13 @@ in example = "http_status:404"; }; - ingress = mkOption { - type = with types; attrsOf (either str (submodule ({ hostname, ... }: { + ingress = lib.mkOption { + type = with lib.types; attrsOf (either str (submodule ({ hostname, ... }: { options = { inherit originRequest; - service = mkOption { - type = with types; nullOr str; + service = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Service to pass the traffic. @@ -209,8 +206,8 @@ in example = "http://localhost:80, tcp://localhost:8000, unix:/home/production/echo.sock, hello_world or http_status:404"; }; - path = mkOption { - type = with types; nullOr str; + path = lib.mkOption { + type = with lib.types; nullOr str; default = null; description = '' Path filter. @@ -251,11 +248,11 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.targets = - mapAttrs' + lib.mapAttrs' (name: tunnel: - nameValuePair "cloudflared-tunnel-${name}" { + lib.nameValuePair "cloudflared-tunnel-${name}" { description = "Cloudflare tunnel '${name}' target"; requires = [ "cloudflared-tunnel-${name}.service" ]; after = [ "cloudflared-tunnel-${name}.service" ]; @@ -265,13 +262,13 @@ in config.services.cloudflared.tunnels; systemd.services = - mapAttrs' + lib.mapAttrs' (name: tunnel: let filterConfig = lib.attrsets.filterAttrsRecursive (_: v: ! builtins.elem v [ null [ ] { } ]); - filterIngressSet = filterAttrs (_: v: builtins.typeOf v == "set"); - filterIngressStr = filterAttrs (_: v: builtins.typeOf v == "string"); + filterIngressSet = lib.filterAttrs (_: v: builtins.typeOf v == "set"); + filterIngressStr = lib.filterAttrs (_: v: builtins.typeOf v == "string"); ingressesSet = filterIngressSet tunnel.ingress; ingressesStr = filterIngressStr tunnel.ingress; @@ -285,21 +282,21 @@ in (map (key: { hostname = key; - } // getAttr key (filterConfig (filterConfig ingressesSet))) - (attrNames ingressesSet)) + } // lib.getAttr key (filterConfig (filterConfig ingressesSet))) + (lib.attrNames ingressesSet)) ++ (map (key: { hostname = key; - service = getAttr key ingressesStr; + service = lib.getAttr key ingressesStr; }) - (attrNames ingressesStr)) + (lib.attrNames ingressesStr)) ++ [{ service = tunnel.default; }]; }; mkConfigFile = pkgs.writeText "cloudflared.yml" (builtins.toJSON fullConfig); in - nameValuePair "cloudflared-tunnel-${name}" ({ + lib.nameValuePair "cloudflared-tunnel-${name}" ({ after = [ "network.target" "network-online.target" ]; wants = [ "network.target" "network-online.target" ]; wantedBy = [ "multi-user.target" ]; @@ -313,17 +310,17 @@ in ) config.services.cloudflared.tunnels; - users.users = mkIf (cfg.user == "cloudflared") { + users.users = lib.mkIf (cfg.user == "cloudflared") { cloudflared = { group = cfg.group; isSystemUser = true; }; }; - users.groups = mkIf (cfg.group == "cloudflared") { + users.groups = lib.mkIf (cfg.group == "cloudflared") { cloudflared = { }; }; }; - meta.maintainers = with maintainers; [ bbigras anpin ]; + meta.maintainers = with lib.maintainers; [ bbigras anpin ]; } diff --git a/nixos/modules/services/networking/cntlm.nix b/nixos/modules/services/networking/cntlm.nix index 16e9c3bb87b5..4615380c41eb 100644 --- a/nixos/modules/services/networking/cntlm.nix +++ b/nixos/modules/services/networking/cntlm.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.cntlm; @@ -16,11 +13,11 @@ let Username ${cfg.username} Domain ${cfg.domain} Password ${cfg.password} - ${optionalString (cfg.netbios_hostname != "") "Workstation ${cfg.netbios_hostname}"} - ${concatMapStrings (entry: "Proxy ${entry}\n") cfg.proxy} - ${optionalString (cfg.noproxy != []) "NoProxy ${concatStringsSep ", " cfg.noproxy}"} + ${lib.optionalString (cfg.netbios_hostname != "") "Workstation ${cfg.netbios_hostname}"} + ${lib.concatMapStrings (entry: "Proxy ${entry}\n") cfg.proxy} + ${lib.optionalString (cfg.noproxy != []) "NoProxy ${lib.concatStringsSep ", " cfg.noproxy}"} - ${concatMapStrings (port: '' + ${lib.concatMapStrings (port: '' Listen ${toString port} '') cfg.port} @@ -33,36 +30,36 @@ in options.services.cntlm = { - enable = mkEnableOption "cntlm, which starts a local proxy"; + enable = lib.mkEnableOption "cntlm, which starts a local proxy"; - username = mkOption { - type = types.str; + username = lib.mkOption { + type = lib.types.str; description = '' Proxy account name, without the possibility to include domain name ('at' sign is interpreted literally). ''; }; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; description = "Proxy account domain/workgroup name."; }; - password = mkOption { + password = lib.mkOption { default = "/etc/cntlm.password"; - type = types.str; + type = lib.types.str; description = "Proxy account password. Note: use chmod 0600 on /etc/cntlm.password for security."; }; - netbios_hostname = mkOption { - type = types.str; + netbios_hostname = lib.mkOption { + type = lib.types.str; default = ""; description = '' The hostname of your machine. ''; }; - proxy = mkOption { - type = types.listOf types.str; + proxy = lib.mkOption { + type = lib.types.listOf lib.types.str; description = '' A list of NTLM/NTLMv2 authenticating HTTP proxies. @@ -73,29 +70,29 @@ in example = [ "proxy.example.com:81" ]; }; - noproxy = mkOption { + noproxy = lib.mkOption { description = '' A list of domains where the proxy is skipped. ''; default = []; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; example = [ "*.example.com" "example.com" ]; }; - port = mkOption { + port = lib.mkOption { default = [3128]; - type = types.listOf types.port; + type = lib.types.listOf lib.types.port; description = "Specifies on which ports the cntlm daemon listens."; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Additional config appended to the end of the generated {file}`cntlm.conf`."; }; - configText = mkOption { - type = types.lines; + configText = lib.mkOption { + type = lib.types.lines; default = ""; description = "Verbatim contents of {file}`cntlm.conf`."; }; @@ -104,7 +101,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.cntlm = { description = "CNTLM is an NTLM / NTLM Session Response / NTLMv2 authenticating HTTP proxy"; after = [ "network.target" ]; diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 2d9b10514a72..855d3872aa62 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, utils, ... }: - -with lib; let dataDir = "/var/lib/consul"; @@ -16,8 +14,8 @@ let configFiles = [ "/etc/consul.json" "/etc/consul-addrs.json" ] ++ cfg.extraConfigFiles; - devices = attrValues (filterAttrs (_: i: i != null) cfg.interface); - systemdDevices = forEach devices + devices = lib.attrValues (lib.filterAttrs (_: i: i != null) cfg.interface); + systemdDevices = lib.forEach devices (i: "sys-subsystem-net-devices-${utils.escapeSystemdPath i}.device"); in { @@ -25,26 +23,26 @@ in services.consul = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enables the consul daemon. ''; }; - package = mkPackageOption pkgs "consul" { }; + package = lib.mkPackageOption pkgs "consul" { }; - webUi = mkOption { - type = types.bool; + webUi = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enables the web interface on the consul http port. ''; }; - leaveOnStop = mkOption { - type = types.bool; + leaveOnStop = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, causes a leave action to be sent when closing consul. @@ -57,16 +55,16 @@ in interface = { - advertise = mkOption { - type = types.nullOr types.str; + advertise = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The name of the interface to pull the advertise_addr from. ''; }; - bind = mkOption { - type = types.nullOr types.str; + bind = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' The name of the interface to pull the bind_addr from. @@ -74,16 +72,16 @@ in }; }; - forceAddrFamily = mkOption { - type = types.enum [ "any" "ipv4" "ipv6" ]; + forceAddrFamily = lib.mkOption { + type = lib.types.enum [ "any" "ipv4" "ipv6" ]; default = "any"; description = '' Whether to bind ipv4/ipv6 or both kind of addresses. ''; }; - forceIpv4 = mkOption { - type = types.nullOr types.bool; + forceIpv4 = lib.mkOption { + type = lib.types.nullOr lib.types.bool; default = null; description = '' Deprecated: Use consul.forceAddrFamily instead. @@ -91,26 +89,26 @@ in ''; }; - dropPrivileges = mkOption { - type = types.bool; + dropPrivileges = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether the consul agent should be run as a non-root consul user. ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = { }; - type = types.attrsOf types.anything; + type = lib.types.attrsOf lib.types.anything; description = '' Extra configuration options which are serialized to json and added to the config.json file. ''; }; - extraConfigFiles = mkOption { + extraConfigFiles = lib.mkOption { default = [ ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = '' Additional configuration files to pass to consul NOTE: These will not trigger the service to be restarted when altered. @@ -118,32 +116,32 @@ in }; alerts = { - enable = mkEnableOption "consul-alerts"; + enable = lib.mkEnableOption "consul-alerts"; - package = mkPackageOption pkgs "consul-alerts" { }; + package = lib.mkPackageOption pkgs "consul-alerts" { }; - listenAddr = mkOption { + listenAddr = lib.mkOption { description = "Api listening address."; default = "localhost:9000"; - type = types.str; + type = lib.types.str; }; - consulAddr = mkOption { + consulAddr = lib.mkOption { description = "Consul api listening address"; default = "localhost:8500"; - type = types.str; + type = lib.types.str; }; - watchChecks = mkOption { + watchChecks = lib.mkOption { description = "Whether to enable check watcher."; default = true; - type = types.bool; + type = lib.types.bool; }; - watchEvents = mkOption { + watchEvents = lib.mkOption { description = "Whether to enable event watcher."; default = true; - type = types.bool; + type = lib.types.bool; }; }; @@ -151,8 +149,8 @@ in }; - config = mkIf cfg.enable ( - mkMerge [{ + config = lib.mkIf cfg.enable ( + lib.mkMerge [{ users.users.consul = { description = "Consul agent daemon user"; @@ -182,18 +180,18 @@ in after = [ "network.target" ] ++ systemdDevices; bindsTo = systemdDevices; restartTriggers = [ config.environment.etc."consul.json".source ] - ++ mapAttrsToList (_: d: d.source) - (filterAttrs (n: _: hasPrefix "consul.d/" n) config.environment.etc); + ++ lib.mapAttrsToList (_: d: d.source) + (lib.filterAttrs (n: _: lib.hasPrefix "consul.d/" n) config.environment.etc); serviceConfig = { ExecStart = "@${lib.getExe cfg.package} consul agent -config-dir /etc/consul.d" - + concatMapStrings (n: " -config-file ${n}") configFiles; + + lib.concatMapStrings (n: " -config-file ${n}") configFiles; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; PermissionsStartOnly = true; User = if cfg.dropPrivileges then "consul" else null; Restart = "on-failure"; TimeoutStartSec = "infinity"; - } // (optionalAttrs (cfg.leaveOnStop) { + } // (lib.optionalAttrs (cfg.leaveOnStop) { ExecStop = "${lib.getExe cfg.package} leave"; }); @@ -231,8 +229,8 @@ in echo "{" > /etc/consul-addrs.json delim=" " '' - + concatStrings (flip mapAttrsToList cfg.interface (name: i: - optionalString (i != null) '' + + lib.concatStrings (lib.flip lib.mapAttrsToList cfg.interface (name: i: + lib.optionalString (i != null) '' echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json delim="," '')) @@ -243,11 +241,11 @@ in } # deprecated - (mkIf (cfg.forceIpv4 != null && cfg.forceIpv4) { + (lib.mkIf (cfg.forceIpv4 != null && cfg.forceIpv4) { services.consul.forceAddrFamily = "ipv4"; }) - (mkIf (cfg.alerts.enable) { + (lib.mkIf (cfg.alerts.enable) { systemd.services.consul-alerts = { wantedBy = [ "multi-user.target" ]; after = [ "consul.service" ]; @@ -259,8 +257,8 @@ in ${lib.getExe cfg.alerts.package} start \ --alert-addr=${cfg.alerts.listenAddr} \ --consul-addr=${cfg.alerts.consulAddr} \ - ${optionalString cfg.alerts.watchChecks "--watch-checks"} \ - ${optionalString cfg.alerts.watchEvents "--watch-events"} + ${lib.optionalString cfg.alerts.watchChecks "--watch-checks"} \ + ${lib.optionalString cfg.alerts.watchEvents "--watch-events"} ''; User = if cfg.dropPrivileges then "consul" else null; Restart = "on-failure"; diff --git a/nixos/modules/services/networking/coredns.nix b/nixos/modules/services/networking/coredns.nix index 370b9e6e8043..14602e06fe82 100644 --- a/nixos/modules/services/networking/coredns.nix +++ b/nixos/modules/services/networking/coredns.nix @@ -1,39 +1,36 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.coredns; configFile = pkgs.writeText "Corefile" cfg.config; in { options.services.coredns = { - enable = mkEnableOption "Coredns dns server"; + enable = lib.mkEnableOption "Coredns dns server"; - config = mkOption { + config = lib.mkOption { default = ""; example = '' . { whoami } ''; - type = types.lines; + type = lib.types.lines; description = '' Verbatim Corefile to use. See for details. ''; }; - package = mkPackageOption pkgs "coredns" { }; + package = lib.mkPackageOption pkgs "coredns" { }; - extraArgs = mkOption { + extraArgs = lib.mkOption { default = []; example = [ "-dns.port=53" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = "Extra arguments to pass to coredns."; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.coredns = { description = "Coredns dns server"; after = [ "network.target" ]; @@ -46,7 +43,7 @@ in { AmbientCapabilities = "cap_net_bind_service"; NoNewPrivileges = true; DynamicUser = true; - ExecStart = "${getBin cfg.package}/bin/coredns -conf=${configFile} ${lib.escapeShellArgs cfg.extraArgs}"; + ExecStart = "${lib.getBin cfg.package}/bin/coredns -conf=${configFile} ${lib.escapeShellArgs cfg.extraArgs}"; ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR1 $MAINPID"; Restart = "on-failure"; }; diff --git a/nixos/modules/services/networking/corerad.nix b/nixos/modules/services/networking/corerad.nix index 2203aa30c161..edeee881008f 100644 --- a/nixos/modules/services/networking/corerad.nix +++ b/nixos/modules/services/networking/corerad.nix @@ -1,20 +1,17 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.corerad; settingsFormat = pkgs.formats.toml {}; in { - meta.maintainers = with maintainers; [ mdlayher ]; + meta.maintainers = with lib.maintainers; [ mdlayher ]; options.services.corerad = { - enable = mkEnableOption "CoreRAD IPv6 NDP RA daemon"; + enable = lib.mkEnableOption "CoreRAD IPv6 NDP RA daemon"; - settings = mkOption { + settings = lib.mkOption { type = settingsFormat.type; - example = literalExpression '' + example = lib.literalExpression '' { interfaces = [ # eth0 is an upstream interface monitoring for IPv6 router advertisements. @@ -42,18 +39,18 @@ in { ''; }; - configFile = mkOption { - type = types.path; - example = literalExpression ''"''${pkgs.corerad}/etc/corerad/corerad.toml"''; + configFile = lib.mkOption { + type = lib.types.path; + example = lib.literalExpression ''"''${pkgs.corerad}/etc/corerad/corerad.toml"''; description = "Path to CoreRAD TOML configuration file."; }; - package = mkPackageOption pkgs "corerad" { }; + package = lib.mkPackageOption pkgs "corerad" { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Prefer the config file over settings if both are set. - services.corerad.configFile = mkDefault (settingsFormat.generate "corerad.toml" cfg.settings); + services.corerad.configFile = lib.mkDefault (settingsFormat.generate "corerad.toml" cfg.settings); systemd.services.corerad = { description = "CoreRAD IPv6 NDP RA daemon"; @@ -68,7 +65,7 @@ in { DynamicUser = true; Type = "notify"; NotifyAccess = "main"; - ExecStart = "${getBin cfg.package}/bin/corerad -c=${cfg.configFile}"; + ExecStart = "${lib.getBin cfg.package}/bin/corerad -c=${cfg.configFile}"; Restart = "on-failure"; RestartKillSignal = "SIGHUP"; }; diff --git a/nixos/modules/services/networking/coturn.nix b/nixos/modules/services/networking/coturn.nix index 3166c0dfb578..40c157d1006e 100644 --- a/nixos/modules/services/networking/coturn.nix +++ b/nixos/modules/services/networking/coturn.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.coturn; pidfile = "/run/turnserver/turnserver.pid"; @@ -8,8 +7,8 @@ listening-port=${toString cfg.listening-port} tls-listening-port=${toString cfg.tls-listening-port} alt-listening-port=${toString cfg.alt-listening-port} alt-tls-listening-port=${toString cfg.alt-tls-listening-port} -${concatStringsSep "\n" (map (x: "listening-ip=${x}") cfg.listening-ips)} -${concatStringsSep "\n" (map (x: "relay-ip=${x}") cfg.relay-ips)} +${lib.concatStringsSep "\n" (map (x: "listening-ip=${x}") cfg.listening-ips)} +${lib.concatStringsSep "\n" (map (x: "relay-ip=${x}") cfg.relay-ips)} min-port=${toString cfg.min-port} max-port=${toString cfg.max-port} ${lib.optionalString cfg.lt-cred-mech "lt-cred-mech"} @@ -40,9 +39,9 @@ ${cfg.extraConfig} in { options = { services.coturn = { - enable = mkEnableOption "coturn TURN server"; - listening-port = mkOption { - type = types.int; + enable = lib.mkEnableOption "coturn TURN server"; + listening-port = lib.mkOption { + type = lib.types.int; default = 3478; description = '' TURN listener port for UDP and TCP. @@ -50,8 +49,8 @@ in { "plain" TCP and UDP port(s), too - if allowed by configuration. ''; }; - tls-listening-port = mkOption { - type = types.int; + tls-listening-port = lib.mkOption { + type = lib.types.int; default = 5349; description = '' TURN listener port for TLS. @@ -65,10 +64,10 @@ in { For secure UDP connections, we support DTLS version 1. ''; }; - alt-listening-port = mkOption { - type = types.int; + alt-listening-port = lib.mkOption { + type = lib.types.int; default = cfg.listening-port + 1; - defaultText = literalExpression "listening-port + 1"; + defaultText = lib.literalExpression "listening-port + 1"; description = '' Alternative listening port for UDP and TCP listeners; default (or zero) value means "listening port plus one". @@ -80,16 +79,16 @@ in { are listening to that endpoint only for "symmetry". ''; }; - alt-tls-listening-port = mkOption { - type = types.int; + alt-tls-listening-port = lib.mkOption { + type = lib.types.int; default = cfg.tls-listening-port + 1; - defaultText = literalExpression "tls-listening-port + 1"; + defaultText = lib.literalExpression "tls-listening-port + 1"; description = '' Alternative listening port for TLS and DTLS protocols. ''; }; - listening-ips = mkOption { - type = types.listOf types.str; + listening-ips = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "203.0.113.42" "2001:DB8::42" ]; description = '' @@ -98,8 +97,8 @@ in { then all IPv4 and IPv6 system IPs will be used for listening. ''; }; - relay-ips = mkOption { - type = types.listOf types.str; + relay-ips = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "203.0.113.42" "2001:DB8::42" ]; description = '' @@ -115,29 +114,29 @@ in { as the family of the client socket). ''; }; - min-port = mkOption { - type = types.int; + min-port = lib.mkOption { + type = lib.types.int; default = 49152; description = '' Lower bound of UDP relay endpoints ''; }; - max-port = mkOption { - type = types.int; + max-port = lib.mkOption { + type = lib.types.int; default = 65535; description = '' Upper bound of UDP relay endpoints ''; }; - lt-cred-mech = mkOption { - type = types.bool; + lt-cred-mech = lib.mkOption { + type = lib.types.bool; default = false; description = '' Use long-term credential mechanism. ''; }; - no-auth = mkOption { - type = types.bool; + no-auth = lib.mkOption { + type = lib.types.bool; default = false; description = '' This option is opposite to lt-cred-mech. @@ -148,8 +147,8 @@ in { lt-cred-mech is default. ''; }; - use-auth-secret = mkOption { - type = types.bool; + use-auth-secret = lib.mkOption { + type = lib.types.bool; default = false; description = '' TURN REST API flag. @@ -172,8 +171,8 @@ in { or can be found in the turn_secret table in the database. ''; }; - static-auth-secret = mkOption { - type = types.nullOr types.str; + static-auth-secret = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' 'Static' authentication secret value (a string) for TURN REST API only. @@ -183,17 +182,17 @@ in { by a separate program, so this is why that other mode is 'dynamic'. ''; }; - static-auth-secret-file = mkOption { - type = types.nullOr types.str; + static-auth-secret-file = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Path to the file containing the static authentication secret. ''; }; - realm = mkOption { - type = types.str; + realm = lib.mkOption { + type = lib.types.str; default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; + defaultText = lib.literalExpression "config.networking.hostName"; example = "example.com"; description = '' The default realm to be used for the users when no explicit @@ -203,60 +202,60 @@ in { mechanism or with TURN REST API. ''; }; - cert = mkOption { - type = types.nullOr types.str; + cert = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "/var/lib/acme/example.com/fullchain.pem"; description = '' Certificate file in PEM format. ''; }; - pkey = mkOption { - type = types.nullOr types.str; + pkey = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; example = "/var/lib/acme/example.com/key.pem"; description = '' Private key file in PEM format. ''; }; - dh-file = mkOption { - type = types.nullOr types.str; + dh-file = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Use custom DH TLS key, stored in PEM format in the file. ''; }; - secure-stun = mkOption { - type = types.bool; + secure-stun = lib.mkOption { + type = lib.types.bool; default = false; description = '' Require authentication of the STUN Binding request. By default, the clients are allowed anonymous access to the STUN Binding functionality. ''; }; - no-cli = mkOption { - type = types.bool; + no-cli = lib.mkOption { + type = lib.types.bool; default = false; description = '' Turn OFF the CLI support. ''; }; - cli-ip = mkOption { - type = types.str; + cli-ip = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Local system IP address to be used for CLI server endpoint. ''; }; - cli-port = mkOption { - type = types.int; + cli-port = lib.mkOption { + type = lib.types.int; default = 5766; description = '' CLI server port. ''; }; - cli-password = mkOption { - type = types.nullOr types.str; + cli-password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' CLI access password. @@ -264,45 +263,45 @@ in { for of the password (see the -P command in the turnadmin utility). ''; }; - no-udp = mkOption { - type = types.bool; + no-udp = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable UDP client listener"; }; - no-tcp = mkOption { - type = types.bool; + no-tcp = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable TCP client listener"; }; - no-tls = mkOption { - type = types.bool; + no-tls = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable TLS client listener"; }; - no-dtls = mkOption { - type = types.bool; + no-dtls = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable DTLS client listener"; }; - no-udp-relay = mkOption { - type = types.bool; + no-udp-relay = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable UDP relay endpoints"; }; - no-tcp-relay = mkOption { - type = types.bool; + no-tcp-relay = lib.mkOption { + type = lib.types.bool; default = false; description = "Disable TCP relay endpoints"; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Additional configuration options"; }; }; }; - config = mkIf cfg.enable (mkMerge ([ + config = lib.mkIf cfg.enable (lib.mkMerge ([ { assertions = [ { assertion = cfg.static-auth-secret != null -> cfg.static-auth-secret-file == null ; message = "static-auth-secret and static-auth-secret-file cannot be set at the same time"; @@ -334,7 +333,7 @@ in { preStart = '' cat ${configFile} > ${runConfig} - ${optionalString (cfg.static-auth-secret-file != null) '' + ${lib.optionalString (cfg.static-auth-secret-file != null) '' ${pkgs.replace-secret}/bin/replace-secret \ "#static-auth-secret#" \ ${cfg.static-auth-secret-file} \ @@ -349,7 +348,7 @@ in { User = "turnserver"; Group = "turnserver"; AmbientCapabilities = - mkIf ( + lib.mkIf ( cfg.listening-port < 1024 || cfg.alt-listening-port < 1024 || cfg.tls-listening-port < 1024 || diff --git a/nixos/modules/services/networking/create_ap.nix b/nixos/modules/services/networking/create_ap.nix index 9bdbcee018ed..cebea3c9059c 100644 --- a/nixos/modules/services/networking/create_ap.nix +++ b/nixos/modules/services/networking/create_ap.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.create_ap; - configFile = pkgs.writeText "create_ap.conf" (generators.toKeyValue { } cfg.settings); + configFile = pkgs.writeText "create_ap.conf" (lib.generators.toKeyValue { } cfg.settings); in { options = { services.create_ap = { - enable = mkEnableOption "setting up wifi hotspots using create_ap"; - settings = mkOption { - type = with types; attrsOf (oneOf [ int bool str ]); + enable = lib.mkEnableOption "setting up wifi hotspots using create_ap"; + settings = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ int bool str ]); default = {}; description = '' Configuration for `create_ap`. @@ -27,7 +24,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd = { services.create_ap = { diff --git a/nixos/modules/services/networking/dante.nix b/nixos/modules/services/networking/dante.nix index d5e76b83986b..aef518ddbfd9 100644 --- a/nixos/modules/services/networking/dante.nix +++ b/nixos/modules/services/networking/dante.nix @@ -1,6 +1,4 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.dante; confFile = pkgs.writeText "dante-sockd.conf" '' @@ -14,15 +12,15 @@ in { meta = { - maintainers = with maintainers; [ arobyn ]; + maintainers = with lib.maintainers; [ arobyn ]; }; options = { services.dante = { - enable = mkEnableOption "Dante SOCKS proxy"; + enable = lib.mkEnableOption "Dante SOCKS proxy"; - config = mkOption { - type = types.lines; + config = lib.mkOption { + type = lib.types.lines; description = '' Contents of Dante's configuration file. NOTE: user.privileged, user.unprivileged and logoutput are set by the service. @@ -31,7 +29,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.config != ""; message = "please provide Dante configuration file contents"; diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index 272a50eb92de..90a3993df686 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -1,5 +1,4 @@ { config, pkgs, lib, ... }: - let cfg = config.services.ddclient; boolToStr = bool: if bool then "yes" else "no"; @@ -39,21 +38,17 @@ let sed -i '/^password=@password_placeholder@$/d' /run/${RuntimeDirectory}/ddclient.conf '')} ''; - in - -with lib; - { imports = [ - (mkChangedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ] + (lib.mkChangedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ] (config: - let value = getAttrFromPath [ "services" "ddclient" "domain" ] config; - in optional (value != "") value)) - (mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "") - (mkRemovedOptionModule [ "services" "ddclient" "password" ] "Use services.ddclient.passwordFile instead.") - (mkRemovedOptionModule [ "services" "ddclient" "ipv6" ] "") + let value = lib.getAttrFromPath [ "services" "ddclient" "domain" ] config; + in lib.optional (value != "") value)) + (lib.mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "") + (lib.mkRemovedOptionModule [ "services" "ddclient" "password" ] "Use services.ddclient.passwordFile instead.") + (lib.mkRemovedOptionModule [ "services" "ddclient" "ipv6" ] "") ]; ###### interface @@ -62,7 +57,7 @@ with lib; services.ddclient = with lib.types; { - enable = mkOption { + enable = lib.mkOption { default = false; type = bool; description = '' @@ -70,7 +65,7 @@ with lib; ''; }; - package = mkOption { + package = lib.mkOption { type = package; default = pkgs.ddclient; defaultText = lib.literalExpression "pkgs.ddclient"; @@ -79,7 +74,7 @@ with lib; ''; }; - domains = mkOption { + domains = lib.mkOption { default = [ "" ]; type = listOf str; description = '' @@ -87,7 +82,7 @@ with lib; ''; }; - username = mkOption { + username = lib.mkOption { # For `nsupdate` username contains the path to the nsupdate executable default = lib.optionalString (config.services.ddclient.protocol == "nsupdate") "${pkgs.bind.dnsutils}/bin/nsupdate"; defaultText = ""; @@ -97,7 +92,7 @@ with lib; ''; }; - passwordFile = mkOption { + passwordFile = lib.mkOption { default = null; type = nullOr str; description = '' @@ -105,7 +100,7 @@ with lib; ''; }; - interval = mkOption { + interval = lib.mkOption { default = "10min"; type = str; description = '' @@ -114,7 +109,7 @@ with lib; ''; }; - configFile = mkOption { + configFile = lib.mkOption { default = null; type = nullOr path; description = '' @@ -124,7 +119,7 @@ with lib; example = "/root/nixos/secrets/ddclient.conf"; }; - protocol = mkOption { + protocol = lib.mkOption { default = "dyndns2"; type = str; description = '' @@ -132,7 +127,7 @@ with lib; ''; }; - server = mkOption { + server = lib.mkOption { default = ""; type = str; description = '' @@ -140,7 +135,7 @@ with lib; ''; }; - ssl = mkOption { + ssl = lib.mkOption { default = true; type = bool; description = '' @@ -148,7 +143,7 @@ with lib; ''; }; - quiet = mkOption { + quiet = lib.mkOption { default = false; type = bool; description = '' @@ -156,7 +151,7 @@ with lib; ''; }; - script = mkOption { + script = lib.mkOption { default = ""; type = str; description = '' @@ -164,21 +159,21 @@ with lib; ''; }; - use = mkOption { + use = lib.mkOption { default = ""; type = str; description = '' Method to determine the IP address to send to the dynamic DNS provider. ''; }; - usev4 = mkOption { + usev4 = lib.mkOption { default = "webv4, webv4=checkip.dyndns.com/, webv4-skip='Current IP Address: '"; type = str; description = '' Method to determine the IPv4 address to send to the dynamic DNS provider. Only used if `use` is not set. ''; }; - usev6 = mkOption { + usev6 = lib.mkOption { default = "webv6, webv6=checkipv6.dyndns.com/, webv6-skip='Current IP Address: '"; type = str; description = '' @@ -186,7 +181,7 @@ with lib; ''; }; - verbose = mkOption { + verbose = lib.mkOption { default = false; type = bool; description = '' @@ -194,7 +189,7 @@ with lib; ''; }; - zone = mkOption { + zone = lib.mkOption { default = ""; type = str; description = '' @@ -202,7 +197,7 @@ with lib; ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { default = ""; type = lines; description = '' @@ -219,15 +214,15 @@ with lib; ###### implementation - config = mkIf config.services.ddclient.enable { + config = lib.mkIf config.services.ddclient.enable { warnings = lib.optional (cfg.use != "") "Setting `use` is deprecated, ddclient now supports `usev4` and `usev6` for separate IPv4/IPv6 configuration."; systemd.services.ddclient = { description = "Dynamic DNS Client"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - restartTriggers = optional (cfg.configFile != null) cfg.configFile; - path = lib.optional (lib.hasPrefix "if," cfg.use) pkgs.iproute2; + restartTriggers = lib.optional (cfg.configFile != null) cfg.configFile; + path = lib.optional (lib.hasPrefix "if," cfg.use || lib.hasPrefix "if," cfg.usev4 || lib.hasPrefix "if," cfg.usev6) pkgs.iproute2; serviceConfig = { DynamicUser = true; diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index a88ce0f1b5a5..a7c896cb28a2 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -1,28 +1,25 @@ { config, lib, pkgs, ... }: - -with lib; - let dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; }; cfg = config.networking.dhcpcd; - interfaces = attrValues config.networking.interfaces; + interfaces = lib.attrValues config.networking.interfaces; enableDHCP = config.networking.dhcpcd.enable && - (config.networking.useDHCP || any (i: i.useDHCP == true) interfaces); + (config.networking.useDHCP || lib.any (i: i.useDHCP == true) interfaces); - enableNTPService = (config.services.ntp.enable || config.services.ntpd-rs.enable || config.services.openntpd.enable || config.services.chrony.enable); + useResolvConf = config.networking.resolvconf.enable; # Don't start dhcpcd on explicitly configured interfaces or on # interfaces that are part of a bridge, bond or sit device. ignoredInterfaces = - map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ipv4.addresses != [ ]) interfaces) - ++ mapAttrsToList (i: _: i) config.networking.sits - ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) - ++ flatten (concatMap (i: attrNames (filterAttrs (_: config: config.type != "internal") i.interfaces)) (attrValues config.networking.vswitches)) - ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds)) + map (i: i.name) (lib.filter (i: if i.useDHCP != null then !i.useDHCP else i.ipv4.addresses != [ ]) interfaces) + ++ lib.mapAttrsToList (i: _: i) config.networking.sits + ++ lib.concatLists (lib.attrValues (lib.mapAttrs (n: v: v.interfaces) config.networking.bridges)) + ++ lib.flatten (lib.concatMap (i: lib.attrNames (lib.filterAttrs (_: config: config.type != "internal") i.interfaces)) (lib.attrValues config.networking.vswitches)) + ++ lib.concatLists (lib.attrValues (lib.mapAttrs (n: v: v.interfaces) config.networking.bonds)) ++ config.networking.dhcpcd.denyInterfaces; arrayAppendOrNull = a1: a2: if a1 == null && a2 == null then null @@ -33,11 +30,11 @@ let # we need to provide dhcp just for those interfaces. allowInterfaces = arrayAppendOrNull cfg.allowInterfaces (if !config.networking.useDHCP && enableDHCP then - map (i: i.name) (filter (i: i.useDHCP == true) interfaces) else null); + map (i: i.name) (lib.filter (i: i.useDHCP == true) interfaces) else null); - staticIPv6Addresses = map (i: i.name) (filter (i: i.ipv6.addresses != [ ]) interfaces); + staticIPv6Addresses = map (i: i.name) (lib.filter (i: i.ipv6.addresses != [ ]) interfaces); - noIPv6rs = concatStringsSep "\n" (map (name: '' + noIPv6rs = lib.concatStringsSep "\n" (map (name: '' interface ${name} noipv6rs '') staticIPv6Addresses); @@ -66,7 +63,7 @@ let denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit* # Use the list of allowed interfaces if specified - ${optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"} + ${lib.optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"} # Immediately fork to background if specified, otherwise wait for IP address to be assigned ${{ @@ -78,36 +75,19 @@ let if-carrier-up = ""; }.${cfg.wait}} - ${optionalString (config.networking.enableIPv6 == false) '' + ${lib.optionalString (config.networking.enableIPv6 == false) '' # Don't solicit or accept IPv6 Router Advertisements and DHCPv6 if disabled IPv6 noipv6 ''} - ${optionalString (config.networking.enableIPv6 && cfg.IPv6rs == null && staticIPv6Addresses != [ ]) noIPv6rs} - ${optionalString (config.networking.enableIPv6 && cfg.IPv6rs == false) '' + ${lib.optionalString (config.networking.enableIPv6 && cfg.IPv6rs == null && staticIPv6Addresses != [ ]) noIPv6rs} + ${lib.optionalString (config.networking.enableIPv6 && cfg.IPv6rs == false) '' noipv6rs ''} ${cfg.extraConfig} ''; - exitHook = pkgs.writeText "dhcpcd.exit-hook" '' - ${optionalString enableNTPService '' - if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then - # Restart ntpd. We need to restart it to make sure that it will actually do something: - # if ntpd cannot resolve the server hostnames in its config file, then it will never do - # anything ever again ("couldn't resolve ..., giving up on it"), so we silently lose - # time synchronisation. This also applies to openntpd. - ${optionalString config.services.ntp.enable "/run/current-system/systemd/bin/systemctl try-reload-or-restart ntpd.service || true"} - ${optionalString config.services.ntpd-rs.enable "/run/current-system/systemd/bin/systemctl try-reload-or-restart ntpd-rs.service || true"} - ${optionalString config.services.openntpd.enable "/run/current-system/systemd/bin/systemctl try-reload-or-restart openntpd.service || true"} - ${optionalString config.services.chrony.enable "/run/current-system/systemd/bin/systemctl try-reload-or-restart chronyd.service || true"} - fi - ''} - - ${cfg.runHook} - ''; - in { @@ -116,8 +96,8 @@ in options = { - networking.dhcpcd.enable = mkOption { - type = types.bool; + networking.dhcpcd.enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable dhcpcd for device configuration. This is mainly to @@ -125,8 +105,8 @@ in ''; }; - networking.dhcpcd.persistent = mkOption { - type = types.bool; + networking.dhcpcd.persistent = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whenever to leave interfaces configured on dhcpcd daemon @@ -137,8 +117,8 @@ in ''; }; - networking.dhcpcd.denyInterfaces = mkOption { - type = types.listOf types.str; + networking.dhcpcd.denyInterfaces = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Disable the DHCP client for any interface whose name matches @@ -148,8 +128,8 @@ in ''; }; - networking.dhcpcd.allowInterfaces = mkOption { - type = types.nullOr (types.listOf types.str); + networking.dhcpcd.allowInterfaces = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; description = '' Enable the DHCP client for any interface whose name matches @@ -159,16 +139,16 @@ in ''; }; - networking.dhcpcd.extraConfig = mkOption { - type = types.lines; + networking.dhcpcd.extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Literal string to append to the config file generated for dhcpcd. ''; }; - networking.dhcpcd.IPv6rs = mkOption { - type = types.nullOr types.bool; + networking.dhcpcd.IPv6rs = lib.mkOption { + type = lib.types.nullOr lib.types.bool; default = null; description = '' Force enable or disable solicitation and receipt of IPv6 Router Advertisements. @@ -177,18 +157,31 @@ in ''; }; - networking.dhcpcd.runHook = mkOption { - type = types.lines; + networking.dhcpcd.runHook = lib.mkOption { + type = lib.types.lines; default = ""; example = "if [[ $reason =~ BOUND ]]; then echo $interface: Routers are $new_routers - were $old_routers; fi"; description = '' Shell code that will be run after all other hooks. See `man dhcpcd-run-hooks` for details on what is possible. + + ::: {.note} + To use sudo or similar tools in your script you may have to set: + + systemd.services.dhcpcd.serviceConfig.NoNewPrivileges = false; + + In addition, as most of the filesystem is inaccessible to dhcpcd + by default, you may want to define some exceptions, e.g. + + systemd.services.dhcpcd.serviceConfig.ReadOnlyPaths = [ + "/run/user/1000/bus" # to send desktop notifications + ]; + ::: ''; }; - networking.dhcpcd.wait = mkOption { - type = types.enum [ "background" "any" "ipv4" "ipv6" "both" "if-carrier-up" ]; + networking.dhcpcd.wait = lib.mkOption { + type = lib.types.enum [ "background" "any" "ipv4" "ipv6" "both" "if-carrier-up" ]; default = "any"; description = '' This option specifies when the dhcpcd service will fork to background. @@ -207,23 +200,7 @@ in ###### implementation - config = mkIf enableDHCP { - - assertions = [ { - # dhcpcd doesn't start properly with malloc ∉ [ libc scudo ] - # see https://github.com/NixOS/nixpkgs/issues/151696 - assertion = - dhcpcd.enablePrivSep - -> elem config.environment.memoryAllocator.provider [ "libc" "scudo" ]; - message = '' - dhcpcd with privilege separation is incompatible with chosen system malloc. - Currently only the `libc` and `scudo` allocators are known to work. - To disable dhcpcd's privilege separation, overlay Nixpkgs and override dhcpcd - to set `enablePrivSep = false`. - ''; - } ]; - - environment.etc."dhcpcd.conf".source = dhcpcdConf; + config = lib.mkIf enableDHCP { systemd.services.dhcpcd = let cfgN = config.networking; @@ -232,11 +209,12 @@ in in { description = "DHCP Client"; - wantedBy = [ "multi-user.target" ] ++ optional (!hasDefaultGatewaySet) "network-online.target"; - wants = [ "network.target" ]; + wantedBy = [ "multi-user.target" ] ++ lib.optional (!hasDefaultGatewaySet) "network-online.target"; + wants = [ "network.target" "resolvconf.service" ]; + after = [ "resolvconf.service" ]; before = [ "network-online.target" ]; - restartTriggers = optional (enableNTPService || cfg.runHook != "") [ exitHook ]; + restartTriggers = [ cfg.runHook ]; # Stopping dhcpcd during a reconfiguration is undesirable # because it brings down the network interfaces configured by @@ -250,13 +228,64 @@ in serviceConfig = { Type = "forking"; PIDFile = "/run/dhcpcd/pid"; + SupplementaryGroups = lib.optional useResolvConf "resolvconf"; + User = "dhcpcd"; + Group = "dhcpcd"; + StateDirectory = "dhcpcd"; RuntimeDirectory = "dhcpcd"; - ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --quiet ${optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf}"; + + ExecStartPre = "+${pkgs.writeShellScript "migrate-dhcpcd" '' + # migrate from old database directory + if test -f /var/db/dhcpcd/duid; then + echo 'migrating DHCP leases from /var/db/dhcpcd to /var/lib/dhcpcd ...' + mv /var/db/dhcpcd/* -t /var/lib/dhcpcd + chown dhcpcd:dhcpcd /var/lib/dhcpcd/* + rmdir /var/db/dhcpcd || true + echo done + fi + ''}"; + + ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --quiet ${lib.optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf}"; ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind"; Restart = "always"; + AmbientCapabilities = [ "CAP_NET_ADMIN" "CAP_NET_RAW" "CAP_NET_BIND_SERVICE" ]; + ReadWritePaths = [ "/proc/sys/net/ipv6" ] + ++ lib.optionals useResolvConf ([ "/run/resolvconf" ] ++ config.networking.resolvconf.subscriberFiles); + DeviceAllow = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = lib.mkDefault true; # may be disabled for sudo in runHook + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = false; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = "tmpfs"; # allow exceptions to be added to ReadOnlyPaths, etc. + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" "AF_PACKET" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallFilter = [ + "@system-service" + "~@aio" "~@chown" "~@keyring" "~@memlock" + ]; + SystemCallArchitectures = "native"; + UMask = "0027"; }; }; + # Note: the service could run with `DynamicUser`, however that makes + # impossible (for no good reason, see systemd issue #20495) to disable + # `NoNewPrivileges` or `ProtectHome`, which users may want to in order + # to run certain scripts in `networking.dhcpcd.runHook`. users.users.dhcpcd = { isSystemUser = true; group = "dhcpcd"; @@ -265,11 +294,9 @@ in environment.systemPackages = [ dhcpcd ]; - environment.etc."dhcpcd.exit-hook" = mkIf (enableNTPService || cfg.runHook != "") { - source = exitHook; - }; + environment.etc."dhcpcd.exit-hook".text = cfg.runHook; - powerManagement.resumeCommands = mkIf config.systemd.services.dhcpcd.enable + powerManagement.resumeCommands = lib.mkIf config.systemd.services.dhcpcd.enable '' # Tell dhcpcd to rebind its interfaces if it's running. /run/current-system/systemd/bin/systemctl reload dhcpcd.service diff --git a/nixos/modules/services/networking/dnscache.nix b/nixos/modules/services/networking/dnscache.nix index 160c7611c6b8..e743d1c54323 100644 --- a/nixos/modules/services/networking/dnscache.nix +++ b/nixos/modules/services/networking/dnscache.nix @@ -1,19 +1,16 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dnscache; dnscache-root = pkgs.runCommand "dnscache-root" { preferLocalBuild = true; } '' mkdir -p $out/{servers,ip} - ${concatMapStrings (ip: '' + ${lib.concatMapStrings (ip: '' touch "$out/ip/"${lib.escapeShellArg ip} '') cfg.clientIps} - ${concatStrings (mapAttrsToList (host: ips: '' - ${concatMapStrings (ip: '' + ${lib.concatStrings (lib.mapAttrsToList (host: ips: '' + ${lib.concatMapStrings (ip: '' echo ${lib.escapeShellArg ip} >> "$out/servers/"${lib.escapeShellArg host} '') ips} '') cfg.domainServers)} @@ -35,33 +32,33 @@ in { options = { services.dnscache = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = "Whether to run the dnscache caching dns server."; }; - ip = mkOption { + ip = lib.mkOption { default = "0.0.0.0"; - type = types.str; + type = lib.types.str; description = "IP address on which to listen for connections."; }; - clientIps = mkOption { + clientIps = lib.mkOption { default = [ "127.0.0.1" ]; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; description = "Client IP addresses (or prefixes) from which to accept connections."; example = ["192.168" "172.23.75.82"]; }; - domainServers = mkOption { + domainServers = lib.mkOption { default = { }; - type = types.attrsOf (types.listOf types.str); + type = lib.types.attrsOf (lib.types.listOf lib.types.str); description = '' Table of {hostname: server} pairs to use as authoritative servers for hosts (and subhosts). If entry for @ is not specified predefined list of root servers is used. ''; - example = literalExpression '' + example = lib.literalExpression '' { "@" = ["8.8.8.8" "8.8.4.4"]; "example.com" = ["192.168.100.100"]; @@ -69,9 +66,9 @@ in { ''; }; - forwardOnly = mkOption { + forwardOnly = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to treat root servers (for @) as caching servers, requesting addresses the same way a client does. This is @@ -84,7 +81,7 @@ in { ###### implementation - config = mkIf config.services.dnscache.enable { + config = lib.mkIf config.services.dnscache.enable { environment.systemPackages = [ pkgs.djbdns ]; users.users.dnscache = { isSystemUser = true; @@ -104,7 +101,7 @@ in { ''; script = '' cd /var/lib/dnscache/ - ${optionalString cfg.forwardOnly "export FORWARDONLY=1"} + ${lib.optionalString cfg.forwardOnly "export FORWARDONLY=1"} exec ./run ''; }; diff --git a/nixos/modules/services/networking/dnscrypt-wrapper.nix b/nixos/modules/services/networking/dnscrypt-wrapper.nix deleted file mode 100644 index fb07d893b88e..000000000000 --- a/nixos/modules/services/networking/dnscrypt-wrapper.nix +++ /dev/null @@ -1,275 +0,0 @@ -{ config, lib, pkgs, ... }: -with lib; - -let - cfg = config.services.dnscrypt-wrapper; - dataDir = "/var/lib/dnscrypt-wrapper"; - - mkPath = path: default: - if path != null - then toString path - else default; - - publicKey = mkPath cfg.providerKey.public "${dataDir}/public.key"; - secretKey = mkPath cfg.providerKey.secret "${dataDir}/secret.key"; - - daemonArgs = with cfg; [ - "--listen-address=${address}:${toString port}" - "--resolver-address=${upstream.address}:${toString upstream.port}" - "--provider-name=${providerName}" - "--provider-publickey-file=${publicKey}" - "--provider-secretkey-file=${secretKey}" - "--provider-cert-file=${providerName}.crt" - "--crypt-secretkey-file=${providerName}.key" - ]; - - genKeys = '' - # generates time-limited keypairs - keyGen() { - dnscrypt-wrapper --gen-crypt-keypair \ - --crypt-secretkey-file=${cfg.providerName}.key - - dnscrypt-wrapper --gen-cert-file \ - --crypt-secretkey-file=${cfg.providerName}.key \ - --provider-cert-file=${cfg.providerName}.crt \ - --provider-publickey-file=${publicKey} \ - --provider-secretkey-file=${secretKey} \ - --cert-file-expire-days=${toString cfg.keys.expiration} - } - - cd ${dataDir} - - # generate provider keypair (first run only) - ${optionalString (cfg.providerKey.public == null || cfg.providerKey.secret == null) '' - if [ ! -f ${publicKey} ] || [ ! -f ${secretKey} ]; then - dnscrypt-wrapper --gen-provider-keypair - fi - ''} - - # generate new keys for rotation - if [ ! -f ${cfg.providerName}.key ] || [ ! -f ${cfg.providerName}.crt ]; then - keyGen - fi - ''; - - rotateKeys = '' - # check if keys are not expired - keyValid() { - fingerprint=$(dnscrypt-wrapper \ - --show-provider-publickey \ - --provider-publickey-file=${publicKey} \ - | awk '{print $(NF)}') - dnscrypt-proxy --test=${toString (cfg.keys.checkInterval + 1)} \ - --resolver-address=127.0.0.1:${toString cfg.port} \ - --provider-name=${cfg.providerName} \ - --provider-key=$fingerprint - } - - cd ${dataDir} - - # archive old keys and restart the service - if ! keyValid; then - echo "certificate soon to become invalid; backing up old cert" - mkdir -p oldkeys - mv -v "${cfg.providerName}.key" "oldkeys/${cfg.providerName}-$(date +%F-%T).key" - mv -v "${cfg.providerName}.crt" "oldkeys/${cfg.providerName}-$(date +%F-%T).crt" - kill "$(pidof -s dnscrypt-wrapper)" - fi - ''; - - - # This is the fork of the original dnscrypt-proxy maintained by Dyne.org. - # dnscrypt-proxy2 doesn't provide the `--test` feature that is needed to - # correctly implement key rotation of dnscrypt-wrapper ephemeral keys. - dnscrypt-proxy1 = pkgs.callPackage - ({ stdenv, fetchFromGitHub, autoreconfHook - , pkg-config, libsodium, ldns, openssl, systemd }: - - stdenv.mkDerivation rec { - pname = "dnscrypt-proxy"; - version = "2019-08-20"; - - src = fetchFromGitHub { - owner = "dyne"; - repo = "dnscrypt-proxy"; - rev = "07ac3825b5069adc28e2547c16b1d983a8ed8d80"; - sha256 = "0c4mq741q4rpmdn09agwmxap32kf0vgfz7pkhcdc5h54chc3g3xy"; - }; - - configureFlags = optional stdenv.isLinux "--with-systemd"; - - nativeBuildInputs = [ autoreconfHook pkg-config ]; - - # depends on - buildInputs = [ libsodium openssl.dev ldns ] ++ optional stdenv.isLinux systemd; - - postInstall = '' - # Previous versions required libtool files to load plugins; they are - # now strictly optional. - rm $out/lib/dnscrypt-proxy/*.la - ''; - - meta = { - description = "A tool for securing communications between a client and a DNS resolver"; - homepage = "https://github.com/dyne/dnscrypt-proxy"; - license = licenses.isc; - maintainers = with maintainers; [ rnhmjoj ]; - platforms = platforms.linux; - }; - }) { }; - -in { - - - ###### interface - - options.services.dnscrypt-wrapper = { - enable = mkEnableOption "DNSCrypt wrapper"; - - address = mkOption { - type = types.str; - default = "127.0.0.1"; - description = '' - The DNSCrypt wrapper will bind to this IP address. - ''; - }; - - port = mkOption { - type = types.port; - default = 5353; - description = '' - The DNSCrypt wrapper will listen for DNS queries on this port. - ''; - }; - - providerName = mkOption { - type = types.str; - default = "2.dnscrypt-cert.${config.networking.hostName}"; - defaultText = literalExpression ''"2.dnscrypt-cert.''${config.networking.hostName}"''; - example = "2.dnscrypt-cert.myresolver"; - description = '' - The name that will be given to this DNSCrypt resolver. - Note: the resolver name must start with `2.dnscrypt-cert.`. - ''; - }; - - providerKey.public = mkOption { - type = types.nullOr types.path; - default = null; - example = "/etc/secrets/public.key"; - description = '' - The filepath to the provider public key. If not given a new - provider key pair will be generated on the first run. - ''; - }; - - providerKey.secret = mkOption { - type = types.nullOr types.path; - default = null; - example = "/etc/secrets/secret.key"; - description = '' - The filepath to the provider secret key. If not given a new - provider key pair will be generated on the first run. - ''; - }; - - upstream.address = mkOption { - type = types.str; - default = "127.0.0.1"; - description = '' - The IP address of the upstream DNS server DNSCrypt will "wrap". - ''; - }; - - upstream.port = mkOption { - type = types.port; - default = 53; - description = '' - The port of the upstream DNS server DNSCrypt will "wrap". - ''; - }; - - keys.expiration = mkOption { - type = types.int; - default = 30; - description = '' - The duration (in days) of the time-limited secret key. - This will be automatically rotated before expiration. - ''; - }; - - keys.checkInterval = mkOption { - type = types.int; - default = 1440; - description = '' - The time interval (in minutes) between key expiration checks. - ''; - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - - users.users.dnscrypt-wrapper = { - description = "dnscrypt-wrapper daemon user"; - home = "${dataDir}"; - createHome = true; - isSystemUser = true; - group = "dnscrypt-wrapper"; - }; - users.groups.dnscrypt-wrapper = { }; - - systemd.services.dnscrypt-wrapper = { - description = "dnscrypt-wrapper daemon"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.dnscrypt-wrapper ]; - - serviceConfig = { - User = "dnscrypt-wrapper"; - WorkingDirectory = dataDir; - Restart = "always"; - ExecStart = "${pkgs.dnscrypt-wrapper}/bin/dnscrypt-wrapper ${toString daemonArgs}"; - }; - - preStart = genKeys; - }; - - - systemd.services.dnscrypt-wrapper-rotate = { - after = [ "network.target" ]; - requires = [ "dnscrypt-wrapper.service" ]; - description = "Rotates DNSCrypt wrapper keys if soon to expire"; - - path = with pkgs; [ dnscrypt-wrapper dnscrypt-proxy1 gawk procps ]; - script = rotateKeys; - serviceConfig.User = "dnscrypt-wrapper"; - }; - - - systemd.timers.dnscrypt-wrapper-rotate = { - description = "Periodically check DNSCrypt wrapper keys for expiration"; - wantedBy = [ "multi-user.target" ]; - - timerConfig = { - Unit = "dnscrypt-wrapper-rotate.service"; - OnBootSec = "1min"; - OnUnitActiveSec = cfg.keys.checkInterval * 60; - }; - }; - - assertions = with cfg; [ - { assertion = (providerKey.public == null && providerKey.secret == null) || - (providerKey.secret != null && providerKey.public != null); - message = "The secret and public provider key must be set together."; - } - ]; - - }; - - meta.maintainers = with lib.maintainers; [ rnhmjoj ]; - -} diff --git a/nixos/modules/services/networking/dnsdist.nix b/nixos/modules/services/networking/dnsdist.nix index cf17a87f649f..cd87abb3d072 100644 --- a/nixos/modules/services/networking/dnsdist.nix +++ b/nixos/modules/services/networking/dnsdist.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dnsdist; @@ -80,38 +77,38 @@ let in { options = { services.dnsdist = { - enable = mkEnableOption "dnsdist domain name server"; + enable = lib.mkEnableOption "dnsdist domain name server"; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; description = "Listen IP address"; default = "0.0.0.0"; }; - listenPort = mkOption { - type = types.port; + listenPort = lib.mkOption { + type = lib.types.port; description = "Listen port"; default = 53; }; dnscrypt = { - enable = mkEnableOption "a DNSCrypt endpoint to dnsdist"; + enable = lib.mkEnableOption "a DNSCrypt endpoint to dnsdist"; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; description = "Listen IP address of the endpoint"; default = "0.0.0.0"; }; - listenPort = mkOption { - type = types.port; + listenPort = lib.mkOption { + type = lib.types.port; description = "Listen port of the endpoint"; default = 443; }; - providerName = mkOption { - type = types.str; + providerName = lib.mkOption { + type = lib.types.str; default = "2.dnscrypt-cert.${config.networking.hostName}"; - defaultText = literalExpression "2.dnscrypt-cert.\${config.networking.hostName}"; + defaultText = lib.literalExpression "2.dnscrypt-cert.\${config.networking.hostName}"; example = "2.dnscrypt-cert.myresolver"; description = '' The name that will be given to this DNSCrypt resolver. @@ -122,8 +119,8 @@ in { ''; }; - providerKey = mkOption { - type = types.nullOr types.path; + providerKey = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' The filepath to the provider secret key. @@ -136,8 +133,8 @@ in { ''; }; - certLifetime = mkOption { - type = types.ints.positive; + certLifetime = lib.mkOption { + type = lib.types.ints.positive; default = 15; description = '' The lifetime (in minutes) of the resolver certificate. @@ -147,8 +144,8 @@ in { }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra lines to be added verbatim to dnsdist.conf. @@ -157,7 +154,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.dnsdist = { description = "dnsdist daemons user"; isSystemUser = true; diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix index e9052cdd3fae..dfa6b8035168 100644 --- a/nixos/modules/services/networking/dnsmasq.nix +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.dnsmasq; dnsmasq = cfg.package; @@ -9,34 +6,29 @@ let # True values are just put as `name` instead of `name=true`, and false values # are turned to comments (false values are expected to be overrides e.g. - # mkForce) + # lib.mkForce) formatKeyValue = name: value: if value == true then name else if value == false then "# setting `${name}` explicitly set to false" - else generators.mkKeyValueDefault { } "=" name value; + else lib.generators.mkKeyValueDefault { } "=" name value; settingsFormat = pkgs.formats.keyValue { mkKeyValue = formatKeyValue; listsAsDuplicateKeys = true; }; - # Because formats.generate is outputting a file, we use of conf-file. Once - # `extraConfig` is deprecated we can just use - # `dnsmasqConf = format.generate "dnsmasq.conf" cfg.settings` - dnsmasqConf = pkgs.writeText "dnsmasq.conf" '' - conf-file=${settingsFormat.generate "dnsmasq.conf" cfg.settings} - ${cfg.extraConfig} - ''; + dnsmasqConf = settingsFormat.generate "dnsmasq.conf" cfg.settings; in { imports = [ - (mkRenamedOptionModule [ "services" "dnsmasq" "servers" ] [ "services" "dnsmasq" "settings" "server" ]) + (lib.mkRenamedOptionModule [ "services" "dnsmasq" "servers" ] [ "services" "dnsmasq" "settings" "server" ]) + (lib.mkRemovedOptionModule [ "services" "dnsmasq" "extraConfig" ] "This option has been replaced by `services.dnsmasq.settings`") ]; ###### interface @@ -45,18 +37,18 @@ in services.dnsmasq = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to run dnsmasq. ''; }; - package = mkPackageOption pkgs "dnsmasq" {}; + package = lib.mkPackageOption pkgs "dnsmasq" {}; - resolveLocalQueries = mkOption { - type = types.bool; + resolveLocalQueries = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether dnsmasq should resolve local queries (i.e. add 127.0.0.1 to @@ -64,21 +56,21 @@ in ''; }; - alwaysKeepRunning = mkOption { - type = types.bool; + alwaysKeepRunning = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, systemd will always respawn dnsmasq even if shut down manually. The default, disabled, will only restart it on error. ''; }; - settings = mkOption { - type = types.submodule { + settings = lib.mkOption { + type = lib.types.submodule { freeformType = settingsFormat.type; - options.server = mkOption { - type = types.listOf types.str; + options.server = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "8.8.8.8" "8.8.4.4" ]; description = '' @@ -99,7 +91,7 @@ in resolv-file = optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf"; } ''; - example = literalExpression '' + example = lib.literalExpression '' { domain-needed = true; dhcp-range = [ "192.168.0.2,192.168.0.254" ]; @@ -107,17 +99,6 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Extra configuration directives that should be added to - `dnsmasq.conf`. - - This option is deprecated, please use {option}`settings` instead. - ''; - }; - }; }; @@ -125,18 +106,16 @@ in ###### implementation - config = mkIf cfg.enable { - - warnings = lib.optional (cfg.extraConfig != "") "Text based config is deprecated, dnsmasq now supports `services.dnsmasq.settings` for an attribute-set based config"; + config = lib.mkIf cfg.enable { services.dnsmasq.settings = { - dhcp-leasefile = mkDefault "${stateDir}/dnsmasq.leases"; - conf-file = mkDefault (optional cfg.resolveLocalQueries "/etc/dnsmasq-conf.conf"); - resolv-file = mkDefault (optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf"); + dhcp-leasefile = lib.mkDefault "${stateDir}/dnsmasq.leases"; + conf-file = lib.mkDefault (lib.optional cfg.resolveLocalQueries "/etc/dnsmasq-conf.conf"); + resolv-file = lib.mkDefault (lib.optional cfg.resolveLocalQueries "/etc/dnsmasq-resolv.conf"); }; networking.nameservers = - optional cfg.resolveLocalQueries "127.0.0.1"; + lib.optional cfg.resolveLocalQueries "127.0.0.1"; services.dbus.packages = [ dnsmasq ]; @@ -147,13 +126,18 @@ in }; users.groups.dnsmasq = {}; - networking.resolvconf = mkIf cfg.resolveLocalQueries { - useLocalResolver = mkDefault true; + networking.resolvconf = lib.mkIf cfg.resolveLocalQueries { + useLocalResolver = lib.mkDefault true; extraConfig = '' dnsmasq_conf=/etc/dnsmasq-conf.conf dnsmasq_resolv=/etc/dnsmasq-resolv.conf ''; + + subscriberFiles = [ + "/etc/dnsmasq-conf.conf" + "/etc/dnsmasq-resolv.conf" + ]; }; systemd.services.dnsmasq = { diff --git a/nixos/modules/services/networking/doh-proxy-rust.nix b/nixos/modules/services/networking/doh-proxy-rust.nix index 1f3850a77bf1..32b7a3750480 100644 --- a/nixos/modules/services/networking/doh-proxy-rust.nix +++ b/nixos/modules/services/networking/doh-proxy-rust.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.doh-proxy-rust; @@ -10,10 +7,10 @@ in { options.services.doh-proxy-rust = { - enable = mkEnableOption "doh-proxy-rust"; + enable = lib.mkEnableOption "doh-proxy-rust"; - flags = mkOption { - type = types.listOf types.str; + flags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "--server-address=9.9.9.9:53" ]; description = '' @@ -24,13 +21,13 @@ in { }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.doh-proxy-rust = { description = "doh-proxy-rust"; after = [ "network.target" "nss-lookup.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.doh-proxy-rust}/bin/doh-proxy ${escapeShellArgs cfg.flags}"; + ExecStart = "${pkgs.doh-proxy-rust}/bin/doh-proxy ${lib.escapeShellArgs cfg.flags}"; Restart = "always"; RestartSec = 10; DynamicUser = true; @@ -55,6 +52,6 @@ in { }; }; - meta.maintainers = with maintainers; [ stephank ]; + meta.maintainers = with lib.maintainers; [ stephank ]; } diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix index 3e92a2d3f7eb..d2ada99cc921 100644 --- a/nixos/modules/services/networking/ejabberd.nix +++ b/nixos/modules/services/networking/ejabberd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.ejabberd; @@ -11,7 +8,7 @@ let ${cfg.ctlConfig} ''; - ectl = ''${cfg.package}/bin/ejabberdctl ${optionalString (cfg.configFile != null) "--config ${cfg.configFile}"} --ctl-config "${ctlcfg}" --spool "${cfg.spoolDir}" --logs "${cfg.logsDir}"''; + ectl = ''${cfg.package}/bin/ejabberdctl ${lib.optionalString (cfg.configFile != null) "--config ${cfg.configFile}"} --ctl-config "${ctlcfg}" --spool "${cfg.spoolDir}" --logs "${cfg.logsDir}"''; dumps = lib.escapeShellArgs cfg.loadDumps; @@ -23,59 +20,59 @@ in { services.ejabberd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to enable ejabberd server"; }; - package = mkPackageOption pkgs "ejabberd" { }; + package = lib.mkPackageOption pkgs "ejabberd" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "ejabberd"; description = "User under which ejabberd is ran"; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "ejabberd"; description = "Group under which ejabberd is ran"; }; - spoolDir = mkOption { - type = types.path; + spoolDir = lib.mkOption { + type = lib.types.path; default = "/var/lib/ejabberd"; description = "Location of the spooldir of ejabberd"; }; - logsDir = mkOption { - type = types.path; + logsDir = lib.mkOption { + type = lib.types.path; default = "/var/log/ejabberd"; description = "Location of the logfile directory of ejabberd"; }; - configFile = mkOption { - type = types.nullOr types.path; + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; description = "Configuration file for ejabberd in YAML format"; default = null; }; - ctlConfig = mkOption { - type = types.lines; + ctlConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Configuration of ejabberdctl"; }; - loadDumps = mkOption { - type = types.listOf types.path; + loadDumps = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = "Configuration dumps that should be loaded on the first startup"; - example = literalExpression "[ ./myejabberd.dump ]"; + example = lib.literalExpression "[ ./myejabberd.dump ]"; }; - imagemagick = mkOption { - type = types.bool; + imagemagick = lib.mkOption { + type = lib.types.bool; default = false; description = "Add ImageMagick to server's path; allows for image thumbnailing"; }; @@ -86,10 +83,10 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; - users.users = optionalAttrs (cfg.user == "ejabberd") { + users.users = lib.optionalAttrs (cfg.user == "ejabberd") { ejabberd = { group = cfg.group; home = cfg.spoolDir; @@ -98,7 +95,7 @@ in { }; }; - users.groups = optionalAttrs (cfg.group == "ejabberd") { + users.groups = lib.optionalAttrs (cfg.group == "ejabberd") { ejabberd.gid = config.ids.gids.ejabberd; }; diff --git a/nixos/modules/services/networking/envoy.nix b/nixos/modules/services/networking/envoy.nix index b36c184fe8d5..876c05755936 100644 --- a/nixos/modules/services/networking/envoy.nix +++ b/nixos/modules/services/networking/envoy.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.envoy; format = pkgs.formats.json { }; @@ -15,12 +12,12 @@ in { options.services.envoy = { - enable = mkEnableOption "Envoy reverse proxy"; + enable = lib.mkEnableOption "Envoy reverse proxy"; - package = mkPackageOption pkgs "envoy" { }; + package = lib.mkPackageOption pkgs "envoy" { }; - requireValidConfig = mkOption { - type = types.bool; + requireValidConfig = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether a failure during config validation at build time is fatal. @@ -29,10 +26,10 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { admin = { access_log_path = "/dev/null"; @@ -56,7 +53,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; systemd.services.envoy = { description = "Envoy reverse proxy"; diff --git a/nixos/modules/services/networking/epmd.nix b/nixos/modules/services/networking/epmd.nix index b450aa1b62c7..90876a67f74d 100644 --- a/nixos/modules/services/networking/epmd.nix +++ b/nixos/modules/services/networking/epmd.nix @@ -1,15 +1,12 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.epmd; in { ###### interface options.services.epmd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable socket activation for Erlang Port Mapper Daemon (epmd), @@ -17,10 +14,10 @@ in Erlang computations. ''; }; - package = mkPackageOption pkgs "erlang" { }; - listenStream = mkOption + package = lib.mkPackageOption pkgs "erlang" { }; + listenStream = lib.mkOption { - type = types.str; + type = lib.types.str; default = "[::]:4369"; description = '' the listenStream used by the systemd socket. @@ -32,7 +29,7 @@ in }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [{ assertion = cfg.listenStream == "[::]:4369" -> config.networking.enableIPv6; message = "epmd listens by default on ipv6, enable ipv6 or change config.services.epmd.listenStream"; @@ -60,5 +57,5 @@ in }; }; - meta.maintainers = teams.beam.members; + meta.maintainers = lib.teams.beam.members; } diff --git a/nixos/modules/services/networking/eternal-terminal.nix b/nixos/modules/services/networking/eternal-terminal.nix index d26e26d0c195..584eafd2962c 100644 --- a/nixos/modules/services/networking/eternal-terminal.nix +++ b/nixos/modules/services/networking/eternal-terminal.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.eternal-terminal; @@ -16,11 +13,11 @@ in services.eternal-terminal = { - enable = mkEnableOption "Eternal Terminal server"; + enable = lib.mkEnableOption "Eternal Terminal server"; - port = mkOption { + port = lib.mkOption { default = 2022; - type = types.port; + type = lib.types.port; description = '' The port the server should listen on. Will use the server's default (2022) if not specified. @@ -28,25 +25,25 @@ in ''; }; - verbosity = mkOption { + verbosity = lib.mkOption { default = 0; - type = types.enum (lib.range 0 9); + type = lib.types.enum (lib.range 0 9); description = '' The verbosity level (0-9). ''; }; - silent = mkOption { + silent = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' If enabled, disables all logging. ''; }; - logSize = mkOption { + logSize = lib.mkOption { default = 20971520; - type = types.int; + type = lib.types.int; description = '' The maximum log size. ''; @@ -56,7 +53,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # We need to ensure the et package is fully installed because # the (remote) et client runs the `etterminal` binary when it diff --git a/nixos/modules/services/networking/expressvpn.nix b/nixos/modules/services/networking/expressvpn.nix index c1d287f57bc2..431a1da70b95 100644 --- a/nixos/modules/services/networking/expressvpn.nix +++ b/nixos/modules/services/networking/expressvpn.nix @@ -1,16 +1,14 @@ { config, lib, pkgs, ... }: - -with lib; { - options.services.expressvpn.enable = mkOption { - type = types.bool; + options.services.expressvpn.enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable the ExpressVPN daemon. ''; }; - config = mkIf config.services.expressvpn.enable { + config = lib.mkIf config.services.expressvpn.enable { boot.kernelModules = [ "tun" ]; systemd.services.expressvpn = { @@ -26,5 +24,5 @@ with lib; }; }; - meta.maintainers = with maintainers; [ yureien ]; + meta.maintainers = with lib.maintainers; [ yureien ]; } diff --git a/nixos/modules/services/networking/fedimintd.nix b/nixos/modules/services/networking/fedimintd.nix new file mode 100644 index 000000000000..c7d93854e21a --- /dev/null +++ b/nixos/modules/services/networking/fedimintd.nix @@ -0,0 +1,309 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) + concatLists + filterAttrs + mapAttrs' + mapAttrsToList + mkEnableOption + mkIf + mkOption + mkOverride + mkPackageOption + nameValuePair + recursiveUpdate + types + ; + + fedimintdOpts = + { + config, + lib, + name, + ... + }: + { + options = { + enable = mkEnableOption "fedimintd"; + + package = mkPackageOption pkgs "fedimint" { }; + + environment = mkOption { + type = types.attrsOf types.str; + description = "Extra Environment variables to pass to the fedimintd."; + default = { + RUST_BACKTRACE = "1"; + }; + example = { + RUST_LOG = "info,fm=debug"; + RUST_BACKTRACE = "1"; + }; + }; + + p2p = { + openFirewall = mkOption { + type = types.bool; + default = true; + description = "Opens port in firewall for fedimintd's p2p port"; + }; + port = mkOption { + type = types.port; + default = 8173; + description = "Port to bind on for p2p connections from peers"; + }; + bind = mkOption { + type = types.str; + default = "0.0.0.0"; + description = "Address to bind on for p2p connections from peers"; + }; + url = mkOption { + type = types.str; + example = "fedimint://p2p.myfedimint.com:8173"; + description = '' + Public address for p2p connections from peers + ''; + }; + }; + api = { + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Opens port in firewall for fedimintd's api port"; + }; + port = mkOption { + type = types.port; + default = 8174; + description = "Port to bind on for API connections relied by the reverse proxy/tls terminator."; + }; + bind = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Address to bind on for API connections relied by the reverse proxy/tls terminator."; + }; + url = mkOption { + type = types.str; + description = '' + Public URL of the API address of the reverse proxy/tls terminator. Usually starting with `wss://`. + ''; + }; + }; + bitcoin = { + network = mkOption { + type = types.str; + default = "signet"; + example = "bitcoin"; + description = "Bitcoin network to participate in."; + }; + rpc = { + url = mkOption { + type = types.str; + default = "http://127.0.0.1:38332"; + example = "signet"; + description = "Bitcoin node (bitcoind/electrum/esplora) address to connect to"; + }; + + kind = mkOption { + type = types.str; + default = "bitcoind"; + example = "electrum"; + description = "Kind of a bitcoin node."; + }; + + secretFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + If set the URL specified in `bitcoin.rpc.url` will get the content of this file added + as an URL password, so `http://user@example.com` will turn into `http://user:SOMESECRET@example.com`. + + Example: + + `/etc/nix-bitcoin-secrets/bitcoin-rpcpassword-public` (for nix-bitcoin default) + ''; + }; + }; + }; + + consensus.finalityDelay = mkOption { + type = types.ints.unsigned; + default = 10; + description = "Consensus peg-in finality delay."; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/fedimintd-${name}/"; + readOnly = true; + description = '' + Path to the data dir fedimintd will use to store its data. + Note that due to using the DynamicUser feature of systemd, this value should not be changed + and is set to be read only. + ''; + }; + + nginx = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to configure nginx for fedimintd + ''; + }; + fqdn = mkOption { + type = types.str; + example = "api.myfedimint.com"; + description = "Public domain of the API address of the reverse proxy/tls terminator."; + }; + path = mkOption { + type = types.str; + example = "/"; + default = "/ws/"; + description = "Path to host the API on and forward to the daemon's api port"; + }; + config = mkOption { + type = types.submodule ( + recursiveUpdate (import ../web-servers/nginx/vhost-options.nix { + inherit config lib; + }) { } + ); + default = { }; + description = "Overrides to the nginx vhost section for api"; + }; + }; + }; + }; +in +{ + options = { + services.fedimintd = mkOption { + type = types.attrsOf (types.submodule fedimintdOpts); + default = { }; + description = "Specification of one or more fedimintd instances."; + }; + }; + + config = + let + eachFedimintd = filterAttrs (fedimintdName: cfg: cfg.enable) config.services.fedimintd; + eachFedimintdNginx = filterAttrs (fedimintdName: cfg: cfg.nginx.enable) eachFedimintd; + in + mkIf (eachFedimintd != { }) { + + networking.firewall.allowedTCPPorts = concatLists ( + mapAttrsToList ( + fedimintdName: cfg: + (lib.optional cfg.api.openFirewall cfg.api.port ++ lib.optional cfg.p2p.openFirewall cfg.p2p.port) + ) eachFedimintd + ); + + systemd.services = mapAttrs' ( + fedimintdName: cfg: + (nameValuePair "fedimintd-${fedimintdName}" ( + let + startScript = pkgs.writeShellScript "fedimintd-start" ( + ( + if cfg.bitcoin.rpc.secretFile != null then + '' + secret=$(${pkgs.coreutils}/bin/head -n 1 "${cfg.bitcoin.rpc.secretFile}") + prefix="''${FM_BITCOIN_RPC_URL%*@*}" # Everything before the last '@' + suffix="''${FM_BITCOIN_RPC_URL##*@}" # Everything after the last '@' + FM_BITCOIN_RPC_URL="''${prefix}:''${secret}@''${suffix}" + '' + else + "" + ) + + '' + exec ${cfg.package}/bin/fedimintd + '' + ); + in + { + description = "Fedimint Server"; + documentation = [ "https://github.com/fedimint/fedimint/" ]; + wantedBy = [ "multi-user.target" ]; + environment = lib.mkMerge [ + { + FM_BIND_P2P = "${cfg.p2p.bind}:${toString cfg.p2p.port}"; + FM_BIND_API = "${cfg.api.bind}:${toString cfg.api.port}"; + FM_P2P_URL = cfg.p2p.url; + FM_API_URL = cfg.api.url; + FM_DATA_DIR = cfg.dataDir; + FM_BITCOIN_NETWORK = cfg.bitcoin.network; + FM_BITCOIN_RPC_URL = cfg.bitcoin.rpc.url; + FM_BITCOIN_RPC_KIND = cfg.bitcoin.rpc.kind; + } + cfg.environment + ]; + serviceConfig = { + DynamicUser = true; + + StateDirectory = "fedimintd-${fedimintdName}"; + StateDirectoryMode = "0700"; + ExecStart = startScript; + + Restart = "always"; + RestartSec = 10; + StartLimitBurst = 5; + UMask = "007"; + LimitNOFILE = "100000"; + + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "full"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + }; + } + )) + ) eachFedimintd; + + services.nginx.virtualHosts = mapAttrs' ( + fedimintdName: cfg: + (nameValuePair cfg.nginx.fqdn ( + lib.mkMerge [ + cfg.nginx.config + + { + # Note: we want by default to enable OpenSSL, but it seems anything 100 and above is + # overriden by default value from vhost-options.nix + enableACME = mkOverride 99 true; + forceSSL = mkOverride 99 true; + locations.${cfg.nginx.path} = { + proxyPass = "http://127.0.0.1:${toString cfg.api.port}/"; + proxyWebsockets = true; + extraConfig = '' + proxy_pass_header Authorization; + ''; + }; + } + ] + )) + ) eachFedimintdNginx; + }; + + meta.maintainers = with lib.maintainers; [ dpc ]; +} diff --git a/nixos/modules/services/networking/ferm.nix b/nixos/modules/services/networking/ferm.nix index 91412f53009c..1fc982d8e9c8 100644 --- a/nixos/modules/services/networking/ferm.nix +++ b/nixos/modules/services/networking/ferm.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.ferm; @@ -17,9 +14,9 @@ let in { options = { services.ferm = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = '' Whether to enable Ferm Firewall. *Warning*: Enabling this service WILL disable the existing NixOS @@ -27,17 +24,17 @@ in { considered at the moment. ''; }; - config = mkOption { + config = lib.mkOption { description = "Verbatim ferm.conf configuration."; default = ""; - defaultText = literalMD "empty firewall, allows any traffic"; - type = types.lines; + defaultText = lib.literalMD "empty firewall, allows any traffic"; + type = lib.types.lines; }; - package = mkPackageOption pkgs "ferm" { }; + package = lib.mkPackageOption pkgs "ferm" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.firewall.enable = false; systemd.services.ferm = { description = "Ferm Firewall"; diff --git a/nixos/modules/services/networking/fireqos.nix b/nixos/modules/services/networking/fireqos.nix index 0b34f0b6b8b4..aa7d8c2c03ef 100644 --- a/nixos/modules/services/networking/fireqos.nix +++ b/nixos/modules/services/networking/fireqos.nix @@ -1,14 +1,11 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.fireqos; fireqosConfig = pkgs.writeText "fireqos.conf" "${cfg.config}"; in { options.services.fireqos = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, FireQOS will be launched with the specified @@ -16,8 +13,8 @@ in { ''; }; - config = mkOption { - type = types.str; + config = lib.mkOption { + type = lib.types.str; default = ""; example = '' interface wlp3s0 world-in input rate 10mbit ethernet @@ -34,7 +31,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.fireqos = { description = "FireQOS"; after = [ "network.target" ]; diff --git a/nixos/modules/services/networking/firewall-iptables.nix b/nixos/modules/services/networking/firewall-iptables.nix index 68895189bcae..086106f0d8d2 100644 --- a/nixos/modules/services/networking/firewall-iptables.nix +++ b/nixos/modules/services/networking/firewall-iptables.nix @@ -29,11 +29,7 @@ complete firewall (in the default configuration). */ - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.networking.firewall; @@ -89,17 +85,17 @@ let # jumps to the "nixos-fw-refuse" chain. ip46tables -N nixos-fw-log-refuse - ${optionalString cfg.logRefusedConnections '' + ${lib.optionalString cfg.logRefusedConnections '' ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "refused connection: " ''} - ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) '' + ${lib.optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) '' ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type broadcast \ -j LOG --log-level info --log-prefix "refused broadcast: " ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type multicast \ -j LOG --log-level info --log-prefix "refused multicast: " ''} ip46tables -A nixos-fw-log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse - ${optionalString cfg.logRefusedPackets '' + ${lib.optionalString cfg.logRefusedPackets '' ip46tables -A nixos-fw-log-refuse \ -j LOG --log-level info --log-prefix "refused packet: " ''} @@ -114,22 +110,19 @@ let ip46tables -t mangle -F nixos-fw-rpfilter 2> /dev/null || true ip46tables -t mangle -X nixos-fw-rpfilter 2> /dev/null || true - ${optionalString (kernelHasRPFilter && (cfg.checkReversePath != false)) '' + ${lib.optionalString (kernelHasRPFilter && (cfg.checkReversePath != false)) '' # Perform a reverse-path test to refuse spoofers # For now, we just drop, as the mangle table doesn't have a log-refuse yet ip46tables -t mangle -N nixos-fw-rpfilter 2> /dev/null || true - ip46tables -t mangle -A nixos-fw-rpfilter -m rpfilter --validmark ${optionalString (cfg.checkReversePath == "loose") "--loose"} -j RETURN + ip46tables -t mangle -A nixos-fw-rpfilter -m rpfilter --validmark ${lib.optionalString (cfg.checkReversePath == "loose") "--loose"} -j RETURN # Allows this host to act as a DHCP4 client without first having to use APIPA iptables -t mangle -A nixos-fw-rpfilter -p udp --sport 67 --dport 68 -j RETURN - # Allows decrypted packets from an IPsec VPN - ip46tables -t mangle -A nixos-fw-rpfilter -m policy --dir in --pol ipsec -j RETURN - # Allows this host to act as a DHCPv4 server iptables -t mangle -A nixos-fw-rpfilter -s 0.0.0.0 -d 255.255.255.255 -p udp --sport 68 --dport 67 -j RETURN - ${optionalString cfg.logReversePathDrops '' + ${lib.optionalString cfg.logReversePathDrops '' ip46tables -t mangle -A nixos-fw-rpfilter -j LOG --log-level info --log-prefix "rpfilter drop: " ''} ip46tables -t mangle -A nixos-fw-rpfilter -j DROP @@ -138,7 +131,7 @@ let ''} # Accept all traffic on the trusted interfaces. - ${flip concatMapStrings cfg.trustedInterfaces (iface: '' + ${lib.flip lib.concatMapStrings cfg.trustedInterfaces (iface: '' ip46tables -A nixos-fw -i ${iface} -j nixos-fw-accept '')} @@ -146,51 +139,51 @@ let ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept # Accept connections to the allowed TCP ports. - ${concatStrings (mapAttrsToList (iface: cfg: - concatMapStrings (port: + ${lib.concatStrings (lib.mapAttrsToList (iface: cfg: + lib.concatMapStrings (port: '' - ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"} + ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept ${lib.optionalString (iface != "default") "-i ${iface}"} '' ) cfg.allowedTCPPorts ) cfg.allInterfaces)} # Accept connections to the allowed TCP port ranges. - ${concatStrings (mapAttrsToList (iface: cfg: - concatMapStrings (rangeAttr: + ${lib.concatStrings (lib.mapAttrsToList (iface: cfg: + lib.concatMapStrings (rangeAttr: let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in '' - ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"} + ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept ${lib.optionalString (iface != "default") "-i ${iface}"} '' ) cfg.allowedTCPPortRanges ) cfg.allInterfaces)} # Accept packets on the allowed UDP ports. - ${concatStrings (mapAttrsToList (iface: cfg: - concatMapStrings (port: + ${lib.concatStrings (lib.mapAttrsToList (iface: cfg: + lib.concatMapStrings (port: '' - ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"} + ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept ${lib.optionalString (iface != "default") "-i ${iface}"} '' ) cfg.allowedUDPPorts ) cfg.allInterfaces)} # Accept packets on the allowed UDP port ranges. - ${concatStrings (mapAttrsToList (iface: cfg: - concatMapStrings (rangeAttr: + ${lib.concatStrings (lib.mapAttrsToList (iface: cfg: + lib.concatMapStrings (rangeAttr: let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in '' - ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"} + ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept ${lib.optionalString (iface != "default") "-i ${iface}"} '' ) cfg.allowedUDPPortRanges ) cfg.allInterfaces)} # Optionally respond to ICMPv4 pings. - ${optionalString cfg.allowPing '' - iptables -w -A nixos-fw -p icmp --icmp-type echo-request ${optionalString (cfg.pingLimit != null) + ${lib.optionalString cfg.allowPing '' + iptables -w -A nixos-fw -p icmp --icmp-type echo-request ${lib.optionalString (cfg.pingLimit != null) "-m limit ${cfg.pingLimit} " }-j nixos-fw-accept ''} - ${optionalString config.networking.enableIPv6 '' + ${lib.optionalString config.networking.enableIPv6 '' # Accept all ICMPv6 messages except redirects and node # information queries (type 139). See RFC 4890, section # 4.4. @@ -221,7 +214,7 @@ let # Clean up after added ruleset ip46tables -D INPUT -j nixos-fw 2>/dev/null || true - ${optionalString (kernelHasRPFilter && (cfg.checkReversePath != false)) '' + ${lib.optionalString (kernelHasRPFilter && (cfg.checkReversePath != false)) '' ip46tables -t mangle -D PREROUTING -j nixos-fw-rpfilter 2>/dev/null || true ''} @@ -259,8 +252,8 @@ in options = { networking.firewall = { - extraCommands = mkOption { - type = types.lines; + extraCommands = lib.mkOption { + type = lib.types.lines; default = ""; example = "iptables -A INPUT -p icmp -j ACCEPT"; description = '' @@ -273,8 +266,8 @@ in ''; }; - extraStopCommands = mkOption { - type = types.lines; + extraStopCommands = lib.mkOption { + type = lib.types.lines; default = ""; example = "iptables -P INPUT ACCEPT"; description = '' @@ -292,7 +285,7 @@ in # FIXME: Maybe if `enable' is false, the firewall should still be # built but not started by default? - config = mkIf (cfg.enable && config.networking.nftables.enable == false) { + config = lib.mkIf (cfg.enable && config.networking.nftables.enable == false) { assertions = [ # This is approximately "checkReversePath -> kernelHasRPFilter", @@ -304,8 +297,7 @@ in } ]; - environment.systemPackages = [ pkgs.nixos-firewall-tool ]; - networking.firewall.checkReversePath = mkIf (!kernelHasRPFilter) (mkDefault false); + networking.firewall.checkReversePath = lib.mkIf (!kernelHasRPFilter) (lib.mkDefault false); systemd.services.firewall = { description = "Firewall"; diff --git a/nixos/modules/services/networking/firewall-nftables.nix b/nixos/modules/services/networking/firewall-nftables.nix index 661d5c9fb1a6..06f070caf25a 100644 --- a/nixos/modules/services/networking/firewall-nftables.nix +++ b/nixos/modules/services/networking/firewall-nftables.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.networking.firewall; - ifaceSet = concatStringsSep ", " ( + ifaceSet = lib.concatStringsSep ", " ( map (x: ''"${x}"'') cfg.trustedInterfaces ); - portsToNftSet = ports: portRanges: concatStringsSep ", " ( + portsToNftSet = ports: portRanges: lib.concatStringsSep ", " ( map (x: toString x) ports ++ map (x: "${toString x.from}-${toString x.to}") portRanges ); @@ -22,8 +19,8 @@ in options = { networking.firewall = { - extraInputRules = mkOption { - type = types.lines; + extraInputRules = lib.mkOption { + type = lib.types.lines; default = ""; example = "ip6 saddr { fc00::/7, fe80::/10 } tcp dport 24800 accept"; description = '' @@ -34,8 +31,8 @@ in ''; }; - extraForwardRules = mkOption { - type = types.lines; + extraForwardRules = lib.mkOption { + type = lib.types.lines; default = ""; example = "iifname wg0 accept"; description = '' @@ -46,8 +43,8 @@ in ''; }; - extraReversePathFilterRules = mkOption { - type = types.lines; + extraReversePathFilterRules = lib.mkOption { + type = lib.types.lines; default = ""; example = "fib daddr . mark . iif type local accept"; description = '' @@ -61,7 +58,7 @@ in }; - config = mkIf (cfg.enable && config.networking.nftables.enable) { + config = lib.mkIf (cfg.enable && config.networking.nftables.enable) { assertions = [ { @@ -73,7 +70,7 @@ in message = "extraStopCommands is incompatible with the nftables based firewall: ${cfg.extraStopCommands}"; } { - assertion = cfg.pingLimit == null || !(hasPrefix "--" cfg.pingLimit); + assertion = cfg.pingLimit == null || !(lib.hasPrefix "--" cfg.pingLimit); message = "nftables syntax like \"2/second\" should be used in networking.firewall.pingLimit"; } { @@ -82,24 +79,25 @@ in } ]; - networking.nftables.preCheckRuleset = '' - # can't validate IPsec rules - sed '/meta ipsec/d' -i ruleset.conf - ''; - networking.nftables.tables."nixos-fw".family = "inet"; networking.nftables.tables."nixos-fw".content = '' - ${optionalString (cfg.checkReversePath != false) '' + set temp-ports { + comment "Temporarily opened ports" + type inet_proto . inet_service + flags interval + auto-merge + } + + ${lib.optionalString (cfg.checkReversePath != false) '' chain rpfilter { type filter hook prerouting priority mangle + 10; policy drop; meta nfproto ipv4 udp sport . udp dport { 67 . 68, 68 . 67 } accept comment "DHCPv4 client/server" - meta ipsec exists accept comment "decrypted packets from an IPsec VPN" - fib saddr . mark ${optionalString (cfg.checkReversePath != "loose") ". iif"} oif exists accept + fib saddr . mark ${lib.optionalString (cfg.checkReversePath != "loose") ". iif"} oif exists accept jump rpfilter-allow - ${optionalString cfg.logReversePathDrops '' + ${lib.optionalString cfg.logReversePathDrops '' log level info prefix "rpfilter drop: " ''} @@ -113,7 +111,7 @@ in chain input { type filter hook input priority filter; policy drop; - ${optionalString (ifaceSet != "") ''iifname { ${ifaceSet} } accept comment "trusted interfaces"''} + ${lib.optionalString (ifaceSet != "") ''iifname { ${ifaceSet} } accept comment "trusted interfaces"''} # Some ICMPv6 types like NDP is untracked ct state vmap { @@ -124,18 +122,18 @@ in untracked: jump input-allow, } - ${optionalString cfg.logRefusedConnections '' + ${lib.optionalString cfg.logRefusedConnections '' tcp flags syn / fin,syn,rst,ack log level info prefix "refused connection: " ''} - ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) '' + ${lib.optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) '' pkttype broadcast log level info prefix "refused broadcast: " pkttype multicast log level info prefix "refused multicast: " ''} - ${optionalString cfg.logRefusedPackets '' + ${lib.optionalString cfg.logRefusedPackets '' pkttype host log level info prefix "refused packet: " ''} - ${optionalString cfg.rejectPackets '' + ${lib.optionalString cfg.rejectPackets '' meta l4proto tcp reject with tcp reset reject ''} @@ -144,20 +142,22 @@ in chain input-allow { - ${concatStrings (mapAttrsToList (iface: cfg: + ${lib.concatStrings (lib.mapAttrsToList (iface: cfg: let - ifaceExpr = optionalString (iface != "default") "iifname ${iface}"; + ifaceExpr = lib.optionalString (iface != "default") "iifname ${iface}"; tcpSet = portsToNftSet cfg.allowedTCPPorts cfg.allowedTCPPortRanges; udpSet = portsToNftSet cfg.allowedUDPPorts cfg.allowedUDPPortRanges; in '' - ${optionalString (tcpSet != "") "${ifaceExpr} tcp dport { ${tcpSet} } accept"} - ${optionalString (udpSet != "") "${ifaceExpr} udp dport { ${udpSet} } accept"} + ${lib.optionalString (tcpSet != "") "${ifaceExpr} tcp dport { ${tcpSet} } accept"} + ${lib.optionalString (udpSet != "") "${ifaceExpr} udp dport { ${udpSet} } accept"} '' ) cfg.allInterfaces)} - ${optionalString cfg.allowPing '' - icmp type echo-request ${optionalString (cfg.pingLimit != null) "limit rate ${cfg.pingLimit}"} accept comment "allow ping" + meta l4proto . th dport @temp-ports accept + + ${lib.optionalString cfg.allowPing '' + icmp type echo-request ${lib.optionalString (cfg.pingLimit != null) "limit rate ${cfg.pingLimit}"} accept comment "allow ping" ''} icmpv6 type != { nd-redirect, 139 } accept comment "Accept all ICMPv6 messages except redirects and node information queries (type 139). See RFC 4890, section 4.4." @@ -167,7 +167,7 @@ in } - ${optionalString cfg.filterForward '' + ${lib.optionalString cfg.filterForward '' chain forward { type filter hook forward priority filter; policy drop; diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix index a35cc51a3870..ab575b884a71 100644 --- a/nixos/modules/services/networking/firewall.nix +++ b/nixos/modules/services/networking/firewall.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.networking.firewall; @@ -10,8 +7,8 @@ let ports: lib.unique (builtins.sort builtins.lessThan ports); commonOptions = { - allowedTCPPorts = mkOption { - type = types.listOf types.port; + allowedTCPPorts = lib.mkOption { + type = lib.types.listOf lib.types.port; default = [ ]; apply = canonicalizePortList; example = [ 22 80 ]; @@ -21,8 +18,8 @@ let ''; }; - allowedTCPPortRanges = mkOption { - type = types.listOf (types.attrsOf types.port); + allowedTCPPortRanges = lib.mkOption { + type = lib.types.listOf (lib.types.attrsOf lib.types.port); default = [ ]; example = [{ from = 8999; to = 9003; }]; description = '' @@ -31,8 +28,8 @@ let ''; }; - allowedUDPPorts = mkOption { - type = types.listOf types.port; + allowedUDPPorts = lib.mkOption { + type = lib.types.listOf lib.types.port; default = [ ]; apply = canonicalizePortList; example = [ 53 ]; @@ -41,8 +38,8 @@ let ''; }; - allowedUDPPortRanges = mkOption { - type = types.listOf (types.attrsOf types.port); + allowedUDPPortRanges = lib.mkOption { + type = lib.types.listOf (lib.types.attrsOf lib.types.port); default = [ ]; example = [{ from = 60000; to = 61000; }]; description = '' @@ -58,8 +55,8 @@ in options = { networking.firewall = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable the firewall. This is a simple stateful @@ -68,18 +65,18 @@ in ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; default = if config.networking.nftables.enable then pkgs.nftables else pkgs.iptables; - defaultText = literalExpression ''if config.networking.nftables.enable then "pkgs.nftables" else "pkgs.iptables"''; - example = literalExpression "pkgs.iptables-legacy"; + defaultText = lib.literalExpression ''if config.networking.nftables.enable then "pkgs.nftables" else "pkgs.iptables"''; + example = lib.literalExpression "pkgs.iptables-legacy"; description = '' The package to use for running the firewall service. ''; }; - logRefusedConnections = mkOption { - type = types.bool; + logRefusedConnections = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to log rejected or dropped incoming connections. @@ -88,8 +85,8 @@ in ''; }; - logRefusedPackets = mkOption { - type = types.bool; + logRefusedPackets = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to log all rejected or dropped incoming packets. @@ -100,8 +97,8 @@ in ''; }; - logRefusedUnicastsOnly = mkOption { - type = types.bool; + logRefusedUnicastsOnly = lib.mkOption { + type = lib.types.bool; default = true; description = '' If {option}`networking.firewall.logRefusedPackets` @@ -111,8 +108,8 @@ in ''; }; - rejectPackets = mkOption { - type = types.bool; + rejectPackets = lib.mkOption { + type = lib.types.bool; default = false; description = '' If set, refused packets are rejected rather than dropped @@ -123,8 +120,8 @@ in ''; }; - trustedInterfaces = mkOption { - type = types.listOf types.str; + trustedInterfaces = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "enp0s2" ]; description = '' @@ -134,8 +131,8 @@ in ''; }; - allowPing = mkOption { - type = types.bool; + allowPing = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to respond to incoming ICMPv4 echo requests @@ -145,8 +142,8 @@ in ''; }; - pingLimit = mkOption { - type = types.nullOr (types.separatedString " "); + pingLimit = lib.mkOption { + type = lib.types.nullOr (lib.types.separatedString " "); default = null; example = "--limit 1/minute --limit-burst 5"; description = '' @@ -160,10 +157,10 @@ in ''; }; - checkReversePath = mkOption { - type = types.either types.bool (types.enum [ "strict" "loose" ]); + checkReversePath = lib.mkOption { + type = lib.types.either lib.types.bool (lib.types.enum [ "strict" "loose" ]); default = true; - defaultText = literalMD "`true` except if the iptables based firewall is in use and the kernel lacks rpfilter support"; + defaultText = lib.literalMD "`true` except if the iptables based firewall is in use and the kernel lacks rpfilter support"; example = "loose"; description = '' Performs a reverse path filter test on a packet. If a reply @@ -180,8 +177,8 @@ in ''; }; - logReversePathDrops = mkOption { - type = types.bool; + logReversePathDrops = lib.mkOption { + type = lib.types.bool; default = false; description = '' Logs dropped packets failing the reverse path filter test if @@ -189,8 +186,8 @@ in ''; }; - filterForward = mkOption { - type = types.bool; + filterForward = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable filtering in IP forwarding. @@ -199,8 +196,8 @@ in ''; }; - connectionTrackingModules = mkOption { - type = types.listOf types.str; + connectionTrackingModules = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ]; description = '' @@ -219,8 +216,8 @@ in ''; }; - autoLoadConntrackHelpers = mkOption { - type = types.bool; + autoLoadConntrackHelpers = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to auto-load connection-tracking helpers. @@ -230,29 +227,29 @@ in ''; }; - extraPackages = mkOption { - type = types.listOf types.package; + extraPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = [ ]; - example = literalExpression "[ pkgs.ipset ]"; + example = lib.literalExpression "[ pkgs.ipset ]"; description = '' Additional packages to be included in the environment of the system as well as the path of networking.firewall.extraCommands. ''; }; - interfaces = mkOption { + interfaces = lib.mkOption { default = { }; - type = with types; attrsOf (submodule [{ options = commonOptions; }]); + type = with lib.types; attrsOf (submodule [{ options = commonOptions; }]); description = '' Interface-specific open ports. ''; }; - allInterfaces = mkOption { + allInterfaces = lib.mkOption { internal = true; visible = false; - default = { default = mapAttrs (name: value: cfg.${name}) commonOptions; } // cfg.interfaces; - type = with types; attrsOf (submodule [{ options = commonOptions; }]); + default = { default = lib.mapAttrs (name: value: cfg.${name}) commonOptions; } // cfg.interfaces; + type = with lib.types; attrsOf (submodule [{ options = commonOptions; }]); description = '' All open ports. ''; @@ -262,7 +259,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { @@ -277,11 +274,14 @@ in networking.firewall.trustedInterfaces = [ "lo" ]; - environment.systemPackages = [ cfg.package ] ++ cfg.extraPackages; + environment.systemPackages = [ + cfg.package + pkgs.nixos-firewall-tool + ] ++ cfg.extraPackages; - boot.kernelModules = (optional cfg.autoLoadConntrackHelpers "nf_conntrack") + boot.kernelModules = (lib.optional cfg.autoLoadConntrackHelpers "nf_conntrack") ++ map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules; - boot.extraModprobeConfig = optionalString cfg.autoLoadConntrackHelpers '' + boot.extraModprobeConfig = lib.optionalString cfg.autoLoadConntrackHelpers '' options nf_conntrack nf_conntrack_helper=1 ''; diff --git a/nixos/modules/services/networking/flannel.nix b/nixos/modules/services/networking/flannel.nix index c55557b668b8..05987df88c18 100644 --- a/nixos/modules/services/networking/flannel.nix +++ b/nixos/modules/services/networking/flannel.nix @@ -1,11 +1,8 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.flannel; - networkConfig = filterAttrs (n: v: v != null) { + networkConfig = lib.filterAttrs (n: v: v != null) { Network = cfg.network; SubnetLen = cfg.subnetLen; SubnetMin = cfg.subnetMin; @@ -14,128 +11,128 @@ let }; in { options.services.flannel = { - enable = mkEnableOption "flannel"; + enable = lib.mkEnableOption "flannel"; - package = mkPackageOption pkgs "flannel" { }; + package = lib.mkPackageOption pkgs "flannel" { }; - publicIp = mkOption { + publicIp = lib.mkOption { description = '' IP accessible by other nodes for inter-host communication. Defaults to the IP of the interface being used for communication. ''; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; }; - iface = mkOption { + iface = lib.mkOption { description = '' Interface to use (IP or name) for inter-host communication. Defaults to the interface for the default route on the machine. ''; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; }; etcd = { - endpoints = mkOption { + endpoints = lib.mkOption { description = "Etcd endpoints"; - type = types.listOf types.str; + type = lib.types.listOf lib.types.str; default = ["http://127.0.0.1:2379"]; }; - prefix = mkOption { + prefix = lib.mkOption { description = "Etcd key prefix"; - type = types.str; + type = lib.types.str; default = "/coreos.com/network"; }; - caFile = mkOption { + caFile = lib.mkOption { description = "Etcd certificate authority file"; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; }; - certFile = mkOption { + certFile = lib.mkOption { description = "Etcd cert file"; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; }; - keyFile = mkOption { + keyFile = lib.mkOption { description = "Etcd key file"; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; }; }; - kubeconfig = mkOption { + kubeconfig = lib.mkOption { description = '' Path to kubeconfig to use for storing flannel config using the Kubernetes API ''; - type = types.nullOr types.path; + type = lib.types.nullOr lib.types.path; default = null; }; - network = mkOption { + network = lib.mkOption { description = " IPv4 network in CIDR format to use for the entire flannel network."; - type = types.str; + type = lib.types.str; }; - nodeName = mkOption { + nodeName = lib.mkOption { description = '' Needed when running with Kubernetes as backend as this cannot be auto-detected"; ''; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = config.networking.fqdnOrHostName; - defaultText = literalExpression "config.networking.fqdnOrHostName"; + defaultText = lib.literalExpression "config.networking.fqdnOrHostName"; example = "node1.example.com"; }; - storageBackend = mkOption { + storageBackend = lib.mkOption { description = "Determines where flannel stores its configuration at runtime"; - type = types.enum ["etcd" "kubernetes"]; + type = lib.types.enum ["etcd" "kubernetes"]; default = "etcd"; }; - subnetLen = mkOption { + subnetLen = lib.mkOption { description = '' The size of the subnet allocated to each host. Defaults to 24 (i.e. /24) unless the Network was configured to be smaller than a /24 in which case it is one less than the network. ''; - type = types.int; + type = lib.types.int; default = 24; }; - subnetMin = mkOption { + subnetMin = lib.mkOption { description = '' The beginning of IP range which the subnet allocation should start with. Defaults to the first subnet of Network. ''; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; }; - subnetMax = mkOption { + subnetMax = lib.mkOption { description = '' The end of IP range which the subnet allocation should start with. Defaults to the last subnet of Network. ''; - type = types.nullOr types.str; + type = lib.types.nullOr lib.types.str; default = null; }; - backend = mkOption { + backend = lib.mkOption { description = "Type of backend to use and specific configurations for that backend."; - type = types.attrs; + type = lib.types.attrs; default = { Type = "vxlan"; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.flannel = { description = "Flannel Service"; wantedBy = [ "multi-user.target" ]; @@ -143,23 +140,23 @@ in { environment = { FLANNELD_PUBLIC_IP = cfg.publicIp; FLANNELD_IFACE = cfg.iface; - } // optionalAttrs (cfg.storageBackend == "etcd") { - FLANNELD_ETCD_ENDPOINTS = concatStringsSep "," cfg.etcd.endpoints; + } // lib.optionalAttrs (cfg.storageBackend == "etcd") { + FLANNELD_ETCD_ENDPOINTS = lib.concatStringsSep "," cfg.etcd.endpoints; FLANNELD_ETCD_KEYFILE = cfg.etcd.keyFile; FLANNELD_ETCD_CERTFILE = cfg.etcd.certFile; FLANNELD_ETCD_CAFILE = cfg.etcd.caFile; ETCDCTL_CERT = cfg.etcd.certFile; ETCDCTL_KEY = cfg.etcd.keyFile; ETCDCTL_CACERT = cfg.etcd.caFile; - ETCDCTL_ENDPOINTS = concatStringsSep "," cfg.etcd.endpoints; + ETCDCTL_ENDPOINTS = lib.concatStringsSep "," cfg.etcd.endpoints; ETCDCTL_API = "3"; - } // optionalAttrs (cfg.storageBackend == "kubernetes") { + } // lib.optionalAttrs (cfg.storageBackend == "kubernetes") { FLANNELD_KUBE_SUBNET_MGR = "true"; FLANNELD_KUBECONFIG_FILE = cfg.kubeconfig; NODE_NAME = cfg.nodeName; }; path = [ pkgs.iptables ]; - preStart = optionalString (cfg.storageBackend == "etcd") '' + preStart = lib.optionalString (cfg.storageBackend == "etcd") '' echo "setting network configuration" until ${pkgs.etcd}/bin/etcdctl put /coreos.com/network/config '${builtins.toJSON networkConfig}' do @@ -175,11 +172,11 @@ in { }; }; - services.etcd.enable = mkDefault (cfg.storageBackend == "etcd" && cfg.etcd.endpoints == ["http://127.0.0.1:2379"]); + services.etcd.enable = lib.mkDefault (cfg.storageBackend == "etcd" && cfg.etcd.endpoints == ["http://127.0.0.1:2379"]); # for some reason, flannel doesn't let you configure this path # see: https://github.com/coreos/flannel/blob/master/Documentation/configuration.md#configuration - environment.etc."kube-flannel/net-conf.json" = mkIf (cfg.storageBackend == "kubernetes") { + environment.etc."kube-flannel/net-conf.json" = lib.mkIf (cfg.storageBackend == "kubernetes") { source = pkgs.writeText "net-conf.json" (builtins.toJSON networkConfig); }; }; diff --git a/nixos/modules/services/networking/freenet.nix b/nixos/modules/services/networking/freenet.nix index 3da3ab0c7df4..4323b98d6707 100644 --- a/nixos/modules/services/networking/freenet.nix +++ b/nixos/modules/services/networking/freenet.nix @@ -1,9 +1,5 @@ # NixOS module for Freenet daemon - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.freenet; @@ -19,14 +15,14 @@ in services.freenet = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable the Freenet daemon"; }; - nice = mkOption { - type = types.int; + nice = lib.mkOption { + type = lib.types.int; default = 10; description = "Set the nice level for the Freenet daemon"; }; @@ -37,7 +33,7 @@ in ### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.freenet = { description = "Freenet daemon"; diff --git a/nixos/modules/services/networking/freeradius.nix b/nixos/modules/services/networking/freeradius.nix index 7fa3a8fa17fa..d747219b29cb 100644 --- a/nixos/modules/services/networking/freeradius.nix +++ b/nixos/modules/services/networking/freeradius.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.freeradius; @@ -13,14 +10,14 @@ let after = ["network.target"]; wants = ["network.target"]; preStart = '' - ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout + ${cfg.package}/bin/radiusd -C -d ${cfg.configDir} -l stdout ''; serviceConfig = { - ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout" + - optionalString cfg.debug " -xx"; + ExecStart = "${cfg.package}/bin/radiusd -f -d ${cfg.configDir} -l stdout" + + lib.optionalString cfg.debug " -xx"; ExecReload = [ - "${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" + "${cfg.package}/bin/radiusd -C -d ${cfg.configDir} -l stdout" "${pkgs.coreutils}/bin/kill -HUP $MAINPID" ]; User = "radius"; @@ -33,18 +30,20 @@ let }; freeradiusConfig = { - enable = mkEnableOption "the freeradius server"; + enable = lib.mkEnableOption "the freeradius server"; - configDir = mkOption { - type = types.path; + package = lib.mkPackageOption pkgs "freeradius" { }; + + configDir = lib.mkOption { + type = lib.types.path; default = "/etc/raddb"; description = '' The path of the freeradius server configuration directory. ''; }; - debug = mkOption { - type = types.bool; + debug = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable debug logging for freeradius (-xx @@ -68,18 +67,20 @@ in ###### implementation - config = mkIf (cfg.enable) { + config = lib.mkIf (cfg.enable) { users = { users.radius = { /*uid = config.ids.uids.radius;*/ description = "Radius daemon user"; isSystemUser = true; + group = "radius"; }; + groups.radius = {}; }; systemd.services.freeradius = freeradiusService cfg; - warnings = optional cfg.debug "Freeradius debug logging is enabled. This will log passwords in plaintext to the journal!"; + warnings = lib.optional cfg.debug "Freeradius debug logging is enabled. This will log passwords in plaintext to the journal!"; }; diff --git a/nixos/modules/services/networking/frp.nix b/nixos/modules/services/networking/frp.nix index fc15efe5642d..56af543b845b 100644 --- a/nixos/modules/services/networking/frp.nix +++ b/nixos/modules/services/networking/frp.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.frp; settingsFormat = pkgs.formats.toml { }; @@ -12,12 +9,12 @@ in { options = { services.frp = { - enable = mkEnableOption "frp"; + enable = lib.mkEnableOption "frp"; - package = mkPackageOption pkgs "frp" { }; + package = lib.mkPackageOption pkgs "frp" { }; - role = mkOption { - type = types.enum [ "server" "client" ]; + role = lib.mkOption { + type = lib.types.enum [ "server" "client" ]; description = '' The frp consists of `client` and `server`. The server is usually deployed on the machine with a public IP address, and @@ -26,7 +23,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = settingsFormat.type; default = { }; description = '' @@ -44,13 +41,13 @@ in config = let - serviceCapability = optionals isServer [ "CAP_NET_BIND_SERVICE" ]; + serviceCapability = lib.optionals isServer [ "CAP_NET_BIND_SERVICE" ]; executableFile = if isClient then "frpc" else "frps"; in - mkIf cfg.enable { + lib.mkIf cfg.enable { systemd.services = { frp = { - wants = optionals isClient [ "network-online.target" ]; + wants = lib.optionals isClient [ "network-online.target" ]; after = if isClient then [ "network-online.target" ] else [ "network.target" ]; wantedBy = [ "multi-user.target" ]; description = "A fast reverse proxy frp ${cfg.role}"; @@ -59,10 +56,10 @@ in Restart = "on-failure"; RestartSec = 15; ExecStart = "${cfg.package}/bin/${executableFile} --strict_config -c ${configFile}"; - StateDirectoryMode = optionalString isServer "0700"; + StateDirectoryMode = lib.optionalString isServer "0700"; DynamicUser = true; # Hardening - UMask = optionalString isServer "0007"; + UMask = lib.optionalString isServer "0007"; CapabilityBoundingSet = serviceCapability; AmbientCapabilities = serviceCapability; PrivateDevices = true; @@ -72,7 +69,7 @@ in ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; - RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ] ++ optionals isClient [ "AF_UNIX" ]; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ] ++ lib.optionals isClient [ "AF_UNIX" ]; LockPersonality = true; MemoryDenyWriteExecute = true; RestrictRealtime = true; @@ -85,5 +82,5 @@ in }; }; - meta.maintainers = with maintainers; [ zaldnoay ]; + meta.maintainers = with lib.maintainers; [ zaldnoay ]; } diff --git a/nixos/modules/services/networking/frr.nix b/nixos/modules/services/networking/frr.nix index df2b4035d2f0..a70d1dd6554f 100644 --- a/nixos/modules/services/networking/frr.nix +++ b/nixos/modules/services/networking/frr.nix @@ -1,13 +1,55 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.frr; - services = [ - "static" + daemons = [ + "bgpd" + "ospfd" + "ospf6d" + "ripd" + "ripngd" + "isisd" + "pimd" + "pim6d" + "ldpd" + "nhrpd" + "eigrpd" + "babeld" + "sharpd" + "pbrd" + "bfdd" + "fabricd" + "vrrpd" + "pathd" + ]; + + daemonDefaultOptions = { + zebra = "-A 127.0.0.1 -s 90000000"; + mgmtd = "-A 127.0.0.1"; + bgpd = "-A 127.0.0.1"; + ospfd = "-A 127.0.0.1"; + ospf6d = "-A ::1"; + ripd = "-A 127.0.0.1"; + ripngd = "-A ::1"; + isisd = "-A 127.0.0.1"; + pimd = "-A 127.0.0.1"; + pim6d = "-A ::1"; + ldpd = "-A 127.0.0.1"; + nhrpd = "-A 127.0.0.1"; + eigrpd = "-A 127.0.0.1"; + babeld = "-A 127.0.0.1"; + sharpd = "-A 127.0.0.1"; + pbrd = "-A 127.0.0.1"; + staticd = "-A 127.0.0.1"; + bfdd = "-A 127.0.0.1"; + fabricd = "-A 127.0.0.1"; + vrrpd = "-A 127.0.0.1"; + pathd = "-A 127.0.0.1"; + }; + + renamedServices = [ "bgp" "ospf" "ospf6" @@ -25,210 +67,194 @@ let "fabric" ]; - allServices = services ++ [ "zebra" "mgmt" ]; + obsoleteServices = renamedServices ++ [ "static" "mgmt" "zebra" ]; + + allDaemons = builtins.attrNames daemonDefaultOptions; isEnabled = service: cfg.${service}.enable; - daemonName = service: if service == "zebra" then service else "${service}d"; + daemonLine = d: "${d}=${if isEnabled d then "yes" else "no"}"; - configFile = service: - let - scfg = cfg.${service}; - in - if scfg.configFile != null then scfg.configFile - else pkgs.writeText "${daemonName service}.conf" - '' - ! FRR ${daemonName service} configuration - ! - hostname ${config.networking.hostName} - log syslog - service password-encryption - ! - ${scfg.config} - ! - end - ''; + configFile = + if cfg.configFile != null then + cfg.configFile + else + pkgs.writeText "frr.conf" '' + ! FRR configuration + ! + hostname ${config.networking.hostName} + log syslog + service password-encryption + service integrated-vtysh-config + ! + ${cfg.config} + ! + end + ''; - serviceOptions = service: + serviceOptions = + service: { - enable = mkEnableOption "the FRR ${toUpper service} routing protocol"; - - configFile = mkOption { - type = types.nullOr types.path; - default = null; - example = "/etc/frr/${daemonName service}.conf"; + options = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ daemonDefaultOptions.${service} ]; description = '' - Configuration file to use for FRR ${daemonName service}. - By default the NixOS generated files are used. + Options for the FRR ${service} daemon. ''; }; - - config = mkOption { - type = types.lines; - default = ""; - example = - let - examples = { - rip = '' - router rip - network 10.0.0.0/8 - ''; - - ospf = '' - router ospf - network 10.0.0.0/8 area 0 - ''; - - bgp = '' - router bgp 65001 - neighbor 10.0.0.1 remote-as 65001 - ''; - }; - in - examples.${service} or ""; + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; description = '' - ${daemonName service} configuration statements. + Extra options to be appended to the FRR ${service} daemon options. ''; }; - - vtyListenAddress = mkOption { - type = types.str; - default = "localhost"; - description = '' - Address to bind to for the VTY interface. - ''; - }; - - vtyListenPort = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - TCP Port to bind to for the VTY interface. - ''; - }; - - extraOptions = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Extra options for the daemon. - ''; - }; - }; + } + // (if (builtins.elem service daemons) then { enable = lib.mkEnableOption "FRR ${service}"; } else { }); in { ###### interface - imports = [ - { - options.services.frr = { - zebra = (serviceOptions "zebra") // { - enable = mkOption { - type = types.bool; - default = any isEnabled services; + imports = + [ + { + options.services.frr = { + configFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/etc/frr/frr.conf"; description = '' - Whether to enable the Zebra routing manager. - - The Zebra routing manager is automatically enabled - if any routing protocols are configured. + Configuration file to use for FRR. + By default the NixOS generated files are used. + ''; + }; + config = lib.mkOption { + type = lib.types.lines; + default = ""; + example = '' + router rip + network 10.0.0.0/8 + router ospf + network 10.0.0.0/8 area 0 + router bgp 65001 + neighbor 10.0.0.1 remote-as 65001 + ''; + description = '' + FRR configuration statements. + ''; + }; + openFilesLimit = lib.mkOption { + type = lib.types.ints.unsigned; + default = 1024; + description = '' + This is the maximum number of FD's that will be available. Use a + reasonable value for your setup if you are expecting a large number + of peers in say BGP. ''; }; }; - mgmt = (serviceOptions "mgmt") // { - enable = mkOption { - type = types.bool; - default = isEnabled "static"; - defaultText = lib.literalExpression "config.services.frr.static.enable"; - description = '' - Whether to enable the Configuration management daemon. - - The Configuration management daemon is automatically - enabled if needed, at the moment this is when staticd - is enabled. - ''; - }; - }; - }; - } - { options.services.frr = (genAttrs services serviceOptions); } - ]; + } + { options.services.frr = (lib.genAttrs allDaemons serviceOptions); } + (lib.mkRemovedOptionModule [ "services" "frr" "zebra" "enable" ] "FRR zebra is always enabled") + ] + ++ (map (d: lib.mkRenamedOptionModule [ "services" "frr" d "enable" ] [ "services" "frr" "${d}d" "enable" ]) renamedServices) + ++ (map (d: lib.mkRenamedOptionModule [ "services" "frr" d "extraOptions" ] [ "services" "frr" "${d}d" "extraOptions" ]) (renamedServices ++ [ "static" "mgmt" ])) + ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "enable" ] "FRR ${d}d is always enabled") [ "static" "mgmt" ]) + ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "config" ] "FRR switched to integrated-vtysh-config, please use services.frr.config") obsoleteServices) + ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "configFile" ] "FRR switched to integrated-vtysh-config, please use services.frr.config or services.frr.configFile") obsoleteServices) + ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "vtyListenAddress" ] "Please change -A option in services.frr.${d}.options instead") obsoleteServices) + ++ (map (d: lib.mkRemovedOptionModule [ "services" "frr" d "vtyListenPort" ] "Please use `-P «vtyListenPort»` option with services.frr.${d}.extraOptions instead, or change services.frr.${d}.options accordingly") obsoleteServices) + ; ###### implementation - config = mkIf (any isEnabled allServices) { - - environment.systemPackages = [ - pkgs.frr # for the vtysh tool - ]; - - users.users.frr = { - description = "FRR daemon user"; - isSystemUser = true; - group = "frr"; - }; - - users.groups = { - frr = {}; - # Members of the frrvty group can use vtysh to inspect the FRR daemons - frrvty = { members = [ "frr" ]; }; - }; - - environment.etc = let - mkEtcLink = service: { - name = "frr/${daemonName service}.conf"; - value.source = configFile service; - }; + config = + let + daemonList = lib.concatStringsSep "\n" (map daemonLine daemons); + daemonOptionLine = d: "${d}_options=\"${lib.concatStringsSep " " (cfg.${d}.options ++ cfg.${d}.extraOptions)}\""; + daemonOptions = lib.concatStringsSep "\n" (map daemonOptionLine allDaemons); in - (builtins.listToAttrs - (map mkEtcLink (filter isEnabled allServices))) // { - "frr/vtysh.conf".text = ""; + lib.mkIf (lib.any isEnabled daemons || cfg.configFile != null || cfg.config != "") { + + environment.systemPackages = [ + pkgs.frr # for the vtysh tool + ]; + + users.users.frr = { + description = "FRR daemon user"; + isSystemUser = true; + group = "frr"; }; - systemd.tmpfiles.rules = [ - "d /run/frr 0750 frr frr -" - ]; + users.groups = { + frr = { }; + # Members of the frrvty group can use vtysh to inspect the FRR daemons + frrvty = { + members = [ "frr" ]; + }; + }; - systemd.services = - let - frrService = service: - let - scfg = cfg.${service}; - daemon = daemonName service; - in - nameValuePair daemon ({ - wantedBy = [ "multi-user.target" ]; - after = [ "network-pre.target" "systemd-sysctl.service" ] ++ lib.optionals (service != "zebra") [ "zebra.service" ]; - bindsTo = lib.optionals (service != "zebra") [ "zebra.service" ]; - wants = [ "network.target" ]; + environment.etc = { + "frr/frr.conf".source = configFile; + "frr/vtysh.conf".text = '' + service integrated-vtysh-config + ''; + "frr/daemons".text = '' + # This file tells the frr package which daemons to start. + # + # The watchfrr, zebra and staticd daemons are always started. + # + # This part is auto-generated from services.frr..enable config + ${daemonList} - description = if service == "zebra" then "FRR Zebra routing manager" - else "FRR ${toUpper service} routing daemon"; + # If this option is set the /etc/init.d/frr script automatically loads + # the config via "vtysh -b" when the servers are started. + # + vtysh_enable=yes - unitConfig.Documentation = if service == "zebra" then "man:zebra(8)" - else "man:${daemon}(8) man:zebra(8)"; + # This part is auto-generated from services.frr..options or + # services.frr..extraOptions + ${daemonOptions} + ''; + }; - restartTriggers = mkIf (service != "mgmt") [ - (configFile service) - ]; - reloadIfChanged = (service != "mgmt"); + systemd.tmpfiles.rules = [ "d /run/frr 0750 frr frr -" ]; - serviceConfig = { - PIDFile = "frr/${daemon}.pid"; - ExecStart = "${pkgs.frr}/libexec/frr/${daemon}" - + optionalString (scfg.vtyListenAddress != "") " -A ${scfg.vtyListenAddress}" - + optionalString (scfg.vtyListenPort != null) " -P ${toString scfg.vtyListenPort}" - + " " + (concatStringsSep " " scfg.extraOptions); - ExecReload = mkIf (service != "mgmt") "${pkgs.python3.interpreter} ${pkgs.frr}/libexec/frr/frr-reload.py --reload --daemon ${daemon} --bindir ${pkgs.frr}/bin --rundir /run/frr /etc/frr/${daemon}.conf"; - Restart = "on-abnormal"; - }; - }); - in - listToAttrs (map frrService (filter isEnabled allServices)); - - }; + systemd.services.frr = { + description = "FRRouting"; + documentation = [ "https://frrouting.readthedocs.io/en/latest/setup.html" ]; + wants = [ "network.target" ]; + after = [ + "network-pre.target" + "systemd-sysctl.service" + ]; + before = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + startLimitIntervalSec = 180; + reloadIfChanged = true; + restartTriggers = [ + configFile + daemonList + ]; + serviceConfig = { + Nice = -5; + Type = "forking"; + NotifyAccess = "all"; + StartLimitBurst = "3"; + TimeoutSec = 120; + WatchdogSec = 60; + RestartSec = 5; + Restart = "always"; + LimitNOFILE = cfg.openFilesLimit; + PIDFile = "/run/frr/watchfrr.pid"; + ExecStart = "${pkgs.frr}/libexec/frr/frrinit.sh start"; + ExecStop = "${pkgs.frr}/libexec/frr/frrinit.sh stop"; + ExecReload = "${pkgs.frr}/libexec/frr/frrinit.sh reload"; + }; + }; + }; meta.maintainers = with lib.maintainers; [ woffs ]; - } diff --git a/nixos/modules/services/networking/gateone.nix b/nixos/modules/services/networking/gateone.nix index e68f8a47d5c0..83a7ea248594 100644 --- a/nixos/modules/services/networking/gateone.nix +++ b/nixos/modules/services/networking/gateone.nix @@ -1,25 +1,24 @@ { config, lib, pkgs, ...}: -with lib; let cfg = config.services.gateone; in { options = { services.gateone = { - enable = mkEnableOption "GateOne server"; - pidDir = mkOption { + enable = lib.mkEnableOption "GateOne server"; + pidDir = lib.mkOption { default = "/run/gateone"; - type = types.path; + type = lib.types.path; description = "Path of pid files for GateOne."; }; - settingsDir = mkOption { + settingsDir = lib.mkOption { default = "/var/lib/gateone"; - type = types.path; + type = lib.types.path; description = "Path of configuration files for GateOne."; }; }; }; -config = mkIf cfg.enable { +config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs.pythonPackages; [ gateone pkgs.openssh pkgs.procps pkgs.coreutils pkgs.cacert]; diff --git a/nixos/modules/services/networking/gdomap.nix b/nixos/modules/services/networking/gdomap.nix index 3d829cb69135..b7d6e2a2b690 100644 --- a/nixos/modules/services/networking/gdomap.nix +++ b/nixos/modules/services/networking/gdomap.nix @@ -1,21 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; - { # # interface # options = { services.gdomap = { - enable = mkEnableOption "GNUstep Distributed Objects name server"; + enable = lib.mkEnableOption "GNUstep Distributed Objects name server"; }; }; # # implementation # - config = mkIf config.services.gdomap.enable { + config = lib.mkIf config.services.gdomap.enable { # NOTE: gdomap runs as root # TODO: extra user for gdomap? systemd.services.gdomap = { diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix index 522e6b14f868..215d7f79a52c 100644 --- a/nixos/modules/services/networking/git-daemon.nix +++ b/nixos/modules/services/networking/git-daemon.nix @@ -1,5 +1,4 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.gitDaemon; @@ -12,8 +11,8 @@ in options = { services.gitDaemon = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable Git daemon, which allows public hosting of git repositories @@ -27,10 +26,10 @@ in ''; }; - package = mkPackageOption pkgs "git" { }; + package = lib.mkPackageOption pkgs "git" { }; - basePath = mkOption { - type = types.str; + basePath = lib.mkOption { + type = lib.types.str; default = ""; example = "/srv/git/"; description = '' @@ -40,8 +39,8 @@ in ''; }; - exportAll = mkOption { - type = types.bool; + exportAll = lib.mkOption { + type = lib.types.bool; default = false; description = '' Publish all directories that look like Git repositories (have the objects @@ -55,8 +54,8 @@ in ''; }; - repositories = mkOption { - type = types.listOf types.str; + repositories = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "/srv/git" "/home/user/git/repo2" ]; description = '' @@ -68,33 +67,33 @@ in ''; }; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; default = ""; example = "example.com"; description = "Listen on a specific IP address or hostname."; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 9418; description = "Port to listen on."; }; - options = mkOption { - type = types.str; + options = lib.mkOption { + type = lib.types.str; default = ""; description = "Extra configuration options to be passed to Git daemon."; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "git"; description = "User under which Git daemon would be running."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "git"; description = "Group under which Git daemon would be running."; }; @@ -104,9 +103,9 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == "git") { + users.users = lib.optionalAttrs (cfg.user == "git") { git = { uid = config.ids.uids.git; group = "git"; @@ -114,18 +113,18 @@ in }; }; - users.groups = optionalAttrs (cfg.group == "git") { + users.groups = lib.optionalAttrs (cfg.group == "git") { git.gid = config.ids.gids.git; }; systemd.services.git-daemon = { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "${getExe cfg.package} daemon --reuseaddr " - + (optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ") - + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ") + script = "${lib.getExe cfg.package} daemon --reuseaddr " + + (lib.optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ") + + (lib.optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ") + "--port=${toString cfg.port} --user=${cfg.user} --group=${cfg.group} ${cfg.options} " - + "--verbose " + (optionalString cfg.exportAll "--export-all ") + concatStringsSep " " cfg.repositories; + + "--verbose " + (lib.optionalString cfg.exportAll "--export-all ") + lib.concatStringsSep " " cfg.repositories; }; }; diff --git a/nixos/modules/services/networking/globalprotect-vpn.nix b/nixos/modules/services/networking/globalprotect-vpn.nix deleted file mode 100644 index 4292bba78f76..000000000000 --- a/nixos/modules/services/networking/globalprotect-vpn.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.globalprotect; - - execStart = - if cfg.csdWrapper == null then - "${pkgs.globalprotect-openconnect}/bin/gpservice" - else - "${pkgs.globalprotect-openconnect}/bin/gpservice --csd-wrapper=${cfg.csdWrapper}"; -in - -{ - options.services.globalprotect = { - enable = mkEnableOption "globalprotect"; - - settings = mkOption { - description = '' - GlobalProtect-openconnect configuration. For more information, visit - . - ''; - default = { }; - example = { - "vpn1.company.com" = { - openconnect-args = "--script=/path/to/vpnc-script"; - }; - }; - type = types.attrs; - }; - - csdWrapper = mkOption { - description = '' - A script that will produce a Host Integrity Protection (HIP) report, - as described at - ''; - default = null; - example = literalExpression ''"''${pkgs.openconnect}/libexec/openconnect/hipreport.sh"''; - type = types.nullOr types.path; - }; - }; - - config = mkIf cfg.enable { - services.dbus.packages = [ pkgs.globalprotect-openconnect ]; - - environment.etc."gpservice/gp.conf".text = lib.generators.toINI { } cfg.settings; - - systemd.services.gpservice = { - description = "GlobalProtect openconnect DBus service"; - serviceConfig = { - Type = "dbus"; - BusName = "com.yuezk.qt.GPService"; - ExecStart = execStart; - }; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - }; - }; -} diff --git a/nixos/modules/services/networking/gns3-server.nix b/nixos/modules/services/networking/gns3-server.nix index ec6a53dddc70..71980f52df2d 100644 --- a/nixos/modules/services/networking/gns3-server.nix +++ b/nixos/modules/services/networking/gns3-server.nix @@ -129,8 +129,15 @@ in { } ]; + users.groups.gns3 = { }; + users.groups.ubridge = lib.mkIf cfg.ubridge.enable { }; + users.users.gns3 = { + group = "gns3"; + isSystemUser = true; + }; + security.wrappers.ubridge = lib.mkIf cfg.ubridge.enable { capabilities = "cap_net_raw,cap_net_admin=eip"; group = "ubridge"; @@ -150,7 +157,7 @@ in { }; } (lib.mkIf (cfg.ubridge.enable) { - Server.ubridge_path = lib.mkDefault (lib.getExe cfg.ubridge.package); + Server.ubridge_path = lib.mkDefault "/run/wrappers/bin/ubridge"; }) (lib.mkIf (cfg.auth.enable) { Server = { @@ -206,7 +213,6 @@ in { serviceConfig = { ConfigurationDirectory = "gns3"; ConfigurationDirectoryMode = "0750"; - DynamicUser = true; Environment = "HOME=%S/gns3"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; ExecStart = "${lib.getExe cfg.package} ${commandArgs}"; @@ -227,14 +233,27 @@ in { User = "gns3"; WorkingDirectory = "%S/gns3"; + # Required for ubridge integration to work + # + # GNS3 needs to run SUID binaries (ubridge) + # but NoNewPrivileges breaks execution of SUID binaries + DynamicUser = false; + NoNewPrivileges = false; + RestrictSUIDSGID = false; + PrivateUsers = false; + # Hardening - DeviceAllow = lib.optional flags.enableLibvirtd "/dev/kvm"; + DeviceAllow = [ + # ubridge needs access to tun/tap devices + "/dev/net/tap rw" + "/dev/net/tun rw" + ] ++ lib.optionals flags.enableLibvirtd [ + "/dev/kvm" + ]; DevicePolicy = "closed"; LockPersonality = true; MemoryDenyWriteExecute = true; - NoNewPrivileges = true; PrivateTmp = true; - PrivateUsers = true; # Don't restrict ProcSubset because python3Packages.psutil requires read access to /proc/stat # ProcSubset = "pid"; ProtectClock = true; @@ -255,8 +274,7 @@ in { ]; RestrictNamespaces = true; RestrictRealtime = true; - RestrictSUIDSGID = true; - UMask = "0077"; + UMask = "0022"; }; }; }; diff --git a/nixos/modules/services/networking/gnunet.nix b/nixos/modules/services/networking/gnunet.nix index cfe1e1709142..7380f22c13f2 100644 --- a/nixos/modules/services/networking/gnunet.nix +++ b/nixos/modules/services/networking/gnunet.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.gnunet; @@ -44,8 +41,8 @@ in services.gnunet = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to run the GNUnet daemon. GNUnet is GNU's anonymous @@ -54,8 +51,8 @@ in }; fileSharing = { - quota = mkOption { - type = types.int; + quota = lib.mkOption { + type = lib.types.int; default = 1024; description = '' Maximum file system usage (in MiB) for file sharing. @@ -64,8 +61,8 @@ in }; udp = { - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 2086; # assigned by IANA description = '' The UDP port for use by GNUnet. @@ -74,8 +71,8 @@ in }; tcp = { - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 2086; # assigned by IANA description = '' The TCP port for use by GNUnet. @@ -84,8 +81,8 @@ in }; load = { - maxNetDownBandwidth = mkOption { - type = types.int; + maxNetDownBandwidth = lib.mkOption { + type = lib.types.int; default = 50000; description = '' Maximum bandwidth usage (in bits per second) for GNUnet @@ -93,8 +90,8 @@ in ''; }; - maxNetUpBandwidth = mkOption { - type = types.int; + maxNetUpBandwidth = lib.mkOption { + type = lib.types.int; default = 50000; description = '' Maximum bandwidth usage (in bits per second) for GNUnet @@ -102,8 +99,8 @@ in ''; }; - hardNetUpBandwidth = mkOption { - type = types.int; + hardNetUpBandwidth = lib.mkOption { + type = lib.types.int; default = 0; description = '' Hard bandwidth limit (in bits per second) when uploading @@ -112,12 +109,12 @@ in }; }; - package = mkPackageOption pkgs "gnunet" { + package = lib.mkPackageOption pkgs "gnunet" { example = "gnunet_git"; }; - extraOptions = mkOption { - type = types.lines; + extraOptions = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Additional options that will be copied verbatim in `gnunet.conf`. @@ -131,7 +128,7 @@ in ###### implementation - config = mkIf config.services.gnunet.enable { + config = lib.mkIf config.services.gnunet.enable { users.users.gnunet = { group = "gnunet"; diff --git a/nixos/modules/services/networking/go-autoconfig.nix b/nixos/modules/services/networking/go-autoconfig.nix index 2fc7c53218ca..b31ef227c587 100644 --- a/nixos/modules/services/networking/go-autoconfig.nix +++ b/nixos/modules/services/networking/go-autoconfig.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.go-autoconfig; @@ -12,19 +9,19 @@ in { options = { services.go-autoconfig = { - enable = mkEnableOption "IMAP/SMTP autodiscover feature for mail clients"; + enable = lib.mkEnableOption "IMAP/SMTP autodiscover feature for mail clients"; - settings = mkOption { + settings = lib.mkOption { default = { }; description = '' Configuration for go-autoconfig. See for more information. ''; - type = types.submodule { + type = lib.types.submodule { freeformType = format.type; }; - example = literalExpression '' + example = lib.literalExpression '' { service_addr = ":1323"; domain = "autoconfig.example.org"; @@ -43,7 +40,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd = { services.go-autoconfig = { diff --git a/nixos/modules/services/networking/go-camo.nix b/nixos/modules/services/networking/go-camo.nix index cb3b6eade464..adf80901cdc9 100644 --- a/nixos/modules/services/networking/go-camo.nix +++ b/nixos/modules/services/networking/go-camo.nix @@ -55,7 +55,8 @@ in GOCAMO_HMAC_FILE = "%d/hmac"; }; script = '' - export GOCAMO_HMAC=$(cat "$GOCAMO_HMAC_FILE") + GOCAMO_HMAC="$(cat "$GOCAMO_HMAC_FILE")" + export GOCAMO_HMAC exec ${lib.escapeShellArgs(lib.lists.remove "" ([ "${pkgs.go-camo}/bin/go-camo" cfg.listen cfg.sslListen cfg.sslKey cfg.sslCert ] ++ cfg.extraOptions))} ''; serviceConfig = { diff --git a/nixos/modules/services/networking/go-neb.nix b/nixos/modules/services/networking/go-neb.nix index ae414509162b..4a43c574ff53 100644 --- a/nixos/modules/services/networking/go-neb.nix +++ b/nixos/modules/services/networking/go-neb.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.go-neb; @@ -9,16 +6,16 @@ let configFile = settingsFormat.generate "config.yaml" cfg.config; in { options.services.go-neb = { - enable = mkEnableOption "an extensible matrix bot written in Go"; + enable = lib.mkEnableOption "an extensible matrix bot written in Go"; - bindAddress = mkOption { - type = types.str; + bindAddress = lib.mkOption { + type = lib.types.str; description = "Port (and optionally address) to listen on."; default = ":4050"; }; - secretFile = mkOption { - type = types.nullOr types.path; + secretFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; example = "/run/keys/go-neb.env"; description = '' @@ -30,12 +27,12 @@ in { ''; }; - baseUrl = mkOption { - type = types.str; + baseUrl = lib.mkOption { + type = lib.types.str; description = "Public-facing endpoint that can receive webhooks."; }; - config = mkOption { + config = lib.mkOption { inherit (settingsFormat) type; description = '' Your {file}`config.yaml` as a Nix attribute set. @@ -45,7 +42,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.go-neb = let finalConfigFile = if cfg.secretFile == null then configFile else "/var/run/go-neb/config.yaml"; in { @@ -74,5 +71,5 @@ in { }; }; - meta.maintainers = with maintainers; [ hexa maralorn ]; + meta.maintainers = with lib.maintainers; [ hexa maralorn ]; } diff --git a/nixos/modules/services/networking/go-shadowsocks2.nix b/nixos/modules/services/networking/go-shadowsocks2.nix index afbd7ea27c65..438d3fb1c0a6 100644 --- a/nixos/modules/services/networking/go-shadowsocks2.nix +++ b/nixos/modules/services/networking/go-shadowsocks2.nix @@ -1,20 +1,18 @@ { config, lib, pkgs, ... }: - -with lib; let cfg = config.services.go-shadowsocks2.server; in { options.services.go-shadowsocks2.server = { - enable = mkEnableOption "go-shadowsocks2 server"; + enable = lib.mkEnableOption "go-shadowsocks2 server"; - listenAddress = mkOption { - type = types.str; + listenAddress = lib.mkOption { + type = lib.types.str; description = "Server listen address or URL"; example = "ss://AEAD_CHACHA20_POLY1305:your-password@:8488"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.go-shadowsocks2-server = { description = "go-shadowsocks2 server"; diff --git a/nixos/modules/services/networking/gobgpd.nix b/nixos/modules/services/networking/gobgpd.nix index e5d8c190b911..79f1adf4e314 100644 --- a/nixos/modules/services/networking/gobgpd.nix +++ b/nixos/modules/services/networking/gobgpd.nix @@ -1,16 +1,13 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.gobgpd; format = pkgs.formats.toml { }; confFile = format.generate "gobgpd.conf" cfg.settings; in { options.services.gobgpd = { - enable = mkEnableOption "GoBGP Routing Daemon"; + enable = lib.mkEnableOption "GoBGP Routing Daemon"; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = { }; description = '' @@ -18,7 +15,7 @@ in { for details on supported values. ''; - example = literalExpression '' + example = lib.literalExpression '' { global = { config = { @@ -45,7 +42,7 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.gobgpd ]; systemd.services.gobgpd = { wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/networking/hans.nix b/nixos/modules/services/networking/hans.nix index 0d0e2c340ebf..b1cb37158a04 100644 --- a/nixos/modules/services/networking/hans.nix +++ b/nixos/modules/services/networking/hans.nix @@ -1,9 +1,5 @@ # NixOS module for hans, ip over icmp daemon - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.hans; @@ -17,7 +13,7 @@ in options = { services.hans = { - clients = mkOption { + clients = lib.mkOption { default = {}; description = '' Each attribute of this option defines a systemd service that @@ -27,7 +23,7 @@ in where «name» is the name of the corresponding attribute name. ''; - example = literalExpression '' + example = lib.literalExpression '' { foo = { server = "192.0.2.1"; @@ -35,25 +31,25 @@ in } } ''; - type = types.attrsOf (types.submodule ( + type = lib.types.attrsOf (lib.types.submodule ( { options = { - server = mkOption { - type = types.str; + server = lib.mkOption { + type = lib.types.str; default = ""; description = "IP address of server running hans"; example = "192.0.2.1"; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = "Additional command line parameters"; example = "-v"; }; - passwordFile = mkOption { - type = types.str; + passwordFile = lib.mkOption { + type = lib.types.str; default = ""; description = "File that contains password"; }; @@ -63,34 +59,34 @@ in }; server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "enable hans server"; }; - ip = mkOption { - type = types.str; + ip = lib.mkOption { + type = lib.types.str; default = ""; description = "The assigned ip range"; example = "198.51.100.0"; }; - respondToSystemPings = mkOption { - type = types.bool; + respondToSystemPings = lib.mkOption { + type = lib.types.bool; default = false; description = "Force hans respond to ordinary pings"; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = "Additional command line parameters"; example = "-v"; }; - passwordFile = mkOption { - type = types.str; + passwordFile = lib.mkOption { + type = lib.types.str; default = ""; description = "File that contains password"; }; @@ -101,8 +97,8 @@ in ### implementation - config = mkIf (cfg.server.enable || cfg.clients != {}) { - boot.kernel.sysctl = optionalAttrs cfg.server.respondToSystemPings { + config = lib.mkIf (cfg.server.enable || cfg.clients != {}) { + boot.kernel.sysctl = lib.optionalAttrs cfg.server.respondToSystemPings { "net.ipv4.icmp_echo_ignore_all" = 1; }; @@ -115,23 +111,23 @@ in description = "hans client - ${name}"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "${pkgs.hans}/bin/hans -f -u ${hansUser} ${cfg.extraConfig} -c ${cfg.server} ${optionalString (cfg.passwordFile != "") "-p $(cat \"${cfg.passwordFile}\")"}"; + script = "${pkgs.hans}/bin/hans -f -u ${hansUser} ${cfg.extraConfig} -c ${cfg.server} ${lib.optionalString (cfg.passwordFile != "") "-p $(cat \"${cfg.passwordFile}\")"}"; serviceConfig = { RestartSec = "30s"; Restart = "always"; }; }; in - listToAttrs ( - mapAttrsToList - (name: value: nameValuePair "hans-${name}" (createHansClientService name value)) + lib.listToAttrs ( + lib.mapAttrsToList + (name: value: lib.nameValuePair "hans-${name}" (createHansClientService name value)) cfg.clients ) // { - hans = mkIf (cfg.server.enable) { + hans = lib.mkIf (cfg.server.enable) { description = "hans, ip over icmp server daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "${pkgs.hans}/bin/hans -f -u ${hansUser} ${cfg.server.extraConfig} -s ${cfg.server.ip} ${optionalString cfg.server.respondToSystemPings "-r"} ${optionalString (cfg.server.passwordFile != "") "-p $(cat \"${cfg.server.passwordFile}\")"}"; + script = "${pkgs.hans}/bin/hans -f -u ${hansUser} ${cfg.server.extraConfig} -s ${cfg.server.ip} ${lib.optionalString cfg.server.respondToSystemPings "-r"} ${lib.optionalString (cfg.server.passwordFile != "") "-p $(cat \"${cfg.server.passwordFile}\")"}"; }; }; diff --git a/nixos/modules/services/networking/haproxy.nix b/nixos/modules/services/networking/haproxy.nix index 19b096bf4906..23c06f294980 100644 --- a/nixos/modules/services/networking/haproxy.nix +++ b/nixos/modules/services/networking/haproxy.nix @@ -1,40 +1,35 @@ { config, lib, pkgs, ... }: - let cfg = config.services.haproxy; - haproxyCfg = pkgs.writeText "haproxy.conf" '' global # needed for hot-reload to work without dropping packets in multi-worker mode stats socket /run/haproxy/haproxy.sock mode 600 expose-fd listeners level user - ${cfg.config} ''; - in -with lib; { options = { services.haproxy = { - enable = mkEnableOption "HAProxy, the reliable, high performance TCP/HTTP load balancer"; + enable = lib.mkEnableOption "HAProxy, the reliable, high performance TCP/HTTP load balancer"; - package = mkPackageOption pkgs "haproxy" { }; + package = lib.mkPackageOption pkgs "haproxy" { }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "haproxy"; description = "User account under which haproxy runs."; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "haproxy"; description = "Group account under which haproxy runs."; }; - config = mkOption { - type = types.nullOr types.lines; + config = lib.mkOption { + type = lib.types.nullOr lib.types.lines; default = null; description = '' Contents of the HAProxy configuration file, @@ -44,7 +39,7 @@ with lib; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [{ assertion = cfg.config != null; @@ -93,14 +88,14 @@ with lib; }; }; - users.users = optionalAttrs (cfg.user == "haproxy") { + users.users = lib.optionalAttrs (cfg.user == "haproxy") { haproxy = { group = cfg.group; isSystemUser = true; }; }; - users.groups = optionalAttrs (cfg.group == "haproxy") { + users.groups = lib.optionalAttrs (cfg.group == "haproxy") { haproxy = {}; }; }; diff --git a/nixos/modules/services/networking/headscale.nix b/nixos/modules/services/networking/headscale.nix index ea66faeabbf2..9261ec03c532 100644 --- a/nixos/modules/services/networking/headscale.nix +++ b/nixos/modules/services/networking/headscale.nix @@ -3,25 +3,38 @@ lib, pkgs, ... -}: -with lib; let +}: let cfg = config.services.headscale; dataDir = "/var/lib/headscale"; runDir = "/run/headscale"; + cliConfig = { + # Turn off update checks since the origin of our package + # is nixpkgs and not Github. + disable_check_updates = true; + + unix_socket = "${runDir}/headscale.sock"; + }; + settingsFormat = pkgs.formats.yaml {}; configFile = settingsFormat.generate "headscale.yaml" cfg.settings; + cliConfigFile = settingsFormat.generate "headscale.yaml" cliConfig; + + assertRemovedOption = option: message: { + assertion = !lib.hasAttrByPath option cfg; + message = "The option `services.headscale.${lib.options.showOption option}` was removed. " + message; + }; in { options = { services.headscale = { - enable = mkEnableOption "headscale, Open Source coordination server for Tailscale"; + enable = lib.mkEnableOption "headscale, Open Source coordination server for Tailscale"; - package = mkPackageOption pkgs "headscale" { }; + package = lib.mkPackageOption pkgs "headscale" {}; - user = mkOption { + user = lib.mkOption { default = "headscale"; - type = types.str; + type = lib.types.str; description = '' User account under which headscale runs. @@ -33,9 +46,9 @@ in { ''; }; - group = mkOption { + group = lib.mkOption { default = "headscale"; - type = types.str; + type = lib.types.str; description = '' Group under which headscale runs. @@ -47,8 +60,8 @@ in { ''; }; - address = mkOption { - type = types.str; + address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' Listening address of headscale. @@ -56,8 +69,8 @@ in { example = "0.0.0.0"; }; - port = mkOption { - type = types.port; + port = lib.mkOption { + type = lib.types.port; default = 8080; description = '' Listening port of headscale. @@ -65,18 +78,18 @@ in { example = 443; }; - settings = mkOption { + settings = lib.mkOption { description = '' Overrides to {file}`config.yaml` as a Nix attribute set. Check the [example config](https://github.com/juanfont/headscale/blob/main/config-example.yaml) for possible options. ''; - type = types.submodule { + type = lib.types.submodule { freeformType = settingsFormat.type; options = { - server_url = mkOption { - type = types.str; + server_url = lib.mkOption { + type = lib.types.str; default = "http://127.0.0.1:8080"; description = '' The url clients will connect to. @@ -84,25 +97,49 @@ in { example = "https://myheadscale.example.com:443"; }; - private_key_path = mkOption { - type = types.path; - default = "${dataDir}/private.key"; - description = '' - Path to private key file, generated automatically if it does not exist. - ''; - }; - - noise.private_key_path = mkOption { - type = types.path; + noise.private_key_path = lib.mkOption { + type = lib.types.path; default = "${dataDir}/noise_private.key"; description = '' Path to noise private key file, generated automatically if it does not exist. ''; }; + prefixes = let + prefDesc = '' + Each prefix consists of either an IPv4 or IPv6 address, + and the associated prefix length, delimited by a slash. + It must be within IP ranges supported by the Tailscale + client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48. + ''; + in { + v4 = lib.mkOption { + type = lib.types.str; + default = "100.64.0.0/10"; + description = prefDesc; + }; + + v6 = lib.mkOption { + type = lib.types.str; + default = "fd7a:115c:a1e0::/48"; + description = prefDesc; + }; + + allocation = lib.mkOption { + type = lib.types.enum ["sequential" "random"]; + example = "random"; + default = "sequential"; + description = '' + Strategy used for allocation of IPs to nodes, available options: + - sequential (default): assigns the next free IP from the previous given IP. + - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand). + ''; + }; + }; + derp = { - urls = mkOption { - type = types.listOf types.str; + urls = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["https://controlplane.tailscale.com/derpmap/default"]; description = '' List of urls containing DERP maps. @@ -110,8 +147,8 @@ in { ''; }; - paths = mkOption { - type = types.listOf types.path; + paths = lib.mkOption { + type = lib.types.listOf lib.types.path; default = []; description = '' List of file paths containing DERP maps. @@ -119,8 +156,8 @@ in { ''; }; - auto_update_enable = mkOption { - type = types.bool; + auto_update_enable = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to automatically update DERP maps on a set frequency. @@ -128,18 +165,26 @@ in { example = false; }; - update_frequency = mkOption { - type = types.str; + update_frequency = lib.mkOption { + type = lib.types.str; default = "24h"; description = '' Frequency to update DERP maps. ''; example = "5m"; }; + + server.private_key_path = lib.mkOption { + type = lib.types.path; + default = "${dataDir}/derp_server_private.key"; + description = '' + Path to derp private key file, generated automatically if it does not exist. + ''; + }; }; - ephemeral_node_inactivity_timeout = mkOption { - type = types.str; + ephemeral_node_inactivity_timeout = lib.mkOption { + type = lib.types.str; default = "30m"; description = '' Time before an inactive ephemeral node is deleted. @@ -147,128 +192,144 @@ in { example = "5m"; }; - db_type = mkOption { - type = types.enum ["sqlite3" "postgres"]; - example = "postgres"; - default = "sqlite3"; - description = "Database engine to use."; - }; - - db_host = mkOption { - type = types.nullOr types.str; - default = null; - example = "127.0.0.1"; - description = "Database host address."; - }; - - db_port = mkOption { - type = types.nullOr types.port; - default = null; - example = 3306; - description = "Database host port."; - }; - - db_name = mkOption { - type = types.nullOr types.str; - default = null; - example = "headscale"; - description = "Database name."; - }; - - db_user = mkOption { - type = types.nullOr types.str; - default = null; - example = "headscale"; - description = "Database user."; - }; - - db_password_file = mkOption { - type = types.nullOr types.path; - default = null; - example = "/run/keys/headscale-dbpassword"; - description = '' - A file containing the password corresponding to - {option}`database.user`. - ''; - }; - - db_path = mkOption { - type = types.nullOr types.str; - default = "${dataDir}/db.sqlite"; - description = "Path to the sqlite3 database file."; - }; - - log.level = mkOption { - type = types.str; - default = "info"; - description = '' - headscale log level. - ''; - example = "debug"; - }; - - log.format = mkOption { - type = types.str; - default = "text"; - description = '' - headscale log format. - ''; - example = "json"; - }; - - dns_config = { - nameservers = mkOption { - type = types.listOf types.str; - default = ["1.1.1.1"]; + database = { + type = lib.mkOption { + type = lib.types.enum ["sqlite" "sqlite3" "postgres"]; + example = "postgres"; + default = "sqlite"; description = '' - List of nameservers to pass to Tailscale clients. + Database engine to use. + Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. + All new development, testing and optimisations are done with SQLite in mind. ''; }; - override_local_dns = mkOption { - type = types.bool; - default = false; - description = '' - Whether to use [Override local DNS](https://tailscale.com/kb/1054/dns/). - ''; - example = true; + sqlite = { + path = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = "${dataDir}/db.sqlite"; + description = "Path to the sqlite3 database file."; + }; + + write_ahead_log = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Enable WAL mode for SQLite. This is recommended for production environments. + https://www.sqlite.org/wal.html + ''; + example = true; + }; }; - domains = mkOption { - type = types.listOf types.str; + postgres = { + host = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "127.0.0.1"; + description = "Database host address."; + }; + + port = lib.mkOption { + type = lib.types.nullOr lib.types.port; + default = null; + example = 3306; + description = "Database host port."; + }; + + name = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "headscale"; + description = "Database name."; + }; + + user = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "headscale"; + description = "Database user."; + }; + + password_file = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/headscale-dbpassword"; + description = '' + A file containing the password corresponding to + {option}`database.user`. + ''; + }; + }; + }; + + log = { + level = lib.mkOption { + type = lib.types.str; + default = "info"; + description = '' + headscale log level. + ''; + example = "debug"; + }; + + format = lib.mkOption { + type = lib.types.str; + default = "text"; + description = '' + headscale log format. + ''; + example = "json"; + }; + }; + + dns = { + magic_dns = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). + ''; + example = false; + }; + + base_domain = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Defines the base domain to create the hostnames for MagicDNS. + This domain must be different from the {option}`server_url` + domain. + {option}`base_domain` must be a FQDN, without the trailing dot. + The FQDN of the hosts will be `hostname.base_domain` (e.g. + `myhost.tailnet.example.com`). + ''; + example = "tailnet.example.com"; + }; + + nameservers = { + global = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = '' + List of nameservers to pass to Tailscale clients. + ''; + }; + }; + + search_domains = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; description = '' Search domains to inject to Tailscale clients. ''; example = ["mydomain.internal"]; }; - - magic_dns = mkOption { - type = types.bool; - default = true; - description = '' - Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/). - Only works if there is at least a nameserver defined. - ''; - example = false; - }; - - base_domain = mkOption { - type = types.str; - default = ""; - description = '' - Defines the base domain to create the hostnames for MagicDNS. - {option}`baseDomain` must be a FQDNs, without the trailing dot. - The FQDN of the hosts will be - `hostname.namespace.base_domain` (e.g. - `myhost.mynamespace.example.com`). - ''; - }; }; oidc = { - issuer = mkOption { - type = types.str; + issuer = lib.mkOption { + type = lib.types.str; default = ""; description = '' URL to OpenID issuer. @@ -276,33 +337,33 @@ in { example = "https://openid.example.com"; }; - client_id = mkOption { - type = types.str; + client_id = lib.mkOption { + type = lib.types.str; default = ""; description = '' OpenID Connect client ID. ''; }; - client_secret_path = mkOption { - type = types.nullOr types.str; + client_secret_path = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Path to OpenID Connect client secret file. Expands environment variables in format ''${VAR}. ''; }; - scope = mkOption { - type = types.listOf types.str; + scope = lib.mkOption { + type = lib.types.listOf lib.types.str; default = ["openid" "profile" "email"]; description = '' Scopes used in the OIDC flow. ''; }; - extra_params = mkOption { - type = types.attrsOf types.str; - default = { }; + extra_params = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = {}; description = '' Custom query parameters to send with the Authorize Endpoint request. ''; @@ -311,27 +372,27 @@ in { }; }; - allowed_domains = mkOption { - type = types.listOf types.str; - default = [ ]; + allowed_domains = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; description = '' Allowed principal domains. if an authenticated user's domain is not in this list authentication request will be rejected. ''; - example = [ "example.com" ]; + example = ["example.com"]; }; - allowed_users = mkOption { - type = types.listOf types.str; - default = [ ]; + allowed_users = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; description = '' Users allowed to authenticate even if not in allowedDomains. ''; - example = [ "alice@example.com" ]; + example = ["alice@example.com"]; }; - strip_email_domain = mkOption { - type = types.bool; + strip_email_domain = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether the domain part of the email address should be removed when generating namespaces. @@ -339,16 +400,16 @@ in { }; }; - tls_letsencrypt_hostname = mkOption { - type = types.nullOr types.str; + tls_letsencrypt_hostname = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = ""; description = '' Domain name to request a TLS certificate for. ''; }; - tls_letsencrypt_challenge_type = mkOption { - type = types.enum ["TLS-ALPN-01" "HTTP-01"]; + tls_letsencrypt_challenge_type = lib.mkOption { + type = lib.types.enum ["TLS-ALPN-01" "HTTP-01"]; default = "HTTP-01"; description = '' Type of ACME challenge to use, currently supported types: @@ -356,8 +417,8 @@ in { ''; }; - tls_letsencrypt_listen = mkOption { - type = types.nullOr types.str; + tls_letsencrypt_listen = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = ":http"; description = '' When HTTP-01 challenge is chosen, letsencrypt must set up a @@ -366,28 +427,40 @@ in { ''; }; - tls_cert_path = mkOption { - type = types.nullOr types.path; + tls_cert_path = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to already created certificate. ''; }; - tls_key_path = mkOption { - type = types.nullOr types.path; + tls_key_path = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' Path to key for already created certificate. ''; }; - acl_policy_path = mkOption { - type = types.nullOr types.path; - default = null; - description = '' - Path to a file containing ACL policies. - ''; + policy = { + mode = lib.mkOption { + type = lib.types.enum ["file" "database"]; + default = "file"; + description = '' + The mode can be "file" or "database" that defines + where the ACL policies are stored and read from. + ''; + }; + + path = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + If the mode is set to "file", the path to a + HuJSON file containing ACL policies. + ''; + }; }; }; }; @@ -395,67 +468,73 @@ in { }; }; - imports = [ - # TODO address + port = listen_addr - (mkRenamedOptionModule ["services" "headscale" "serverUrl"] ["services" "headscale" "settings" "server_url"]) - (mkRenamedOptionModule ["services" "headscale" "privateKeyFile"] ["services" "headscale" "settings" "private_key_path"]) - (mkRenamedOptionModule ["services" "headscale" "derp" "urls"] ["services" "headscale" "settings" "derp" "urls"]) - (mkRenamedOptionModule ["services" "headscale" "derp" "paths"] ["services" "headscale" "settings" "derp" "paths"]) + imports = with lib; [ (mkRenamedOptionModule ["services" "headscale" "derp" "autoUpdate"] ["services" "headscale" "settings" "derp" "auto_update_enable"]) + (mkRenamedOptionModule ["services" "headscale" "derp" "paths"] ["services" "headscale" "settings" "derp" "paths"]) (mkRenamedOptionModule ["services" "headscale" "derp" "updateFrequency"] ["services" "headscale" "settings" "derp" "update_frequency"]) + (mkRenamedOptionModule ["services" "headscale" "derp" "urls"] ["services" "headscale" "settings" "derp" "urls"]) (mkRenamedOptionModule ["services" "headscale" "ephemeralNodeInactivityTimeout"] ["services" "headscale" "settings" "ephemeral_node_inactivity_timeout"]) - (mkRenamedOptionModule ["services" "headscale" "database" "type"] ["services" "headscale" "settings" "db_type"]) - (mkRenamedOptionModule ["services" "headscale" "database" "path"] ["services" "headscale" "settings" "db_path"]) - (mkRenamedOptionModule ["services" "headscale" "database" "host"] ["services" "headscale" "settings" "db_host"]) - (mkRenamedOptionModule ["services" "headscale" "database" "port"] ["services" "headscale" "settings" "db_port"]) - (mkRenamedOptionModule ["services" "headscale" "database" "name"] ["services" "headscale" "settings" "db_name"]) - (mkRenamedOptionModule ["services" "headscale" "database" "user"] ["services" "headscale" "settings" "db_user"]) - (mkRenamedOptionModule ["services" "headscale" "database" "passwordFile"] ["services" "headscale" "settings" "db_password_file"]) (mkRenamedOptionModule ["services" "headscale" "logLevel"] ["services" "headscale" "settings" "log" "level"]) - (mkRenamedOptionModule ["services" "headscale" "dns" "nameservers"] ["services" "headscale" "settings" "dns_config" "nameservers"]) - (mkRenamedOptionModule ["services" "headscale" "dns" "domains"] ["services" "headscale" "settings" "dns_config" "domains"]) - (mkRenamedOptionModule ["services" "headscale" "dns" "magicDns"] ["services" "headscale" "settings" "dns_config" "magic_dns"]) - (mkRenamedOptionModule ["services" "headscale" "dns" "baseDomain"] ["services" "headscale" "settings" "dns_config" "base_domain"]) - (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "issuer"] ["services" "headscale" "settings" "oidc" "issuer"]) (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "clientId"] ["services" "headscale" "settings" "oidc" "client_id"]) (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "clientSecretFile"] ["services" "headscale" "settings" "oidc" "client_secret_path"]) - (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "hostname"] ["services" "headscale" "settings" "tls_letsencrypt_hostname"]) - (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "challengeType"] ["services" "headscale" "settings" "tls_letsencrypt_challenge_type"]) - (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "httpListen"] ["services" "headscale" "settings" "tls_letsencrypt_listen"]) + (mkRenamedOptionModule ["services" "headscale" "openIdConnect" "issuer"] ["services" "headscale" "settings" "oidc" "issuer"]) + (mkRenamedOptionModule ["services" "headscale" "serverUrl"] ["services" "headscale" "settings" "server_url"]) (mkRenamedOptionModule ["services" "headscale" "tls" "certFile"] ["services" "headscale" "settings" "tls_cert_path"]) (mkRenamedOptionModule ["services" "headscale" "tls" "keyFile"] ["services" "headscale" "settings" "tls_key_path"]) - (mkRenamedOptionModule ["services" "headscale" "aclPolicyFile"] ["services" "headscale" "settings" "acl_policy_path"]) + (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "challengeType"] ["services" "headscale" "settings" "tls_letsencrypt_challenge_type"]) + (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "hostname"] ["services" "headscale" "settings" "tls_letsencrypt_hostname"]) + (mkRenamedOptionModule ["services" "headscale" "tls" "letsencrypt" "httpListen"] ["services" "headscale" "settings" "tls_letsencrypt_listen"]) (mkRemovedOptionModule ["services" "headscale" "openIdConnect" "domainMap"] '' Headscale no longer uses domain_map. If you're using an old version of headscale you can still set this option via services.headscale.settings.oidc.domain_map. '') ]; - config = mkIf cfg.enable { - services.headscale.settings = { - listen_addr = mkDefault "${cfg.address}:${toString cfg.port}"; + config = lib.mkIf cfg.enable { + assertions = [ + { + # This is stricter than it needs to be but is exactly what upstream does: + # https://github.com/kradalby/headscale/blob/adc084f20f843d7963c999764fa83939668d2d2c/hscontrol/types/config.go#L799 + assertion = with cfg.settings; dns.use_username_in_magic_dns or false || dns.base_domain == "" || !lib.hasInfix dns.base_domain server_url; + message = "server_url cannot contain the base_domain, this will cause the headscale server and embedded DERP to become unreachable from the Tailscale node."; + } + { + assertion = with cfg.settings; dns.magic_dns -> dns.base_domain != ""; + message = "dns.base_domain must be set when using MagicDNS"; + } + (assertRemovedOption ["settings" "acl_policy_path"] "Use `policy.path` instead.") + (assertRemovedOption ["settings" "db_host"] "Use `database.postgres.host` instead.") + (assertRemovedOption ["settings" "db_name"] "Use `database.postgres.name` instead.") + (assertRemovedOption ["settings" "db_password_file"] "Use `database.postgres.password_file` instead.") + (assertRemovedOption ["settings" "db_path"] "Use `database.sqlite.path` instead.") + (assertRemovedOption ["settings" "db_port"] "Use `database.postgres.port` instead.") + (assertRemovedOption ["settings" "db_type"] "Use `database.type` instead.") + (assertRemovedOption ["settings" "db_user"] "Use `database.postgres.user` instead.") + (assertRemovedOption ["settings" "dns_config"] "Use `dns` instead.") + (assertRemovedOption ["settings" "dns_config" "domains"] "Use `dns.search_domains` instead.") + (assertRemovedOption ["settings" "dns_config" "nameservers"] "Use `dns.nameservers.global` instead.") + ]; - # Turn off update checks since the origin of our package - # is nixpkgs and not Github. - disable_check_updates = true; + services.headscale.settings = lib.mkMerge [ + cliConfig + { + listen_addr = lib.mkDefault "${cfg.address}:${toString cfg.port}"; - unix_socket = "${runDir}/headscale.sock"; - - tls_letsencrypt_cache_dir = "${dataDir}/.cache"; - }; + tls_letsencrypt_cache_dir = "${dataDir}/.cache"; + } + ]; environment = { - # Setup the headscale configuration in a known path in /etc to - # allow both the Server and the Client use it to find the socket - # for communication. - etc."headscale/config.yaml".source = configFile; + # Headscale CLI needs a minimal config to be able to locate the unix socket + # to talk to the server instance. + etc."headscale/config.yaml".source = cliConfigFile; - systemPackages = [ cfg.package ]; + systemPackages = [cfg.package]; }; - users.groups.headscale = mkIf (cfg.group == "headscale") {}; + users.groups.headscale = lib.mkIf (cfg.group == "headscale") {}; - users.users.headscale = mkIf (cfg.user == "headscale") { + users.users.headscale = lib.mkIf (cfg.user == "headscale") { description = "headscale user"; home = dataDir; group = cfg.group; @@ -464,23 +543,20 @@ in { systemd.services.headscale = { description = "headscale coordination server for Tailscale"; - wants = [ "network-online.target" ]; + wants = ["network-online.target"]; after = ["network-online.target"]; wantedBy = ["multi-user.target"]; - restartTriggers = [configFile]; - - environment.GIN_MODE = "release"; script = '' - ${optionalString (cfg.settings.db_password_file != null) '' - export HEADSCALE_DB_PASS="$(head -n1 ${escapeShellArg cfg.settings.db_password_file})" + ${lib.optionalString (cfg.settings.database.postgres.password_file != null) '' + export HEADSCALE_DATABASE_POSTGRES_PASS="$(head -n1 ${lib.escapeShellArg cfg.settings.database.postgres.password_file})" ''} - exec ${cfg.package}/bin/headscale serve + exec ${lib.getExe cfg.package} serve --config ${configFile} ''; serviceConfig = let - capabilityBoundingSet = ["CAP_CHOWN"] ++ optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE"; + capabilityBoundingSet = ["CAP_CHOWN"] ++ lib.optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE"; in { Restart = "always"; Type = "simple"; @@ -525,5 +601,5 @@ in { }; }; - meta.maintainers = with maintainers; [kradalby misterio77]; + meta.maintainers = with lib.maintainers; [kradalby misterio77]; } diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix index b678656f2e04..3a3f14523d41 100644 --- a/nixos/modules/services/networking/hostapd.nix +++ b/nixos/modules/services/networking/hostapd.nix @@ -235,7 +235,7 @@ in { }; channel = mkOption { - default = 7; + default = 0; example = 11; type = types.int; description = '' diff --git a/nixos/modules/services/networking/htpdate.nix b/nixos/modules/services/networking/htpdate.nix index 6954e5b060c4..fa422854872c 100644 --- a/nixos/modules/services/networking/htpdate.nix +++ b/nixos/modules/services/networking/htpdate.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let inherit (pkgs) htpdate; @@ -16,32 +13,32 @@ in services.htpdate = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Enable htpdate daemon. ''; }; - extraOptions = mkOption { - type = types.str; + extraOptions = lib.mkOption { + type = lib.types.str; default = ""; description = '' Additional command line arguments to pass to htpdate. ''; }; - servers = mkOption { - type = types.listOf types.str; + servers = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "www.google.com" ]; description = '' HTTP servers to use for time synchronization. ''; }; - proxy = mkOption { - type = types.str; + proxy = lib.mkOption { + type = lib.types.str; default = ""; example = "127.0.0.1:8118"; description = '' @@ -55,7 +52,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.htpdate = { description = "htpdate daemon"; @@ -63,14 +60,14 @@ in serviceConfig = { Type = "forking"; PIDFile = "/run/htpdate.pid"; - ExecStart = concatStringsSep " " [ + ExecStart = lib.concatStringsSep " " [ "${htpdate}/bin/htpdate" "-D -u nobody" "-a -s" "-l" - "${optionalString (cfg.proxy != "") "-P ${cfg.proxy}"}" + "${lib.optionalString (cfg.proxy != "") "-P ${cfg.proxy}"}" "${cfg.extraOptions}" - "${concatStringsSep " " cfg.servers}" + "${lib.concatStringsSep " " cfg.servers}" ]; }; }; diff --git a/nixos/modules/services/networking/i2p.nix b/nixos/modules/services/networking/i2p.nix index 2b38697b1f47..5d7b339dc01b 100644 --- a/nixos/modules/services/networking/i2p.nix +++ b/nixos/modules/services/networking/i2p.nix @@ -1,17 +1,14 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.i2p; homeDir = "/var/lib/i2p"; in { ###### interface - options.services.i2p.enable = mkEnableOption "I2P router"; + options.services.i2p.enable = lib.mkEnableOption "I2P router"; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.i2p = { group = "i2p"; description = "i2p User"; diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix index 2bb9df15de2c..72069e609ac2 100644 --- a/nixos/modules/services/networking/i2pd.nix +++ b/nixos/modules/services/networking/i2pd.nix @@ -1,17 +1,17 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkIf mkOption mkDefault mkEnableOption types optional optionals; + inherit (lib.types) nullOr bool listOf str attrsOf submodule; cfg = config.services.i2pd; homeDir = "/var/lib/i2pd"; strOpt = k: v: k + " = " + v; - boolOpt = k: v: k + " = " + boolToString v; + boolOpt = k: v: k + " = " + lib.boolToString v; intOpt = k: v: k + " = " + toString v; - lstOpt = k: xs: k + " = " + concatStringsSep "," xs; + lstOpt = k: xs: k + " = " + lib.concatStringsSep "," xs; optionalNullString = o: s: optional (s != null) (strOpt o s); optionalNullBool = o: b: optional (b != null) (boolOpt o b); optionalNullInt = o: i: optional (i != null) (intOpt o i); @@ -54,7 +54,7 @@ let mkKeyedEndpointOpt = name: addr: port: keyloc: (mkEndpointOpt name addr port) // { keys = mkOption { - type = with types; nullOr str; + type = nullOr str; default = keyloc; description = '' File to persist ${lib.toUpper name} keys. @@ -162,8 +162,8 @@ let (sec "meshnets") (boolOpt "yggdrasil" cfg.yggdrasil.enable) ] ++ (optionalNullString "yggaddress" cfg.yggdrasil.address) - ++ (flip map - (collect (proto: proto ? port && proto ? address) cfg.proto) + ++ (lib.flip map + (lib.collect (proto: proto ? port && proto ? address) cfg.proto) (proto: let protoOpts = [ (sec proto.name) (boolOpt "enabled" proto.enable) @@ -178,10 +178,10 @@ let ++ (optionals (proto ? outproxy) (optionalNullString "outproxy" proto.outproxy)) ++ (optionals (proto ? outproxyPort) (optionalNullInt "outproxyport" proto.outproxyPort)) ++ (optionals (proto ? outproxyEnable) (optionalNullBool "outproxy.enabled" proto.outproxyEnable)); - in (concatStringsSep "\n" protoOpts) + in (lib.concatStringsSep "\n" protoOpts) )); in - pkgs.writeText "i2pd.conf" (concatStringsSep "\n" opts); + pkgs.writeText "i2pd.conf" (lib.concatStringsSep "\n" opts); tunnelConf = let mkOutTunnel = tun: @@ -200,7 +200,7 @@ let ++ (optionals (tun ? outbound.quantity) (optionalNullInt "outbound.quantity" tun.outbound.quantity)) ++ (optionals (tun ? crypto.tagsToSend) (optionalNullInt "crypto.tagstosend" tun.crypto.tagsToSend)); in - concatStringsSep "\n" outTunOpts; + lib.concatStringsSep "\n" outTunOpts; mkInTunnel = tun: let @@ -214,16 +214,16 @@ let ++ (optionals (tun ? inPort) (optionalNullInt "inport" tun.inPort)) ++ (optionals (tun ? accessList) (optionalEmptyList "accesslist" tun.accessList)); in - concatStringsSep "\n" inTunOpts; + lib.concatStringsSep "\n" inTunOpts; - allOutTunnels = collect (tun: tun ? port && tun ? destination) cfg.outTunnels; - allInTunnels = collect (tun: tun ? port && tun ? address) cfg.inTunnels; + allOutTunnels = lib.collect (tun: tun ? port && tun ? destination) cfg.outTunnels; + allInTunnels = lib.collect (tun: tun ? port && tun ? address) cfg.inTunnels; opts = [ notice ] ++ (map mkOutTunnel allOutTunnels) ++ (map mkInTunnel allInTunnels); in - pkgs.writeText "i2pd-tunnels.conf" (concatStringsSep "\n" opts); + pkgs.writeText "i2pd-tunnels.conf" (lib.concatStringsSep "\n" opts); - i2pdFlags = concatStringsSep " " ( + i2pdFlags = lib.concatStringsSep " " ( optional (cfg.address != null) ("--host=" + cfg.address) ++ [ "--service" ("--conf=" + i2pdConf) @@ -235,7 +235,7 @@ in { imports = [ - (mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ]) + (lib.mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ]) ]; ###### interface @@ -252,7 +252,7 @@ in ''; }; - package = mkPackageOption pkgs "i2pd" { }; + package = lib.mkPackageOption pkgs "i2pd" { }; logLevel = mkOption { type = types.enum ["debug" "info" "warn" "error"]; @@ -269,7 +269,7 @@ in logCLFTime = mkEnableOption "full CLF-formatted date and time to log"; address = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Your external IP or hostname. @@ -277,7 +277,7 @@ in }; family = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Specify a family the router belongs to. @@ -285,7 +285,7 @@ in }; dataDir = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Alternative path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -301,7 +301,7 @@ in }; ifname = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Network interface to bind to. @@ -309,7 +309,7 @@ in }; ifname4 = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' IPv4 interface to bind to. @@ -317,7 +317,7 @@ in }; ifname6 = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' IPv6 interface to bind to. @@ -325,7 +325,7 @@ in }; ntcpProxy = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Proxy URL for NTCP transport. @@ -399,7 +399,7 @@ in reseed.verify = mkEnableOption "SU3 signature verification"; reseed.file = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Full path to SU3 file to reseed from. @@ -407,7 +407,7 @@ in }; reseed.urls = mkOption { - type = with types; listOf str; + type = listOf str; default = []; description = '' Reseed URLs. @@ -415,7 +415,7 @@ in }; reseed.floodfill = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Path to router info of floodfill to reseed from. @@ -423,7 +423,7 @@ in }; reseed.zipfile = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Path to local .zip file to reseed from. @@ -431,7 +431,7 @@ in }; reseed.proxy = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' URL for reseed proxy, supports http/socks. @@ -446,7 +446,7 @@ in ''; }; addressbook.subscriptions = mkOption { - type = with types; listOf str; + type = listOf str; default = [ "http://inr.i2p/export/alive-hosts.txt" "http://i2p-projekt.i2p/hosts.txt" @@ -460,7 +460,7 @@ in trust.enable = mkEnableOption "explicit trust options"; trust.family = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Router Family to trust for first hops. @@ -468,7 +468,7 @@ in }; trust.routers = mkOption { - type = with types; listOf str; + type = listOf str; default = []; description = '' Only connect to the listed routers. @@ -543,7 +543,7 @@ in yggdrasil.enable = mkEnableOption "Yggdrasil"; yggdrasil.address = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Your local yggdrasil address. Specify it if you want to bind your router to a @@ -572,7 +572,7 @@ in }; strictHeaders = mkOption { - type = with types; nullOr bool; + type = nullOr bool; default = null; description = '' Enable strict host checking on WebUI. @@ -580,7 +580,7 @@ in }; hostname = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = '' Expected hostname for WebUI. @@ -591,7 +591,7 @@ in proto.httpProxy = (mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 "httpproxy-keys.dat") // { outproxy = mkOption { - type = with types; nullOr str; + type = nullOr str; default = null; description = "Upstream outproxy bind address."; }; @@ -618,7 +618,7 @@ in outTunnels = mkOption { default = {}; - type = with types; attrsOf (submodule ( + type = attrsOf (submodule ( { name, ... }: { options = { destinationPort = mkOption { @@ -639,7 +639,7 @@ in inTunnels = mkOption { default = {}; - type = with types; attrsOf (submodule ( + type = attrsOf (submodule ( { name, ... }: { options = { inPort = mkOption { @@ -648,7 +648,7 @@ in description = "Service port. Default to the tunnel's listen port."; }; accessList = mkOption { - type = with types; listOf str; + type = listOf str; default = []; description = "I2P nodes that are allowed to connect to this service."; }; diff --git a/nixos/modules/services/networking/inadyn.nix b/nixos/modules/services/networking/inadyn.nix index 7022673538c8..c98d6a231506 100644 --- a/nixos/modules/services/networking/inadyn.nix +++ b/nixos/modules/services/networking/inadyn.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.inadyn; @@ -11,10 +8,10 @@ let renderOption = k: v: if builtins.elem k [ "provider" "custom" ] then lib.concatStringsSep "\n" - (mapAttrsToList + (lib.mapAttrsToList (name: config: '' ${k} ${name} { - ${lib.concatStringsSep "\n " (mapAttrsToList renderOption (filterAttrs nonEmptyValue config))} + ${lib.concatStringsSep "\n " (lib.mapAttrsToList renderOption (lib.filterAttrs nonEmptyValue config))} }'') v) else if k == "include" then @@ -22,7 +19,7 @@ let else if k == "hostname" && builtins.isList v then "${k} = { ${builtins.concatStringsSep ", " (map (s: "\"${s}\"") v)} }" else if builtins.isBool v then - "${k} = ${boolToString v}" + "${k} = ${lib.boolToString v}" else if builtins.isString v then "${k} = \"${v}\"" else @@ -33,32 +30,32 @@ let # This file was generated by nix # do not edit - ${(lib.concatStringsSep "\n" (mapAttrsToList renderOption (filterAttrs nonEmptyValue cfg.settings)))} + ${(lib.concatStringsSep "\n" (lib.mapAttrsToList renderOption (lib.filterAttrs nonEmptyValue cfg.settings)))} ''; configFile = if (cfg.configFile != null) then cfg.configFile else configFile'; in { - options.services.inadyn = with types; + options.services.inadyn = with lib.types; let providerOptions = { - include = mkOption { + include = lib.mkOption { default = null; description = "File to include additional settings for this provider from."; type = nullOr path; }; - ssl = mkOption { + ssl = lib.mkOption { default = true; description = "Whether to use HTTPS for this DDNS provider."; type = bool; }; - username = mkOption { + username = lib.mkOption { default = null; description = "Username for this DDNS provider."; type = nullOr str; }; - password = mkOption { + password = lib.mkOption { default = null; description = '' Password for this DDNS provider. @@ -68,7 +65,7 @@ in ''; type = nullOr str; }; - hostname = mkOption { + hostname = lib.mkOption { default = "*"; example = "your.cool-domain.com"; description = "Hostname alias(es)."; @@ -77,12 +74,12 @@ in }; in { - enable = mkEnableOption ('' + enable = lib.mkEnableOption ('' synchronise your machine's IP address with a dynamic DNS provider using inadyn ''); - user = mkOption { + user = lib.mkOption { default = "inadyn"; - type = types.str; + type = lib.types.str; description = '' User account under which inadyn runs. @@ -93,9 +90,9 @@ in ::: ''; }; - group = mkOption { + group = lib.mkOption { default = "inadyn"; - type = types.str; + type = lib.types.str; description = '' Group account under which inadyn runs. @@ -106,7 +103,7 @@ in ::: ''; }; - interval = mkOption { + interval = lib.mkOption { default = "*-*-* *:*:00"; description = '' How often to check the current IP. @@ -119,24 +116,24 @@ in default = "notice"; description = "Set inadyn's log level."; }; - settings = mkOption { + settings = lib.mkOption { default = { }; description = "See `inadyn.conf (5)`"; type = submodule { freeformType = attrs; options = { - allow-ipv6 = mkOption { + allow-ipv6 = lib.mkOption { default = config.networking.enableIPv6; defaultText = "`config.networking.enableIPv6`"; description = "Whether to get IPv6 addresses from interfaces."; type = bool; }; - forced-update = mkOption { + forced-update = lib.mkOption { default = 2592000; description = "Duration (in seconds) after which an update is forced."; type = ints.positive; }; - provider = mkOption { + provider = lib.mkOption { default = { }; description = '' Settings for DDNS providers built-in to inadyn. @@ -148,7 +145,7 @@ in options = providerOptions; }); }; - custom = mkOption { + custom = lib.mkOption { default = { }; description = '' Settings for custom DNS providers. @@ -156,11 +153,11 @@ in type = attrsOf (submodule { freeformType = attrs; options = providerOptions // { - ddns-server = mkOption { + ddns-server = lib.mkOption { description = "DDNS server name."; type = str; }; - ddns-path = mkOption { + ddns-path = lib.mkOption { description = '' DDNS server path. @@ -175,7 +172,7 @@ in }; }; }; - configFile = mkOption { + configFile = lib.mkOption { default = null; description = '' Configuration file for inadyn. @@ -238,12 +235,12 @@ in timers.inadyn.timerConfig.Persistent = true; }; - users.users.inadyn = mkIf (cfg.user == "inadyn") { + users.users.inadyn = lib.mkIf (cfg.user == "inadyn") { group = cfg.group; isSystemUser = true; }; - users.groups = mkIf (cfg.group == "inadyn") { + users.groups = lib.mkIf (cfg.group == "inadyn") { inadyn = { }; }; }; diff --git a/nixos/modules/services/networking/iodine.nix b/nixos/modules/services/networking/iodine.nix index c474f5f278bf..2bdfa6f1b844 100644 --- a/nixos/modules/services/networking/iodine.nix +++ b/nixos/modules/services/networking/iodine.nix @@ -1,24 +1,20 @@ # NixOS module for iodine, ip over dns daemon - { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.iodine; iodinedUser = "iodined"; /* is this path made unreadable by ProtectHome = true ? */ - isProtected = x: hasPrefix "/root" x || hasPrefix "/home" x; + isProtected = x: lib.hasPrefix "/root" x || lib.hasPrefix "/home" x; in { imports = [ - (mkRenamedOptionModule [ "services" "iodined" "enable" ] [ "services" "iodine" "server" "enable" ]) - (mkRenamedOptionModule [ "services" "iodined" "domain" ] [ "services" "iodine" "server" "domain" ]) - (mkRenamedOptionModule [ "services" "iodined" "ip" ] [ "services" "iodine" "server" "ip" ]) - (mkRenamedOptionModule [ "services" "iodined" "extraConfig" ] [ "services" "iodine" "server" "extraConfig" ]) - (mkRemovedOptionModule [ "services" "iodined" "client" ] "") + (lib.mkRenamedOptionModule [ "services" "iodined" "enable" ] [ "services" "iodine" "server" "enable" ]) + (lib.mkRenamedOptionModule [ "services" "iodined" "domain" ] [ "services" "iodine" "server" "domain" ]) + (lib.mkRenamedOptionModule [ "services" "iodined" "ip" ] [ "services" "iodine" "server" "ip" ]) + (lib.mkRenamedOptionModule [ "services" "iodined" "extraConfig" ] [ "services" "iodine" "server" "extraConfig" ]) + (lib.mkRemovedOptionModule [ "services" "iodined" "client" ] "") ]; ### configuration @@ -26,7 +22,7 @@ in options = { services.iodine = { - clients = mkOption { + clients = lib.mkOption { default = {}; description = '' Each attribute of this option defines a systemd service that @@ -36,7 +32,7 @@ in where «name» is the name of the corresponding attribute name. ''; - example = literalExpression '' + example = lib.literalExpression '' { foo = { server = "tunnel.mdomain.com"; @@ -45,33 +41,33 @@ in } } ''; - type = types.attrsOf ( - types.submodule ( + type = lib.types.attrsOf ( + lib.types.submodule ( { options = { - server = mkOption { - type = types.str; + server = lib.mkOption { + type = lib.types.str; default = ""; description = "Hostname of server running iodined"; example = "tunnel.mydomain.com"; }; - relay = mkOption { - type = types.str; + relay = lib.mkOption { + type = lib.types.str; default = ""; description = "DNS server to use as an intermediate relay to the iodined server"; example = "8.8.8.8"; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = "Additional command line parameters"; example = "-l 192.168.1.10 -p 23"; }; - passwordFile = mkOption { - type = types.str; + passwordFile = lib.mkOption { + type = lib.types.str; default = ""; description = "Path to a file containing the password."; }; @@ -82,35 +78,35 @@ in }; server = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "enable iodined server"; }; - ip = mkOption { - type = types.str; + ip = lib.mkOption { + type = lib.types.str; default = ""; description = "The assigned ip address or ip range"; example = "172.16.10.1/24"; }; - domain = mkOption { - type = types.str; + domain = lib.mkOption { + type = lib.types.str; default = ""; description = "Domain or subdomain of which nameservers point to us"; example = "tunnel.mydomain.com"; }; - extraConfig = mkOption { - type = types.str; + extraConfig = lib.mkOption { + type = lib.types.str; default = ""; description = "Additional command line parameters"; example = "-l 192.168.1.10 -p 23"; }; - passwordFile = mkOption { - type = types.str; + passwordFile = lib.mkOption { + type = lib.types.str; default = ""; description = "File that contains password"; }; @@ -121,7 +117,7 @@ in ### implementation - config = mkIf (cfg.server.enable || cfg.clients != {}) { + config = lib.mkIf (cfg.server.enable || cfg.clients != {}) { environment.systemPackages = [ pkgs.iodine ]; boot.kernelModules = [ "tun" ]; @@ -132,7 +128,7 @@ in description = "iodine client - ${name}"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${builtins.toString cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}"; + script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${lib.optionalString (cfg.passwordFile != "") "< \"${builtins.toString cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}"; serviceConfig = { RestartSec = "30s"; Restart = "always"; @@ -157,16 +153,16 @@ in }; }; in - listToAttrs ( - mapAttrsToList - (name: value: nameValuePair "iodine-${name}" (createIodineClientService name value)) + lib.listToAttrs ( + lib.mapAttrsToList + (name: value: lib.nameValuePair "iodine-${name}" (createIodineClientService name value)) cfg.clients ) // { - iodined = mkIf (cfg.server.enable) { + iodined = lib.mkIf (cfg.server.enable) { description = "iodine, ip over dns server daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${builtins.toString cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}"; + script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${lib.optionalString (cfg.server.passwordFile != "") "< \"${builtins.toString cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}"; serviceConfig = { # Filesystem access ProtectSystem = "strict"; diff --git a/nixos/modules/services/networking/ivpn.nix b/nixos/modules/services/networking/ivpn.nix index 535510f4e813..6482bbadaeb2 100644 --- a/nixos/modules/services/networking/ivpn.nix +++ b/nixos/modules/services/networking/ivpn.nix @@ -2,11 +2,10 @@ let cfg = config.services.ivpn; in -with lib; { options.services.ivpn = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' This option enables iVPN daemon. @@ -15,7 +14,7 @@ with lib; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { boot.kernelModules = [ "tun" ]; environment.systemPackages = with pkgs; [ ivpn ivpn-service ]; @@ -47,5 +46,5 @@ with lib; }; }; - meta.maintainers = with maintainers; [ ataraxiasjel ]; + meta.maintainers = with lib.maintainers; [ ataraxiasjel ]; } diff --git a/nixos/modules/services/networking/jicofo.nix b/nixos/modules/services/networking/jicofo.nix index d4199c10fa2e..91906e417361 100644 --- a/nixos/modules/services/networking/jicofo.nix +++ b/nixos/modules/services/networking/jicofo.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.jicofo; @@ -10,10 +7,10 @@ let configFile = format.generate "jicofo.conf" cfg.config; in { - options.services.jicofo = with types; { - enable = mkEnableOption "Jitsi Conference Focus - component of Jitsi Meet"; + options.services.jicofo = with lib.types; { + enable = lib.mkEnableOption "Jitsi Conference Focus - component of Jitsi Meet"; - xmppHost = mkOption { + xmppHost = lib.mkOption { type = str; example = "localhost"; description = '' @@ -21,7 +18,7 @@ in ''; }; - xmppDomain = mkOption { + xmppDomain = lib.mkOption { type = nullOr str; example = "meet.example.org"; description = '' @@ -31,7 +28,7 @@ in ''; }; - componentPasswordFile = mkOption { + componentPasswordFile = lib.mkOption { type = str; example = "/run/keys/jicofo-component"; description = '' @@ -39,7 +36,7 @@ in ''; }; - userName = mkOption { + userName = lib.mkOption { type = str; default = "focus"; description = '' @@ -47,7 +44,7 @@ in ''; }; - userDomain = mkOption { + userDomain = lib.mkOption { type = str; example = "auth.meet.example.org"; description = '' @@ -55,7 +52,7 @@ in ''; }; - userPasswordFile = mkOption { + userPasswordFile = lib.mkOption { type = str; example = "/run/keys/jicofo-user"; description = '' @@ -63,7 +60,7 @@ in ''; }; - bridgeMuc = mkOption { + bridgeMuc = lib.mkOption { type = str; example = "jvbbrewery@internal.meet.example.org"; description = '' @@ -71,10 +68,10 @@ in ''; }; - config = mkOption { + config = lib.mkOption { type = format.type; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { jicofo.bridge.max-bridge-participants = 42; } @@ -85,7 +82,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.jicofo.config = { jicofo = { bridge.brewery-jid = cfg.bridgeMuc; @@ -120,7 +117,7 @@ in restartTriggers = [ configFile ]; - environment.JAVA_SYS_PROPS = concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") jicofoProps); + environment.JAVA_SYS_PROPS = lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "${k}=${toString v}") jicofoProps); script = '' export JICOFO_AUTH_PASS="$(<${cfg.userPasswordFile})" @@ -154,7 +151,7 @@ in environment.etc."jitsi/jicofo/sip-communicator.properties".text = ""; environment.etc."jitsi/jicofo/logging.properties".source = - mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal"; + lib.mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal"; }; meta.maintainers = lib.teams.jitsi.members; diff --git a/nixos/modules/services/networking/jigasi.nix b/nixos/modules/services/networking/jigasi.nix index e701689031b1..d69d905788f4 100644 --- a/nixos/modules/services/networking/jigasi.nix +++ b/nixos/modules/services/networking/jigasi.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.jigasi; homeDirName = "jigasi-home"; @@ -10,10 +7,10 @@ let sipCommunicatorPropertiesFileUnsubstituted = "${pkgs.jigasi}/etc/jitsi/jigasi/sip-communicator.properties"; in { - options.services.jigasi = with types; { - enable = mkEnableOption "Jitsi Gateway to SIP - component of Jitsi Meet"; + options.services.jigasi = with lib.types; { + enable = lib.mkEnableOption "Jitsi Gateway to SIP - component of Jitsi Meet"; - xmppHost = mkOption { + xmppHost = lib.mkOption { type = str; example = "localhost"; description = '' @@ -21,7 +18,7 @@ in ''; }; - xmppDomain = mkOption { + xmppDomain = lib.mkOption { type = nullOr str; example = "meet.example.org"; description = '' @@ -31,7 +28,7 @@ in ''; }; - componentPasswordFile = mkOption { + componentPasswordFile = lib.mkOption { type = str; example = "/run/keys/jigasi-component"; description = '' @@ -39,7 +36,7 @@ in ''; }; - userName = mkOption { + userName = lib.mkOption { type = str; default = "callcontrol"; description = '' @@ -47,7 +44,7 @@ in ''; }; - userDomain = mkOption { + userDomain = lib.mkOption { type = str; example = "internal.meet.example.org"; description = '' @@ -55,7 +52,7 @@ in ''; }; - userPasswordFile = mkOption { + userPasswordFile = lib.mkOption { type = str; example = "/run/keys/jigasi-user"; description = '' @@ -63,7 +60,7 @@ in ''; }; - bridgeMuc = mkOption { + bridgeMuc = lib.mkOption { type = str; example = "jigasibrewery@internal.meet.example.org"; description = '' @@ -71,7 +68,7 @@ in ''; }; - defaultJvbRoomName = mkOption { + defaultJvbRoomName = lib.mkOption { type = str; default = ""; example = "siptest"; @@ -80,8 +77,8 @@ in ''; }; - environmentFile = mkOption { - type = types.nullOr types.path; + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; default = null; description = '' File containing environment variables to be passed to the jigasi service, @@ -93,10 +90,10 @@ in ''; }; - config = mkOption { + config = lib.mkOption { type = attrsOf str; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "org.jitsi.jigasi.auth.URL" = "XMPP:jitsi-meet.example.com"; } @@ -107,12 +104,12 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.jicofo.config = { "org.jitsi.jicofo.jigasi.BREWERY" = "${cfg.bridgeMuc}"; }; - services.jigasi.config = mapAttrs (_: v: mkDefault v) { + services.jigasi.config = lib.mapAttrs (_: v: lib.mkDefault v) { "org.jitsi.jigasi.BRIDGE_MUC" = cfg.bridgeMuc; }; @@ -186,7 +183,7 @@ in restartTriggers = [ config.environment.etc."jitsi/jigasi/sip-communicator.properties".source ]; - environment.JAVA_SYS_PROPS = concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") jigasiProps); + environment.JAVA_SYS_PROPS = lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "${k}=${toString v}") jigasiProps); script = '' ${pkgs.jigasi}/bin/jigasi \ @@ -228,9 +225,9 @@ in }; environment.etc."jitsi/jigasi/sip-communicator.properties".source = - mkDefault "${sipCommunicatorPropertiesFile}"; + lib.mkDefault "${sipCommunicatorPropertiesFile}"; environment.etc."jitsi/jigasi/logging.properties".source = - mkDefault "${stateDir}/logging.properties-journal"; + lib.mkDefault "${stateDir}/logging.properties-journal"; }; meta.maintainers = lib.teams.jitsi.members; diff --git a/nixos/modules/services/networking/jitsi-videobridge.nix b/nixos/modules/services/networking/jitsi-videobridge.nix index d73a9f256dfb..14eb64eae253 100644 --- a/nixos/modules/services/networking/jitsi-videobridge.nix +++ b/nixos/modules/services/networking/jitsi-videobridge.nix @@ -1,16 +1,13 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.jitsi-videobridge; - attrsToArgs = a: concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") a); + attrsToArgs = a: lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "${k}=${toString v}") a); format = pkgs.formats.hocon { }; # We're passing passwords in environment variables that have names generated # from an attribute name, which may not be a valid bash identifier. - toVarName = s: "XMPP_PASSWORD_" + stringAsChars (c: if builtins.match "[A-Za-z0-9]" c != null then c else "_") s; + toVarName = s: "XMPP_PASSWORD_" + lib.stringAsChars (c: if builtins.match "[A-Za-z0-9]" c != null then c else "_") s; defaultJvbConfig = { videobridge = { @@ -25,7 +22,7 @@ let enabled = true; transports = [ { type = "muc"; } ]; }; - apis.xmpp-client.configs = flip mapAttrs cfg.xmppConfigs (name: xmppConfig: { + apis.xmpp-client.configs = lib.flip lib.mapAttrs cfg.xmppConfigs (name: xmppConfig: { hostname = xmppConfig.hostName; domain = xmppConfig.domain; username = xmppConfig.userName; @@ -39,21 +36,21 @@ let }; # Allow overriding leaves of the default config despite types.attrs not doing any merging. - jvbConfig = recursiveUpdate defaultJvbConfig cfg.config; + jvbConfig = lib.recursiveUpdate defaultJvbConfig cfg.config; in { imports = [ - (mkRemovedOptionModule [ "services" "jitsi-videobridge" "apis" ] + (lib.mkRemovedOptionModule [ "services" "jitsi-videobridge" "apis" ] "services.jitsi-videobridge.apis was broken and has been migrated into the boolean option services.jitsi-videobridge.colibriRestApi. It is set to false by default, setting it to true will correctly enable the private /colibri rest API." ) ]; - options.services.jitsi-videobridge = with types; { - enable = mkEnableOption "Jitsi Videobridge, a WebRTC compatible video router"; + options.services.jitsi-videobridge = with lib.types; { + enable = lib.mkEnableOption "Jitsi Videobridge, a WebRTC compatible video router"; - config = mkOption { + config = lib.mkOption { type = attrs; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { videobridge = { ice.udp.port = 5000; @@ -72,14 +69,14 @@ in ''; }; - xmppConfigs = mkOption { + xmppConfigs = lib.mkOption { description = '' XMPP servers to connect to. See for more information. ''; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { "localhost" = { hostName = "localhost"; @@ -92,14 +89,14 @@ in ''; type = attrsOf (submodule ({ name, ... }: { options = { - hostName = mkOption { + hostName = lib.mkOption { type = str; example = "xmpp.example.org"; description = '' Hostname of the XMPP server to connect to. Name of the attribute set is used by default. ''; }; - domain = mkOption { + domain = lib.mkOption { type = nullOr str; default = null; example = "auth.xmpp.example.org"; @@ -107,28 +104,28 @@ in Domain part of JID of the XMPP user, if it is different from hostName. ''; }; - userName = mkOption { + userName = lib.mkOption { type = str; default = "jvb"; description = '' User part of the JID. ''; }; - passwordFile = mkOption { + passwordFile = lib.mkOption { type = str; example = "/run/keys/jitsi-videobridge-xmpp1"; description = '' File containing the password for the user. ''; }; - mucJids = mkOption { + mucJids = lib.mkOption { type = str; example = "jvbbrewery@internal.xmpp.example.org"; description = '' JID of the MUC to join. JiCoFo needs to be configured to join the same MUC. ''; }; - mucNickname = mkOption { + mucNickname = lib.mkOption { # Upstream DEBs use UUID, let's use hostname instead. type = str; description = '' @@ -136,7 +133,7 @@ in nickname (aka resource part of the JID). By default, system hostname is used. ''; }; - disableCertificateVerification = mkOption { + disableCertificateVerification = lib.mkOption { type = bool; default = false; description = '' @@ -145,8 +142,8 @@ in }; }; config = { - hostName = mkDefault name; - mucNickname = mkDefault (builtins.replaceStrings [ "." ] [ "-" ] ( + hostName = lib.mkDefault name; + mucNickname = lib.mkDefault (builtins.replaceStrings [ "." ] [ "-" ] ( config.networking.fqdnOrHostName )); }; @@ -154,26 +151,44 @@ in }; nat = { - localAddress = mkOption { + localAddress = lib.mkOption { type = nullOr str; default = null; example = "192.168.1.42"; description = '' - Local address when running behind NAT. + Local address to assume when running behind NAT. ''; }; - publicAddress = mkOption { + publicAddress = lib.mkOption { type = nullOr str; default = null; example = "1.2.3.4"; description = '' - Public address when running behind NAT. + Public address to assume when running behind NAT. + ''; + }; + + harvesterAddresses = lib.mkOption { + type = listOf str; + default = [ + "stunserver.stunprotocol.org:3478" + "stun.framasoft.org:3478" + "meet-jit-si-turnrelay.jitsi.net:443" + ]; + example = []; + description = '' + Addresses of public STUN services to use to automatically find + the public and local addresses of this Jitsi-Videobridge instance + without the need for manual configuration. + + This option is ignored if {option}`services.jitsi-videobridge.nat.localAddress` + and {option}`services.jitsi-videobridge.nat.publicAddress` are set. ''; }; }; - extraProperties = mkOption { + extraProperties = lib.mkOption { type = attrsOf str; default = { }; description = '' @@ -181,7 +196,7 @@ in ''; }; - openFirewall = mkOption { + openFirewall = lib.mkOption { type = bool; default = false; description = '' @@ -189,7 +204,7 @@ in ''; }; - colibriRestApi = mkOption { + colibriRestApi = lib.mkOption { type = bool; description = '' Whether to enable the private rest API for the COLIBRI control interface. @@ -199,13 +214,16 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.groups.jitsi-meet = {}; - services.jitsi-videobridge.extraProperties = optionalAttrs (cfg.nat.localAddress != null) { - "org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS" = cfg.nat.localAddress; - "org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS" = cfg.nat.publicAddress; - }; + services.jitsi-videobridge.extraProperties = + if (cfg.nat.localAddress != null) then { + "org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS" = cfg.nat.localAddress; + "org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS" = cfg.nat.publicAddress; + } else { + "org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES" = lib.concatStringsSep "," cfg.nat.harvesterAddresses; + }; systemd.services.jitsi-videobridge2 = let jvbProps = { @@ -215,7 +233,7 @@ in "-Dconfig.file" = format.generate "jvb.conf" jvbConfig; # Mitigate CVE-2021-44228 "-Dlog4j2.formatMsgNoLookups" = true; - } // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties); + } // (lib.mapAttrs' (k: v: lib.nameValuePair "-D${k}" v) cfg.extraProperties); in { aliases = [ "jitsi-videobridge.service" ]; @@ -225,7 +243,7 @@ in environment.JAVA_SYS_PROPS = attrsToArgs jvbProps; - script = (concatStrings (mapAttrsToList (name: xmppConfig: + script = (lib.concatStrings (lib.mapAttrsToList (name: xmppConfig: "export ${toVarName name}=$(cat ${xmppConfig.passwordFile})\n" ) cfg.xmppConfigs)) + '' @@ -262,16 +280,16 @@ in }; environment.etc."jitsi/videobridge/logging.properties".source = - mkDefault "${pkgs.jitsi-videobridge}/etc/jitsi/videobridge/logging.properties-journal"; + lib.mkDefault "${pkgs.jitsi-videobridge}/etc/jitsi/videobridge/logging.properties-journal"; # (from videobridge2 .deb) # this sets the max, so that we can bump the JVB UDP single port buffer size. - boot.kernel.sysctl."net.core.rmem_max" = mkDefault 10485760; - boot.kernel.sysctl."net.core.netdev_max_backlog" = mkDefault 100000; + boot.kernel.sysctl."net.core.rmem_max" = lib.mkDefault 10485760; + boot.kernel.sysctl."net.core.netdev_max_backlog" = lib.mkDefault 100000; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ jvbConfig.videobridge.ice.tcp.port ]; - networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ jvbConfig.videobridge.ice.udp.port ]; assertions = [{ diff --git a/nixos/modules/services/networking/jotta-cli.nix b/nixos/modules/services/networking/jotta-cli.nix index e0fa1ef332fe..566e7fc503a6 100644 --- a/nixos/modules/services/networking/jotta-cli.nix +++ b/nixos/modules/services/networking/jotta-cli.nix @@ -1,25 +1,22 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.jotta-cli; in { options = { services.jotta-cli = { - enable = mkEnableOption "Jottacloud Command-line Tool"; + enable = lib.mkEnableOption "Jottacloud Command-line Tool"; - options = mkOption { + options = lib.mkOption { default = [ "stdoutlog" "datadir" "%h/.jottad/" ]; example = [ ]; - type = with types; listOf str; + type = with lib.types; listOf str; description = "Command-line options passed to jottad."; }; package = lib.mkPackageOption pkgs "jotta-cli" { }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.user.services.jottad = { description = "Jottacloud Command-line Tool daemon"; @@ -27,7 +24,7 @@ in { serviceConfig = { Type = "notify"; EnvironmentFile = "-%h/.config/jotta-cli/jotta-cli.env"; - ExecStart = "${lib.getExe' cfg.package "jottad"} ${concatStringsSep " " cfg.options}"; + ExecStart = "${lib.getExe' cfg.package "jottad"} ${lib.concatStringsSep " " cfg.options}"; Restart = "on-failure"; }; diff --git a/nixos/modules/services/networking/kea.nix b/nixos/modules/services/networking/kea.nix index 11add600b66f..8a145c37a61f 100644 --- a/nixos/modules/services/networking/kea.nix +++ b/nixos/modules/services/networking/kea.nix @@ -3,9 +3,6 @@ , pkgs , ... }: - -with lib; - let cfg = config.services.kea; @@ -32,17 +29,17 @@ let package = pkgs.kea; in { - options.services.kea = with types; { - ctrl-agent = mkOption { + options.services.kea = with lib.types; { + ctrl-agent = lib.mkOption { description = '' Kea Control Agent configuration ''; default = {}; type = submodule { options = { - enable = mkEnableOption "Kea Control Agent"; + enable = lib.mkEnableOption "Kea Control Agent"; - extraArgs = mkOption { + extraArgs = lib.mkOption { type = listOf str; default = []; description = '' @@ -50,7 +47,7 @@ in ''; }; - configFile = mkOption { + configFile = lib.mkOption { type = nullOr path; default = null; description = '' @@ -61,7 +58,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = null; description = '' @@ -72,16 +69,16 @@ in }; }; - dhcp4 = mkOption { + dhcp4 = lib.mkOption { description = '' DHCP4 Server configuration ''; default = {}; type = submodule { options = { - enable = mkEnableOption "Kea DHCP4 server"; + enable = lib.mkEnableOption "Kea DHCP4 server"; - extraArgs = mkOption { + extraArgs = lib.mkOption { type = listOf str; default = []; description = '' @@ -89,7 +86,7 @@ in ''; }; - configFile = mkOption { + configFile = lib.mkOption { type = nullOr path; default = null; description = '' @@ -100,7 +97,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = null; example = { @@ -132,16 +129,16 @@ in }; }; - dhcp6 = mkOption { + dhcp6 = lib.mkOption { description = '' DHCP6 Server configuration ''; default = {}; type = submodule { options = { - enable = mkEnableOption "Kea DHCP6 server"; + enable = lib.mkEnableOption "Kea DHCP6 server"; - extraArgs = mkOption { + extraArgs = lib.mkOption { type = listOf str; default = []; description = '' @@ -149,7 +146,7 @@ in ''; }; - configFile = mkOption { + configFile = lib.mkOption { type = nullOr path; default = null; description = '' @@ -160,7 +157,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = null; example = { @@ -193,16 +190,16 @@ in }; }; - dhcp-ddns = mkOption { + dhcp-ddns = lib.mkOption { description = '' Kea DHCP-DDNS configuration ''; default = {}; type = submodule { options = { - enable = mkEnableOption "Kea DDNS server"; + enable = lib.mkEnableOption "Kea DDNS server"; - extraArgs = mkOption { + extraArgs = lib.mkOption { type = listOf str; default = []; description = '' @@ -210,7 +207,7 @@ in ''; }; - configFile = mkOption { + configFile = lib.mkOption { type = nullOr path; default = null; description = '' @@ -221,7 +218,7 @@ in ''; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; default = null; example = { @@ -258,14 +255,14 @@ in StateDirectory = "kea"; UMask = "0077"; }; - in mkIf (cfg.ctrl-agent.enable || cfg.dhcp4.enable || cfg.dhcp6.enable || cfg.dhcp-ddns.enable) (mkMerge [ + in lib.mkIf (cfg.ctrl-agent.enable || cfg.dhcp4.enable || cfg.dhcp6.enable || cfg.dhcp-ddns.enable) (lib.mkMerge [ { environment.systemPackages = [ package ]; } - (mkIf cfg.ctrl-agent.enable { + (lib.mkIf cfg.ctrl-agent.enable { assertions = [{ - assertion = xor (cfg.ctrl-agent.settings == null) (cfg.ctrl-agent.configFile == null); + assertion = lib.xor (cfg.ctrl-agent.settings == null) (cfg.ctrl-agent.configFile == null); message = "Either services.kea.ctrl-agent.settings or services.kea.ctrl-agent.configFile must be set to a non-null value."; }]; @@ -308,9 +305,9 @@ in }; }) - (mkIf cfg.dhcp4.enable { + (lib.mkIf cfg.dhcp4.enable { assertions = [{ - assertion = xor (cfg.dhcp4.settings == null) (cfg.dhcp4.configFile == null); + assertion = lib.xor (cfg.dhcp4.settings == null) (cfg.dhcp4.configFile == null); message = "Either services.kea.dhcp4.settings or services.kea.dhcp4.configFile must be set to a non-null value."; }]; @@ -358,9 +355,9 @@ in }; }) - (mkIf cfg.dhcp6.enable { + (lib.mkIf cfg.dhcp6.enable { assertions = [{ - assertion = xor (cfg.dhcp6.settings == null) (cfg.dhcp6.configFile == null); + assertion = lib.xor (cfg.dhcp6.settings == null) (cfg.dhcp6.configFile == null); message = "Either services.kea.dhcp6.settings or services.kea.dhcp6.configFile must be set to a non-null value."; }]; @@ -406,9 +403,9 @@ in }; }) - (mkIf cfg.dhcp-ddns.enable { + (lib.mkIf cfg.dhcp-ddns.enable { assertions = [{ - assertion = xor (cfg.dhcp-ddns.settings == null) (cfg.dhcp-ddns.configFile == null); + assertion = lib.xor (cfg.dhcp-ddns.settings == null) (cfg.dhcp-ddns.configFile == null); message = "Either services.kea.dhcp-ddns.settings or services.kea.dhcp-ddns.configFile must be set to a non-null value."; }]; @@ -453,7 +450,7 @@ in ]); - meta.maintainers = with maintainers; [ hexa ]; + meta.maintainers = with lib.maintainers; [ hexa ]; # uses attributes of the linked package meta.buildDocsInSandbox = false; } diff --git a/nixos/modules/services/networking/keybase.nix b/nixos/modules/services/networking/keybase.nix index 495102cb7eee..9bb7ad3844a0 100644 --- a/nixos/modules/services/networking/keybase.nix +++ b/nixos/modules/services/networking/keybase.nix @@ -1,8 +1,6 @@ { config, lib, pkgs, ... }: -with lib; let cfg = config.services.keybase; - in { ###### interface @@ -11,8 +9,8 @@ in { services.keybase = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Whether to start the Keybase service."; }; @@ -22,7 +20,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/keybase.service systemd.user.services.keybase = { diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix index 145b4ad1dd3f..d174edb0fc93 100644 --- a/nixos/modules/services/networking/knot.nix +++ b/nixos/modules/services/networking/knot.nix @@ -337,6 +337,7 @@ in { SystemCallFilter = [ "@system-service" "~@privileged" + "@chown" ] ++ optionals (cfg.enableXDP) [ "bpf" ]; diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix index d295e40f3922..4c1d6c50d830 100644 --- a/nixos/modules/services/networking/kresd.nix +++ b/nixos/modules/services/networking/kresd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.kresd; @@ -12,11 +9,11 @@ let al_v4 = builtins.match "([0-9.]+):([0-9]+)($)" addr; al_v6 = builtins.match "\\[(.+)]:([0-9]+)(%.*|$)" addr; al_portOnly = builtins.match "(^)([0-9]+)" addr; - al = findFirst (a: a != null) + al = lib.findFirst (a: a != null) (throw "services.kresd.*: incorrect address specification '${addr}'") [ al_v4 al_v6 al_portOnly ]; - port = elemAt al 1; - addrSpec = if al_portOnly == null then "'${head al}${elemAt al 2}'" else "{'::', '0.0.0.0'}"; + port = lib.elemAt al 1; + addrSpec = if al_portOnly == null then "'${lib.head al}${lib.elemAt al 2}'" else "{'::', '0.0.0.0'}"; in # freebind is set for compatibility with earlier kresd services; # it could be configurable, for example. '' @@ -25,30 +22,30 @@ let configFile = pkgs.writeText "kresd.conf" ( "" - + concatMapStrings (mkListen "dns") cfg.listenPlain - + concatMapStrings (mkListen "tls") cfg.listenTLS - + concatMapStrings (mkListen "doh2") cfg.listenDoH + + lib.concatMapStrings (mkListen "dns") cfg.listenPlain + + lib.concatMapStrings (mkListen "tls") cfg.listenTLS + + lib.concatMapStrings (mkListen "doh2") cfg.listenDoH + cfg.extraConfig ); in { - meta.maintainers = [ maintainers.vcunat /* upstream developer */ ]; + meta.maintainers = [ lib.maintainers.vcunat /* upstream developer */ ]; imports = [ - (mkChangedOptionModule [ "services" "kresd" "interfaces" ] [ "services" "kresd" "listenPlain" ] + (lib.mkChangedOptionModule [ "services" "kresd" "interfaces" ] [ "services" "kresd" "listenPlain" ] (config: - let value = getAttrFromPath [ "services" "kresd" "interfaces" ] config; + let value = lib.getAttrFromPath [ "services" "kresd" "interfaces" ] config; in map - (iface: if elem ":" (stringToCharacters iface) then "[${iface}]:53" else "${iface}:53") # Syntax depends on being IPv6 or IPv4. + (iface: if lib.elem ":" (lib.stringToCharacters iface) then "[${iface}]:53" else "${iface}:53") # Syntax depends on being IPv6 or IPv4. value ) ) - (mkRemovedOptionModule [ "services" "kresd" "cacheDir" ] "Please use (bind-)mounting instead.") + (lib.mkRemovedOptionModule [ "services" "kresd" "cacheDir" ] "Please use (bind-)mounting instead.") ]; ###### interface options.services.kresd = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable knot-resolver domain name server. @@ -57,18 +54,19 @@ in { and give commands interactively to kresd@1.service. ''; }; - package = mkPackageOption pkgs "knot-resolver" { + package = lib.mkPackageOption pkgs "knot-resolver" { example = "knot-resolver.override { extraFeatures = true; }"; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra lines to be added verbatim to the generated configuration file. + See upstream documentation for more details. ''; }; - listenPlain = mkOption { - type = with types; listOf str; + listenPlain = lib.mkOption { + type = with lib.types; listOf str; default = [ "[::1]:53" "127.0.0.1:53" ]; example = [ "53" ]; description = '' @@ -76,8 +74,8 @@ in { For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`. ''; }; - listenTLS = mkOption { - type = with types; listOf str; + listenTLS = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "198.51.100.1:853" "[2001:db8::1]:853" "853" ]; description = '' @@ -85,8 +83,8 @@ in { For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`. ''; }; - listenDoH = mkOption { - type = with types; listOf str; + listenDoH = lib.mkOption { + type = with lib.types; listOf str; default = []; example = [ "198.51.100.1:443" "[2001:db8::1]:443" "443" ]; description = '' @@ -94,8 +92,8 @@ in { For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`. ''; }; - instances = mkOption { - type = types.ints.unsigned; + instances = lib.mkOption { + type = lib.types.ints.unsigned; default = 1; description = '' The number of instances to start. They will be called kresd@{1,2,...}.service. @@ -107,10 +105,10 @@ in { }; ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { environment.etc."knot-resolver/kresd.conf".source = configFile; # not required - networking.resolvconf.useLocalResolver = mkDefault true; + networking.resolvconf.useLocalResolver = lib.mkDefault true; users.users.knot-resolver = { isSystemUser = true; @@ -124,7 +122,7 @@ in { systemd.targets.kresd = { # configure units started by default wantedBy = [ "multi-user.target" ]; wants = [ "kres-cache-gc.service" ] - ++ map (i: "kresd@${toString i}.service") (range 1 cfg.instances); + ++ map (i: "kresd@${toString i}.service") (lib.range 1 cfg.instances); }; systemd.services."kresd@".serviceConfig = { ExecStart = "${cfg.package}/bin/kresd --noninteractive " diff --git a/nixos/modules/services/networking/lambdabot.nix b/nixos/modules/services/networking/lambdabot.nix index a141962f512f..8c8e5648450c 100644 --- a/nixos/modules/services/networking/lambdabot.nix +++ b/nixos/modules/services/networking/lambdabot.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.lambdabot; @@ -18,16 +15,16 @@ in services.lambdabot = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = "Enable the Lambdabot IRC bot"; }; - package = mkPackageOption pkgs "lambdabot" { }; + package = lib.mkPackageOption pkgs "lambdabot" { }; - script = mkOption { - type = types.str; + script = lib.mkOption { + type = lib.types.str; default = ""; description = "Lambdabot script"; }; @@ -38,7 +35,7 @@ in ### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.lambdabot = { description = "Lambdabot daemon"; diff --git a/nixos/modules/services/networking/libreswan.nix b/nixos/modules/services/networking/libreswan.nix index ae71acf089f4..a66ff3065224 100644 --- a/nixos/modules/services/networking/libreswan.nix +++ b/nixos/modules/services/networking/libreswan.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.libreswan; @@ -11,14 +8,14 @@ let trim = chars: str: let - nonchars = filter (x : !(elem x.value chars)) - (imap0 (i: v: {ind = i; value = v;}) (stringToCharacters str)); + nonchars = lib.filter (x : !(lib.elem x.value chars)) + (lib.imap0 (i: v: {ind = i; value = v;}) (lib.stringToCharacters str)); in lib.optionalString (nonchars != [ ]) - (substring (head nonchars).ind (add 1 (sub (last nonchars).ind (head nonchars).ind)) str); - indent = str: concatStrings (concatMap (s: [" " (trim [" " "\t"] s) "\n"]) (splitString "\n" str)); + (lib.substring (lib.head nonchars).ind (lib.add 1 (lib.sub (lib.last nonchars).ind (lib.head nonchars).ind)) str); + indent = str: lib.concatStrings (lib.concatMap (s: [" " (trim [" " "\t"] s) "\n"]) (lib.splitString "\n" str)); configText = indent (toString cfg.configSetup); - connectionText = concatStrings (mapAttrsToList (n: v: + connectionText = lib.concatStrings (lib.mapAttrsToList (n: v: '' conn ${n} ${indent v} @@ -32,7 +29,7 @@ let ${connectionText} ''; - policyFiles = mapAttrs' (name: text: + policyFiles = lib.mapAttrs' (name: text: { name = "ipsec.d/policies/${name}"; value.source = pkgs.writeText "ipsec-policy-${name}" text; }) cfg.policies; @@ -47,10 +44,10 @@ in services.libreswan = { - enable = mkEnableOption "Libreswan IPsec service"; + enable = lib.mkEnableOption "Libreswan IPsec service"; - configSetup = mkOption { - type = types.lines; + configSetup = lib.mkOption { + type = lib.types.lines; default = '' protostack=netkey virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 @@ -63,10 +60,10 @@ in description = "Options to go in the 'config setup' section of the Libreswan IPsec configuration"; }; - connections = mkOption { - type = types.attrsOf types.lines; + connections = lib.mkOption { + type = lib.types.attrsOf lib.types.lines; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { myconnection = ''' auto=add left=%defaultroute @@ -82,10 +79,10 @@ in description = "A set of connections to define for the Libreswan IPsec service"; }; - policies = mkOption { - type = types.attrsOf types.lines; + policies = lib.mkOption { + type = lib.types.attrsOf lib.types.lines; default = {}; - example = literalExpression '' + example = lib.literalExpression '' { private-or-clear = ''' # Attempt opportunistic IPsec for the entire Internet 0.0.0.0/0 @@ -102,8 +99,8 @@ in ''; }; - disableRedirects = mkOption { - type = types.bool; + disableRedirects = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to disable send and accept redirects for all network interfaces. @@ -119,7 +116,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { # Install package, systemd units, etc. environment.systemPackages = [ pkgs.libreswan pkgs.iproute2 ]; @@ -136,7 +133,7 @@ in systemd.services.ipsec = { description = "Internet Key Exchange (IKE) Protocol Daemon for IPsec"; wantedBy = [ "multi-user.target" ]; - restartTriggers = [ configFile ] ++ mapAttrsToList (n: v: v.source) policyFiles; + restartTriggers = [ configFile ] ++ lib.mapAttrsToList (n: v: v.source) policyFiles; path = with pkgs; [ libreswan iproute2 @@ -145,7 +142,7 @@ in iptables nettools ]; - preStart = optionalString cfg.disableRedirects '' + preStart = lib.optionalString cfg.disableRedirects '' # Disable send/receive redirects echo 0 | tee /proc/sys/net/ipv4/conf/*/send_redirects echo 0 | tee /proc/sys/net/ipv{4,6}/conf/*/accept_redirects diff --git a/nixos/modules/services/networking/lldpd.nix b/nixos/modules/services/networking/lldpd.nix index d5de9c45d84b..98a4cff265f1 100644 --- a/nixos/modules/services/networking/lldpd.nix +++ b/nixos/modules/services/networking/lldpd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.lldpd; @@ -9,17 +6,17 @@ in { options.services.lldpd = { - enable = mkEnableOption "Link Layer Discovery Protocol Daemon"; + enable = lib.mkEnableOption "Link Layer Discovery Protocol Daemon"; - extraArgs = mkOption { - type = types.listOf types.str; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; default = []; example = [ "-c" "-k" "-I eth0" ]; description = "List of command line parameters for lldpd"; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users._lldpd = { description = "lldpd user"; group = "_lldpd"; @@ -33,7 +30,7 @@ in systemd.services.lldpd = { wantedBy = [ "multi-user.target" ]; - environment.LLDPD_OPTIONS = concatStringsSep " " cfg.extraArgs; + environment.LLDPD_OPTIONS = lib.concatStringsSep " " cfg.extraArgs; }; }; } diff --git a/nixos/modules/services/networking/logmein-hamachi.nix b/nixos/modules/services/networking/logmein-hamachi.nix index b7d960264d21..852101f09dff 100644 --- a/nixos/modules/services/networking/logmein-hamachi.nix +++ b/nixos/modules/services/networking/logmein-hamachi.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let cfg = config.services.logmein-hamachi; @@ -14,8 +11,8 @@ in options = { - services.logmein-hamachi.enable = mkOption { - type = types.bool; + services.logmein-hamachi.enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to enable LogMeIn Hamachi, a proprietary @@ -28,7 +25,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.logmein-hamachi = { description = "LogMeIn Hamachi Daemon"; diff --git a/nixos/modules/services/networking/lxd-image-server.nix b/nixos/modules/services/networking/lxd-image-server.nix index 93374a385a90..4712a3c1b3db 100644 --- a/nixos/modules/services/networking/lxd-image-server.nix +++ b/nixos/modules/services/networking/lxd-image-server.nix @@ -1,7 +1,4 @@ { config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.lxd-image-server; format = pkgs.formats.toml {}; @@ -11,16 +8,16 @@ in { options = { services.lxd-image-server = { - enable = mkEnableOption "lxd-image-server"; + enable = lib.mkEnableOption "lxd-image-server"; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; description = "Group assigned to the user and the webroot directory."; default = "nginx"; example = "www-data"; }; - settings = mkOption { + settings = lib.mkOption { type = format.type; description = '' Configuration for lxd-image-server. @@ -31,9 +28,9 @@ in }; nginx = { - enable = mkEnableOption "nginx"; - domain = mkOption { - type = types.str; + enable = lib.mkEnableOption "nginx"; + domain = lib.mkOption { + type = lib.types.str; description = "Domain to use for nginx virtual host."; example = "images.example.org"; }; @@ -41,8 +38,8 @@ in }; }; - config = mkMerge [ - (mkIf (cfg.enable) { + config = lib.mkMerge [ + (lib.mkIf (cfg.enable) { users.users.lxd-image-server = { isSystemUser = true; group = cfg.group; @@ -88,12 +85,12 @@ in }; }) # this is separate so it can be enabled on mirrored hosts - (mkIf (cfg.nginx.enable) { + (lib.mkIf (cfg.nginx.enable) { # https://github.com/Avature/lxd-image-server/blob/master/resources/nginx/includes/lxd-image-server.pkg.conf services.nginx.virtualHosts = { "${cfg.nginx.domain}" = { forceSSL = true; - enableACME = mkDefault true; + enableACME = lib.mkDefault true; root = location; diff --git a/nixos/modules/services/networking/matterbridge.nix b/nixos/modules/services/networking/matterbridge.nix index cdcb69070dfb..74b388d68408 100644 --- a/nixos/modules/services/networking/matterbridge.nix +++ b/nixos/modules/services/networking/matterbridge.nix @@ -1,7 +1,4 @@ { options, config, pkgs, lib, ... }: - -with lib; - let cfg = config.services.matterbridge; @@ -17,10 +14,12 @@ in { options = { services.matterbridge = { - enable = mkEnableOption "Matterbridge chat platform bridge"; + enable = lib.mkEnableOption "Matterbridge chat platform bridge"; - configPath = mkOption { - type = with types; nullOr str; + package = lib.mkPackageOption pkgs "matterbridge" { }; + + configPath = lib.mkOption { + type = with lib.types; nullOr str; default = null; example = "/etc/nixos/matterbridge.toml"; description = '' @@ -28,8 +27,8 @@ in ''; }; - configFile = mkOption { - type = types.str; + configFile = lib.mkOption { + type = lib.types.str; example = '' # WARNING: as this file contains credentials, do not use this option! # It is kept only for backwards compatibility, and would cause your @@ -70,16 +69,16 @@ in The matterbridge configuration file in the TOML file format. ''; }; - user = mkOption { - type = types.str; + user = lib.mkOption { + type = lib.types.str; default = "matterbridge"; description = '' User which runs the matterbridge service. ''; }; - group = mkOption { - type = types.str; + group = lib.mkOption { + type = lib.types.str; default = "matterbridge"; description = '' Group which runs the matterbridge service. @@ -88,18 +87,18 @@ in }; }; - config = mkIf cfg.enable { - warnings = optional options.services.matterbridge.configFile.isDefined + config = lib.mkIf cfg.enable { + warnings = lib.optional options.services.matterbridge.configFile.isDefined "The option services.matterbridge.configFile is insecure and should be replaced with services.matterbridge.configPath"; - users.users = optionalAttrs (cfg.user == "matterbridge") + users.users = lib.optionalAttrs (cfg.user == "matterbridge") { matterbridge = { group = "matterbridge"; isSystemUser = true; }; }; - users.groups = optionalAttrs (cfg.group == "matterbridge") + users.groups = lib.optionalAttrs (cfg.group == "matterbridge") { matterbridge = { }; }; @@ -111,7 +110,7 @@ in serviceConfig = { User = cfg.user; Group = cfg.group; - ExecStart = "${pkgs.matterbridge}/bin/matterbridge -conf ${matterbridgeConfToml}"; + ExecStart = "${cfg.package}/bin/matterbridge -conf ${matterbridgeConfToml}"; Restart = "always"; RestartSec = "10"; }; diff --git a/nixos/modules/services/networking/mihomo.nix b/nixos/modules/services/networking/mihomo.nix index a425952b54ce..05d3d304d460 100644 --- a/nixos/modules/services/networking/mihomo.nix +++ b/nixos/modules/services/networking/mihomo.nix @@ -18,7 +18,7 @@ in package = lib.mkPackageOption pkgs "mihomo" { }; configFile = lib.mkOption { - type = lib.types.nullOr lib.types.path; + type = lib.types.path; description = "Configuration file to use."; }; diff --git a/nixos/modules/services/networking/monero.nix b/nixos/modules/services/networking/monero.nix index 37a687f524b9..5cb418a9f1e6 100644 --- a/nixos/modules/services/networking/monero.nix +++ b/nixos/modules/services/networking/monero.nix @@ -1,12 +1,10 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.monero; listToConf = option: list: - concatMapStrings (value: "${option}=${value}\n") list; + lib.concatMapStrings (value: "${option}=${value}\n") list; login = (cfg.rpc.user != null && cfg.rpc.password != null); @@ -14,17 +12,17 @@ let log-file=/dev/stdout data-dir=${dataDir} - ${optionalString mining.enable '' + ${lib.optionalString mining.enable '' start-mining=${mining.address} mining-threads=${toString mining.threads} ''} rpc-bind-ip=${rpc.address} rpc-bind-port=${toString rpc.port} - ${optionalString login '' + ${lib.optionalString login '' rpc-login=${rpc.user}:${rpc.password} ''} - ${optionalString rpc.restricted '' + ${lib.optionalString rpc.restricted '' restricted-rpc=1 ''} @@ -50,34 +48,34 @@ in services.monero = { - enable = mkEnableOption "Monero node daemon"; + enable = lib.mkEnableOption "Monero node daemon"; - dataDir = mkOption { - type = types.str; + dataDir = lib.mkOption { + type = lib.types.str; default = "/var/lib/monero"; description = '' The directory where Monero stores its data files. ''; }; - mining.enable = mkOption { - type = types.bool; + mining.enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to mine monero. ''; }; - mining.address = mkOption { - type = types.str; + mining.address = lib.mkOption { + type = lib.types.str; default = ""; description = '' Monero address where to send mining rewards. ''; }; - mining.threads = mkOption { - type = types.addCheck types.int (x: x>=0); + mining.threads = lib.mkOption { + type = lib.types.addCheck lib.types.int (x: x>=0); default = 0; description = '' Number of threads used for mining. @@ -85,48 +83,48 @@ in ''; }; - rpc.user = mkOption { - type = types.nullOr types.str; + rpc.user = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' User name for RPC connections. ''; }; - rpc.password = mkOption { - type = types.nullOr types.str; + rpc.password = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = null; description = '' Password for RPC connections. ''; }; - rpc.address = mkOption { - type = types.str; + rpc.address = lib.mkOption { + type = lib.types.str; default = "127.0.0.1"; description = '' IP address the RPC server will bind to. ''; }; - rpc.port = mkOption { - type = types.port; + rpc.port = lib.mkOption { + type = lib.types.port; default = 18081; description = '' Port the RPC server will bind to. ''; }; - rpc.restricted = mkOption { - type = types.bool; + rpc.restricted = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether to restrict RPC to view only commands. ''; }; - limits.upload = mkOption { - type = types.addCheck types.int (x: x>=-1); + limits.upload = lib.mkOption { + type = lib.types.addCheck lib.types.int (x: x>=-1); default = -1; description = '' Limit of the upload rate in kB/s. @@ -134,8 +132,8 @@ in ''; }; - limits.download = mkOption { - type = types.addCheck types.int (x: x>=-1); + limits.download = lib.mkOption { + type = lib.types.addCheck lib.types.int (x: x>=-1); default = -1; description = '' Limit of the download rate in kB/s. @@ -143,8 +141,8 @@ in ''; }; - limits.threads = mkOption { - type = types.addCheck types.int (x: x>=0); + limits.threads = lib.mkOption { + type = lib.types.addCheck lib.types.int (x: x>=0); default = 0; description = '' Maximum number of threads used for a parallel job. @@ -152,8 +150,8 @@ in ''; }; - limits.syncSize = mkOption { - type = types.addCheck types.int (x: x>=0); + limits.syncSize = lib.mkOption { + type = lib.types.addCheck lib.types.int (x: x>=0); default = 0; description = '' Maximum number of blocks to sync at once. @@ -161,16 +159,16 @@ in ''; }; - extraNodes = mkOption { - type = types.listOf types.str; + extraNodes = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' List of additional peer IP addresses to add to the local list. ''; }; - priorityNodes = mkOption { - type = types.listOf types.str; + priorityNodes = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' List of peer IP addresses to connect to and @@ -178,8 +176,8 @@ in ''; }; - exclusiveNodes = mkOption { - type = types.listOf types.str; + exclusiveNodes = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' List of peer IP addresses to connect to *only*. @@ -187,8 +185,8 @@ in ''; }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = '' Extra lines to be added verbatim to monerod configuration. @@ -202,7 +200,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.monero = { isSystemUser = true; @@ -228,7 +226,7 @@ in }; }; - assertions = singleton { + assertions = lib.singleton { assertion = cfg.mining.enable -> cfg.mining.address != ""; message = '' You need a Monero address to receive mining rewards: diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 468f58b56bb1..e628be0d5b1b 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -1,39 +1,36 @@ { config, lib, pkgs, ...}: - -with lib; - let cfg = config.services.mosquitto; # note that mosquitto config parsing is very simplistic as of may 2021. # often times they'll e.g. strtok() a line, check the first two tokens, and ignore the rest. # there's no escaping available either, so we have to prevent any being necessary. - str = types.strMatching "[^\r\n]*" // { + str = lib.types.strMatching "[^\r\n]*" // { description = "single-line string"; }; - path = types.addCheck types.path (p: str.check "${p}"); - configKey = types.strMatching "[^\r\n\t ]+"; - optionType = with types; oneOf [ str path bool int ] // { + path = lib.types.addCheck lib.types.path (p: str.check "${p}"); + configKey = lib.types.strMatching "[^\r\n\t ]+"; + optionType = with lib.types; oneOf [ str path bool int ] // { description = "string, path, bool, or integer"; }; optionToString = v: - if isBool v then boolToString v + if lib.isBool v then lib.boolToString v else if path.check v then "${v}" else toString v; assertKeysValid = prefix: valid: config: - mapAttrsToList + lib.mapAttrsToList (n: _: { assertion = valid ? ${n}; message = "Invalid config key ${prefix}.${n}."; }) config; - formatFreeform = { prefix ? "" }: mapAttrsToList (n: v: "${prefix}${n} ${optionToString v}"); + formatFreeform = { prefix ? "" }: lib.mapAttrsToList (n: v: "${prefix}${n} ${optionToString v}"); - userOptions = with types; submodule { + userOptions = with lib.types; submodule { options = { - password = mkOption { + password = lib.mkOption { type = uniq (nullOr str); default = null; description = '' @@ -41,7 +38,7 @@ let ''; }; - passwordFile = mkOption { + passwordFile = lib.mkOption { type = uniq (nullOr path); example = "/path/to/file"; default = null; @@ -54,7 +51,7 @@ let ''; }; - hashedPassword = mkOption { + hashedPassword = lib.mkOption { type = uniq (nullOr str); default = null; description = '' @@ -66,7 +63,7 @@ let ''; }; - hashedPasswordFile = mkOption { + hashedPasswordFile = lib.mkOption { type = uniq (nullOr path); example = "/path/to/file"; default = null; @@ -82,7 +79,7 @@ let ''; }; - acl = mkOption { + acl = lib.mkOption { type = listOf str; example = [ "read A/B" "readwrite A/#" ]; default = []; @@ -94,15 +91,15 @@ let }; userAsserts = prefix: users: - mapAttrsToList + lib.mapAttrsToList (n: _: { assertion = builtins.match "[^:\r\n]+" n != null; message = "Invalid user name ${n} in ${prefix}"; }) users - ++ mapAttrsToList + ++ lib.mapAttrsToList (n: u: { - assertion = count (s: s != null) [ + assertion = lib.count (s: s != null) [ u.password u.passwordFile u.hashedPassword u.hashedPasswordFile ] <= 1; message = "Cannot set more than one password option for user ${n} in ${prefix}"; @@ -112,26 +109,26 @@ let userScope = prefix: index: "${prefix}-user-${toString index}"; credentialID = prefix: credential: "${prefix}-${credential}"; - toScopedUsers = listenerScope: users: pipe users [ - attrNames - (imap0 (index: user: nameValuePair user + toScopedUsers = listenerScope: users: lib.pipe users [ + lib.attrNames + (lib.imap0 (index: user: lib.nameValuePair user (users.${user} // { scope = userScope listenerScope index; }) )) - listToAttrs + lib.listToAttrs ]; - userCredentials = user: credentials: pipe credentials [ - (filter (credential: user.${credential} != null)) + userCredentials = user: credentials: lib.pipe credentials [ + (lib.filter (credential: user.${credential} != null)) (map (credential: "${credentialID user.scope credential}:${user.${credential}}")) ]; - usersCredentials = listenerScope: users: credentials: pipe users [ + usersCredentials = listenerScope: users: credentials: lib.pipe users [ (toScopedUsers listenerScope) - (mapAttrsToList (_: user: userCredentials user credentials)) - concatLists + (lib.mapAttrsToList (_: user: userCredentials user credentials)) + lib.concatLists ]; - systemdCredentials = listeners: listenerCredentials: pipe listeners [ - (imap0 (index: listener: listenerCredentials (listenerScope index) listener)) - concatLists + systemdCredentials = listeners: listenerCredentials: lib.pipe listeners [ + (lib.imap0 (index: listener: listenerCredentials (listenerScope index) listener)) + lib.concatLists ]; makePasswordFile = listenerScope: users: path: @@ -139,12 +136,12 @@ let makeLines = store: file: let scopedUsers = toScopedUsers listenerScope users; in - mapAttrsToList - (name: user: ''addLine ${escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'') - (filterAttrs (_: user: user.${store} != null) scopedUsers) - ++ mapAttrsToList - (name: user: ''addFile ${escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'') - (filterAttrs (_: user: user.${file} != null) scopedUsers); + lib.mapAttrsToList + (name: user: ''addLine ${lib.escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'') + (lib.filterAttrs (_: user: user.${store} != null) scopedUsers) + ++ lib.mapAttrsToList + (name: user: ''addFile ${lib.escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'') + (lib.filterAttrs (_: user: user.${file} != null) scopedUsers); plainLines = makeLines "password" "passwordFile"; hashedLines = makeLines "hashedPassword" "hashedPasswordFile"; in @@ -154,7 +151,7 @@ let set -eu - file=${escapeShellArg path} + file=${lib.escapeShellArg path} rm -f "$file" touch "$file" @@ -170,23 +167,23 @@ let echo "$1:$(cat "$2")" >> "$file" } '' - + concatStringsSep "\n" + + lib.concatStringsSep "\n" (plainLines - ++ optional (plainLines != []) '' + ++ lib.optional (plainLines != []) '' ${cfg.package}/bin/mosquitto_passwd -U "$file" '' ++ hashedLines)); - authPluginOptions = with types; submodule { + authPluginOptions = with lib.types; submodule { options = { - plugin = mkOption { + plugin = lib.mkOption { type = path; description = '' Plugin path to load, should be a `.so` file. ''; }; - denySpecialChars = mkOption { + denySpecialChars = lib.mkOption { type = bool; description = '' Automatically disallow all clients using `#` @@ -195,7 +192,7 @@ let default = true; }; - options = mkOption { + options = lib.mkOption { type = attrsOf optionType; description = '' Options for the auth plugin. Each key turns into a `auth_opt_*` @@ -207,7 +204,7 @@ let }; authAsserts = prefix: auth: - mapAttrsToList + lib.mapAttrsToList (n: _: { assertion = configKey.check n; message = "Invalid auth plugin key ${prefix}.${n}"; @@ -253,9 +250,9 @@ let use_username_as_clientid = 1; }; - listenerOptions = with types; submodule { + listenerOptions = with lib.types; submodule { options = { - port = mkOption { + port = lib.mkOption { type = port; description = '' Port to listen on. Must be set to 0 to listen on a unix domain socket. @@ -263,7 +260,7 @@ let default = 1883; }; - address = mkOption { + address = lib.mkOption { type = nullOr str; description = '' Address to listen on. Listen on `0.0.0.0`/`::` @@ -272,7 +269,7 @@ let default = null; }; - authPlugins = mkOption { + authPlugins = lib.mkOption { type = listOf authPluginOptions; description = '' Authentication plugin to attach to this listener. @@ -282,7 +279,7 @@ let default = []; }; - users = mkOption { + users = lib.mkOption { type = attrsOf userOptions; example = { john = { password = "123456"; acl = [ "readwrite john/#" ]; }; }; description = '' @@ -291,7 +288,7 @@ let default = {}; }; - omitPasswordAuth = mkOption { + omitPasswordAuth = lib.mkOption { type = bool; description = '' Omits password checking, allowing anyone to log in with any user name unless @@ -300,7 +297,7 @@ let default = false; }; - acl = mkOption { + acl = lib.mkOption { type = listOf str; description = '' Additional ACL items to prepend to the generated ACL file. @@ -309,7 +306,7 @@ let default = []; }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = attrsOf optionType; }; @@ -324,7 +321,7 @@ let listenerAsserts = prefix: listener: assertKeysValid "${prefix}.settings" freeformListenerKeys listener.settings ++ userAsserts prefix listener.users - ++ imap0 + ++ lib.imap0 (i: v: authAsserts "${prefix}.authPlugins.${toString i}" v) listener.authPlugins; @@ -333,9 +330,9 @@ let "listener ${toString listener.port} ${toString listener.address}" "acl_file /etc/mosquitto/acl-${toString idx}.conf" ] - ++ optional (! listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}" + ++ lib.optional (! listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}" ++ formatFreeform {} listener.settings - ++ concatMap formatAuthPlugin listener.authPlugins; + ++ lib.concatMap formatAuthPlugin listener.authPlugins; freeformBridgeKeys = { bridge_alpn = 1; @@ -373,19 +370,19 @@ let try_private = 1; }; - bridgeOptions = with types; submodule { + bridgeOptions = with lib.types; submodule { options = { - addresses = mkOption { + addresses = lib.mkOption { type = listOf (submodule { options = { - address = mkOption { + address = lib.mkOption { type = str; description = '' Address of the remote MQTT broker. ''; }; - port = mkOption { + port = lib.mkOption { type = port; description = '' Port of the remote MQTT broker. @@ -400,7 +397,7 @@ let ''; }; - topics = mkOption { + topics = lib.mkOption { type = listOf str; description = '' Topic patterns to be shared between the two brokers. @@ -411,7 +408,7 @@ let example = [ "# both 2 local/topic/ remote/topic/" ]; }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = attrsOf optionType; }; @@ -426,14 +423,14 @@ let bridgeAsserts = prefix: bridge: assertKeysValid "${prefix}.settings" freeformBridgeKeys bridge.settings ++ [ { - assertion = length bridge.addresses > 0; + assertion = lib.length bridge.addresses > 0; message = "Bridge ${prefix} needs remote broker addresses"; } ]; formatBridge = name: bridge: [ "connection ${name}" - "addresses ${concatMapStringsSep " " (a: "${a.address}:${toString a.port}") bridge.addresses}" + "addresses ${lib.concatMapStringsSep " " (a: "${a.address}:${toString a.port}") bridge.addresses}" ] ++ map (t: "topic ${t}") bridge.topics ++ formatFreeform {} bridge.settings; @@ -468,12 +465,12 @@ let websockets_log_level = 1; }; - globalOptions = with types; { - enable = mkEnableOption "the MQTT Mosquitto broker"; + globalOptions = with lib.types; { + enable = lib.mkEnableOption "the MQTT Mosquitto broker"; - package = mkPackageOption pkgs "mosquitto" { }; + package = lib.mkPackageOption pkgs "mosquitto" { }; - bridges = mkOption { + bridges = lib.mkOption { type = attrsOf bridgeOptions; default = {}; description = '' @@ -481,7 +478,7 @@ let ''; }; - listeners = mkOption { + listeners = lib.mkOption { type = listOf listenerOptions; default = []; description = '' @@ -489,7 +486,7 @@ let ''; }; - includeDirs = mkOption { + includeDirs = lib.mkOption { type = listOf path; description = '' Directories to be scanned for further config files to include. @@ -500,7 +497,7 @@ let default = []; }; - logDest = mkOption { + logDest = lib.mkOption { type = listOf (either path (enum [ "stdout" "stderr" "syslog" "topic" "dlt" ])); description = '' Destinations to send log messages to. @@ -508,7 +505,7 @@ let default = [ "stderr" ]; }; - logType = mkOption { + logType = lib.mkOption { type = listOf (enum [ "debug" "error" "warning" "notice" "information" "subscribe" "unsubscribe" "websockets" "none" "all" ]); description = '' @@ -517,7 +514,7 @@ let default = []; }; - persistence = mkOption { + persistence = lib.mkOption { type = bool; description = '' Enable persistent storage of subscriptions and messages. @@ -525,15 +522,15 @@ let default = true; }; - dataDir = mkOption { + dataDir = lib.mkOption { default = "/var/lib/mosquitto"; - type = types.path; + type = lib.types.path; description = '' The data directory. ''; }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = attrsOf optionType; }; @@ -545,10 +542,10 @@ let }; globalAsserts = prefix: cfg: - flatten [ + lib.flatten [ (assertKeysValid "${prefix}.settings" freeformGlobalKeys cfg.settings) - (imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners) - (mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges) + (lib.imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners) + (lib.mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges) ]; formatGlobal = cfg: @@ -561,12 +558,12 @@ let cfg.logDest ++ map (t: "log_type ${t}") cfg.logType ++ formatFreeform {} cfg.settings - ++ concatLists (imap0 formatListener cfg.listeners) - ++ concatLists (mapAttrsToList formatBridge cfg.bridges) + ++ lib.concatLists (lib.imap0 formatListener cfg.listeners) + ++ lib.concatLists (lib.mapAttrsToList formatBridge cfg.bridges) ++ map (d: "include_dir ${d}") cfg.includeDirs; configFile = pkgs.writeText "mosquitto.conf" - (concatStringsSep "\n" (formatGlobal cfg)); + (lib.concatStringsSep "\n" (formatGlobal cfg)); in @@ -578,7 +575,7 @@ in ###### Implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = globalAsserts "services.mosquitto" cfg; @@ -633,13 +630,13 @@ in ReadWritePaths = [ cfg.dataDir "/tmp" # mosquitto_passwd creates files in /tmp before moving them - ] ++ filter path.check cfg.logDest; + ] ++ lib.filter path.check cfg.logDest; ReadOnlyPaths = map (p: "${p}") (cfg.includeDirs - ++ filter + ++ lib.filter (v: v != null) - (flatten [ + (lib.flatten [ (map (l: [ (l.settings.psk_file or null) @@ -652,7 +649,7 @@ in (l.settings.keyfile or null) ]) cfg.listeners) - (mapAttrsToList + (lib.mapAttrsToList (_: b: [ (b.settings.bridge_cafile or null) (b.settings.bridge_capath or null) @@ -680,26 +677,26 @@ in UMask = "0077"; }; preStart = - concatStringsSep + lib.concatStringsSep "\n" - (imap0 + (lib.imap0 (idx: listener: makePasswordFile (listenerScope idx) listener.users "${cfg.dataDir}/passwd-${toString idx}") cfg.listeners); }; - environment.etc = listToAttrs ( - imap0 + environment.etc = lib.listToAttrs ( + lib.imap0 (idx: listener: { name = "mosquitto/acl-${toString idx}.conf"; value = { user = config.users.users.mosquitto.name; group = config.users.users.mosquitto.group; mode = "0400"; - text = (concatStringsSep + text = (lib.concatStringsSep "\n" - (flatten [ + (lib.flatten [ listener.acl - (mapAttrsToList + (lib.mapAttrsToList (n: u: [ "user ${n}" ] ++ map (t: "topic ${t}") u.acl) listener.users) ])); diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix index 41d8ab4058bc..c47a684571fe 100644 --- a/nixos/modules/services/networking/murmur.nix +++ b/nixos/modules/services/networking/murmur.nix @@ -349,6 +349,7 @@ in RestrictRealtime = true; SystemCallArchitectures = "native"; SystemCallFilter = "@system-service"; + UMask = 027; }; }; @@ -406,4 +407,6 @@ in } ''; }; + + meta.maintainers = with lib.maintainers; [ felixsinger ]; } diff --git a/nixos/modules/services/networking/nar-serve.nix b/nixos/modules/services/networking/nar-serve.nix index 5a5cefe86d29..ea5be25a4d26 100644 --- a/nixos/modules/services/networking/nar-serve.nix +++ b/nixos/modules/services/networking/nar-serve.nix @@ -1,18 +1,18 @@ { config, pkgs, lib, ... }: -with lib; let + inherit (lib) mkOption types; cfg = config.services.nar-serve; in { meta = { - maintainers = [ maintainers.rizary maintainers.zimbatm ]; + maintainers = with lib.maintainers; [ rizary zimbatm ]; }; options = { services.nar-serve = { - enable = mkEnableOption "serving NAR file contents via HTTP"; + enable = lib.mkEnableOption "serving NAR file contents via HTTP"; - package = mkPackageOption pkgs "nar-serve" { }; + package = lib.mkPackageOption pkgs "nar-serve" { }; port = mkOption { type = types.port; @@ -48,7 +48,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { systemd.services.nar-serve = { description = "NAR server"; after = [ "network.target" ]; diff --git a/nixos/modules/services/networking/netbird.nix b/nixos/modules/services/networking/netbird.nix index e68c39946fe3..d39c373dbc94 100644 --- a/nixos/modules/services/networking/netbird.nix +++ b/nixos/modules/services/networking/netbird.nix @@ -35,9 +35,7 @@ let cfg = config.services.netbird; in { - meta.maintainers = with maintainers; [ - misuzu - ]; + meta.maintainers = with maintainers; [ ]; meta.doc = ./netbird.md; options.services.netbird = { diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index fda8245ba97d..dedd53e345fe 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -514,6 +514,12 @@ in environment.etc = { "NetworkManager/NetworkManager.conf".source = configFile; + + # The networkmanager-l2tp plugin expects /etc/ipsec.secrets to include /etc/ipsec.d/ipsec.nm-l2tp.secrets; + # see https://github.com/NixOS/nixpkgs/issues/64965 + "ipsec.secrets".text = '' + include ipsec.d/ipsec.nm-l2tp.secrets + ''; } // builtins.listToAttrs (map (pkg: nameValuePair "NetworkManager/${pkg.networkManagerPlugin}" { diff --git a/nixos/modules/services/networking/nixops-dns.nix b/nixos/modules/services/networking/nixops-dns.nix index 5e33d872ea45..5d009d6d3084 100644 --- a/nixos/modules/services/networking/nixops-dns.nix +++ b/nixos/modules/services/networking/nixops-dns.nix @@ -68,10 +68,10 @@ in servers = [ "/${cfg.domain}/127.0.0.1#5300" ]; - extraConfig = '' - bind-interfaces - listen-address=127.0.0.1 - ''; + settings = { + bind-interfaces = true; + listen-address = "127.0.0.1"; + }; }; }; diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix index b17416c1e3d3..fe878ddbe05f 100644 --- a/nixos/modules/services/networking/nsd.nix +++ b/nixos/modules/services/networking/nsd.nix @@ -603,8 +603,8 @@ in reuseport = mkOption { type = types.bool; - default = pkgs.stdenv.isLinux; - defaultText = literalExpression "pkgs.stdenv.isLinux"; + default = pkgs.stdenv.hostPlatform.isLinux; + defaultText = literalExpression "pkgs.stdenv.hostPlatform.isLinux"; description = '' Whether to enable SO_REUSEPORT on all used sockets. This lets multiple processes bind to the same port. This speeds up operation especially diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix index a152b72143da..01baa58879da 100644 --- a/nixos/modules/services/networking/pleroma.nix +++ b/nixos/modules/services/networking/pleroma.nix @@ -1,7 +1,13 @@ -{ config, options, lib, pkgs, stdenv, ... }: +{ + config, + lib, + pkgs, + ... +}: let cfg = config.services.pleroma; -in { +in +{ options = { services.pleroma = with lib; { enable = mkEnableOption "pleroma"; @@ -48,7 +54,7 @@ in { Have a look to Pleroma section in the NixOS manual for more information. - ''; + ''; }; secretConfigFile = mkOption { @@ -73,7 +79,7 @@ in { group = cfg.group; isSystemUser = true; }; - groups."${cfg.group}" = {}; + groups."${cfg.group}" = { }; }; environment.systemPackages = [ cfg.package ]; @@ -90,57 +96,79 @@ in { import_config "${cfg.secretConfigFile}" ''; - systemd.services.pleroma = { - description = "Pleroma social network"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" "postgresql.service" ]; - wantedBy = [ "multi-user.target" ]; - restartTriggers = [ config.environment.etc."/pleroma/config.exs".source ]; - environment.RELEASE_COOKIE = "/var/lib/pleroma/.cookie"; - serviceConfig = { - User = cfg.user; - Group = cfg.group; - Type = "exec"; - WorkingDirectory = "~"; - StateDirectory = "pleroma pleroma/static pleroma/uploads"; - StateDirectoryMode = "700"; + systemd.services = + let + commonSystemdServiceConfig = { + User = cfg.user; + Group = cfg.group; + WorkingDirectory = "~"; + StateDirectory = "pleroma pleroma/static pleroma/uploads"; + StateDirectoryMode = "700"; + # Systemd sandboxing directives. + # Taken from the upstream contrib systemd service at + # pleroma/installation/pleroma.service + PrivateTmp = true; + ProtectHome = true; + ProtectSystem = "full"; + PrivateDevices = false; + NoNewPrivileges = true; + CapabilityBoundingSet = "~CAP_SYS_ADMIN"; + }; - # Checking the conf file is there then running the database - # migration before each service start, just in case there are - # some pending ones. - # - # It's sub-optimal as we'll always run this, even if pleroma - # has not been updated. But the no-op process is pretty fast. - # Better be safe than sorry migration-wise. - ExecStartPre = - let preScript = pkgs.writers.writeBashBin "pleromaStartPre" '' - if [ ! -f /var/lib/pleroma/.cookie ] - then - echo "Creating cookie file" - dd if=/dev/urandom bs=1 count=16 | hexdump -e '16/1 "%02x"' > /var/lib/pleroma/.cookie - fi - ${cfg.package}/bin/pleroma_ctl migrate - ''; - in "${preScript}/bin/pleromaStartPre"; + in + { + pleroma-migrations = { + description = "Pleroma social network migrations"; + wants = [ "network-online.target" ]; + after = [ + "network-online.target" + "postgresql.service" + ]; + wantedBy = [ "pleroma.service" ]; + environment.RELEASE_COOKIE = "/var/lib/pleroma/.cookie"; + serviceConfig = commonSystemdServiceConfig // { + Type = "oneshot"; + # Checking the conf file is there then running the database + # migration before each service start, just in case there are + # some pending ones. + # + # It's sub-optimal as we'll always run this, even if pleroma + # has not been updated. But the no-op process is pretty fast. + # Better be safe than sorry migration-wise. + ExecStart = + let + preScript = pkgs.writers.writeBashBin "pleroma-migrations" '' + if [ ! -f /var/lib/pleroma/.cookie ] + then + echo "Creating cookie file" + dd if=/dev/urandom bs=1 count=16 | hexdump -e '16/1 "%02x"' > /var/lib/pleroma/.cookie + fi + ${cfg.package}/bin/pleroma_ctl migrate + ''; + in + "${preScript}/bin/pleroma-migrations"; + }; + # disksup requires bash + path = [ pkgs.bash ]; + }; - ExecStart = "${cfg.package}/bin/pleroma start"; - ExecStop = "${cfg.package}/bin/pleroma stop"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - - # Systemd sandboxing directives. - # Taken from the upstream contrib systemd service at - # pleroma/installation/pleroma.service - PrivateTmp = true; - ProtectHome = true; - ProtectSystem = "full"; - PrivateDevices = false; - NoNewPrivileges = true; - CapabilityBoundingSet = "~CAP_SYS_ADMIN"; + pleroma = { + description = "Pleroma social network"; + wants = [ "pleroma-migrations.service" ]; + after = [ "pleroma-migrations.service" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ config.environment.etc."/pleroma/config.exs".source ]; + environment.RELEASE_COOKIE = "/var/lib/pleroma/.cookie"; + serviceConfig = commonSystemdServiceConfig // { + Type = "exec"; + ExecStart = "${cfg.package}/bin/pleroma start"; + ExecStop = "${cfg.package}/bin/pleroma stop"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + # disksup requires bash + path = [ pkgs.bash ]; + }; }; - # disksup requires bash - path = [ pkgs.bash ]; - }; - }; meta.maintainers = with lib.maintainers; [ picnoir ]; meta.doc = ./pleroma.md; diff --git a/nixos/modules/services/networking/quorum.nix b/nixos/modules/services/networking/quorum.nix index bddcd18c7fbe..8f6df0881b23 100644 --- a/nixos/modules/services/networking/quorum.nix +++ b/nixos/modules/services/networking/quorum.nix @@ -201,11 +201,11 @@ in { --syncmode ${cfg.syncmode} \ ${optionalString (cfg.permissioned) "--permissioned"} \ - --mine --minerthreads 1 \ + --mine --miner.threads 1 \ ${optionalString (cfg.rpc.enable) "--rpc --rpcaddr ${cfg.rpc.address} --rpcport ${toString cfg.rpc.port} --rpcapi ${cfg.rpc.api}"} \ ${optionalString (cfg.ws.enable) - "--ws --wsaddr ${cfg.ws.address} --wsport ${toString cfg.ws.port} --wsapi ${cfg.ws.api} --wsorigins ${cfg.ws.origins}"} \ + "--ws --ws.addr ${cfg.ws.address} --ws.port ${toString cfg.ws.port} --ws.api ${cfg.ws.api} --ws.origins ${cfg.ws.origins}"} \ --emitcheckpoints \ --datadir ${dataDir} \ --port ${toString cfg.port}''; diff --git a/nixos/modules/services/networking/resilio.nix b/nixos/modules/services/networking/resilio.nix index 02773d78b132..f9c682f168b7 100644 --- a/nixos/modules/services/networking/resilio.nix +++ b/nixos/modules/services/networking/resilio.nix @@ -5,8 +5,6 @@ with lib; let cfg = config.services.resilio; - resilioSync = pkgs.resilio-sync; - sharedFoldersRecord = map (entry: { dir = entry.directory; @@ -83,6 +81,8 @@ in ''; }; + package = mkPackageOption pkgs "resilio-sync" { }; + deviceName = mkOption { type = types.str; example = "Voltron"; @@ -285,7 +285,7 @@ in RuntimeDirectory = "rslsync"; ExecStartPre = "${createConfig}/bin/create-resilio-config"; ExecStart = '' - ${resilioSync}/bin/rslsync --nodaemon --config ${runConfigPath} + ${lib.getExe cfg.package} --nodaemon --config ${runConfigPath} ''; }; }; diff --git a/nixos/modules/services/networking/scion/scion-ip-gateway.nix b/nixos/modules/services/networking/scion/scion-ip-gateway.nix new file mode 100644 index 000000000000..1801828c8ad0 --- /dev/null +++ b/nixos/modules/services/networking/scion/scion-ip-gateway.nix @@ -0,0 +1,92 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + globalCfg = config.services.scion; + cfg = config.services.scion.scion-ip-gateway; + toml = pkgs.formats.toml { }; + json = pkgs.formats.json { }; + connectionDir = if globalCfg.stateless then "/run" else "/var/lib"; + defaultConfig = { + tunnel = { }; + gateway = { + traffic_policy_file = "${trafficConfigFile}"; + }; + }; + defaultTrafficConfig = { + ASes = { }; + ConfigVersion = 9001; + }; + configFile = toml.generate "scion-ip-gateway.toml" (recursiveUpdate defaultConfig cfg.config); + trafficConfigFile = json.generate "scion-ip-gateway-traffic.json" ( + recursiveUpdate defaultTrafficConfig cfg.trafficConfig + ); +in +{ + options.services.scion.scion-ip-gateway = { + enable = mkEnableOption "the scion-ip-gateway service"; + config = mkOption { + default = { }; + type = toml.type; + example = literalExpression '' + { + tunnel = { + src_ipv4 = "172.16.100.1"; + }; + } + ''; + description = '' + scion-ip-gateway daemon configuration + ''; + }; + trafficConfig = mkOption { + default = { }; + type = json.type; + example = literalExpression '' + { + ASes = { + "2-ffaa:0:b" = { + Nets = [ + "172.16.1.0/24" + ]; + }; + }; + ConfigVersion = 9001; + } + ''; + description = '' + scion-ip-gateway traffic configuration + ''; + }; + }; + config = mkIf cfg.enable { + systemd.services.scion-ip-gateway = { + description = "SCION IP Gateway Service"; + after = [ + "network-online.target" + "scion-dispatcher.service" + ]; + wants = [ + "network-online.target" + "scion-dispatcher.service" + ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Group = if (config.services.scion.scion-dispatcher.enable == true) then "scion" else null; + ExecStart = "${globalCfg.package}/bin/scion-ip-gateway --config ${configFile}"; + DynamicUser = true; + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + Restart = "on-failure"; + KillMode = "control-group"; + RemainAfterExit = false; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/scion/scion.nix b/nixos/modules/services/networking/scion/scion.nix index efab97f7cd8d..0b26f24e7ed0 100644 --- a/nixos/modules/services/networking/scion/scion.nix +++ b/nixos/modules/services/networking/scion/scion.nix @@ -42,6 +42,7 @@ in scion-daemon.enable = true; scion-router.enable = true; scion-control.enable = true; + scion-ip-gateway.enable = true; }; assertions = [ { assertion = cfg.bypassBootstrapWarning == true; diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix index 486bc145cd5d..356bcfe04419 100644 --- a/nixos/modules/services/networking/seafile.nix +++ b/nixos/modules/services/networking/seafile.nix @@ -1,19 +1,42 @@ -{ config, lib, pkgs, ... }: -with lib; +{ + config, + lib, + pkgs, + ... +}: let cfg = config.services.seafile; settingsFormat = pkgs.formats.ini { }; - ccnetConf = settingsFormat.generate "ccnet.conf" cfg.ccnetSettings; + ccnetConf = settingsFormat.generate "ccnet.conf" ( + lib.attrsets.recursiveUpdate { + Database = { + ENGINE = "mysql"; + UNIX_SOCKET = "/var/run/mysqld/mysqld.sock"; + DB = "ccnet_db"; + CONNECTION_CHARSET = "utf8"; + }; + } cfg.ccnetSettings + ); - seafileConf = settingsFormat.generate "seafile.conf" cfg.seafileSettings; + seafileConf = settingsFormat.generate "seafile.conf" ( + lib.attrsets.recursiveUpdate { + database = { + type = "mysql"; + unix_socket = "/var/run/mysqld/mysqld.sock"; + db_name = "seafile_db"; + connection_charset = "utf8"; + }; + } cfg.seafileSettings + ); seahubSettings = pkgs.writeText "seahub_settings.py" '' FILE_SERVER_ROOT = '${cfg.ccnetSettings.General.SERVICE_URL}/seafhttp' DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': '${seahubDir}/seahub.db', + 'ENGINE': 'django.db.backends.mysql', + 'NAME' : 'seahub_db', + 'HOST' : '/var/run/mysqld/mysqld.sock', } } MEDIA_ROOT = '${seahubDir}/media/' @@ -21,23 +44,25 @@ let SERVICE_URL = '${cfg.ccnetSettings.General.SERVICE_URL}' + CSRF_TRUSTED_ORIGINS = ["${cfg.ccnetSettings.General.SERVICE_URL}"] + with open('${seafRoot}/.seahubSecret') as f: SECRET_KEY = f.readline().rstrip() ${cfg.seahubExtraConf} ''; - seafRoot = "/var/lib/seafile"; # hardcode it due to dynamicuser + seafRoot = "/var/lib/seafile"; ccnetDir = "${seafRoot}/ccnet"; - dataDir = "${seafRoot}/data"; seahubDir = "${seafRoot}/seahub"; + defaultUser = "seafile"; in { ###### Interface - options.services.seafile = { + options.services.seafile = with lib; { enable = mkEnableOption "Seafile server"; ccnetSettings = mkOption { @@ -47,7 +72,7 @@ in options = { General = { SERVICE_URL = mkOption { - type = types.str; + type = types.singleLineStr; example = "https://www.example.com"; description = '' Seahub public URL. @@ -78,11 +103,17 @@ in ''; }; host = mkOption { - type = types.str; - default = "127.0.0.1"; - example = "0.0.0.0"; + type = types.singleLineStr; + default = "ipv4:127.0.0.1"; + example = "unix:/run/seafile/server.sock"; description = '' - The binding address used by seafile fileserver. + The bind address used by seafile fileserver. + + The addr can be defined as one of the following: + - ipv6: for binding to an IPv6 address. + - unix: for binding to a unix named socket + - ipv4: for binding to an ipv4 address + Otherwise the addr is assumed to be ipv4. ''; }; }; @@ -96,6 +127,19 @@ in ''; }; + seahubAddress = mkOption { + type = types.singleLineStr; + default = "unix:/run/seahub/gunicorn.sock"; + example = "[::1]:8083"; + description = '' + Which address to bind the seahub server to, of the form: + - HOST + - HOST:PORT + - unix:PATH. + IPv6 HOSTs must be wrapped in brackets. + ''; + }; + workers = mkOption { type = types.int; default = 4; @@ -107,7 +151,7 @@ in adminEmail = mkOption { example = "john@example.com"; - type = types.str; + type = types.singleLineStr; description = '' Seafile Seahub Admin Account Email. ''; @@ -115,17 +159,79 @@ in initialAdminPassword = mkOption { example = "someStrongPass"; - type = types.str; + type = types.singleLineStr; description = '' Seafile Seahub Admin Account initial password. - Should be change via Seahub web front-end. + Should be changed via Seahub web front-end. ''; }; - seafilePackage = mkPackageOption pkgs "seafile-server" { }; + seahubPackage = mkPackageOption pkgs "seahub" { }; + + user = mkOption { + type = types.singleLineStr; + default = defaultUser; + description = "User account under which seafile runs."; + }; + + group = mkOption { + type = types.singleLineStr; + default = defaultUser; + description = "Group under which seafile runs."; + }; + + dataDir = mkOption { + type = types.path; + default = "${seafRoot}/data"; + description = "Path in which to store user data"; + }; + + gc = { + enable = mkEnableOption "automatic garbage collection on stored data blocks"; + + dates = mkOption { + type = types.listOf types.singleLineStr; + default = [ "Sun 03:00:00" ]; + description = '' + When to run garbage collection on stored data blocks. + The time format is described in {manpage}`systemd.time(7)`. + ''; + }; + + randomizedDelaySec = mkOption { + default = "0"; + type = types.singleLineStr; + example = "45min"; + description = '' + Add a randomized delay before each garbage collection. + 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. + ''; + }; + }; seahubExtraConf = mkOption { default = ""; + example = '' + CSRF_TRUSTED_ORIGINS = ["https://example.com"] + ''; type = types.lines; description = '' Extra config to append to `seahub_settings.py` file. @@ -137,12 +243,40 @@ in ###### Implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { + services.mysql = { + enable = true; + package = lib.mkDefault pkgs.mariadb; + ensureDatabases = [ + "ccnet_db" + "seafile_db" + "seahub_db" + ]; + ensureUsers = [ + { + name = cfg.user; + ensurePermissions = { + "ccnet_db.*" = "ALL PRIVILEGES"; + "seafile_db.*" = "ALL PRIVILEGES"; + "seahub_db.*" = "ALL PRIVILEGES"; + }; + } + ]; + }; environment.etc."seafile/ccnet.conf".source = ccnetConf; environment.etc."seafile/seafile.conf".source = seafileConf; environment.etc."seafile/seahub_settings.py".source = seahubSettings; + users.users = lib.optionalAttrs (cfg.user == defaultUser) { + "${defaultUser}" = { + group = cfg.group; + isSystemUser = true; + }; + }; + + users.groups = lib.optionalAttrs (cfg.group == defaultUser) { "${defaultUser}" = { }; }; + systemd.targets.seafile = { wantedBy = [ "multi-user.target" ]; description = "Seafile components"; @@ -150,10 +284,12 @@ in systemd.services = let - securityOptions = { + serviceOptions = { ProtectHome = true; PrivateUsers = true; PrivateDevices = true; + PrivateTmp = true; + ProtectSystem = "strict"; ProtectClock = true; ProtectHostname = true; ProtectProc = "invisible"; @@ -162,36 +298,49 @@ in ProtectKernelLogs = true; ProtectControlGroups = true; RestrictNamespaces = true; + RemoveIPC = true; LockPersonality = true; RestrictRealtime = true; RestrictSUIDSGID = true; + NoNewPrivileges = true; MemoryDenyWriteExecute = true; SystemCallArchitectures = "native"; - RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ]; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + ]; + + User = cfg.user; + Group = cfg.group; + StateDirectory = "seafile"; + RuntimeDirectory = "seafile"; + LogsDirectory = "seafile"; + ConfigurationDirectory = "seafile"; + ReadWritePaths = lib.lists.optional (cfg.dataDir != "${seafRoot}/data") cfg.dataDir; }; in { seaf-server = { description = "Seafile server"; partOf = [ "seafile.target" ]; - after = [ "network.target" ]; + unitConfig.RequiresMountsFor = lib.lists.optional (cfg.dataDir != "${seafRoot}/data") cfg.dataDir; + requires = [ "mysql.service" ]; + after = [ + "network.target" + "mysql.service" + ]; wantedBy = [ "seafile.target" ]; - restartTriggers = [ ccnetConf seafileConf ]; - path = [ pkgs.sqlite ]; - serviceConfig = securityOptions // { - User = "seafile"; - Group = "seafile"; - DynamicUser = true; - StateDirectory = "seafile"; - RuntimeDirectory = "seafile"; - LogsDirectory = "seafile"; - ConfigurationDirectory = "seafile"; + restartTriggers = [ + ccnetConf + seafileConf + ]; + serviceConfig = serviceOptions // { ExecStart = '' - ${cfg.seafilePackage}/bin/seaf-server \ + ${lib.getExe cfg.seahubPackage.seafile-server} \ --foreground \ -F /etc/seafile \ -c ${ccnetDir} \ - -d ${dataDir} \ + -d ${cfg.dataDir} \ -l /var/log/seafile/server.log \ -P /run/seafile/server.pid \ -p /run/seafile @@ -199,100 +348,201 @@ in }; preStart = '' if [ ! -f "${seafRoot}/server-setup" ]; then - mkdir -p ${dataDir}/library-template - mkdir -p ${ccnetDir}/{GroupMgr,misc,OrgMgr,PeerMgr} - sqlite3 ${ccnetDir}/GroupMgr/groupmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/groupmgr.sql" - sqlite3 ${ccnetDir}/misc/config.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/config.sql" - sqlite3 ${ccnetDir}/OrgMgr/orgmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/org.sql" - sqlite3 ${ccnetDir}/PeerMgr/usermgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/user.sql" - sqlite3 ${dataDir}/seafile.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/seafile.sql" - echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup + mkdir -p ${cfg.dataDir}/library-template + # Load schema on first install + ${pkgs.mariadb.client}/bin/mysql --database=ccnet_db < ${cfg.seahubPackage.seafile-server}/share/seafile/sql/mysql/ccnet.sql + ${pkgs.mariadb.client}/bin/mysql --database=seafile_db < ${cfg.seahubPackage.seafile-server}/share/seafile/sql/mysql/seafile.sql + echo "${cfg.seahubPackage.seafile-server.version}-mysql" > "${seafRoot}"/server-setup + echo Loaded MySQL schemas for first install fi # checking for upgrades and handling them installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1) installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2) - pkgMajor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f1) - pkgMinor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f2) + pkgMajor=$(echo "${cfg.seahubPackage.seafile-server.version}" | cut -d"." -f1) + pkgMinor=$(echo "${cfg.seahubPackage.seafile-server.version}" | cut -d"." -f2) if [[ $installedMajor == $pkgMajor && $installedMinor == $pkgMinor ]]; then : - elif [[ $installedMajor == 8 && $installedMinor == 0 && $pkgMajor == 9 && $pkgMinor == 0 ]]; then - # Upgrade from 8.0 to 9.0 - sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/9.0.0/sqlite3/seafile.sql" - echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup - elif [[ $installedMajor == 9 && $installedMinor == 0 && $pkgMajor == 10 && $pkgMinor == 0 ]]; then - # Upgrade from 9.0 to 10.0 - sqlite3 ${dataDir}/seafile.db ".read ${pkgs.seahub}/scripts/upgrade/sql/10.0.0/sqlite3/seafile.sql" - echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup + elif [[ $installedMajor == 10 && $installedMinor == 0 && $pkgMajor == 11 && $pkgMinor == 0 ]]; then + # Upgrade from 10.0 to 11.0: migrate to mysql + echo Migrating from version 10 to 11 + + # From https://github.com/haiwen/seahub/blob/e12f941bfef7191795d8c72a7d339c01062964b2/scripts/sqlite2mysql.sh + + echo Migrating ccnet database to MySQL + ${lib.getExe pkgs.sqlite} ${ccnetDir}/PeerMgr/usermgr.db ".dump" | \ + ${lib.getExe cfg.seahubPackage.python3} ${cfg.seahubPackage}/scripts/sqlite2mysql.py > ${ccnetDir}/ccnet.sql + ${lib.getExe pkgs.sqlite} ${ccnetDir}/GroupMgr/groupmgr.db ".dump" | \ + ${lib.getExe cfg.seahubPackage.python3} ${cfg.seahubPackage}/scripts/sqlite2mysql.py >> ${ccnetDir}/ccnet.sql + sed 's/ctime INTEGER/ctime BIGINT/g' -i ${ccnetDir}/ccnet.sql + sed 's/email TEXT, role TEXT/email VARCHAR(255), role TEXT/g' -i ${ccnetDir}/ccnet.sql + ${pkgs.mariadb.client}/bin/mysql --database=ccnet_db < ${ccnetDir}/ccnet.sql + + echo Migrating seafile database to MySQL + ${lib.getExe pkgs.sqlite} ${cfg.dataDir}/seafile.db ".dump" | \ + ${lib.getExe cfg.seahubPackage.python3} ${cfg.seahubPackage}/scripts/sqlite2mysql.py > ${cfg.dataDir}/seafile.sql + sed 's/owner_id TEXT/owner_id VARCHAR(255)/g' -i ${cfg.dataDir}/seafile.sql + sed 's/user_name TEXT/user_name VARCHAR(255)/g' -i ${cfg.dataDir}/seafile.sql + ${pkgs.mariadb.client}/bin/mysql --database=seafile_db < ${cfg.dataDir}/seafile.sql + + echo Migrating seahub database to MySQL + echo 'SET FOREIGN_KEY_CHECKS=0;' > ${seahubDir}/seahub.sql + ${lib.getExe pkgs.sqlite} ${seahubDir}/seahub.db ".dump" | \ + ${lib.getExe cfg.seahubPackage.python3} ${cfg.seahubPackage}/scripts/sqlite2mysql.py >> ${seahubDir}/seahub.sql + sed 's/`permission` , `reporter` text NOT NULL/`permission` longtext NOT NULL/g' -i ${seahubDir}/seahub.sql + sed 's/varchar(256) NOT NULL UNIQUE/varchar(255) NOT NULL UNIQUE/g' -i ${seahubDir}/seahub.sql + sed 's/, UNIQUE (`user_email`, `contact_email`)//g' -i ${seahubDir}/seahub.sql + sed '/INSERT INTO `base_dirfileslastmodifiedinfo`/d' -i ${seahubDir}/seahub.sql + sed '/INSERT INTO `notifications_usernotification`/d' -i ${seahubDir}/seahub.sql + sed 's/DEFERRABLE INITIALLY DEFERRED//g' -i ${seahubDir}/seahub.sql + ${pkgs.mariadb.client}/bin/mysql --database=seahub_db < ${seahubDir}/seahub.sql + + echo "${cfg.seahubPackage.seafile-server.version}-mysql" > "${seafRoot}"/server-setup + echo Migration complete else - echo "Unsupported upgrade" >&2 + echo "Unsupported upgrade: $installedMajor.$installedMinor to $pkgMajor.$pkgMinor" >&2 exit 1 fi ''; + + # Fix unix socket permissions + postStart = ( + lib.strings.optionalString (lib.strings.hasPrefix "unix:" cfg.seafileSettings.fileserver.host) '' + while [[ ! -S "${lib.strings.removePrefix "unix:" cfg.seafileSettings.fileserver.host}" ]]; do + sleep 1 + done + chmod 666 "${lib.strings.removePrefix "unix:" cfg.seafileSettings.fileserver.host}" + '' + ); }; seahub = { description = "Seafile Server Web Frontend"; wantedBy = [ "seafile.target" ]; partOf = [ "seafile.target" ]; - after = [ "network.target" "seaf-server.service" ]; - requires = [ "seaf-server.service" ]; + unitConfig.RequiresMountsFor = lib.lists.optional (cfg.dataDir != "${seafRoot}/data") cfg.dataDir; + requires = [ + "mysql.service" + "seaf-server.service" + ]; + after = [ + "network.target" + "mysql.service" + "seaf-server.service" + ]; restartTriggers = [ seahubSettings ]; environment = { - PYTHONPATH = "${pkgs.seahub.pythonPath}:${pkgs.seahub}/thirdpart:${pkgs.seahub}"; + PYTHONPATH = "${cfg.seahubPackage.pythonPath}:${cfg.seahubPackage}/thirdpart:${cfg.seahubPackage}"; DJANGO_SETTINGS_MODULE = "seahub.settings"; CCNET_CONF_DIR = ccnetDir; - SEAFILE_CONF_DIR = dataDir; + SEAFILE_CONF_DIR = cfg.dataDir; SEAFILE_CENTRAL_CONF_DIR = "/etc/seafile"; SEAFILE_RPC_PIPE_PATH = "/run/seafile"; SEAHUB_LOG_DIR = "/var/log/seafile"; }; - serviceConfig = securityOptions // { - User = "seafile"; - Group = "seafile"; - DynamicUser = true; + serviceConfig = serviceOptions // { RuntimeDirectory = "seahub"; - StateDirectory = "seafile"; - LogsDirectory = "seafile"; - ConfigurationDirectory = "seafile"; ExecStart = '' - ${pkgs.seahub.python.pkgs.gunicorn}/bin/gunicorn seahub.wsgi:application \ + ${lib.getExe cfg.seahubPackage.python3.pkgs.gunicorn} seahub.wsgi:application \ --name seahub \ --workers ${toString cfg.workers} \ --log-level=info \ --preload \ --timeout=1200 \ --limit-request-line=8190 \ - --bind unix:/run/seahub/gunicorn.sock + --bind ${cfg.seahubAddress} ''; }; preStart = '' mkdir -p ${seahubDir}/media # Link all media except avatars - for m in `find ${pkgs.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do + for m in `find ${cfg.seahubPackage}/media/ -maxdepth 1 -not -name "avatars"`; do ln -sf $m ${seahubDir}/media/ done if [ ! -e "${seafRoot}/.seahubSecret" ]; then - ${pkgs.seahub.python}/bin/python ${pkgs.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret - chmod 400 ${seafRoot}/.seahubSecret + ( + umask 377 && + ${lib.getExe cfg.seahubPackage.python3} ${cfg.seahubPackage}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret + ) fi if [ ! -f "${seafRoot}/seahub-setup" ]; then # avatars directory should be writable - install -D -t ${seahubDir}/media/avatars/ ${pkgs.seahub}/media/avatars/default.png - install -D -t ${seahubDir}/media/avatars/groups ${pkgs.seahub}/media/avatars/groups/default.png + install -D -t ${seahubDir}/media/avatars/ ${cfg.seahubPackage}/media/avatars/default.png + install -D -t ${seahubDir}/media/avatars/groups ${cfg.seahubPackage}/media/avatars/groups/default.png # init database - ${pkgs.seahub}/manage.py migrate + ${cfg.seahubPackage}/manage.py migrate # create admin account - ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.seahub}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."' - echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup" + ${lib.getExe pkgs.expect} -c 'spawn ${cfg.seahubPackage}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."' + echo "${cfg.seahubPackage.version}-mysql" > "${seafRoot}/seahub-setup" fi if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.seahub.version}" ]; then - # update database - ${pkgs.seahub}/manage.py migrate - echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup" + # run django migrations + ${cfg.seahubPackage}/manage.py migrate + echo "${cfg.seahubPackage.version}-mysql" > "${seafRoot}/seahub-setup" fi ''; }; + + seaf-gc = { + description = "Seafile storage garbage collection"; + conflicts = [ + "seaf-server.service" + "seahub.service" + ]; + after = [ + "seaf-server.service" + "seahub.service" + ]; + unitConfig.RequiresMountsFor = lib.lists.optional (cfg.dataDir != "${seafRoot}/data") cfg.dataDir; + onSuccess = [ + "seaf-server.service" + "seahub.service" + ]; + onFailure = [ + "seaf-server.service" + "seahub.service" + ]; + startAt = lib.lists.optionals cfg.gc.enable cfg.gc.dates; + serviceConfig = serviceOptions // { + Type = "oneshot"; + }; + script = '' + if [ ! -f "${seafRoot}/server-setup" ]; then + echo "Server not setup yet, GC not needed" >&2 + exit + fi + + # checking for pending upgrades + installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1) + installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2) + pkgMajor=$(echo "${cfg.seahubPackage.seafile-server.version}" | cut -d"." -f1) + pkgMinor=$(echo "${cfg.seahubPackage.seafile-server.version}" | cut -d"." -f2) + + if [[ $installedMajor != $pkgMajor || $installedMinor != $pkgMinor ]]; then + echo "Server not upgraded yet" >&2 + exit + fi + + # Clean up user-deleted blocks and libraries + ${cfg.seahubPackage.seafile-server}/bin/seafserv-gc \ + -F /etc/seafile \ + -c ${ccnetDir} \ + -d ${cfg.dataDir} \ + --rm-fs + ''; + }; }; + + systemd.timers.seaf-gc = lib.mkIf cfg.gc.enable { + timerConfig = { + randomizedDelaySec = cfg.gc.randomizedDelaySec; + Persistent = cfg.gc.persistent; + }; + }; }; + + meta.maintainers = with lib.maintainers; [ + greizgh + schmittlauch + ]; } diff --git a/nixos/modules/services/networking/shairport-sync.nix b/nixos/modules/services/networking/shairport-sync.nix index eb61663e4d92..df7e143bb41f 100644 --- a/nixos/modules/services/networking/shairport-sync.nix +++ b/nixos/modules/services/networking/shairport-sync.nix @@ -82,7 +82,7 @@ in createHome = true; home = "/var/lib/shairport-sync"; group = cfg.group; - extraGroups = [ "audio" ] ++ optional config.hardware.pulseaudio.enable "pulse"; + extraGroups = [ "audio" ] ++ optional (config.hardware.pulseaudio.enable || config.services.pipewire.pulse.enable) "pulse"; }; groups.${cfg.group} = {}; }; diff --git a/nixos/modules/services/networking/shorewall.nix b/nixos/modules/services/networking/shorewall.nix index 05087aaa8b3b..8d05543e9051 100644 --- a/nixos/modules/services/networking/shorewall.nix +++ b/nixos/modules/services/networking/shorewall.nix @@ -58,7 +58,7 @@ in { install -D -d -m 750 /var/lib/shorewall install -D -d -m 755 /var/lock/subsys touch /var/log/shorewall.log - chown 750 /var/log/shorewall.log + chmod 750 /var/log/shorewall.log ''; }; environment = { diff --git a/nixos/modules/services/networking/shorewall6.nix b/nixos/modules/services/networking/shorewall6.nix index 1eab3284d15f..3088e59fa9eb 100644 --- a/nixos/modules/services/networking/shorewall6.nix +++ b/nixos/modules/services/networking/shorewall6.nix @@ -58,7 +58,7 @@ in { install -D -d -m 750 /var/lib/shorewall6 install -D -d -m 755 /var/lock/subsys touch /var/log/shorewall6.log - chown 750 /var/log/shorewall6.log + chmod 750 /var/log/shorewall6.log ''; }; environment = { diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix index 2e572a3d071a..d9c314f5ec64 100644 --- a/nixos/modules/services/networking/smokeping.nix +++ b/nixos/modules/services/networking/smokeping.nix @@ -313,11 +313,16 @@ in group = cfg.user; description = "smokeping daemon user"; home = smokepingHome; - createHome = true; - # When `cfg.webService` is enabled, `nginx` requires read permissions on the home directory. - homeMode = "711"; }; + + users.users.${config.services.nginx.user} = mkIf cfg.webService { + extraGroups = [ + cfg.user ## user == group in this module + ]; + }; + users.groups.${cfg.user} = { }; + systemd.services.smokeping = { reloadTriggers = [ configPath ]; requiredBy = [ "multi-user.target" ]; @@ -327,15 +332,23 @@ in ExecStart = "${cfg.package}/bin/smokeping --config=/etc/smokeping.conf --nodaemon"; }; preStart = '' - mkdir -m 0755 -p ${smokepingHome}/cache ${smokepingHome}/data - ln -snf ${cfg.package}/htdocs/css ${smokepingHome}/css - ln -snf ${cfg.package}/htdocs/js ${smokepingHome}/js - ln -snf ${cgiHome} ${smokepingHome}/smokeping.fcgi ${cfg.package}/bin/smokeping --check --config=${configPath} ${cfg.package}/bin/smokeping --static --config=${configPath} ''; }; + systemd.tmpfiles.rules = [ + # create cache and data directories + "d ${smokepingHome}/cache 0750 ${cfg.user} ${cfg.user}" + "d ${smokepingHome}/data 0750 ${cfg.user} ${cfg.user}" + # create symlings + "L+ ${smokepingHome}/css - - - - ${cfg.package}/htdocs/css" + "L+ ${smokepingHome}/js - - - - ${cfg.package}/htdocs/js" + "L+ ${smokepingHome}/smokeping.fcgi - - - - ${cgiHome}" + # recursively adjust access mode and ownership (in case config change) + "Z ${smokepingHome} 0750 ${cfg.user} ${cfg.user}" + ]; + # use nginx to serve the smokeping web service services.fcgiwrap.instances.smokeping = mkIf cfg.webService { process.user = cfg.user; @@ -367,4 +380,3 @@ in nh2 ]; } - diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 1e4e34a4f167..26ca39f73d39 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -1,7 +1,4 @@ { config, lib, pkgs, ... }: - -with lib; - let # The splicing information needed for nativeBuildInputs isn't available @@ -17,8 +14,8 @@ let let # reports boolean as yes / no mkValueString = with lib; v: - if isInt v then toString v - else if isString v then v + if lib.isInt v then toString v + else if lib.isString v then v else if true == v then "yes" else if false == v then "no" else throw "unsupported type ${builtins.typeOf v}: ${(lib.generators.toPretty {}) v}"; @@ -37,10 +34,10 @@ let in { inherit (base) type; generate = name: value: - let transformedValue = mapAttrs (key: val: - if isList val then - if elem key commaSeparated then concatStringsSep "," val - else if elem key spaceSeparated then concatStringsSep " " val + let transformedValue = lib.mapAttrs (key: val: + if lib.isList val then + if lib.elem key commaSeparated then lib.concatStringsSep "," val + else if lib.elem key spaceSeparated then lib.concatStringsSep " " val else throw "list value for unknown key ${key}: ${(lib.generators.toPretty {}) val}" else val @@ -49,7 +46,7 @@ let base.generate name transformedValue; }; - configFile = settingsFormat.generate "sshd.conf-settings" (filterAttrs (n: v: v != null) cfg.settings); + configFile = settingsFormat.generate "sshd.conf-settings" (lib.filterAttrs (n: v: v != null) cfg.settings); sshconf = pkgs.runCommand "sshd.conf-final" { } '' cat ${configFile} - >$out < ''; }; - Macs = mkOption { - type = types.nullOr (types.listOf types.str); + Macs = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = [ "hmac-sha2-512-etm@openssh.com" "hmac-sha2-256-etm@openssh.com" @@ -448,15 +445,15 @@ in ''; }; - StrictModes = mkOption { - type = types.nullOr (types.bool); + StrictModes = lib.mkOption { + type = lib.types.nullOr (lib.types.bool); default = true; description = '' Whether sshd should check file modes and ownership of directories ''; }; - Ciphers = mkOption { - type = types.nullOr (types.listOf types.str); + Ciphers = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); default = [ "chacha20-poly1305@openssh.com" "aes256-gcm@openssh.com" @@ -474,16 +471,16 @@ in ''; }; - AllowUsers = mkOption { - type = with types; nullOr (listOf str); + AllowUsers = lib.mkOption { + type = with lib.types; nullOr (listOf str); default = null; description = '' If specified, login is allowed only for the listed users. See {manpage}`sshd_config(5)` for details. ''; }; - DenyUsers = mkOption { - type = with types; nullOr (listOf str); + DenyUsers = lib.mkOption { + type = with lib.types; nullOr (listOf str); default = null; description = '' If specified, login is denied for all listed users. Takes @@ -491,8 +488,8 @@ in See {manpage}`sshd_config(5)` for details. ''; }; - AllowGroups = mkOption { - type = with types; nullOr (listOf str); + AllowGroups = lib.mkOption { + type = with lib.types; nullOr (listOf str); default = null; description = '' If specified, login is allowed only for users part of the @@ -500,8 +497,8 @@ in See {manpage}`sshd_config(5)` for details. ''; }; - DenyGroups = mkOption { - type = with types; nullOr (listOf str); + DenyGroups = lib.mkOption { + type = with lib.types; nullOr (listOf str); default = null; description = '' If specified, login is denied for all users part of the listed @@ -512,21 +509,21 @@ in }; # Disabled by default, since pam_motd handles this. PrintMotd = - mkEnableOption "printing /etc/motd when a user logs in interactively" - // { type = types.nullOr types.bool; }; + lib.mkEnableOption "printing /etc/motd when a user logs in interactively" + // { type = lib.types.nullOr lib.types.bool; }; }; }); }; - extraConfig = mkOption { - type = types.lines; + extraConfig = lib.mkOption { + type = lib.types.lines; default = ""; description = "Verbatim contents of {file}`sshd_config`."; }; - moduliFile = mkOption { + moduliFile = lib.mkOption { example = "/etc/my-local-ssh-moduli;"; - type = types.path; + type = lib.types.path; description = '' Path to `moduli` file to install in `/etc/ssh/moduli`. If this option is unset, then @@ -536,8 +533,8 @@ in }; - users.users = mkOption { - type = with types; attrsOf (submodule userOptions); + users.users = lib.mkOption { + type = with lib.types; attrsOf (submodule userOptions); }; }; @@ -545,7 +542,7 @@ in ###### implementation - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { users.users.sshd = { @@ -555,8 +552,8 @@ in }; users.groups.sshd = {}; - services.openssh.moduliFile = mkDefault "${cfg.package}/etc/ssh/moduli"; - services.openssh.sftpServerExecutable = mkDefault "${cfg.package}/libexec/sftp-server"; + services.openssh.moduliFile = lib.mkDefault "${cfg.package}/etc/ssh/moduli"; + services.openssh.sftpServerExecutable = lib.mkDefault "${cfg.package}/libexec/sftp-server"; environment.etc = authKeysFiles // authPrincipalsFiles // { "ssh/moduli".source = cfg.moduliFile; @@ -567,13 +564,13 @@ in let service = { description = "SSH Daemon"; - wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; + wantedBy = lib.optional (!cfg.startWhenNeeded) "multi-user.target"; after = [ "network.target" ]; stopIfChanged = false; path = [ cfg.package pkgs.gawk ]; environment.LD_LIBRARY_PATH = nssModulesPath; - restartTriggers = optionals (!cfg.startWhenNeeded) [ + restartTriggers = lib.optionals (!cfg.startWhenNeeded) [ config.environment.etc."ssh/sshd_config".source ]; @@ -583,18 +580,19 @@ in # socket activation, it goes to the remote side (#19589). exec >&2 - ${flip concatMapStrings cfg.hostKeys (k: '' + ${lib.flip lib.concatMapStrings cfg.hostKeys (k: '' if ! [ -s "${k.path}" ]; then if ! [ -h "${k.path}" ]; then rm -f "${k.path}" fi - mkdir -m 0755 -p "$(dirname '${k.path}')" + mkdir -p "$(dirname '${k.path}')" + chmod 0755 "$(dirname '${k.path}')" ssh-keygen \ -t "${k.type}" \ - ${optionalString (k ? bits) "-b ${toString k.bits}"} \ - ${optionalString (k ? rounds) "-a ${toString k.rounds}"} \ - ${optionalString (k ? comment) "-C '${k.comment}'"} \ - ${optionalString (k ? openSSHFormat && k.openSSHFormat) "-o"} \ + ${lib.optionalString (k ? bits) "-b ${toString k.bits}"} \ + ${lib.optionalString (k ? rounds) "-a ${toString k.rounds}"} \ + ${lib.optionalString (k ? comment) "-C '${k.comment}'"} \ + ${lib.optionalString (k ? openSSHFormat && k.openSSHFormat) "-o"} \ -f "${k.path}" \ -N "" fi @@ -603,8 +601,8 @@ in serviceConfig = { ExecStart = - (optionalString cfg.startWhenNeeded "-") + - "${cfg.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + + (lib.optionalString cfg.startWhenNeeded "-") + + "${cfg.package}/bin/sshd " + (lib.optionalString cfg.startWhenNeeded "-i ") + "-D " + # don't detach into a daemon process "-f /etc/ssh/sshd_config"; KillMode = "process"; @@ -625,7 +623,7 @@ in { description = "SSH Socket"; wantedBy = [ "sockets.target" ]; socketConfig.ListenStream = if cfg.listenAddresses != [] then - concatMap + lib.concatMap ({ addr, port }: if port != null then [ "${addr}:${toString port}" ] else map (p: "${addr}:${toString p}") cfg.ports) @@ -645,7 +643,7 @@ in }; - networking.firewall.allowedTCPPorts = optionals cfg.openFirewall cfg.ports; + networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall cfg.ports; security.pam.services.sshd = lib.mkIf cfg.settings.UsePAM { startSession = true; @@ -662,34 +660,34 @@ in services.openssh.authorizedKeysFiles = lib.optional cfg.authorizedKeysInHomedir "%h/.ssh/authorized_keys" ++ [ "/etc/ssh/authorized_keys.d/%u" ]; - services.openssh.settings.AuthorizedPrincipalsFile = mkIf (authPrincipalsFiles != {}) "/etc/ssh/authorized_principals.d/%u"; + services.openssh.settings.AuthorizedPrincipalsFile = lib.mkIf (authPrincipalsFiles != {}) "/etc/ssh/authorized_principals.d/%u"; - services.openssh.extraConfig = mkOrder 0 + services.openssh.extraConfig = lib.mkOrder 0 '' Banner ${if cfg.banner == null then "none" else pkgs.writeText "ssh_banner" cfg.banner} AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} - ${concatMapStrings (port: '' + ${lib.concatMapStrings (port: '' Port ${toString port} '') cfg.ports} - ${concatMapStrings ({ port, addr, ... }: '' - ListenAddress ${addr}${optionalString (port != null) (":" + toString port)} + ${lib.concatMapStrings ({ port, addr, ... }: '' + ListenAddress ${addr}${lib.optionalString (port != null) (":" + toString port)} '') cfg.listenAddresses} - ${optionalString cfgc.setXAuthLocation '' + ${lib.optionalString cfgc.setXAuthLocation '' XAuthLocation ${pkgs.xorg.xauth}/bin/xauth ''} - ${optionalString cfg.allowSFTP '' - Subsystem sftp ${cfg.sftpServerExecutable} ${concatStringsSep " " cfg.sftpFlags} + ${lib.optionalString cfg.allowSFTP '' + Subsystem sftp ${cfg.sftpServerExecutable} ${lib.concatStringsSep " " cfg.sftpFlags} ''} AuthorizedKeysFile ${toString cfg.authorizedKeysFiles} - ${optionalString (cfg.authorizedKeysCommand != "none") '' + ${lib.optionalString (cfg.authorizedKeysCommand != "none") '' AuthorizedKeysCommand ${cfg.authorizedKeysCommand} AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser} ''} - ${flip concatMapStrings cfg.hostKeys (k: '' + ${lib.flip lib.concatMapStrings cfg.hostKeys (k: '' HostKey ${k.path} '')} ''; @@ -699,13 +697,13 @@ in { nativeBuildInputs = [ validationPackage ]; } '' - ${concatMapStringsSep "\n" + ${lib.concatMapStringsSep "\n" (lport: "sshd -G -T -C lport=${toString lport} -f ${sshconf} > /dev/null") cfg.ports} - ${concatMapStringsSep "\n" + ${lib.concatMapStringsSep "\n" (la: - concatMapStringsSep "\n" - (port: "sshd -G -T -C ${escapeShellArg "laddr=${la.addr},lport=${toString port}"} -f ${sshconf} > /dev/null") + lib.concatMapStringsSep "\n" + (port: "sshd -G -T -C ${lib.escapeShellArg "laddr=${la.addr},lport=${toString port}"} -f ${sshconf} > /dev/null") (if la.port != null then [ la.port ] else cfg.ports) ) cfg.listenAddresses} @@ -726,7 +724,7 @@ in # Grab the groups, we don't care about the group identifiers lib.attrValues ( # Group the settings that are the same in lower case - lib.groupBy lib.strings.toLower (attrNames cfg.settings) + lib.groupBy lib.strings.toLower (lib.attrNames cfg.settings) ) ); formattedDuplicates = lib.concatMapStringsSep ", " (dupl: "(${lib.concatStringsSep ", " dupl})") duplicates; @@ -735,7 +733,7 @@ in assertion = lib.length duplicates == 0; message = ''Duplicate sshd config key; does your capitalization match the option's? Duplicate keys: ${formattedDuplicates}''; })] - ++ forEach cfg.listenAddresses ({ addr, ... }: { + ++ lib.forEach cfg.listenAddresses ({ addr, ... }: { assertion = addr != null; message = "addr must be specified in each listenAddresses entry"; }); diff --git a/nixos/modules/services/networking/strongswan.nix b/nixos/modules/services/networking/strongswan.nix index 0c04a9c85396..1cb9f4e1fc5a 100644 --- a/nixos/modules/services/networking/strongswan.nix +++ b/nixos/modules/services/networking/strongswan.nix @@ -3,14 +3,12 @@ let inherit (builtins) toFile; - inherit (lib) concatMapStringsSep concatStringsSep mapAttrsToList + inherit (lib) concatMapStrings concatStringsSep mapAttrsToList mkIf mkEnableOption mkOption types literalExpression optionalString; cfg = config.services.strongswan; - ipsecSecrets = secrets: toFile "ipsec.secrets" ( - concatMapStringsSep "\n" (f: "include ${f}") secrets - ); + ipsecSecrets = secrets: concatMapStrings (f: "include ${f}\n") secrets; ipsecConf = {setup, connections, ca}: let @@ -138,16 +136,12 @@ in }; - config = with cfg; - let - secretsFile = ipsecSecrets cfg.secrets; - in - mkIf enable + config = with cfg; mkIf enable { # here we should use the default strongswan ipsec.secrets and # append to it (default one is empty so not a pb for now) - environment.etc."ipsec.secrets".source = secretsFile; + environment.etc."ipsec.secrets".text = ipsecSecrets cfg.secrets; systemd.services.strongswan = { description = "strongSwan IPSec Service"; @@ -156,7 +150,10 @@ in wants = [ "network-online.target" ]; after = [ "network-online.target" ]; environment = { - STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secretsFile managePlugins enabledPlugins; }; + STRONGSWAN_CONF = strongswanConf { + inherit setup connections ca managePlugins enabledPlugins; + secretsFile = "/etc/ipsec.secrets"; + }; }; serviceConfig = { ExecStart = "${pkgs.strongswan}/sbin/ipsec start --nofork"; diff --git a/nixos/modules/services/networking/suricata/default.nix b/nixos/modules/services/networking/suricata/default.nix new file mode 100644 index 000000000000..5473fc913ebc --- /dev/null +++ b/nixos/modules/services/networking/suricata/default.nix @@ -0,0 +1,282 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.suricata; + pkg = cfg.package; + yaml = pkgs.formats.yaml { }; + inherit (lib) + mkEnableOption + mkPackageOption + mkOption + types + literalExpression + filterAttrsRecursive + concatStringsSep + strings + lists + mkIf + ; +in +{ + meta.maintainers = with lib.maintainers; [ felbinger ]; + + options.services.suricata = { + enable = mkEnableOption "Suricata"; + + package = mkPackageOption pkgs "suricata" { }; + + configFile = mkOption { + type = types.path; + visible = false; + default = pkgs.writeTextFile { + name = "suricata.yaml"; + text = '' + %YAML 1.1 + --- + ${builtins.readFile ( + yaml.generate "suricata-settings-raw.yaml" ( + filterAttrsRecursive (name: value: value != null) cfg.settings + ) + )} + ''; + }; + description = '' + Configuration file for suricata. + + It is not usual to override the default values; it is recommended to use `settings`. + If you want to include extra configuration to the file, use the `settings.includes`. + ''; + }; + + settings = mkOption { + type = types.submodule (import ./settings.nix { inherit config lib yaml; }); + example = literalExpression '' + vars.address-groups.HOME_NET = "192.168.178.0/24"; + outputs = [ + { + fast = { + enabled = true; + filename = "fast.log"; + append = "yes"; + }; + } + { + eve-log = { + enabled = true; + filetype = "regular"; + filename = "eve.json"; + community-id = true; + types = [ + { + alert.tagged-packets = "yes"; + } + ]; + }; + } + ]; + af-packet = [ + { + interface = "eth0"; + cluster-id = "99"; + cluster-type = "cluster_flow"; + defrag = "yes"; + } + { + interface = "default"; + } + ]; + af-xdp = [ + { + interface = "eth1"; + } + ]; + dpdk.interfaces = [ + { + interface = "eth2"; + } + ]; + pcap = [ + { + interface = "eth3"; + } + ]; + app-layer.protocols = { + telnet.enabled = "yes"; + dnp3.enabled = "yes"; + modbus.enabled = "yes"; + }; + ''; + description = "Suricata settings"; + }; + + enabledSources = mkOption { + type = types.listOf types.str; + # see: nix-shell -p suricata python3Packages.pyyaml --command 'suricata-update list-sources' + default = [ + "et/open" + "etnetera/aggressive" + "stamus/lateral" + "oisf/trafficid" + "tgreen/hunting" + "sslbl/ja3-fingerprints" + "sslbl/ssl-fp-blacklist" + "malsilo/win-malware" + "pawpatrules" + ]; + description = '' + List of sources that should be enabled. + Currently sources which require a secret-code are not supported. + ''; + }; + + disabledRules = mkOption { + type = types.listOf types.str; + # protocol dnp3 seams to be disabled, which causes the signature evaluation to fail, so we disable the + # dnp3 rules, see https://github.com/OISF/suricata/blob/master/rules/dnp3-events.rules for more details + default = [ + "2270000" + "2270001" + "2270002" + "2270003" + "2270004" + ]; + description = '' + List of rules that should be disabled. + ''; + }; + }; + + config = + let + captureInterfaces = + let + inherit (lists) unique optionals; + in + unique ( + map (e: e.interface) ( + (optionals (cfg.settings.af-packet != null) cfg.settings.af-packet) + ++ (optionals (cfg.settings.af-xdp != null) cfg.settings.af-xdp) + ++ (optionals ( + cfg.settings.dpdk != null && cfg.settings.dpdk.interfaces != null + ) cfg.settings.dpdk.interfaces) + ++ (optionals (cfg.settings.pcap != null) cfg.settings.pcap) + ) + ); + in + mkIf cfg.enable { + assertions = [ + { + assertion = (builtins.length captureInterfaces) > 0; + message = '' + At least one capture interface must be configured: + - `services.suricata.settings.af-packet` + - `services.suricata.settings.af-xdp` + - `services.suricata.settings.dpdk.interfaces` + - `services.suricata.settings.pcap` + ''; + } + ]; + + boot.kernelModules = mkIf (cfg.settings.af-packet != null) [ "af_packet" ]; + + users = { + groups.${cfg.settings.run-as.group} = { }; + users.${cfg.settings.run-as.user} = { + group = cfg.settings.run-as.group; + isSystemUser = true; + }; + }; + + systemd.tmpfiles.rules = [ + "d ${cfg.settings."default-log-dir"} 755 ${cfg.settings.run-as.user} ${cfg.settings.run-as.group}" + "d /var/lib/suricata 755 ${cfg.settings.run-as.user} ${cfg.settings.run-as.group}" + "d ${cfg.settings."default-rule-path"} 755 ${cfg.settings.run-as.user} ${cfg.settings.run-as.group}" + ]; + + systemd.services = { + suricata-update = { + description = "Update Suricata Rules"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + script = + let + python = pkgs.python3.withPackages (ps: with ps; [ pyyaml ]); + enabledSourcesCmds = map ( + src: "${python.interpreter} ${pkg}/bin/suricata-update enable-source ${src}" + ) cfg.enabledSources; + in + '' + ${concatStringsSep "\n" enabledSourcesCmds} + ${python.interpreter} ${pkg}/bin/suricata-update update-sources + ${python.interpreter} ${pkg}/bin/suricata-update update --suricata-conf ${cfg.configFile} --no-test \ + --disable-conf ${pkgs.writeText "suricata-disable-conf" "${concatStringsSep "\n" cfg.disabledRules}"} + ''; + serviceConfig = { + Type = "oneshot"; + + PrivateTmp = true; + PrivateDevices = true; + PrivateIPC = true; + + DynamicUser = true; + User = cfg.settings.run-as.user; + Group = cfg.settings.run-as.group; + + ReadOnlyPaths = cfg.configFile; + ReadWritePaths = [ + "/var/lib/suricata" + cfg.settings."default-rule-path" + ]; + }; + }; + suricata = { + description = "Suricata"; + wantedBy = [ "multi-user.target" ]; + after = [ "suricata-update.service" ]; + serviceConfig = + let + interfaceOptions = strings.concatMapStrings (interface: " -i ${interface}") captureInterfaces; + in + { + ExecStartPre = "!${pkg}/bin/suricata -c ${cfg.configFile} -T"; + ExecStart = "!${pkg}/bin/suricata -c ${cfg.configFile}${interfaceOptions}"; + Restart = "on-failure"; + + User = cfg.settings.run-as.user; + Group = cfg.settings.run-as.group; + + NoNewPrivileges = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateIPC = true; + ProtectSystem = "strict"; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + ProtectHostname = true; + ProtectProc = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + ProcSubset = "pid"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + RemoveIPC = true; + + ReadOnlyPaths = cfg.configFile; + ReadWritePaths = cfg.settings."default-log-dir"; + RuntimeDirectory = "suricata"; + }; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/suricata/settings.nix b/nixos/modules/services/networking/suricata/settings.nix new file mode 100644 index 000000000000..f96d78ca66d5 --- /dev/null +++ b/nixos/modules/services/networking/suricata/settings.nix @@ -0,0 +1,625 @@ +{ + lib, + config, + yaml, + ... +}: +let + cfg = config.services.suricata; + inherit (lib) + mkEnableOption + mkOption + types + literalExpression + ; + mkDisableOption = + name: + mkEnableOption name + // { + default = true; + example = false; + }; +in +{ + freeformType = yaml.type; + options = { + vars = mkOption { + type = types.nullOr ( + types.submodule { + options = { + address-groups = mkOption { + type = ( + types.submodule { + options = { + HOME_NET = mkOption { default = "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"; }; + EXTERNAL_NET = mkOption { default = "!$HOME_NET"; }; + HTTP_SERVERS = mkOption { default = "$HOME_NET"; }; + SMTP_SERVERS = mkOption { default = "$HOME_NET"; }; + SQL_SERVERS = mkOption { default = "$HOME_NET"; }; + DNS_SERVERS = mkOption { default = "$HOME_NET"; }; + TELNET_SERVERS = mkOption { default = "$HOME_NET"; }; + AIM_SERVERS = mkOption { default = "$EXTERNAL_NET"; }; + DC_SERVERS = mkOption { default = "$HOME_NET"; }; + DNP3_SERVER = mkOption { default = "$HOME_NET"; }; + DNP3_CLIENT = mkOption { default = "$HOME_NET"; }; + MODBUS_CLIENT = mkOption { default = "$HOME_NET"; }; + MODBUS_SERVER = mkOption { default = "$HOME_NET"; }; + ENIP_CLIENT = mkOption { default = "$HOME_NET"; }; + ENIP_SERVER = mkOption { default = "$HOME_NET"; }; + }; + } + ); + default = { }; + example = { + HOME_NET = "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"; + EXTERNAL_NET = "!$HOME_NET"; + HTTP_SERVERS = "$HOME_NET"; + SMTP_SERVERS = "$HOME_NET"; + SQL_SERVERS = "$HOME_NET"; + DNS_SERVERS = "$HOME_NET"; + TELNET_SERVERS = "$HOME_NET"; + AIM_SERVERS = "$EXTERNAL_NET"; + DC_SERVERS = "$HOME_NET"; + DNP3_SERVER = "$HOME_NET"; + DNP3_CLIENT = "$HOME_NET"; + MODBUS_CLIENT = "$HOME_NET"; + MODBUS_SERVER = "$HOME_NET"; + ENIP_CLIENT = "$HOME_NET"; + ENIP_SERVER = "$HOME_NET"; + }; + description = '' + The address group variables for suricata, if not defined the + default value of suricata (see example) will be used. + Your settings will extend the predefined values in example. + ''; + }; + + port-groups = mkOption { + type = with types; nullOr (attrsOf str); + default = { + HTTP_PORTS = "80"; + SHELLCODE_PORTS = "!80"; + ORACLE_PORTS = "1521"; + SSH_PORTS = "22"; + DNP3_PORTS = "20000"; + MODBUS_PORTS = "502"; + FILE_DATA_PORTS = "[$HTTP_PORTS,110,143]"; + FTP_PORTS = "21"; + GENEVE_PORTS = "6081"; + VXLAN_PORTS = "4789"; + TEREDO_PORTS = "3544"; + }; + description = '' + The port group variables for suricata. + ''; + }; + }; + } + ); + default = { }; # add default values to config + }; + + stats = mkOption { + type = + with types; + nullOr (submodule { + options = { + enable = mkEnableOption "suricata global stats"; + + interval = mkOption { + type = types.str; + default = "8"; + description = '' + The interval field (in seconds) controls the interval at + which stats are updated in the log. + ''; + }; + + decoder-events = mkOption { + type = types.bool; + default = true; + description = '' + Add decode events to stats + ''; + }; + + decoder-events-prefix = mkOption { + type = types.str; + default = "decoder.event"; + description = '' + Decoder event prefix in stats. Has been 'decoder' before, but that leads + to missing events in the eve.stats records. + ''; + }; + + stream-events = mkOption { + type = types.bool; + default = false; + description = '' + Add stream events as stats. + ''; + }; + }; + }); + default = null; # do not add to config unless specified + }; + + plugins = mkOption { + type = with types; nullOr (listOf path); + default = null; + description = '' + Plugins -- Experimental -- specify the filename for each plugin shared object + ''; + }; + + outputs = mkOption { + type = + with types; + nullOr ( + listOf ( + attrsOf (submodule { + freeformType = yaml.type; + options = { + enabled = mkEnableOption ""; + }; + }) + ) + ); + default = null; + example = literalExpression '' + [ + { + fast = { + enabled = "yes"; + filename = "fast.log"; + append = "yes"; + }; + } + { + eve-log = { + enabled = "yes"; + filetype = "regular"; + filename = "eve.json"; + community-id = true; + types = [ + { + alert.tagged-packets = "yes"; + } + ]; + }; + } + ]; + ''; + description = '' + Configure the type of alert (and other) logging you would like. + + Valid values for are e. g. `fast`, `eve-log`, `syslog`, `file-store`, ... + - `fast`: a line based alerts log similar to Snort's fast.log + - `eve-log`: Extensible Event Format (nicknamed EVE) event log in JSON format + + For more details regarding the configuration, checkout the shipped suricata.yaml + ```shell + nix-shell -p suricata yq coreutils-full --command 'yq < $(dirname $(which suricata))/../etc/suricata/suricata.yaml' + ``` + and the [suricata documentation](https://docs.suricata.io/en/latest/output/index.html). + ''; + }; + + "default-log-dir" = mkOption { + type = types.str; + default = "/var/log/suricata"; + description = '' + The default logging directory. Any log or output file will be placed here if it's + not specified with a full path name. This can be overridden with the -l command + line parameter. + ''; + }; + + logging = { + "default-log-level" = mkOption { + type = types.enum [ + "error" + "warning" + "notice" + "info" + "perf" + "config" + "debug" + ]; + default = "notice"; + description = '' + The default log level: can be overridden in an output section. + Note that debug level logging will only be emitted if Suricata was + compiled with the --enable-debug configure option. + ''; + }; + + "default-log-format" = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The default output format. Optional parameter, should default to + something reasonable if not provided. Can be overridden in an + output section. You can leave this out to get the default. + ''; + }; + + "default-output-filter" = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + A regex to filter output. Can be overridden in an output section. + Defaults to empty (no filter). + ''; + }; + + "stacktrace-on-signal" = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Requires libunwind to be available when Suricata is configured and built. + If a signal unexpectedly terminates Suricata, displays a brief diagnostic + message with the offending stacktrace if enabled. + ''; + }; + + outputs = { + console = { + enable = mkDisableOption "logging to console"; + }; + file = { + enable = mkDisableOption "logging to file"; + + level = mkOption { + type = types.enum [ + "error" + "warning" + "notice" + "info" + "perf" + "config" + "debug" + ]; + default = "info"; + description = '' + Loglevel for logs written to the logfile + ''; + }; + + filename = mkOption { + type = types.str; + default = "suricata.log"; + description = '' + Filename of the logfile + ''; + }; + + format = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Logformat for logs written to the logfile + ''; + }; + + type = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Type of logfile + ''; + }; + }; + syslog = { + enable = mkEnableOption "logging to syslog"; + + facility = mkOption { + type = types.str; + default = "local5"; + description = '' + Facility to log to + ''; + }; + + format = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Logformat for logs send to syslog + ''; + }; + + type = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Type of logs send to syslog + ''; + }; + }; + }; + }; + + "af-packet" = mkOption { + type = + with types; + nullOr ( + listOf (submodule { + freeformType = yaml.type; + options = { + interface = mkOption { + type = types.str; + default = null; + }; + }; + }) + ); + default = null; + description = '' + Linux high speed capture support + ''; + }; + + "af-xdp" = mkOption { + type = + with types; + nullOr ( + listOf (submodule { + freeformType = yaml.type; + options = { + interface = mkOption { + type = types.str; + default = null; + }; + }; + }) + ); + default = null; + description = '' + Linux high speed af-xdp capture support, see + [docs/capture-hardware/af-xdp](https://docs.suricata.io/en/suricata-7.0.3/capture-hardware/af-xdp.html) + ''; + }; + + "dpdk" = mkOption { + type = + with types; + nullOr (submodule { + options = { + eal-params.proc-type = mkOption { + type = with types; nullOr str; + default = null; + }; + interfaces = mkOption { + type = + with types; + nullOr ( + listOf (submodule { + freeformType = yaml.type; + options = { + interface = mkOption { + type = types.str; + default = null; + }; + }; + }) + ); + default = null; + }; + }; + }); + default = null; + description = '' + DPDK capture support, see + [docs/capture-hardware/dpdk](https://docs.suricata.io/en/suricata-7.0.3/capture-hardware/dpdk.html) + ''; + }; + + "pcap" = mkOption { + type = + with types; + nullOr ( + listOf (submodule { + freeformType = yaml.type; + options = { + interface = mkOption { + type = types.str; + default = null; + }; + }; + }) + ); + default = null; + description = '' + Cross platform libpcap capture support + ''; + }; + + "pcap-file".checksum-checks = mkOption { + type = types.enum [ + "yes" + "no" + "auto" + ]; + default = "auto"; + description = '' + Possible values are: + - yes: checksum validation is forced + - no: checksum validation is disabled + - auto: Suricata uses a statistical approach to detect when + checksum off-loading is used. (default) + Warning: 'checksum-validation' must be set to yes to have checksum tested + ''; + }; + + "app-layer" = mkOption { + type = + with types; + nullOr (submodule { + options = { + "error-policy" = mkOption { + type = types.enum [ + "drop-flow" + "pass-flow" + "bypass" + "drop-packet" + "pass-packet" + "reject" + "ignore" + ]; + default = "ignore"; + description = '' + The error-policy setting applies to all app-layer parsers. Values can be + "drop-flow", "pass-flow", "bypass", "drop-packet", "pass-packet", "reject" or + "ignore" (the default). + ''; + }; + protocols = mkOption { + type = + with types; + nullOr ( + attrsOf (submodule { + freeformType = yaml.type; + options = { + enabled = mkOption { + type = types.enum [ + "yes" + "no" + "detection-only" + ]; + default = "no"; + description = '' + The option "enabled" takes 3 values - "yes", "no", "detection-only". + "yes" enables both detection and the parser, "no" disables both, and + "detection-only" enables protocol detection only (parser disabled). + ''; + }; + }; + }) + ); + default = null; + }; + }; + }); + default = null; # do not add to config unless specified + }; + + "run-as" = { + user = mkOption { + type = types.str; + default = "suricata"; + description = "Run Suricata with a specific user-id"; + }; + group = mkOption { + type = types.str; + default = "suricata"; + description = "Run Suricata with a specific group-id"; + }; + }; + + "host-mode" = mkOption { + type = types.enum [ + "router" + "sniffer-only" + "auto" + ]; + default = "auto"; + description = '' + If the Suricata box is a router for the sniffed networks, set it to 'router'. If + it is a pure sniffing setup, set it to 'sniffer-only'. If set to auto, the variable + is internally switched to 'router' in IPS mode and 'sniffer-only' in IDS mode. + This feature is currently only used by the reject* keywords. + ''; + }; + + "unix-command" = mkOption { + type = + with types; + nullOr (submodule { + options = { + enabled = mkOption { + type = types.either types.bool (types.enum [ "auto" ]); + default = "auto"; + }; + filename = mkOption { + type = types.path; + default = "/run/suricata/suricata-command.socket"; + }; + }; + }); + default = { }; + description = '' + Unix command socket that can be used to pass commands to Suricata. + An external tool can then connect to get information from Suricata + or trigger some modifications of the engine. Set enabled to yes + to activate the feature. In auto mode, the feature will only be + activated in live capture mode. You can use the filename variable to set + the file name of the socket. + ''; + }; + + "exception-policy" = mkOption { + type = types.enum [ + "auto" + "drop-packet" + "drop-flow" + "reject" + "bypass" + "pass-packet" + "pass-flow" + "ignore" + ]; + default = "auto"; + description = '' + Define a common behavior for all exception policies. + In IPS mode, the default is drop-flow. For cases when that's not possible, the + engine will fall to drop-packet. To fallback to old behavior (setting each of + them individually, or ignoring all), set this to ignore. + All values available for exception policies can be used, and there is one + extra option: auto - which means drop-flow or drop-packet (as explained above) + in IPS mode, and ignore in IDS mode. Exception policy values are: drop-packet, + drop-flow, reject, bypass, pass-packet, pass-flow, ignore (disable). + ''; + }; + + "default-rule-path" = mkOption { + type = types.path; + default = "/var/lib/suricata/rules"; + description = "Path in which suricata-update managed rules are stored by default"; + }; + + "rule-files" = mkOption { + type = types.listOf types.str; + default = [ "suricata.rules" ]; + description = "Files to load suricata-update managed rules, relative to 'default-rule-path'"; + }; + + "classification-file" = mkOption { + type = types.str; + default = "/var/lib/suricata/rules/classification.config"; + description = "Suricata classification configuration file"; + }; + + "reference-config-file" = mkOption { + type = types.str; + default = "${cfg.package}/etc/suricata/reference.config"; + description = "Suricata reference configuration file"; + }; + + "threshold-file" = mkOption { + type = types.str; + default = "${cfg.package}/etc/suricata/threshold.config"; + description = "Suricata threshold configuration file"; + }; + + includes = mkOption { + type = with types; nullOr (listOf path); + default = null; + description = '' + Files to include in the suricata configuration. See + [docs/configuration/suricata-yaml](https://docs.suricata.io/en/suricata-7.0.3/configuration/suricata-yaml.html) + for available options. + ''; + }; + }; +} diff --git a/nixos/modules/services/networking/syncplay.nix b/nixos/modules/services/networking/syncplay.nix index b56754ea3f2e..22808248abbc 100644 --- a/nixos/modules/services/networking/syncplay.nix +++ b/nixos/modules/services/networking/syncplay.nix @@ -7,18 +7,41 @@ let cmdArgs = [ "--port" cfg.port ] + ++ optionals (cfg.isolateRooms) [ "--isolate-rooms" ] + ++ optionals (!cfg.ready) [ "--disable-ready" ] + ++ optionals (!cfg.chat) [ "--disable-chat" ] ++ optionals (cfg.salt != null) [ "--salt" cfg.salt ] + ++ optionals (cfg.motdFile != null) [ "--motd-file" cfg.motdFile ] + ++ optionals (cfg.roomsDBFile != null) [ "--rooms-db-file" cfg.roomsDBFile ] + ++ optionals (cfg.permanentRoomsFile != null) [ "--permanent-rooms-file" cfg.permanentRoomsFile ] + ++ [ "--max-chat-message-length" cfg.maxChatMessageLength ] + ++ [ "--max-username-length" cfg.maxUsernameLength ] + ++ optionals (cfg.statsDBFile != null) [ "--stats-db-file" cfg.statsDBFile ] ++ optionals (cfg.certDir != null) [ "--tls" cfg.certDir ] + ++ optionals cfg.ipv4Only [ "--ipv4-only" ] + ++ optionals cfg.ipv6Only [ "--ipv6-only" ] + ++ optionals (cfg.interfaceIpv4 != "") [ "--interface-ipv4" cfg.interfaceIpv4 ] + ++ optionals (cfg.interfaceIpv6 != "") [ "--interface-ipv6" cfg.interfaceIpv6 ] ++ cfg.extraArgs; + useACMEHostDir = optionalString (cfg.useACMEHost != null) config.security.acme.certs.${cfg.useACMEHost}.directory; in { + imports = [ + (mkRemovedOptionModule [ "services" "syncplay" "user" ] + "The syncplay service now uses DynamicUser, override the systemd unit settings if you need the old functionality.") + (mkRemovedOptionModule [ "services" "syncplay" "group" ] + "The syncplay service now uses DynamicUser, override the systemd unit settings if you need the old functionality.") + ]; + options = { services.syncplay = { enable = mkOption { type = types.bool; default = false; - description = "If enabled, start the Syncplay server."; + description = '' + If enabled, start the Syncplay server. + ''; }; port = mkOption { @@ -29,6 +52,39 @@ in ''; }; + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to the file that contains the server password. If + `null`, the server doesn't require a password. + ''; + }; + + isolateRooms = mkOption { + type = types.bool; + default = false; + description = '' + Enable room isolation. + ''; + }; + + ready = mkOption { + type = types.bool; + default = true; + description = '' + Check readiness of users. + ''; + }; + + chat = mkOption { + type = types.bool; + default = true; + description = '' + Chat with users in the same room. + ''; + }; + salt = mkOption { type = types.nullOr types.str; default = null; @@ -37,7 +93,7 @@ in instance to still work when the server is restarted. The salt will be readable in the nix store and the processlist. If this is not intended use `saltFile` instead. Mutually exclusive with - . + {option}`services.syncplay.saltFile`. ''; }; @@ -49,7 +105,83 @@ in operator passwords generated by this server instance to still work when the server is restarted. `null`, the server doesn't load the salt from a file. Mutually exclusive with - . + {option}`services.syncplay.salt`. + ''; + }; + + motd = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Text to display when users join. The motd will be readable in the nix store + and the processlist. If this is not intended use `motdFile` instead. + Will be overriden by {option}`services.syncplay.motdFile`. + ''; + }; + + motdFile = mkOption { + type = types.nullOr types.str; + default = if cfg.motd != null then (builtins.toFile "motd" cfg.motd) else null; + defaultText = literalExpression ''if services.syncplay.motd != null then (builtins.toFile "motd" services.syncplay.motd) else null''; + description = '' + Path to text to display when users join. + Will override {option}`services.syncplay.motd`. + ''; + }; + + roomsDBFile = mkOption { + type = types.nullOr types.str; + default = null; + example = "rooms.db"; + description = '' + Path to SQLite database file to store room states. + Relative to the working directory provided by systemd. + ''; + }; + + permanentRooms = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of rooms that will be listed even if the room is empty. + Will be overriden by {option}`services.syncplay.permanentRoomsFile`. + ''; + }; + + permanentRoomsFile = mkOption { + type = types.nullOr types.str; + default = if cfg.permanentRooms != [ ] then (builtins.toFile "perm" (builtins.concatStringsSep "\n" cfg.permanentRooms)) else null; + defaultText = literalExpression ''if services.syncplay.permanentRooms != [ ] then (builtins.toFile "perm" (builtins.concatStringsSep "\n" services.syncplay.permanentRooms)) else null''; + description = '' + File with list of rooms that will be listed even if the room is empty, + newline delimited. + Will override {option}`services.syncplay.permanentRooms`. + ''; + }; + + maxChatMessageLength = mkOption { + type = types.ints.unsigned; + default = 150; + description = '' + Maximum number of characters in a chat message. + ''; + }; + + maxUsernameLength = mkOption { + type = types.ints.unsigned; + default = 16; + description = '' + Maximum number of characters in a username. + ''; + }; + + statsDBFile = mkOption { + type = types.nullOr types.str; + default = null; + example = "stats.db"; + description = '' + Path to SQLite database file to store stats. + Relative to the working directory provided by systemd. ''; }; @@ -62,6 +194,49 @@ in ''; }; + useACMEHost = mkOption { + type = types.nullOr types.str; + default = null; + example = "syncplay.example.com"; + description = '' + If set, use NixOS-generated ACME certificate with the specified name for TLS. + + Note that it requires {option}`security.acme` to be setup, e.g., credentials provided if using DNS-01 validation. + ''; + }; + + ipv4Only = mkOption { + type = types.bool; + default = false; + description = '' + Listen only on IPv4 when strting the server. + ''; + }; + + ipv6Only = mkOption { + type = types.bool; + default = false; + description = '' + Listen only on IPv6 when strting the server. + ''; + }; + + interfaceIpv4 = mkOption { + type = types.str; + default = ""; + description = '' + The IP address to bind to for IPv4. Leaving it empty defaults to using all. + ''; + }; + + interfaceIpv6 = mkOption { + type = types.str; + default = ""; + description = '' + The IP address to bind to for IPv6. Leaving it empty defaults to using all. + ''; + }; + extraArgs = mkOption { type = types.listOf types.str; default = [ ]; @@ -70,28 +245,12 @@ in ''; }; - user = mkOption { - type = types.str; - default = "nobody"; + package = mkOption { + type = types.package; + default = pkgs.syncplay-nogui; + defaultText = literalExpression "pkgs.syncplay-nogui"; description = '' - User to use when running Syncplay. - ''; - }; - - group = mkOption { - type = types.str; - default = "nogroup"; - description = '' - Group to use when running Syncplay. - ''; - }; - - passwordFile = mkOption { - type = types.nullOr types.path; - default = null; - description = '' - Path to the file that contains the server password. If - `null`, the server doesn't require a password. + Package to use for syncplay. ''; }; }; @@ -103,7 +262,24 @@ in assertion = cfg.salt == null || cfg.saltFile == null; message = "services.syncplay.salt and services.syncplay.saltFile are mutually exclusive."; } + { + assertion = cfg.certDir == null || cfg.useACMEHost == null; + message = "services.syncplay.certDir and services.syncplay.useACMEHost are mutually exclusive."; + } + { + assertion = !cfg.ipv4Only || !cfg.ipv6Only; + message = "services.syncplay.ipv4Only and services.syncplay.ipv6Only are mutually exclusive."; + } ]; + + warnings = optional (cfg.interfaceIpv4 != "" && cfg.ipv6Only) "You have specified services.syncplay.interfaceIpv4 but IPv4 is disabled by services.syncplay.ipv6Only." + ++ optional (cfg.interfaceIpv6 != "" && cfg.ipv4Only) "You have specified services.syncplay.interfaceIpv6 but IPv6 is disabled by services.syncplay.ipv4Only."; + + security.acme.certs = mkIf (cfg.useACMEHost != null) { + "${cfg.useACMEHost}".reloadServices = [ "syncplay.service" ]; + }; + + networking.firewall.allowedTCPPorts = [ cfg.port ]; systemd.services.syncplay = { description = "Syncplay Service"; wantedBy = [ "multi-user.target" ]; @@ -111,20 +287,26 @@ in after = [ "network-online.target" ]; serviceConfig = { - User = cfg.user; - Group = cfg.group; - LoadCredential = lib.optional (cfg.passwordFile != null) "password:${cfg.passwordFile}" - ++ lib.optional (cfg.saltFile != null) "salt:${cfg.saltFile}"; + DynamicUser = true; + StateDirectory = "syncplay"; + WorkingDirectory = "%S/syncplay"; + LoadCredential = optional (cfg.passwordFile != null) "password:${cfg.passwordFile}" + ++ optional (cfg.saltFile != null) "salt:${cfg.saltFile}" + ++ optionals (cfg.useACMEHost != null) [ + "cert.pem:${useACMEHostDir}/cert.pem" + "privkey.pem:${useACMEHostDir}/key.pem" + "chain.pem:${useACMEHostDir}/chain.pem" + ]; }; script = '' - ${lib.optionalString (cfg.passwordFile != null) '' + ${optionalString (cfg.passwordFile != null) '' export SYNCPLAY_PASSWORD=$(cat "''${CREDENTIALS_DIRECTORY}/password") ''} - ${lib.optionalString (cfg.saltFile != null) '' + ${optionalString (cfg.saltFile != null) '' export SYNCPLAY_SALT=$(cat "''${CREDENTIALS_DIRECTORY}/salt") ''} - exec ${pkgs.syncplay-nogui}/bin/syncplay-server ${escapeShellArgs cmdArgs} + exec ${cfg.package}/bin/syncplay-server ${escapeShellArgs cmdArgs} ${optionalString (cfg.useACMEHost != null) "--tls $CREDENTIALS_DIRECTORY"} ''; }; }; diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index 94ff838b50e0..2d32cf451706 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -714,10 +714,6 @@ in { ExecStart = updateConfig; }; }; - - syncthing-resume = { - wantedBy = [ "suspend.target" ]; - }; }; }; } diff --git a/nixos/modules/services/networking/tailscale-derper.nix b/nixos/modules/services/networking/tailscale-derper.nix new file mode 100644 index 000000000000..9549cc5c6640 --- /dev/null +++ b/nixos/modules/services/networking/tailscale-derper.nix @@ -0,0 +1,132 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.tailscale.derper; +in +{ + meta.maintainers = with lib.maintainers; [ SuperSandro2000 ]; + + options = { + services.tailscale.derper = { + enable = lib.mkEnableOption "Tailscale Derper. See upstream doc how to configure it on clients"; + + domain = lib.mkOption { + type = lib.types.str; + description = "Domain name under which the derper server is reachable."; + }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to open the firewall for the specified port. + Derper requires the used ports to be opened, otherwise it doesn't work as expected. + ''; + }; + + package = lib.mkPackageOption pkgs [ + "tailscale" + "derper" + ] { }; + + stunPort = lib.mkOption { + type = lib.types.port; + default = 3478; + description = '' + STUN port to listen on. + See online docs on how to configure a different external port. + ''; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 8010; + description = "The port the derper process will listen on. This is not the port tailscale will connect to."; + }; + + verifyClients = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to verify clients against a locally running tailscale daemon if they are allowed to connect to this node or not. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + networking.firewall = lib.mkIf cfg.openFirewall { + # port 80 and 443 are opened by nginx already + allowedUDPPorts = [ cfg.stunPort ]; + }; + + services = { + nginx = { + enable = true; + upstreams.tailscale-derper = { + servers."127.0.0.1:${toString cfg.port}" = { }; + extraConfig = '' + keepalive 64; + ''; + }; + virtualHosts."${cfg.domain}" = { + addSSL = true; # this cannot be forceSSL as derper sends some information over port 80, too. + locations."/" = { + proxyPass = "http://tailscale-derper"; + proxyWebsockets = true; + extraConfig = '' + keepalive_timeout 0; + proxy_buffering off; + ''; + }; + }; + }; + + tailscale.enable = lib.mkIf cfg.verifyClients true; + }; + + systemd.services.tailscale-derper = { + serviceConfig = { + ExecStart = + "${lib.getExe' cfg.package "derper"} -a :${toString cfg.port} -c /var/lib/derper/derper.key -hostname=${cfg.domain} -stun-port ${toString cfg.stunPort}" + + lib.optionalString cfg.verifyClients " -verify-clients"; + DynamicUser = true; + Restart = "always"; + RestartSec = "5sec"; # don't crash loop immediately + StateDirectory = "derper"; + Type = "simple"; + + CapabilityBoundingSet = [ "" ]; + DeviceAllow = null; + LockPersonality = true; + NoNewPrivileges = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" ]; + }; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/nixos/modules/services/networking/tailscale.nix b/nixos/modules/services/networking/tailscale.nix index a690dc610e82..aaff9221d5f0 100644 --- a/nixos/modules/services/networking/tailscale.nix +++ b/nixos/modules/services/networking/tailscale.nix @@ -57,6 +57,34 @@ in { example = "/run/secrets/tailscale_key"; description = '' A file containing the auth key. + Tailscale will be automatically started if provided. + ''; + }; + + authKeyParameters = mkOption { + type = types.submodule { + options = { + ephemeral = mkOption { + type = types.nullOr types.bool; + default = null; + description = "Whether to register as an ephemeral node."; + }; + preauthorized = mkOption { + type = types.nullOr types.bool; + default = null; + description = "Whether to skip manual device approval."; + }; + baseURL = mkOption { + type = types.nullOr types.str; + default = null; + description = "Base URL for the Tailscale API."; + }; + }; + }; + default = { }; + description = '' + Extra parameters to pass after the auth key. + See https://tailscale.com/kb/1215/oauth-clients#registering-new-nodes-using-oauth-credentials ''; }; @@ -88,8 +116,10 @@ in { environment.systemPackages = [ cfg.package ]; # for the CLI systemd.packages = [ cfg.package ]; systemd.services.tailscaled = { + after = lib.mkIf (config.networking.networkmanager.enable) [ "NetworkManager-wait-online.service" ]; wantedBy = [ "multi-user.target" ]; path = [ + (builtins.dirOf config.security.wrapperDir) # for `su` to use taildrive with correct access rights pkgs.procps # for collecting running services (opt-in feature) pkgs.getent # for `getent` to look up user shells pkgs.kmod # required to pass tailscale's v6nat check @@ -121,10 +151,25 @@ in { serviceConfig = { Type = "oneshot"; }; - script = '' - status=$(${config.systemd.package}/bin/systemctl show -P StatusText tailscaled.service) - if [[ $status != Connected* ]]; then - ${cfg.package}/bin/tailscale up --auth-key 'file:${cfg.authKeyFile}' ${escapeShellArgs cfg.extraUpFlags} + # https://github.com/tailscale/tailscale/blob/v1.72.1/ipn/backend.go#L24-L32 + script = let + statusCommand = "${lib.getExe cfg.package} status --json --peers=false | ${lib.getExe pkgs.jq} -r '.BackendState'"; + paramToString = v: + if (builtins.isBool v) then (lib.boolToString v) + else (toString v); + params = lib.pipe cfg.authKeyParameters [ + (lib.filterAttrs (_: v: v != null)) + (lib.mapAttrsToList (k: v: "${k}=${paramToString v}")) + (builtins.concatStringsSep "&") + (params: if params != "" then "?${params}" else "") + ]; + in '' + while [[ "$(${statusCommand})" == "NoState" ]]; do + sleep 0.5 + done + status=$(${statusCommand}) + if [[ "$status" == "NeedsLogin" || "$status" == "NeedsMachineAuth" ]]; then + ${lib.getExe cfg.package} up --auth-key "$(cat ${cfg.authKeyFile})${params}" ${escapeShellArgs cfg.extraUpFlags} fi ''; }; @@ -137,7 +182,7 @@ in { Type = "oneshot"; }; script = '' - ${cfg.package}/bin/tailscale set ${escapeShellArgs cfg.extraSetFlags} + ${lib.getExe cfg.package} set ${escapeShellArgs cfg.extraSetFlags} ''; }; diff --git a/nixos/modules/services/networking/tvheadend.nix b/nixos/modules/services/networking/tvheadend.nix deleted file mode 100644 index 19a10a03bd9b..000000000000 --- a/nixos/modules/services/networking/tvheadend.nix +++ /dev/null @@ -1,63 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let cfg = config.services.tvheadend; - pidFile = "${config.users.users.tvheadend.home}/tvheadend.pid"; -in - -{ - options = { - services.tvheadend = { - enable = mkEnableOption "Tvheadend"; - httpPort = mkOption { - type = types.int; - default = 9981; - description = "Port to bind HTTP to."; - }; - - htspPort = mkOption { - type = types.int; - default = 9982; - description = "Port to bind HTSP to."; - }; - }; - }; - - config = mkIf cfg.enable { - users.users.tvheadend = { - description = "Tvheadend Service user"; - home = "/var/lib/tvheadend"; - createHome = true; - isSystemUser = true; - group = "tvheadend"; - }; - users.groups.tvheadend = {}; - - systemd.services.tvheadend = { - description = "Tvheadend TV streaming server"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - serviceConfig = { - Type = "forking"; - PIDFile = pidFile; - Restart = "always"; - RestartSec = 5; - User = "tvheadend"; - Group = "video"; - ExecStart = '' - ${pkgs.tvheadend}/bin/tvheadend \ - --http_port ${toString cfg.httpPort} \ - --htsp_port ${toString cfg.htspPort} \ - -f \ - -C \ - -p ${pidFile} \ - -u tvheadend \ - -g video - ''; - ExecStop = "${pkgs.coreutils}/bin/rm ${pidFile}"; - }; - }; - }; -} diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix index 38908e3d6f1d..8c5bc82ffcb1 100644 --- a/nixos/modules/services/networking/unifi.nix +++ b/nixos/modules/services/networking/unifi.nix @@ -2,8 +2,8 @@ let cfg = config.services.unifi; stateDir = "/var/lib/unifi"; - cmd = lib.escapeShellArgs ([ "@${cfg.jrePackage}/bin/java" "java" ] - ++ lib.optionals (lib.versionAtLeast (lib.getVersion cfg.jrePackage) "16") [ + cmd = lib.escapeShellArgs ([ + "@${cfg.jrePackage}/bin/java" "java" "--add-opens=java.base/java.lang=ALL-UNNAMED" "--add-opens=java.base/java.time=ALL-UNNAMED" "--add-opens=java.base/sun.security.util=ALL-UNNAMED" @@ -27,24 +27,19 @@ in ''; }; - services.unifi.jrePackage = lib.mkOption { - type = lib.types.package; - default = if (lib.versionAtLeast (lib.getVersion cfg.unifiPackage) "7.5") then pkgs.jdk17_headless else if (lib.versionAtLeast (lib.getVersion cfg.unifiPackage) "7.3") then pkgs.jdk11 else pkgs.jre8; - defaultText = lib.literalExpression ''if (lib.versionAtLeast (lib.getVersion cfg.unifiPackage) "7.5") then pkgs.jdk17_headless else if (lib.versionAtLeast (lib.getVersion cfg.unifiPackage) "7.3" then pkgs.jdk11 else pkgs.jre8''; - description = '' - The JRE package to use. Check the release notes to ensure it is supported. + services.unifi.jrePackage = lib.mkPackageOption pkgs "jdk" { + default = "jdk17_headless"; + extraDescription = '' + Check the UniFi controller release notes to ensure it is supported. ''; }; - services.unifi.unifiPackage = lib.mkPackageOption pkgs "unifi5" { }; + services.unifi.unifiPackage = lib.mkPackageOption pkgs "unifi" { + default = "unifi8"; + }; services.unifi.mongodbPackage = lib.mkPackageOption pkgs "mongodb" { - default = "mongodb-5_0"; - extraDescription = '' - ::: {.note} - unifi7 officially only supports mongodb up until 4.4 but works with 5.0. - ::: - ''; + default = "mongodb-7_0"; }; services.unifi.openFirewall = lib.mkOption { @@ -92,6 +87,29 @@ in config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = lib.versionAtLeast config.system.stateVersion "24.11" + || ( + options.services.unifi.unifiPackage.highestPrio < (lib.mkOptionDefault { }).priority + && options.services.unifi.mongodbPackage.highestPrio < (lib.mkOptionDefault { }).priority + ); + message = '' + Support for UniFi < 8 has been dropped; please explicitly set + `services.unifi.unifiPackage` and `services.unifi.mongodbPackage`. + + Note that the previous default MongoDB version was 5.0 and MongoDB + only supports migrating one major version at a time; therefore, you + may wish to set `services.unifi.mongodbPackage = pkgs.mongodb-6_0;` + and activate your configuration before upgrading again to the default + `mongodb-7_0` supported by `unifi8`. + + For more information, see the MongoDB upgrade notes: + + ''; + } + ]; + users.users.unifi = { isSystemUser = true; group = "unifi"; diff --git a/nixos/modules/services/networking/veilid.nix b/nixos/modules/services/networking/veilid.nix new file mode 100644 index 000000000000..d471a5f61952 --- /dev/null +++ b/nixos/modules/services/networking/veilid.nix @@ -0,0 +1,227 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +let + cfg = config.services.veilid; + dataDir = "/var/db/veilid-server"; + + settingsFormat = pkgs.formats.yaml { }; + configFile = settingsFormat.generate "veilid-server.conf" cfg.settings; +in +{ + config = mkIf cfg.enable { + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ 5150 ]; + allowedUDPPorts = [ 5150 ]; + }; + + # Based on https://gitlab.com/veilid/veilid/-/blob/main/package/systemd/veilid-server.service?ref_type=heads + systemd.services.veilid = { + enable = true; + description = "Veilid Headless Node"; + wants = [ "network-online.target" ]; + before = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ configFile ]; + environment = { + RUST_BACKTRACE = "1"; + }; + serviceConfig = { + ExecStart = "${pkgs.veilid}/bin/veilid-server -c ${configFile}"; + ExecReload = "${pkgs.coreutils}/bin/kill -s HUP $MAINPID"; + KillSignal = "SIGQUIT"; + TimeoutStopSec = 5; + WorkingDirectory = "/"; + User = "veilid"; + Group = "veilid"; + UMask = "0002"; + + CapabilityBoundingSet = ""; + SystemCallFilter = [ "@system-service" ]; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectHome = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = dataDir; + + RestrictRealtime = true; + SystemCallArchitectures = "native"; + LockPersonality = true; + RestrictSUIDSGID = true; + }; + }; + users.users.veilid = { + isSystemUser = true; + group = "veilid"; + home = dataDir; + createHome = true; + }; + users.groups.veilid = { }; + + environment = { + systemPackages = [ pkgs.veilid ]; + }; + services.veilid.settings = { }; + }; + + options.services.veilid = { + enable = mkEnableOption "Veilid Headless Node"; + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open firewall on ports 5150/tcp, 5150/udp"; + }; + settings = mkOption { + description = '' + Build veilid-server.conf with nix expression. + Check Configuration Keys. + ''; + type = types.submodule { + freeformType = settingsFormat.type; + + options = { + client_api = { + ipc_enabled = mkOption { + type = types.bool; + default = true; + description = "veilid-server will respond to Python and other JSON client requests."; + }; + ipc_directory = mkOption { + type = types.str; + default = "${dataDir}/ipc"; + description = "IPC directory where file sockets are stored."; + }; + }; + logging = { + system = { + enabled = mkOption { + type = types.bool; + default = true; + description = "Events of type 'system' will be logged."; + }; + level = mkOption { + type = types.str; + default = "info"; + example = "debug"; + description = "The minimum priority of system events to be logged."; + }; + }; + terminal = { + enabled = mkOption { + type = types.bool; + default = false; + description = "Events of type 'terminal' will be logged."; + }; + level = mkOption { + type = types.str; + default = "info"; + example = "debug"; + description = "The minimum priority of terminal events to be logged."; + }; + }; + api = { + enabled = mkOption { + type = types.bool; + default = false; + description = "Events of type 'api' will be logged."; + }; + level = mkOption { + type = types.str; + default = "info"; + example = "debug"; + description = "The minimum priority of api events to be logged."; + }; + }; + }; + core = { + capabilities = { + disable = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "APPM" ]; + description = "A list of capabilities to disable (for example, DHTV to say you cannot store DHT information)."; + }; + }; + protected_store = { + allow_insecure_fallback = mkOption { + type = types.bool; + default = true; + description = "If we can't use system-provided secure storage, should we proceed anyway?"; + }; + always_use_insecure_storage = mkOption { + type = types.bool; + default = true; + description = "Should we bypass any attempt to use system-provided secure storage?"; + }; + directory = mkOption { + type = types.str; + default = "${dataDir}/protected_store"; + description = "The filesystem directory to store your protected store in."; + }; + }; + table_store = { + directory = mkOption { + type = types.str; + default = "${dataDir}/table_store"; + description = "The filesystem directory to store your table store within."; + }; + }; + block_store = { + directory = mkOption { + type = types.nullOr types.str; + default = "${dataDir}/block_store"; + description = "The filesystem directory to store blocks for the block store."; + }; + }; + network = { + routing_table = { + bootstrap = mkOption { + type = types.listOf types.str; + default = [ "bootstrap.veilid.net" ]; + description = "Host name of existing well-known Veilid bootstrap servers for the network to connect to."; + }; + node_id = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Base64-encoded public key for the node, used as the node's ID."; + }; + }; + dht = { + min_peer_count = mkOption { + type = types.number; + default = 20; + description = "Minimum number of nodes to keep in the peer table."; + }; + }; + upnp = mkOption { + type = types.bool; + default = true; + description = "Should the app try to improve its incoming network connectivity using UPnP?"; + }; + detect_address_changes = mkOption { + type = types.bool; + default = true; + description = "Should veilid-core detect and notify on network address changes?"; + }; + }; + }; + }; + }; + }; + }; + + meta.maintainers = with maintainers; [ figboy9 ]; +} diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index b068f2227310..4fec023a2368 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -45,6 +45,8 @@ let "update_config=1" ]) ++ [ "pmf=1" ] + ++ optional (cfg.secretsFile != null) + "ext_password_backend=file:${cfg.secretsFile}" ++ optional cfg.scanOnLowSignal ''bgscan="simple:30:-70:3600"'' ++ optional (cfg.extraConfig != "") cfg.extraConfig); @@ -56,8 +58,6 @@ let if configIsGenerated then pkgs.writeText "wpa_supplicant.conf" generatedConfig else "/etc/wpa_supplicant.conf"; - # the config file with environment variables replaced - finalConfig = ''"$RUNTIME_DIRECTORY"/wpa_supplicant.conf''; # Creates a network block for wpa_supplicant.conf mkNetwork = opts: @@ -90,8 +90,8 @@ let let deviceUnit = optional (iface != null) "sys-subsystem-net-devices-${utils.escapeSystemdPath iface}.device"; configStr = if cfg.allowAuxiliaryImperativeNetworks - then "-c /etc/wpa_supplicant.conf -I ${finalConfig}" - else "-c ${finalConfig}"; + then "-c /etc/wpa_supplicant.conf -I ${configFile}" + else "-c ${configFile}"; in { description = "WPA Supplicant instance" + optionalString (iface != null) " for interface ${iface}"; @@ -109,8 +109,6 @@ let serviceConfig.UMask = "066"; serviceConfig.RuntimeDirectory = "wpa_supplicant"; serviceConfig.RuntimeDirectoryMode = "700"; - serviceConfig.EnvironmentFile = mkIf (cfg.environmentFile != null) - (builtins.toString cfg.environmentFile); script = '' @@ -125,21 +123,6 @@ let touch /etc/wpa_supplicant.conf ''} - # substitute environment variables - if [ -f "${configFile}" ]; then - ${pkgs.gawk}/bin/awk '{ - for(varname in ENVIRON) { - find = "@"varname"@" - repl = ENVIRON[varname] - if (i = index($0, find)) - $0 = substr($0, 1, i-1) repl substr($0, i+length(find)) - } - print - }' "${configFile}" > ${finalConfig} - else - touch ${finalConfig} - fi - iface_args="-s ${optionalString cfg.dbusControlled "-u"} -D${cfg.driver} ${configStr}" ${if iface == null then '' @@ -231,36 +214,34 @@ in { ''; }; - environmentFile = mkOption { + secretsFile = mkOption { type = types.nullOr types.path; default = null; - example = "/run/secrets/wireless.env"; + example = "/run/secrets/wireless.conf"; description = '' File consisting of lines of the form `varname=value` to define variables for the wireless configuration. - See section "EnvironmentFile=" in {manpage}`systemd.exec(5)` for a syntax reference. - Secrets (PSKs, passwords, etc.) can be provided without adding them to - the world-readable Nix store by defining them in the environment file and - referring to them in option {option}`networking.wireless.networks` - with the syntax `@varname@`. Example: + the world-readable Nix store by defining them in the secrets file and + referring to them in option [](#opt-networking.wireless.networks) + with the syntax `ext:secretname`. Example: ``` - # content of /run/secrets/wireless.env - PSK_HOME=mypassword - PASS_WORK=myworkpassword - ``` + # content of /run/secrets/wireless.conf + psk_home=mypassword + psk_other=6a381cea59c7a2d6b30736ba0e6f397f7564a044bcdb7a327a1d16a1ed91b327 + pass_work=myworkpassword - ``` # wireless-related configuration - networking.wireless.environmentFile = "/run/secrets/wireless.env"; + networking.wireless.secretsFile = "/run/secrets/wireless.conf"; networking.wireless.networks = { - home.psk = "@PSK_HOME@"; + home.pskRaw = "ext:psk_home"; + other.pskRaw = "ext:psk_other"; work.auth = ''' eap=PEAP identity="my-user@example.com" - password="@PASS_WORK@" + password=ext:pass_work '''; }; ``` @@ -271,15 +252,16 @@ in { type = types.attrsOf (types.submodule { options = { psk = mkOption { - type = types.nullOr types.str; + type = types.nullOr (types.strMatching "[[:print:]]{8,63}"); default = null; description = '' The network's pre-shared key in plaintext defaulting to being a network without any authentication. ::: {.warning} - Be aware that this will be written to the nix store - in plaintext! Use an environment variable instead. + Be aware that this will be written to the Nix store + in plaintext! Use {var}`pskRaw` with an external + reference to keep it safe. ::: ::: {.note} @@ -289,19 +271,28 @@ in { }; pskRaw = mkOption { - type = types.nullOr types.str; + type = types.nullOr + (types.strMatching "([[:xdigit:]]{64})|(ext:[^=]+)"); default = null; + example = "ext:name_of_the_secret_here"; description = '' - The network's pre-shared key in hex defaulting - to being a network without any authentication. + Either the raw pre-shared key in hexadecimal format + or the name of the secret (as defined inside + [](#opt-networking.wireless.secretsFile) and prefixed + with `ext:`) containing the network pre-shared key. ::: {.warning} - Be aware that this will be written to the nix store - in plaintext! Use an environment variable instead. + Be aware that this will be written to the Nix store + in plaintext! Always use an external reference. ::: ::: {.note} - Mutually exclusive with {var}`psk`. + The external secret can be either the plaintext + passphrase or the raw pre-shared key. + ::: + + ::: {.note} + Mutually exclusive with {var}`psk` and {var}`auth`. ::: ''; }; @@ -354,22 +345,21 @@ in { example = '' eap=PEAP identity="user@example.com" - password="@EXAMPLE_PASSWORD@" + password=ext:example_password ''; description = '' - Use this option to configure advanced authentication methods like EAP. - See - {manpage}`wpa_supplicant.conf(5)` - for example configurations. + Use this option to configure advanced authentication methods + like EAP. See {manpage}`wpa_supplicant.conf(5)` for example + configurations. ::: {.warning} - Be aware that this will be written to the nix store - in plaintext! Use an environment variable for secrets. + Be aware that this will be written to the Nix store + in plaintext! Use an external reference like + `ext:secretname` for secrets. ::: ::: {.note} - Mutually exclusive with {var}`psk` and - {var}`pskRaw`. + Mutually exclusive with {var}`psk` and {var}`pskRaw`. ::: ''; }; @@ -393,13 +383,14 @@ in { type = types.nullOr types.int; default = null; description = '' - By default, all networks will get same priority group (0). If some of the - networks are more desirable, this field can be used to change the order in - which wpa_supplicant goes through the networks when selecting a BSS. The - priority groups will be iterated in decreasing priority (i.e., the larger the - priority value, the sooner the network is matched against the scan results). - Within each priority group, networks will be selected based on security - policy, signal strength, etc. + By default, all networks will get same priority group (0). If + some of the networks are more desirable, this field can be used + to change the order in which wpa_supplicant goes through the + networks when selecting a BSS. The priority groups will be + iterated in decreasing priority (i.e., the larger the priority + value, the sooner the network is matched against the scan + results). Within each priority group, networks will be selected + based on security policy, signal strength, etc. ''; }; @@ -411,9 +402,7 @@ in { ''; description = '' Extra configuration lines appended to the network block. - See - {manpage}`wpa_supplicant.conf(5)` - for available options. + See {manpage}`wpa_supplicant.conf(5)` for available options. ''; }; @@ -432,7 +421,7 @@ in { }; echelon = { # safe version of the above: read PSK from the - psk = "@PSK_ECHELON@"; # variable PSK_ECHELON, defined in environmentFile, + pskRaw = "ext:psk_echelon"; # variable psk_echelon, defined in secretsFile, }; # this won't leak into /nix/store "echelon's AP" = { # SSID with spaces and/or special characters @@ -493,6 +482,31 @@ in { }; }; + imports = [ + (mkRemovedOptionModule [ "networking" "wireless" "environmentFile" ] + '' + Secrets are now handled by the `networking.wireless.secretsFile` and + `networking.wireless.networks..pskRaw` options. + The change is motivated by a mechanism recently added by wpa_supplicant + itself to separate secrets from configuration, making the previous + method obsolete. + + The syntax of the `secretsFile` is the same as before, except the + values are interpreted literally, unlike environment variables. + To update, remove quotes or character escapes, if necessary, and + apply the following changes to your configuration: + { + home.psk = "@psk_home@"; → home.pskRaw = "ext:psk_home"; + other.pskRaw = "@psk_other@"; → other.pskRaw = "ext:psk_other"; + work.auth = ''' + eap=PEAP + identity="my-user@example.com" + password=@pass_work@ → password=ext:pass_work + '''; + } + '') + ]; + config = mkIf cfg.enable { assertions = flip mapAttrsToList cfg.networks (name: cfg: { assertion = with cfg; count (x: x != null) [ psk pskRaw auth ] <= 1; diff --git a/nixos/modules/services/networking/wstunnel.nix b/nixos/modules/services/networking/wstunnel.nix index 439e1f8ea9b5..bf56858a190f 100644 --- a/nixos/modules/services/networking/wstunnel.nix +++ b/nixos/modules/services/networking/wstunnel.nix @@ -1,7 +1,8 @@ -{ config -, lib -, pkgs -, ... +{ + config, + lib, + pkgs, + ... }: let @@ -29,10 +30,9 @@ let package = lib.mkPackageOption pkgs "wstunnel" { }; - autoStart = - lib.mkEnableOption "starting this wstunnel instance automatically" // { - default = true; - }; + autoStart = lib.mkEnableOption "starting this wstunnel instance automatically" // { + default = true; + }; extraArgs = lib.mkOption { description = '' @@ -48,6 +48,13 @@ let }; }; + # The original argument name `websocketPingFrequency` is a misnomer, as the frequency is the inverse of the interval. + websocketPingInterval = lib.mkOption { + description = "Frequency at which the client will send websocket ping to the server."; + type = lib.types.nullOr lib.types.ints.unsigned; + default = null; + }; + loggingLevel = lib.mkOption { description = '' Passed to --log-lvl @@ -75,192 +82,191 @@ let }; }; - serverSubmodule = { config, ... }: { - options = commonOptions // { - listen = lib.mkOption { - description = '' - Address and port to listen on. - Setting the port to a value below 1024 will also give the process - the required `CAP_NET_BIND_SERVICE` capability. - ''; - type = lib.types.submodule hostPortSubmodule; - default = { - host = "0.0.0.0"; - port = if config.enableHTTPS then 443 else 80; - }; - defaultText = lib.literalExpression '' - { + serverSubmodule = + { config, ... }: + { + options = commonOptions // { + listen = lib.mkOption { + description = '' + Address and port to listen on. + Setting the port to a value below 1024 will also give the process + the required `CAP_NET_BIND_SERVICE` capability. + ''; + type = lib.types.submodule hostPortSubmodule; + default = { host = "0.0.0.0"; - port = if enableHTTPS then 443 else 80; - } - ''; - }; + port = if config.enableHTTPS then 443 else 80; + }; + defaultText = lib.literalExpression '' + { + host = "0.0.0.0"; + port = if enableHTTPS then 443 else 80; + } + ''; + }; - restrictTo = lib.mkOption { - description = '' - Accepted traffic will be forwarded only to this service. - ''; - type = lib.types.listOf (lib.types.submodule hostPortSubmodule); - default = [ ]; - example = [{ - host = "127.0.0.1"; - port = 51820; - }]; - }; + restrictTo = lib.mkOption { + description = '' + Accepted traffic will be forwarded only to this service. + ''; + type = lib.types.listOf (lib.types.submodule hostPortSubmodule); + default = [ ]; + example = [ + { + host = "127.0.0.1"; + port = 51820; + } + ]; + }; - enableHTTPS = lib.mkOption { - description = "Use HTTPS for the tunnel server."; - type = lib.types.bool; - default = true; - }; + enableHTTPS = lib.mkOption { + description = "Use HTTPS for the tunnel server."; + type = lib.types.bool; + default = true; + }; - tlsCertificate = lib.mkOption { - description = '' - TLS certificate to use instead of the hardcoded one in case of HTTPS connections. - Use together with `tlsKey`. - ''; - type = lib.types.nullOr lib.types.path; - default = null; - example = "/var/lib/secrets/cert.pem"; - }; + tlsCertificate = lib.mkOption { + description = '' + TLS certificate to use instead of the hardcoded one in case of HTTPS connections. + Use together with `tlsKey`. + ''; + type = lib.types.nullOr lib.types.path; + default = null; + example = "/var/lib/secrets/cert.pem"; + }; - tlsKey = lib.mkOption { - description = '' - TLS key to use instead of the hardcoded on in case of HTTPS connections. - Use together with `tlsCertificate`. - ''; - type = lib.types.nullOr lib.types.path; - default = null; - example = "/var/lib/secrets/key.pem"; - }; + tlsKey = lib.mkOption { + description = '' + TLS key to use instead of the hardcoded on in case of HTTPS connections. + Use together with `tlsCertificate`. + ''; + type = lib.types.nullOr lib.types.path; + default = null; + example = "/var/lib/secrets/key.pem"; + }; - useACMEHost = lib.mkOption { - description = '' - Use a certificate generated by the NixOS ACME module for the given host. - Note that this will not generate a new certificate - you will need to do so with `security.acme.certs`. - ''; - type = lib.types.nullOr lib.types.str; - default = null; - example = "example.com"; + useACMEHost = lib.mkOption { + description = '' + Use a certificate generated by the NixOS ACME module for the given host. + Note that this will not generate a new certificate - you will need to do so with `security.acme.certs`. + ''; + type = lib.types.nullOr lib.types.str; + default = null; + example = "example.com"; + }; }; }; - }; - clientSubmodule = { config, ... }: { - options = commonOptions // { - connectTo = lib.mkOption { - description = "Server address and port to connect to."; - type = lib.types.str; - example = "https://wstunnel.server.com:8443"; - }; + clientSubmodule = + { config, ... }: + { + options = commonOptions // { + connectTo = lib.mkOption { + description = "Server address and port to connect to."; + type = lib.types.str; + example = "https://wstunnel.server.com:8443"; + }; - localToRemote = lib.mkOption { - description = ''Listen on local and forwards traffic from remote.''; - type = lib.types.listOf (lib.types.str); - default = [ ]; - example = [ - "tcp://1212:google.com:443" - "unix:///tmp/wstunnel.sock:g.com:443" - ]; - }; + localToRemote = lib.mkOption { + description = ''Listen on local and forwards traffic from remote.''; + type = lib.types.listOf (lib.types.str); + default = [ ]; + example = [ + "tcp://1212:google.com:443" + "unix:///tmp/wstunnel.sock:g.com:443" + ]; + }; - remoteToLocal = lib.mkOption { - description = "Listen on remote and forwards traffic from local. Only tcp is supported"; - type = lib.types.listOf lib.types.str; - default = [ ]; - example = [ - "tcp://1212:google.com:443" - "unix://wstunnel.sock:g.com:443" - ]; - }; + remoteToLocal = lib.mkOption { + description = "Listen on remote and forwards traffic from local. Only tcp is supported"; + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ + "tcp://1212:google.com:443" + "unix://wstunnel.sock:g.com:443" + ]; + }; - addNetBind = lib.mkEnableOption "Whether add CAP_NET_BIND_SERVICE to the tunnel service, this should be enabled if you want to bind port < 1024"; + addNetBind = lib.mkEnableOption "Whether add CAP_NET_BIND_SERVICE to the tunnel service, this should be enabled if you want to bind port < 1024"; - httpProxy = lib.mkOption { - description = '' - Proxy to use to connect to the wstunnel server (`USER:PASS@HOST:PORT`). + httpProxy = lib.mkOption { + description = '' + Proxy to use to connect to the wstunnel server (`USER:PASS@HOST:PORT`). - ::: {.warning} - Passwords specified here will be world-readable in the Nix store! - To pass a password to the service, point the `environmentFile` option - to a file containing `PROXY_PASSWORD=` and set - this option to `:$PROXY_PASSWORD@:`. - Note however that this will also locally leak the passwords at - runtime via e.g. /proc//cmdline. - ::: - ''; - type = lib.types.nullOr lib.types.str; - default = null; - }; + ::: {.warning} + Passwords specified here will be world-readable in the Nix store! + To pass a password to the service, point the `environmentFile` option + to a file containing `PROXY_PASSWORD=` and set + this option to `:$PROXY_PASSWORD@:`. + Note however that this will also locally leak the passwords at + runtime via e.g. /proc//cmdline. + ::: + ''; + type = lib.types.nullOr lib.types.str; + default = null; + }; - soMark = lib.mkOption { - description = '' - Mark network packets with the SO_MARK sockoption with the specified value. - Setting this option will also enable the required `CAP_NET_ADMIN` capability - for the systemd service. - ''; - type = lib.types.nullOr lib.types.ints.unsigned; - default = null; - }; + soMark = lib.mkOption { + description = '' + Mark network packets with the SO_MARK sockoption with the specified value. + Setting this option will also enable the required `CAP_NET_ADMIN` capability + for the systemd service. + ''; + type = lib.types.nullOr lib.types.ints.unsigned; + default = null; + }; - upgradePathPrefix = lib.mkOption { - description = '' - Use a specific HTTP path prefix that will show up in the upgrade - request to the `wstunnel` server. - Useful when running `wstunnel` behind a reverse proxy. - ''; - type = lib.types.nullOr lib.types.str; - default = null; - example = "wstunnel"; - }; + upgradePathPrefix = lib.mkOption { + description = '' + Use a specific HTTP path prefix that will show up in the upgrade + request to the `wstunnel` server. + Useful when running `wstunnel` behind a reverse proxy. + ''; + type = lib.types.nullOr lib.types.str; + default = null; + example = "wstunnel"; + }; - tlsSNI = lib.mkOption { - description = "Use this as the SNI while connecting via TLS. Useful for circumventing hostname-based firewalls."; - type = lib.types.nullOr lib.types.str; - default = null; - }; + tlsSNI = lib.mkOption { + description = "Use this as the SNI while connecting via TLS. Useful for circumventing hostname-based firewalls."; + type = lib.types.nullOr lib.types.str; + default = null; + }; - tlsVerifyCertificate = lib.mkOption { - description = "Whether to verify the TLS certificate of the server. It might be useful to set this to `false` when working with the `tlsSNI` option."; - type = lib.types.bool; - default = true; - }; + tlsVerifyCertificate = lib.mkOption { + description = "Whether to verify the TLS certificate of the server. It might be useful to set this to `false` when working with the `tlsSNI` option."; + type = lib.types.bool; + default = true; + }; - # The original argument name `websocketPingFrequency` is a misnomer, as the frequency is the inverse of the interval. - websocketPingInterval = lib.mkOption { - description = "Frequency at which the client will send websocket ping to the server."; - type = lib.types.nullOr lib.types.ints.unsigned; - default = null; - }; + upgradeCredentials = lib.mkOption { + description = '' + Use these credentials to authenticate during the HTTP upgrade request + (Basic authorization type, `USER:[PASS]`). - upgradeCredentials = lib.mkOption { - description = '' - Use these credentials to authenticate during the HTTP upgrade request - (Basic authorization type, `USER:[PASS]`). - - ::: {.warning} - Passwords specified here will be world-readable in the Nix store! - To pass a password to the service, point the `environmentFile` option - to a file containing `HTTP_PASSWORD=` and set this - option to `:$HTTP_PASSWORD`. - Note however that this will also locally leak the passwords at runtime - via e.g. /proc//cmdline. - ::: - ''; - type = lib.types.nullOr lib.types.str; - default = null; - }; + ::: {.warning} + Passwords specified here will be world-readable in the Nix store! + To pass a password to the service, point the `environmentFile` option + to a file containing `HTTP_PASSWORD=` and set this + option to `:$HTTP_PASSWORD`. + Note however that this will also locally leak the passwords at runtime + via e.g. /proc//cmdline. + ::: + ''; + type = lib.types.nullOr lib.types.str; + default = null; + }; - customHeaders = lib.mkOption { - description = "Custom HTTP headers to send during the upgrade request."; - type = lib.types.attrsOf lib.types.str; - default = { }; - example = { - "X-Some-Header" = "some-value"; + customHeaders = lib.mkOption { + description = "Custom HTTP headers to send during the upgrade request."; + type = lib.types.attrsOf lib.types.str; + default = { }; + example = { + "X-Some-Header" = "some-value"; + }; }; }; }; - }; generateServerUnit = name: serverCfg: { name = "wstunnel-server-${name}"; @@ -270,22 +276,25 @@ let in { description = "wstunnel server - ${name}"; - requires = [ "network.target" "network-online.target" ]; - after = [ "network.target" "network-online.target" ]; + requires = [ + "network.target" + "network-online.target" + ]; + after = [ + "network.target" + "network-online.target" + ]; wantedBy = lib.optional serverCfg.autoStart "multi-user.target"; environment.RUST_LOG = serverCfg.loggingLevel; serviceConfig = { Type = "exec"; - EnvironmentFile = - lib.optional (serverCfg.environmentFile != null) serverCfg.environmentFile; + EnvironmentFile = lib.optional (serverCfg.environmentFile != null) serverCfg.environmentFile; DynamicUser = true; - SupplementaryGroups = - lib.optional (serverCfg.useACMEHost != null) certConfig.group; + SupplementaryGroups = lib.optional (serverCfg.useACMEHost != null) certConfig.group; PrivateTmp = true; - AmbientCapabilities = - lib.optionals (serverCfg.listen.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; + AmbientCapabilities = lib.optionals (serverCfg.listen.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; NoNewPrivileges = true; RestrictNamespaces = "uts ipc pid user cgroup"; ProtectSystem = "strict"; @@ -305,19 +314,28 @@ let script = with serverCfg; '' ${lib.getExe package} \ server \ - ${lib.cli.toGNUCommandLineShell { } ( - lib.recursiveUpdate - { - restrict-to = map hostPortToString restrictTo; - tls-certificate = if useACMEHost != null - then "${certConfig.directory}/fullchain.pem" - else "${tlsCertificate}"; - tls-private-key = if useACMEHost != null - then "${certConfig.directory}/key.pem" - else "${tlsKey}"; - } - extraArgs - )} \ + ${ + lib.cli.toGNUCommandLineShell { } ( + lib.recursiveUpdate { + restrict-to = map hostPortToString restrictTo; + websocket-ping-frequency-sec = websocketPingInterval; + tls-certificate = + if !enableHTTPS then + null + else if useACMEHost != null then + "${certConfig.directory}/fullchain.pem" + else + "${tlsCertificate}"; + tls-private-key = + if !enableHTTPS then + null + else if useACMEHost != null then + "${certConfig.directory}/key.pem" + else + "${tlsKey}"; + } extraArgs + ) + } \ ${lib.escapeShellArg "${if enableHTTPS then "wss" else "ws"}://${hostPortToString listen}"} ''; }; @@ -327,21 +345,26 @@ let name = "wstunnel-client-${name}"; value = { description = "wstunnel client - ${name}"; - requires = [ "network.target" "network-online.target" ]; - after = [ "network.target" "network-online.target" ]; + requires = [ + "network.target" + "network-online.target" + ]; + after = [ + "network.target" + "network-online.target" + ]; wantedBy = lib.optional clientCfg.autoStart "multi-user.target"; environment.RUST_LOG = clientCfg.loggingLevel; serviceConfig = { Type = "exec"; - EnvironmentFile = - lib.optional (clientCfg.environmentFile != null) clientCfg.environmentFile; + EnvironmentFile = lib.optional (clientCfg.environmentFile != null) clientCfg.environmentFile; DynamicUser = true; PrivateTmp = true; AmbientCapabilities = - (lib.optionals clientCfg.addNetBind [ "CAP_NET_BIND_SERVICE" ]) ++ - (lib.optionals (clientCfg.soMark != null) [ "CAP_NET_ADMIN" ]); + (lib.optionals clientCfg.addNetBind [ "CAP_NET_BIND_SERVICE" ]) + ++ (lib.optionals (clientCfg.soMark != null) [ "CAP_NET_ADMIN" ]); NoNewPrivileges = true; RestrictNamespaces = "uts ipc pid user cgroup"; ProtectSystem = "strict"; @@ -361,22 +384,22 @@ let script = with clientCfg; '' ${lib.getExe package} \ client \ - ${lib.cli.toGNUCommandLineShell { } ( - lib.recursiveUpdate - { - local-to-remote = localToRemote; - remote-to-local = remoteToLocal; - http-headers = lib.mapAttrsToList (n: v: "${n}:${v}") customHeaders; - http-proxy = httpProxy; - socket-so-mark = soMark; - http-upgrade-path-prefix = upgradePathPrefix; - tls-sni-override = tlsSNI; - tls-verify-certificate = tlsVerifyCertificate; - websocket-ping-frequency-sec = websocketPingInterval; - http-upgrade-credentials = upgradeCredentials; - } - extraArgs - )} \ + ${ + lib.cli.toGNUCommandLineShell { } ( + lib.recursiveUpdate { + local-to-remote = localToRemote; + remote-to-local = remoteToLocal; + http-headers = lib.mapAttrsToList (n: v: "${n}:${v}") customHeaders; + http-proxy = httpProxy; + socket-so-mark = soMark; + http-upgrade-path-prefix = upgradePathPrefix; + tls-sni-override = tlsSNI; + tls-verify-certificate = tlsVerifyCertificate; + websocket-ping-frequency-sec = websocketPingInterval; + http-upgrade-credentials = upgradeCredentials; + } extraArgs + ) + } \ ${lib.escapeShellArg connectTo} ''; }; @@ -399,10 +422,12 @@ in enableHTTPS = true; tlsCertificate = "/var/lib/secrets/fullchain.pem"; tlsKey = "/var/lib/secrets/key.pem"; - restrictTo = [{ - host = "127.0.0.1"; - port = 51820; - }]; + restrictTo = [ + { + host = "127.0.0.1"; + port = 51820; + } + ]; }; }; }; @@ -429,40 +454,40 @@ in config = lib.mkIf cfg.enable { systemd.services = - (lib.mapAttrs' generateServerUnit (lib.filterAttrs (n: v: v.enable) cfg.servers)) // - (lib.mapAttrs' generateClientUnit (lib.filterAttrs (n: v: v.enable) cfg.clients)); + (lib.mapAttrs' generateServerUnit (lib.filterAttrs (n: v: v.enable) cfg.servers)) + // (lib.mapAttrs' generateClientUnit (lib.filterAttrs (n: v: v.enable) cfg.clients)); assertions = - (lib.mapAttrsToList - (name: serverCfg: { - assertion = - !(serverCfg.useACMEHost != null && serverCfg.tlsCertificate != null); - message = '' - Options services.wstunnel.servers."${name}".useACMEHost and services.wstunnel.servers."${name}".{tlsCertificate, tlsKey} are mutually exclusive. - ''; - }) - cfg.servers) ++ + (lib.mapAttrsToList (name: serverCfg: { + assertion = !(serverCfg.useACMEHost != null && serverCfg.tlsCertificate != null); + message = '' + Options services.wstunnel.servers."${name}".useACMEHost and services.wstunnel.servers."${name}".{tlsCertificate, tlsKey} are mutually exclusive. + ''; + }) cfg.servers) + ++ - (lib.mapAttrsToList - (name: serverCfg: { + (lib.mapAttrsToList (name: serverCfg: { assertion = - (serverCfg.tlsCertificate == null && serverCfg.tlsKey == null) || - (serverCfg.tlsCertificate != null && serverCfg.tlsKey != null); + (serverCfg.tlsCertificate == null && serverCfg.tlsKey == null) + || (serverCfg.tlsCertificate != null && serverCfg.tlsKey != null); message = '' services.wstunnel.servers."${name}".tlsCertificate and services.wstunnel.servers."${name}".tlsKey need to be set together. ''; - }) - cfg.servers) ++ + }) cfg.servers) + ++ - (lib.mapAttrsToList - (name: clientCfg: { + (lib.mapAttrsToList (name: clientCfg: { assertion = !(clientCfg.localToRemote == [ ] && clientCfg.remoteToLocal == [ ]); message = '' Either one of services.wstunnel.clients."${name}".localToRemote or services.wstunnel.clients."${name}".remoteToLocal must be set. ''; - }) - cfg.clients); + }) cfg.clients); }; - meta.maintainers = with lib.maintainers; [ alyaeanyx rvdp neverbehave ]; + meta.maintainers = with lib.maintainers; [ + alyaeanyx + raylas + rvdp + neverbehave + ]; } diff --git a/nixos/modules/services/networking/yggdrasil.nix b/nixos/modules/services/networking/yggdrasil.nix index c1c952adac39..0fb51400d666 100644 --- a/nixos/modules/services/networking/yggdrasil.nix +++ b/nixos/modules/services/networking/yggdrasil.nix @@ -1,6 +1,8 @@ { config, lib, pkgs, ... }: -with lib; + let + inherit (lib) mkIf mkOption; + inherit (lib.types) nullOr path bool listOf str; keysPath = "/var/lib/yggdrasil/keys.json"; cfg = config.services.yggdrasil; @@ -11,14 +13,14 @@ let in { imports = [ - (mkRenamedOptionModule + (lib.mkRenamedOptionModule [ "services" "yggdrasil" "config" ] [ "services" "yggdrasil" "settings" ]) ]; - options = with types; { + options = { services.yggdrasil = { - enable = mkEnableOption "the yggdrasil system service"; + enable = lib.mkEnableOption "the yggdrasil system service"; settings = mkOption { type = format.type; @@ -73,7 +75,7 @@ in }; group = mkOption { - type = types.nullOr types.str; + type = nullOr str; default = null; example = "wheel"; description = "Group to grant access to the Yggdrasil control socket. If `null`, only root can access the socket."; @@ -108,9 +110,9 @@ in ''; }; - package = mkPackageOption pkgs "yggdrasil" { }; + package = lib.mkPackageOption pkgs "yggdrasil" { }; - persistentKeys = mkEnableOption '' + persistentKeys = lib.mkEnableOption '' persistent keys. If enabled then keys will be generated once and Yggdrasil will retain the same IPv6 address when the service is restarted. Keys are stored at ${keysPath} @@ -232,6 +234,6 @@ in ); meta = { doc = ./yggdrasil.md; - maintainers = with lib.maintainers; [ gazally ehmry ]; + maintainers = with lib.maintainers; [ gazally ehmry nagy ]; }; } diff --git a/nixos/modules/services/networking/zapret.nix b/nixos/modules/services/networking/zapret.nix new file mode 100644 index 000000000000..53309b046931 --- /dev/null +++ b/nixos/modules/services/networking/zapret.nix @@ -0,0 +1,159 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.services.zapret; + + whitelist = lib.optionalString ( + cfg.whitelist != null + ) "--hostlist ${pkgs.writeText "zapret-whitelist" (lib.concatStringsSep "\n" cfg.whitelist)}"; + + blacklist = + lib.optionalString (cfg.blacklist != null) + "--hostlist-exclude ${pkgs.writeText "zapret-blacklist" (lib.concatStringsSep "\n" cfg.blacklist)}"; + + ports = if cfg.httpSupport then "80,443" else "443"; +in +{ + options.services.zapret = { + enable = lib.mkEnableOption "the Zapret DPI bypass service."; + package = lib.mkPackageOption pkgs "zapret" { }; + params = lib.mkOption { + default = [ ]; + type = with lib.types; listOf str; + example = '' + [ + "--dpi-desync=fake,disorder2" + "--dpi-desync-ttl=1" + "--dpi-desync-autottl=2" + ]; + ''; + description = '' + Specify the bypass parameters for Zapret binary. + There are no universal parameters as they vary between different networks, so you'll have to find them yourself. + + This can be done by running the `blockcheck` binary from zapret package, i.e. `nix-shell -p zapret --command blockcheck`. + It'll try different params and then tell you which params are working for your network. + ''; + }; + whitelist = lib.mkOption { + default = null; + type = with lib.types; nullOr (listOf str); + example = '' + [ + "youtube.com" + "googlevideo.com" + "ytimg.com" + "youtu.be" + ] + ''; + description = '' + Specify a list of domains to bypass. All other domains will be ignored. + You can specify either whitelist or blacklist, but not both. + If neither are specified, then bypass all domains. + + It is recommended to specify the whitelist. This will make sure that other resources won't be affected by this service. + ''; + }; + blacklist = lib.mkOption { + default = null; + type = with lib.types; nullOr (listOf str); + example = '' + [ + "example.com" + ] + ''; + description = '' + Specify a list of domains NOT to bypass. All other domains will be bypassed. + You can specify either whitelist or blacklist, but not both. + If neither are specified, then bypass all domains. + ''; + }; + qnum = lib.mkOption { + default = 200; + type = lib.types.int; + description = '' + Routing queue number. + Only change this if you already use the default queue number somewhere else. + ''; + }; + configureFirewall = lib.mkOption { + default = true; + type = lib.types.bool; + description = '' + Whether to setup firewall routing so that system http(s) traffic is forwarded via this service. + Disable if you want to set it up manually. + ''; + }; + httpSupport = lib.mkOption { + default = true; + type = lib.types.bool; + description = '' + Whether to route http traffic on port 80. + Http bypass rarely works and you might want to disable it if you don't utilise http connections. + ''; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + assertions = [ + { + assertion = (cfg.whitelist == null) || (cfg.blacklist == null); + message = "Can't specify both whitelist and blacklist."; + } + { + assertion = (builtins.length cfg.params) != 0; + message = "You have to specify zapret parameters. See the params option's description."; + } + ]; + + systemd.services.zapret = { + description = "DPI bypass service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + ExecStart = "${cfg.package}/bin/nfqws --pidfile=/run/nfqws.pid ${lib.concatStringsSep " " cfg.params} ${whitelist} ${blacklist} --qnum=${toString cfg.qnum}"; + Type = "simple"; + PIDFile = "/run/nfqws.pid"; + Restart = "always"; + RuntimeMaxSec = "1h"; # This service loves to crash silently or cause network slowdowns. It also restarts instantly. In my experience restarting it hourly provided the best experience. + + # hardening + DevicePolicy = "closed"; + KeyringMode = "private"; + PrivateTmp = true; + PrivateMounts = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + ProtectProc = "invisible"; + RemoveIPC = true; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + }; + }; + } + + # Route system traffic via service for specified ports. + (lib.mkIf cfg.configureFirewall { + networking.firewall.extraCommands = '' + iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports ${ports} -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num ${toString cfg.qnum} --queue-bypass + ''; + }) + ] + ); + + meta.maintainers = with lib.maintainers; [ + voronind + nishimara + ]; +} diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index 668bccab2e2d..a1fb0b3951e4 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -9,7 +9,6 @@ let cfg = config.services.printing; cups = cfg.package; - avahiEnabled = config.services.avahi.enable; polkitEnabled = config.security.polkit.enable; additionalBackends = pkgs.runCommand "additional-cups-backends" { @@ -99,7 +98,7 @@ let cupsdFile (writeConf "client.conf" cfg.clientConf) (writeConf "snmp.conf" cfg.snmpConf) - ] ++ optional avahiEnabled browsedFile + ] ++ optional cfg.browsed.enable browsedFile ++ cfg.drivers; pathsToLink = [ "/etc/cups" ]; ignoreCollisions = true; @@ -185,8 +184,8 @@ in type = types.bool; default = false; description = '' - Whether to open the firewall for TCP/UDP ports specified in - listenAdrresses option. + Whether to open the firewall for TCP ports specified in + listenAddresses option. ''; }; @@ -270,6 +269,15 @@ in ''; }; + browsed.enable = mkOption { + type = types.bool; + default = config.services.avahi.enable; + defaultText = literalExpression "config.services.avahi.enable"; + description = '' + Whether to enable the CUPS Remote Printer Discovery (browsed) daemon. + ''; + }; + browsedConf = mkOption { type = types.lines; default = ""; @@ -339,7 +347,7 @@ in services.dbus.packages = [ cups.out ] ++ optional polkitEnabled cups-pk-helper; services.udev.packages = cfg.drivers; - # Allow asswordless printer admin for members of wheel group + # Allow passwordless printer admin for members of wheel group security.polkit.extraConfig = mkIf polkitEnabled '' polkit.addRule(function(action, subject) { if (action.id == "org.opensuse.cupspkhelper.mechanism.all-edit" && @@ -419,7 +427,7 @@ in serviceConfig.PrivateTmp = true; }; - systemd.services.cups-browsed = mkIf avahiEnabled + systemd.services.cups-browsed = mkIf cfg.browsed.enable { description = "CUPS Remote Printer Discovery"; wantedBy = [ "multi-user.target" ]; @@ -485,7 +493,6 @@ in listenPorts = parsePorts cfg.listenAddresses; in mkIf cfg.openFirewall { allowedTCPPorts = listenPorts; - allowedUDPPorts = listenPorts; }; }; diff --git a/nixos/modules/services/security/authelia.nix b/nixos/modules/services/security/authelia.nix index f73c1ce41e5b..1cc137341e11 100644 --- a/nixos/modules/services/security/authelia.nix +++ b/nixos/modules/services/security/authelia.nix @@ -165,10 +165,10 @@ let log = { level = mkOption { - type = types.enum [ "info" "debug" "trace" ]; + type = types.enum [ "trace" "debug" "info" "warn" "error" ]; default = "debug"; example = "info"; - description = "Level of verbosity for logs: info, debug, trace."; + description = "Level of verbosity for logs."; }; format = mkOption { diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix index 90b69df2d4a3..2b0929599723 100644 --- a/nixos/modules/services/security/clamav.nix +++ b/nixos/modules/services/security/clamav.nix @@ -165,7 +165,7 @@ in environment.etc."clamav/clamd.conf".source = clamdConfigFile; systemd.slices.system-clamav = { - description = "ClamAV slice"; + description = "ClamAV Antivirus Slice"; }; systemd.services.clamav-daemon = mkIf cfg.daemon.enable { diff --git a/nixos/modules/services/security/endlessh-go.nix b/nixos/modules/services/security/endlessh-go.nix index 480bfc8cb9ef..9f9225994c7f 100644 --- a/nixos/modules/services/security/endlessh-go.nix +++ b/nixos/modules/services/security/endlessh-go.nix @@ -9,6 +9,8 @@ in options.services.endlessh-go = { enable = mkEnableOption "endlessh-go service"; + package = mkPackageOption pkgs "endlessh-go" { }; + listenAddress = mkOption { type = types.str; default = "0.0.0.0"; @@ -86,7 +88,7 @@ in { Restart = "always"; ExecStart = with cfg; concatStringsSep " " ([ - "${pkgs.endlessh-go}/bin/endlessh-go" + (lib.getExe cfg.package) "-logtostderr" "-host=${listenAddress}" "-port=${toString port}" @@ -131,7 +133,7 @@ in }; networking.firewall.allowedTCPPorts = with cfg; - optionals openFirewall [ port prometheus.port ]; + optionals openFirewall [ port ]; }; meta.maintainers = with maintainers; [ azahi ]; diff --git a/nixos/modules/services/security/kanidm.nix b/nixos/modules/services/security/kanidm.nix index dd86fab09a17..cf2fffac3f5d 100644 --- a/nixos/modules/services/security/kanidm.nix +++ b/nixos/modules/services/security/kanidm.nix @@ -6,10 +6,42 @@ ... }: let + inherit (lib) + any + attrNames + attrValues + concatLines + concatLists + converge + filter + filterAttrs + filterAttrsRecursive + flip + foldl' + getExe + hasInfix + hasPrefix + isStorePath + last + mapAttrsToList + mkEnableOption + mkForce + mkIf + mkMerge + mkOption + mkPackageOption + optional + optionalString + splitString + subtractLists + types + unique + ; + cfg = config.services.kanidm; settingsFormat = pkgs.formats.toml { }; # Remove null values, so we can document optional values that don't end up in the generated TOML file. - filterConfig = lib.converge (lib.filterAttrsRecursive (_: v: v != null)); + filterConfig = converge (filterAttrsRecursive (_: v: v != null)); serverConfigFile = settingsFormat.generate "server.toml" (filterConfig cfg.serverSettings); clientConfigFile = settingsFormat.generate "kanidm-config.toml" (filterConfig cfg.clientSettings); unixConfigFile = settingsFormat.generate "kanidm-unixd.toml" (filterConfig cfg.unixSettings); @@ -22,24 +54,26 @@ let # This makes sure that if e.g. the tls_chain is in the nix store and /nix/store is already in the mount # paths, no new bind mount is added. Adding subpaths caused problems on ofborg. hasPrefixInList = - list: newPath: - lib.any (path: lib.hasPrefix (builtins.toString path) (builtins.toString newPath)) list; - mergePaths = lib.foldl' ( + list: newPath: any (path: hasPrefix (builtins.toString path) (builtins.toString newPath)) list; + mergePaths = foldl' ( merged: newPath: let # If the new path is a prefix to some existing path, we need to filter it out - filteredPaths = lib.filter ( - p: !lib.hasPrefix (builtins.toString newPath) (builtins.toString p) - ) merged; + filteredPaths = filter (p: !hasPrefix (builtins.toString newPath) (builtins.toString p)) merged; # If a prefix of the new path is already in the list, do not add it - filteredNew = lib.optional (!hasPrefixInList filteredPaths newPath) newPath; + filteredNew = optional (!hasPrefixInList filteredPaths newPath) newPath; in filteredPaths ++ filteredNew ) [ ]; defaultServiceConfig = { + # Setting the type to notify enables additional healthchecks, ensuring units + # after and requiring kanidm-* wait for it to complete startup + Type = "notify"; BindReadOnlyPaths = [ "/nix/store" + # For healthcheck notifications + "/run/systemd/notify" "-/etc/resolv.conf" "-/etc/nsswitch.conf" "-/etc/hosts" @@ -84,13 +118,13 @@ let mkPresentOption = what: - lib.mkOption { + mkOption { description = "Whether to ensure that this ${what} is present or absent."; - type = lib.types.bool; + type = types.bool; default = true; }; - filterPresent = lib.filterAttrs (_: v: v.present); + filterPresent = filterAttrs (_: v: v.present); provisionStateJson = pkgs.writeText "provision-state.json" ( builtins.toJSON { inherit (cfg.provision) groups persons systems; } @@ -98,7 +132,7 @@ let # Only recover the admin account if a password should explicitly be provisioned # for the account. Otherwise it is not needed for provisioning. - maybeRecoverAdmin = lib.optionalString (cfg.provision.adminPasswordFile != null) '' + maybeRecoverAdmin = optionalString (cfg.provision.adminPasswordFile != null) '' KANIDM_ADMIN_PASSWORD=$(< ${cfg.provision.adminPasswordFile}) # We always reset the admin account password if a desired password was specified. if ! KANIDM_RECOVER_ACCOUNT_PASSWORD=$KANIDM_ADMIN_PASSWORD ${cfg.package}/bin/kanidmd recover-account -c ${serverConfigFile} admin --from-environment >/dev/null; then @@ -128,7 +162,7 @@ let echo "kanidm provision: Failed to recover admin account" >&2 exit 1 fi - if ! KANIDM_IDM_ADMIN_PASSWORD=$(grep '{"password' <<< "$recover_out" | ${lib.getExe pkgs.jq} -r .password); then + if ! KANIDM_IDM_ADMIN_PASSWORD=$(grep '{"password' <<< "$recover_out" | ${getExe pkgs.jq} -r .password); then echo "$recover_out" >&2 echo "kanidm provision: Failed to parse password for idm_admin account" >&2 exit 1 @@ -140,8 +174,8 @@ let # Wait for the kanidm server to come online count=0 - while ! ${lib.getExe pkgs.curl} -L --silent --max-time 1 --connect-timeout 1 --fail \ - ${lib.optionalString cfg.provision.acceptInvalidCerts "--insecure"} \ + while ! ${getExe pkgs.curl} -L --silent --max-time 1 --connect-timeout 1 --fail \ + ${optionalString cfg.provision.acceptInvalidCerts "--insecure"} \ ${cfg.provision.instanceUrl} >/dev/null do sleep 1 @@ -156,58 +190,58 @@ let ${maybeRecoverAdmin} KANIDM_PROVISION_IDM_ADMIN_TOKEN=$KANIDM_IDM_ADMIN_PASSWORD \ - ${lib.getExe pkgs.kanidm-provision} \ - ${lib.optionalString (!cfg.provision.autoRemove) "--no-auto-remove"} \ - ${lib.optionalString cfg.provision.acceptInvalidCerts "--accept-invalid-certs"} \ + ${getExe pkgs.kanidm-provision} \ + ${optionalString (!cfg.provision.autoRemove) "--no-auto-remove"} \ + ${optionalString cfg.provision.acceptInvalidCerts "--accept-invalid-certs"} \ --url "${cfg.provision.instanceUrl}" \ --state ${provisionStateJson} ''; serverPort = # ipv6: - if lib.hasInfix "]:" cfg.serverSettings.bindaddress then - lib.last (lib.splitString "]:" cfg.serverSettings.bindaddress) + if hasInfix "]:" cfg.serverSettings.bindaddress then + last (splitString "]:" cfg.serverSettings.bindaddress) else # ipv4: - if lib.hasInfix "." cfg.serverSettings.bindaddress then - lib.last (lib.splitString ":" cfg.serverSettings.bindaddress) + if hasInfix "." cfg.serverSettings.bindaddress then + last (splitString ":" cfg.serverSettings.bindaddress) # default is 8443 else "8443"; in { options.services.kanidm = { - enableClient = lib.mkEnableOption "the Kanidm client"; - enableServer = lib.mkEnableOption "the Kanidm server"; - enablePam = lib.mkEnableOption "the Kanidm PAM and NSS integration"; + enableClient = mkEnableOption "the Kanidm client"; + enableServer = mkEnableOption "the Kanidm server"; + enablePam = mkEnableOption "the Kanidm PAM and NSS integration"; - package = lib.mkPackageOption pkgs "kanidm" { }; + package = mkPackageOption pkgs "kanidm" { }; - serverSettings = lib.mkOption { - type = lib.types.submodule { + serverSettings = mkOption { + type = types.submodule { freeformType = settingsFormat.type; options = { - bindaddress = lib.mkOption { + bindaddress = mkOption { description = "Address/port combination the webserver binds to."; example = "[::1]:8443"; - type = lib.types.str; + type = types.str; }; # Should be optional but toml does not accept null - ldapbindaddress = lib.mkOption { + ldapbindaddress = mkOption { description = '' Address and port the LDAP server is bound to. Setting this to `null` disables the LDAP interface. ''; example = "[::1]:636"; default = null; - type = lib.types.nullOr lib.types.str; + type = types.nullOr types.str; }; - origin = lib.mkOption { + origin = mkOption { description = "The origin of your Kanidm instance. Must have https as protocol."; example = "https://idm.example.org"; - type = lib.types.strMatching "^https://.*"; + type = types.strMatching "^https://.*"; }; - domain = lib.mkOption { + domain = mkOption { description = '' The `domain` that Kanidm manages. Must be below or equal to the domain specified in `serverSettings.origin`. @@ -218,58 +252,58 @@ in ''; example = "example.org"; default = null; - type = lib.types.nullOr lib.types.str; + type = types.nullOr types.str; }; - db_path = lib.mkOption { + db_path = mkOption { description = "Path to Kanidm database."; default = "/var/lib/kanidm/kanidm.db"; readOnly = true; - type = lib.types.path; + type = types.path; }; - tls_chain = lib.mkOption { + tls_chain = mkOption { description = "TLS chain in pem format."; - type = lib.types.path; + type = types.path; }; - tls_key = lib.mkOption { + tls_key = mkOption { description = "TLS key in pem format."; - type = lib.types.path; + type = types.path; }; - log_level = lib.mkOption { + log_level = mkOption { description = "Log level of the server."; default = "info"; - type = lib.types.enum [ + type = types.enum [ "info" "debug" "trace" ]; }; - role = lib.mkOption { + role = mkOption { description = "The role of this server. This affects the replication relationship and thereby available features."; default = "WriteReplica"; - type = lib.types.enum [ + type = types.enum [ "WriteReplica" "WriteReplicaNoUI" "ReadOnlyReplica" ]; }; online_backup = { - path = lib.mkOption { + path = mkOption { description = "Path to the output directory for backups."; - type = lib.types.path; + type = types.path; default = "/var/lib/kanidm/backups"; }; - schedule = lib.mkOption { + schedule = mkOption { description = "The schedule for backups in cron format."; - type = lib.types.str; + type = types.str; default = "00 22 * * *"; }; - versions = lib.mkOption { + versions = mkOption { description = '' Number of backups to keep. The default is set to `0`, in order to disable backups by default. ''; - type = lib.types.ints.unsigned; + type = types.ints.unsigned; default = 0; example = 7; }; @@ -285,14 +319,14 @@ in ''; }; - clientSettings = lib.mkOption { - type = lib.types.submodule { + clientSettings = mkOption { + type = types.submodule { freeformType = settingsFormat.type; - options.uri = lib.mkOption { + options.uri = mkOption { description = "Address of the Kanidm server."; example = "http://127.0.0.1:8080"; - type = lib.types.str; + type = types.str; }; }; description = '' @@ -303,20 +337,20 @@ in ''; }; - unixSettings = lib.mkOption { - type = lib.types.submodule { + unixSettings = mkOption { + type = types.submodule { freeformType = settingsFormat.type; options = { - pam_allowed_login_groups = lib.mkOption { + pam_allowed_login_groups = mkOption { description = "Kanidm groups that are allowed to login using PAM."; example = "my_pam_group"; - type = lib.types.listOf lib.types.str; + type = types.listOf types.str; }; - hsm_pin_path = lib.mkOption { + hsm_pin_path = mkOption { description = "Path to a HSM pin."; default = "/var/cache/kanidm-unixd/hsm-pin"; - type = lib.types.path; + type = types.path; }; }; }; @@ -329,73 +363,73 @@ in }; provision = { - enable = lib.mkEnableOption "provisioning of groups, users and oauth2 resource servers"; + enable = mkEnableOption "provisioning of groups, users and oauth2 resource servers"; - instanceUrl = lib.mkOption { + instanceUrl = mkOption { description = "The instance url to which the provisioning tool should connect."; default = "https://localhost:${serverPort}"; defaultText = ''"https://localhost:"''; - type = lib.types.str; + type = types.str; }; - acceptInvalidCerts = lib.mkOption { + acceptInvalidCerts = mkOption { description = '' Whether to allow invalid certificates when provisioning the target instance. By default this is only allowed when the instanceUrl is localhost. This is dangerous when used with an external URL. ''; - type = lib.types.bool; - default = lib.hasPrefix "https://localhost:" cfg.provision.instanceUrl; - defaultText = ''lib.hasPrefix "https://localhost:" cfg.provision.instanceUrl''; + type = types.bool; + default = hasPrefix "https://localhost:" cfg.provision.instanceUrl; + defaultText = ''hasPrefix "https://localhost:" cfg.provision.instanceUrl''; }; - adminPasswordFile = lib.mkOption { + adminPasswordFile = mkOption { description = "Path to a file containing the admin password for kanidm. Do NOT use a file from the nix store here!"; example = "/run/secrets/kanidm-admin-password"; default = null; - type = lib.types.nullOr lib.types.path; + type = types.nullOr types.path; }; - idmAdminPasswordFile = lib.mkOption { + idmAdminPasswordFile = mkOption { description = '' Path to a file containing the idm admin password for kanidm. Do NOT use a file from the nix store here! If this is not given but provisioning is enabled, the idm_admin password will be reset on each restart. ''; example = "/run/secrets/kanidm-idm-admin-password"; default = null; - type = lib.types.nullOr lib.types.path; + type = types.nullOr types.path; }; - autoRemove = lib.mkOption { + autoRemove = mkOption { description = '' Determines whether deleting an entity in this provisioning config should automatically cause them to be removed from kanidm, too. This works because the provisioning tool tracks all entities it has ever created. If this is set to false, you need to explicitly specify `present = false` to delete an entity. ''; - type = lib.types.bool; + type = types.bool; default = true; }; - groups = lib.mkOption { + groups = mkOption { description = "Provisioning of kanidm groups"; default = { }; - type = lib.types.attrsOf ( - lib.types.submodule (groupSubmod: { + type = types.attrsOf ( + types.submodule (groupSubmod: { options = { present = mkPresentOption "group"; - members = lib.mkOption { + members = mkOption { description = "List of kanidm entities (persons, groups, ...) which are part of this group."; - type = lib.types.listOf lib.types.str; - apply = lib.unique; + type = types.listOf types.str; + apply = unique; default = [ ]; }; }; - config.members = lib.concatLists ( - lib.flip lib.mapAttrsToList cfg.provision.persons ( + config.members = concatLists ( + flip mapAttrsToList cfg.provision.persons ( person: personCfg: - lib.optional ( + optional ( personCfg.present && builtins.elem groupSubmod.config._module.args.name personCfg.groups ) person ) @@ -404,38 +438,38 @@ in ); }; - persons = lib.mkOption { + persons = mkOption { description = "Provisioning of kanidm persons"; default = { }; - type = lib.types.attrsOf ( - lib.types.submodule { + type = types.attrsOf ( + types.submodule { options = { present = mkPresentOption "person"; - displayName = lib.mkOption { + displayName = mkOption { description = "Display name"; - type = lib.types.str; + type = types.str; example = "My User"; }; - legalName = lib.mkOption { + legalName = mkOption { description = "Full legal name"; - type = lib.types.nullOr lib.types.str; + type = types.nullOr types.str; example = "Jane Doe"; default = null; }; - mailAddresses = lib.mkOption { + mailAddresses = mkOption { description = "Mail addresses. First given address is considered the primary address."; - type = lib.types.listOf lib.types.str; + type = types.listOf types.str; example = [ "jane.doe@example.com" ]; default = [ ]; }; - groups = lib.mkOption { + groups = mkOption { description = "List of groups this person should belong to."; - type = lib.types.listOf lib.types.str; - apply = lib.unique; + type = types.listOf types.str; + apply = unique; default = [ ]; }; }; @@ -443,119 +477,119 @@ in ); }; - systems.oauth2 = lib.mkOption { + systems.oauth2 = mkOption { description = "Provisioning of oauth2 resource servers"; default = { }; - type = lib.types.attrsOf ( - lib.types.submodule { + type = types.attrsOf ( + types.submodule { options = { present = mkPresentOption "oauth2 resource server"; - public = lib.mkOption { + public = mkOption { description = "Whether this is a public client (enforces PKCE, doesn't use a basic secret)"; - type = lib.types.bool; + type = types.bool; default = false; }; - displayName = lib.mkOption { + displayName = mkOption { description = "Display name"; - type = lib.types.str; + type = types.str; example = "Some Service"; }; - originUrl = lib.mkOption { + originUrl = mkOption { description = "The origin URL of the service. OAuth2 redirects will only be allowed to sites under this origin. Must end with a slash."; type = let - originStrType = lib.types.strMatching ".*://.*/$"; + originStrType = types.strMatching ".*://.*/$"; in - lib.types.either originStrType (lib.types.nonEmptyListOf originStrType); + types.either originStrType (types.nonEmptyListOf originStrType); example = "https://someservice.example.com/"; }; - originLanding = lib.mkOption { + originLanding = mkOption { description = "When redirecting from the Kanidm Apps Listing page, some linked applications may need to land on a specific page to trigger oauth2/oidc interactions."; - type = lib.types.str; + type = types.str; example = "https://someservice.example.com/home"; }; - basicSecretFile = lib.mkOption { + basicSecretFile = mkOption { description = '' The basic secret to use for this service. If null, the random secret generated by kanidm will not be touched. Do NOT use a path from the nix store here! ''; - type = lib.types.nullOr lib.types.path; + type = types.nullOr types.path; example = "/run/secrets/some-oauth2-basic-secret"; default = null; }; - enableLocalhostRedirects = lib.mkOption { + enableLocalhostRedirects = mkOption { description = "Allow localhost redirects. Only for public clients."; - type = lib.types.bool; + type = types.bool; default = false; }; - enableLegacyCrypto = lib.mkOption { + enableLegacyCrypto = mkOption { description = "Enable legacy crypto on this client. Allows JWT signing algorthms like RS256."; - type = lib.types.bool; + type = types.bool; default = false; }; - allowInsecureClientDisablePkce = lib.mkOption { + allowInsecureClientDisablePkce = mkOption { description = '' Disable PKCE on this oauth2 resource server to work around insecure clients that may not support it. You should request the client to enable PKCE! Only for non-public clients. ''; - type = lib.types.bool; + type = types.bool; default = false; }; - preferShortUsername = lib.mkOption { + preferShortUsername = mkOption { description = "Use 'name' instead of 'spn' in the preferred_username claim"; - type = lib.types.bool; + type = types.bool; default = false; }; - scopeMaps = lib.mkOption { + scopeMaps = mkOption { description = '' Maps kanidm groups to returned oauth scopes. See [Scope Relations](https://kanidm.github.io/kanidm/stable/integrations/oauth2.html#scope-relationships) for more information. ''; - type = lib.types.attrsOf (lib.types.listOf lib.types.str); + type = types.attrsOf (types.listOf types.str); default = { }; }; - supplementaryScopeMaps = lib.mkOption { + supplementaryScopeMaps = mkOption { description = '' Maps kanidm groups to additionally returned oauth scopes. See [Scope Relations](https://kanidm.github.io/kanidm/stable/integrations/oauth2.html#scope-relationships) for more information. ''; - type = lib.types.attrsOf (lib.types.listOf lib.types.str); + type = types.attrsOf (types.listOf types.str); default = { }; }; - removeOrphanedClaimMaps = lib.mkOption { + removeOrphanedClaimMaps = mkOption { description = "Whether claim maps not specified here but present in kanidm should be removed from kanidm."; - type = lib.types.bool; + type = types.bool; default = true; }; - claimMaps = lib.mkOption { + claimMaps = mkOption { description = '' Adds additional claims (and values) based on which kanidm groups an authenticating party belongs to. See [Claim Maps](https://kanidm.github.io/kanidm/master/integrations/oauth2.html#custom-claim-maps) for more information. ''; default = { }; - type = lib.types.attrsOf ( - lib.types.submodule { + type = types.attrsOf ( + types.submodule { options = { - joinType = lib.mkOption { + joinType = mkOption { description = '' Determines how multiple values are joined to create the claim value. See [Claim Maps](https://kanidm.github.io/kanidm/master/integrations/oauth2.html#custom-claim-maps) for more information. ''; - type = lib.types.enum [ + type = types.enum [ "array" "csv" "ssv" @@ -563,10 +597,10 @@ in default = "array"; }; - valuesByGroup = lib.mkOption { + valuesByGroup = mkOption { description = "Maps kanidm groups to values for the claim."; default = { }; - type = lib.types.attrsOf (lib.types.listOf lib.types.str); + type = types.attrsOf (types.listOf types.str); }; }; } @@ -579,26 +613,26 @@ in }; }; - config = lib.mkIf (cfg.enableClient || cfg.enableServer || cfg.enablePam) { + config = mkIf (cfg.enableClient || cfg.enableServer || cfg.enablePam) { assertions = let entityList = - type: attrs: lib.flip lib.mapAttrsToList (filterPresent attrs) (name: _: { inherit type name; }); + type: attrs: flip mapAttrsToList (filterPresent attrs) (name: _: { inherit type name; }); entities = entityList "group" cfg.provision.groups ++ entityList "person" cfg.provision.persons ++ entityList "oauth2" cfg.provision.systems.oauth2; # Accumulate entities by name. Track corresponding entity types for later duplicate check. - entitiesByName = lib.foldl' ( + entitiesByName = foldl' ( acc: { type, name }: acc // { ${name} = (acc.${name} or [ ]) ++ [ type ]; } ) { } entities; assertGroupsKnown = opt: groups: let - knownGroups = lib.attrNames (filterPresent cfg.provision.groups); - unknownGroups = lib.subtractLists knownGroups groups; + knownGroups = attrNames (filterPresent cfg.provision.groups); + unknownGroups = subtractLists knownGroups groups; in { assertion = (cfg.enableServer && cfg.provision.enable) -> unknownGroups == [ ]; @@ -608,7 +642,7 @@ in assertEntitiesKnown = opt: entities: let - unknownEntities = lib.subtractLists (lib.attrNames entitiesByName) entities; + unknownEntities = subtractLists (attrNames entitiesByName) entities; in { assertion = (cfg.enableServer && cfg.provision.enable) -> unknownEntities == [ ]; @@ -620,7 +654,7 @@ in assertion = !cfg.enableServer || ((cfg.serverSettings.tls_chain or null) == null) - || (!lib.isStorePath cfg.serverSettings.tls_chain); + || (!isStorePath cfg.serverSettings.tls_chain); message = '' points to a file in the Nix store. You should use a quoted absolute path to @@ -631,7 +665,7 @@ in assertion = !cfg.enableServer || ((cfg.serverSettings.tls_key or null) == null) - || (!lib.isStorePath cfg.serverSettings.tls_key); + || (!isStorePath cfg.serverSettings.tls_key); message = '' points to a file in the Nix store. You should use a quoted absolute path to @@ -677,9 +711,7 @@ in && ( cfg.provision.adminPasswordFile != null || cfg.provision.idmAdminPasswordFile != null - || lib.any (x: x.basicSecretFile != null) ( - lib.attrValues (filterPresent cfg.provision.systems.oauth2) - ) + || any (x: x.basicSecretFile != null) (attrValues (filterPresent cfg.provision.systems.oauth2)) ) ) -> cfg.package.enableSecretProvisioning; @@ -692,48 +724,48 @@ in ( let # Filter all names that occurred in more than one entity type. - duplicateNames = lib.filterAttrs (_: v: builtins.length v > 1) entitiesByName; + duplicateNames = filterAttrs (_: v: builtins.length v > 1) entitiesByName; in { assertion = cfg.provision.enable -> duplicateNames == { }; message = '' services.kanidm.provision requires all entity names (group, person, oauth2, ...) to be unique! - ${lib.concatLines ( - lib.mapAttrsToList (name: xs: " - '${name}' used as: ${toString xs}") duplicateNames + ${concatLines ( + mapAttrsToList (name: xs: " - '${name}' used as: ${toString xs}") duplicateNames )}''; } ) ] - ++ lib.flip lib.mapAttrsToList (filterPresent cfg.provision.persons) ( + ++ flip mapAttrsToList (filterPresent cfg.provision.persons) ( person: personCfg: assertGroupsKnown "services.kanidm.provision.persons.${person}.groups" personCfg.groups ) - ++ lib.flip lib.mapAttrsToList (filterPresent cfg.provision.groups) ( + ++ flip mapAttrsToList (filterPresent cfg.provision.groups) ( group: groupCfg: assertEntitiesKnown "services.kanidm.provision.groups.${group}.members" groupCfg.members ) - ++ lib.concatLists ( - lib.flip lib.mapAttrsToList (filterPresent cfg.provision.systems.oauth2) ( + ++ concatLists ( + flip mapAttrsToList (filterPresent cfg.provision.systems.oauth2) ( oauth2: oauth2Cfg: [ (assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.scopeMaps" ( - lib.attrNames oauth2Cfg.scopeMaps + attrNames oauth2Cfg.scopeMaps )) (assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.supplementaryScopeMaps" ( - lib.attrNames oauth2Cfg.supplementaryScopeMaps + attrNames oauth2Cfg.supplementaryScopeMaps )) ] - ++ lib.concatLists ( - lib.flip lib.mapAttrsToList oauth2Cfg.claimMaps ( + ++ concatLists ( + flip mapAttrsToList oauth2Cfg.claimMaps ( claim: claimCfg: [ (assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.claimMaps.${claim}.valuesByGroup" ( - lib.attrNames claimCfg.valuesByGroup + attrNames claimCfg.valuesByGroup )) # At least one group must map to a value in each claim map { assertion = (cfg.provision.enable && cfg.enableServer) - -> lib.any (xs: xs != [ ]) (lib.attrValues claimCfg.valuesByGroup); + -> any (xs: xs != [ ]) (attrValues claimCfg.valuesByGroup); message = "services.kanidm.provision.systems.oauth2.${oauth2}.claimMaps.${claim} does not specify any values for any group"; } # Public clients cannot define a basic secret @@ -762,7 +794,7 @@ in ) ); - environment.systemPackages = lib.mkIf cfg.enableClient [ cfg.package ]; + environment.systemPackages = mkIf cfg.enableClient [ cfg.package ]; systemd.tmpfiles.settings."10-kanidm" = { ${cfg.serverSettings.online_backup.path}.d = { @@ -772,11 +804,11 @@ in }; }; - systemd.services.kanidm = lib.mkIf cfg.enableServer { + systemd.services.kanidm = mkIf cfg.enableServer { description = "kanidm identity management daemon"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - serviceConfig = lib.mkMerge [ + serviceConfig = mkMerge [ # Merge paths and ignore existing prefixes needs to sidestep mkMerge ( defaultServiceConfig @@ -789,7 +821,7 @@ in StateDirectoryMode = "0700"; RuntimeDirectory = "kanidmd"; ExecStart = "${cfg.package}/bin/kanidmd server -c ${serverConfigFile}"; - ExecStartPost = lib.mkIf cfg.provision.enable postStartScript; + ExecStartPost = mkIf cfg.provision.enable postStartScript; User = "kanidm"; Group = "kanidm"; @@ -803,9 +835,9 @@ in AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; # This would otherwise override the CAP_NET_BIND_SERVICE capability. - PrivateUsers = lib.mkForce false; + PrivateUsers = mkForce false; # Port needs to be exposed to the host network - PrivateNetwork = lib.mkForce false; + PrivateNetwork = mkForce false; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" @@ -817,7 +849,7 @@ in environment.RUST_LOG = "info"; }; - systemd.services.kanidm-unixd = lib.mkIf cfg.enablePam { + systemd.services.kanidm-unixd = mkIf cfg.enablePam { description = "Kanidm PAM daemon"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; @@ -825,7 +857,7 @@ in unixConfigFile clientConfigFile ]; - serviceConfig = lib.mkMerge [ + serviceConfig = mkMerge [ defaultServiceConfig { CacheDirectory = "kanidm-unixd"; @@ -848,7 +880,7 @@ in "/run/kanidm-unixd:/var/run/kanidm-unixd" ]; # Needs to connect to kanidmd - PrivateNetwork = lib.mkForce false; + PrivateNetwork = mkForce false; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" @@ -860,7 +892,7 @@ in environment.RUST_LOG = "info"; }; - systemd.services.kanidm-unixd-tasks = lib.mkIf cfg.enablePam { + systemd.services.kanidm-unixd-tasks = mkIf cfg.enablePam { description = "Kanidm PAM home management daemon"; wantedBy = [ "multi-user.target" ]; after = [ @@ -910,25 +942,25 @@ in }; # These paths are hardcoded - environment.etc = lib.mkMerge [ - (lib.mkIf cfg.enableServer { "kanidm/server.toml".source = serverConfigFile; }) - (lib.mkIf options.services.kanidm.clientSettings.isDefined { + environment.etc = mkMerge [ + (mkIf cfg.enableServer { "kanidm/server.toml".source = serverConfigFile; }) + (mkIf options.services.kanidm.clientSettings.isDefined { "kanidm/config".source = clientConfigFile; }) - (lib.mkIf cfg.enablePam { "kanidm/unixd".source = unixConfigFile; }) + (mkIf cfg.enablePam { "kanidm/unixd".source = unixConfigFile; }) ]; - system.nssModules = lib.mkIf cfg.enablePam [ cfg.package ]; + system.nssModules = mkIf cfg.enablePam [ cfg.package ]; - system.nssDatabases.group = lib.optional cfg.enablePam "kanidm"; - system.nssDatabases.passwd = lib.optional cfg.enablePam "kanidm"; + system.nssDatabases.group = optional cfg.enablePam "kanidm"; + system.nssDatabases.passwd = optional cfg.enablePam "kanidm"; - users.groups = lib.mkMerge [ - (lib.mkIf cfg.enableServer { kanidm = { }; }) - (lib.mkIf cfg.enablePam { kanidm-unixd = { }; }) + users.groups = mkMerge [ + (mkIf cfg.enableServer { kanidm = { }; }) + (mkIf cfg.enablePam { kanidm-unixd = { }; }) ]; - users.users = lib.mkMerge [ - (lib.mkIf cfg.enableServer { + users.users = mkMerge [ + (mkIf cfg.enableServer { kanidm = { description = "Kanidm server"; isSystemUser = true; @@ -936,7 +968,7 @@ in packages = [ cfg.package ]; }; }) - (lib.mkIf cfg.enablePam { + (mkIf cfg.enablePam { kanidm-unixd = { description = "Kanidm PAM daemon"; isSystemUser = true; diff --git a/nixos/modules/services/system/automatic-timezoned.nix b/nixos/modules/services/system/automatic-timezoned.nix index 6150aa22cfbd..50f84f39af7d 100644 --- a/nixos/modules/services/system/automatic-timezoned.nix +++ b/nixos/modules/services/system/automatic-timezoned.nix @@ -16,6 +16,11 @@ in timezone up-to-date based on the current location. It uses geoclue2 to determine the current location and systemd-timedated to actually set the timezone. + + To avoid silent overriding by the service, if you have explicitly set a + timezone, either remove it or ensure that it is set with a lower priority + than the default value using `lib.mkDefault` or `lib.mkOverride`. This is + to make the choice deliberate. An error will be presented otherwise. ''; }; package = mkPackageOption pkgs "automatic-timezoned" { }; @@ -23,6 +28,10 @@ in }; config = mkIf cfg.enable { + # This will give users an error if they have set an explicit time + # zone, rather than having the service silently override it. + time.timeZone = null; + security.polkit.extraConfig = '' polkit.addRule(function(action, subject) { if (action.id == "org.freedesktop.timedate1.set-timezone" diff --git a/nixos/modules/services/system/localtimed.nix b/nixos/modules/services/system/localtimed.nix index bd83d227aa35..70d65f4d2bba 100644 --- a/nixos/modules/services/system/localtimed.nix +++ b/nixos/modules/services/system/localtimed.nix @@ -16,6 +16,11 @@ in { Enable `localtimed`, a simple daemon for keeping the system timezone up-to-date based on the current location. It uses geoclue2 to determine the current location. + + To avoid silent overriding by the service, if you have explicitly set a + timezone, either remove it or ensure that it is set with a lower priority + than the default value using `lib.mkDefault` or `lib.mkOverride`. This is + to make the choice deliberate. An error will be presented otherwise. ''; }; package = mkPackageOption pkgs "localtime" { }; @@ -24,6 +29,10 @@ in { }; config = mkIf cfg.enable { + # This will give users an error if they have set an explicit time + # zone, rather than having the service silently override it. + time.timeZone = null; + services.geoclue2.appConfig.localtimed = { isAllowed = true; isSystem = true; diff --git a/nixos/modules/services/system/nix-daemon.nix b/nixos/modules/services/system/nix-daemon.nix index 3d44bdac34bf..adadce4f88d6 100644 --- a/nixos/modules/services/system/nix-daemon.nix +++ b/nixos/modules/services/system/nix-daemon.nix @@ -198,6 +198,7 @@ in IOSchedulingClass = cfg.daemonIOSchedClass; IOSchedulingPriority = cfg.daemonIOSchedPriority; LimitNOFILE = 1048576; + Delegate = "yes"; }; restartTriggers = [ config.environment.etc."nix/nix.conf".source ]; diff --git a/nixos/modules/services/system/userborn.nix b/nixos/modules/services/system/userborn.nix new file mode 100644 index 000000000000..bd3f2175b128 --- /dev/null +++ b/nixos/modules/services/system/userborn.nix @@ -0,0 +1,183 @@ +{ + utils, + config, + lib, + pkgs, + ... +}: + +let + + cfg = config.services.userborn; + userCfg = config.users; + + userbornConfig = { + groups = lib.mapAttrsToList (username: opts: { + inherit (opts) name gid members; + }) config.users.groups; + + users = lib.mapAttrsToList (username: opts: { + inherit (opts) + name + uid + group + description + home + password + hashedPassword + hashedPasswordFile + initialPassword + initialHashedPassword + ; + isNormal = opts.isNormalUser; + shell = utils.toShellPath opts.shell; + }) config.users.users; + }; + + userbornConfigJson = pkgs.writeText "userborn.json" (builtins.toJSON userbornConfig); + + immutableEtc = config.system.etc.overlay.enable && !config.system.etc.overlay.mutable; + # The filenames created by userborn. + passwordFiles = [ + "group" + "passwd" + "shadow" + ]; + +in +{ + + options.services.userborn = { + + enable = lib.mkEnableOption "userborn"; + + package = lib.mkPackageOption pkgs "userborn" { }; + + passwordFilesLocation = lib.mkOption { + type = lib.types.str; + default = if immutableEtc then "/var/lib/nixos" else "/etc"; + defaultText = lib.literalExpression ''if immutableEtc then "/var/lib/nixos" else "/etc"''; + description = '' + The location of the original password files. + + If this is not `/etc`, the files are symlinked from this location to `/etc`. + + The primary motivation for this is an immutable `/etc`, where we cannot + write the files directly to `/etc`. + + However this an also serve other use cases, e.g. when `/etc` is on a `tmpfs`. + ''; + }; + + }; + + config = lib.mkIf cfg.enable { + + assertions = [ + { + assertion = !(config.systemd.sysusers.enable && cfg.enable); + message = "You cannot use systemd-sysusers and Userborn at the same time"; + } + { + assertion = config.system.activationScripts.users == ""; + message = "system.activationScripts.users has to be empty to use userborn"; + } + { + assertion = immutableEtc -> (cfg.passwordFilesLocation != "/etc"); + message = "When `system.etc.overlay.mutable = false`, `services.userborn.passwordFilesLocation` cannot be set to `/etc`"; + } + ]; + + system.activationScripts.users = lib.mkForce ""; + system.activationScripts.hashes = lib.mkForce ""; + + systemd = { + + # Create home directories, do not create /var/empty even if that's a user's + # home. + tmpfiles.settings.home-directories = lib.mapAttrs' ( + username: opts: + lib.nameValuePair (toString opts.home) { + d = { + mode = opts.homeMode; + user = opts.name; + inherit (opts) group; + }; + } + ) (lib.filterAttrs (_username: opts: opts.createHome && opts.home != "/var/empty") userCfg.users); + + services.userborn = { + wantedBy = [ "sysinit.target" ]; + requiredBy = [ "sysinit-reactivation.target" ]; + after = [ + "systemd-remount-fs.service" + "systemd-tmpfiles-setup-dev-early.service" + ]; + before = [ + "systemd-tmpfiles-setup-dev.service" + "sysinit.target" + "shutdown.target" + "sysinit-reactivation.target" + ]; + conflicts = [ "shutdown.target" ]; + restartTriggers = [ + userbornConfigJson + cfg.passwordFilesLocation + ]; + # This way we don't have to re-declare all the dependencies to other + # services again. + aliases = [ "systemd-sysusers.service" ]; + + unitConfig = { + Description = "Manage Users and Groups"; + DefaultDependencies = false; + }; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + TimeoutSec = "90s"; + + ExecStart = "${lib.getExe cfg.package} ${userbornConfigJson} ${cfg.passwordFilesLocation}"; + + ExecStartPre = lib.mkMerge [ + (lib.mkIf (!config.system.etc.overlay.mutable) [ + "${pkgs.coreutils}/bin/mkdir -p ${cfg.passwordFilesLocation}" + ]) + + # Make the source files writable before executing userborn. + (lib.mkIf (!userCfg.mutableUsers) ( + lib.map (file: "-${pkgs.util-linux}/bin/umount ${cfg.passwordFilesLocation}/${file}") passwordFiles + )) + ]; + + # Make the source files read-only after userborn has finished. + ExecStartPost = lib.mkIf (!userCfg.mutableUsers) ( + lib.map ( + file: + "${pkgs.util-linux}/bin/mount --bind -o ro ${cfg.passwordFilesLocation}/${file} ${cfg.passwordFilesLocation}/${file}" + ) passwordFiles + ); + }; + }; + }; + + # Statically create the symlinks to passwordFilesLocation when they're not + # inside /etc because we will not be able to do it at runtime in case of an + # immutable /etc! + environment.etc = lib.mkIf (cfg.passwordFilesLocation != "/etc") ( + lib.listToAttrs ( + lib.map ( + file: + lib.nameValuePair file { + source = "${cfg.passwordFilesLocation}/${file}"; + mode = "direct-symlink"; + } + ) passwordFiles + ) + ); + }; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + +} diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix index 5fa67b5ca264..b3f38eba6642 100644 --- a/nixos/modules/services/video/frigate.nix +++ b/nixos/modules/services/video/frigate.nix @@ -39,10 +39,8 @@ let ''; }; roles = mkOption { - type = listOf (enum [ "detect" "record" "rtmp" ]); - example = literalExpression '' - [ "detect" "rtmp" ] - ''; + type = listOf (enum [ "audio" "detect" "record" ]); + example = [ "detect" "record" ]; description = '' List of roles for this stream ''; @@ -54,6 +52,48 @@ let }; }; + # auth_request.conf + nginxAuthRequest = '' + # Send a subrequest to verify if the user is authenticated and has permission to access the resource. + auth_request /auth; + + # Save the upstream metadata response headers from Authelia to variables. + auth_request_set $user $upstream_http_remote_user; + auth_request_set $groups $upstream_http_remote_groups; + auth_request_set $name $upstream_http_remote_name; + auth_request_set $email $upstream_http_remote_email; + + # Inject the metadata response headers from the variables into the request made to the backend. + proxy_set_header Remote-User $user; + proxy_set_header Remote-Groups $groups; + proxy_set_header Remote-Email $email; + proxy_set_header Remote-Name $name; + + # Refresh the cookie as needed + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + + # Pass the location header back up if it exists + auth_request_set $redirection_url $upstream_http_location; + add_header Location $redirection_url; + ''; + + nginxProxySettings = '' + # Basic Proxy Configuration + client_body_buffer_size 128k; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; ## Timeout if the real server is dead. + proxy_redirect http:// $scheme://; + proxy_cache_bypass $cookie_session; + proxy_no_cache $cookie_session; + proxy_buffers 64 256k; + + # Advanced Proxy Configuration + send_timeout 5m; + proxy_read_timeout 360; + proxy_send_timeout 360; + proxy_connect_timeout 360; + ''; + in { @@ -126,8 +166,9 @@ in services.nginx = { enable = true; additionalModules = with pkgs.nginxModules; [ + develkit secure-token - rtmp + set-misc vod ]; recommendedProxySettings = mkDefault true; @@ -158,43 +199,46 @@ in # Based on https://github.com/blakeblackshear/frigate/blob/v0.13.1/docker/main/rootfs/usr/local/nginx/conf/nginx.conf virtualHosts."${cfg.hostname}" = { locations = { - "/api/" = { - proxyPass = "http://frigate-api/"; + # auth_location.conf + "/auth" = { + proxyPass = "http://frigate-api/auth"; extraConfig = '' - proxy_cache frigate_api_cache; - proxy_cache_lock on; - proxy_cache_use_stale updating; - proxy_cache_valid 200 5s; - proxy_cache_bypass $http_x_cache_bypass; - proxy_no_cache $should_not_cache; - add_header X-Cache-Status $upstream_cache_status; + internal; - location /api/vod/ { - proxy_pass http://frigate-api/vod/; - proxy_cache off; - } + # Strip all request headers + proxy_pass_request_headers off; - location /api/stats { - access_log off; - rewrite ^/api/(.*)$ $1 break; - proxy_pass http://frigate-api; - } + # Pass info about the request + proxy_set_header X-Original-Method $request_method; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Server-Port $server_port; + proxy_set_header Content-Length ""; - location /api/version { - access_log off; - rewrite ^/api/(.*)$ $1 break; - proxy_pass http://frigate-api; - } - ''; - }; - "~* /api/.*\.(jpg|jpeg|png)$" = { - proxyPass = "http://frigate-api"; - extraConfig = '' - rewrite ^/api/(.*)$ $1 break; + # Pass along auth related info + proxy_set_header Authorization $http_authorization; + proxy_set_header Cookie $http_cookie; + proxy_set_header X-CSRF-TOKEN "1"; + + # Pass headers for common auth proxies + proxy_set_header Remote-User $http_remote_user; + proxy_set_header Remote-Groups $http_remote_groups; + proxy_set_header Remote-Email $http_remote_email; + proxy_set_header Remote-Name $http_remote_name; + proxy_set_header X-Forwarded-User $http_x_forwarded_user; + proxy_set_header X-Forwarded-Groups $http_x_forwarded_groups; + proxy_set_header X-Forwarded-Email $http_x_forwarded_email; + proxy_set_header X-Forwarded-Preferred-Username $http_x_forwarded_preferred_username; + proxy_set_header X-authentik-username $http_x_authentik_username; + proxy_set_header X-authentik-groups $http_x_authentik_groups; + proxy_set_header X-authentik-email $http_x_authentik_email; + proxy_set_header X-authentik-name $http_x_authentik_name; + proxy_set_header X-authentik-uid $http_x_authentik_uid; + + ${nginxProxySettings} ''; }; "/vod/" = { - extraConfig = '' + extraConfig = nginxAuthRequest + '' aio threads; vod hls; @@ -206,38 +250,84 @@ in ''; }; "/stream/" = { - # TODO + alias = "/var/cache/frigate/stream/"; + extraConfig = nginxAuthRequest + '' + add_header Cache-Control "no-store"; + expires off; + + types { + application/dash+xml mpd; + application/vnd.apple.mpegurl m3u8; + video/mp2t ts; + image/jpeg jpg; + } + ''; + }; + "/clips/" = { + root = "/var/lib/frigate"; + extraConfig = nginxAuthRequest + '' + types { + video/mp4 mp4; + image/jpeg jpg; + } + + expires 7d; + add_header Cache-Control "public"; + autoindex on; + ''; + }; + "/cache/" = { + alias = "/var/cache/frigate/"; + extraConfig = '' + internal; + ''; + }; + "/recordings/" = { + root = "/var/lib/frigate"; + extraConfig = nginxAuthRequest + '' + types { + video/mp4 mp4; + } + + autoindex on; + autoindex_format json; + ''; + }; + "/exports/" = { + root = "/var/lib/frigate"; + extraConfig = nginxAuthRequest + '' + types { + video/mp4 mp4; + } + + autoindex on; + autoindex_format json; + ''; }; "/ws" = { proxyPass = "http://frigate-mqtt-ws/"; proxyWebsockets = true; + extraConfig = nginxAuthRequest + nginxProxySettings; }; "/live/jsmpeg" = { proxyPass = "http://frigate-jsmpeg/"; proxyWebsockets = true; - }; - "/live/mse/" = { - proxyPass = "http://frigate-go2rtc/"; - proxyWebsockets = true; + extraConfig = nginxAuthRequest + nginxProxySettings; }; # frigate lovelace card uses this path "/live/mse/api/ws" = { proxyPass = "http://frigate-go2rtc/api/ws"; proxyWebsockets = true; - extraConfig = '' + extraConfig = nginxAuthRequest + nginxProxySettings + '' limit_except GET { deny all; } ''; }; - "/live/webrtc/" = { - proxyPass = "http://frigate-go2rtc/"; - proxyWebsockets = true; - }; "/live/webrtc/api/ws" = { proxyPass = "http://frigate-go2rtc/api/ws"; proxyWebsockets = true; - extraConfig = '' + extraConfig = nginxAuthRequest + nginxProxySettings + '' limit_except GET { deny all; } @@ -246,17 +336,16 @@ in # pass through go2rtc player "/live/webrtc/webrtc.html" = { proxyPass = "http://frigate-go2rtc/webrtc.html"; - proxyWebsockets = true; - extraConfig = '' + extraConfig = nginxAuthRequest + nginxProxySettings + '' limit_except GET { deny all; } ''; }; + # frontend uses this to fetch the version "/api/go2rtc/api" = { proxyPass = "http://frigate-go2rtc/api"; - proxyWebsockets = true; - extraConfig = '' + extraConfig = nginxAuthRequest + nginxProxySettings + '' limit_except GET { deny all; } @@ -266,35 +355,64 @@ in "/api/go2rtc/webrtc" = { proxyPass = "http://frigate-go2rtc/api/webrtc"; proxyWebsockets = true; - extraConfig = '' + extraConfig = nginxAuthRequest + nginxProxySettings + '' limit_except GET { deny all; } ''; }; - "/cache/" = { - alias = "/var/cache/frigate/"; - }; - "/clips/" = { - root = "/var/lib/frigate"; - extraConfig = '' - types { - video/mp4 mp4; - image/jpeg jpg; - } - - autoindex on; + "~* /api/.*\.(jpg|jpeg|png|webp|gif)$" = { + proxyPass = "http://frigate-api"; + extraConfig = nginxAuthRequest + nginxProxySettings + '' + rewrite ^/api/(.*)$ $1 break; ''; }; - "/recordings/" = { - root = "/var/lib/frigate"; - extraConfig = '' - types { - video/mp4 mp4; + "/api/" = { + proxyPass = "http://frigate-api/"; + extraConfig = nginxAuthRequest + nginxProxySettings + '' + add_header Cache-Control "no-store"; + expires off; + + proxy_cache frigate_api_cache; + proxy_cache_lock on; + proxy_cache_use_stale updating; + proxy_cache_valid 200 5s; + proxy_cache_bypass $http_x_cache_bypass; + proxy_no_cache $should_not_cache; + add_header X-Cache-Status $upstream_cache_status; + + location /api/vod/ { + ${nginxAuthRequest} + proxy_pass http://frigate-api/vod/; + proxy_cache off; + add_header Cache-Control "no-store"; + ${nginxProxySettings} } - autoindex on; - autoindex_format json; + location /api/login { + auth_request off; + rewrite ^/api(/.*)$ $1 break; + proxy_pass http://frigate-api; + ${nginxProxySettings} + } + + location /api/stats { + ${nginxAuthRequest} + access_log off; + rewrite ^/api/(.*)$ $1 break; + add_header Cache-Control "no-store"; + proxy_pass http://frigate-api; + ${nginxProxySettings} + } + + location /api/version { + ${nginxAuthRequest} + access_log off; + rewrite ^/api/(.*)$ $1 break; + add_header Cache-Control "no-store"; + proxy_pass http://frigate-api; + ${nginxProxySettings} + } ''; }; "/assets/" = { @@ -307,21 +425,10 @@ in }; "/" = { root = cfg.package.web; - tryFiles = "$uri $uri/ /index.html"; + tryFiles = "$uri $uri.html $uri/ /index.html"; extraConfig = '' add_header Cache-Control "no-store"; expires off; - - sub_filter 'href="/BASE_PATH/' 'href="$http_x_ingress_path/'; - sub_filter 'url(/BASE_PATH/' 'url($http_x_ingress_path/'; - sub_filter '"/BASE_PATH/dist/' '"$http_x_ingress_path/dist/'; - sub_filter '"/BASE_PATH/js/' '"$http_x_ingress_path/js/'; - sub_filter '"/BASE_PATH/assets/' '"$http_x_ingress_path/assets/'; - sub_filter '"/BASE_PATH/monacoeditorwork/' '"$http_x_ingress_path/assets/'; - sub_filter 'return"/BASE_PATH/"' 'return window.baseUrl'; - sub_filter '' ''; - sub_filter_types text/css application/javascript; - sub_filter_once off; ''; }; }; @@ -338,17 +445,21 @@ in vod_segment_duration 10000; vod_hls_mpegts_align_frames off; vod_hls_mpegts_interleave_frames on; + # file handle caching / aio open_file_cache max=1000 inactive=5m; open_file_cache_valid 2m; open_file_cache_min_uses 1; open_file_cache_errors on; aio on; + # https://github.com/kaltura/nginx-vod-module#vod_open_file_thread_pool vod_open_file_thread_pool default; + # vod caches vod_metadata_cache metadata_cache 512m; vod_mapping_cache mapping_cache 5m 10m; + # gzip manifest gzip_types application/vnd.apple.mpegurl; ''; @@ -407,7 +518,7 @@ in libva-utils procps radeontop - ] ++ lib.optionals (!stdenv.isAarch64) [ + ] ++ lib.optionals (!stdenv.hostPlatform.isAarch64) [ # not available on aarch64-linux intel-gpu-tools ]; @@ -427,6 +538,9 @@ in PrivateTmp = true; CacheDirectory = "frigate"; CacheDirectoryMode = "0750"; + + # Sockets/IPC + RuntimeDirectory = "frigate"; }; }; }; diff --git a/nixos/modules/services/video/go2rtc/default.nix b/nixos/modules/services/video/go2rtc/default.nix index 399f4d582171..f74c172907fe 100644 --- a/nixos/modules/services/video/go2rtc/default.nix +++ b/nixos/modules/services/video/go2rtc/default.nix @@ -55,8 +55,8 @@ in ffmpeg = { bin = mkOption { type = path; - default = "${lib.getBin pkgs.ffmpeg_6-headless}/bin/ffmpeg"; - defaultText = literalExpression "\${lib.getBin pkgs.ffmpeg_6-headless}/bin/ffmpeg"; + default = lib.getExe pkgs.ffmpeg-headless; + defaultText = literalExpression "lib.getExe pkgs.ffmpeg-headless"; description = '' The ffmpeg package to use for transcoding. ''; diff --git a/nixos/modules/services/video/unifi-video.nix b/nixos/modules/services/video/unifi-video.nix deleted file mode 100644 index 99c04bafd141..000000000000 --- a/nixos/modules/services/video/unifi-video.nix +++ /dev/null @@ -1,252 +0,0 @@ -{ config, lib, options, pkgs, utils, ... }: -with lib; -let - cfg = config.services.unifi-video; - opt = options.services.unifi-video; - mainClass = "com.ubnt.airvision.Main"; - cmd = '' - ${pkgs.jsvc}/bin/jsvc \ - -cwd ${stateDir} \ - -debug \ - -verbose:class \ - -nodetach \ - -user unifi-video \ - -home ${cfg.jrePackage}/lib/openjdk \ - -cp ${pkgs.commonsDaemon}/share/java/commons-daemon-1.2.4.jar:${stateDir}/lib/airvision.jar \ - -pidfile ${cfg.pidFile} \ - -procname unifi-video \ - -Djava.security.egd=file:/dev/./urandom \ - -Xmx${toString cfg.maximumJavaHeapSize}M \ - -Xss512K \ - -XX:+UseG1GC \ - -XX:+UseStringDeduplication \ - -XX:MaxMetaspaceSize=768M \ - -Djava.library.path=${stateDir}/lib \ - -Djava.awt.headless=true \ - -Djavax.net.ssl.trustStore=${stateDir}/etc/ufv-truststore \ - -Dfile.encoding=UTF-8 \ - -Dav.tempdir=/var/cache/unifi-video - ''; - - mongoConf = pkgs.writeTextFile { - name = "mongo.conf"; - executable = false; - text = '' - # for documentation of all options, see https://www.mongodb.com/docs/manual/reference/configuration-options/ - - storage: - dbPath: ${cfg.dataDir}/db - journal: - enabled: true - syncPeriodSecs: 60 - - systemLog: - destination: file - logAppend: true - path: ${stateDir}/logs/mongod.log - - net: - port: 7441 - bindIp: 127.0.0.1 - http: - enabled: false - - operationProfiling: - slowOpThresholdMs: 500 - mode: off - ''; - }; - - - mongoWtConf = pkgs.writeTextFile { - name = "mongowt.conf"; - executable = false; - text = '' - # for documentation of all options, see: - # https://www.mongodb.com/docs/manual/reference/configuration-options/ - - storage: - dbPath: ${cfg.dataDir}/db-wt - journal: - enabled: true - wiredTiger: - engineConfig: - cacheSizeGB: 1 - - systemLog: - destination: file - logAppend: true - path: logs/mongod.log - - net: - port: 7441 - bindIp: 127.0.0.1 - - operationProfiling: - slowOpThresholdMs: 500 - mode: off - ''; - }; - - stateDir = "/var/lib/unifi-video"; - -in -{ - - options.services.unifi-video = { - - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether or not to enable the unifi-video service. - ''; - }; - - jrePackage = mkPackageOption pkgs "jre8" { }; - - unifiVideoPackage = mkPackageOption pkgs "unifi-video" { }; - - mongodbPackage = mkPackageOption pkgs "mongodb" { - default = "mongodb-5_0"; - }; - - logDir = mkOption { - type = types.str; - default = "${stateDir}/logs"; - description = '' - Where to store the logs. - ''; - }; - - dataDir = mkOption { - type = types.str; - default = "${stateDir}/data"; - description = '' - Where to store the database and other data. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Whether or not to open the required ports on the firewall. - ''; - }; - - maximumJavaHeapSize = mkOption { - type = types.nullOr types.int; - default = 1024; - example = 4096; - description = '' - Set the maximum heap size for the JVM in MB. - ''; - }; - - pidFile = mkOption { - type = types.path; - default = "${cfg.dataDir}/unifi-video.pid"; - defaultText = literalExpression ''"''${config.${opt.dataDir}}/unifi-video.pid"''; - description = "Location of unifi-video pid file."; - }; - - }; - - config = mkIf cfg.enable { - - warnings = optional - (options.services.unifi-video.openFirewall.highestPrio >= (mkOptionDefault null).priority) - "The current services.unifi-video.openFirewall = true default is deprecated and will change to false in 22.11. Set it explicitly to silence this warning."; - - users.users.unifi-video = { - description = "UniFi Video controller daemon user"; - home = stateDir; - group = "unifi-video"; - isSystemUser = true; - }; - users.groups.unifi-video = {}; - - networking.firewall = mkIf cfg.openFirewall { - # https://help.ui.com/hc/en-us/articles/217875218-UniFi-Video-Ports-Used - allowedTCPPorts = [ - 7080 # HTTP portal - 7443 # HTTPS portal - 7445 # Video over HTTP (mobile app) - 7446 # Video over HTTPS (mobile app) - 7447 # RTSP via the controller - 7442 # Camera management from cameras to NVR over WAN - ]; - allowedUDPPorts = [ - 6666 # Inbound camera streams sent over WAN - ]; - }; - - systemd.tmpfiles.rules = [ - "d '${stateDir}' 0700 unifi-video unifi-video - -" - "d '/var/cache/unifi-video' 0700 unifi-video unifi-video - -" - - "d '${stateDir}/logs' 0700 unifi-video unifi-video - -" - "C '${stateDir}/etc' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/etc" - "C '${stateDir}/webapps' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/webapps" - "C '${stateDir}/email' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/email" - "C '${stateDir}/fw' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/fw" - "C '${stateDir}/lib' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/lib" - - "d '${stateDir}/data' 0700 unifi-video unifi-video - -" - "d '${stateDir}/data/db' 0700 unifi-video unifi-video - -" - "C '${stateDir}/data/system.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/etc/system.properties" - - "d '${stateDir}/bin' 0700 unifi-video unifi-video - -" - "f '${stateDir}/bin/evostreamms' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/evostreamms" - "f '${stateDir}/bin/libavcodec.so.54' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavcodec.so.54" - "f '${stateDir}/bin/libavformat.so.54' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavformat.so.54" - "f '${stateDir}/bin/libavutil.so.52' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavutil.so.52" - "f '${stateDir}/bin/ubnt.avtool' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/ubnt.avtool" - "f '${stateDir}/bin/ubnt.updater' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/ubnt.updater" - "C '${stateDir}/bin/mongo' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongo" - "C '${stateDir}/bin/mongod' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongod" - "C '${stateDir}/bin/mongoperf' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongoperf" - "C '${stateDir}/bin/mongos' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongos" - - "d '${stateDir}/conf' 0700 unifi-video unifi-video - -" - "C '${stateDir}/conf/evostream' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/evostream" - "Z '${stateDir}/conf/evostream' 0700 unifi-video unifi-video - -" - "L+ '${stateDir}/conf/mongodv3.0+.conf' 0700 unifi-video unifi-video - ${mongoConf}" - "L+ '${stateDir}/conf/mongodv3.6+.conf' 0700 unifi-video unifi-video - ${mongoConf}" - "L+ '${stateDir}/conf/mongod-wt.conf' 0700 unifi-video unifi-video - ${mongoWtConf}" - "L+ '${stateDir}/conf/catalina.policy' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/catalina.policy" - "L+ '${stateDir}/conf/catalina.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/catalina.properties" - "L+ '${stateDir}/conf/context.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/context.xml" - "L+ '${stateDir}/conf/logging.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/logging.properties" - "L+ '${stateDir}/conf/server.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/server.xml" - "L+ '${stateDir}/conf/tomcat-users.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/tomcat-users.xml" - "L+ '${stateDir}/conf/web.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/web.xml" - ]; - - systemd.services.unifi-video = { - description = "UniFi Video NVR daemon"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ] ; - unitConfig.RequiresMountsFor = stateDir; - # Make sure package upgrades trigger a service restart - restartTriggers = [ cfg.unifiVideoPackage cfg.mongodbPackage ]; - path = with pkgs; [ gawk coreutils busybox which jre8 lsb-release libcap util-linux ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${(removeSuffix "\n" cmd)} ${mainClass} start"; - ExecStop = "${(removeSuffix "\n" cmd)} stop ${mainClass} stop"; - Restart = "on-failure"; - UMask = "0077"; - User = "unifi-video"; - WorkingDirectory = "${stateDir}"; - }; - }; - }; - - imports = [ - (mkRenamedOptionModule [ "services" "unifi-video" "openPorts" ] [ "services" "unifi-video" "openFirewall" ]) - ]; - - meta.maintainers = with lib.maintainers; [ rsynnest ]; -} diff --git a/nixos/modules/services/wayland/hypridle.nix b/nixos/modules/services/wayland/hypridle.nix index ee35812fd440..231a0b7f93ec 100644 --- a/nixos/modules/services/wayland/hypridle.nix +++ b/nixos/modules/services/wayland/hypridle.nix @@ -17,7 +17,10 @@ in config = lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package ]; - systemd.packages = [ cfg.package ]; + systemd = { + packages = [ cfg.package ]; + user.services.hypridle.wantedBy = [ "graphical-session.target" ]; + }; }; meta.maintainers = with lib.maintainers; [ johnrtitor ]; diff --git a/nixos/modules/services/web-servers/bluemap.nix b/nixos/modules/services/web-apps/bluemap.nix similarity index 88% rename from nixos/modules/services/web-servers/bluemap.nix rename to nixos/modules/services/web-apps/bluemap.nix index 731468fd9a0e..0b45501980e6 100644 --- a/nixos/modules/services/web-servers/bluemap.nix +++ b/nixos/modules/services/web-apps/bluemap.nix @@ -13,6 +13,9 @@ let (format.generate "${name}.conf" value)) cfg.maps); + addonsFolder = pkgs.linkFarm "addons" + (lib.attrsets.mapAttrs' (name: value: lib.nameValuePair "${name}.jar" value) cfg.addons); + storageFolder = pkgs.linkFarm "storage" (lib.attrsets.mapAttrs' (name: value: lib.nameValuePair "${name}.conf" @@ -25,11 +28,16 @@ let "core.conf" = coreConfig; "webapp.conf" = webappConfig; "webserver.conf" = webserverConfig; - "resourcepacks" = pkgs.linkFarm "resourcepacks" cfg.resourcepacks; + "packs" = pkgs.linkFarm "packs" cfg.resourcepacks; + "addons" = addonsFolder; }; inherit (lib) mkOption; in { + imports = [ + (lib.mkRenamedOptionModule [ "services" "bluemap" "resourcepacks" ] [ "services" "bluemap" "packs" ]) + ]; + options.services.bluemap = { enable = lib.mkEnableOption "bluemap"; @@ -219,6 +227,26 @@ in { ''; }; + addons = mkOption { + type = lib.types.attrsOf lib.types.pathInStore; + default = { }; + description = '' + A set of jar addons to be loaded. + + See for a list of officially recognized addons. + ''; + + example = lib.literalExpression '' + { + blueBridge = ./blueBridge.jar; + blueBorder = pkgs.fetchurl { + url = "https://github.com/pop4959/BlueBorder/releases/download/1.1.1/BlueBorder-1.1.1.jar"; + hash = "..."; + }; + } + ''; + }; + storage = mkOption { type = lib.types.attrsOf (lib.types.submodule { freeformType = format.type; @@ -249,10 +277,13 @@ in { ''; }; - resourcepacks = mkOption { + packs = mkOption { type = lib.types.attrsOf lib.types.pathInStore; default = { }; - description = "A set of resourcepacks to use, loaded in alphabetical order"; + description = '' + A set of resourcepacks, datapacks, and mods to extract resources from, + loaded in alphabetical order. + ''; }; }; @@ -293,11 +324,12 @@ in { "${cfg.host}" = { root = config.services.bluemap.webRoot; locations = { - "~* ^/maps/[^/]*/tiles/[^/]*.json$".extraConfig = '' - error_page 404 =200 /assets/emptyTile.json; + "@empty".return = "204"; + + "~* ^/maps/[^/]*/tiles/".extraConfig = '' + error_page 404 = @empty; gzip_static always; ''; - "~* ^/maps/[^/]*/tiles/[^/]*.png$".tryFiles = "$uri =204"; }; }; }; diff --git a/nixos/modules/services/web-apps/collabora-online.nix b/nixos/modules/services/web-apps/collabora-online.nix new file mode 100644 index 000000000000..122674b67110 --- /dev/null +++ b/nixos/modules/services/web-apps/collabora-online.nix @@ -0,0 +1,200 @@ +{ + config, + lib, + pkgs, + utils, + ... +}: + +let + cfg = config.services.collabora-online; + + freeformType = lib.types.attrsOf ((pkgs.formats.json { }).type) // { + description = '' + `coolwsd.xml` configuration type, used to override values in the default configuration. + + Attribute names correspond to XML tags unless prefixed with `@`. Nested attribute sets + correspond to nested XML tags. Attribute prefixed with `@` correspond to XML attributes. E.g., + `{ storage.wopi."@allow" = true; }` in Nix corresponds to + `` in `coolwsd.xml`, or `--o:storage.wopi[@allow]=true` + in the command line. + + Arrays correspond to multiple elements with the same tag name. E.g. + `{ host = [ '''127\.0\.0\.1''' "::1" ]; }` in Nix corresponds to + ```xml + + 127\.0\.0\.1 + ::1 + + ``` + in `coolwsd.xml`, or + `--o:net.post_allow.host[0]='127\.0\.0\.1 --o:net.post_allow.host[1]=::1` in the command line. + + Null values could be used to remove an element from the default configuration. + ''; + }; + + configFile = + pkgs.runCommandLocal "coolwsd.xml" + { + nativeBuildInputs = [ + pkgs.jq + pkgs.yq-go + ]; + userConfig = builtins.toJSON { config = cfg.settings; }; + passAsFile = [ "userConfig" ]; + } + # Merge the cfg.settings into the default coolwsd.xml. + # See https://github.com/CollaboraOnline/online/issues/10049. + '' + yq --input-format=xml \ + --xml-attribute-prefix=@ \ + --output-format=json \ + ${cfg.package}/etc/coolwsd/coolwsd.xml \ + > ./default_coolwsd.json + + jq '.[0] * .[1] | del(..|nulls)' \ + --slurp \ + ./default_coolwsd.json \ + $userConfigPath \ + > ./merged.json + + yq --output-format=xml \ + --xml-attribute-prefix=@ \ + ./merged.json \ + > $out + ''; +in +{ + options.services.collabora-online = { + enable = lib.mkEnableOption "collabora-online"; + + package = lib.mkPackageOption pkgs "Collabora Online" { default = "collabora-online"; }; + + port = lib.mkOption { + type = lib.types.port; + default = 9980; + description = "Listening port"; + }; + + settings = lib.mkOption { + type = freeformType; + default = { }; + description = '' + Configuration for Collabora Online WebSocket Daemon, see + , or + for the default + configuration. + ''; + }; + + aliasGroups = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule { + options = { + host = lib.mkOption { + type = lib.types.str; + example = "scheme://hostname:port"; + description = "Hostname to allow or deny."; + }; + + aliases = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ + "scheme://aliasname1:port" + "scheme://aliasname2:port" + ]; + description = "A list of regex pattern of aliasname."; + }; + }; + } + ); + default = [ ]; + description = "Alias groups to use."; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments to pass to the service."; + }; + }; + + config = lib.mkIf cfg.enable { + services.collabora-online.settings = { + child_root_path = lib.mkDefault "/var/lib/cool/child-roots"; + sys_template_path = lib.mkDefault "/var/lib/cool/systemplate"; + + file_server_root_path = lib.mkDefault "${config.services.collabora-online.package}/share/coolwsd"; + + # Use mount namespaces instead of setcap'd coolmount/coolforkit. + mount_namespaces = lib.mkDefault true; + + # By default, use dummy self-signed certificates provided for testing. + ssl.ca_file_path = lib.mkDefault "${config.services.collabora-online.package}/etc/coolwsd/ca-chain.cert.pem"; + ssl.cert_file_path = lib.mkDefault "${config.services.collabora-online.package}/etc/coolwsd/cert.pem"; + ssl.key_file_path = lib.mkDefault "${config.services.collabora-online.package}/etc/coolwsd/key.pem"; + }; + + users.users.cool = { + isSystemUser = true; + group = "cool"; + }; + users.groups.cool = { }; + + systemd.services.coolwsd-systemplate-setup = { + description = "Collabora Online WebSocket Daemon Setup"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = utils.escapeSystemdExecArgs [ + "${cfg.package}/bin/coolwsd-systemplate-setup" + "/var/lib/cool/systemplate" + "${cfg.package.libreoffice}/lib/collaboraoffice" + ]; + RemainAfterExit = true; + StateDirectory = "cool"; + Type = "oneshot"; + User = "cool"; + }; + }; + + systemd.services.coolwsd = { + description = "Collabora Online WebSocket Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ + "network.target" + "coolwsd-systemplate-setup.service" + ]; + + environment = builtins.listToAttrs ( + lib.imap1 (n: ag: { + name = "aliasgroup${toString n}"; + value = lib.concatStringsSep "," ([ ag.host ] ++ ag.aliases); + }) cfg.aliasGroups + ); + + serviceConfig = { + ExecStart = utils.escapeSystemdExecArgs ( + [ + "${cfg.package}/bin/coolwsd" + "--config-file=${configFile}" + "--port=${toString cfg.port}" + "--use-env-vars" + "--version" + ] + ++ cfg.extraArgs + ); + KillMode = "mixed"; + KillSignal = "SIGINT"; + LimitNOFILE = "infinity:infinity"; + Restart = "always"; + StateDirectory = "cool"; + TimeoutStopSec = 120; + User = "cool"; + }; + }; + }; + + meta.maintainers = [ lib.maintainers.xzfc ]; +} diff --git a/nixos/modules/services/web-apps/davis.nix b/nixos/modules/services/web-apps/davis.nix index d9b28020dc2d..621f2ff20e2b 100644 --- a/nixos/modules/services/web-apps/davis.nix +++ b/nixos/modules/services/web-apps/davis.nix @@ -493,7 +493,7 @@ in }; "~* ^/.well-known/(caldav|carddav)$" = { extraConfig = '' - return 302 $http_x_forwarded_proto://$host/dav/; + return 302 https://$host/dav/; ''; }; "~ ^(.+\.php)(.*)$" = { @@ -505,7 +505,7 @@ in fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_split_path_info ^(.+\.php)(.*)$; - fastcgi_param X-Forwarded-Proto $http_x_forwarded_proto; + fastcgi_param X-Forwarded-Proto https; fastcgi_param X-Forwarded-Port $http_x_forwarded_port; ''; }; diff --git a/nixos/modules/services/web-apps/dependency-track.nix b/nixos/modules/services/web-apps/dependency-track.nix new file mode 100644 index 000000000000..ba3dbee97288 --- /dev/null +++ b/nixos/modules/services/web-apps/dependency-track.nix @@ -0,0 +1,608 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.dependency-track; + + settingsFormat = pkgs.formats.javaProperties { }; + + frontendConfigFormat = pkgs.formats.json { }; + frontendConfigFile = frontendConfigFormat.generate "config.json" { + API_BASE_URL = cfg.frontend.baseUrl; + OIDC_ISSUER = cfg.oidc.issuer; + OIDC_CLIENT_ID = cfg.oidc.clientId; + OIDC_SCOPE = cfg.oidc.scope; + OIDC_FLOW = cfg.oidc.flow; + OIDC_LOGIN_BUTTON_TEXT = cfg.oidc.loginButtonText; + }; + + sslEnabled = + config.services.nginx.virtualHosts.${cfg.nginx.domain}.addSSL + || config.services.nginx.virtualHosts.${cfg.nginx.domain}.forceSSL + || config.services.nginx.virtualHosts.${cfg.nginx.domain}.onlySSL + || config.services.nginx.virtualHosts.${cfg.nginx.domain}.enableACME; + + assertStringPath = + optionName: value: + if lib.isPath value then + throw '' + services.dependency-track.${optionName}: + ${toString value} + is a Nix path, but should be a string, since Nix + paths are copied into the world-readable Nix store. + '' + else + value; + + filterNull = lib.filterAttrs (_: v: v != null); + + renderSettings = + settings: + lib.mapAttrs' ( + n: v: + lib.nameValuePair (lib.toUpper (lib.replaceStrings [ "." ] [ "_" ] n)) ( + if lib.isBool v then lib.boolToString v else v + ) + ) (filterNull settings); +in +{ + options.services.dependency-track = { + enable = lib.mkEnableOption "dependency-track"; + + package = lib.mkPackageOption pkgs "dependency-track" { }; + + logLevel = lib.mkOption { + type = lib.types.enum [ + "INFO" + "WARN" + "ERROR" + "DEBUG" + "TRACE" + ]; + default = "INFO"; + description = "Log level for dependency-track"; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 8080; + description = '' + On which port dependency-track should listen for new HTTP connections. + ''; + }; + + javaArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "-Xmx4G" ]; + description = "Java options passed to JVM"; + }; + + database = { + type = lib.mkOption { + type = lib.types.enum [ + "h2" + "postgresql" + "manual" + ]; + default = "postgresql"; + description = '' + `h2` database is not recommended for a production setup. + `postgresql` this settings it recommended for production setups. + `manual` the module doesn't handle database settings. + ''; + }; + + createLocally = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether a database should be automatically created on the + local host. Set this to false if you plan on provisioning a + local database yourself. + ''; + }; + + databaseName = lib.mkOption { + type = lib.types.str; + default = "dependency-track"; + description = '' + Database name to use when connecting to an external or + manually provisioned database; has no effect when a local + database is automatically provisioned. + + To use this with a local database, set {option}`services.dependency-track.database.createLocally` + to `false` and create the database and user. + ''; + }; + + username = lib.mkOption { + type = lib.types.str; + default = "dependency-track"; + description = '' + Username to use when connecting to an external or manually + provisioned database; has no effect when a local database is + automatically provisioned. + + To use this with a local database, set {option}`services.dependency-track.database.createLocally` + to `false` and create the database and user. + ''; + }; + + passwordFile = lib.mkOption { + type = lib.types.path; + example = "/run/keys/db_password"; + apply = assertStringPath "passwordFile"; + description = '' + The path to a file containing the database password. + ''; + }; + }; + + ldap.bindPasswordFile = lib.mkOption { + type = lib.types.path; + example = "/run/keys/ldap_bind_password"; + apply = assertStringPath "bindPasswordFile"; + description = '' + The path to a file containing the LDAP bind password. + ''; + }; + + frontend = { + baseUrl = lib.mkOption { + type = lib.types.str; + default = lib.optionalString cfg.nginx.enable "${ + if sslEnabled then "https" else "http" + }://${cfg.nginx.domain}"; + defaultText = lib.literalExpression '' + lib.optionalString config.services.dependency-track.nginx.enable "''${ + if sslEnabled then "https" else "http" + }://''${config.services.dependency-track.nginx.domain}"; + ''; + description = '' + The base URL of the API server. + + NOTE: + * This URL must be reachable by the browsers of your users. + * The frontend container itself does NOT communicate with the API server directly, it just serves static files. + * When deploying to dedicated servers, please use the external IP or domain of the API server. + ''; + }; + }; + + oidc = { + enable = lib.mkEnableOption "oidc support"; + issuer = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Defines the issuer URL to be used for OpenID Connect. + See alpine.oidc.issuer property of the API server. + ''; + }; + clientId = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Defines the client ID for OpenID Connect. + ''; + }; + scope = lib.mkOption { + type = lib.types.str; + default = "openid profile email"; + description = '' + Defines the scopes to request for OpenID Connect. + See also: https://openid.net/specs/openid-connect-basic-1_0.html#Scopes + ''; + }; + flow = lib.mkOption { + type = lib.types.enum [ + "code" + "implicit" + ]; + default = "code"; + description = '' + Specifies the OpenID Connect flow to use. + Values other than "implicit" will result in the Code+PKCE flow to be used. + Usage of the implicit flow is strongly discouraged, but may be necessary when + the IdP of choice does not support the Code+PKCE flow. + See also: + - https://oauth.net/2/grant-types/implicit/ + - https://oauth.net/2/pkce/ + ''; + }; + loginButtonText = lib.mkOption { + type = lib.types.str; + default = "Login with OpenID Connect"; + description = '' + Defines the scopes to request for OpenID Connect. + See also: https://openid.net/specs/openid-connect-basic-1_0.html#Scopes + ''; + }; + usernameClaim = lib.mkOption { + type = lib.types.str; + default = "name"; + example = "preferred_username"; + description = '' + Defines the name of the claim that contains the username in the provider's userinfo endpoint. + Common claims are "name", "username", "preferred_username" or "nickname". + See also: https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse + ''; + }; + userProvisioning = lib.mkOption { + type = lib.types.bool; + default = false; + example = true; + description = '' + Specifies if mapped OpenID Connect accounts are automatically created upon successful + authentication. When a user logs in with a valid access token but an account has + not been previously provisioned, an authentication failure will be returned. + This allows admins to control specifically which OpenID Connect users can access the + system and which users cannot. When this value is set to true, a local OpenID Connect + user will be created and mapped to the OpenID Connect account automatically. This + automatic provisioning only affects authentication, not authorization. + ''; + }; + teamSynchronization = lib.mkOption { + type = lib.types.bool; + default = false; + example = true; + description = '' + This option will ensure that team memberships for OpenID Connect users are dynamic and + synchronized with membership of OpenID Connect groups or assigned roles. When a team is + mapped to an OpenID Connect group, all local OpenID Connect users will automatically be + assigned to the team if they are a member of the group the team is mapped to. If the user + is later removed from the OpenID Connect group, they will also be removed from the team. This + option provides the ability to dynamically control user permissions via the identity provider. + Note that team synchronization is only performed during user provisioning and after successful + authentication. + ''; + }; + teams = { + claim = lib.mkOption { + type = lib.types.str; + default = "groups"; + description = '' + Defines the name of the claim that contains group memberships or role assignments in the provider's userinfo endpoint. + The claim must be an array of strings. Most public identity providers do not support group or role management. + When using a customizable / on-demand hosted identity provider, name, content, and inclusion in the userinfo endpoint + will most likely need to be configured. + ''; + }; + default = lib.mkOption { + type = lib.types.nullOr lib.types.commas; + default = null; + description = '' + Defines one or more team names that auto-provisioned OIDC users shall be added to. + Multiple team names may be provided as comma-separated list. + + Has no effect when {option}`services.dependency-track.oidc.userProvisioning`=false, + or {option}`services.dependency-track.oidc.teamSynchronization`=true. + ''; + }; + }; + }; + + nginx = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = '' + Whether to set up an nginx virtual host. + ''; + }; + + domain = lib.mkOption { + type = lib.types.str; + example = "dtrack.example.com"; + description = '' + The domain name under which to set up the virtual host. + ''; + }; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + "alpine.data.directory" = lib.mkOption { + type = lib.types.path; + default = "/var/lib/dependency-track"; + description = '' + Defines the path to the data directory. This directory will hold logs, keys, + and any database or index files along with application-specific files or + directories. + ''; + }; + "alpine.database.mode" = lib.mkOption { + type = lib.types.enum [ + "server" + "embedded" + "external" + ]; + default = + if cfg.database.type == "h2" then + "embedded" + else if cfg.database.type == "postgresql" then + "external" + else + null; + defaultText = lib.literalExpression '' + if config.services.dependency-track.database.type == "h2" then "embedded" + else if config.services.dependency-track.database.type == "postgresql" then "external" + else null + ''; + description = '' + Defines the database mode of operation. Valid choices are: + 'server', 'embedded', and 'external'. + In server mode, the database will listen for connections from remote hosts. + In embedded mode, the system will be more secure and slightly faster. + External mode should be used when utilizing an external database server + (i.e. mysql, postgresql, etc). + ''; + }; + "alpine.database.url" = lib.mkOption { + type = lib.types.str; + default = + if cfg.database.type == "h2" then + "jdbc:h2:/var/lib/dependency-track/db" + else if cfg.database.type == "postgresql" then + "jdbc:postgresql:${cfg.database.databaseName}?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/run/postgresql/.s.PGSQL.5432" + else + null; + + defaultText = lib.literalExpression '' + if config.services.dependency-track.database.type == "h2" then "jdbc:h2:/var/lib/dependency-track/db" + else if config.services.dependency-track.database.type == "postgresql" then "jdbc:postgresql:''${config.services.dependency-track.database.name}?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=/run/postgresql/.s.PGSQL.5432" + else null + ''; + description = "Specifies the JDBC URL to use when connecting to the database."; + }; + "alpine.database.driver" = lib.mkOption { + type = lib.types.enum [ + "org.h2.Driver" + "org.postgresql.Driver" + "com.microsoft.sqlserver.jdbc.SQLServerDriver" + "com.mysql.cj.jdbc.Driver" + ]; + default = + if cfg.database.type == "h2" then + "org.h2.Driver" + else if cfg.database.type == "postgresql" then + "org.postgresql.Driver" + else + null; + defaultText = lib.literalExpression '' + if config.services.dependency-track.database.type == "h2" then "org.h2.Driver" + else if config.services.dependency-track.database.type == "postgresql" then "org.postgresql.Driver" + else null; + ''; + description = "Specifies the JDBC driver class to use."; + }; + "alpine.database.username" = lib.mkOption { + type = lib.types.str; + default = if cfg.database.createLocally then "dependency-track" else cfg.database.username; + defaultText = lib.literalExpression '' + if config.services.dependency-track.database.createLocally then "dependency-track" + else config.services.dependency-track.database.username + ''; + description = "Specifies the username to use when authenticating to the database."; + }; + "alpine.ldap.enabled" = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Defines if LDAP will be used for user authentication. If enabled, + alpine.ldap.* properties should be set accordingly. + ''; + }; + "alpine.oidc.enabled" = lib.mkOption { + type = lib.types.bool; + default = cfg.oidc.enable; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.enable"; + description = '' + Defines if OpenID Connect will be used for user authentication. + If enabled, alpine.oidc.* properties should be set accordingly. + ''; + }; + "alpine.oidc.client.id" = lib.mkOption { + type = lib.types.str; + default = cfg.oidc.clientId; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.clientId"; + description = '' + Defines the client ID to be used for OpenID Connect. + The client ID should be the same as the one configured for the frontend, + and will only be used to validate ID tokens. + ''; + }; + "alpine.oidc.issuer" = lib.mkOption { + type = lib.types.str; + default = cfg.oidc.issuer; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.issuer"; + description = '' + Defines the issuer URL to be used for OpenID Connect. + This issuer MUST support provider configuration via the /.well-known/openid-configuration endpoint. + See also: + - https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata + - https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig + ''; + }; + "alpine.oidc.username.claim" = lib.mkOption { + type = lib.types.str; + default = cfg.oidc.usernameClaim; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.usernameClaim"; + description = '' + Defines the name of the claim that contains the username in the provider's userinfo endpoint. + Common claims are "name", "username", "preferred_username" or "nickname". + See also: https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse + ''; + }; + "alpine.oidc.user.provisioning" = lib.mkOption { + type = lib.types.bool; + default = cfg.oidc.userProvisioning; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.userProvisioning"; + description = '' + Specifies if mapped OpenID Connect accounts are automatically created upon successful + authentication. When a user logs in with a valid access token but an account has + not been previously provisioned, an authentication failure will be returned. + This allows admins to control specifically which OpenID Connect users can access the + system and which users cannot. When this value is set to true, a local OpenID Connect + user will be created and mapped to the OpenID Connect account automatically. This + automatic provisioning only affects authentication, not authorization. + ''; + }; + "alpine.oidc.team.synchronization" = lib.mkOption { + type = lib.types.bool; + default = cfg.oidc.teamSynchronization; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.teamSynchronization"; + description = '' + This option will ensure that team memberships for OpenID Connect users are dynamic and + synchronized with membership of OpenID Connect groups or assigned roles. When a team is + mapped to an OpenID Connect group, all local OpenID Connect users will automatically be + assigned to the team if they are a member of the group the team is mapped to. If the user + is later removed from the OpenID Connect group, they will also be removed from the team. This + option provides the ability to dynamically control user permissions via the identity provider. + Note that team synchronization is only performed during user provisioning and after successful + authentication. + ''; + }; + "alpine.oidc.teams.claim" = lib.mkOption { + type = lib.types.str; + default = cfg.oidc.teams.claim; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.teams.claim"; + description = '' + Defines the name of the claim that contains group memberships or role assignments in the provider's userinfo endpoint. + The claim must be an array of strings. Most public identity providers do not support group or role management. + When using a customizable / on-demand hosted identity provider, name, content, and inclusion in the userinfo endpoint + will most likely need to be configured. + ''; + }; + "alpine.oidc.teams.default" = lib.mkOption { + type = lib.types.nullOr lib.types.commas; + default = cfg.oidc.teams.default; + defaultText = lib.literalExpression "config.services.dependency-track.oidc.teams.default"; + description = '' + Defines one or more team names that auto-provisioned OIDC users shall be added to. + Multiple team names may be provided as comma-separated list. + + Has no effect when {option}`services.dependency-track.oidc.userProvisioning`=false, + or {option}`services.dependency-track.oidc.teamSynchronization`=true. + ''; + }; + }; + }; + default = { }; + description = "See https://docs.dependencytrack.org/getting-started/configuration/#default-configuration for possible options"; + }; + }; + + config = lib.mkIf cfg.enable { + services.nginx = lib.mkIf cfg.nginx.enable { + enable = true; + recommendedGzipSettings = lib.mkDefault true; + recommendedOptimisation = lib.mkDefault true; + recommendedProxySettings = lib.mkDefault true; + recommendedTlsSettings = lib.mkDefault true; + upstreams.dependency-track.servers."localhost:${toString cfg.port}" = { }; + virtualHosts.${cfg.nginx.domain} = { + locations = { + "/".proxyPass = "http://dependency-track"; + "= /static/config.json".alias = frontendConfigFile; + }; + }; + }; + + systemd.services.dependency-track-postgresql-init = lib.mkIf cfg.database.createLocally { + after = [ "postgresql.service" ]; + before = [ "dependency-track.service" ]; + bindsTo = [ "postgresql.service" ]; + path = [ config.services.postgresql.package ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "postgres"; + Group = "postgres"; + LoadCredential = [ "db_password:${cfg.database.passwordFile}" ]; + PrivateTmp = true; + }; + script = '' + set -eou pipefail + shopt -s inherit_errexit + + # Read the password from the credentials directory and + # escape any single quotes by adding additional single + # quotes after them, following the rules laid out here: + # https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS + db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")" + db_password="''${db_password//\'/\'\'}" + + echo "CREATE ROLE \"dependency-track\" WITH LOGIN PASSWORD '$db_password' CREATEDB" > /tmp/create_role.sql + psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='dependency-track'" | grep -q 1 || psql -tA --file="/tmp/create_role.sql" + psql -tAc "SELECT 1 FROM pg_database WHERE datname = 'dependency-track'" | grep -q 1 || psql -tAc 'CREATE DATABASE "dependency-track" OWNER "dependency-track"' + ''; + }; + + services.postgresql.enable = lib.mkIf cfg.database.createLocally (lib.mkDefault true); + + systemd.services."dependency-track" = + let + databaseServices = + if cfg.database.createLocally then + [ + "dependency-track-postgresql-init.service" + "postgresql.service" + ] + else + [ ]; + in + { + description = "Dependency Track"; + wantedBy = [ "multi-user.target" ]; + requires = databaseServices; + after = databaseServices; + # provide settings via env vars to allow overriding default settings. + environment = { + HOME = "%S/dependency-track"; + } // renderSettings cfg.settings; + serviceConfig = { + User = "dependency-track"; + Group = "dependency-track"; + DynamicUser = true; + StateDirectory = "dependency-track"; + LoadCredential = + [ "db_password:${cfg.database.passwordFile}" ] + ++ lib.optional cfg.settings."alpine.ldap.enabled" + "ldap_bind_password:${cfg.ldap.bindPasswordFile}"; + }; + script = '' + set -eou pipefail + shopt -s inherit_errexit + + export ALPINE_DATABASE_PASSWORD_FILE="$CREDENTIALS_DIRECTORY/db_password" + ${lib.optionalString cfg.settings."alpine.ldap.enabled" '' + export ALPINE_LDAP_BIND_PASSWORD="$(<"$CREDENTIALS_DIRECTORY/ldap_bind_password")" + ''} + + exec ${lib.getExe pkgs.jre_headless} ${ + lib.escapeShellArgs ( + cfg.javaArgs + ++ [ + "-DdependencyTrack.logging.level=${cfg.logLevel}" + "-jar" + "${cfg.package}/share/dependency-track/dependency-track.jar" + "-port" + "${toString cfg.port}" + ] + ) + } + ''; + }; + }; + + meta = { + maintainers = lib.teams.cyberus.members; + }; +} diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix index c5ea809c8d59..b288a08efd85 100644 --- a/nixos/modules/services/web-apps/dokuwiki.nix +++ b/nixos/modules/services/web-apps/dokuwiki.nix @@ -17,6 +17,10 @@ let extraConfig = mkPhpIni cfg.phpOptions; }; + # "you're escaped" -> "'you\'re escaped'" + # https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.single + toPhpString = s: "'${escape [ "'" "\\" ] s}'"; + dokuwikiAclAuthConfig = hostName: cfg: let inherit (cfg) acl; acl_gen = concatMapStringsSep "\n" (l: "${l.page} \t ${l.actor} \t ${toString l.level}"); @@ -43,12 +47,12 @@ let mkPhpValue = v: let isHasAttr = s: isAttrs v && hasAttr s v; in - if isString v then escapeShellArg v + if isString v then toPhpString v # NOTE: If any value contains a , (comma) this will not get escaped - else if isList v && any lib.strings.isCoercibleToString v then escapeShellArg (concatMapStringsSep "," toString v) + else if isList v && strings.isConvertibleWithToString v then toPhpString (concatMapStringsSep "," toString v) else if isInt v then toString v else if isBool v then toString (if v then 1 else 0) - else if isHasAttr "_file" then "trim(file_get_contents(${lib.escapeShellArg v._file}))" + else if isHasAttr "_file" then "trim(file_get_contents(${toPhpString (toString v._file)}))" else if isHasAttr "_raw" then v._raw else abort "The dokuwiki localConf value ${lib.generators.toPretty {} v} can not be encoded." ; @@ -59,7 +63,7 @@ let [" = ${mkPhpValue v};"] else mkPhpAttrVals v; - in map (e: "[${escapeShellArg k}]${e}") (flatten values); + in map (e: "[${toPhpString k}]${e}") (flatten values); dokuwikiLocalConfig = hostName: cfg: let conf_gen = c: map (v: "$conf${v}") (mkPhpAttrVals c); diff --git a/nixos/modules/services/web-apps/firefly-iii-data-importer.nix b/nixos/modules/services/web-apps/firefly-iii-data-importer.nix new file mode 100644 index 000000000000..5d1712a506d8 --- /dev/null +++ b/nixos/modules/services/web-apps/firefly-iii-data-importer.nix @@ -0,0 +1,301 @@ +{ + pkgs, + config, + lib, + ... +}: + +let + cfg = config.services.firefly-iii-data-importer; + + user = cfg.user; + group = cfg.group; + + defaultUser = "firefly-iii-data-importer"; + defaultGroup = "firefly-iii-data-importer"; + + artisan = "${cfg.package}/artisan"; + + env-file-values = lib.attrsets.mapAttrs' ( + n: v: lib.attrsets.nameValuePair (lib.strings.removeSuffix "_FILE" n) v + ) (lib.attrsets.filterAttrs (n: v: lib.strings.hasSuffix "_FILE" n) cfg.settings); + env-nonfile-values = lib.attrsets.filterAttrs (n: v: !lib.strings.hasSuffix "_FILE" n) cfg.settings; + + data-importer-maintenance = pkgs.writeShellScript "data-importer-maintenance.sh" '' + set -a + ${lib.strings.toShellVars env-nonfile-values} + ${lib.strings.concatLines ( + lib.attrsets.mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values + )} + set +a + ${artisan} package:discover + ${artisan} cache:clear + ${artisan} config:cache + ''; + + commonServiceConfig = { + Type = "oneshot"; + User = user; + Group = group; + StateDirectory = "firefly-iii-data-importer"; + ReadWritePaths = [ cfg.dataDir ]; + WorkingDirectory = cfg.package; + PrivateTmp = true; + PrivateDevices = true; + CapabilityBoundingSet = ""; + AmbientCapabilities = ""; + ProtectSystem = "strict"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + ProtectClock = true; + ProtectHostname = true; + ProtectHome = "tmpfs"; + ProtectKernelLogs = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + PrivateNetwork = false; + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service @resources" + "~@obsolete @privileged" + ]; + RestrictSUIDSGID = true; + RemoveIPC = true; + NoNewPrivileges = true; + RestrictRealtime = true; + RestrictNamespaces = true; + LockPersonality = true; + PrivateUsers = true; + }; + +in +{ + + options.services.firefly-iii-data-importer = { + enable = lib.mkEnableOption "Firefly III Data Importer"; + + user = lib.mkOption { + type = lib.types.str; + default = defaultUser; + description = "User account under which firefly-iii-data-importer runs."; + }; + + group = lib.mkOption { + type = lib.types.str; + default = if cfg.enableNginx then "nginx" else defaultGroup; + defaultText = "If `services.firefly-iii-data-importer.enableNginx` is true then `nginx` else ${defaultGroup}"; + description = '' + Group under which firefly-iii-data-importer runs. It is best to set this to the group + of whatever webserver is being used as the frontend. + ''; + }; + + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/firefly-iii-data-importer"; + description = '' + The place where firefly-iii data importer stores its state. + ''; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.firefly-iii-data-importer; + defaultText = lib.literalExpression "pkgs.firefly-iii-data-importer"; + description = '' + The firefly-iii-data-importer package served by php-fpm and the webserver of choice. + This option can be used to point the webserver to the correct root. It + may also be used to set the package to a different version, say a + development version. + ''; + apply = + firefly-iii-data-importer: + firefly-iii-data-importer.override (prev: { + dataDir = cfg.dataDir; + }); + }; + + enableNginx = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable nginx or not. If enabled, an nginx virtual host will + be created for access to firefly-iii data importer. If not enabled, then you may use + `''${config.services.firefly-iii-data-importer.package}` as your document root in + whichever webserver you wish to setup. + ''; + }; + + virtualHost = lib.mkOption { + type = lib.types.str; + default = "localhost"; + description = '' + The hostname at which you wish firefly-iii-data-importer to be served. If you have + enabled nginx using `services.firefly-iii-data-importer.enableNginx` then this will + be used. + ''; + }; + + poolConfig = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.oneOf [ + lib.types.str + lib.types.int + lib.types.bool + ] + ); + default = { }; + defaultText = lib.literalExpression '' + { + "pm" = "dynamic"; + "pm.max_children" = 32; + "pm.start_servers" = 2; + "pm.min_spare_servers" = 2; + "pm.max_spare_servers" = 4; + "pm.max_requests" = 500; + } + ''; + description = '' + Options for the Firefly III Data Importer PHP pool. See the documentation on php-fpm.conf + for details on configuration directives. + ''; + }; + + settings = lib.mkOption { + default = { }; + description = '' + Options for firefly-iii data importer configuration. Refer to + for + details on supported values. All