diff --git a/.editorconfig b/.editorconfig
index b780def5d11e..17f92c50d169 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -67,10 +67,6 @@ indent_style = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
-[pkgs/build-support/upstream-updater/**]
-indent_style = unset
-trim_trailing_whitespace = unset
-
[pkgs/development/compilers/elm/registry.dat]
end_of_line = unset
insert_final_newline = unset
@@ -84,10 +80,3 @@ trim_trailing_whitespace = unset
[pkgs/tools/misc/timidity/timidity.cfg]
trim_trailing_whitespace = unset
-
-[pkgs/tools/security/enpass/data.json]
-insert_final_newline = unset
-trim_trailing_whitespace = unset
-
-[pkgs/top-level/emscripten-packages.nix]
-trim_trailing_whitespace = unset
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 000000000000..4a581f9dcea3
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,32 @@
+# This file contains a list of commits that are not likely what you
+# are looking for in a blame, such as mass reformatting or renaming.
+# You can set this file as a default ignore file for blame by running
+# the following command.
+#
+# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
+#
+# To temporarily not use this file add
+# --ignore-revs-file=""
+# to your blame command.
+#
+# The ignoreRevsFile can't be set globally due to blame failing if the file isn't present.
+# To not have to set the option in every repository it is needed in,
+# save the following script in your path with the name "git-bblame"
+# now you can run
+# $ git bblame $FILE
+# to use the .git-blame-ignore-revs file if it is present.
+#
+# #!/usr/bin/env bash
+# repo_root=$(git rev-parse --show-toplevel)
+# if [[ -e $repo_root/.git-blame-ignore-revs ]]; then
+# git blame --ignore-revs-file="$repo_root/.git-blame-ignore-revs" $@
+# else
+# git blame $@
+# fi
+
+
+# nixos/modules/rename: Sort alphabetically
+1f71224fe86605ef4cd23ed327b3da7882dad382
+
+# nixos: fix module paths in rename.nix
+d08ede042b74b8199dc748323768227b88efcf7c
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f2b58f80ee15..008d51b29aa4 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -10,9 +10,6 @@
# 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.
-# We still add the team to the list next to its members, this helps keeping things
-# in sync. (Put non team members before the team to distinguish them.)
-# See https://github.com/NixOS/nixpkgs/issues/124085 for more details
# This file
/.github/CODEOWNERS @edolstra
@@ -39,10 +36,10 @@
/pkgs/top-level/stage.nix @nbp @Ericson2314 @matthewbauer
/pkgs/top-level/splice.nix @Ericson2314 @matthewbauer
/pkgs/top-level/release-cross.nix @Ericson2314 @matthewbauer
-/pkgs/stdenv/generic @Ericson2314 @matthewbauer @cab404
+/pkgs/stdenv/generic @Ericson2314 @matthewbauer
/pkgs/stdenv/cross @Ericson2314 @matthewbauer
-/pkgs/build-support/cc-wrapper @Ericson2314 @orivej
-/pkgs/build-support/bintools-wrapper @Ericson2314 @orivej
+/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 @aszlig
@@ -77,6 +74,12 @@
# NixOS integration test driver
/nixos/lib/test-driver @tfc
+# 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
+
# Updaters
## update.nix
/maintainers/scripts/update.nix @jtojnar
@@ -91,8 +94,7 @@
/pkgs/development/python-modules @FRidh @jonringer
/doc/languages-frameworks/python.section.md @FRidh
/pkgs/development/tools/poetry2nix @adisbladis
-/pkgs/development/interpreters/python/hooks @FRidh @jonringer @DavHau
-/pkgs/development/interpreters/python/conda @DavHau
+/pkgs/development/interpreters/python/hooks @FRidh @jonringer
# Haskell
/doc/languages-frameworks/haskell.section.md @cdepillabout @sternenseemann @maralorn @expipiplus1
@@ -104,13 +106,13 @@
/pkgs/top-level/haskell-packages.nix @cdepillabout @sternenseemann @maralorn @expipiplus1
# Perl
-/pkgs/development/interpreters/perl @volth @stigtsp @zakame
-/pkgs/top-level/perl-packages.nix @volth @stigtsp @zakame
-/pkgs/development/perl-modules @volth @stigtsp @zakame
+/pkgs/development/interpreters/perl @stigtsp @zakame
+/pkgs/top-level/perl-packages.nix @stigtsp @zakame
+/pkgs/development/perl-modules @stigtsp @zakame
# R
-/pkgs/applications/science/math/R @jbedo @bcdarwin
-/pkgs/development/r-modules @jbedo @bcdarwin
+/pkgs/applications/science/math/R @jbedo
+/pkgs/development/r-modules @jbedo
# Ruby
/pkgs/development/interpreters/ruby @marsam
@@ -119,10 +121,7 @@
# Rust
/pkgs/development/compilers/rust @Mic92 @LnL7 @zowoq
/pkgs/build-support/rust @zowoq
-
-# Darwin-related
-/pkgs/stdenv/darwin @NixOS/darwin-maintainers
-/pkgs/os-specific/darwin @NixOS/darwin-maintainers
+/doc/languages-frameworks/rust.section.md @zowoq
# C compilers
/pkgs/development/compilers/gcc @matthewbauer
@@ -132,15 +131,6 @@
/pkgs/top-level/unix-tools.nix @matthewbauer
/pkgs/development/tools/xcbuild @matthewbauer
-# Beam-related (Erlang, Elixir, LFE, etc)
-/pkgs/development/beam-modules @gleber
-/pkgs/development/interpreters/erlang @gleber
-/pkgs/development/interpreters/lfe @gleber
-/pkgs/development/interpreters/elixir @gleber
-/pkgs/development/tools/build-managers/rebar @gleber
-/pkgs/development/tools/build-managers/rebar3 @gleber
-/pkgs/development/tools/erlang @gleber
-
# Audio
/nixos/modules/services/audio/botamusique.nix @mweinelt
/nixos/modules/services/audio/snapserver.nix @mweinelt
@@ -208,7 +198,7 @@
/pkgs/development/idris-modules @Infinisil
# Bazel
-/pkgs/development/tools/build-managers/bazel @mboes @Profpatsch
+/pkgs/development/tools/build-managers/bazel @Profpatsch
# NixOS modules for e-mail and dns services
/nixos/modules/services/mail/mailman.nix @peti
@@ -217,18 +207,18 @@
/nixos/modules/services/mail/rspamd.nix @peti
# Emacs
-/pkgs/applications/editors/emacs-modes @adisbladis
-/pkgs/applications/editors/emacs @adisbladis
-/pkgs/top-level/emacs-packages.nix @adisbladis
+/pkgs/applications/editors/emacs/elisp-packages @adisbladis
+/pkgs/applications/editors/emacs @adisbladis
+/pkgs/top-level/emacs-packages.nix @adisbladis
# Neovim
/pkgs/applications/editors/neovim @jonringer @teto
# VimPlugins
-/pkgs/misc/vim-plugins @jonringer @softinio
+/pkgs/applications/editors/vim/plugins @jonringer
# VsCode Extensions
-/pkgs/misc/vscode-extensions @jonringer
+/pkgs/applications/editors/vscode/extensions @jonringer
# Prometheus exporter modules and tests
/nixos/modules/services/monitoring/prometheus/exporters.nix @WilliButz
@@ -236,22 +226,22 @@
/nixos/tests/prometheus-exporters.nix @WilliButz
# PHP interpreter, packages, extensions, tests and documentation
-/doc/languages-frameworks/php.section.md @NixOS/php @aanderse @etu @globin @ma27 @talyz
-/nixos/tests/php @NixOS/php @aanderse @etu @globin @ma27 @talyz
-/pkgs/build-support/build-pecl.nix @NixOS/php @aanderse @etu @globin @ma27 @talyz
-/pkgs/development/interpreters/php @jtojnar @NixOS/php @aanderse @etu @globin @ma27 @talyz
-/pkgs/development/php-packages @NixOS/php @aanderse @etu @globin @ma27 @talyz
-/pkgs/top-level/php-packages.nix @jtojnar @NixOS/php @aanderse @etu @globin @ma27 @talyz
+/doc/languages-frameworks/php.section.md @aanderse @etu @globin @ma27 @talyz
+/nixos/tests/php @aanderse @etu @globin @ma27 @talyz
+/pkgs/build-support/build-pecl.nix @aanderse @etu @globin @ma27 @talyz
+/pkgs/development/interpreters/php @jtojnar @aanderse @etu @globin @ma27 @talyz
+/pkgs/development/php-packages @aanderse @etu @globin @ma27 @talyz
+/pkgs/top-level/php-packages.nix @jtojnar @aanderse @etu @globin @ma27 @talyz
# Podman, CRI-O modules and related
-/nixos/modules/virtualisation/containers.nix @NixOS/podman @zowoq @adisbladis
-/nixos/modules/virtualisation/cri-o.nix @NixOS/podman @zowoq @adisbladis
-/nixos/modules/virtualisation/podman @NixOS/podman @zowoq @adisbladis
-/nixos/tests/cri-o.nix @NixOS/podman @zowoq @adisbladis
-/nixos/tests/podman @NixOS/podman @zowoq @adisbladis
+/nixos/modules/virtualisation/containers.nix @zowoq @adisbladis
+/nixos/modules/virtualisation/cri-o.nix @zowoq @adisbladis
+/nixos/modules/virtualisation/podman @zowoq @adisbladis
+/nixos/tests/cri-o.nix @zowoq @adisbladis
+/nixos/tests/podman @zowoq @adisbladis
# Docker tools
-/pkgs/build-support/docker @roberth @utdemir
+/pkgs/build-support/docker @roberth
/nixos/tests/docker-tools-overlay.nix @roberth
/nixos/tests/docker-tools.nix @roberth
/doc/builders/images/dockertools.xml @roberth
@@ -266,8 +256,8 @@
/pkgs/development/go-packages @kalbasit @Mic92 @zowoq
# GNOME
-/pkgs/desktops/gnome @NixOS/GNOME @jtojnar @hedning
-/pkgs/desktops/gnome/extensions @piegamesde @NixOS/GNOME @jtojnar @hedning
+/pkgs/desktops/gnome @jtojnar @hedning
+/pkgs/desktops/gnome/extensions @piegamesde @jtojnar @hedning
# Cinnamon
/pkgs/desktops/cinnamon @mkg20001
@@ -288,10 +278,10 @@
# Matrix
/pkgs/servers/heisenbridge @piegamesde
-/pkgs/servers/matrix-conduit @piegamesde @pstn
+/pkgs/servers/matrix-conduit @piegamesde
/pkgs/servers/matrix-synapse/matrix-appservice-irc @piegamesde
/nixos/modules/services/misc/heisenbridge.nix @piegamesde
/nixos/modules/services/misc/matrix-appservice-irc.nix @piegamesde
-/nixos/modules/services/misc/matrix-conduit.nix @piegamesde @pstn
+/nixos/modules/services/misc/matrix-conduit.nix @piegamesde
/nixos/tests/matrix-appservice-irc.nix @piegamesde
-/nixos/tests/matrix-conduit.nix @piegamesde @pstn
+/nixos/tests/matrix-conduit.nix @piegamesde
diff --git a/.github/ISSUE_TEMPLATE/out_of_date_package_report.md b/.github/ISSUE_TEMPLATE/out_of_date_package_report.md
index 72c09a19c0e6..f1535526c2a7 100644
--- a/.github/ISSUE_TEMPLATE/out_of_date_package_report.md
+++ b/.github/ISSUE_TEMPLATE/out_of_date_package_report.md
@@ -13,10 +13,10 @@ assignees: ''
- [ ] Checked the [nixpkgs master branch](https://github.com/NixOS/nixpkgs)
current version:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 268b1594de71..397e5ff5d175 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,16 +1,10 @@
+###### Description of changes
+
-###### Motivation for this change
-
-
###### Things done
@@ -34,3 +28,14 @@ Reviewing guidelines: https://nixos.org/manual/nixpkgs/unstable/#chap-reviewing-
- [ ] (Module addition) Added a release notes entry if adding a new NixOS module
- [ ] (Release notes changes) Ran `nixos/doc/manual/md-to-db.sh` to update generated release notes
- [ ] Fits [CONTRIBUTING.md](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md).
+
+
diff --git a/.github/labeler.yml b/.github/labeler.yml
index e23cd9598ff9..a48f60e77638 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -5,10 +5,6 @@
- pkgs/development/libraries/agda/**/*
- pkgs/top-level/agda-packages.nix
-"6.topic: bsd":
- - pkgs/os-specific/bsd/**/*
- - pkgs/stdenv/freebsd/**/*
-
"6.topic: cinnamon":
- pkgs/desktops/cinnamon/**/*
@@ -16,7 +12,7 @@
- nixos/modules/services/editors/emacs.nix
- nixos/modules/services/editors/emacs.xml
- nixos/tests/emacs-daemon.nix
- - pkgs/applications/editors/emacs-modes/**/*
+ - pkgs/applications/editors/emacs/elisp-packages/**/*
- pkgs/applications/editors/emacs/**/*
- pkgs/build-support/emacs/**/*
- pkgs/top-level/emacs-packages.nix
@@ -142,7 +138,7 @@
"6.topic: vim":
- doc/languages-frameworks/vim.section.md
- pkgs/applications/editors/vim/**/*
- - pkgs/misc/vim-plugins/**/*
+ - pkgs/applications/editors/vim/plugins/**/*
- nixos/modules/programs/neovim.nix
- pkgs/applications/editors/neovim/**/*
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 0e3f315bb0de..4ee5adfaac1e 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -2,13 +2,19 @@ name: Backport
on:
pull_request_target:
types: [closed, labeled]
+
+# WARNING:
+# When extending this action, be aware that $GITHUB_TOKEN allows write access to
+# the GitHub repository. This means that it should not evaluate user input in a
+# way that allows code injection.
+
jobs:
backport:
name: Backport Pull Request
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@v2
+ - uses: actions/checkout@v3
with:
# required to find all branches
fetch-depth: 0
diff --git a/.github/workflows/basic-eval.yml b/.github/workflows/basic-eval.yml
index 67634af51f62..51429ae40bee 100644
--- a/.github/workflows/basic-eval.yml
+++ b/.github/workflows/basic-eval.yml
@@ -14,7 +14,12 @@ 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@v2
+ - uses: actions/checkout@v3
- uses: cachix/install-nix-action@v16
+ - uses: cachix/cachix-action@v10
+ with:
+ # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere.
+ name: nixpkgs-ci
+ signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
# explicit list of supportedSystems is needed until aarch64-darwin becomes part of the trunk jobset
- run: nix-build pkgs/top-level/release.nix -A tarball.nixpkgs-basic-release-checks --arg supportedSystems '[ "aarch64-darwin" "aarch64-linux" "x86_64-linux" "x86_64-darwin" ]'
diff --git a/.github/workflows/direct-push.yml b/.github/workflows/direct-push.yml
index 459475c3c6bc..082a4806e619 100644
--- a/.github/workflows/direct-push.yml
+++ b/.github/workflows/direct-push.yml
@@ -22,7 +22,7 @@ jobs:
if: steps.ismerge.outputs.ismerge != 'true'
- name: Warn if the commit was a direct push
if: steps.ismerge.outputs.ismerge != 'true'
- uses: peter-evans/commit-comment@v1
+ uses: peter-evans/commit-comment@v2
with:
body: |
@${{ github.actor }}, you pushed a commit directly to master/release branch
diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml
index 28e20d6c9458..de49e55ef2a7 100644
--- a/.github/workflows/editorconfig.yml
+++ b/.github/workflows/editorconfig.yml
@@ -24,7 +24,7 @@ jobs:
- name: print list of changed files
run: |
cat "$HOME/changed_files"
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge
diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml
index 4d1e2a2a0f95..5f949ddc56b1 100644
--- a/.github/workflows/labels.yml
+++ b/.github/workflows/labels.yml
@@ -4,6 +4,11 @@ on:
pull_request_target:
types: [edited, opened, synchronize, reopened]
+# WARNING:
+# When extending this action, be aware that $GITHUB_TOKEN allows some write
+# access to the GitHub API. This means that it should not evaluate user input in
+# a way that allows code injection.
+
permissions:
contents: read
pull-requests: write
@@ -13,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS'
steps:
- - uses: actions/labeler@v3
+ - uses: actions/labeler@v4
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
sync-labels: true
diff --git a/.github/workflows/manual-nixos.yml b/.github/workflows/manual-nixos.yml
index b9181c5f3bbc..61a8a217651d 100644
--- a/.github/workflows/manual-nixos.yml
+++ b/.github/workflows/manual-nixos.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS'
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge
@@ -24,7 +24,7 @@ jobs:
extra_nix_config: sandbox = true
- uses: cachix/cachix-action@v10
with:
- # This cache is for the nixos/nixpkgs manual builds and should not be trusted or used elsewhere.
+ # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere.
name: nixpkgs-ci
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
- name: Building NixOS manual
diff --git a/.github/workflows/manual-nixpkgs.yml b/.github/workflows/manual-nixpkgs.yml
index 3bdbd7f78fc4..70d9aab69828 100644
--- a/.github/workflows/manual-nixpkgs.yml
+++ b/.github/workflows/manual-nixpkgs.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS'
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge
@@ -24,7 +24,7 @@ jobs:
extra_nix_config: sandbox = true
- uses: cachix/cachix-action@v10
with:
- # This cache is for the nixos/nixpkgs manual builds and should not be trusted or used elsewhere.
+ # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere.
name: nixpkgs-ci
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
- name: Building Nixpkgs manual
diff --git a/.github/workflows/nixos-manual.yml b/.github/workflows/nixos-manual.yml
index e1c5b4dc93b9..bd70f228d462 100644
--- a/.github/workflows/nixos-manual.yml
+++ b/.github/workflows/nixos-manual.yml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS'
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
# pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge
diff --git a/.github/workflows/pending-set.yml b/.github/workflows/pending-set.yml
index 944d1deefb9f..b15e4847e67c 100644
--- a/.github/workflows/pending-set.yml
+++ b/.github/workflows/pending-set.yml
@@ -3,6 +3,11 @@ name: "set pending status"
on:
pull_request_target:
+# WARNING:
+# When extending this action, be aware that $GITHUB_TOKEN allows write access to
+# the GitHub repository. This means that it should not evaluate user input in a
+# way that allows code injection.
+
jobs:
action:
runs-on: ubuntu-latest
diff --git a/.github/workflows/periodic-merge-24h.yml b/.github/workflows/periodic-merge-24h.yml
index b8535fdf9527..027c63aad9a2 100644
--- a/.github/workflows/periodic-merge-24h.yml
+++ b/.github/workflows/periodic-merge-24h.yml
@@ -38,7 +38,7 @@ jobs:
into: staging-21.11
name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
uses: devmasx/merge-branch@1.4.0
@@ -49,7 +49,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Comment on failure
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@v2
if: ${{ failure() }}
with:
issue-number: 105153
diff --git a/.github/workflows/periodic-merge-6h.yml b/.github/workflows/periodic-merge-6h.yml
index daa9b6d3c844..5588d216ea03 100644
--- a/.github/workflows/periodic-merge-6h.yml
+++ b/.github/workflows/periodic-merge-6h.yml
@@ -32,7 +32,7 @@ jobs:
into: staging
name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
uses: devmasx/merge-branch@1.4.0
@@ -43,7 +43,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Comment on failure
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@v2
if: ${{ failure() }}
with:
issue-number: 105153
diff --git a/.github/workflows/update-terraform-providers.yml b/.github/workflows/update-terraform-providers.yml
index 33ebb6f14ac3..0c775cb6e402 100644
--- a/.github/workflows/update-terraform-providers.yml
+++ b/.github/workflows/update-terraform-providers.yml
@@ -10,7 +10,7 @@ jobs:
if: github.repository_owner == 'NixOS' && github.ref == 'refs/heads/master' # ensure workflow_dispatch only runs on master
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: cachix/install-nix-action@v16
- name: setup
id: setup
@@ -21,7 +21,7 @@ jobs:
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
pushd pkgs/applications/networking/cluster/terraform-providers
- ./update-all-providers
+ ./update-all-providers --no-build
git commit -m "${{ steps.setup.outputs.title }}" providers.json
popd
- name: create PR
@@ -39,7 +39,7 @@ jobs:
title: ${{ steps.setup.outputs.title }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: comment on failure
- uses: peter-evans/create-or-update-comment@v1
+ uses: peter-evans/create-or-update-comment@v2
if: ${{ failure() }}
with:
issue-number: 153416
diff --git a/README.md b/README.md
index e0970f85ff23..ff66ef0d85e8 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,15 @@
-
+
+
+
+
+
+
-
-
+
+
[Nixpkgs](https://github.com/nixos/nixpkgs) is a collection of over
diff --git a/doc/builders/fetchers.chapter.md b/doc/builders/fetchers.chapter.md
index 28388ba685d8..d9f22b062827 100644
--- a/doc/builders/fetchers.chapter.md
+++ b/doc/builders/fetchers.chapter.md
@@ -72,6 +72,10 @@ Used with Mercurial. Expects `url`, `rev`, and `sha256`.
A number of fetcher functions wrap part of `fetchurl` and `fetchzip`. They are mainly convenience functions intended for commonly used destinations of source code in Nixpkgs. These wrapper fetchers are listed below.
+## `fetchFromGitea` {#fetchfromgitea}
+
+`fetchFromGitea` expects five arguments. `domain` is the gitea server name. `owner` is a string corresponding to the Gitea user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every Gitea HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `sha256` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `sha256` is currently preferred.
+
## `fetchFromGitHub` {#fetchfromgithub}
`fetchFromGitHub` expects four arguments. `owner` is a string corresponding to the GitHub user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every GitHub HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `sha256` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `sha256` is currently preferred.
diff --git a/doc/builders/packages/steam.section.md b/doc/builders/packages/steam.section.md
index 0cfc1a2c2458..3ce33c9b60ef 100644
--- a/doc/builders/packages/steam.section.md
+++ b/doc/builders/packages/steam.section.md
@@ -56,7 +56,7 @@ Use `programs.steam.enable = true;` if you want to add steam to systemPackages a
## steam-run {#sec-steam-run}
-The FHS-compatible chroot used for Steam can also be used to run other Linux games that expect a FHS environment. To use it, install the `steam-run-native` package and run the game with
+The FHS-compatible chroot used for Steam can also be used to run other Linux games that expect a FHS environment. To use it, install the `steam-run` package and run the game with
```
steam-run ./foo
diff --git a/doc/builders/special/fhs-environments.section.md b/doc/builders/special/fhs-environments.section.md
index 43dc99b7c18f..cacad261e28f 100644
--- a/doc/builders/special/fhs-environments.section.md
+++ b/doc/builders/special/fhs-environments.section.md
@@ -45,3 +45,5 @@ One can create a simple environment using a `shell.nix` like that:
```
Running `nix-shell` would then drop you into a shell with these libraries and binaries available. You can use this to run closed-source applications which expect FHS structure without hassles: simply change `runScript` to the application path, e.g. `./bin/start.sh` -- relative paths are supported.
+
+Additionally, the FHS builder links all relocated gsettings-schemas (the glib setup-hook moves them to `share/gsettings-schemas/${name}/glib-2.0/schemas`) to their standard FHS location. This means you don't need to wrap binaries with `wrapGAppsHook`.
diff --git a/doc/contributing/coding-conventions.chapter.md b/doc/contributing/coding-conventions.chapter.md
index 79d90c23a40f..dac6d828ac0b 100644
--- a/doc/contributing/coding-conventions.chapter.md
+++ b/doc/contributing/coding-conventions.chapter.md
@@ -224,7 +224,7 @@ There are a few naming guidelines:
- Dashes in the package name _should_ be preserved in new variable names, rather than converted to underscores or camel cased — e.g., `http-parser` instead of `http_parser` or `httpParser`. The hyphenated style is preferred in all three package names.
-- If there are multiple versions of a package, this _should_ be reflected in the variable names in `all-packages.nix`, e.g. `json-c-0-9` and `json-c-0-11`. If there is an obvious “default” version, make an attribute like `json-c = json-c-0-9;`. See also [](#sec-versioning)
+- If there are multiple versions of a package, this _should_ be reflected in the variable names in `all-packages.nix`, e.g. `json-c_0_9` and `json-c_0_11`. If there is an obvious “default” version, make an attribute like `json-c = json-c_0_9;`. See also [](#sec-versioning)
## File naming and organisation {#sec-organisation}
@@ -540,10 +540,11 @@ If you do need to do create this sort of patch file, one way to do so is with gi
If a patch is available online but does not cleanly apply, it can be modified in some fixed ways by using additional optional arguments for `fetchpatch`:
+- `relative`: Similar to using `git-diff`'s `--relative` flag, only keep changes inside the specified directory, making paths relative to it.
- `stripLen`: Remove the first `stripLen` components of pathnames in the patch.
- `extraPrefix`: Prefix pathnames by this string.
-- `excludes`: Exclude files matching this pattern.
-- `includes`: Include only files matching this pattern.
+- `excludes`: Exclude files matching these patterns (applies after the above arguments).
+- `includes`: Include only files matching these patterns (applies after the above arguments).
- `revert`: Revert the patch.
Note that because the checksum is computed after applying these effects, using or modifying these arguments will have no effect unless the `sha256` argument is changed as well.
diff --git a/doc/contributing/reviewing-contributions.chapter.md b/doc/contributing/reviewing-contributions.chapter.md
index 3f3ba60947cc..3417854730ef 100644
--- a/doc/contributing/reviewing-contributions.chapter.md
+++ b/doc/contributing/reviewing-contributions.chapter.md
@@ -103,7 +103,8 @@ Sample template for a new package review is provided below.
- [ ] `meta.maintainers` is set
- [ ] build time only dependencies are declared in `nativeBuildInputs`
- [ ] source is fetched using the appropriate function
-- [ ] phases are respected
+- [ ] the list of `phases` is not overridden
+- [ ] when a phase (like `installPhase`) is overridden it starts with `runHook preInstall` and ends with `runHook postInstall`.
- [ ] patches that are remotely available are fetched with `fetchpatch`
##### Possible improvements
@@ -121,10 +122,10 @@ Reviewing process:
- [CODEOWNERS](https://help.github.com/articles/about-codeowners/) will make GitHub notify users based on the submitted changes, but it can happen that it misses some of the package maintainers.
- Ensure that the module tests, if any, are succeeding.
- Ensure that the introduced options are correct.
- - Type should be appropriate (string related types differs in their merging capabilities, `optionSet` and `string` types are deprecated).
+ - 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.
- Ensure that option changes are backward compatible.
- - `mkRenamedOptionModule` and `mkAliasOptionModule` functions provide way to make option changes backward compatible.
+ - `mkRenamedOptionModuleWith` provides a way to make option changes backward compatible.
- Ensure that removed options are declared with `mkRemovedOptionModule`
- Ensure that changes that are not backward compatible are mentioned in release notes.
- Ensure that documentations affected by the change is updated.
@@ -156,7 +157,7 @@ Reviewing process:
- Ensure that the module tests, if any, are succeeding.
- Ensure that the introduced options are correct.
- - Type should be appropriate (string related types differs in their merging capabilities, `optionSet` and `string` types are deprecated).
+ - 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.
- Ensure that module `meta` field is present
- Maintainers should be declared in `meta.maintainers`.
diff --git a/doc/contributing/submitting-changes.chapter.md b/doc/contributing/submitting-changes.chapter.md
index d5b5f5a60175..109d051c016f 100644
--- a/doc/contributing/submitting-changes.chapter.md
+++ b/doc/contributing/submitting-changes.chapter.md
@@ -98,7 +98,7 @@ We use jbidwatcher as an example for a discontinued project here.
1. Create a new branch for your change, e.g. `git checkout -b jbidwatcher`
1. Remove the actual package including its directory, e.g. `rm -rf pkgs/applications/misc/jbidwatcher`
1. Remove the package from the list of all packages (`pkgs/top-level/all-packages.nix`).
-1. Add an alias for the package name in `pkgs/top-level/aliases.nix` (There is also `pkgs/misc/vim-plugins/aliases.nix`. Package sets typically do not have aliases, so we can't add them there.)
+1. Add an alias for the package name in `pkgs/top-level/aliases.nix` (There is also `pkgs/applications/editors/vim/plugins/aliases.nix`. Package sets typically do not have aliases, so we can't add them there.)
For example in this case:
diff --git a/doc/functions/library/attrsets.xml b/doc/functions/library/attrsets.xml
index a30f4edf4c19..052bfa1f6ae3 100644
--- a/doc/functions/library/attrsets.xml
+++ b/doc/functions/library/attrsets.xml
@@ -1474,7 +1474,7 @@ lib.attrsets.zipAttrsWith
lib.attrsets.zipAttrs
- zipAttrsWith :: [ AttrSet ] -> AttrSet
+ zipAttrs :: [ AttrSet ] -> AttrSet
diff --git a/doc/languages-frameworks/coq.section.md b/doc/languages-frameworks/coq.section.md
index a5155aedaf52..9a692104a041 100644
--- a/doc/languages-frameworks/coq.section.md
+++ b/doc/languages-frameworks/coq.section.md
@@ -29,7 +29,8 @@ The recommended way of defining a derivation for a Coq library, is to use the `c
* `releaseRev` (optional, defaults to `(v: v)`), provides a default mapping from release names to revision hashes/branch names/tags,
* `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`,
-* `extraBuildInputs` (optional), by default `buildInputs` just contains `coq`, this allows to add more build inputs,
+* `extraNativeBuildInputs` (optional), by default `nativeBuildInputs` just contains `coq`, this allows to add more native build inputs, `nativeBuildInputs` are executables and `buildInputs` are libraries and dependencies,
+* `extraBuildInputs` (optional), this allows to add more build inputs,
* `mlPlugin` (optional, defaults to `false`). Some extensions (plugins) might require OCaml and sometimes other OCaml packages. Standard dependencies can be added by setting the current option to `true`. For a finer grain control, the `coq.ocamlPackages` attribute can be used in `extraBuildInputs` to depend on the same package set Coq was built against.
* `useDune2ifVersion` (optional, default to `(x: false)` uses Dune2 to build the package if the provided predicate evaluates to true on the version, e.g. `useDune2if = versions.isGe "1.1"` will use dune if the version of the package is greater or equal to `"1.1"`,
* `useDune2` (optional, defaults to `false`) uses Dune2 to build the package if set to true, the presence of this attribute overrides the behavior of the previous one.
diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md
index bf5742d6855e..817317804923 100644
--- a/doc/languages-frameworks/javascript.section.md
+++ b/doc/languages-frameworks/javascript.section.md
@@ -85,7 +85,7 @@ you will still need to commit the modified version of the lock files, but at lea
each tool has an abstraction to just build the node_modules (dependencies) directory. you can always use the stdenv.mkDerivation with the node_modules to build the package (symlink the node_modules directory and then use the package build command). the node_modules abstraction can be also used to build some web framework frontends. For an example of this see how [plausible](https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/web-apps/plausible/default.nix) is built. mkYarnModules to make the derivation containing node_modules. Then when building the frontend you can just symlink the node_modules directory
-## javascript packages inside nixpkgs {#javascript-packages-nixpkgs}
+## Javascript packages inside nixpkgs {#javascript-packages-nixpkgs}
The `pkgs/development/node-packages` folder contains a generated collection of
[NPM packages](https://npmjs.com/) that can be installed with the Nix package
@@ -121,12 +121,14 @@ requires `node-gyp-build`, so [we override](https://github.com/NixOS/nixpkgs/blo
};
```
+### Adding and Updating Javascript packages in nixpkgs
+
To add a package from NPM to nixpkgs:
1. Modify `pkgs/development/node-packages/node-packages.json` to add, update
or remove package entries to have it included in `nodePackages` and
`nodePackages_latest`.
-2. Run the script: `cd pkgs/development/node-packages && ./generate.sh`.
+2. Run the script: `./pkgs/development/node-packages/generate.sh`.
3. Build your new package to test your changes:
`cd /path/to/nixpkgs && nix-build -A nodePackages.`.
To build against the latest stable Current Node.js version (e.g. 14.x):
@@ -137,6 +139,26 @@ For more information about the generation process, consult the
[README.md](https://github.com/svanderburg/node2nix) file of the `node2nix`
tool.
+To update NPM packages in nixpkgs, run the same `generate.sh` script:
+
+```sh
+./pkgs/development/node-packages/generate.sh
+```
+
+#### Git protocol error
+
+Some packages may have Git dependencies from GitHub specified with `git://`.
+GitHub has
+[disabled unecrypted Git connections](https://github.blog/2021-09-01-improving-git-protocol-security-github/#no-more-unauthenticated-git),
+so you may see the following error when running the generate script:
+`The unauthenticated git protocol on port 9418 is no longer supported`.
+
+Use the following Git configuration to resolve the issue:
+
+```sh
+git config --global url."https://github.com/".insteadOf git://github.com/
+```
+
## Tool specific instructions {#javascript-tool-specific}
### node2nix {#javascript-node2nix}
diff --git a/doc/languages-frameworks/ocaml.section.md b/doc/languages-frameworks/ocaml.section.md
index d266a032268c..c6e40eaa20d0 100644
--- a/doc/languages-frameworks/ocaml.section.md
+++ b/doc/languages-frameworks/ocaml.section.md
@@ -32,14 +32,18 @@ Given that most of the OCaml ecosystem is now built with dune, nixpkgs includes
Here is a simple package example.
-- It defines an (optional) attribute `minimalOCamlVersion` that will be used to
- throw a descriptive evaluation error if building with an older OCaml is
- attempted.
+- It defines an (optional) attribute `minimalOCamlVersion` (see note below)
+ that will be used to throw a descriptive evaluation error if building with
+ an older OCaml is attempted.
- It uses the `fetchFromGitHub` fetcher to get its source.
-- `useDune2 = true` ensures that the latest version of Dune is used for the
- build (this may become the default value in a future release).
+- `duneVersion = "2"` ensures that Dune version 2 is used for the
+ build (this is the default; valid values are `"1"`, `"2"`, and `"3"`);
+ note that there is also a legacy `useDune2` boolean attribute:
+ set to `false` it corresponds to `duneVersion = "1"`; set to `true` it
+ corresponds to `duneVersion = "2"`. If both arguments (`duneVersion` and
+ `useDune2`) are given, the second one (`useDune2`) is silently ignored.
- It sets the optional `doCheck` attribute such that tests will be run with
`dune runtest -p angstrom` after the build (`dune build -p angstrom`) is
@@ -67,7 +71,7 @@ Here is a simple package example.
buildDunePackage rec {
pname = "angstrom";
version = "0.15.0";
- useDune2 = true;
+ duneVersion = "2";
minimalOCamlVersion = "4.04";
@@ -117,3 +121,11 @@ buildDunePackage rec {
};
}
```
+
+Note about `minimalOCamlVersion`. A deprecated version of this argument was
+spelled `minimumOCamlVersion`; setting the old attribute wrongly modifies the
+derivation hash and is therefore inappropriate. As a technical dept, currently
+packaged libraries may still use the old spelling: maintainers are invited to
+fix this when updating packages. Massive renaming is strongly discouraged as it
+would be challenging to review, difficult to test, and will cause unnecessary
+rebuild.
diff --git a/doc/languages-frameworks/python.section.md b/doc/languages-frameworks/python.section.md
index 9f9ace513c30..693ea016e0a5 100644
--- a/doc/languages-frameworks/python.section.md
+++ b/doc/languages-frameworks/python.section.md
@@ -979,6 +979,31 @@ with import {};
in python.withPackages(ps: [ps.blaze])).env
```
+#### Optional extra dependencies
+
+Some packages define optional dependencies for additional features. With
+`setuptools` this is called `extras_require` and `flit` calls it `extras-require`. A
+method for supporting this is by declaring the extras of a package in its
+`passthru`, e.g. in case of the package `dask`
+
+```nix
+passthru.extras-require = {
+ complete = [ distributed ];
+};
+```
+
+and letting the package requiring the extra add the list to its dependencies
+
+```nix
+propagatedBuildInputs = [
+ ...
+] ++ dask.extras-require.complete;
+```
+
+Note this method is preferred over adding parameters to builders, as that can
+result in packages depending on different variants and thereby causing
+collisions.
+
#### `buildPythonApplication` function {#buildpythonapplication-function}
The `buildPythonApplication` function is practically the same as
diff --git a/doc/languages-frameworks/rust.section.md b/doc/languages-frameworks/rust.section.md
index 56faf636df10..e19783e29e6a 100644
--- a/doc/languages-frameworks/rust.section.md
+++ b/doc/languages-frameworks/rust.section.md
@@ -464,6 +464,8 @@ you of the correct hash.
be disabled by setting `dontUseCargoParallelTests`.
* `cargoInstallHook`: install binaries and static/shared libraries
that were built using `cargoBuildHook`.
+* `bindgenHook`: for crates which use `bindgen` as a build dependency, lets
+ `bindgen` find `libclang` and `libclang` find the libraries in `buildInputs`.
### Examples {#examples}
diff --git a/doc/languages-frameworks/texlive.section.md b/doc/languages-frameworks/texlive.section.md
index 6b505cefcc95..060f5c647c29 100644
--- a/doc/languages-frameworks/texlive.section.md
+++ b/doc/languages-frameworks/texlive.section.md
@@ -6,7 +6,7 @@ Since release 15.09 there is a new TeX Live packaging that lives entirely under
- For basic usage just pull `texlive.combined.scheme-basic` for an environment with basic LaTeX support.
-- It typically won't work to use separately installed packages together. Instead, you can build a custom set of packages like this:
+- It typically won't work to use separately installed packages together. Instead, you can build a custom set of packages like this. Most CTAN packages should be available:
```nix
texlive.combine {
diff --git a/doc/languages-frameworks/vim.section.md b/doc/languages-frameworks/vim.section.md
index 4ffd6736e238..563fdf45a861 100644
--- a/doc/languages-frameworks/vim.section.md
+++ b/doc/languages-frameworks/vim.section.md
@@ -18,7 +18,7 @@ Adding custom .vimrc lines can be done using the following code:
```nix
vim_configurable.customize {
- # `name` specifies the name of the executable and package
+ # `name` optionally specifies the name of the executable and package
name = "vim-with-plugins";
vimrcConfig.customRC = ''
@@ -28,6 +28,9 @@ vim_configurable.customize {
```
This configuration is used when Vim is invoked with the command specified as name, in this case `vim-with-plugins`.
+You can also omit `name` to customize Vim itself. See the
+[definition of `vimUtils.makeCustomizable`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/vim-utils.nix#L408)
+for all supported options.
For Neovim the `configure` argument can be overridden to achieve the same:
@@ -286,7 +289,7 @@ Sample output1:
"reload" = buildVimPluginFrom2Nix { # created by nix#NixDerivation
name = "reload";
src = fetchgit {
- url = "git://github.com/xolox/vim-reload";
+ url = "https://github.com/xolox/vim-reload";
rev = "0a601a668727f5b675cb1ddc19f6861f3f7ab9e1";
sha256 = "0vb832l9yxj919f5hfg6qj6bn9ni57gnjd3bj7zpq7d4iv2s4wdh";
};
@@ -309,9 +312,9 @@ Sample output2:
## Adding new plugins to nixpkgs {#adding-new-plugins-to-nixpkgs}
-Nix expressions for Vim plugins are stored in [pkgs/misc/vim-plugins](https://github.com/NixOS/nixpkgs/tree/master/pkgs/misc/vim-plugins). For the vast majority of plugins, Nix expressions are automatically generated by running [`./update.py`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/update.py). This creates a [generated.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/generated.nix) file based on the plugins listed in [vim-plugin-names](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/vim-plugin-names). Plugins are listed in alphabetical order in `vim-plugin-names` using the format `[github username]/[repository]@[gitref]`. For example https://github.com/scrooloose/nerdtree becomes `scrooloose/nerdtree`.
+Nix expressions for Vim plugins are stored in [pkgs/applications/editors/vim/plugins](https://github.com/NixOS/nixpkgs/tree/master/pkgs/applications/editors/vim/plugins). For the vast majority of plugins, Nix expressions are automatically generated by running [`./update.py`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/update.py). This creates a [generated.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/generated.nix) file based on the plugins listed in [vim-plugin-names](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/vim-plugin-names). Plugins are listed in alphabetical order in `vim-plugin-names` using the format `[github username]/[repository]@[gitref]`. For example https://github.com/scrooloose/nerdtree becomes `scrooloose/nerdtree`.
-Some plugins require overrides in order to function properly. Overrides are placed in [overrides.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/overrides.nix). Overrides are most often required when a plugin requires some dependencies, or extra steps are required during the build process. For example `deoplete-fish` requires both `deoplete-nvim` and `vim-fish`, and so the following override was added:
+Some plugins require overrides in order to function properly. Overrides are placed in [overrides.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/overrides.nix). Overrides are most often required when a plugin requires some dependencies, or extra steps are required during the build process. For example `deoplete-fish` requires both `deoplete-nvim` and `vim-fish`, and so the following override was added:
```nix
deoplete-fish = super.deoplete-fish.overrideAttrs(old: {
@@ -330,13 +333,13 @@ Finally, there are some plugins that are also packaged in nodePackages because t
Run the update script with a GitHub API token that has at least `public_repo` access. Running the script without the token is likely to result in rate-limiting (429 errors). For steps on creating an API token, please refer to [GitHub's token documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token).
```sh
-GITHUB_API_TOKEN=my_token ./pkgs/misc/vim-plugins/update.py
+GITHUB_API_TOKEN=my_token ./pkgs/applications/editors/vim/plugins/update.py
```
Alternatively, set the number of processes to a lower count to avoid rate-limiting.
```sh
-./pkgs/misc/vim-plugins/update.py --proc 1
+./pkgs/applications/editors/vim/plugins/update.py --proc 1
```
## Important repositories {#important-repositories}
diff --git a/doc/stdenv/meta.chapter.md b/doc/stdenv/meta.chapter.md
index ac518cee524c..d3e1dd5b27d8 100644
--- a/doc/stdenv/meta.chapter.md
+++ b/doc/stdenv/meta.chapter.md
@@ -192,10 +192,6 @@ meta.hydraPlatforms = [];
If set to `true`, the package is marked as "broken", meaning that it won’t show up in `nix-env -qa`, and cannot be built or installed. Such packages should be removed from Nixpkgs eventually unless they are fixed.
-### `updateWalker` {#var-meta-updateWalker}
-
-If set to `true`, the package is tested to be updated correctly by the `update-walker.sh` script without additional settings. Such packages have `meta.version` set and their homepage (or the page specified by `meta.downloadPage`) contains a direct link to the package tarball.
-
## Licenses {#sec-meta-license}
The `meta.license` attribute should preferably contain a value from `lib.licenses` defined in [`nixpkgs/lib/licenses.nix`](https://github.com/NixOS/nixpkgs/blob/master/lib/licenses.nix), or in-place license description of the same format if the license is unlikely to be useful in another expression.
diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md
index 6d72bd0deb4f..1d4ca99e3cbe 100644
--- a/doc/stdenv/stdenv.chapter.md
+++ b/doc/stdenv/stdenv.chapter.md
@@ -319,10 +319,16 @@ For information about how to run the updates, execute `nix-shell maintainers/scr
## Phases {#sec-stdenv-phases}
-The generic builder has a number of *phases*. Package builds are split into phases to make it easier to override specific parts of the build (e.g., unpacking the sources or installing the binaries). Furthermore, it allows a nicer presentation of build logs in the Nix build farm.
+`stdenv.mkDerivation` sets the Nix [derivation](https://nixos.org/manual/nix/stable/expressions/derivations.html#derivations)'s builder to a script that loads the stdenv `setup.sh` bash library and calls `genericBuild`. Most packaging functions rely on this default builder.
+
+This generic command invokes a number of *phases*. Package builds are split into phases to make it easier to override specific parts of the build (e.g., unpacking the sources or installing the binaries).
Each phase can be overridden in its entirety either by setting the environment variable `namePhase` to a string containing some shell commands to be executed, or by redefining the shell function `namePhase`. The former is convenient to override a phase from the derivation, while the latter is convenient from a build script. However, typically one only wants to *add* some commands to a phase, e.g. by defining `postInstall` or `preFixup`, as skipping some of the default actions may have unexpected consequences. The default script for each phase is defined in the file `pkgs/stdenv/generic/setup.sh`.
+When overriding a phase, for example `installPhase`, it is important to start with `runHook preInstall` and end it with `runHook postInstall`, otherwise `preInstall` and `postInstall` will not be run. Even if you don't use them directly, it is good practice to do so anyways for downstream users who would want to add a `postInstall` by overriding your derivation.
+
+While inside an interactive `nix-shell`, if you wanted to run all phases in the order they would be run in an actual build, you can invoke `genericBuild` yourself.
+
### Controlling phases {#ssec-controlling-phases}
There are a number of variables that control what phases are executed and in what order:
@@ -333,7 +339,8 @@ 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`.
-Usually, if you just want to add a few phases, it’s more convenient to set one of the variables below (such as `preInstallPhases`), as you then don’t specify all the normal phases.
+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`).
##### `prePhases` {#var-stdenv-prePhases}
@@ -790,7 +797,7 @@ Hook executed at the start of the distribution phase.
Hook executed at the end of the distribution phase.
-## Shell functions {#ssec-stdenv-functions}
+## Shell functions and utilities {#ssec-stdenv-functions}
The standard environment provides a number of useful functions.
@@ -814,6 +821,19 @@ There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/bui
Using the `makeBinaryWrapper` implementation is usually preferred, as it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less ` - by scrolling past the binary data you should be able to see the shell command that generated the executable and there see the environment variables that were injected into the wrapper.
+### `remove-references-to -t` \ [ `-t` \ ... ] \ ... {#fun-remove-references-to}
+
+Removes the references of the specified files to the specified store files. This is done without changing the size of the file by replacing the hash by `eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`, and should work on compiled executables. This is meant to be used to remove the dependency of the output on inputs that are known to be unnecessary at runtime. Of course, reckless usage will break the patched programs.
+To use this, add `removeReferencesTo` to `nativeBuildInputs`.
+
+As `remove-references-to` is an actual executable and not a shell function, it can be used with `find`.
+Example removing all references to the compiler in the output:
+```nix
+postInstall = ''
+ find "$out" -type f -exec remove-references-to -t ${stdenv.cc} '{}' +
+'';
+```
+
### `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/doc/using/overlays.chapter.md b/doc/using/overlays.chapter.md
index df152bc14e7b..a51aa9ee8fc5 100644
--- a/doc/using/overlays.chapter.md
+++ b/doc/using/overlays.chapter.md
@@ -77,7 +77,7 @@ In Nixpkgs, we have multiple implementations of the BLAS/LAPACK numerical linear
The Nixpkgs attribute is `openblas` for ILP64 (integer width = 64 bits) and `openblasCompat` for LP64 (integer width = 32 bits). `openblasCompat` is the default.
-- [LAPACK reference](http://www.netlib.org/lapack/) (also provides BLAS)
+- [LAPACK reference](http://www.netlib.org/lapack/) (also provides BLAS and CBLAS)
The Nixpkgs attribute is `lapack-reference`.
@@ -117,7 +117,23 @@ $ LD_LIBRARY_PATH=$(nix-build -A mkl)/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH n
Intel MKL requires an `openmp` implementation when running with multiple processors. By default, `mkl` will use Intel's `iomp` implementation if no other is specified, but this is a runtime-only dependency and binary compatible with the LLVM implementation. To use that one instead, Intel recommends users set it with `LD_PRELOAD`. Note that `mkl` is only available on `x86_64-linux` and `x86_64-darwin`. Moreover, Hydra is not building and distributing pre-compiled binaries using it.
-For BLAS/LAPACK switching to work correctly, all packages must depend on `blas` or `lapack`. This ensures that only one BLAS/LAPACK library is used at one time. There are two versions of BLAS/LAPACK currently in the wild, `LP64` (integer size = 32 bits) and `ILP64` (integer size = 64 bits). Some software needs special flags or patches to work with `ILP64`. You can check if `ILP64` is used in Nixpkgs with `blas.isILP64` and `lapack.isILP64`. Some software does NOT work with `ILP64`, and derivations need to specify an assertion to prevent this. You can prevent `ILP64` from being used with the following:
+To override `blas` and `lapack` with its reference implementations (i.e. for development purposes), one can use the following overlay:
+
+```nix
+self: super:
+
+{
+ blas = super.blas.override {
+ blasProvider = self.lapack-reference;
+ };
+
+ lapack = super.lapack.override {
+ lapackProvider = self.lapack-reference;
+ };
+}
+```
+
+For BLAS/LAPACK switching to work correctly, all packages must depend on `blas` or `lapack`. This ensures that only one BLAS/LAPACK library is used at one time. There are two versions of BLAS/LAPACK currently in the wild, `LP64` (integer size = 32 bits) and `ILP64` (integer size = 64 bits). The attributes `blas` and `lapack` are `LP64` by default. Their `ILP64` version are provided through the attributes `blas-ilp64` and `lapack-ilp64`. Some software needs special flags or patches to work with `ILP64`. You can check if `ILP64` is used in Nixpkgs with `blas.isILP64` and `lapack.isILP64`. Some software does NOT work with `ILP64`, and derivations need to specify an assertion to prevent this. You can prevent `ILP64` from being used with the following:
```nix
{ stdenv, blas, lapack, ... }:
diff --git a/flake.nix b/flake.nix
index 39553cde0ab5..c48d6c68e583 100644
--- a/flake.nix
+++ b/flake.nix
@@ -21,39 +21,13 @@
nixos = import ./nixos/lib { lib = final; };
- nixosSystem = { modules, ... } @ args:
+ nixosSystem = args:
import ./nixos/lib/eval-config.nix (args // {
- modules =
- let
- moduleDeclarationFile =
- let
- # Even though `modules` is a mandatory argument for `nixosSystem`, it doesn't
- # mean that the evaluator always keeps track of its position. If there
- # are too many levels of indirection, the position gets lost at some point.
- intermediatePos = builtins.unsafeGetAttrPos "modules" args;
- in
- if intermediatePos == null then null else intermediatePos.file;
-
- # Add the invoking file as error message location for modules
- # that don't have their own locations; presumably inline modules.
- addModuleDeclarationFile =
- m: if moduleDeclarationFile == null then m else {
- _file = moduleDeclarationFile;
- imports = [ m ];
- };
-
- in
- map addModuleDeclarationFile modules ++ [
- {
- system.nixos.versionSuffix =
- ".${final.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}.${self.shortRev or "dirty"}";
- system.nixos.revision = final.mkIf (self ? rev) self.rev;
-
- # NOTE: This assumes that `nixpkgs.config` is _not_ used when
- # nixpkgs.pkgs is set OR _module.args.pkgs is set.
- nixpkgs.config.path = self.outPath;
- }
- ];
+ modules = args.modules ++ [ {
+ system.nixos.versionSuffix =
+ ".${final.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")}.${self.shortRev or "dirty"}";
+ system.nixos.revision = final.mkIf (self ? rev) self.rev;
+ } ];
});
});
@@ -66,7 +40,7 @@
}).nixos.manual.x86_64-linux;
};
- legacyPackages = forAllSystems (system: import ./. { inherit system; config.path = self.outPath; });
+ legacyPackages = forAllSystems (system: import ./. { inherit system; });
nixosModules = {
notDetected = import ./nixos/modules/installer/scan/not-detected.nix;
diff --git a/lib/attrsets.nix b/lib/attrsets.nix
index dafdd98f498e..516fdd8d33fd 100644
--- a/lib/attrsets.nix
+++ b/lib/attrsets.nix
@@ -4,8 +4,8 @@
let
inherit (builtins) head tail length;
inherit (lib.trivial) id;
- inherit (lib.strings) concatStringsSep sanitizeDerivationName;
- inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all;
+ inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
+ inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all partition groupBy take foldl;
in
rec {
@@ -78,6 +78,103 @@ rec {
in attrByPath attrPath (abort errorMsg);
+ /* Update or set specific paths of an attribute set.
+
+ Takes a list of updates to apply and an attribute set to apply them to,
+ and returns the attribute set with the updates applied. Updates are
+ represented as { path = ...; update = ...; } values, where `path` is a
+ list of strings representing the attribute path that should be updated,
+ and `update` is a function that takes the old value at that attribute path
+ as an argument and returns the new
+ value it should be.
+
+ Properties:
+ - Updates to deeper attribute paths are applied before updates to more
+ shallow attribute paths
+ - Multiple updates to the same attribute path are applied in the order
+ they appear in the update list
+ - If any but the last `path` element leads into a value that is not an
+ attribute set, an error is thrown
+ - If there is an update for an attribute path that doesn't exist,
+ accessing the argument in the update function causes an error, but
+ intermediate attribute sets are implicitly created as needed
+
+ Example:
+ updateManyAttrsByPath [
+ {
+ path = [ "a" "b" ];
+ update = old: { d = old.c; };
+ }
+ {
+ path = [ "a" "b" "c" ];
+ update = old: old + 1;
+ }
+ {
+ path = [ "x" "y" ];
+ update = old: "xy";
+ }
+ ] { a.b.c = 0; }
+ => { a = { b = { d = 1; }; }; x = { y = "xy"; }; }
+ */
+ updateManyAttrsByPath = let
+ # When recursing into attributes, instead of updating the `path` of each
+ # update using `tail`, which needs to allocate an entirely new list,
+ # we just pass a prefix length to use and make sure to only look at the
+ # path without the prefix length, so that we can reuse the original list
+ # entries.
+ go = prefixLength: hasValue: value: updates:
+ let
+ # Splits updates into ones on this level (split.right)
+ # And ones on levels further down (split.wrong)
+ split = partition (el: length el.path == prefixLength) updates;
+
+ # Groups updates on further down levels into the attributes they modify
+ nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
+
+ # Applies only nested modification to the input value
+ withNestedMods =
+ # Return the value directly if we don't have any nested modifications
+ if split.wrong == [] then
+ if hasValue then value
+ else
+ # Throw an error if there is no value. This `head` call here is
+ # safe, but only in this branch since `go` could only be called
+ # with `hasValue == false` for nested updates, in which case
+ # it's also always called with at least one update
+ let updatePath = (head split.right).path; in
+ throw
+ ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
+ + "not exist in the given value, but the first update to this "
+ + "path tries to access the existing value.")
+ else
+ # If there are nested modifications, try to apply them to the value
+ if ! hasValue then
+ # But if we don't have a value, just use an empty attribute set
+ # as the value, but simplify the code a bit
+ mapAttrs (name: go (prefixLength + 1) false null) nested
+ else if isAttrs value then
+ # If we do have a value and it's an attribute set, override it
+ # with the nested modifications
+ value //
+ mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
+ else
+ # However if it's not an attribute set, we can't apply the nested
+ # modifications, throw an error
+ let updatePath = (head split.wrong).path; in
+ throw
+ ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
+ + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
+ + "of the given value is not an attribute set, so we can't "
+ + "update an attribute inside of it.");
+
+ # We get the final result by applying all the updates on this level
+ # after having applied all the nested updates
+ # We use foldl instead of foldl' so that in case of multiple updates,
+ # intermediate values aren't evaluated if not needed
+ in foldl (acc: el: el.update acc) withNestedMods split.right;
+
+ in updates: value: go 0 true value updates;
+
/* Return the specified attributes from a set.
Example:
@@ -276,7 +373,7 @@ rec {
/* Like `mapAttrsRecursive', but it takes an additional predicate
- function that tells it whether to recursive into an attribute
+ function that tells it whether to recurse into an attribute
set. If it returns false, `mapAttrsRecursiveCond' does not
recurse, but does apply the map function. If it returns true, it
does recurse, and does not apply the map function.
@@ -327,7 +424,7 @@ rec {
isDerivation "foobar"
=> false
*/
- isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
+ isDerivation = x: x.type or null == "derivation";
/* Converts a store path to a fake derivation. */
toDerivation = path:
@@ -477,6 +574,20 @@ rec {
overrideExisting = old: new:
mapAttrs (name: value: new.${name} or value) old;
+ /* Turns a list of strings into a human-readable description of those
+ strings represented as an attribute path. The result of this function is
+ not intended to be machine-readable.
+
+ Example:
+ showAttrPath [ "foo" "10" "bar" ]
+ => "foo.\"10\".bar"
+ showAttrPath []
+ => ""
+ */
+ showAttrPath = path:
+ if path == [] then ""
+ else concatMapStringsSep "." escapeNixIdentifier path;
+
/* Get a package output.
If no output is found, fallback to `.out` and then to the default.
diff --git a/lib/default.nix b/lib/default.nix
index 268422538803..1f06283790a8 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -66,9 +66,10 @@ let
stringLength sub substring tail trace;
inherit (self.trivial) id const pipe concat or and bitAnd bitOr bitXor
bitNot boolToString mergeAttrs flip mapNullable inNixShell isFloat min max
- importJSON importTOML warn warnIf throwIfNot checkListOfEnum
- info showWarnings nixpkgsVersion version
- mod compare splitByAndCompare functionArgs setFunctionArgs isFunction
+ importJSON importTOML warn warnIf warnIfNot throwIf throwIfNot checkListOfEnum
+ info showWarnings nixpkgsVersion version isInOldestRelease
+ mod compare splitByAndCompare
+ functionArgs setFunctionArgs isFunction toFunction
toHexString toBaseDigits;
inherit (self.fixedPoints) fix fix' converge extends composeExtensions
composeManyExtensions makeExtensible makeExtensibleWithCustomName;
@@ -78,9 +79,10 @@ let
mapAttrs' mapAttrsToList mapAttrsRecursive mapAttrsRecursiveCond
genAttrs isDerivation toDerivation optionalAttrs
zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
- recursiveUpdate matchAttrs overrideExisting getOutput getBin
+ recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin
getLib getDev getMan chooseDevOutputs zipWithNames zip
- recurseIntoAttrs dontRecurseIntoAttrs cartesianProductOfSets;
+ recurseIntoAttrs dontRecurseIntoAttrs cartesianProductOfSets
+ updateManyAttrsByPath;
inherit (self.lists) singleton forEach foldr fold foldl foldl' imap0 imap1
concatMap flatten remove findSingle findFirst any all count
optional optionals toList range partition zipListsWith zipLists
@@ -111,22 +113,23 @@ let
cleanSource sourceByRegex sourceFilesBySuffices
commitIdFromGitRepo cleanSourceWith pathHasContext
canCleanSource pathIsRegularFile pathIsGitRepo;
- inherit (self.modules) evalModules unifyModuleSyntax
- applyIfFunction mergeModules
+ inherit (self.modules) evalModules setDefaultModuleLocation
+ unifyModuleSyntax applyModuleArgsIfFunction mergeModules
mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
pushDownProperties dischargeProperties filterOverrides
sortProperties fixupOptionType mkIf mkAssert mkMerge mkOverride
mkOptionDefault mkDefault mkImageMediaOverride mkForce mkVMOverride
mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions
mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule
- mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule
+ mkRenamedOptionModule mkRenamedOptionModuleWith
+ mkMergedOptionModule mkChangedOptionModule
mkAliasOptionModule mkDerivedConfig doRename;
inherit (self.options) isOption mkEnableOption mkSinkUndeclaredOptions
mergeDefaultOption mergeOneOption mergeEqualOption mergeUniqueOption
getValues getFiles
optionAttrSetToDocList optionAttrSetToDocList'
scrubOptionValue literalExpression literalExample literalDocBook
- showOption showFiles unknownModule mkOption;
+ showOption showFiles unknownModule mkOption mkPackageOption;
inherit (self.types) isType setType defaultTypeMerge defaultFunctor
isOptionType mkOptionType;
inherit (self.asserts)
diff --git a/lib/licenses.nix b/lib/licenses.nix
index 160b684330ef..2928d11d8b22 100644
--- a/lib/licenses.nix
+++ b/lib/licenses.nix
@@ -389,6 +389,11 @@ in mkLicense lset) ({
free = false;
};
+ generaluser = {
+ fullName = "GeneralUser GS License v2.0";
+ url = "http://www.schristiancollins.com/generaluser.php"; # license included in sources
+ };
+
gpl1Only = {
spdxId = "GPL-1.0-only";
fullName = "GNU General Public License v1.0 only";
@@ -465,6 +470,11 @@ in mkLicense lset) ({
spdxId = "imagemagick";
};
+ imlib2 = {
+ spdxId = "Imlib2";
+ fullName = "Imlib2 License";
+ };
+
inria-compcert = {
fullName = "INRIA Non-Commercial License Agreement for the CompCert verified compiler";
url = "https://compcert.org/doc/LICENSE.txt";
@@ -591,6 +601,21 @@ in mkLicense lset) ({
spdxId = "MIT";
fullName = "MIT License";
};
+ # https://spdx.org/licenses/MIT-feh.html
+ mit-feh = {
+ spdxId = "MIT-feh";
+ fullName = "feh License";
+ };
+
+ mitAdvertising = {
+ spdxId = "MIT-advertising";
+ fullName = "Enlightenment License (e16)";
+ };
+
+ mit0 = {
+ spdxId = "MIT-0";
+ fullName = "MIT No Attribution";
+ };
mpl10 = {
spdxId = "MPL-1.0";
diff --git a/lib/lists.nix b/lib/lists.nix
index 1dbff7668d75..a030280c8dcc 100644
--- a/lib/lists.nix
+++ b/lib/lists.nix
@@ -4,6 +4,7 @@
let
inherit (lib.strings) toInt;
inherit (lib.trivial) compare min;
+ inherit (lib.attrsets) mapAttrs;
in
rec {
@@ -340,15 +341,15 @@ rec {
groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
=> { true = 12; false = 3; }
*/
- groupBy' = op: nul: pred: lst:
- foldl' (r: e:
- let
- key = pred e;
- in
- r // { ${key} = op (r.${key} or nul) e; }
- ) {} lst;
+ groupBy' = op: nul: pred: lst: mapAttrs (name: foldl op nul) (groupBy pred lst);
- groupBy = groupBy' (sum: e: sum ++ [e]) [];
+ groupBy = builtins.groupBy or (
+ pred: foldl' (r: e:
+ let
+ key = pred e;
+ in
+ r // { ${key} = (r.${key} or []) ++ [e]; }
+ ) {});
/* Merges two lists of the same size together. If the sizes aren't the same
the merging stops at the shortest. How both lists are merged is defined
diff --git a/lib/modules.nix b/lib/modules.nix
index c68bbfcaa3e0..894104cc5790 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -9,7 +9,7 @@ let
catAttrs
concatLists
concatMap
- count
+ concatStringsSep
elem
filter
findFirst
@@ -47,6 +47,20 @@ let
showOption
unknownModule
;
+
+ showDeclPrefix = loc: decl: prefix:
+ " - option(s) with prefix `${showOption (loc ++ [prefix])}' in module `${decl._file}'";
+ showRawDecls = loc: decls:
+ concatStringsSep "\n"
+ (sort (a: b: a < b)
+ (concatMap
+ (decl: map
+ (showDeclPrefix loc decl)
+ (attrNames decl.options)
+ )
+ decls
+ ));
+
in
rec {
@@ -138,7 +152,7 @@ rec {
# support for that, in turn it's lazy in its values. This means e.g.
# a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't
# start a download when `pkgs` wasn't evaluated.
- type = types.lazyAttrsOf types.unspecified;
+ type = types.lazyAttrsOf types.raw;
internal = true;
description = "Arguments passed to each module.";
};
@@ -151,8 +165,7 @@ rec {
};
_module.freeformType = mkOption {
- # Disallow merging for now, but could be implemented nicely with a `types.optionType`
- type = types.nullOr (types.uniq types.attrs);
+ type = types.nullOr types.optionType;
internal = true;
default = null;
description = ''
@@ -269,11 +282,11 @@ rec {
# Like unifyModuleSyntax, but also imports paths and calls functions if necessary
loadModule = args: fallbackFile: fallbackKey: m:
if isFunction m || isAttrs m then
- unifyModuleSyntax fallbackFile fallbackKey (applyIfFunction fallbackKey m args)
+ unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgsIfFunction fallbackKey m args)
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}"
- else unifyModuleSyntax (toString m) (toString m) (applyIfFunction (toString m) (import m) args);
+ else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
/*
Collects all modules recursively into the form
@@ -334,6 +347,10 @@ rec {
in modulesPath: initialModules: args:
filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
+ /* Wrap a module with a default location for reporting errors. */
+ setDefaultModuleLocation = file: m:
+ { _file = file; imports = [ m ]; };
+
/* Massage a module into canonical form, that is, a set consisting
of ‘options’, ‘config’ and ‘imports’ attributes. */
unifyModuleSyntax = file: key: m:
@@ -366,7 +383,7 @@ rec {
config = addFreeformType (addMeta (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]));
};
- applyIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
+ applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
let
# Module arguments are resolved in a strict manner when attribute set
# deconstruction is used. As the arguments are now defined with the
@@ -471,26 +488,61 @@ rec {
[{ inherit (module) file; inherit value; }]
) configs;
+ # Convert an option tree decl to a submodule option decl
+ optionTreeToOption = decl:
+ if isOption decl.options
+ then decl
+ else decl // {
+ options = mkOption {
+ type = types.submoduleWith {
+ modules = [ { options = decl.options; } ];
+ # `null` is not intended for use by modules. It is an internal
+ # value that means "whatever the user has declared elsewhere".
+ # This might become obsolete with https://github.com/NixOS/nixpkgs/issues/162398
+ shorthandOnlyDefinesConfig = null;
+ };
+ };
+ };
+
resultsByName = mapAttrs (name: decls:
# We're descending into attribute ‘name’.
let
loc = prefix ++ [name];
defns = defnsByName.${name} or [];
defns' = defnsByName'.${name} or [];
- nrOptions = count (m: isOption m.options) decls;
+ optionDecls = filter (m: isOption m.options) decls;
in
- if nrOptions == length decls then
+ if length optionDecls == length decls then
let opt = fixupOptionType loc (mergeOptionDecls loc decls);
in {
matchedOptions = evalOptionValue loc opt defns';
unmatchedDefns = [];
}
- else if nrOptions != 0 then
- let
- firstOption = findFirst (m: isOption m.options) "" decls;
- firstNonOption = findFirst (m: !isOption m.options) "" decls;
- in
- throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'."
+ else if optionDecls != [] then
+ if all (x: x.options.type.name == "submodule") optionDecls
+ # Raw options can only be merged into submodules. Merging into
+ # attrsets might be nice, but ambiguous. Suppose we have
+ # attrset as a `attrsOf submodule`. User declares option
+ # attrset.foo.bar, this could mean:
+ # a. option `bar` is only available in `attrset.foo`
+ # b. option `foo.bar` is available in all `attrset.*`
+ # c. reject and require "" as a reminder that it behaves like (b).
+ # d. magically combine (a) and (c).
+ # All of the above are merely syntax sugar though.
+ then
+ let opt = fixupOptionType loc (mergeOptionDecls loc (map optionTreeToOption decls));
+ in {
+ matchedOptions = evalOptionValue loc opt defns';
+ unmatchedDefns = [];
+ }
+ else
+ let
+ firstNonOption = findFirst (m: !isOption m.options) "" decls;
+ nonOptions = filter (m: !isOption m.options) decls;
+ in
+ throw "The option `${showOption loc}' in module `${(lib.head optionDecls)._file}' would be a parent of the following options, but its type `${(lib.head optionDecls).options.type.description or ""}' does not support nested options.\n${
+ showRawDecls loc nonOptions
+ }"
else
mergeModules' loc decls defns) declsByName;
@@ -534,11 +586,9 @@ rec {
correspond to the definition of 'loc' in 'opt.file'. */
mergeOptionDecls =
let
- packSubmodule = file: m:
- { _file = file; imports = [ m ]; };
coerceOption = file: opt:
- if isFunction opt then packSubmodule file opt
- else packSubmodule file { options = opt; };
+ if isFunction opt then setDefaultModuleLocation file opt
+ else setDefaultModuleLocation file { options = opt; };
in loc: opts:
foldl' (res: opt:
let t = res.type;
@@ -559,17 +609,9 @@ rec {
throw "The option `${showOption loc}' in `${opt._file}' is already declared in ${showFiles res.declarations}."
else
let
- /* Add the modules of the current option to the list of modules
- already collected. The options attribute except either a list of
- submodules or a submodule. For each submodule, we add the file of the
- current option declaration as the file use for the submodule. If the
- submodule defines any filename, then we ignore the enclosing option file. */
- options' = toList opt.options.options;
-
getSubModules = opt.options.type.getSubModules or null;
submodules =
- if getSubModules != null then map (packSubmodule opt._file) getSubModules ++ res.options
- else if opt.options ? options then map (coerceOption opt._file) options' ++ res.options
+ if getSubModules != null then map (setDefaultModuleLocation opt._file) getSubModules ++ res.options
else res.options;
in opt.options // res //
{ declarations = res.declarations ++ [opt._file];
@@ -752,26 +794,13 @@ rec {
compare = a: b: (a.priority or 1000) < (b.priority or 1000);
in sort compare defs';
- /* Hack for backward compatibility: convert options of type
- optionSet to options of type submodule. FIXME: remove
- eventually. */
+ # This calls substSubModules, whose entire purpose is only to ensure that
+ # option declarations in submodules have accurate position information.
+ # TODO: Merge this into mergeOptionDecls
fixupOptionType = loc: opt:
- let
- options = opt.options or
- (throw "Option `${showOption loc}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}.");
- f = tp:
- let optionSetIn = type: (tp.name == type) && (tp.functor.wrapped.name == "optionSet");
- in
- if tp.name == "option set" || tp.name == "submodule" then
- throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}."
- else if optionSetIn "attrsOf" then types.attrsOf (types.submodule options)
- else if optionSetIn "listOf" then types.listOf (types.submodule options)
- else if optionSetIn "nullOr" then types.nullOr (types.submodule options)
- else tp;
- in
- if opt.type.getSubModules or null == null
- then opt // { type = f (opt.type or types.unspecified); }
- else opt // { type = opt.type.substSubModules opt.options; options = []; };
+ if opt.type.getSubModules or null == null
+ then opt // { type = opt.type or types.unspecified; }
+ else opt // { type = opt.type.substSubModules opt.options; options = []; };
/* Properties. */
@@ -903,6 +932,26 @@ rec {
use = builtins.trace "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
};
+ mkRenamedOptionModuleWith = {
+ /* Old option path as list of strings. */
+ from,
+ /* New option path as list of strings. */
+ to,
+
+ /*
+ Release number of the first release that contains the rename, ignoring backports.
+ Set it to the upcoming release, matching the nixpkgs/.version file.
+ */
+ sinceRelease,
+
+ }: doRename {
+ inherit from to;
+ visible = false;
+ warn = lib.isInOldestRelease sinceRelease;
+ use = lib.warnIf (lib.isInOldestRelease sinceRelease)
+ "Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
+ };
+
/* Return a module that causes a warning to be shown if any of the "from"
option is defined; the defined values can be used in the "mergeFn" to set
the "to" value.
diff --git a/lib/options.nix b/lib/options.nix
index 627aac24d2fb..8d0801775c46 100644
--- a/lib/options.nix
+++ b/lib/options.nix
@@ -79,8 +79,6 @@ rec {
visible ? null,
# Whether the option can be set only once
readOnly ? null,
- # Deprecated, used by types.optionSet.
- options ? null
} @ attrs:
attrs // { _type = "option"; };
@@ -231,7 +229,7 @@ rec {
then true
else opt.visible or true;
readOnly = opt.readOnly or false;
- type = opt.type.description or null;
+ type = opt.type.description or "unspecified";
}
// optionalAttrs (opt ? example) { example = scrubOptionValue opt.example; }
// optionalAttrs (opt ? default) { default = scrubOptionValue opt.default; }
diff --git a/lib/sources.nix b/lib/sources.nix
index ae2df7235213..343449d9a603 100644
--- a/lib/sources.nix
+++ b/lib/sources.nix
@@ -20,17 +20,26 @@ let
readFile
;
- # Returns the type of a path: regular (for file), symlink, or directory
- pathType = p: getAttr (baseNameOf p) (readDir (dirOf p));
+ /*
+ Returns the type of a path: regular (for file), symlink, or directory.
+ */
+ pathType = path: getAttr (baseNameOf path) (readDir (dirOf path));
- # Returns true if the path exists and is a directory, false otherwise
- pathIsDirectory = p: if pathExists p then (pathType p) == "directory" else false;
+ /*
+ Returns true if the path exists and is a directory, false otherwise.
+ */
+ pathIsDirectory = path: if pathExists path then (pathType path) == "directory" else false;
- # Returns true if the path exists and is a regular file, false otherwise
- pathIsRegularFile = p: if pathExists p then (pathType p) == "regular" else false;
+ /*
+ Returns true if the path exists and is a regular file, false otherwise.
+ */
+ pathIsRegularFile = path: if pathExists path then (pathType path) == "regular" else false;
- # Bring in a path as a source, filtering out all Subversion and CVS
- # directories, as well as backup files (*~).
+ /*
+ A basic filter for `cleanSourceWith` that removes
+ directories of version control system, backup files (*~)
+ and some generated files.
+ */
cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! (
# Filter out version control software files/directories
(baseName == ".git" || type == "directory" && (baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) ||
@@ -48,43 +57,48 @@ let
(type == "unknown")
);
- # Filters a source tree removing version control files and directories using cleanSourceWith
- #
- # Example:
- # cleanSource ./.
+ /*
+ Filters a source tree removing version control files and directories using cleanSourceFilter.
+
+ Example:
+ cleanSource ./.
+ */
cleanSource = src: cleanSourceWith { filter = cleanSourceFilter; inherit src; };
- # Like `builtins.filterSource`, except it will compose with itself,
- # allowing you to chain multiple calls together without any
- # intermediate copies being put in the nix store.
- #
- # lib.cleanSourceWith {
- # filter = f;
- # src = lib.cleanSourceWith {
- # filter = g;
- # src = ./.;
- # };
- # }
- # # Succeeds!
- #
- # builtins.filterSource f (builtins.filterSource g ./.)
- # # Fails!
- #
- # Parameters:
- #
- # src: A path or cleanSourceWith result to filter and/or rename.
- #
- # filter: A function (path -> type -> bool)
- # Optional with default value: constant true (include everything)
- # The function will be combined with the && operator such
- # that src.filter is called lazily.
- # For implementing a filter, see
- # https://nixos.org/nix/manual/#builtin-filterSource
- #
- # name: Optional name to use as part of the store path.
- # This defaults to `src.name` or otherwise `"source"`.
- #
- cleanSourceWith = { filter ? _path: _type: true, src, name ? null }:
+ /*
+ Like `builtins.filterSource`, except it will compose with itself,
+ allowing you to chain multiple calls together without any
+ intermediate copies being put in the nix store.
+
+ Example:
+ lib.cleanSourceWith {
+ filter = f;
+ src = lib.cleanSourceWith {
+ filter = g;
+ src = ./.;
+ };
+ }
+ # Succeeds!
+
+ builtins.filterSource f (builtins.filterSource g ./.)
+ # Fails!
+
+ */
+ cleanSourceWith =
+ {
+ # A path or cleanSourceWith result to filter and/or rename.
+ src,
+ # Optional with default value: constant true (include everything)
+ # The function will be combined with the && operator such
+ # that src.filter is called lazily.
+ # For implementing a filter, see
+ # https://nixos.org/nix/manual/#builtin-filterSource
+ # Type: A function (path -> type -> bool)
+ filter ? _path: _type: true,
+ # Optional name to use as part of the store path.
+ # This defaults to `src.name` or otherwise `"source"`.
+ name ? null
+ }:
let
orig = toSourceAttributes src;
in fromSourceAttributes {
@@ -116,9 +130,11 @@ let
satisfiesSubpathInvariant = src ? satisfiesSubpathInvariant && src.satisfiesSubpathInvariant;
};
- # Filter sources by a list of regular expressions.
- #
- # E.g. `src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]`
+ /*
+ Filter sources by a list of regular expressions.
+
+ Example: src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]
+ */
sourceByRegex = src: regexes:
let
isFiltered = src ? _isLibCleanSourceWith;
@@ -153,8 +169,11 @@ let
pathIsGitRepo = path: (tryEval (commitIdFromGitRepo path)).success;
- # Get the commit id of a git repo
- # Example: commitIdFromGitRepo
+ /*
+ Get the commit id of a git repo.
+
+ Example: commitIdFromGitRepo
+ */
commitIdFromGitRepo =
let readCommitFromFile = file: path:
let fileName = toString path + "/" + file;
diff --git a/lib/systems/default.nix b/lib/systems/default.nix
index 529eeb6514b9..7ddd5b8a5812 100644
--- a/lib/systems/default.nix
+++ b/lib/systems/default.nix
@@ -105,7 +105,8 @@ rec {
else if final.isAarch64 then "arm64"
else if final.isx86_32 then "i386"
else if final.isx86_64 then "x86_64"
- else if final.isMips then "mips"
+ else if final.isMips32 then "mips"
+ else if final.isMips64 then "mips" # linux kernel does not distinguish mips32/mips64
else if final.isPower then "powerpc"
else if final.isRiscV then "riscv"
else if final.isS390 then "s390"
diff --git a/lib/systems/doubles.nix b/lib/systems/doubles.nix
index 00e57339a310..27cdaf6a7233 100644
--- a/lib/systems/doubles.nix
+++ b/lib/systems/doubles.nix
@@ -26,7 +26,7 @@ let
# Linux
"aarch64-linux" "armv5tel-linux" "armv6l-linux" "armv7a-linux"
- "armv7l-linux" "i686-linux" "m68k-linux" "mipsel-linux"
+ "armv7l-linux" "i686-linux" "m68k-linux" "mipsel-linux" "mips64el-linux"
"powerpc64-linux" "powerpc64le-linux" "riscv32-linux"
"riscv64-linux" "s390-linux" "s390x-linux" "x86_64-linux"
@@ -87,7 +87,11 @@ in {
darwin = filterDoubles predicates.isDarwin;
freebsd = filterDoubles predicates.isFreeBSD;
# Should be better, but MinGW is unclear.
- gnu = filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnu; }) ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnueabi; }) ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnueabihf; });
+ gnu = filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnu; })
+ ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnueabi; })
+ ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnueabihf; })
+ ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnuabin32; })
+ ++ filterDoubles (matchAttrs { kernel = parse.kernels.linux; abi = parse.abis.gnuabi64; });
illumos = filterDoubles predicates.isSunOS;
linux = filterDoubles predicates.isLinux;
netbsd = filterDoubles predicates.isNetBSD;
diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix
index 9c0c91617e8a..997a7a8c273a 100644
--- a/lib/systems/examples.nix
+++ b/lib/systems/examples.nix
@@ -93,6 +93,26 @@ rec {
config = "mipsel-unknown-linux-gnu";
} // platforms.fuloong2f_n32;
+ # MIPS ABI table transcribed from here: https://wiki.debian.org/Multiarch/Tuples
+
+ # can execute on 32bit chip
+ mips-linux-gnu = { config = "mips-linux-gnu"; } // platforms.gcc_mips32r2_o32;
+ mipsel-linux-gnu = { config = "mipsel-linux-gnu"; } // platforms.gcc_mips32r2_o32;
+ mipsisa32r6-linux-gnu = { config = "mipsisa32r6-linux-gnu"; } // platforms.gcc_mips32r6_o32;
+ mipsisa32r6el-linux-gnu = { config = "mipsisa32r6el-linux-gnu"; } // platforms.gcc_mips32r6_o32;
+
+ # require 64bit chip (for more registers, 64-bit floating point, 64-bit "long long") but use 32bit pointers
+ mips64-linux-gnuabin32 = { config = "mips64-linux-gnuabin32"; } // platforms.gcc_mips64r2_n32;
+ mips64el-linux-gnuabin32 = { config = "mips64el-linux-gnuabin32"; } // platforms.gcc_mips64r2_n32;
+ mipsisa64r6-linux-gnuabin32 = { config = "mipsisa64r6-linux-gnuabin32"; } // platforms.gcc_mips64r6_n32;
+ mipsisa64r6el-linux-gnuabin32 = { config = "mipsisa64r6el-linux-gnuabin32"; } // platforms.gcc_mips64r6_n32;
+
+ # 64bit pointers
+ mips64-linux-gnuabi64 = { config = "mips64-linux-gnuabi64"; } // platforms.gcc_mips64r2_64;
+ mips64el-linux-gnuabi64 = { config = "mips64el-linux-gnuabi64"; } // platforms.gcc_mips64r2_64;
+ mipsisa64r6-linux-gnuabi64 = { config = "mipsisa64r6-linux-gnuabi64"; } // platforms.gcc_mips64r6_64;
+ mipsisa64r6el-linux-gnuabi64 = { config = "mipsisa64r6el-linux-gnuabi64"; } // platforms.gcc_mips64r6_64;
+
muslpi = raspberryPi // {
config = "armv6l-unknown-linux-musleabihf";
};
diff --git a/lib/systems/inspect.nix b/lib/systems/inspect.nix
index 718954e0839a..89cac575c67d 100644
--- a/lib/systems/inspect.nix
+++ b/lib/systems/inspect.nix
@@ -17,6 +17,10 @@ rec {
isAarch32 = { cpu = { family = "arm"; bits = 32; }; };
isAarch64 = { cpu = { family = "arm"; bits = 64; }; };
isMips = { cpu = { family = "mips"; }; };
+ isMips32 = { cpu = { family = "mips"; bits = 32; }; };
+ isMips64 = { cpu = { family = "mips"; bits = 64; }; };
+ isMips64n32 = { cpu = { family = "mips"; bits = 64; }; abi = { abi = "n32"; }; };
+ isMips64n64 = { cpu = { family = "mips"; bits = 64; }; abi = { abi = "64"; }; };
isMmix = { cpu = { family = "mmix"; }; };
isRiscV = { cpu = { family = "riscv"; }; };
isSparc = { cpu = { family = "sparc"; }; };
@@ -57,7 +61,7 @@ rec {
isAndroid = [ { abi = abis.android; } { abi = abis.androideabi; } ];
isGnu = with abis; map (a: { abi = a; }) [ gnuabi64 gnu gnueabi gnueabihf ];
- isMusl = with abis; map (a: { abi = a; }) [ musl musleabi musleabihf ];
+ isMusl = with abis; map (a: { abi = a; }) [ musl musleabi musleabihf muslabin32 muslabi64 ];
isUClibc = with abis; map (a: { abi = a; }) [ uclibc uclibceabi uclibceabihf ];
isEfi = map (family: { cpu.family = family; })
diff --git a/lib/systems/parse.nix b/lib/systems/parse.nix
index 8a88d8cfbe87..3ceddbb599b9 100644
--- a/lib/systems/parse.nix
+++ b/lib/systems/parse.nix
@@ -359,13 +359,20 @@ rec {
];
};
gnuabi64 = { abi = "64"; };
+ muslabi64 = { abi = "64"; };
+
+ # NOTE: abi=n32 requires a 64-bit MIPS chip! That is not a typo.
+ # It is basically the 64-bit abi with 32-bit pointers. Details:
+ # https://www.linux-mips.org/pub/linux/mips/doc/ABI/MIPS-N32-ABI-Handbook.pdf
+ gnuabin32 = { abi = "n32"; };
+ muslabin32 = { abi = "n32"; };
musleabi = { float = "soft"; };
musleabihf = { float = "hard"; };
musl = {};
- uclibceabihf = { float = "soft"; };
- uclibceabi = { float = "hard"; };
+ uclibceabi = { float = "soft"; };
+ uclibceabihf = { float = "hard"; };
uclibc = {};
unknown = {};
diff --git a/lib/systems/platforms.nix b/lib/systems/platforms.nix
index b2a8dbedef4f..04d55416242e 100644
--- a/lib/systems/platforms.nix
+++ b/lib/systems/platforms.nix
@@ -1,3 +1,10 @@
+# Note: lib/systems/default.nix takes care of producing valid,
+# fully-formed "platform" values (e.g. hostPlatform, buildPlatform,
+# targetPlatform, etc) containing at least the minimal set of attrs
+# required (see types.parsedPlatform in lib/systems/parse.nix). This
+# file takes an already-valid platform and further elaborates it with
+# optional fields such as linux-kernel, gcc, etc.
+
{ lib }:
rec {
pc = {
@@ -482,6 +489,43 @@ rec {
};
};
+ # can execute on 32bit chip
+ gcc_mips32r2_o32 = { gcc = { arch = "mips32r2"; abi = "o32"; }; };
+ gcc_mips32r6_o32 = { gcc = { arch = "mips32r6"; abi = "o32"; }; };
+ gcc_mips64r2_n32 = { gcc = { arch = "mips64r2"; abi = "n32"; }; };
+ gcc_mips64r6_n32 = { gcc = { arch = "mips64r6"; abi = "n32"; }; };
+ gcc_mips64r2_64 = { gcc = { arch = "mips64r2"; abi = "64"; }; };
+ gcc_mips64r6_64 = { gcc = { arch = "mips64r6"; abi = "64"; }; };
+
+ # based on:
+ # https://www.mail-archive.com/qemu-discuss@nongnu.org/msg05179.html
+ # https://gmplib.org/~tege/qemu.html#mips64-debian
+ mips64el-qemu-linux-gnuabi64 = (import ./examples).mips64el-linux-gnuabi64 // {
+ linux-kernel = {
+ name = "mips64el";
+ baseConfig = "64r2el_defconfig";
+ target = "vmlinuz";
+ autoModules = false;
+ DTB = true;
+ # for qemu 9p passthrough filesystem
+ extraConfig = ''
+ MIPS_MALTA y
+ PAGE_SIZE_4KB y
+ CPU_LITTLE_ENDIAN y
+ CPU_MIPS64_R2 y
+ 64BIT y
+ CPU_MIPS64_R2 y
+
+ NET_9P y
+ NET_9P_VIRTIO y
+ 9P_FS y
+ 9P_FS_POSIX_ACL y
+ PCI y
+ VIRTIO_PCI y
+ '';
+ };
+ };
+
##
## Other
##
@@ -499,6 +543,9 @@ rec {
};
};
+ # This function takes a minimally-valid "platform" and returns an
+ # attrset containing zero or more additional attrs which should be
+ # included in the platform in order to further elaborate it.
select = platform:
# x86
/**/ if platform.isx86 then pc
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index 5fa95828df69..271119031395 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -761,4 +761,156 @@ runTests {
{ a = 3; b = 30; c = 300; }
];
};
+
+ # The example from the showAttrPath documentation
+ testShowAttrPathExample = {
+ expr = showAttrPath [ "foo" "10" "bar" ];
+ expected = "foo.\"10\".bar";
+ };
+
+ testShowAttrPathEmpty = {
+ expr = showAttrPath [];
+ expected = "";
+ };
+
+ testShowAttrPathVarious = {
+ expr = showAttrPath [
+ "."
+ "foo"
+ "2"
+ "a2-b"
+ "_bc'de"
+ ];
+ expected = ''".".foo."2".a2-b._bc'de'';
+ };
+
+ testGroupBy = {
+ expr = groupBy (n: toString (mod n 5)) (range 0 16);
+ expected = {
+ "0" = [ 0 5 10 15 ];
+ "1" = [ 1 6 11 16 ];
+ "2" = [ 2 7 12 ];
+ "3" = [ 3 8 13 ];
+ "4" = [ 4 9 14 ];
+ };
+ };
+
+ testGroupBy' = {
+ expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ];
+ expected = { false = 3; true = 12; };
+ };
+
+ # The example from the updateManyAttrsByPath documentation
+ testUpdateManyAttrsByPathExample = {
+ expr = updateManyAttrsByPath [
+ {
+ path = [ "a" "b" ];
+ update = old: { d = old.c; };
+ }
+ {
+ path = [ "a" "b" "c" ];
+ update = old: old + 1;
+ }
+ {
+ path = [ "x" "y" ];
+ update = old: "xy";
+ }
+ ] { a.b.c = 0; };
+ expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; };
+ };
+
+ # If there are no updates, the value is passed through
+ testUpdateManyAttrsByPathNone = {
+ expr = updateManyAttrsByPath [] "something";
+ expected = "something";
+ };
+
+ # A single update to the root path is just like applying the function directly
+ testUpdateManyAttrsByPathSingleIncrement = {
+ expr = updateManyAttrsByPath [
+ {
+ path = [ ];
+ update = old: old + 1;
+ }
+ ] 0;
+ expected = 1;
+ };
+
+ # Multiple updates can be applied are done in order
+ testUpdateManyAttrsByPathMultipleIncrements = {
+ expr = updateManyAttrsByPath [
+ {
+ path = [ ];
+ update = old: old + "a";
+ }
+ {
+ path = [ ];
+ update = old: old + "b";
+ }
+ {
+ path = [ ];
+ update = old: old + "c";
+ }
+ ] "";
+ expected = "abc";
+ };
+
+ # If an update doesn't use the value, all previous updates are not evaluated
+ testUpdateManyAttrsByPathLazy = {
+ expr = updateManyAttrsByPath [
+ {
+ path = [ ];
+ update = old: old + throw "nope";
+ }
+ {
+ path = [ ];
+ update = old: "untainted";
+ }
+ ] (throw "start");
+ expected = "untainted";
+ };
+
+ # Deeply nested attributes can be updated without affecting others
+ testUpdateManyAttrsByPathDeep = {
+ expr = updateManyAttrsByPath [
+ {
+ path = [ "a" "b" "c" ];
+ update = old: old + 1;
+ }
+ ] {
+ a.b.c = 0;
+
+ a.b.z = 0;
+ a.y.z = 0;
+ x.y.z = 0;
+ };
+ expected = {
+ a.b.c = 1;
+
+ a.b.z = 0;
+ a.y.z = 0;
+ x.y.z = 0;
+ };
+ };
+
+ # Nested attributes are updated first
+ testUpdateManyAttrsByPathNestedBeforehand = {
+ expr = updateManyAttrsByPath [
+ {
+ path = [ "a" ];
+ update = old: old // { x = old.b; };
+ }
+ {
+ path = [ "a" "b" ];
+ update = old: old + 1;
+ }
+ ] {
+ a.b = 0;
+ };
+ expected = {
+ a.b = 1;
+ a.x = 1;
+ };
+ };
+
}
diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh
index 590937da5b8f..8050c6539fc2 100755
--- a/lib/tests/modules.sh
+++ b/lib/tests/modules.sh
@@ -62,6 +62,13 @@ checkConfigError() {
checkConfigOutput '^false$' config.enable ./declare-enable.nix
checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*: true' config.enable ./define-enable.nix
+checkConfigOutput '^1$' config.bare-submodule.nested ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix
+checkConfigOutput '^2$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix
+checkConfigOutput '^42$' config.bare-submodule.nested ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix ./declare-bare-submodule-deep-option.nix ./define-bare-submodule-values.nix
+checkConfigOutput '^420$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-nested-option.nix ./declare-bare-submodule-deep-option.nix ./define-bare-submodule-values.nix
+checkConfigOutput '^2$' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix ./define-shorthandOnlyDefinesConfig-true.nix
+checkConfigError 'The option .bare-submodule.deep. in .*/declare-bare-submodule-deep-option.nix. is already declared in .*/declare-bare-submodule-deep-option-duplicate.nix' config.bare-submodule.deep ./declare-bare-submodule.nix ./declare-bare-submodule-deep-option.nix ./declare-bare-submodule-deep-option-duplicate.nix
+
# Check integer types.
# unsigned
checkConfigOutput '^42$' config.value ./declare-int-unsigned-value.nix ./define-value-int-positive.nix
@@ -240,6 +247,11 @@ checkConfigOutput '^"24"$' config.foo ./freeform-attrsOf.nix ./freeform-str-dep-
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
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
+# freeformTypes can get merged using `types.type`, including submodules
+checkConfigOutput '^10$' config.free.xxx.foo ./freeform-submodules.nix
+checkConfigOutput '^10$' config.free.yyy.bar ./freeform-submodules.nix
## types.anything
# Check that attribute sets are merged recursively
@@ -284,6 +296,37 @@ checkConfigOutput '^"a b"$' config.resultFoo ./declare-variants.nix ./define-var
checkConfigOutput '^"a y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a b c"$' config.resultFooFoo ./declare-variants.nix ./define-variant.nix
+## emptyValue's
+checkConfigOutput "[ ]" config.list.a ./emptyValues.nix
+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
+
+## types.raw
+checkConfigOutput "{ foo = ; }" config.unprocessedNesting ./raw.nix
+checkConfigOutput "10" config.processedToplevel ./raw.nix
+checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix
+checkConfigOutput "bar" config.priorities ./raw.nix
+
+## Option collision
+checkConfigError \
+ 'The option .set. in module .*/declare-set.nix. would be a parent of the following options, but its type .attribute set of signed integers. does not support nested options.\n\s*- option[(]s[)] with prefix .set.enable. in module .*/declare-enable-nested.nix.' \
+ config.set \
+ ./declare-set.nix ./declare-enable-nested.nix
+
+# Test that types.optionType merges types correctly
+checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
+checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
+
+# Test that types.optionType correctly annotates option locations
+checkConfigError 'The option .theOption.nested. in .other.nix. is already declared in .optionTypeFile.nix.' config.theOption.nested ./optionTypeFile.nix
+
+# Test that types.optionType leaves types untouched as long as they don't need to be merged
+checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survives-type-merge.nix
+
cat < string -> a -> a
*/
- warnIf = cond: msg: if cond then warn msg else id;
+ warnIf = cond: msg: if cond then warn msg else x: x;
+
+ /*
+ Like warnIf, but negated (warn if the first argument is `false`).
+
+ Type: bool -> string -> a -> a
+ */
+ warnIfNot = cond: msg: if cond then x: x else warn msg;
/*
Like the `assert b; e` expression, but with a custom error message and
@@ -347,6 +378,13 @@ rec {
*/
throwIfNot = cond: msg: if cond then x: x else throw msg;
+ /*
+ Like throwIfNot, but negated (throw if the first argument is `true`).
+
+ Type: bool -> string -> a -> a
+ */
+ throwIf = cond: msg: if cond then throw msg else x: x;
+
/* Check if the elements in a list are valid values from a enum, returning the identity function, or throwing an error message otherwise.
Example:
@@ -403,6 +441,25 @@ rec {
isFunction = f: builtins.isFunction f ||
(f ? __functor && isFunction (f.__functor f));
+ /*
+ Turns any non-callable values into constant functions.
+ Returns callable values as is.
+
+ Example:
+
+ nix-repl> lib.toFunction 1 2
+ 1
+
+ nix-repl> lib.toFunction (x: x + 1) 2
+ 3
+ */
+ toFunction =
+ # Any value
+ v:
+ if isFunction v
+ then v
+ else k: v;
+
/* Convert the given positive integer to a string of its hexadecimal
representation. For example:
diff --git a/lib/types.nix b/lib/types.nix
index f2f9b2bca985..5c4b96310617 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -61,7 +61,11 @@ let
boolToString
;
- inherit (lib.modules) mergeDefinitions;
+ inherit (lib.modules)
+ mergeDefinitions
+ fixupOptionType
+ mergeOptionDecls
+ ;
outer_types =
rec {
isType = type: x: (x._type or "") == type;
@@ -162,6 +166,13 @@ rec {
# nixos/doc/manual/development/option-types.xml!
types = rec {
+ raw = mkOptionType rec {
+ name = "raw";
+ description = "raw value";
+ check = value: true;
+ merge = mergeOneOption;
+ };
+
anything = mkOptionType {
name = "anything";
description = "anything";
@@ -357,13 +368,21 @@ rec {
emptyValue = { value = {}; };
};
- # derivation is a reserved keyword.
+ # A package is a top-level store path (/nix/store/hash-name). This includes:
+ # - derivations
+ # - more generally, attribute sets with an `outPath` or `__toString` attribute
+ # pointing to a store path, e.g. flake inputs
+ # - strings with context, e.g. "${pkgs.foo}" or (toString pkgs.foo)
+ # - hardcoded store path literals (/nix/store/hash-foo) or strings without context
+ # ("/nix/store/hash-foo"). These get a context added to them using builtins.storePath.
package = mkOptionType {
name = "package";
check = x: isDerivation x || isStorePath x;
merge = loc: defs:
let res = mergeOneOption loc defs;
- in if isDerivation res then res else toDerivation res;
+ in if builtins.isPath res || (builtins.isString res && ! builtins.hasContext res)
+ then toDerivation res
+ else res;
};
shellPackage = package // {
@@ -390,7 +409,7 @@ rec {
).optionalValue
) def.value
) defs)));
- emptyValue = { value = {}; };
+ emptyValue = { value = []; };
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
getSubModules = elemType.getSubModules;
substSubModules = m: listOf (elemType.substSubModules m);
@@ -402,7 +421,7 @@ rec {
let list = addCheck (types.listOf elemType) (l: l != []);
in list // {
description = "non-empty " + list.description;
- # Note: emptyValue is left as is, because another module may define an element.
+ emptyValue = { }; # no .value attr, meaning unset
};
attrsOf = elemType: mkOptionType rec {
@@ -503,7 +522,7 @@ rec {
functionTo = elemType: mkOptionType {
name = "functionTo";
- description = "function that evaluates to a(n) ${elemType.name}";
+ description = "function that evaluates to a(n) ${elemType.description}";
check = isFunction;
merge = loc: defs:
fnArgs: (mergeDefinitions (loc ++ [ "[function body]" ]) elemType (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs)).mergedValue;
@@ -518,6 +537,33 @@ rec {
modules = toList modules;
};
+ # The type of a type!
+ optionType = mkOptionType {
+ name = "optionType";
+ description = "optionType";
+ check = value: value._type or null == "option-type";
+ merge = loc: defs:
+ if length defs == 1
+ then (head defs).value
+ else let
+ # Prepares the type definitions for mergeOptionDecls, which
+ # annotates submodules types with file locations
+ optionModules = map ({ value, file }:
+ {
+ _file = file;
+ # There's no way to merge types directly from the module system,
+ # but we can cheat a bit by just declaring an option with the type
+ options = lib.mkOption {
+ type = value;
+ };
+ }
+ ) defs;
+ # Merges all the types into a single one, including submodule merging.
+ # This also propagates file information to all submodules
+ mergedOption = fixupOptionType loc (mergeOptionDecls loc optionModules);
+ in mergedOption.type;
+ };
+
submoduleWith =
{ modules
, specialArgs ? {}
@@ -526,14 +572,18 @@ rec {
let
inherit (lib.modules) evalModules;
- coerce = unify: value: if isFunction value
- then setFunctionArgs (args: unify (value args)) (functionArgs value)
- else unify (if shorthandOnlyDefinesConfig then { config = value; } else value);
+ shorthandToModule = if shorthandOnlyDefinesConfig == false
+ then value: value
+ else value: { config = value; };
allModules = defs: imap1 (n: { value, file }:
- if isAttrs value || isFunction value then
- # Annotate the value with the location of its definition for better error messages
- coerce (lib.modules.unifyModuleSyntax file "${toString file}-${toString n}") value
+ if isFunction value
+ then setFunctionArgs
+ (args: lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (value args))
+ (functionArgs value)
+ else if isAttrs value
+ then
+ lib.modules.unifyModuleSyntax file "${toString file}-${toString n}" (shorthandToModule value)
else value
) defs;
@@ -601,7 +651,11 @@ rec {
then lhs.specialArgs // rhs.specialArgs
else throw "A submoduleWith option is declared multiple times with the same specialArgs \"${toString (attrNames intersecting)}\"";
shorthandOnlyDefinesConfig =
- if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig
+ if lhs.shorthandOnlyDefinesConfig == null
+ then rhs.shorthandOnlyDefinesConfig
+ else if rhs.shorthandOnlyDefinesConfig == null
+ then lhs.shorthandOnlyDefinesConfig
+ else if lhs.shorthandOnlyDefinesConfig == rhs.shorthandOnlyDefinesConfig
then lhs.shorthandOnlyDefinesConfig
else throw "A submoduleWith option is declared multiple times with conflicting shorthandOnlyDefinesConfig values";
};
@@ -695,14 +749,6 @@ rec {
nestedTypes.finalType = finalType;
};
- # Obsolete alternative to configOf. It takes its option
- # declarations from the ‘options’ attribute of containing option
- # declaration.
- optionSet = mkOptionType {
- name = "optionSet";
- description = "option set";
- deprecationMessage = "Use `types.submodule' instead";
- };
# Augment the given type with an additional type check function.
addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; };
diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
index e991280a0f28..25c5bd078e51 100644
--- a/maintainers/maintainer-list.nix
+++ b/maintainers/maintainer-list.nix
@@ -145,6 +145,12 @@
githubId = 16829510;
name = "Aaron Janse";
};
+ aaronjheng = {
+ email = "wentworth@outlook.com";
+ github = "aaronjheng";
+ githubId = 806876;
+ name = "Aaron Jheng";
+ };
aaronschif = {
email = "aaronschif@gmail.com";
github = "aaronschif";
@@ -513,12 +519,6 @@
githubId = 38869148;
name = "Alex Eyre";
};
- algorith = {
- email = "dries_van_daele@telenet.be";
- github = "DriesVanDaele";
- githubId = 1141488;
- name = "Dries Van Daele";
- };
alibabzo = {
email = "alistair.bill@gmail.com";
github = "alibabzo";
@@ -601,6 +601,12 @@
githubId = 15623522;
name = "Amar Paul";
};
+ amarshall = {
+ email = "andrew@johnandrewmarshall.com";
+ github = "amarshall";
+ githubId = 153175;
+ name = "Andrew Marshall";
+ };
ambroisie = {
email = "bruno.nixpkgs@belanyi.fr";
github = "ambroisie";
@@ -765,13 +771,6 @@
githubId = 11699655;
name = "Stanislas Lange";
};
- angustrau = {
- name = "Angus Trau";
- email = "nix@angus.ws";
- matrix = "@angustrau:matrix.org";
- github = "angustrau";
- githubId = 13267947;
- };
anhdle14 = {
name = "Le Anh Duc";
email = "anhdle14@icloud.com";
@@ -930,6 +929,12 @@
githubId = 1296771;
name = "Anders Riutta";
};
+ arjan-s = {
+ email = "github@anymore.nl";
+ github = "arjan-s";
+ githubId = 10400299;
+ name = "Arjan Schrijver";
+ };
arkivm = {
email = "vikram186@gmail.com";
github = "arkivm";
@@ -1083,6 +1088,12 @@
githubId = 55833;
name = "Troels Henriksen";
};
+ atila = {
+ name = "Átila Saraiva";
+ email = "atilasaraiva@gmail.com";
+ github = "AtilaSaraiva";
+ githubId = 29521461;
+ };
atkinschang = {
email = "atkinschang+nixpkgs@gmail.com";
github = "AtkinsChang";
@@ -1185,14 +1196,14 @@
name = "Artturi N";
};
azahi = {
- email = "azahi@teknik.io";
- matrix = "@azahi:matrix.org";
+ name = "Azat Bahawi";
+ email = "azat@bahawi.net";
+ matrix = "@azahi:azahi.cc";
github = "azahi";
githubId = 22211000;
- name = "Azat Bahawi";
keys = [{
- longkeyid = "rsa2048/0xB40FCB6608BBE3B6";
- fingerprint = "E9F3 483F 31C7 29B4 4CA2 7C38 B40F CB66 08BB E3B6";
+ longkeyid = "rsa4096/0xC8C6BDDB3847F72B";
+ fingerprint = "2688 0377 C31D 9E81 9BDF 83A8 C8C6 BDDB 3847 F72B";
}];
};
ayazhafiz = {
@@ -1201,6 +1212,12 @@
githubId = 262763;
name = "Ayaz Hafiz";
};
+ azuwis = {
+ email = "azuwis@gmail.com";
+ github = "azuwis";
+ githubId = 9315;
+ name = "Zhong Jianxin";
+ };
b4dm4n = {
email = "fabianm88@gmail.com";
github = "B4dM4n";
@@ -1284,12 +1301,24 @@
githubId = 127523;
name = "Herman Fries";
};
+ BarinovMaxim = {
+ name = "Barinov Maxim";
+ email = "barinov274@gmail.com";
+ github = "barinov274";
+ githubId = 54442153;
+ };
barrucadu = {
email = "mike@barrucadu.co.uk";
github = "barrucadu";
githubId = 75235;
name = "Michael Walker";
};
+ bartsch = {
+ email = "consume.noise@gmail.com";
+ github = "bartsch";
+ githubId = 3390885;
+ name = "Daniel Martin";
+ };
bartuka = {
email = "wand@hey.com";
github = "wandersoncferreira";
@@ -1671,6 +1700,12 @@
githubId = 355401;
name = "Brian Hicks";
};
+ brianmcgee = {
+ name = "Brian McGee";
+ email = "brian@41north.dev";
+ github = "brianmcgee";
+ githubId = 1173648;
+ };
Br1ght0ne = {
email = "brightone@protonmail.com";
github = "Br1ght0ne";
@@ -1878,6 +1913,12 @@
githubId = 82591;
name = "Carl Sverre";
};
+ carpinchomug = {
+ email = "aki.suda@protonmail.com";
+ github = "carpinchomug";
+ githubId = 101536256;
+ name = "Akiyoshi Suda";
+ };
cartr = {
email = "carter.sande@duodecima.technology";
github = "cartr";
@@ -2164,6 +2205,12 @@
githubId = 42220376;
name = "Charlotte Van Petegem";
};
+ cigrainger = {
+ name = "Christopher Grainger";
+ email = "chris@amplified.ai";
+ github = "cigrainger";
+ githubId = 3984794;
+ };
ciil = {
email = "simon@lackerbauer.com";
github = "ciil";
@@ -2207,7 +2254,7 @@
ckie = {
email = "nixpkgs-0efe364@ckie.dev";
github = "ckiee";
- githubId = 2526321;
+ githubId = 25263210;
keys = [{
longkeyid = "rsa4096/0x13E79449C0525215";
fingerprint = "539F 0655 4D35 38A5 429A E253 13E7 9449 C052 5215";
@@ -2309,6 +2356,13 @@
githubId = 5561189;
name = "Cody Opel";
};
+ Cogitri = {
+ email = "oss@cogitri.dev";
+ github = "Cogitri";
+ githubId = 8766773;
+ matrix = "@cogitri:cogitri.dev";
+ name = "Rasmus Thomsen";
+ };
cohei = {
email = "a.d.xvii.kal.mai@gmail.com";
github = "cohei";
@@ -2381,6 +2435,13 @@
githubId = 11145016;
name = "J.C.";
};
+ congee = {
+ email = "changshengwu@pm.me";
+ matrix = "@congeec:matrix.org";
+ github = "congee";
+ name = "Changsheng Wu";
+ githubId = 2083950;
+ };
contrun = {
email = "uuuuuu@protonmail.com";
github = "contrun";
@@ -2393,6 +2454,23 @@
githubId = 5510514;
name = "Conrad Mearns";
};
+ corbanr = {
+ email = "corban@raunco.co";
+ github = "CorbanR";
+ githubId = 1918683;
+ matrix = "@corbansolo:matrix.org";
+ name = "Corban Raun";
+ keys = [
+ {
+ longkeyid = "rsa4096/0xA697A56F1F151189";
+ fingerprint = "6607 0B24 8CE5 64ED 22CE 0950 A697 A56F 1F15 1189";
+ }
+ {
+ longkeyid = "ed25519/0x230F4AC153F90F29";
+ fingerprint = "D8CB 816A B678 A4E6 1EC7 5325 230F 4AC1 53F9 0F29";
+ }
+ ];
+ };
couchemar = {
email = "couchemar@yandex.ru";
github = "couchemar";
@@ -2752,6 +2830,12 @@
githubId = 49904992;
name = "Dawid Sowa";
};
+ dbeckwith = {
+ email = "djbsnx@gmail.com";
+ github = "dbeckwith";
+ githubId = 1279939;
+ name = "Daniel Beckwith";
+ };
dbirks = {
email = "david@birks.dev";
github = "dbirks";
@@ -2878,6 +2962,12 @@
githubId = 19733;
name = "Moritz Heidkamp";
};
+ DerickEddington = {
+ email = "derick.eddington@pm.me";
+ github = "DerickEddington";
+ githubId = 4731128;
+ name = "Derick Eddington";
+ };
dermetfan = {
email = "serverkorken@gmail.com";
github = "dermetfan";
@@ -2962,6 +3052,12 @@
githubId = 8404455;
name = "Diego Lelis";
};
+ DieracDelta = {
+ email = "justin@restivo.me";
+ github = "DieracDelta";
+ githubId = 13730968;
+ name = "Justin Restivo";
+ };
diffumist = {
email = "git@diffumist.me";
github = "diffumist";
@@ -3380,6 +3476,12 @@
githubId = 18535642;
name = "Emily";
};
+ emilytrau = {
+ name = "Emily Trau";
+ email = "nix@angus.ws";
+ github = "emilytrau";
+ githubId = 13267947;
+ };
enderger = {
email = "endergeryt@gmail.com";
github = "enderger";
@@ -3735,6 +3837,12 @@
githubId = 222467;
name = "Dmitry Ivanov";
};
+ Etjean = {
+ email = "et.jean@outlook.fr";
+ github = "Etjean";
+ githubId = 32169529;
+ name = "Etienne Jean";
+ };
etu = {
email = "elis@hirwing.se";
matrix = "@etu:semi.social";
@@ -3917,6 +4025,12 @@
githubId = 1276854;
name = "Florian Peter";
};
+ fbeffa = {
+ email = "beffa@fbengineering.ch";
+ github = "fedeinthemix";
+ githubId = 7670450;
+ name = "Federico Beffa";
+ };
fbrs = {
email = "yuuki@protonmail.com";
github = "cideM";
@@ -4009,6 +4123,12 @@
github = "fitzgibbon";
githubId = 617048;
};
+ fkautz = {
+ name = "Frederick F. Kautz IV";
+ email = "fkautz@alumni.cmu.edu";
+ github = "fkautz";
+ githubId = 135706;
+ };
Flakebi = {
email = "flakebi@t-online.de";
github = "Flakebi";
@@ -4133,7 +4253,12 @@
githubId = 119691;
name = "Michael Gough";
};
-
+ freax13 = {
+ email = "erbse.13@gmx.de";
+ github = "freax13";
+ githubId = 14952658;
+ name = "Tom Dohrmann";
+ };
fredeb = {
email = "im@fredeb.dev";
github = "fredeeb";
@@ -4395,6 +4520,12 @@
githubId = 27668;
name = "Tobias Pflug";
};
+ gin66 = {
+ email = "jochen@kiemes.de";
+ github = "gin66";
+ githubId = 5549373;
+ name = "Jochen Kiemes";
+ };
giogadi = {
email = "lgtorres42@gmail.com";
github = "giogadi";
@@ -4474,7 +4605,7 @@
gordias = {
name = "Gordias";
email = "gordias@disroot.org";
- github = "NotGordias";
+ github = "gordiasdot";
githubId = 94724133;
keys = [{
longkeyid = "ed25519/0x5D47284830FAA4FA";
@@ -5455,6 +5586,12 @@
githubId = 221929;
name = "Jean-Baptiste Giraudeau";
};
+ jc = {
+ name = "Josh Cooper";
+ email = "josh@cooper.is";
+ github = "joshua-cooper";
+ githubId = 35612334;
+ };
jceb = {
name = "jceb";
email = "jceb@e-jc.de";
@@ -5529,6 +5666,12 @@
github = "jduan";
githubId = 452450;
};
+ jdupak = {
+ name = "Jakub Dupak";
+ email = "dev@jakubdupak.com";
+ github = "jdupak";
+ githubId = 22683640;
+ };
jecaro = {
email = "jeancharles.quillet@gmail.com";
github = "jecaro";
@@ -5583,6 +5726,16 @@
githubId = 143075;
name = "James Felix Black";
};
+ jfchevrette = {
+ email = "jfchevrette@gmail.com";
+ github = "jfchevrette";
+ githubId = 3001;
+ name = "Jean-Francois Chevrette";
+ keys = [{
+ longkeyid = "rsa4096/0x67A0585801290DC6";
+ fingerprint = "B612 96A9 498E EECD D5E9 C0F0 67A0 5858 0129 0DC6";
+ }];
+ };
jflanglois = {
email = "yourstruly@julienlanglois.me";
github = "jflanglois";
@@ -5739,6 +5892,12 @@
githubId = 587870;
name = "Jonathan Mettes";
};
+ jmgilman = {
+ email = "joshuagilman@gmail.com";
+ github = "jmgilman";
+ githubId = 2308444;
+ name = "Joshua Gilman";
+ };
jo1gi = {
email = "joakimholm@protonmail.com";
github = "jo1gi";
@@ -5965,6 +6124,12 @@
githubId = 4611077;
name = "Raymond Gauthier";
};
+ jrpotter = {
+ email = "jrpotter2112@gmail.com";
+ github = "jrpotter";
+ githubId = 3267697;
+ name = "Joshua Potter";
+ };
jschievink = {
email = "jonasschievink@gmail.com";
matrix = "@jschievink:matrix.org";
@@ -6020,6 +6185,12 @@
githubId = 810075;
name = "Juan Rodal";
};
+ juboba = {
+ email = "juboba@gmail.com";
+ github = "juboba";
+ githubId = 1189739;
+ name = "Julio Borja Barra";
+ };
juliendehos = {
email = "dehos@lisic.univ-littoral.fr";
github = "juliendehos";
@@ -6068,6 +6239,16 @@
githubId = 2396926;
name = "Justin Woo";
};
+ jvanbruegge = {
+ email = "supermanitu@gmail.com";
+ github = "jvanbruegge";
+ githubId = 1529052;
+ name = "Jan van Brügge";
+ keys = [{
+ longkeyid = "rsa4096/0x366572BE7D6C78A2";
+ fingerprint = "3513 5CE5 77AD 711F 3825 9A99 3665 72BE 7D6C 78A2";
+ }];
+ };
jwatt = {
email = "jwatt@broken.watch";
github = "jjwatt";
@@ -6228,6 +6409,12 @@
githubId = 37185887;
name = "Calvin Kim";
};
+ keldu = {
+ email = "mail@keldu.de";
+ github = "keldu";
+ githubId = 15373888;
+ name = "Claudius Holeksa";
+ };
kennyballou = {
email = "kb@devnulllabs.io";
github = "kennyballou";
@@ -6263,6 +6450,12 @@
githubId = 209729;
name = "Kevin Griffin";
};
+ kevink = {
+ email = "kevin@kevink.dev";
+ github = "Unkn0wnCat";
+ githubId = 8211181;
+ name = "Kevin Kandlbinder";
+ };
kfollesdal = {
email = "kfollesdal@gmail.com";
github = "kfollesdal";
@@ -6419,7 +6612,7 @@
githubId = 18447310;
};
kloenk = {
- email = "me@kloenk.de";
+ email = "me@kloenk.dev";
matrix = "@kloenk:petabyte.dev";
name = "Finn Behrens";
github = "kloenk";
@@ -6526,6 +6719,12 @@
githubId = 787421;
name = "Kevin Quick";
};
+ kradalby = {
+ name = "Kristoffer Dalby";
+ email = "kristoffer@dalby.cc";
+ github = "kradalby";
+ githubId = 98431;
+ };
kraem = {
email = "me@kraem.xyz";
github = "kraem";
@@ -6967,12 +7166,6 @@
githubId = 36448130;
name = "Michael Brantley";
};
- linarcx = {
- email = "linarcx@gmail.com";
- github = "linarcx";
- githubId = 10884422;
- name = "Kaveh Ahangar";
- };
linc01n = {
email = "git@lincoln.hk";
github = "linc01n";
@@ -7035,6 +7228,12 @@
githubId = 30698906;
name = "Luna D Dragon";
};
+ LunNova = {
+ email = "nixpkgs-maintainer@lunnova.dev";
+ github = "LunNova";
+ githubId = 782440;
+ name = "Luna Nova";
+ };
lionello = {
email = "lio@lunesu.com";
github = "lionello";
@@ -7071,6 +7270,29 @@
githubId = 1267527;
name = "Daniel Firth";
};
+ lockejan = {
+ email = "git@smittie.de";
+ matrix = "@jan:smittie.de";
+ github = "lockejan";
+ githubId = 25434434;
+ name = "Jan Schmitt";
+ keys = [{
+ longkeyid = "dsa2048/0xA2BC3C6F14351991";
+ fingerprint = "1763 9903 2D7C 5B82 5D5A 0EAD A2BC 3C6F 1435 1991";
+ }];
+ };
+ lodi = {
+ email = "anthony.lodi@gmail.com";
+ github = "lodi";
+ githubId = 918448;
+ name = "Anthony Lodi";
+ };
+ loicreynier = {
+ email = "loic@loireynier.fr";
+ github = "loicreynier";
+ githubId = 88983487;
+ name = "Loïc Reynier";
+ };
lopsided98 = {
email = "benwolsieffer@gmail.com";
github = "lopsided98";
@@ -7506,16 +7728,6 @@
githubId = 29855073;
name = "Michael Colicchia";
};
- matdsoupe = {
- github = "matdsoupe";
- githubId = 44469426;
- name = "Matheus de Souza Pessanha";
- email = "matheus_pessanha2001@outlook.com";
- keys = [{
- longkeyid = "rsa4096/0x2671964AB1E06A08";
- fingerprint = "2F32 CFEF E11A D73B A740 FA47 2671 964A B1E0 6A08";
- }];
- };
matejc = {
email = "cotman.matej@gmail.com";
github = "matejc";
@@ -7571,6 +7783,16 @@
githubId = 279868;
name = "Matti Kariluoma";
};
+ matthewpi = {
+ email = "me+nix@matthewp.io";
+ github = "matthewpi";
+ githubId = 26559841;
+ name = "Matthew Penner";
+ keys = [{
+ longkeyid = "ed25519/0x31311906AD4CF6D6";
+ fingerprint = "5118 F1CC B7B0 6C17 4DD1 5267 3131 1906 AD4C F6D6";
+ }];
+ };
maurer = {
email = "matthew.r.maurer+nix@gmail.com";
github = "maurer";
@@ -7617,6 +7839,12 @@
githubId = 1187050;
name = "Maximilian Huber";
};
+ maximsmol = {
+ email = "maximsmol@gmail.com";
+ github = "maximsmol";
+ githubId = 1472826;
+ name = "Max Smolin";
+ };
maxxk = {
email = "maxim.krivchikov@gmail.com";
github = "maxxk";
@@ -7797,12 +8025,6 @@
github = "kira-bruneau";
githubId = 382041;
};
- meutraa = {
- email = "paul+nixpkgs@lost.host";
- name = "Paul Meredith";
- github = "meutraa";
- githubId = 68550871;
- };
mephistophiles = {
email = "mussitantesmortem@gmail.com";
name = "Maxim Zhukov";
@@ -7845,6 +8067,12 @@
githubId = 668926;
name = "Maximilian Güntner";
};
+ mh = {
+ email = "68288772+markus-heinrich@users.noreply.github.com";
+ github = "markus-heinrich";
+ githubId = 68288772;
+ name = "Markus Heinrich";
+ };
mhaselsteiner = {
email = "magdalena.haselsteiner@gmx.at";
github = "mhaselsteiner";
@@ -7916,6 +8144,12 @@
fingerprint = "FEF0 AE2D 5449 3482 5F06 40AA 186A 1EDA C5C6 3F83";
}];
};
+ mihnea-s = {
+ email = "mihn.stn@gmail.com";
+ github = "mihnea-s";
+ githubId = 43088426;
+ name = "Mihnea Stoian";
+ };
mikefaille = {
email = "michael@faille.io";
github = "mikefaille";
@@ -8030,13 +8264,6 @@
githubId = 1001112;
name = "Marcin Janczyk";
};
- mjlbach = {
- email = "m.j.lbach@gmail.com";
- matrix = "@atrius:matrix.org";
- github = "mjlbach";
- githubId = 13316262;
- name = "Michael Lingelbach";
- };
mjp = {
email = "mike@mythik.co.uk";
github = "MikePlayle";
@@ -8271,6 +8498,17 @@
githubId = 3073833;
name = "Massimo Redaelli";
};
+ mrhedgehog = {
+ name = "Mr Hedgehog";
+ email = "hedgehog@mrhedgehog.xyz";
+ matrix = "@mrhedgehog:jupiterbroadcasting.com";
+ github = "ModdedGamers";
+ githubId = 35778371;
+ keys = [{
+ longkeyid = "rsa4096/0x7D5107866B1C6752";
+ fingerprint = "38A0 29B0 4A7E 4C13 A4BB 86C8 7D51 0786 6B1C 6752";
+ }];
+ };
mrkkrp = {
email = "markkarpov92@gmail.com";
github = "mrkkrp";
@@ -8415,6 +8653,17 @@
githubId = 25388474;
name = "Matej Urbas";
};
+ mvisonneau = {
+ name = "Maxime VISONNEAU";
+ email = "maxime@visonneau.fr";
+ matrix = "@maxime:visonneau.fr";
+ github = "mvisonneau";
+ githubId = 1761583;
+ keys = [{
+ longkeyid = "rsa4096/0x150D6F0AE9198D24";
+ fingerprint = "EC63 0CEA E8BC 5EE5 5C58 F2E3 150D 6F0A E919 8D24";
+ }];
+ };
mvnetbiz = {
email = "mvnetbiz@gmail.com";
matrix = "@mvtva:matrix.org";
@@ -8440,6 +8689,12 @@
githubId = 9636071;
name = "Myrl Hex";
};
+ n0emis = {
+ email = "nixpkgs@n0emis.network";
+ github = "n0emis";
+ githubId = 22817873;
+ name = "Ember Keske";
+ };
nadrieril = {
email = "nadrieril@gmail.com";
github = "nadrieril";
@@ -8507,6 +8762,12 @@
fingerprint = "4BFF 0614 03A2 47F0 AA0B 4BC4 916D 8B67 2418 92AE";
}];
};
+ nbr = {
+ email = "nbr@users.noreply.github.com";
+ github = "nbr";
+ githubId = 3819225;
+ name = "Nick Braga";
+ };
nbren12 = {
email = "nbren12@gmail.com";
github = "nbren12";
@@ -8542,6 +8803,12 @@
githubId = 3747396;
name = "Nathan Isom";
};
+ nelsonjeppesen = {
+ email = "nix@jeppesen.io";
+ github = "NelsonJeppesen";
+ githubId = 50854675;
+ name = "Nelson Jeppesen";
+ };
neonfuz = {
email = "neonfuz@gmail.com";
github = "neonfuz";
@@ -8664,6 +8931,12 @@
githubId = 8214542;
name = "Nicolò Balzarotti";
};
+ nidabdella = {
+ name = "Mohamed Nidabdella";
+ email = "nidabdella.mohamed@gmail.com";
+ github = "nidabdella";
+ githubId = 8083813;
+ };
NieDzejkob = {
email = "kuba@kadziolka.net";
github = "NieDzejkob";
@@ -8839,9 +9112,9 @@
githubId = 2946283;
name = "Brian Cohen";
};
- novoxudonoser = {
+ novoxd = {
email = "radnovox@gmail.com";
- github = "novoxudonoser";
+ github = "novoxd";
githubId = 6052922;
name = "Kirill Struokov";
};
@@ -8969,6 +9242,12 @@
githubId = 158758;
name = "Oliver Dunkl";
};
+ ofek = {
+ email = "oss@ofek.dev";
+ github = "ofek";
+ githubId = 9677399;
+ name = "Ofek Lev";
+ };
offline = {
email = "jaka@x-truder.net";
github = "offlinehacker";
@@ -9063,6 +9342,12 @@
githubId = 23431373;
name = "Christoph Neidahl";
};
+ opeik = {
+ email = "sandro@stikic.com";
+ github = "opeik";
+ githubId = 11566773;
+ name = "Sandro Stikić";
+ };
orbekk = {
email = "kjetil.orbekk@gmail.com";
github = "orbekk";
@@ -9147,6 +9432,12 @@
githubId = 15930073;
name = "Moritz Scheuren";
};
+ ozkutuk = {
+ email = "ozkutuk@protonmail.com";
+ github = "ozkutuk";
+ githubId = 5948762;
+ name = "Berk Özkütük";
+ };
pablovsky = {
email = "dealberapablo07@gmail.com";
github = "pablo1107";
@@ -9215,6 +9506,13 @@
githubId = 71795;
name = "Mica Semrick";
};
+ papojari = {
+ email = "papojari-git.ovoid@aleeas.com";
+ matrix = "@papojari:artemislena.eu";
+ github = "papojari";
+ githubId = 81317317;
+ name = "papojari";
+ };
paraseba = {
email = "paraseba@gmail.com";
github = "paraseba";
@@ -9652,6 +9950,12 @@
fingerprint = "48AD DE10 F27B AFB4 7BB0 CCAF 2D25 95A0 0D08 ACE0";
}];
};
+ ppenguin = {
+ name = "Jeroen Versteeg";
+ email = "hieronymusv@gmail.com";
+ github = "ppenguin";
+ githubId = 17690377;
+ };
ppom = {
name = "Paco Pompeani";
email = "paco@ecomail.io";
@@ -9786,6 +10090,12 @@
githubId = 20524473;
name = "Psyanticy";
};
+ psydvl = {
+ email = "psydvl@fea.st";
+ github = "psydvl";
+ githubId = 43755002;
+ name = "Dmitriy P";
+ };
ptival = {
email = "valentin.robert.42@gmail.com";
github = "Ptival";
@@ -10002,6 +10312,16 @@
githubId = 16487165;
name = "Rafael Basso";
};
+ rbreslow = {
+ name = "Rocky Breslow";
+ email = "1774125+rbreslow@users.noreply.github.com";
+ github = "rbreslow";
+ githubId = 1774125;
+ keys = [{
+ longkeyid = "ed25519/0xA0D32ACCA38B88ED";
+ fingerprint = "B5B7 BCA0 EE6F F31E 263A 69E3 A0D3 2ACC A38B 88ED";
+ }];
+ };
rbrewer = {
email = "rwb123@gmail.com";
github = "rbrewer123";
@@ -10020,6 +10340,20 @@
githubId = 16624;
name = "Maxim Ivanov";
};
+ reckenrode = {
+ name = "Randy Eckenrode";
+ email = "randy@largeandhighquality.com";
+ matrix = "@reckenrode:matrix.org";
+ github = "reckenrode";
+ githubId = 7413633;
+ keys = [
+ # compare with https://keybase.io/reckenrode
+ {
+ longkeyid = "ed25519/0xFBF19A982CCE0048";
+ fingerprint = "01D7 5486 3A6D 64EA AC77 0D26 FBF1 9A98 2CCE 0048";
+ }
+ ];
+ };
redfish64 = {
email = "engler@gmail.com";
github = "redfish64";
@@ -10114,6 +10448,18 @@
githubId = 22803888;
name = "Lu Hongxu";
};
+ rgnns = {
+ email = "jglievano@gmail.com";
+ github = "rgnns";
+ githubId = 811827;
+ name = "Gabriel Lievano";
+ };
+ rgrinberg = {
+ name = "Rudi Grinberg";
+ email = "me@rgrinberg.com";
+ github = "rgrinberg";
+ githubId = 139003;
+ };
rgrunbla = {
email = "remy@grunblatt.org";
github = "rgrunbla";
@@ -10138,6 +10484,13 @@
githubId = 6047658;
name = "Ryan Horiguchi";
};
+ rhysmdnz = {
+ email = "rhys@memes.nz";
+ matrix = "@rhys:memes.nz";
+ github = "rhysmdnz";
+ githubId = 2162021;
+ name = "Rhys Davies";
+ };
ribose-jeffreylau = {
name = "Jeffrey Lau";
email = "jeffrey.lau@ribose.com";
@@ -10814,6 +11167,12 @@
githubId = 19472270;
name = "Sebastian";
};
+ sebastianblunt = {
+ name = "Sebastian Blunt";
+ email = "nix@sebastianblunt.com";
+ github = "sebastianblunt";
+ githubId = 47431204;
+ };
sebbadk = {
email = "sebastian@sebba.dk";
github = "SEbbaDK";
@@ -10952,6 +11311,12 @@
githubId = 293035;
name = "Shawn Dellysse";
};
+ shawn8901 = {
+ email = "shawn8901@googlemail.com";
+ github = "shawn8901";
+ githubId = 12239057;
+ name = "Shawn8901";
+ };
shazow = {
email = "andrey.petrov@shazow.net";
github = "shazow";
@@ -10988,6 +11353,16 @@
github = "shikanime";
githubId = 22115108;
};
+ shiryel = {
+ email = "contact@shiryel.com";
+ name = "Shiryel";
+ github = "shiryel";
+ githubId = 35617139;
+ keys = [{
+ longkeyid = "ed25519/0xC4041EA6B32633DE";
+ fingerprint = "AB63 4CD9 3322 BD42 6231 F764 C404 1EA6 B326 33DE";
+ }];
+ };
shlevy = {
email = "shea@shealevy.com";
github = "shlevy";
@@ -11411,6 +11786,23 @@
githubId = 1699155;
name = "Steve Elliott";
};
+ stehessel = {
+ email = "stephan@stehessel.de";
+ github = "stehessel";
+ githubId = 55607356;
+ name = "Stephan Heßelmann";
+ };
+ steinybot = {
+ name = "Jason Pickens";
+ email = "jasonpickensnz@gmail.com";
+ matrix = "@steinybot:matrix.org";
+ github = "steinybot";
+ githubId = 4659562;
+ keys = [{
+ longkeyid = "ed25519/0x21DE1CAE59762A0F";
+ fingerprint = "2709 1DEC CC42 4635 4299 569C 21DE 1CAE 5976 2A0F";
+ }];
+ };
stelcodes = {
email = "stel@stel.codes";
github = "stelcodes";
@@ -11554,6 +11946,13 @@
githubId = 2666479;
name = "Y Nguyen";
};
+ superherointj = {
+ name = "Sérgio G.";
+ email = "5861043+superherointj@users.noreply.github.com";
+ matrix = "@superherointj:matrix.org";
+ github = "superherointj";
+ githubId = 5861043;
+ };
SuperSandro2000 = {
email = "sandro.jaeckel@gmail.com";
matrix = "@sandro:supersandro.de";
@@ -11794,6 +12193,13 @@
githubId = 863327;
name = "Tyler Benster";
};
+ tboerger = {
+ email = "thomas@webhippie.de";
+ matrix = "@tboerger:matrix.org";
+ github = "tboerger";
+ githubId = 156964;
+ name = "Thomas Boerger";
+ };
tcbravo = {
email = "tomas.bravo@protonmail.ch";
github = "tcbravo";
@@ -12153,6 +12559,7 @@
};
toastal = {
email = "toastal+nix@posteo.net";
+ matrix = "@toastal:matrix.org";
github = "toastal";
githubId = 561087;
name = "toastal";
@@ -12403,6 +12810,12 @@
githubId = 1983821;
name = "Eric Wolf";
};
+ uakci = {
+ name = "uakci";
+ email = "uakci@uakci.pl";
+ github = "uakci";
+ githubId = 6961268;
+ };
udono = {
email = "udono@virtual-things.biz";
github = "udono";
@@ -12641,9 +13054,9 @@
githubId = 5837359;
name = "Adrian Pistol";
};
- vika_nezrimaya = {
+ vikanezrimaya = {
email = "vika@fireburn.ru";
- github = "kisik21";
+ github = "vikanezrimaya";
githubId = 7953163;
name = "Vika Shleina";
keys = [{
@@ -12667,6 +13080,12 @@
githubId = 118959;
name = "VinyMeuh";
};
+ viraptor = {
+ email = "nix@viraptor.info";
+ github = "viraptor";
+ githubId = 188063;
+ name = "Stanisław Pitucha";
+ };
viric = {
email = "viric@viric.name";
github = "viric";
@@ -12824,6 +13243,12 @@
githubId = 34962284;
name = "wchresta";
};
+ wdavidw = {
+ name = "David Worms";
+ email = "david@adaltas.com";
+ github = "wdavidw";
+ githubId = 46896;
+ };
wedens = {
email = "kirill.wedens@gmail.com";
name = "wedens";
@@ -13013,7 +13438,7 @@
name = "Wayne Scott";
};
wucke13 = {
- email = "info@wucke13.de";
+ email = "wucke13@gmail.com";
github = "wucke13";
githubId = 20400405;
name = "Wucke";
@@ -13092,6 +13517,12 @@
githubId = 1297598;
name = "Konrad Borowski";
};
+ xgroleau = {
+ email = "xgroleau@gmail.com";
+ github = "xgroleau";
+ githubId = 31734358;
+ name = "Xavier Groleau";
+ };
xiorcale = {
email = "quentin.vaucher@pm.me";
github = "xiorcale";
@@ -13148,7 +13579,7 @@
};
yana = {
email = "yana@riseup.net";
- github = "alpakido";
+ github = "sowelisuwi";
githubId = 1643293;
name = "Yana Timoshenko";
};
@@ -13602,10 +14033,10 @@
github = "nagisa";
githubId = 679122;
};
- yevhenshymotiuk = {
+ yshym = {
name = "Yevhen Shymotiuk";
- email = "yevhenshymotiuk@gmail.com";
- github = "yevhenshymotiuk";
+ email = "yshym@pm.me";
+ github = "yshym";
githubId = 44244245;
};
hmenke = {
@@ -13729,6 +14160,16 @@
github = "zeri42";
githubId = 68825133;
};
+ zoedsoupe = {
+ github = "zoedsoupe";
+ githubId = 44469426;
+ name = "Zoey de Souza Pessanha";
+ email = "zoey.spessanha@outlook.com";
+ keys = [{
+ longkeyid = "rsa4096/0x1E1E889CDBD6A315";
+ fingerprint = "EAA1 51DB 472B 0122 109A CB17 1E1E 889C DBD6 A315";
+ }];
+ };
zombiezen = {
name = "Ross Light";
email = "ross@zombiezen.com";
@@ -13769,6 +14210,12 @@
github = "jpagex";
githubId = 635768;
};
+ vbrandl = {
+ name = "Valentin Brandl";
+ email = "mail+nixpkgs@vbrandl.net";
+ github = "vbrandl";
+ githubId = 20639051;
+ };
portothree = {
name = "Gustavo Porto";
email = "gustavoporto@ya.ru";
@@ -13792,4 +14239,16 @@
fingerprint = "3586 3350 BFEA C101 DB1A 4AF0 1F81 112D 62A9 ADCE";
}];
};
+ ameer = {
+ name = "Ameer Taweel";
+ email = "ameertaweel2002@gmail.com";
+ github = "AmeerTaweel";
+ githubId = 20538273;
+ };
+ nigelgbanks = {
+ name = "Nigel Banks";
+ email = "nigel.g.banks@gmail.com";
+ github = "nigelgbanks";
+ githubId = 487373;
+ };
}
diff --git a/maintainers/scripts/haskell/regenerate-hackage-packages.sh b/maintainers/scripts/haskell/regenerate-hackage-packages.sh
index 285f6ed7cf94..9d51eb4ca4af 100755
--- a/maintainers/scripts/haskell/regenerate-hackage-packages.sh
+++ b/maintainers/scripts/haskell/regenerate-hackage-packages.sh
@@ -20,7 +20,7 @@ HACKAGE2NIX="${HACKAGE2NIX:-hackage2nix}"
# See: https://github.com/NixOS/nixpkgs/pull/122023
export LC_ALL=C.UTF-8
-extraction_derivation='with import ./. {}; runCommand "unpacked-cabal-hashes" { } "tar xf ${all-cabal-hashes} --strip-components=1 --one-top-level=$out"'
+extraction_derivation='with import ./. {}; runCommandLocal "unpacked-cabal-hashes" { } "tar xf ${all-cabal-hashes} --strip-components=1 --one-top-level=$out"'
unpacked_hackage="$(nix-build -E "$extraction_derivation" --no-out-link)"
config_dir=pkgs/development/haskell-modules/configuration-hackage2nix
diff --git a/maintainers/scripts/luarocks-packages.csv b/maintainers/scripts/luarocks-packages.csv
index 23303d22c471..bdda8020a3da 100644
--- a/maintainers/scripts/luarocks-packages.csv
+++ b/maintainers/scripts/luarocks-packages.csv
@@ -68,7 +68,7 @@ luautf8,,,,,,pstn
luazip,,,,,,
lua-yajl,,,,,,pstn
luuid,,,,,,
-luv,,,,1.42.0-0,,
+luv,,,,1.43.0-0,,
lyaml,,,,,,lblasc
markdown,,,,,,
mediator_lua,,,,,,
@@ -81,6 +81,6 @@ rapidjson,https://github.com/xpol/lua-rapidjson.git,,,,,
readline,,,,,,
say,https://github.com/Olivine-Labs/say.git,,,,,
std._debug,https://github.com/lua-stdlib/_debug.git,,,,,
-std.normalize,git://github.com/lua-stdlib/normalize.git,,,,,
+std.normalize,https://github.com/lua-stdlib/normalize.git,,,,,
stdlib,,,,41.2.2,,vyp
vstruct,https://github.com/ToxicFrog/vstruct.git,,,,,
diff --git a/maintainers/scripts/pluginupdate.py b/maintainers/scripts/pluginupdate.py
index de85b88da3fd..017e3ac758ac 100644
--- a/maintainers/scripts/pluginupdate.py
+++ b/maintainers/scripts/pluginupdate.py
@@ -1,4 +1,4 @@
-# Used by pkgs/misc/vim-plugins/update.py and pkgs/applications/editors/kakoune/plugins/update.py
+# Used by pkgs/applications/editors/vim/plugins/update.py and pkgs/applications/editors/kakoune/plugins/update.py
# format:
# $ nix run nixpkgs.python3Packages.black -c black update.py
@@ -73,9 +73,13 @@ def retry(ExceptionToCheck: Any, tries: int = 4, delay: float = 3, backoff: floa
return deco_retry
+@dataclass
+class FetchConfig:
+ proc: int
+ github_token: str
-def make_request(url: str) -> urllib.request.Request:
- token = os.getenv("GITHUB_API_TOKEN")
+
+def make_request(url: str, token=None) -> urllib.request.Request:
headers = {}
if token is not None:
headers["Authorization"] = f"token {token}"
@@ -90,6 +94,7 @@ class Repo:
self.branch = branch
self.alias = alias
self.redirect: Dict[str, str] = {}
+ self.token = "dummy_token"
@property
def name(self):
@@ -132,10 +137,11 @@ class Repo:
class RepoGitHub(Repo):
def __init__(
- self, owner: str, repo: str, branch: str, alias: Optional[str]
+ self, owner: str, repo: str, branch: str, alias: Optional[str]
) -> None:
self.owner = owner
self.repo = repo
+ self.token = None
'''Url to the repo'''
super().__init__(self.url(""), branch, alias)
log.debug("Instantiating github repo %s/%s", self.owner, self.repo)
@@ -150,7 +156,7 @@ class RepoGitHub(Repo):
@retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
def has_submodules(self) -> bool:
try:
- req = make_request(self.url(f"blob/{self.branch}/.gitmodules"))
+ req = make_request(self.url(f"blob/{self.branch}/.gitmodules"), self.token)
urllib.request.urlopen(req, timeout=10).close()
except urllib.error.HTTPError as e:
if e.code == 404:
@@ -162,7 +168,7 @@ class RepoGitHub(Repo):
@retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
def latest_commit(self) -> Tuple[str, datetime]:
commit_url = self.url(f"commits/{self.branch}.atom")
- commit_req = make_request(commit_url)
+ commit_req = make_request(commit_url, self.token)
with urllib.request.urlopen(commit_req, timeout=10) as req:
self._check_for_redirect(commit_url, req)
xml = req.read()
@@ -291,15 +297,41 @@ class Editor:
"""To fill the cache"""
return get_current_plugins(self)
- def load_plugin_spec(self, plugin_file) -> List[PluginDesc]:
- return load_plugin_spec(plugin_file)
+ def load_plugin_spec(self, config: FetchConfig, plugin_file) -> List[PluginDesc]:
+ plugins = []
+ with open(plugin_file) as f:
+ for line in f:
+ if line.startswith("#"):
+ continue
+ plugin = parse_plugin_line(config, line)
+ plugins.append(plugin)
+ return plugins
def generate_nix(self, plugins, outfile: str):
'''Returns nothing for now, writes directly to outfile'''
raise NotImplementedError()
- def get_update(self, input_file: str, outfile: str, proc: int):
- return get_update(input_file, outfile, proc, editor=self)
+ def get_update(self, input_file: str, outfile: str, config: FetchConfig):
+ cache: Cache = Cache(self.get_current_plugins(), self.cache_file)
+ _prefetch = functools.partial(prefetch, cache=cache)
+
+ def update() -> dict:
+ plugin_names = self.load_plugin_spec(config, input_file)
+
+ try:
+ pool = Pool(processes=config.proc)
+ results = pool.map(_prefetch, plugin_names)
+ finally:
+ cache.store()
+
+ plugins, redirects = check_results(results)
+
+ self.generate_nix(plugins, outfile)
+
+ return redirects
+
+ return update
+
@property
def attr_path(self):
@@ -345,7 +377,15 @@ class Editor:
dest="proc",
type=int,
default=30,
- help="Number of concurrent processes to spawn. Export GITHUB_API_TOKEN allows higher values.",
+ help="Number of concurrent processes to spawn. Setting --github-token allows higher values.",
+ )
+ parser.add_argument(
+ "--github-token",
+ "-t",
+ type=str,
+ default=os.getenv("GITHUB_API_TOKEN"),
+ help="""Allows to set --proc to higher values.
+ Uses GITHUB_API_TOKEN environment variables as the default value.""",
)
parser.add_argument(
"--no-commit", "-n", action="store_true", default=False,
@@ -414,8 +454,8 @@ def prefetch_plugin(
)
-def fetch_plugin_from_pluginline(plugin_line: str) -> Plugin:
- plugin, _ = prefetch_plugin(parse_plugin_line(plugin_line))
+def fetch_plugin_from_pluginline(config: FetchConfig, plugin_line: str) -> Plugin:
+ plugin, _ = prefetch_plugin(parse_plugin_line(config, plugin_line))
return plugin
@@ -465,7 +505,7 @@ def make_repo(uri, branch, alias) -> Repo:
repo = Repo(uri.strip(), branch, alias)
return repo
-def parse_plugin_line(line: str) -> PluginDesc:
+def parse_plugin_line(config: FetchConfig, line: str) -> PluginDesc:
branch = "HEAD"
alias = None
uri = line
@@ -476,21 +516,11 @@ def parse_plugin_line(line: str) -> PluginDesc:
uri, branch = uri.split("@")
repo = make_repo(uri.strip(), branch.strip(), alias)
+ repo.token = config.github_token
return PluginDesc(repo, branch.strip(), alias)
-def load_plugin_spec(plugin_file: str) -> List[PluginDesc]:
- plugins = []
- with open(plugin_file) as f:
- for line in f:
- if line.startswith("#"):
- continue
- plugin = parse_plugin_line(line)
- plugins.append(plugin)
- return plugins
-
-
def get_cache_path(cache_file_name: str) -> Optional[Path]:
xdg_cache = os.environ.get("XDG_CACHE_HOME", None)
if xdg_cache is None:
@@ -556,6 +586,7 @@ def prefetch(
def rewrite_input(
+ config: FetchConfig,
input_file: Path,
deprecated: Path,
redirects: Dict[str, str] = None,
@@ -573,8 +604,8 @@ def rewrite_input(
with open(deprecated, "r") as f:
deprecations = json.load(f)
for old, new in redirects.items():
- old_plugin = fetch_plugin_from_pluginline(old)
- new_plugin = fetch_plugin_from_pluginline(new)
+ old_plugin = fetch_plugin_from_pluginline(config, old)
+ new_plugin = fetch_plugin_from_pluginline(config, new)
if old_plugin.normalized_name != new_plugin.normalized_name:
deprecations[old_plugin.normalized_name] = {
"new": new_plugin.normalized_name,
@@ -600,40 +631,21 @@ def commit(repo: git.Repo, message: str, files: List[Path]) -> None:
print("no changes in working tree to commit")
-def get_update(input_file: str, outfile: str, proc: int, editor: Editor):
- cache: Cache = Cache(editor.get_current_plugins(), editor.cache_file)
- _prefetch = functools.partial(prefetch, cache=cache)
-
- def update() -> dict:
- plugin_names = editor.load_plugin_spec(input_file)
-
- try:
- pool = Pool(processes=proc)
- results = pool.map(_prefetch, plugin_names)
- finally:
- cache.store()
-
- plugins, redirects = check_results(results)
-
- editor.generate_nix(plugins, outfile)
-
- return redirects
-
- return update
-
def update_plugins(editor: Editor, args):
"""The main entry function of this module. All input arguments are grouped in the `Editor`."""
log.setLevel(LOG_LEVELS[args.debug])
log.info("Start updating plugins")
- update = editor.get_update(args.input_file, args.outfile, args.proc)
+ fetch_config = FetchConfig(args.proc, args.github_token)
+ update = editor.get_update(args.input_file, args.outfile, fetch_config)
redirects = update()
- editor.rewrite_input(args.input_file, editor.deprecated, redirects)
+ editor.rewrite_input(fetch_config, args.input_file, editor.deprecated, redirects)
autocommit = not args.no_commit
+ nixpkgs_repo = None
if autocommit:
nixpkgs_repo = git.Repo(editor.root, search_parent_directories=True)
commit(nixpkgs_repo, f"{editor.attr_path}: update", [args.outfile])
@@ -648,9 +660,9 @@ def update_plugins(editor: Editor, args):
)
for plugin_line in args.add_plugins:
- editor.rewrite_input(args.input_file, editor.deprecated, append=(plugin_line + "\n",))
+ editor.rewrite_input(fetch_config, args.input_file, editor.deprecated, append=(plugin_line + "\n",))
update()
- plugin = fetch_plugin_from_pluginline(plugin_line)
+ plugin = fetch_plugin_from_pluginline(fetch_config, plugin_line)
if autocommit:
commit(
nixpkgs_repo,
diff --git a/maintainers/scripts/remove-old-aliases.py b/maintainers/scripts/remove-old-aliases.py
new file mode 100755
index 000000000000..c5629c829594
--- /dev/null
+++ b/maintainers/scripts/remove-old-aliases.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p "python3.withPackages(ps: with ps; [ ])" nix
+"""
+A program to remove old aliases or convert old aliases to throws
+Example usage:
+./maintainers/scripts/remove-old-aliases.py --year 2018 --file ./pkgs/top-level/aliases.nix
+
+Check this file with mypy after every change!
+$ mypy --strict maintainers/scripts/remove-old-aliases.py
+"""
+import argparse
+import shutil
+import subprocess
+from datetime import date as datetimedate
+from datetime import datetime
+from pathlib import Path
+
+
+def process_args() -> argparse.Namespace:
+ """process args"""
+ arg_parser = argparse.ArgumentParser()
+ arg_parser.add_argument(
+ "--year", required=True, type=int, help="operate on aliases older than $year"
+ )
+ arg_parser.add_argument(
+ "--month",
+ type=int,
+ default=1,
+ help="operate on aliases older than $year-$month",
+ )
+ arg_parser.add_argument(
+ "--only-throws",
+ action="store_true",
+ help="only operate on throws. e.g remove throws older than $date",
+ )
+ arg_parser.add_argument("--file", required=True, type=Path, help="alias file")
+ arg_parser.add_argument(
+ "--dry-run", action="store_true", help="don't modify files, only print results"
+ )
+ return arg_parser.parse_args()
+
+
+def get_date_lists(
+ txt: list[str], cutoffdate: datetimedate, only_throws: bool
+) -> tuple[list[str], list[str], list[str]]:
+ """get a list of lines in which the date is older than $cutoffdate"""
+ date_older_list: list[str] = []
+ date_older_throw_list: list[str] = []
+ date_sep_line_list: list[str] = []
+
+ for lineno, line in enumerate(txt, start=1):
+ line = line.rstrip()
+ my_date = None
+ for string in line.split():
+ string = string.strip(":")
+ try:
+ # strip ':' incase there is a string like 2019-11-01:
+ my_date = datetime.strptime(string, "%Y-%m-%d").date()
+ except ValueError:
+ try:
+ my_date = datetime.strptime(string, "%Y-%m").date()
+ except ValueError:
+ continue
+
+ if (
+ my_date is None
+ or my_date > cutoffdate
+ or "preserve, reason:" in line.lower()
+ ):
+ continue
+
+ if "=" not in line:
+ date_sep_line_list.append(f"{lineno} {line}")
+ # 'if' lines could be complicated
+ elif "if " in line and "if =" not in line:
+ print(f"RESOLVE MANUALLY {line}")
+ elif "throw" in line:
+ date_older_throw_list.append(line)
+ elif not only_throws:
+ date_older_list.append(line)
+
+ return (
+ date_older_list,
+ date_sep_line_list,
+ date_older_throw_list,
+ )
+
+
+def convert_to_throw(date_older_list: list[str]) -> list[tuple[str, str]]:
+ """convert a list of lines to throws"""
+ converted_list = []
+ for line in date_older_list.copy():
+ indent: str = " " * (len(line) - len(line.lstrip()))
+ before_equal = ""
+ after_equal = ""
+ try:
+ before_equal, after_equal = (x.strip() for x in line.split("=", maxsplit=2))
+ except ValueError as err:
+ print(err, line, "\n")
+ date_older_list.remove(line)
+ continue
+
+ alias = before_equal.strip()
+ after_equal_list = [x.strip(";:") for x in after_equal.split()]
+
+ converted = (
+ f"{indent}{alias} = throw \"'{alias}' has been renamed to/replaced by"
+ f" '{after_equal_list.pop(0)}'\";"
+ f' # Converted to throw {datetime.today().strftime("%Y-%m-%d")}'
+ )
+ converted_list.append((line, converted))
+
+ return converted_list
+
+
+def generate_text_to_write(
+ txt: list[str],
+ date_older_list: list[str],
+ converted_to_throw: list[tuple[str, str]],
+ date_older_throw_list: list[str],
+) -> list[str]:
+ """generate a list of text to be written to the aliasfile"""
+ text_to_write: list[str] = []
+ for line in txt:
+ text_to_append: str = ""
+ if converted_to_throw:
+ for tupl in converted_to_throw:
+ if line == tupl[0]:
+ text_to_append = f"{tupl[1]}\n"
+ if line not in date_older_list and line not in date_older_throw_list:
+ text_to_append = f"{line}\n"
+ if text_to_append:
+ text_to_write.append(text_to_append)
+
+ return text_to_write
+
+
+def write_file(
+ aliasfile: Path,
+ text_to_write: list[str],
+) -> None:
+ """write file"""
+ temp_aliasfile = Path(f"{aliasfile}.raliases")
+ with open(temp_aliasfile, "w", encoding="utf-8") as far:
+ for line in text_to_write:
+ far.write(line)
+ print("\nChecking the syntax of the new aliasfile")
+ try:
+ subprocess.run(
+ ["nix-instantiate", "--eval", temp_aliasfile],
+ check=True,
+ stdout=subprocess.DEVNULL,
+ )
+ except subprocess.CalledProcessError:
+ print(
+ "\nSyntax check failed,",
+ "there may have been a line which only has\n"
+ 'aliasname = "reason why";\n'
+ "when it should have been\n"
+ 'aliasname = throw "reason why";',
+ )
+ temp_aliasfile.unlink()
+ return
+ shutil.move(f"{aliasfile}.raliases", aliasfile)
+ print(f"{aliasfile} modified! please verify with 'git diff'.")
+
+
+def main() -> None:
+ """main"""
+ args = process_args()
+
+ only_throws = args.only_throws
+ aliasfile = Path(args.file).absolute()
+ cutoffdate = (datetime.strptime(f"{args.year}-{args.month}-01", "%Y-%m-%d")).date()
+
+ txt: list[str] = (aliasfile.read_text(encoding="utf-8")).splitlines()
+
+ date_older_list: list[str] = []
+ date_sep_line_list: list[str] = []
+ date_older_throw_list: list[str] = []
+
+ date_older_list, date_sep_line_list, date_older_throw_list = get_date_lists(
+ txt, cutoffdate, only_throws
+ )
+
+ converted_to_throw: list[tuple[str, str]] = []
+ if date_older_list:
+ converted_to_throw = convert_to_throw(date_older_list)
+ print(" Will be converted to throws. ".center(100, "-"))
+ for l_n in date_older_list:
+ print(l_n)
+
+ if date_older_throw_list:
+ print(" Will be removed. ".center(100, "-"))
+ for l_n in date_older_throw_list:
+ print(l_n)
+
+ if date_sep_line_list:
+ print(" On separate line, resolve manually. ".center(100, "-"))
+ for l_n in date_sep_line_list:
+ print(l_n)
+
+ if not args.dry_run:
+ text_to_write = generate_text_to_write(
+ txt, date_older_list, converted_to_throw, date_older_throw_list
+ )
+ write_file(aliasfile, text_to_write)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/maintainers/scripts/update-luarocks-packages b/maintainers/scripts/update-luarocks-packages
index c559d5699dff..73a233c5f103 100755
--- a/maintainers/scripts/update-luarocks-packages
+++ b/maintainers/scripts/update-luarocks-packages
@@ -25,8 +25,8 @@ from pathlib import Path
log = logging.getLogger()
log.addHandler(logging.StreamHandler())
-ROOT = Path(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))).parent.parent
-from pluginupdate import Editor, update_plugins, PluginDesc, CleanEnvironment, LOG_LEVELS, Cache
+ROOT = Path(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))).parent.parent # type: ignore
+from pluginupdate import Editor, update_plugins, FetchConfig, CleanEnvironment
PKG_LIST="maintainers/scripts/luarocks-packages.csv"
TMP_FILE="$(mktemp)"
@@ -118,7 +118,7 @@ class LuaEditor(Editor):
def attr_path(self):
return "luaPackages"
- def get_update(self, input_file: str, outfile: str, proc: int):
+ def get_update(self, input_file: str, outfile: str, config: FetchConfig):
_prefetch = generate_pkg_nix
def update() -> dict:
@@ -126,14 +126,14 @@ class LuaEditor(Editor):
sorted_plugin_specs = sorted(plugin_specs, key=lambda v: v.name.lower())
try:
- pool = Pool(processes=proc)
+ pool = Pool(processes=config.proc)
results = pool.map(_prefetch, sorted_plugin_specs)
finally:
pass
self.generate_nix(results, outfile)
- redirects = []
+ redirects = {}
return redirects
return update
@@ -181,11 +181,9 @@ def generate_pkg_nix(plug: LuaPlugin):
cmd.append(plug.version)
- #
if plug.server != "src" and plug.server:
cmd.append(f"--only-server={plug.server}")
-
if plug.luaversion:
with CleanEnvironment():
local_pkgs = str(ROOT.resolve())
@@ -209,7 +207,6 @@ def main():
parser = editor.create_parser()
args = parser.parse_args()
- log.setLevel(LOG_LEVELS[args.debug])
update_plugins(editor, args)
diff --git a/maintainers/scripts/update.nix b/maintainers/scripts/update.nix
index d881d68301ba..1a2f06c73a2c 100755
--- a/maintainers/scripts/update.nix
+++ b/maintainers/scripts/update.nix
@@ -147,7 +147,7 @@ let
to run update script for specific package, or
- % nix-shell maintainers/scripts/update.nix --arg predicate '(path: pkg: builtins.isList pkg.updateScript && builtins.length pkg.updateScript >= 1 && (let script = builtins.head pkg.updateScript; in builtins.isAttrs script && script.name == "gnome-update-script"))'
+ % nix-shell maintainers/scripts/update.nix --arg predicate '(path: pkg: pkg.updateScript.name or null == "gnome-update-script")'
to run update script for all packages matching given predicate, or
diff --git a/maintainers/scripts/update.py b/maintainers/scripts/update.py
index 06b12a0ee04e..07e0b5c68305 100644
--- a/maintainers/scripts/update.py
+++ b/maintainers/scripts/update.py
@@ -88,6 +88,10 @@ async def commit_changes(name: str, merge_lock: asyncio.Lock, worktree: str, bra
async with merge_lock:
await check_subprocess('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)
diff --git a/maintainers/team-list.nix b/maintainers/team-list.nix
index 361be88045f1..66cba166f2ca 100644
--- a/maintainers/team-list.nix
+++ b/maintainers/team-list.nix
@@ -50,6 +50,7 @@ with lib.maintainers; {
DianaOlympos
gleber
happysalada
+ minijackson
yurrriq
];
scope = "Maintain BEAM-related packages and modules.";
@@ -64,7 +65,6 @@ with lib.maintainers; {
chia = {
members = [
- atemu
lourkeur
];
scope = "Maintain the Chia blockchain and its dependencies";
@@ -117,6 +117,7 @@ with lib.maintainers; {
gnome = {
members = [
+ bobby285271
hedning
jtojnar
dasj19
@@ -214,7 +215,6 @@ with lib.maintainers; {
mguentner
ekleog
ralith
- mjlbach
dandellion
sumnerevans
];
@@ -223,7 +223,7 @@ with lib.maintainers; {
openstack = {
members = [
- angustrau
+ emilytrau
SuperSandro2000
];
scope = "Maintain the ecosystem around OpenStack";
@@ -278,6 +278,13 @@ with lib.maintainers; {
scope = "Maintain SageMath and the dependencies that are likely to break it.";
};
+ sphinx = {
+ members = [
+ SuperSandro2000
+ ];
+ scope = "Maintain Sphinx related packages.";
+ };
+
serokell = {
# Verify additions by approval of an already existing member of the team.
members = [
diff --git a/nixos/doc/manual/development/activation-script.section.md b/nixos/doc/manual/development/activation-script.section.md
new file mode 100644
index 000000000000..df6836624040
--- /dev/null
+++ b/nixos/doc/manual/development/activation-script.section.md
@@ -0,0 +1,72 @@
+# Activation script {#sec-activation-script}
+
+The activation script is a bash script called to activate the new
+configuration which resides in a NixOS system in `$out/activate`. Since its
+contents depend on your system configuration, the contents may differ.
+This chapter explains how the script works in general and some common NixOS
+snippets. Please be aware that the script is executed on every boot and system
+switch, so tasks that can be performed in other places should be performed
+there (for example letting a directory of a service be created by systemd using
+mechanisms like `StateDirectory`, `CacheDirectory`, ... or if that's not
+possible using `preStart` of the service).
+
+Activation scripts are defined as snippets using
+[](#opt-system.activationScripts). They can either be a simple multiline string
+or an attribute set that can depend on other snippets. The builder for the
+activation script will take these dependencies into account and order the
+snippets accordingly. As a simple example:
+
+```nix
+system.activationScripts.my-activation-script = {
+ deps = [ "etc" ];
+ # supportsDryActivation = true;
+ text = ''
+ echo "Hallo i bims"
+ '';
+};
+```
+
+This example creates an activation script snippet that is run after the `etc`
+snippet. The special variable `supportsDryActivation` can be set so the snippet
+is also run when `nixos-rebuild dry-activate` is run. To differentiate between
+real and dry activation, the `$NIXOS_ACTION` environment variable can be
+read which is set to `dry-activate` when a dry activation is done.
+
+An activation script can write to special files instructing
+`switch-to-configuration` to restart/reload units. The script will take these
+requests into account and will incorperate the unit configuration as described
+above. This means that the activation script will "fake" a modified unit file
+and `switch-to-configuration` will act accordingly. By doing so, configuration
+like [systemd.services.\.restartIfChanged](#opt-systemd.services) is
+respected. Since the activation script is run **after** services are already
+stopped, [systemd.services.\.stopIfChanged](#opt-systemd.services)
+cannot be taken into account anymore and the unit is always restarted instead
+of being stopped and started afterwards.
+
+The files that can be written to are `/run/nixos/activation-restart-list` and
+`/run/nixos/activation-reload-list` with their respective counterparts for
+dry activation being `/run/nixos/dry-activation-restart-list` and
+`/run/nixos/dry-activation-reload-list`. Those files can contain
+newline-separated lists of unit names where duplicates are being ignored. These
+files are not create automatically and activation scripts must take the
+possiblility into account that they have to create them first.
+
+## NixOS snippets {#sec-activation-script-nixos-snippets}
+
+There are some snippets NixOS enables by default because disabling them would
+most likely break you system. This section lists a few of them and what they
+do:
+
+- `binsh` creates `/bin/sh` which points to the runtime shell
+- `etc` sets up the contents of `/etc`, this includes systemd units and
+ excludes `/etc/passwd`, `/etc/group`, and `/etc/shadow` (which are managed by
+ the `users` snippet)
+- `hostname` sets the system's hostname in the kernel (not in `/etc`)
+- `modprobe` sets the path to the `modprobe` binary for module auto-loading
+- `nix` prepares the nix store and adds a default initial channel
+- `specialfs` is responsible for mounting filesystems like `/proc` and `sys`
+- `users` creates and removes users and groups by managing `/etc/passwd`,
+ `/etc/group` and `/etc/shadow`. This also creates home directories
+- `usrbinenv` creates `/usr/bin/env`
+- `var` creates some directories in `/var` that are not service-specific
+- `wrappers` creates setuid wrappers like `ping` and `sudo`
diff --git a/nixos/doc/manual/development/development.xml b/nixos/doc/manual/development/development.xml
index 0b2ad60a878b..21286cdbd2b4 100644
--- a/nixos/doc/manual/development/development.xml
+++ b/nixos/doc/manual/development/development.xml
@@ -12,6 +12,7 @@
+
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md
index fff06e1ea5ba..53ecb9b3a624 100644
--- a/nixos/doc/manual/development/option-declarations.section.md
+++ b/nixos/doc/manual/development/option-declarations.section.md
@@ -27,9 +27,10 @@ The function `mkOption` accepts the following arguments.
`type`
-: The type of the option (see [](#sec-option-types)). It may be
- omitted, but that's not advisable since it may lead to errors that
- are hard to diagnose.
+: The type of the option (see [](#sec-option-types)). This
+ argument is mandatory for nixpkgs modules. Setting this is highly
+ recommended for the sake of documentation and type checking. In case it is
+ not set, a fallback type with unspecified behavior is used.
`default`
@@ -145,26 +146,26 @@ As an example, we will take the case of display managers. There is a
central display manager module for generic display manager options and a
module file per display manager backend (sddm, gdm \...).
-There are two approach to this module structure:
+There are two approaches we could take with this module structure:
-- Managing the display managers independently by adding an enable
+- Configuring the display managers independently by adding an enable
option to every display manager module backend. (NixOS)
-- Managing the display managers in the central module by adding an
- option to select which display manager backend to use.
+- Configuring the display managers in the central module by adding
+ an option to select which display manager backend to use.
Both approaches have problems.
Making backends independent can quickly become hard to manage. For
-display managers, there can be only one enabled at a time, but the type
-system can not enforce this restriction as there is no relation between
-each backend `enable` option. As a result, this restriction has to be
-done explicitely by adding assertions in each display manager backend
-module.
+display managers, there can only be one enabled at a time, but the
+type system cannot enforce this restriction as there is no relation
+between each backend's `enable` option. As a result, this restriction
+has to be done explicitly by adding assertions in each display manager
+backend module.
-On the other hand, managing the display managers backends in the central
-module will require to change the central module option every time a new
-backend is added or removed.
+On the other hand, managing the display manager backends in the
+central module will require changing the central module option every
+time a new backend is added or removed.
By using extensible option types, it is possible to create a placeholder
option in the central module
@@ -175,7 +176,7 @@ and to extend it in each backend module
As a result, `displayManager.enable` option values can be added without
changing the main service module file and the type system automatically
-enforce that there can only be a single display manager enabled.
+enforces that there can only be a single display manager enabled.
::: {#ex-option-declaration-eot-service .example}
::: {.title}
diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md
index 56ffa8e9d79c..00f1d85bdb61 100644
--- a/nixos/doc/manual/development/option-types.section.md
+++ b/nixos/doc/manual/development/option-types.section.md
@@ -16,13 +16,14 @@ merging is handled.
`types.path`
-: A filesystem path, defined as anything that when coerced to a string
- starts with a slash. Even if derivations can be considered as path,
- the more specific `types.package` should be preferred.
+: A filesystem path is anything that starts with a slash when
+ coerced to a string. Even if derivations can be considered as
+ paths, the more specific `types.package` should be preferred.
`types.package`
-: A derivation or a store path.
+: A top-level store path. This can be an attribute set pointing
+ to a store path, like a derivation or a flake input.
`types.anything`
@@ -63,6 +64,24 @@ merging is handled.
```
:::
+`types.raw`
+
+: A type which doesn't do any checking, merging or nested evaluation. It
+ accepts a single arbitrary value that is not recursed into, making it
+ useful for values coming from outside the module system, such as package
+ sets or arbitrary data. Options of this type are still evaluated according
+ to priorities and conditionals, so `mkForce`, `mkIf` and co. still work on
+ the option value itself, but not for any value nested within it. This type
+ should only be used when checking, merging and nested evaluation are not
+ desirable.
+
+`types.optionType`
+
+: The type of an option's type. Its merging operation ensures that nested
+ options have the correct file location annotated, and that if possible,
+ multiple option definitions are correctly merged together. The main use
+ case is as the type of the `_module.freeformType` option.
+
`types.attrs`
: A free-form attribute set.
diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
index 4c399586eb52..a1431859ff59 100644
--- a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
+++ b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md
@@ -5,7 +5,7 @@ when developing or debugging a test:
```ShellSession
$ nix-build . -A nixosTests.login.driverInteractive
-$ ./result/bin/nixos-test-driver --interactive
+$ ./result/bin/nixos-test-driver
[...]
>>>
```
@@ -28,7 +28,7 @@ You can re-use the VM states coming from a previous run by setting the
`--keep-vm-state` flag.
```ShellSession
-$ ./result/bin/nixos-test-driver --interactive --keep-vm-state
+$ ./result/bin/nixos-test-driver --keep-vm-state
```
The machine state is stored in the `$TMPDIR/vm-state-machinename`
diff --git a/nixos/doc/manual/development/running-nixos-tests.section.md b/nixos/doc/manual/development/running-nixos-tests.section.md
index d6a456f01883..1bec023b613a 100644
--- a/nixos/doc/manual/development/running-nixos-tests.section.md
+++ b/nixos/doc/manual/development/running-nixos-tests.section.md
@@ -24,8 +24,8 @@ After building/downloading all required dependencies, this will perform
a build that starts a QEMU/KVM virtual machine containing a NixOS
system. The virtual machine mounts the Nix store of the host; this makes
VM creation very fast, as no disk image needs to be created. Afterwards,
-you can view a pretty-printed log of the test:
+you can view a log of the test:
```ShellSession
-$ firefox result/log.html
+$ nix-store --read-log result
```
diff --git a/nixos/doc/manual/development/settings-options.section.md b/nixos/doc/manual/development/settings-options.section.md
index 58a3d8448af5..f9bb6ff9cc41 100644
--- a/nixos/doc/manual/development/settings-options.section.md
+++ b/nixos/doc/manual/development/settings-options.section.md
@@ -66,6 +66,45 @@ have a predefined type and string generator already declared under
and returning a set with TOML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
+`pkgs.formats.elixirConf { elixir ? pkgs.elixir }`
+
+: A function taking an attribute set with values
+
+ `elixir`
+
+ : The Elixir package which will be used to format the generated output
+
+ It returns a set with Elixir-Config-specific attributes `type`, `lib`, and
+ `generate` as specified [below](#pkgs-formats-result).
+
+ The `lib` attribute contains functions to be used in settings, for
+ generating special Elixir values:
+
+ `mkRaw elixirCode`
+
+ : Outputs the given string as raw Elixir code
+
+ `mkGetEnv { envVariable, fallback ? null }`
+
+ : Makes the configuration fetch an environment variable at runtime
+
+ `mkAtom atom`
+
+ : Outputs the given string as an Elixir atom, instead of the default
+ Elixir binary string. Note: lowercase atoms still needs to be prefixed
+ with `:`
+
+ `mkTuple array`
+
+ : Outputs the given array as an Elixir tuple, instead of the default
+ Elixir list
+
+ `mkMap attrset`
+
+ : Outputs the given attribute set as an Elixir map, instead of the
+ default Elixir keyword list
+
+
::: {#pkgs-formats-result}
These functions all return an attribute set with these values:
:::
@@ -74,6 +113,12 @@ These functions all return an attribute set with these values:
: A module system type representing a value of the format
+`lib`
+
+: Utility functions for convenience, or special interactions with the format.
+ This attribute is optional. It may contain inside a `types` attribute
+ containing types specific to this format.
+
`generate` *`filename jsonValue`*
: A function that can render a value of the format to a file. Returns
diff --git a/nixos/doc/manual/development/unit-handling.section.md b/nixos/doc/manual/development/unit-handling.section.md
new file mode 100644
index 000000000000..a7ccb3dbd042
--- /dev/null
+++ b/nixos/doc/manual/development/unit-handling.section.md
@@ -0,0 +1,62 @@
+# Unit handling {#sec-unit-handling}
+
+To figure out what units need to be started/stopped/restarted/reloaded, the
+script first checks the current state of the system, similar to what `systemctl
+list-units` shows. For each of the units, the script goes through the following
+checks:
+
+- Is the unit file still in the new system? If not, **stop** the service unless
+ it sets `X-StopOnRemoval` in the `[Unit]` section to `false`.
+
+- Is it a `.target` unit? If so, **start** it unless it sets
+ `RefuseManualStart` in the `[Unit]` section to `true` or `X-OnlyManualStart`
+ in the `[Unit]` section to `true`. Also **stop** the unit again unless it
+ sets `X-StopOnReconfiguration` to `false`.
+
+- Are the contents of the unit files different? They are compared by parsing
+ them and comparing their contents. If they are different but only
+ `X-Reload-Triggers` in the `[Unit]` section is changed, **reload** the unit.
+ The NixOS module system allows setting these triggers with the option
+ [systemd.services.\.reloadTriggers](#opt-systemd.services). There are
+ some additional keys in the `[Unit]` section that are ignored as well. If the
+ unit files differ in any way, the following actions are performed:
+
+ - `.path` and `.slice` units are ignored. There is no need to restart them
+ since changes in their values are applied by systemd when systemd is
+ reloaded.
+
+ - `.mount` units are **reload**ed. These mostly come from the `/etc/fstab`
+ parser.
+
+ - `.socket` units are currently ignored. This is to be fixed at a later
+ point.
+
+ - The rest of the units (mostly `.service` units) are then **reload**ed if
+ `X-ReloadIfChanged` in the `[Service]` section is set to `true` (exposed
+ via [systemd.services.\.reloadIfChanged](#opt-systemd.services)).
+ A little exception is done for units that were deactivated in the meantime,
+ for example because they require a unit that got stopped before. These
+ are **start**ed instead of reloaded.
+
+ - If the reload flag is not set, some more flags decide if the unit is
+ skipped. These flags are `X-RestartIfChanged` in the `[Service]` section
+ (exposed via
+ [systemd.services.\.restartIfChanged](#opt-systemd.services)),
+ `RefuseManualStop` in the `[Unit]` section, and `X-OnlyManualStart` in the
+ `[Unit]` section.
+
+ - Further behavior depends on the unit having `X-StopIfChanged` in the
+ `[Service]` section set to `true` (exposed via
+ [systemd.services.\.stopIfChanged](#opt-systemd.services)). This is
+ set to `true` by default and must be explicitly turned off if not wanted.
+ If the flag is enabled, the unit is **stop**ped and then **start**ed. If
+ not, the unit is **restart**ed. The goal of the flag is to make sure that
+ the new unit never runs in the old environment which is still in place
+ before the activation script is run. This behavior is different when the
+ service is socket-activated, as outlined in the following steps.
+
+ - The last thing that is taken into account is whether the unit is a service
+ and socket-activated. If `X-StopIfChanged` is **not** set, the service
+ is **restart**ed with the others. If it is set, both the service and the
+ socket are **stop**ped and the socket is **start**ed, leaving socket
+ activation to start the service when it's needed.
diff --git a/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md b/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md
new file mode 100644
index 000000000000..aad82831a3c2
--- /dev/null
+++ b/nixos/doc/manual/development/what-happens-during-a-system-switch.chapter.md
@@ -0,0 +1,53 @@
+# What happens during a system switch? {#sec-switching-systems}
+
+Running `nixos-rebuild switch` is one of the more common tasks under NixOS.
+This chapter explains some of the internals of this command to make it simpler
+for new module developers to configure their units correctly and to make it
+easier to understand what is happening and why for curious administrators.
+
+`nixos-rebuild`, like many deployment solutions, calls `switch-to-configuration`
+which resides in a NixOS system at `$out/bin/switch-to-configuration`. The
+script is called with the action that is to be performed like `switch`, `test`,
+`boot`. There is also the `dry-activate` action which does not really perform
+the actions but rather prints what it would do if you called it with `test`.
+This feature can be used to check what service states would be changed if the
+configuration was switched to.
+
+If the action is `switch` or `boot`, the bootloader is updated first so the
+configuration will be the next one to boot. Unless `NIXOS_NO_SYNC` is set to
+`1`, `/nix/store` is synced to disk.
+
+If the action is `switch` or `test`, the currently running system is inspected
+and the actions to switch to the new system are calculated. This process takes
+two data sources into account: `/etc/fstab` and the current systemd status.
+Mounts and swaps are read from `/etc/fstab` and the corresponding actions are
+generated. If a new mount is added, for example, the proper `.mount` unit is
+marked to be started. The current systemd state is inspected, the difference
+between the current system and the desired configuration is calculated and
+actions are generated to get to this state. There are a lot of nuances that can
+be controlled by the units which are explained here.
+
+After calculating what should be done, the actions are carried out. The order
+of actions is always the same:
+- Stop units (`systemctl stop`)
+- Run activation script (`$out/activate`)
+- See if the activation script requested more units to restart
+- Restart systemd if needed (`systemd daemon-reexec`)
+- Forget about the failed state of units (`systemctl reset-failed`)
+- Reload systemd (`systemctl daemon-reload`)
+- Reload systemd user instances (`systemctl --user daemon-reload`)
+- Set up tmpfiles (`systemd-tmpfiles --create`)
+- Reload units (`systemctl reload`)
+- Restart units (`systemctl restart`)
+- Start units (`systemctl start`)
+- Inspect what changed during these actions and print units that failed and
+ that were newly started
+
+Most of these actions are either self-explaining but some of them have to do
+with our units or the activation script. For this reason, these topics are
+explained in the next sections.
+
+```{=docbook}
+
+
+```
diff --git a/nixos/doc/manual/development/writing-modules.chapter.md b/nixos/doc/manual/development/writing-modules.chapter.md
index 2e3c6b34f1f5..0c41cbd3cb75 100644
--- a/nixos/doc/manual/development/writing-modules.chapter.md
+++ b/nixos/doc/manual/development/writing-modules.chapter.md
@@ -90,6 +90,17 @@ modules: `systemd.services` (the set of all systemd services) and
`systemd.timers` (the list of commands to be executed periodically by
`systemd`).
+Care must be taken when writing systemd services using `Exec*` directives. By
+default systemd performs substitution on `%` specifiers in these
+directives, expands environment variables from `$FOO` and `${FOO}`, splits
+arguments on whitespace, and splits commands on `;`. All of these must be escaped
+to avoid unexpected substitution or splitting when interpolating into an `Exec*`
+directive, e.g. when using an `extraArgs` option to pass additional arguments to
+the service. The functions `utils.escapeSystemdExecArg` and
+`utils.escapeSystemdExecArgs` are provided for this, see [Example: Escaping in
+Exec directives](#exec-escaping-example) for an example. When using these
+functions system environment substitution should *not* be disabled explicitly.
+
::: {#locate-example .example}
::: {.title}
**Example: NixOS Module for the "locate" Service**
@@ -153,6 +164,37 @@ in {
```
:::
+::: {#exec-escaping-example .example}
+::: {.title}
+**Example: Escaping in Exec directives**
+:::
+```nix
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+ cfg = config.services.echo;
+ echoAll = pkgs.writeScript "echo-all" ''
+ #! ${pkgs.runtimeShell}
+ for s in "$@"; do
+ printf '%s\n' "$s"
+ done
+ '';
+ args = [ "a%Nything" "lang=\${LANG}" ";" "/bin/sh -c date" ];
+in {
+ systemd.services.echo =
+ { description = "Echo to the journal";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig.Type = "oneshot";
+ serviceConfig.ExecStart = ''
+ ${echoAll} ${utils.escapeSystemdExecArgs args}
+ '';
+ };
+}
+```
+:::
+
```{=docbook}
diff --git a/nixos/doc/manual/development/writing-nixos-tests.section.md b/nixos/doc/manual/development/writing-nixos-tests.section.md
index 7de57d0d2a37..433e1906f775 100644
--- a/nixos/doc/manual/development/writing-nixos-tests.section.md
+++ b/nixos/doc/manual/development/writing-nixos-tests.section.md
@@ -158,6 +158,12 @@ The following methods are available on machine objects:
e.g., `send_chars("foobar\n")` will type the string `foobar`
followed by the Enter key.
+`send_console`
+
+: Send keys to the kernel console. This allows interaction with the systemd
+ emergency mode, for example. Takes a string that is sent, e.g.,
+ `send_console("\n\nsystemctl default\n")`.
+
`execute`
: Execute a shell command, returning a list `(status, stdout)`.
@@ -272,6 +278,13 @@ The following methods are available on machine objects:
Killing the interactive session with `Ctrl-d` or `Ctrl-c` also ends
the guest session.
+`console_interact`
+
+: Allows you to directly interact with QEMU's stdin. This should
+ only be used during test development, not in production tests.
+ Output from QEMU is only read line-wise. `Ctrl-c` kills QEMU and
+ `Ctrl-d` closes console and returns to the test runner.
+
To test user units declared by `systemd.user.services` the optional
`user` argument can be used:
diff --git a/nixos/doc/manual/from_md/development/activation-script.section.xml b/nixos/doc/manual/from_md/development/activation-script.section.xml
new file mode 100644
index 000000000000..0d9e911216ef
--- /dev/null
+++ b/nixos/doc/manual/from_md/development/activation-script.section.xml
@@ -0,0 +1,150 @@
+
+ Activation script
+
+ The activation script is a bash script called to activate the new
+ configuration which resides in a NixOS system in
+ $out/activate. Since its contents depend on your
+ system configuration, the contents may differ. This chapter explains
+ how the script works in general and some common NixOS snippets.
+ Please be aware that the script is executed on every boot and system
+ switch, so tasks that can be performed in other places should be
+ performed there (for example letting a directory of a service be
+ created by systemd using mechanisms like
+ StateDirectory,
+ CacheDirectory, … or if that’s not possible using
+ preStart of the service).
+
+
+ Activation scripts are defined as snippets using
+ . They can either be
+ a simple multiline string or an attribute set that can depend on
+ other snippets. The builder for the activation script will take
+ these dependencies into account and order the snippets accordingly.
+ As a simple example:
+
+
+system.activationScripts.my-activation-script = {
+ deps = [ "etc" ];
+ # supportsDryActivation = true;
+ text = ''
+ echo "Hallo i bims"
+ '';
+};
+
+
+ This example creates an activation script snippet that is run after
+ the etc snippet. The special variable
+ supportsDryActivation can be set so the snippet
+ is also run when nixos-rebuild dry-activate is
+ run. To differentiate between real and dry activation, the
+ $NIXOS_ACTION environment variable can be read
+ which is set to dry-activate when a dry
+ activation is done.
+
+
+ An activation script can write to special files instructing
+ switch-to-configuration to restart/reload units.
+ The script will take these requests into account and will
+ incorperate the unit configuration as described above. This means
+ that the activation script will fake
a modified unit
+ file and switch-to-configuration will act
+ accordingly. By doing so, configuration like
+ systemd.services.<name>.restartIfChanged
+ is respected. Since the activation script is run
+ after services are already
+ stopped,
+ systemd.services.<name>.stopIfChanged
+ cannot be taken into account anymore and the unit is always
+ restarted instead of being stopped and started afterwards.
+
+
+ The files that can be written to are
+ /run/nixos/activation-restart-list and
+ /run/nixos/activation-reload-list with their
+ respective counterparts for dry activation being
+ /run/nixos/dry-activation-restart-list and
+ /run/nixos/dry-activation-reload-list. Those
+ files can contain newline-separated lists of unit names where
+ duplicates are being ignored. These files are not create
+ automatically and activation scripts must take the possiblility into
+ account that they have to create them first.
+
+
+ NixOS snippets
+
+ There are some snippets NixOS enables by default because disabling
+ them would most likely break you system. This section lists a few
+ of them and what they do:
+
+
+
+
+ binsh creates /bin/sh
+ which points to the runtime shell
+
+
+
+
+ etc sets up the contents of
+ /etc, this includes systemd units and
+ excludes /etc/passwd,
+ /etc/group, and
+ /etc/shadow (which are managed by the
+ users snippet)
+
+
+
+
+ hostname sets the system’s hostname in the
+ kernel (not in /etc)
+
+
+
+
+ modprobe sets the path to the
+ modprobe binary for module auto-loading
+
+
+
+
+ nix prepares the nix store and adds a
+ default initial channel
+
+
+
+
+ specialfs is responsible for mounting
+ filesystems like /proc and
+ sys
+
+
+
+
+ users creates and removes users and groups
+ by managing /etc/passwd,
+ /etc/group and
+ /etc/shadow. This also creates home
+ directories
+
+
+
+
+ usrbinenv creates
+ /usr/bin/env
+
+
+
+
+ var creates some directories in
+ /var that are not service-specific
+
+
+
+
+ wrappers creates setuid wrappers like
+ ping and sudo
+
+
+
+
+
diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml
index 0eeffae628e1..0ac5e0eeca2d 100644
--- a/nixos/doc/manual/from_md/development/option-declarations.section.xml
+++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml
@@ -38,9 +38,11 @@ options = {
The type of the option (see
- ). It may be omitted, but
- that’s not advisable since it may lead to errors that are hard
- to diagnose.
+ ). This argument is
+ mandatory for nixpkgs modules. Setting this is highly
+ recommended for the sake of documentation and type checking.
+ In case it is not set, a fallback type with unspecified
+ behavior is used.
@@ -215,21 +217,22 @@ lib.mkOption {
manager backend (sddm, gdm ...).
- There are two approach to this module structure:
+ There are two approaches we could take with this module
+ structure:
- Managing the display managers independently by adding an
- enable option to every display manager module backend.
- (NixOS)
+ Configuring the display managers independently by adding
+ an enable option to every display manager module
+ backend. (NixOS)
- Managing the display managers in the central module by
- adding an option to select which display manager backend
- to use.
+ Configuring the display managers in the central module
+ by adding an option to select which display manager
+ backend to use.
@@ -238,16 +241,16 @@ lib.mkOption {
Making backends independent can quickly become hard to
- manage. For display managers, there can be only one enabled
- at a time, but the type system can not enforce this
- restriction as there is no relation between each backend
+ manage. For display managers, there can only be one enabled
+ at a time, but the type system cannot enforce this
+ restriction as there is no relation between each backend’s
enable option. As a result, this
- restriction has to be done explicitely by adding assertions
+ restriction has to be done explicitly by adding assertions
in each display manager backend module.
- On the other hand, managing the display managers backends in
- the central module will require to change the central module
+ On the other hand, managing the display manager backends in
+ the central module will require changing the central module
option every time a new backend is added or removed.
@@ -268,7 +271,7 @@ lib.mkOption {
As a result, displayManager.enable option
values can be added without changing the main service module
- file and the type system automatically enforce that there
+ file and the type system automatically enforces that there
can only be a single display manager enabled.
diff --git a/nixos/doc/manual/from_md/development/option-types.section.xml b/nixos/doc/manual/from_md/development/option-types.section.xml
index 76ffb6f837c3..444729292702 100644
--- a/nixos/doc/manual/from_md/development/option-types.section.xml
+++ b/nixos/doc/manual/from_md/development/option-types.section.xml
@@ -30,10 +30,10 @@
- A filesystem path, defined as anything that when coerced to
- a string starts with a slash. Even if derivations can be
- considered as path, the more specific
- types.package should be preferred.
+ A filesystem path is anything that starts with a slash when
+ coerced to a string. Even if derivations can be considered
+ as paths, the more specific types.package
+ should be preferred.
@@ -43,7 +43,9 @@
- A derivation or a store path.
+ A top-level store path. This can be an attribute set
+ pointing to a store path, like a derivation or a flake
+ input.
@@ -92,6 +94,39 @@
+
+
+ types.raw
+
+
+
+ A type which doesn’t do any checking, merging or nested
+ evaluation. It accepts a single arbitrary value that is not
+ recursed into, making it useful for values coming from
+ outside the module system, such as package sets or arbitrary
+ data. Options of this type are still evaluated according to
+ priorities and conditionals, so mkForce,
+ mkIf and co. still work on the option
+ value itself, but not for any value nested within it. This
+ type should only be used when checking, merging and nested
+ evaluation are not desirable.
+
+
+
+
+
+ types.optionType
+
+
+
+ The type of an option’s type. Its merging operation ensures
+ that nested options have the correct file location
+ annotated, and that if possible, multiple option definitions
+ are correctly merged together. The main use case is as the
+ type of the _module.freeformType option.
+
+
+
types.attrs
diff --git a/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml b/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
index 8348ab56deb3..0e47350a0d24 100644
--- a/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
+++ b/nixos/doc/manual/from_md/development/running-nixos-tests-interactively.section.xml
@@ -6,7 +6,7 @@
$ nix-build . -A nixosTests.login.driverInteractive
-$ ./result/bin/nixos-test-driver --interactive
+$ ./result/bin/nixos-test-driver
[...]
>>>
@@ -30,7 +30,7 @@ $ ./result/bin/nixos-test-driver --interactive
the --keep-vm-state flag.
-$ ./result/bin/nixos-test-driver --interactive --keep-vm-state
+$ ./result/bin/nixos-test-driver --keep-vm-state
The machine state is stored in the
diff --git a/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml b/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml
index 7159b95b22b0..da2e5076c956 100644
--- a/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml
+++ b/nixos/doc/manual/from_md/development/running-nixos-tests.section.xml
@@ -26,9 +26,9 @@ machine: QEMU running (pid 8841)
perform a build that starts a QEMU/KVM virtual machine containing a
NixOS system. The virtual machine mounts the Nix store of the host;
this makes VM creation very fast, as no disk image needs to be
- created. Afterwards, you can view a pretty-printed log of the test:
+ created. Afterwards, you can view a log of the test:
-$ firefox result/log.html
+$ nix-store --read-log result
diff --git a/nixos/doc/manual/from_md/development/settings-options.section.xml b/nixos/doc/manual/from_md/development/settings-options.section.xml
index c9430b77579c..746011a2d075 100644
--- a/nixos/doc/manual/from_md/development/settings-options.section.xml
+++ b/nixos/doc/manual/from_md/development/settings-options.section.xml
@@ -137,6 +137,97 @@
+
+
+ pkgs.formats.elixirConf { elixir ? pkgs.elixir }
+
+
+
+ A function taking an attribute set with values
+
+
+
+
+ elixir
+
+
+
+ The Elixir package which will be used to format the
+ generated output
+
+
+
+
+
+ It returns a set with Elixir-Config-specific attributes
+ type, lib, and
+ generate as specified
+ below.
+
+
+ The lib attribute contains functions to
+ be used in settings, for generating special Elixir values:
+
+
+
+
+ mkRaw elixirCode
+
+
+
+ Outputs the given string as raw Elixir code
+
+
+
+
+
+ mkGetEnv { envVariable, fallback ? null }
+
+
+
+ Makes the configuration fetch an environment variable
+ at runtime
+
+
+
+
+
+ mkAtom atom
+
+
+
+ Outputs the given string as an Elixir atom, instead of
+ the default Elixir binary string. Note: lowercase
+ atoms still needs to be prefixed with
+ :
+
+
+
+
+
+ mkTuple array
+
+
+
+ Outputs the given array as an Elixir tuple, instead of
+ the default Elixir list
+
+
+
+
+
+ mkMap attrset
+
+
+
+ Outputs the given attribute set as an Elixir map,
+ instead of the default Elixir keyword list
+
+
+
+
+
+
These functions all return an attribute set with these values:
@@ -152,6 +243,19 @@
+
+
+ lib
+
+
+
+ Utility functions for convenience, or special interactions
+ with the format. This attribute is optional. It may contain
+ inside a types attribute containing types
+ specific to this format.
+
+
+
generate
diff --git a/nixos/doc/manual/from_md/development/unit-handling.section.xml b/nixos/doc/manual/from_md/development/unit-handling.section.xml
new file mode 100644
index 000000000000..4c980e1213a8
--- /dev/null
+++ b/nixos/doc/manual/from_md/development/unit-handling.section.xml
@@ -0,0 +1,131 @@
+
+ Unit handling
+
+ To figure out what units need to be
+ started/stopped/restarted/reloaded, the script first checks the
+ current state of the system, similar to what
+ systemctl list-units shows. For each of the
+ units, the script goes through the following checks:
+
+
+
+
+ Is the unit file still in the new system? If not,
+ stop the service unless it
+ sets X-StopOnRemoval in the
+ [Unit] section to false.
+
+
+
+
+ Is it a .target unit? If so,
+ start it unless it sets
+ RefuseManualStart in the
+ [Unit] section to true or
+ X-OnlyManualStart in the
+ [Unit] section to true.
+ Also stop the unit again
+ unless it sets X-StopOnReconfiguration to
+ false.
+
+
+
+
+ Are the contents of the unit files different? They are compared
+ by parsing them and comparing their contents. If they are
+ different but only X-Reload-Triggers in the
+ [Unit] section is changed,
+ reload the unit. The NixOS
+ module system allows setting these triggers with the option
+ systemd.services.<name>.reloadTriggers.
+ There are some additional keys in the [Unit]
+ section that are ignored as well. If the unit files differ in
+ any way, the following actions are performed:
+
+
+
+
+ .path and .slice units
+ are ignored. There is no need to restart them since changes
+ in their values are applied by systemd when systemd is
+ reloaded.
+
+
+
+
+ .mount units are
+ reloaded. These mostly
+ come from the /etc/fstab parser.
+
+
+
+
+ .socket units are currently ignored. This
+ is to be fixed at a later point.
+
+
+
+
+ The rest of the units (mostly .service
+ units) are then reloaded
+ if X-ReloadIfChanged in the
+ [Service] section is set to
+ true (exposed via
+ systemd.services.<name>.reloadIfChanged).
+ A little exception is done for units that were deactivated
+ in the meantime, for example because they require a unit
+ that got stopped before. These are
+ started instead of
+ reloaded.
+
+
+
+
+ If the reload flag is not set, some more flags decide if the
+ unit is skipped. These flags are
+ X-RestartIfChanged in the
+ [Service] section (exposed via
+ systemd.services.<name>.restartIfChanged),
+ RefuseManualStop in the
+ [Unit] section, and
+ X-OnlyManualStart in the
+ [Unit] section.
+
+
+
+
+ Further behavior depends on the unit having
+ X-StopIfChanged in the
+ [Service] section set to
+ true (exposed via
+ systemd.services.<name>.stopIfChanged).
+ This is set to true by default and must
+ be explicitly turned off if not wanted. If the flag is
+ enabled, the unit is
+ stopped and then
+ started. If not, the unit
+ is restarted. The goal of
+ the flag is to make sure that the new unit never runs in the
+ old environment which is still in place before the
+ activation script is run. This behavior is different when
+ the service is socket-activated, as outlined in the
+ following steps.
+
+
+
+
+ The last thing that is taken into account is whether the
+ unit is a service and socket-activated. If
+ X-StopIfChanged is
+ not set, the service is
+ restarted with the
+ others. If it is set, both the service and the socket are
+ stopped and the socket is
+ started, leaving socket
+ activation to start the service when it’s needed.
+
+
+
+
+
+
diff --git a/nixos/doc/manual/from_md/development/what-happens-during-a-system-switch.chapter.xml b/nixos/doc/manual/from_md/development/what-happens-during-a-system-switch.chapter.xml
new file mode 100644
index 000000000000..66ba792ddacb
--- /dev/null
+++ b/nixos/doc/manual/from_md/development/what-happens-during-a-system-switch.chapter.xml
@@ -0,0 +1,122 @@
+
+ What happens during a system switch?
+
+ Running nixos-rebuild switch is one of the more
+ common tasks under NixOS. This chapter explains some of the
+ internals of this command to make it simpler for new module
+ developers to configure their units correctly and to make it easier
+ to understand what is happening and why for curious administrators.
+
+
+ nixos-rebuild, like many deployment solutions,
+ calls switch-to-configuration which resides in a
+ NixOS system at $out/bin/switch-to-configuration.
+ The script is called with the action that is to be performed like
+ switch, test,
+ boot. There is also the
+ dry-activate action which does not really perform
+ the actions but rather prints what it would do if you called it with
+ test. This feature can be used to check what
+ service states would be changed if the configuration was switched
+ to.
+
+
+ If the action is switch or
+ boot, the bootloader is updated first so the
+ configuration will be the next one to boot. Unless
+ NIXOS_NO_SYNC is set to 1,
+ /nix/store is synced to disk.
+
+
+ If the action is switch or
+ test, the currently running system is inspected
+ and the actions to switch to the new system are calculated. This
+ process takes two data sources into account:
+ /etc/fstab and the current systemd status. Mounts
+ and swaps are read from /etc/fstab and the
+ corresponding actions are generated. If a new mount is added, for
+ example, the proper .mount unit is marked to be
+ started. The current systemd state is inspected, the difference
+ between the current system and the desired configuration is
+ calculated and actions are generated to get to this state. There are
+ a lot of nuances that can be controlled by the units which are
+ explained here.
+
+
+ After calculating what should be done, the actions are carried out.
+ The order of actions is always the same:
+
+
+
+
+ Stop units (systemctl stop)
+
+
+
+
+ Run activation script ($out/activate)
+
+
+
+
+ See if the activation script requested more units to restart
+
+
+
+
+ Restart systemd if needed
+ (systemd daemon-reexec)
+
+
+
+
+ Forget about the failed state of units
+ (systemctl reset-failed)
+
+
+
+
+ Reload systemd (systemctl daemon-reload)
+
+
+
+
+ Reload systemd user instances
+ (systemctl --user daemon-reload)
+
+
+
+
+ Set up tmpfiles (systemd-tmpfiles --create)
+
+
+
+
+ Reload units (systemctl reload)
+
+
+
+
+ Restart units (systemctl restart)
+
+
+
+
+ Start units (systemctl start)
+
+
+
+
+ Inspect what changed during these actions and print units that
+ failed and that were newly started
+
+
+
+
+ Most of these actions are either self-explaining but some of them
+ have to do with our units or the activation script. For this reason,
+ these topics are explained in the next sections.
+
+
+
+
diff --git a/nixos/doc/manual/from_md/development/writing-modules.chapter.xml b/nixos/doc/manual/from_md/development/writing-modules.chapter.xml
index e33c24f4f12c..367731eda090 100644
--- a/nixos/doc/manual/from_md/development/writing-modules.chapter.xml
+++ b/nixos/doc/manual/from_md/development/writing-modules.chapter.xml
@@ -122,6 +122,25 @@
services) and systemd.timers (the list of
commands to be executed periodically by systemd).
+
+ Care must be taken when writing systemd services using
+ Exec* directives. By default systemd performs
+ substitution on %<char> specifiers in these
+ directives, expands environment variables from
+ $FOO and ${FOO}, splits
+ arguments on whitespace, and splits commands on
+ ;. All of these must be escaped to avoid
+ unexpected substitution or splitting when interpolating into an
+ Exec* directive, e.g. when using an
+ extraArgs option to pass additional arguments to
+ the service. The functions
+ utils.escapeSystemdExecArg and
+ utils.escapeSystemdExecArgs are provided for
+ this, see Example: Escaping in
+ Exec directives for an example. When using these functions
+ system environment substitution should not be
+ disabled explicitly.
+
Example: NixOS Module for the
@@ -183,6 +202,36 @@ in {
};
};
}
+
+
+
+ Example: Escaping in Exec
+ directives
+
+
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+ cfg = config.services.echo;
+ echoAll = pkgs.writeScript "echo-all" ''
+ #! ${pkgs.runtimeShell}
+ for s in "$@"; do
+ printf '%s\n' "$s"
+ done
+ '';
+ args = [ "a%Nything" "lang=\${LANG}" ";" "/bin/sh -c date" ];
+in {
+ systemd.services.echo =
+ { description = "Echo to the journal";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig.Type = "oneshot";
+ serviceConfig.ExecStart = ''
+ ${echoAll} ${utils.escapeSystemdExecArgs args}
+ '';
+ };
+}
diff --git a/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml b/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml
index 45c9c40c6095..4f856f98f2a2 100644
--- a/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml
+++ b/nixos/doc/manual/from_md/development/writing-nixos-tests.section.xml
@@ -261,6 +261,19 @@ start_all()
+
+
+ send_console
+
+
+
+ Send keys to the kernel console. This allows interaction
+ with the systemd emergency mode, for example. Takes a string
+ that is sent, e.g.,
+ send_console("\n\nsystemctl default\n").
+
+
+
execute
@@ -502,6 +515,21 @@ machine.systemctl("list-jobs --no-pager", "any-user") # spaw
+
+
+ console_interact
+
+
+
+ Allows you to directly interact with QEMU’s stdin. This
+ should only be used during test development, not in
+ production tests. Output from QEMU is only read line-wise.
+ Ctrl-c kills QEMU and
+ Ctrl-d closes console and returns to the
+ test runner.
+
+
+
To test user units declared by
diff --git a/nixos/doc/manual/from_md/installation/installing-pxe.section.xml b/nixos/doc/manual/from_md/installation/installing-pxe.section.xml
index 1dd15ddacba8..94172de65ea0 100644
--- a/nixos/doc/manual/from_md/installation/installing-pxe.section.xml
+++ b/nixos/doc/manual/from_md/installation/installing-pxe.section.xml
@@ -7,11 +7,11 @@
These instructions assume that you have an existing PXE or iPXE
infrastructure and simply want to add the NixOS installer as another
- option. To build the necessary files from a recent version of
+ option. To build the necessary files from your current version of
nixpkgs, you can run:
-nix-build -A netboot.x86_64-linux nixos/release.nix
+nix-build -A netboot.x86_64-linux '<nixpkgs/nixos/release.nix>'
This will create a result directory containing: *
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
index 59da373f38e1..b61a0268dee2 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
@@ -26,8 +26,36 @@
- iptables now uses
- nf_tables backend.
+ iptables is now using
+ nf_tables under the hood, by using
+ iptables-nft, similar to
+ Debian
+ and
+ Fedora.
+ This means, ip[6]tables,
+ arptables and ebtables
+ commands will actually show rules from some specific tables in
+ the nf_tables kernel subsystem. In case
+ you’re migrating from an older release without rebooting,
+ there might be cases where you end up with iptable rules
+ configured both in the legacy iptables
+ kernel backend, as well as in the nf_tables
+ backend. This can lead to confusing firewall behaviour. An
+ iptables-save after switching will complain
+ about iptables-legacy tables present
. It’s
+ probably best to reboot after the upgrade, or manually
+ removing all legacy iptables rules (via the
+ iptables-legacy package).
+
+
+
+
+ systemd got an nftables backend, and
+ configures (networkd) rules in their own
+ io.systemd.* tables. Check
+ nft list ruleset to see these rules, not
+ iptables-save (which only shows
+ iptables-created rules.
@@ -1429,6 +1457,17 @@ Superuser created successfully.
knob.
+
+
+ /usr will always be included in the initial
+ ramdisk. See the
+ fileSystems.<name>.neededForBoot
+ option. If any files exist under /usr
+ (which is not typical for NixOS), they will be included in the
+ initial ramdisk, increasing its size to a possibly problematic
+ extent.
+
+
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 436157515ebe..0c5b3b4fec76 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -15,6 +15,14 @@
Highlights
+
+
+ The firefox browser on
+ x86_64-linux is now making use of
+ profile-guided optimization resulting in a much more
+ responsive browsing experience.
+
+
security.acme.defaults has been added to
@@ -25,6 +33,16 @@
services.nginx.virtualHosts.*.enableACME).
+
+
+ GNOME has been upgraded to 42. Please take a look at their
+ Release
+ Notes for details. Notably, it replaces gedit with
+ GNOME Text Editor, GNOME Terminal with GNOME Console (formerly
+ King’s Cross), and GNOME Screenshot with a tool built into the
+ Shell.
+
+
PHP 8.1 is now available
@@ -42,6 +60,34 @@
upgrade notes.
+
+
+ systemd services can now set
+ systemd.services.<name>.reloadTriggers
+ instead of reloadIfChanged for a more
+ granular distinction between reloads and restarts.
+
+
+
+
+ kops
+ defaults to 1.22.4, which will enable
+ Instance
+ Metadata Service Version 2 and require tokens on new
+ clusters with Kubernetes 1.22. This will increase security by
+ default, but may break some types of workloads. See the
+ release
+ notes for details.
+
+
+
+
+ Module authors can use
+ mkRenamedOptionModuleWith to automate the
+ deprecation cycle without annoying out-of-tree module authors
+ and their users.
+
+
@@ -79,12 +125,18 @@
services.filebeat.
+
+
+ apfs,
+ a kernel module for mounting the Apple File System (APFS).
+
+
FRRouting, a
popular suite of Internet routing protocol daemons (BGP, BFD,
- OSPF, IS-IS, VVRP and others). Available as
- services.frr
+ OSPF, IS-IS, VRRP and others). Available as
+ services.frr
@@ -94,6 +146,13 @@
services.heisenbridge.
+
+
+ snowflake-proxy,
+ a system to defeat internet censorship. Available as
+ services.snowflake-proxy.
+
+
ergochat, a modern
@@ -108,6 +167,21 @@
services.powerdns-admin.
+
+
+ pgadmin4,
+ an admin interface for the PostgreSQL database. Available at
+ services.pgadmin.
+
+
+
+
+ input-remapper,
+ an easy to use tool to change the mapping of your input device
+ buttons. Available at
+ services.input-remapper.
+
+
InvoicePlane,
@@ -123,6 +197,15 @@
services.maddy.
+
+
+ K40-Whisperer,
+ a program to control cheap Chinese laser cutters. Available as
+ programs.k40-whisperer.enable.
+ Users must add themselves to the k40 group
+ to be able to access the device.
+
+
mtr-exporter,
@@ -130,6 +213,14 @@
services.mtr-exporter.
+
+
+ prometheus-pve-exporter,
+ a tool that exposes information from the Proxmox VE API for
+ use by Prometheus. Available as
+ services.prometheus.exporters.pve.
+
+
tetrd, share your
@@ -138,6 +229,14 @@
services.tetrd.
+
+
+ agate,
+ a very simple server for the Gemini hypertext protocol.
+ Available as
+ services.agate.
+
+
ArchiSteamFarm,
@@ -162,6 +261,13 @@
services.baget.
+
+
+ moosefs, fault
+ tolerant petabyte distributed file system. Available as
+ moosefs.
+
+
prosody-filer,
@@ -169,6 +275,38 @@
services.prosody-filer.
+
+
+ systembus-notify,
+ allow system level notifications to reach the users. Available
+ as
+ services.systembus-notify.
+ Please keep in mind that this service should only be enabled
+ on machines with fully trusted users, as any local user is
+ able to DoS user sessions by spamming notifications.
+
+
+
+
+ ethercalc,
+ an online collaborative spreadsheet. Available as
+ services.ethercalc.
+
+
+
+
+ nbd, a
+ Network Block Device server. Available as
+ services.nbd.
+
+
+
+
+ nix-ld,
+ Run unpatched dynamic binaries on NixOS. Available as
+ programs.nix-ld.
+
+
timetagger,
@@ -185,6 +323,28 @@
services.rstudio-server.
+
+
+ headscale,
+ an Open Source implementation of the
+ Tailscale
+ Control Server. Available as
+ services.headscale
+
+
+
+
+ blocky,
+ fast and lightweight DNS proxy as ad-blocker for local network
+ with many features.
+
+
+
+
+ pacemaker
+ cluster resource manager
+
+
@@ -211,6 +371,36 @@
haskellPackages.callPackage).
+
+
+ pkgs.ghc.withPackages as well as
+ haskellPackages.ghcWithPackages etc. now
+ needs be overridden directly, as opposed to overriding the
+ result of calling it. Additionally, the
+ withLLVM parameter has been renamed to
+ useLLVM. So instead of
+ (ghc.withPackages (p: [])).override { withLLVM = true; },
+ one needs to use
+ (ghc.withPackages.override { useLLVM = true; }) (p: []).
+
+
+
+
+ The home-assistant module now requires
+ users that don’t want their configuration to be managed
+ declaratively to set
+ services.home-assistant.config = null;.
+ This is required due to the way default settings are handled
+ with the new settings style.
+
+
+ Additionally the default list of
+ extraComponents now includes the minimal
+ dependencies to successfully complete the
+ onboarding
+ procedure.
+
+
pkgs.emacsPackages.orgPackages is removed
@@ -228,6 +418,66 @@
removed due to it being an outdated version.
+
+
+ services.kubernetes.scheduler.{port,address}
+ now set --secure-port and
+ --bind-address instead of
+ --port and --address,
+ since the former have been deprecated and are no longer
+ functional in kubernetes>=1.23. Ensure that you are not
+ relying on the insecure behaviour before upgrading.
+
+
+
+
+ services.k3s.enable no longer implies
+ systemd.enableUnifiedCgroupHierarchy = false,
+ and will default to the systemd
cgroup driver
+ when using services.k3s.docker = true. This
+ change may require a reboot to take effect, and k3s may not be
+ able to run if the boot cgroup hierarchy does not match its
+ configuration. The previous behavior may be retained by
+ explicitly setting
+ systemd.enableUnifiedCgroupHierarchy = false
+ in your configuration.
+
+
+
+
+ fonts.fonts no longer includes ancient
+ bitmap fonts when both
+ config.services.xserver.enable and
+ config.nixpkgs.config.allowUnfree are
+ enabled. If you still want these fonts, use:
+
+
+{
+ fonts.fonts = [
+ pkgs.xorg.fontbhlucidatypewriter100dpi
+ pkgs.xorg.fontbhlucidatypewriter75dpi
+ pkgs.xorg.fontbh100dpi
+ ];
+}
+
+
+
+
+ The DHCP server (services.dhcpd4,
+ services.dhcpd6) has been hardened. The
+ service is now using the systemd’s
+ DynamicUser mechanism to run as an
+ unprivileged dynamically-allocated user with limited
+ capabilities. The dhcpd state files are now always stored in
+ /var/lib/dhcpd{4,6} and the
+ services.dhcpd4.stateDir and
+ service.dhcpd6.stateDir options have been
+ removed. If you were depending on root privileges or
+ set{uid,gid,cap} binaries in dhcpd shell hooks, you may give
+ dhcpd more capabilities with e.g.
+ systemd.services.dhcpd6.serviceConfig.AmbientCapabilities.
+
+
The mailpile email webclient
@@ -235,6 +485,138 @@
its reliance on python2.
+
+
+ services.ipfs.extraFlags is now escaped
+ with utils.escapeSystemdExecArgs. If you
+ rely on systemd interpolating extraFlags in
+ the service ExecStart, this will no longer
+ work.
+
+
+
+
+ The matrix-synapse service
+ (services.matrix-synapse) has been
+ converted to use the settings option
+ defined in RFC42. This means that options that are part of
+ your homeserver.yaml configuration, and
+ that were specified at the top-level of the module
+ (services.matrix-synapse) now need to be
+ moved into
+ services.matrix-synapse.settings. And while
+ not all options you may use are defined in there, they are
+ still supported, because you can set arbitrary values in this
+ freeform type.
+
+
+ The listeners.*.bind_address option was
+ renamed to bind_addresses in order to match
+ the upstream homeserver.yaml option name.
+ It is now also a list of strings instead of a string.
+
+
+ An example to make the required migration clearer:
+
+
+ Before:
+
+
+{
+ services.matrix-synapse = {
+ enable = true;
+
+ server_name = "example.com";
+ public_baseurl = "https://example.com:8448";
+
+ enable_registration = false;
+ registration_shared_secret = "xohshaeyui8jic7uutuDogahkee3aehuaf6ei3Xouz4iicie5thie6nohNahceut";
+ macaroon_secret_key = "xoo8eder9seivukaiPh1cheikohquuw8Yooreid0The4aifahth3Ou0aiShaiz4l";
+
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+
+ listeners = [ {
+ port = 8448;
+ bind_address = "";
+ type = "http";
+ tls = true;
+ resources = [ {
+ names = [ "client" ];
+ compress = true;
+ } {
+ names = [ "federation" ];
+ compress = false;
+ } ];
+ } ];
+
+ };
+}
+
+
+ After:
+
+
+{
+ services.matrix-synapse = {
+ enable = true;
+
+ # this attribute set holds all values that go into your homeserver.yaml configuration
+ # See https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml for
+ # possible values.
+ settings = {
+ server_name = "example.com";
+ public_baseurl = "https://example.com:8448";
+
+ enable_registration = false;
+ # pass `registration_shared_secret` and `macaroon_secret_key` via `extraConfigFiles` instead
+
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+
+ listeners = [ {
+ port = 8448;
+ bind_addresses = [
+ "::"
+ "0.0.0.0"
+ ];
+ type = "http";
+ tls = true;
+ resources = [ {
+ names = [ "client" ];
+ compress = true;
+ } {
+ names = [ "federation" ];
+ compress = false;
+ } ];
+ } ];
+ };
+
+ extraConfigFiles = [
+ /run/keys/matrix-synapse/secrets.yaml
+ ];
+ };
+}
+
+
+ The secrets in your original config should be migrated into a
+ YAML file that is included via
+ extraConfigFiles.
+
+
+ Additionally a few option defaults have been synced up with
+ upstream default values, for example the
+ max_upload_size grew from
+ 10M to 50M. For the same
+ reason, the default media_store_path was
+ changed from ${dataDir}/media to
+ ${dataDir}/media_store if
+ system.stateVersion is at least
+ 22.05. Files will need to be manually moved
+ to the new location if the stateVersion is
+ updated.
+
+
The MoinMoin wiki engine
@@ -242,6 +624,25 @@
because Python 2 is being retired from nixpkgs.
+
+
+ Services in the hadoop module previously
+ set openFirewall to true by default. This
+ has now been changed to false. Node definitions for multi-node
+ clusters would need openFirewall = true; to
+ be added to to hadoop services when upgrading from NixOS
+ 21.11.
+
+
+
+
+ services.hadoop.yarn.nodemanager now uses
+ cgroup-based CPU limit enforcement by default. Additionally,
+ the option useCGroups was added to
+ nodemanagers as an easy way to switch back to the old
+ behavior.
+
+
The wafHook hook now honors
@@ -271,6 +672,39 @@
writers.writePyPy2 needs to be used.
+
+
+ buildGoModule was updated to use
+ go_1_17, third party derivations that
+ specify >= go 1.17 in the main go.mod
+ will need to regenerate their vendorSha256
+ hash.
+
+
+
+
+ The gnome-passwordsafe package updated to
+ version
+ 6.x and renamed to gnome-secrets.
+
+
+
+
+ services.gnome.experimental-features.realtime-scheduling
+ option has been removed, as GNOME Shell now
+ uses
+ rtkit. Use
+ security.rtkit.enable = true; instead. As
+ before, you will need to have it enabled using GSettings.
+
+
+
+
+ services.telepathy will no longer be
+ enabled by default for GNOME desktops, one should enable it in
+ their configs if using Empathy or Polari.
+
+
If you previously used
@@ -279,6 +713,15 @@
virtualisation.docker.daemon.settings.
+
+
+ Ntopng (services.ntopng) is updated to
+ 5.2.1 and uses a separate Redis instance if
+ system.stateVersion is at least
+ 22.05. Existing setups shouldn’t be
+ affected.
+
+
The backward compatibility in
@@ -301,6 +744,13 @@
support due to python2 deprecation in nixpkgs
+
+
+ services.miniflux.adminCredentialFiles is
+ now required, instead of defaulting to
+ admin and password.
+
+
The autorestic package has been upgraded
@@ -382,6 +832,80 @@
unmaintained
+
+
+ pkgs._7zz is now correctly licensed as
+ LGPL3+ and BSD3 with optional unfree unRAR licensed code
+
+
+
+
+ The vim.customize function produced by
+ vimUtils.makeCustomizable now has a
+ slightly different interface:
+
+
+
+
+ The wrapper now includes everything in the given Vim
+ derivation if name is
+ "vim" (the default). This
+ makes the wrapManual argument obsolete,
+ but this behavior can be overriden by setting the
+ standalone argument.
+
+
+
+
+ All the executables present in the given derivation (or,
+ in standalone mode, only the
+ *vim ones) are wrapped. This makes the
+ wrapGui argument obsolete.
+
+
+
+
+ The vimExecutableName and
+ gvimExecutableName arguments were
+ replaced by a single executableName
+ argument in which the shell variable
+ $exe can be used to refer to the
+ wrapped executable’s name.
+
+
+
+
+ See the comments in
+ pkgs/applications/editors/vim/plugins/vim-utils.nix
+ for more details.
+
+
+ vimUtils.vimWithRC was removed. You should
+ instead use customize on a Vim derivation,
+ which now accepts vimrcFile and
+ gvimrcFile arguments.
+
+
+
+
+ tilp2 was removed together with its module
+
+
+
+
+ The F-PROT antivirus (fprot package) and
+ its service module were removed because it reached
+ end-of-life.
+
+
+
+
+ bird1 and its modules
+ services.bird as well as
+ services.bird6 have been removed. Upgrade
+ to services.bird2.
+
+
The options
@@ -394,6 +918,16 @@
true.
+
+
+ The miller package has been upgraded from
+ 5.10.3 to
+ 6.2.0.
+ See
+ What’s
+ new in Miller 6.
+
+
MultiMC has been replaced with the fork PolyMC due to upstream
@@ -410,6 +944,25 @@
~/.local/share/polymc/polymc.cfg.
+
+
+ systemd-nspawn@.service settings have been
+ reverted to the default systemd behaviour. User namespaces are
+ now activated by default. If you want to keep running nspawn
+ containers without user namespaces you need to set
+ systemd.nspawn.<name>.execConfig.PrivateUsers = false
+
+
+
+
+ The Tor SOCKS proxy is now actually disabled if
+ services.tor.client.enable is set to
+ false (the default). If you are using this
+ functionality but didn’t change the setting or set it to
+ false, you now need to set it to
+ true.
+
+
The terraform 0.12 compatibility has been removed and the
@@ -428,6 +981,39 @@
directly.
+
+
+ The dendrite package has been upgraded from
+ 0.5.1 to
+ 0.6.5.
+ Instances configured with split sqlite databases, which has
+ been the default in NixOS, require merging of the federation
+ sender and signing key databases. See upstream
+ release
+ notes on version 0.6.0 for details on database changes.
+
+
+
+
+ The existing pkgs.opentelemetry-collector
+ has been moved to
+ pkgs.opentelemetry-collector-contrib to
+ match the actual source being the contrib
+ edition. pkgs.opentelemetry-collector is
+ now the actual core release of opentelemetry-collector. If you
+ use the community contributions you should change the package
+ you refer to. If you don’t need them update your commands from
+ otelcontribcol to
+ otelcorecol and enjoy a 7x smaller binary.
+
+
+
+
+ pkgs.pgadmin now refers to
+ pkgs.pgadmin4. If you still need pgadmin3,
+ use pkgs.pgadmin3.
+
+
pkgs.noto-fonts-cjk is now deprecated in
@@ -442,14 +1028,111 @@
- The interface that allows activation scripts to restart units
- has been reworked. Restarting and reloading is now done by a
- single file
- /run/nixos/activation-restart-list that
- honors restartIfChanged and
- reloadIfChanged of the units.
+ pkgs.epgstation has been upgraded from v1
+ to v2, resulting in incompatible changes in the database
+ scheme and configuration format.
+
+
+ Some top-level settings under
+ services.epgstation
+ is now deprecated because it was redudant due to the same
+ options being present in
+ services.epgstation.settings.
+
+
+
+
+ The option services.epgstation.basicAuth
+ was removed because basic authentication support was dropped
+ by upstream.
+
+
+
+
+ The option
+ services.epgstation.database.passwordFile
+ no longer has a default value. Make sure to set this option
+ explicitly before upgrading. Change the database password if
+ necessary.
+
+
+
+
+ The
+ services.epgstation.settings
+ option now expects options for config.yml
+ in EPGStation v2.
+
+
+
+
+ Existing data for the
+ services.epgstation
+ module would have to be backed up prior to the upgrade. To
+ back up exising data to
+ /tmp/epgstation.bak, run
+ sudo -u epgstation epgstation run backup /tmp/epgstation.bak.
+ To import that data after to the upgrade, run
+ sudo -u epgstation epgstation run v1migrate /tmp/epgstation.bak
+
+
+
+
+ switch-to-configuration (the script that is
+ run when running nixos-rebuild switch for
+ example) has been reworked
+
+
+
+
+ The interface that allows activation scripts to restart
+ units has been streamlined. Restarting and reloading is
+ now done by a single file
+ /run/nixos/activation-restart-list that
+ honors restartIfChanged and
+ reloadIfChanged of the units.
+
+
+
+
+ Preferring to reload instead of restarting can still
+ be achieved using
+ /run/nixos/activation-reload-list.
+
+
+
+
+
+
+ The script now uses a proper ini-file parser to parse
+ systemd units. Some values are now only searched in one
+ section instead of in the entire unit. This is only
+ relevant for units that don’t use the NixOS systemd moule.
+
+
+
+
+ RefuseManualStop,
+ X-OnlyManualStart,
+ X-StopOnRemoval,
+ X-StopOnReconfiguration are only
+ searched in the [Unit] section
+
+
+
+
+ X-ReloadIfChanged,
+ X-RestartIfChanged,
+ X-StopIfChanged are only searched
+ in the [Service] section
+
+
+
+
+
+
The services.bookstack.cacheDir option has
@@ -479,6 +1162,97 @@
wrapper for assert conditions.
+
+
+ The vpnc package has been changed to use
+ GnuTLS instead of OpenSSL by default for licensing reasons.
+
+
+
+
+ pkgs.vimPlugins.onedark-nvim now refers to
+ navarasu/onedark.nvim
+ (formerly refers to
+ olimorris/onedarkpro.nvim).
+
+
+
+
+ services.pipewire.enable will default to
+ enabling the WirePlumber session manager instead of
+ pipewire-media-session. pipewire-media-session is deprecated
+ by upstream and not recommended, but can still be manually
+ enabled by setting
+ services.pipewire.media-session.enable to
+ true and
+ services.pipewire.wireplumber.enable to
+ false.
+
+
+
+
+ pkgs.makeDesktopItem has been refactored to
+ provide a more idiomatic API. Specifically:
+
+
+
+
+ All valid options as of FDO Desktop Entry specification
+ version 1.4 can now be passed in as explicit arguments
+
+
+
+
+ exec can now be null, for entries that
+ are not of type Application
+
+
+
+
+ mimeType argument is renamed to
+ mimeTypes for consistency
+
+
+
+
+ mimeTypes,
+ categories,
+ implements,
+ keywords, onlyShowIn
+ and notShowIn take lists of strings
+ instead of one string with semicolon separators
+
+
+
+
+ extraDesktopEntries renamed to
+ extraConfig for consistency
+
+
+
+
+ Actions should now be provided as an attrset
+ actions, the Actions
+ line will be autogenerated.
+
+
+
+
+ extraEntries is removed.
+
+
+
+
+ Additional validation is added both at eval time and at
+ build time.
+
+
+
+
+ See the vscode package for a more detailed
+ example.
+
+
@@ -531,6 +1305,30 @@
was added.
+
+
+ The configuration portion of the nix-daemon
+ module has been reworked and exposed as
+ nix.settings:
+
+
+
+
+ Legacy options have been mapped to the corresponding
+ options under under
+ nix.settings
+ and will be deprecated when NixOS 21.11 reaches end of
+ life.
+
+
+
+
+ nix.buildMachines.publicHostKey
+ has been added.
+
+
+
+
The
@@ -541,6 +1339,46 @@
using the PyPy interpreter were added.
+
+
+ Some improvements have been made to the
+ hadoop module:
+
+
+
+
+ A gatewayRole option has been added,
+ for deploying hadoop cluster configuration files to a node
+ that does not have any active services
+
+
+
+
+ Support for older versions of hadoop have been added to
+ the module
+
+
+
+
+ Overriding and extending site XML files has been made
+ easier
+
+
+
+
+
+
+ If you are using Wayland you can choose to use the Ozone
+ Wayland support in Chrome and several Electron apps by setting
+ the environment variable NIXOS_OZONE_WL=1
+ (for example via
+ environment.sessionVariables.NIXOS_OZONE_WL = "1").
+ This is not enabled by default because Ozone Wayland is still
+ under heavy development and behavior is not always flawless.
+ Furthermore, not all Electron apps use the latest Electron
+ versions.
+
+
The influxdb2 package was split into
@@ -551,6 +1389,20 @@
compatibilty, but will be removed at a later date.
+
+
+ The unifi package was switched from
+ unifi6 to unifi7. Direct
+ downgrades from Unifi 7 to Unifi 6 are not possible and
+ require restoring from a backup made by Unifi 6.
+
+
+
+
+ programs.zsh.autosuggestions.strategy now
+ takes a list of strings instead of a string.
+
+
The services.unifi.openPorts option default
@@ -559,6 +1411,15 @@
using this default will print a warning when rebuilt.
+
+
+ The services.unifi-video.openPorts option
+ default value of true is now deprecated and
+ will be changed to false in 22.11.
+ Configurations using this default will print a warning when
+ rebuilt.
+
+
security.acme certificates will now
@@ -622,12 +1483,65 @@
- A new option
- boot.initrd.extraModprobeConfig has been
- added which can be used to configure kernel modules that are
- loaded in the initrd.
+ The options boot.extraModprobeConfig and
+ boot.blacklistedKernelModules now also take
+ effect in the initrd by copying the file
+ /etc/modprobe.d/nixos.conf into the initrd.
+
+
+ nixos-generate-config now puts the dhcp
+ configuration in hardware-configuration.nix
+ instead of configuration.nix.
+
+
+
+
+ ORY Kratos was updated to version 0.8.3-alpha.1.pre.0, which
+ introduces some breaking changes:
+
+
+
+
+ If you are relying on the SQLite images, update your
+ Docker Pull commands as follows:
+
+
+
+
+ docker pull oryd/kratos:{version}
+
+
+
+
+
+
+ Additionally, all passwords now have to be at least 8
+ characters long.
+
+
+
+
+ For more details, see:
+
+
+
+
+ Release
+ Notes for v0.8.1-alpha-1
+
+
+
+
+ Release
+ Notes for v0.8.2-alpha-1
+
+
+
+
+
+
fetchFromSourcehut now allows fetching
@@ -637,6 +1551,16 @@
true.
+
+
+ The element-desktop package now has an
+ useKeytar option (defaults to
+ true), which allows disabling
+ keytar and in turn
+ libsecret usage (which binds to native
+ credential managers / keychain libraries).
+
+
The option services.thelounge.plugins has
@@ -646,12 +1570,29 @@
pkgs.theLoungePlugins.themes.
+
+
+ The option
+ services.xserver.videoDriver = [ "nvidia" ];
+ will now also install
+ nvidia
+ VA-API drivers by default.
+
+
The firmwareLinuxNonfree package has been
renamed to linux-firmware.
+
+
+ It is now possible to specify wordlists to include as handy to
+ access environment variables using the
+ config.environment.wordlist configuration
+ options.
+
+
The services.mbpfan module was converted to
@@ -660,6 +1601,14 @@
0042 configuration.
+
+
+ The default value for
+ programs.spacefm.settings.graphical_su got
+ unset. It previously pointed to gksu which
+ has been removed.
+
+
A new module was added for the
@@ -669,6 +1618,12 @@
programs.starship.settings.
+
+
+ The Dino XMPP client
+ was updated to 0.3, adding support for audio and video calls.
+
+
services.mattermost.plugins has been added
@@ -676,6 +1631,13 @@
Plugins are automatically repackaged using autoPatchelf.
+
+
+ services.logrotate.enable now defaults to
+ true if any rotate path has been defined, and some paths have
+ been added by default.
+
+
The zrepl package has been updated from
@@ -712,6 +1674,96 @@
warning.
+
+
+ services.autorandr now allows for adding
+ hooks and profiles declaratively.
+
+
+
+
+ The pomerium-cli command has been moved out
+ of the pomerium package into the
+ pomerium-cli package, following upstream’s
+ repository split. If you are using the
+ pomerium-cli command, you should now
+ install the pomerium-cli package.
+
+
+
+
+ The option
+ services.networking.networkmanager.enableFccUnlock
+ was added to support FCC unlock procedures. Since release
+ 1.18.4, the ModemManager daemon no longer automatically
+ performs the FCC unlock procedure by default. See
+ the
+ docs for more details.
+
+
+
+
+ programs.tmux has a new option
+ plugins that accepts a list of packages
+ from the tmuxPlugins group. The specified
+ packages are added to the system and loaded by
+ tmux.
+
+
+
+
+ The polkit service, available at
+ security.polkit.enable, is now disabled by
+ default. It will automatically be enabled through services and
+ desktop environments as needed.
+
+
+
+
+ The hadoop package has added support for
+ aarch64-linux and
+ aarch64-darwin as of 3.3.1
+ (#158613).
+
+
+
+
+ The R package now builds again on
+ aarch64-darwin
+ (#158992).
+
+
+
+
+ The spark3 package has been updated from
+ 3.1.2 to 3.2.1
+ (#160075):
+
+
+
+
+ Testing has been enabled for
+ aarch64-linux in addition to
+ x86_64-linux.
+
+
+
+
+ The spark3 package is now usable on
+ aarch64-darwin as a result of
+ #158613
+ and
+ #158992.
+
+
+
+
+
+
+ The programs.nncp options were added for
+ generating host-global NNCP configuration.
+
+
diff --git a/nixos/doc/manual/installation/installing-pxe.section.md b/nixos/doc/manual/installation/installing-pxe.section.md
index 2016a258251f..4fbd6525f8c3 100644
--- a/nixos/doc/manual/installation/installing-pxe.section.md
+++ b/nixos/doc/manual/installation/installing-pxe.section.md
@@ -5,11 +5,11 @@ setup.
These instructions assume that you have an existing PXE or iPXE
infrastructure and simply want to add the NixOS installer as another
-option. To build the necessary files from a recent version of nixpkgs,
+option. To build the necessary files from your current version of nixpkgs,
you can run:
```ShellSession
-nix-build -A netboot.x86_64-linux nixos/release.nix
+nix-build -A netboot.x86_64-linux ''
```
This will create a `result` directory containing: \* `bzImage` -- the
diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml
index 6c7fc57f8d83..b2ca9f457a2b 100644
--- a/nixos/doc/manual/man-nixos-rebuild.xml
+++ b/nixos/doc/manual/man-nixos-rebuild.xml
@@ -91,6 +91,10 @@
flake-uri
+
+
+
+
input-name flake-uri
@@ -453,7 +457,7 @@
Allow ad-hoc remote builders for building the new system. This requires
the user executing nixos-rebuild (usually root) to be
configured as a trusted user in the Nix daemon. This can be achieved by
- using the nix.trustedUsers NixOS option. Examples
+ using the nix.settings.trusted-users NixOS option. Examples
values for that option are described in the Remote builds
chapter in the Nix manual, (i.e. --builders
"ssh://bigbrother x86_64-linux"). By specifying an empty string
@@ -594,6 +598,20 @@
+
+
+
+
+
+
+ Do not imply if
+ /etc/nixos/flake.nix exists. With this
+ option, it is possible to build non-flake NixOS configurations
+ even if the current NixOS systems uses flakes.
+
+
+
+
diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml
index 74ca57850ea5..216fea677757 100644
--- a/nixos/doc/manual/release-notes/release-notes.xml
+++ b/nixos/doc/manual/release-notes/release-notes.xml
@@ -8,6 +8,7 @@
This section lists the release notes for each stable version of NixOS and
current unstable revision.
+
diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md
index 1b59842e020b..310d32cfdd72 100644
--- a/nixos/doc/manual/release-notes/rl-2111.section.md
+++ b/nixos/doc/manual/release-notes/rl-2111.section.md
@@ -8,7 +8,22 @@ In addition to numerous new and upgraded packages, this release has the followin
- Nix has been updated to version 2.4, reference its [release notes](https://discourse.nixos.org/t/nix-2-4-released/15822) for more information on what has changed. The previous version of Nix, 2.3.16, remains available for the time being in the `nix_2_3` package.
-- `iptables` now uses `nf_tables` backend.
+- `iptables` is now using `nf_tables` under the hood, by using `iptables-nft`,
+ similar to [Debian](https://wiki.debian.org/nftables#Current_status) and
+ [Fedora](https://fedoraproject.org/wiki/Changes/iptables-nft-default).
+ This means, `ip[6]tables`, `arptables` and `ebtables` commands will actually
+ show rules from some specific tables in the `nf_tables` kernel subsystem.
+ In case you're migrating from an older release without rebooting, there might
+ be cases where you end up with iptable rules configured both in the legacy
+ `iptables` kernel backend, as well as in the `nf_tables` backend.
+ This can lead to confusing firewall behaviour. An `iptables-save` after
+ switching will complain about "iptables-legacy tables present".
+ It's probably best to reboot after the upgrade, or manually removing all
+ legacy iptables rules (via the `iptables-legacy` package).
+
+- systemd got an `nftables` backend, and configures (networkd) rules in their
+ own `io.systemd.*` tables. Check `nft list ruleset` to see these rules, not
+ `iptables-save` (which only shows `iptables`-created rules.
- PHP now defaults to PHP 8.0, updated from 7.4.
@@ -419,6 +434,9 @@ In addition to numerous new and upgraded packages, this release has the followin
- The Linux kernel for security reasons now restricts access to BPF syscalls via `BPF_UNPRIV_DEFAULT_OFF=y`. Unprivileged access can be reenabled via the `kernel.unprivileged_bpf_disabled` sysctl knob.
+- `/usr` will always be included in the initial ramdisk. See the `fileSystems..neededForBoot` option.
+ If any files exist under `/usr` (which is not typical for NixOS), they will be included in the initial ramdisk, increasing its size to a possibly problematic extent.
+
## Other Notable Changes {#sec-release-21.11-notable-changes}
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index 9d919711cb7f..7cafdcabbaaf 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -6,17 +6,29 @@ In addition to numerous new and upgraded packages, this release has the followin
## Highlights {#sec-release-22.05-highlights}
+- The `firefox` browser on `x86_64-linux` is now making use of
+ profile-guided optimization resulting in a much more responsive
+ browsing experience.
+
- `security.acme.defaults` has been added to simplify configuring
settings for many certificates at once. This also opens up the
the option to use DNS-01 validation when using `enableACME` on
web server virtual hosts (e.g. `services.nginx.virtualHosts.*.enableACME`).
+- GNOME has been upgraded to 42. Please take a look at their [Release Notes](https://release.gnome.org/42/) for details. Notably, it replaces gedit with GNOME Text Editor, GNOME Terminal with GNOME Console (formerly King’s Cross), and GNOME Screenshot with a tool built into the Shell.
+
- PHP 8.1 is now available
- Mattermost has been updated to extended support release 6.3, as the previously packaged extended support release 5.37 is [reaching its end of life](https://docs.mattermost.com/upgrade/extended-support-release.html).
Migrations may take a while, see the [changelog](https://docs.mattermost.com/install/self-managed-changelog.html#release-v6-3-extended-support-release)
and [important upgrade notes](https://docs.mattermost.com/upgrade/important-upgrade-notes.html).
+- systemd services can now set [systemd.services.\.reloadTriggers](#opt-systemd.services) instead of `reloadIfChanged` for a more granular distinction between reloads and restarts.
+
+- [`kops`](https://kops.sigs.k8s.io) defaults to 1.22.4, which will enable [Instance Metadata Service Version 2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) and require tokens on new clusters with Kubernetes 1.22. This will increase security by default, but may break some types of workloads. See the [release notes](https://kops.sigs.k8s.io/releases/1.22-notes/) for details.
+
+- Module authors can use `mkRenamedOptionModuleWith` to automate the deprecation cycle without annoying out-of-tree module authors and their users.
+
## New Services {#sec-release-22.05-new-services}
- [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable).
@@ -27,40 +39,72 @@ 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, VVRP and others). Available as [services.frr](#opt-services.ffr.babel.enable)
+- [apfs](https://github.com/linux-apfs/linux-apfs-rw), a kernel module for mounting the Apple File System (APFS).
+
+- [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)
- [heisenbridge](https://github.com/hifi/heisenbridge), a bouncer-style Matrix IRC bridge. Available as [services.heisenbridge](options.html#opt-services.heisenbridge.enable).
+- [snowflake-proxy](https://snowflake.torproject.org/), a system to defeat internet censorship. Available as [services.snowflake-proxy](options.html#opt-services.snowflake-proxy.enable).
+
- [ergochat](https://ergo.chat), a modern IRC with IRCv3 features. Available as [services.ergochat](options.html#opt-services.ergochat.enable).
- [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin), a web interface for the PowerDNS server. Available at [services.powerdns-admin](options.html#opt-services.powerdns-admin.enable).
+- [pgadmin4](https://github.com/postgres/pgadmin4), an admin interface for the PostgreSQL database. Available at [services.pgadmin](options.html#opt-services.pgadmin.enable).
+
+- [input-remapper](https://github.com/sezanzeb/input-remapper), an easy to use tool to change the mapping of your input device buttons. Available at [services.input-remapper](options.html#opt-services.input-remapper.enable).
+
- [InvoicePlane](https://invoiceplane.com), web application for managing and creating invoices. Available at [services.invoiceplane](options.html#opt-services.invoiceplane.enable).
- [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
+- [K40-Whisperer](https://www.scorchworks.com/K40whisperer/k40whisperer.html), a program to control cheap Chinese laser cutters. Available as [programs.k40-whisperer.enable](options.html#opt-programs.k4-whisperer.enable). Users must add themselves to the `k40` group to be able to access the device.
+
- [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable).
+- [prometheus-pve-exporter](https://github.com/prometheus-pve/prometheus-pve-exporter), a tool that exposes information from the Proxmox VE API for use by Prometheus. Available as [services.prometheus.exporters.pve](options.html#opt-services.prometheus.exporters.pve).
+
- [tetrd](https://tetrd.app), share your internet connection from your device to your PC and vice versa through a USB cable. Available at [services.tetrd](#opt-services.tetrd.enable).
+- [agate](https://github.com/mbrubeck/agate), a very simple server for the Gemini hypertext protocol. Available as [services.agate](options.html#opt-services.agate.enable).
+
- [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm), a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously. Available as [services.archisteamfarm](options.html#opt-services.archisteamfarm.enable).
- [teleport](https://goteleport.com), allows engineers and security professionals to unify access for SSH servers, Kubernetes clusters, web applications, and databases across all environments. Available at [services.teleport](#opt-services.teleport.enable).
- [BaGet](https://loic-sharma.github.io/BaGet/), a lightweight NuGet and symbol server. Available at [services.baget](#opt-services.baget.enable).
+- [moosefs](https://moosefs.com), fault tolerant petabyte distributed file system.
+ Available as [moosefs](#opt-services.moosefs.client.enable).
+
- [prosody-filer](https://github.com/ThomasLeister/prosody-filer), a server for handling XMPP HTTP Upload requests. Available at [services.prosody-filer](#opt-services.prosody-filer.enable).
+- [systembus-notify](https://github.com/rfjakob/systembus-notify), allow system level notifications to reach the users. Available as [services.systembus-notify](opt-services.systembus-notify.enable). Please keep in mind that this service should only be enabled on machines with fully trusted users, as any local user is able to DoS user sessions by spamming notifications.
+
+- [ethercalc](https://github.com/audreyt/ethercalc), an online collaborative
+ spreadsheet. Available as [services.ethercalc](options.html#opt-services.ethercalc.enable).
+
+- [nbd](https://nbd.sourceforge.io/), a Network Block Device server. Available as [services.nbd](options.html#opt-services.nbd.server.enable).
+
+- [nix-ld](https://github.com/Mic92/nix-ld), Run unpatched dynamic binaries on NixOS. Available as [programs.nix-ld](options.html#opt-programs.nix-ld.enable).
+
- [timetagger](https://timetagger.app), an open source time-tracker with an intuitive user experience and powerful reporting. [services.timetagger](options.html#opt-services.timetagger.enable).
- [rstudio-server](https://www.rstudio.com/products/rstudio/#rstudio-server), a browser-based version of the RStudio IDE for the R programming language. Available as [services.rstudio-server](options.html#opt-services.rstudio-server.enable).
+- [headscale](https://github.com/juanfont/headscale), an Open Source implementation of the [Tailscale](https://tailscale.io) Control Server. Available as [services.headscale](options.html#opt-services.headscale.enable)
+
+- [blocky](https://0xerr0r.github.io/blocky/), fast and lightweight DNS proxy as ad-blocker for local network with many features.
+
+- [pacemaker](https://clusterlabs.org/pacemaker/) cluster resource manager
+
## Backward Incompatibilities {#sec-release-22.05-incompatibilities}
- `pkgs.ghc` now refers to `pkgs.targetPackages.haskellPackages.ghc`.
- This *only* makes a difference if you are cross-compiling and will
+ This _only_ makes a difference if you are cross-compiling and will
ensure that `pkgs.ghc` always runs on the host platform and compiles
for the target platform (similar to `pkgs.gcc` for example).
`haskellPackages.ghc` still behaves as before, running on the build
@@ -71,6 +115,21 @@ In addition to numerous new and upgraded packages, this release has the followin
instead to ensure cross compilation keeps working (or switch to
`haskellPackages.callPackage`).
+- `pkgs.ghc.withPackages` as well as `haskellPackages.ghcWithPackages` etc.
+ now needs be overridden directly, as opposed to overriding the result of
+ calling it. Additionally, the `withLLVM` parameter has been renamed to
+ `useLLVM`. So instead of `(ghc.withPackages (p: [])).override { withLLVM = true; }`,
+ one needs to use `(ghc.withPackages.override { useLLVM = true; }) (p: [])`.
+
+- The `home-assistant` module now requires users that don't want their
+ configuration to be managed declaratively to set
+ `services.home-assistant.config = null;`. This is required
+ due to the way default settings are handled with the new settings style.
+
+ Additionally the default list of `extraComponents` now includes the minimal
+ dependencies to successfully complete the [onboarding](https://www.home-assistant.io/getting-started/onboarding/)
+ procedure.
+
- `pkgs.emacsPackages.orgPackages` is removed because org elpa is deprecated.
The packages in the top level of `pkgs.emacsPackages`, such as org and
org-contrib, refer to the ones in `pkgs.emacsPackages.elpaPackages` and
@@ -78,10 +137,138 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.kubernetes.addons.dashboard` was removed due to it being an outdated version.
+- `services.kubernetes.scheduler.{port,address}` now set `--secure-port` and `--bind-address` instead of `--port` and `--address`, since the former have been deprecated and are no longer functional in kubernetes>=1.23. Ensure that you are not relying on the insecure behaviour before upgrading.
+
+- `services.k3s.enable` no longer implies `systemd.enableUnifiedCgroupHierarchy = false`, and will default to the 'systemd' cgroup driver when using `services.k3s.docker = true`.
+ This change may require a reboot to take effect, and k3s may not be able to run if the boot cgroup hierarchy does not match its configuration.
+ The previous behavior may be retained by explicitly setting `systemd.enableUnifiedCgroupHierarchy = false` in your configuration.
+
+- `fonts.fonts` no longer includes ancient bitmap fonts when both `config.services.xserver.enable` and `config.nixpkgs.config.allowUnfree` are enabled.
+ If you still want these fonts, use:
+
+ ```nix
+ {
+ fonts.fonts = [
+ pkgs.xorg.fontbhlucidatypewriter100dpi
+ pkgs.xorg.fontbhlucidatypewriter75dpi
+ pkgs.xorg.fontbh100dpi
+ ];
+ }
+ ```
+
+- The DHCP server (`services.dhcpd4`, `services.dhcpd6`) has been hardened.
+ The service is now using the systemd's `DynamicUser` mechanism to run as an unprivileged dynamically-allocated user with limited capabilities.
+ The dhcpd state files are now always stored in `/var/lib/dhcpd{4,6}` and the `services.dhcpd4.stateDir` and `service.dhcpd6.stateDir` options have been removed.
+ If you were depending on root privileges or set{uid,gid,cap} binaries in dhcpd shell hooks, you may give dhcpd more capabilities with e.g. `systemd.services.dhcpd6.serviceConfig.AmbientCapabilities`.
+
- The `mailpile` email webclient (`services.mailpile`) has been removed due to its reliance on python2.
+- `services.ipfs.extraFlags` is now escaped with `utils.escapeSystemdExecArgs`. If you rely on systemd interpolating `extraFlags` in the service `ExecStart`, this will no longer work.
+
+- The `matrix-synapse` service (`services.matrix-synapse`) has been converted to use the `settings` option defined in RFC42.
+ This means that options that are part of your `homeserver.yaml` configuration, and that were specified at the top-level of the
+ module (`services.matrix-synapse`) now need to be moved into `services.matrix-synapse.settings`. And while not all options you
+ may use are defined in there, they are still supported, because you can set arbitrary values in this freeform type.
+
+ The `listeners.*.bind_address` option was renamed to `bind_addresses` in order to match the upstream `homeserver.yaml` option
+ name. It is now also a list of strings instead of a string.
+
+ An example to make the required migration clearer:
+
+ Before:
+ ```nix
+ {
+ services.matrix-synapse = {
+ enable = true;
+
+ server_name = "example.com";
+ public_baseurl = "https://example.com:8448";
+
+ enable_registration = false;
+ registration_shared_secret = "xohshaeyui8jic7uutuDogahkee3aehuaf6ei3Xouz4iicie5thie6nohNahceut";
+ macaroon_secret_key = "xoo8eder9seivukaiPh1cheikohquuw8Yooreid0The4aifahth3Ou0aiShaiz4l";
+
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+
+ listeners = [ {
+ port = 8448;
+ bind_address = "";
+ type = "http";
+ tls = true;
+ resources = [ {
+ names = [ "client" ];
+ compress = true;
+ } {
+ names = [ "federation" ];
+ compress = false;
+ } ];
+ } ];
+
+ };
+ }
+ ```
+
+ After:
+ ```nix
+ {
+ services.matrix-synapse = {
+ enable = true;
+
+ # this attribute set holds all values that go into your homeserver.yaml configuration
+ # See https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml for
+ # possible values.
+ settings = {
+ server_name = "example.com";
+ public_baseurl = "https://example.com:8448";
+
+ enable_registration = false;
+ # pass `registration_shared_secret` and `macaroon_secret_key` via `extraConfigFiles` instead
+
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+ tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
+
+ listeners = [ {
+ port = 8448;
+ bind_addresses = [
+ "::"
+ "0.0.0.0"
+ ];
+ type = "http";
+ tls = true;
+ resources = [ {
+ names = [ "client" ];
+ compress = true;
+ } {
+ names = [ "federation" ];
+ compress = false;
+ } ];
+ } ];
+ };
+
+ extraConfigFiles = [
+ /run/keys/matrix-synapse/secrets.yaml
+ ];
+ };
+ }
+ ```
+
+ The secrets in your original config should be migrated into a YAML file that is included via `extraConfigFiles`.
+
+ Additionally a few option defaults have been synced up with upstream default values, for example the `max_upload_size` grew from `10M` to `50M`. For the same reason, the default
+ `media_store_path` was changed from `${dataDir}/media` to `${dataDir}/media_store` if `system.stateVersion` is at least `22.05`. Files will need to be manually moved to the new
+ location if the `stateVersion` is updated.
+
- The MoinMoin wiki engine (`services.moinmoin`) has been removed, because Python 2 is being retired from nixpkgs.
+- Services in the `hadoop` module previously set `openFirewall` to true by default.
+ This has now been changed to false. Node definitions for multi-node clusters would need
+ `openFirewall = true;` to be added to to hadoop services when upgrading from NixOS 21.11.
+
+- `services.hadoop.yarn.nodemanager` now uses cgroup-based CPU limit enforcement by default.
+ Additionally, the option `useCGroups` was added to nodemanagers as an easy way to switch
+ back to the old behavior.
+
- The `wafHook` hook now honors `NIX_BUILD_CORES` when `enableParallelBuilding` is not set explicitly. Packages can restore the old behaviour by setting `enableParallelBuilding=false`.
- `pkgs.claws-mail-gtk2`, representing Claws Mail's older release version three, was removed in order to get rid of Python 2.
@@ -90,8 +277,18 @@ In addition to numerous new and upgraded packages, this release has the followin
- The `writers.writePython2` and corresponding `writers.writePython2Bin` convenience functions to create executable Python 2 scripts in the store were removed in preparation of removal of the Python 2 interpreter.
Scripts have to be converted to Python 3 for use with `writers.writePython3` or `writers.writePyPy2` needs to be used.
+- `buildGoModule` was updated to use `go_1_17`, third party derivations that specify >= go 1.17 in the main `go.mod` will need to regenerate their `vendorSha256` hash.
+
+- The `gnome-passwordsafe` package updated to [version 6.x](https://gitlab.gnome.org/World/secrets/-/tags/6.0) and renamed to `gnome-secrets`.
+
+- `services.gnome.experimental-features.realtime-scheduling` option has been removed, as GNOME Shell now [uses rtkit](https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2060). Use `security.rtkit.enable = true;` instead. As before, you will need to have it enabled using GSettings.
+
+- `services.telepathy` will no longer be enabled by default for GNOME desktops, one should enable it in their configs if using Empathy or Polari.
+
- If you previously used `/etc/docker/daemon.json`, you need to incorporate the changes into the new option `virtualisation.docker.daemon.settings`.
+- Ntopng (`services.ntopng`) is updated to 5.2.1 and uses a separate Redis instance if `system.stateVersion` is at least `22.05`. Existing setups shouldn't be affected.
+
- The backward compatibility in `services.wordpress` to configure sites with
the old interface has been removed. Please use `services.wordpress.sites`
instead.
@@ -101,6 +298,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- opensmtpd-extras is no longer build with python2 scripting support due to python2 deprecation in nixpkgs
+- `services.miniflux.adminCredentialFiles` is now required, instead of defaulting to `admin` and `password`.
+
- The `autorestic` package has been upgraded from 1.3.0 to 1.5.0 which introduces breaking changes in config file, check [their migration guide](https://autorestic.vercel.app/migration/1.4_1.5) for more details.
- For `pkgs.python3.pkgs.ipython`, its direct dependency `pkgs.python3.pkgs.matplotlib-inline`
@@ -126,22 +325,93 @@ In addition to numerous new and upgraded packages, this release has the followin
- `pkgs.docbookrx` was removed since it's unmaintained
+- `pkgs._7zz` is now correctly licensed as LGPL3+ and BSD3 with optional unfree unRAR licensed code
+
+- The `vim.customize` function produced by `vimUtils.makeCustomizable` now has a slightly different interface:
+ * The wrapper now includes everything in the given Vim derivation if `name` is `"vim"` (the default). This makes the `wrapManual` argument obsolete, but this behavior can be overriden by setting the `standalone` argument.
+ * All the executables present in the given derivation (or, in `standalone` mode, only the `*vim` ones) are wrapped. This makes the `wrapGui` argument obsolete.
+ * The `vimExecutableName` and `gvimExecutableName` arguments were replaced by a single `executableName` argument in which the shell variable `$exe` can be used to refer to the wrapped executable's name.
+
+ See the comments in `pkgs/applications/editors/vim/plugins/vim-utils.nix` for more details.
+
+ `vimUtils.vimWithRC` was removed. You should instead use `customize` on a Vim derivation, which now accepts `vimrcFile` and `gvimrcFile` arguments.
+
+- `tilp2` was removed together with its module
+
+- The F-PROT antivirus (`fprot` package) and its service module were removed because it
+ reached [end-of-life](https://kb.cyren.com/av-support/index.php?/Knowledgebase/Article/View/434/0/end-of-sale--end-of-life-for-f-prot-and-csam).
+
+- `bird1` and its modules `services.bird` as well as `services.bird6` have been removed. Upgrade to `services.bird2`.
+
- The options `networking.interfaces..ipv4.routes` and `networking.interfaces..ipv6.routes` are no longer ignored when using networkd instead of the default scripted network backend by setting `networking.useNetworkd` to `true`.
+- The `miller` package has been upgraded from 5.10.3 to [6.2.0](https://github.com/johnkerl/miller/releases/tag/v6.2.0). See [What's new in Miller 6](https://miller.readthedocs.io/en/latest/new-in-miller-6).
+
- MultiMC has been replaced with the fork PolyMC due to upstream developers being hostile to 3rd party package maintainers. PolyMC removes all MultiMC branding and is aimed at providing proper 3rd party packages like the one contained in Nixpkgs. This change affects the data folder where game instances and other save and configuration files are stored. Users with existing installations should rename `~/.local/share/multimc` to `~/.local/share/polymc`. The main config file's path has also moved from `~/.local/share/multimc/multimc.cfg` to `~/.local/share/polymc/polymc.cfg`.
+- `systemd-nspawn@.service` settings have been reverted to the default systemd behaviour. User namespaces are now activated by default. If you want to keep running nspawn containers without user namespaces you need to set `systemd.nspawn..execConfig.PrivateUsers = false`
+
+- The Tor SOCKS proxy is now actually disabled if `services.tor.client.enable` is set to `false` (the default). If you are using this functionality but didn't change the setting or set it to `false`, you now need to set it to `true`.
+
- The terraform 0.12 compatibility has been removed and the `terraform.withPlugins` and `terraform-providers.mkProvider` implementations simplified. Providers now need to be stored under
`$out/libexec/terraform-providers/////_/terraform-provider-_v` (which mkProvider does).
This breaks back-compat so it's not possible to mix-and-match with previous versions of nixpkgs. In exchange, it now becomes possible to use the providers from [nixpkgs-terraform-providers-bin](https://github.com/numtide/nixpkgs-terraform-providers-bin) directly.
+- The `dendrite` package has been upgraded from 0.5.1 to
+ [0.6.5](https://github.com/matrix-org/dendrite/releases/tag/v0.6.5). Instances
+ configured with split sqlite databases, which has been the default
+ in NixOS, require merging of the federation sender and signing key
+ databases. See upstream [release
+ notes](https://github.com/matrix-org/dendrite/releases/tag/v0.6.0)
+ on version 0.6.0 for details on database changes.
+
+- The existing `pkgs.opentelemetry-collector` has been moved to
+ `pkgs.opentelemetry-collector-contrib` to match the actual source being the
+ "contrib" edition. `pkgs.opentelemetry-collector` is now the actual core
+ release of opentelemetry-collector. If you use the community contributions
+ you should change the package you refer to. If you don't need them update your
+ commands from `otelcontribcol` to `otelcorecol` and enjoy a 7x smaller binary.
+
+- `pkgs.pgadmin` now refers to `pkgs.pgadmin4`.
+ If you still need pgadmin3, use `pkgs.pgadmin3`.
+
- `pkgs.noto-fonts-cjk` is now deprecated in favor of `pkgs.noto-fonts-cjk-sans`
and `pkgs.noto-fonts-cjk-serif` because they each have different release
schedules. To maintain compatibility with prior releases of Nixpkgs,
`pkgs.noto-fonts-cjk` is currently an alias of `pkgs.noto-fonts-cjk-sans` and
doesn't include serif fonts.
-- The interface that allows activation scripts to restart units has been reworked. Restarting and reloading is now done by a single file `/run/nixos/activation-restart-list` that honors `restartIfChanged` and `reloadIfChanged` of the units.
+- `pkgs.epgstation` has been upgraded from v1 to v2, resulting in incompatible
+ changes in the database scheme and configuration format.
+
+- Some top-level settings under [services.epgstation](#opt-services.epgstation.enable)
+ is now deprecated because it was redudant due to the same options being
+ present in [services.epgstation.settings](#opt-services.epgstation.settings).
+
+- The option `services.epgstation.basicAuth` was removed because basic
+ authentication support was dropped by upstream.
+
+- The option [services.epgstation.database.passwordFile](#opt-services.epgstation.database.passwordFile)
+ no longer has a default value. Make sure to set this option explicitly before
+ upgrading. Change the database password if necessary.
+
+- The [services.epgstation.settings](#opt-services.epgstation.settings)
+ option now expects options for `config.yml` in EPGStation v2.
+
+- Existing data for the [services.epgstation](#opt-services.epgstation.enable)
+ module would have to be backed up prior to the upgrade. To back up exising
+ data to `/tmp/epgstation.bak`, run
+ `sudo -u epgstation epgstation run backup /tmp/epgstation.bak`.
+ To import that data after to the upgrade, run
+ `sudo -u epgstation epgstation run v1migrate /tmp/epgstation.bak`
+
+- `switch-to-configuration` (the script that is run when running `nixos-rebuild switch` for example) has been reworked
+ * The interface that allows activation scripts to restart units has been streamlined. Restarting and reloading is now done by a single file `/run/nixos/activation-restart-list` that honors `restartIfChanged` and `reloadIfChanged` of the units.
+ * Preferring to reload instead of restarting can still be achieved using `/run/nixos/activation-reload-list`.
+ * The script now uses a proper ini-file parser to parse systemd units. Some values are now only searched in one section instead of in the entire unit. This is only relevant for units that don't use the NixOS systemd moule.
+ * `RefuseManualStop`, `X-OnlyManualStart`, `X-StopOnRemoval`, `X-StopOnReconfiguration` are only searched in the `[Unit]` section
+ * `X-ReloadIfChanged`, `X-RestartIfChanged`, `X-StopIfChanged` are only searched in the `[Service]` section
- The `services.bookstack.cacheDir` option has been removed, since the
cache directory is now handled by systemd.
@@ -153,6 +423,27 @@ In addition to numerous new and upgraded packages, this release has the followin
- `lib.assertMsg` and `lib.assertOneOf` no longer return `false` if the passed condition is `false`, `throw`ing the given error message instead (which makes the resulting error message less cluttered). This will not impact the behaviour of code using these functions as intended, namely as top-level wrapper for `assert` conditions.
+- The `vpnc` package has been changed to use GnuTLS instead of OpenSSL by default for licensing reasons.
+
+- `pkgs.vimPlugins.onedark-nvim` now refers to [navarasu/onedark.nvim](https://github.com/navarasu/onedark.nvim)
+ (formerly refers to [olimorris/onedarkpro.nvim](https://github.com/olimorris/onedarkpro.nvim)).
+
+- `services.pipewire.enable` will default to enabling the WirePlumber session manager instead of pipewire-media-session.
+ pipewire-media-session is deprecated by upstream and not recommended, but can still be manually enabled by setting
+ `services.pipewire.media-session.enable` to `true` and `services.pipewire.wireplumber.enable` to `false`.
+
+- `pkgs.makeDesktopItem` has been refactored to provide a more idiomatic API. Specifically:
+ - All valid options as of FDO Desktop Entry specification version 1.4 can now be passed in as explicit arguments
+ - `exec` can now be null, for entries that are not of type Application
+ - `mimeType` argument is renamed to `mimeTypes` for consistency
+ - `mimeTypes`, `categories`, `implements`, `keywords`, `onlyShowIn` and `notShowIn` take lists of strings instead of one string with semicolon separators
+ - `extraDesktopEntries` renamed to `extraConfig` for consistency
+ - Actions should now be provided as an attrset `actions`, the `Actions` line will be autogenerated.
+ - `extraEntries` is removed.
+ - Additional validation is added both at eval time and at build time.
+
+ See the `vscode` package for a more detailed example.
+
## Other Notable Changes {#sec-release-22.05-notable-changes}
@@ -177,22 +468,47 @@ In addition to numerous new and upgraded packages, this release has the followin
to allow users to make changes to the `nixos-rebuild build-vm` configuration
that do not apply to their normal system.
- The `config.system.build.vm` attribute now always exists and defaults to the
+ The `config.system.build.vm` attribute now always exists and defaults to the
value from `vmVariant`. Configurations that import the `virtualisation/qemu-vm.nix`
module themselves will override this value, such that `vmVariant` is not used.
Similarly [virtualisation.vmVariantWithBootloader](#opt-virtualisation.vmVariantWithBootLoader) was added.
+- The configuration portion of the `nix-daemon` module has been reworked and exposed as [nix.settings](options.html#opt-nix-settings):
+ * Legacy options have been mapped to the corresponding options under under [nix.settings](options.html#opt-nix.settings) and will be deprecated when NixOS 21.11 reaches end of life.
+ * [nix.buildMachines.publicHostKey](options.html#opt-nix.buildMachines.publicHostKey) has been added.
+
- The `writers.writePyPy2`/`writers.writePyPy3` and corresponding `writers.writePyPy2Bin`/`writers.writePyPy3Bin` convenience functions to create executable Python 2/3 scripts using the PyPy interpreter were added.
+- Some improvements have been made to the `hadoop` module:
+ - A `gatewayRole` option has been added, for deploying hadoop cluster configuration files to a node that does not have any active services
+ - Support for older versions of hadoop have been added to the module
+ - Overriding and extending site XML files has been made easier
+
+- If you are using Wayland you can choose to use the Ozone Wayland support
+ in Chrome and several Electron apps by setting the environment variable
+ `NIXOS_OZONE_WL=1` (for example via
+ `environment.sessionVariables.NIXOS_OZONE_WL = "1"`).
+ This is not enabled by default because Ozone Wayland is
+ still under heavy development and behavior is not always flawless.
+ Furthermore, not all Electron apps use the latest Electron versions.
+
- The `influxdb2` package was split into `influxdb2-server` and
`influxdb2-cli`, matching the split that took place upstream. A
combined `influxdb2` package is still provided in this release for
backwards compatibilty, but will be removed at a later date.
+- The `unifi` package was switched from `unifi6` to `unifi7`.
+ Direct downgrades from Unifi 7 to Unifi 6 are not possible and require restoring from a backup made by Unifi 6.
+
+- `programs.zsh.autosuggestions.strategy` now takes a list of strings instead of a string.
+
- The `services.unifi.openPorts` option default value of `true` is now deprecated and will be changed to `false` in 22.11.
Configurations using this default will print a warning when rebuilt.
+- The `services.unifi-video.openPorts` option default value of `true` is now deprecated and will be changed to `false` in 22.11.
+ Configurations using this default will print a warning when rebuilt.
+
- `security.acme` certificates will now correctly check for CA
revokation before reaching their minimum age.
@@ -217,30 +533,84 @@ In addition to numerous new and upgraded packages, this release has the followin
- The option `services.duplicati.dataDir` has been added to allow changing the location of duplicati's files.
-- A new option `boot.initrd.extraModprobeConfig` has been added which can be used to configure kernel modules that are loaded in the initrd.
+- The options `boot.extraModprobeConfig` and `boot.blacklistedKernelModules` now also take effect in the initrd by copying the file `/etc/modprobe.d/nixos.conf` into the initrd.
+
+- `nixos-generate-config` now puts the dhcp configuration in `hardware-configuration.nix` instead of `configuration.nix`.
+
+- ORY Kratos was updated to version 0.8.3-alpha.1.pre.0, which introduces some breaking changes:
+ - If you are relying on the SQLite images, update your Docker Pull commands as follows:
+ - `docker pull oryd/kratos:{version}`
+ - Additionally, all passwords now have to be at least 8 characters long.
+ - For more details, see:
+ - [Release Notes for v0.8.1-alpha-1](https://github.com/ory/kratos/releases/tag/v0.8.1-alpha.1)
+ - [Release Notes for v0.8.2-alpha-1](https://github.com/ory/kratos/releases/tag/v0.8.2-alpha.1)
- `fetchFromSourcehut` now allows fetching repositories recursively
using `fetchgit` or `fetchhg` if the argument `fetchSubmodules`
is set to `true`.
+- The `element-desktop` package now has an `useKeytar` option (defaults to `true`),
+ which allows disabling `keytar` and in turn `libsecret` usage
+ (which binds to native credential managers / keychain libraries).
+
- The option `services.thelounge.plugins` has been added to allow installing plugins for The Lounge. Plugins can be found in `pkgs.theLoungePlugins.plugins` and `pkgs.theLoungePlugins.themes`.
+- The option `services.xserver.videoDriver = [ "nvidia" ];` will now also install [nvidia VA-API drivers](https://github.com/elFarto/nvidia-vaapi-driver) by default.
+
- The `firmwareLinuxNonfree` package has been renamed to `linux-firmware`.
+- It is now possible to specify wordlists to include as handy to access environment variables using the `config.environment.wordlist` configuration options.
+
- The `services.mbpfan` module was converted to a [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) configuration.
+- The default value for `programs.spacefm.settings.graphical_su` got unset. It previously pointed to `gksu` which has been removed.
+
- A new module was added for the [Starship](https://starship.rs/) shell prompt,
providing the options `programs.starship.enable` and `programs.starship.settings`.
+- The [Dino](https://dino.im) XMPP client was updated to 0.3, adding support for audio and video calls.
+
- `services.mattermost.plugins` has been added to allow the declarative installation of Mattermost plugins.
Plugins are automatically repackaged using autoPatchelf.
+- `services.logrotate.enable` now defaults to true if any rotate path has
+ been defined, and some paths have been added by default.
+
- The `zrepl` package has been updated from 0.4.0 to 0.5:
- * The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume.
- * A bug involving encrypt-on-receive has been fixed. Read the [zrepl documentation](https://zrepl.github.io/configuration/sendrecvoptions.html#job-recv-options-placeholder) and check the output of `zfs get -r encryption,zrepl:placeholder PATH_TO_ROOTFS` on the receiver.
+
+ - The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume.
+ - A bug involving encrypt-on-receive has been fixed. Read the [zrepl documentation](https://zrepl.github.io/configuration/sendrecvoptions.html#job-recv-options-placeholder) and check the output of `zfs get -r encryption,zrepl:placeholder PATH_TO_ROOTFS` on the receiver.
- Renamed option `services.openssh.challengeResponseAuthentication` to `services.openssh.kbdInteractiveAuthentication`.
Reason is that the old name has been deprecated upstream.
Using the old option name will still work, but produce a warning.
+- `services.autorandr` now allows for adding hooks and profiles declaratively.
+
+- The `pomerium-cli` command has been moved out of the `pomerium` package into
+ the `pomerium-cli` package, following upstream's repository split. If you are
+ using the `pomerium-cli` command, you should now install the `pomerium-cli`
+ package.
+
+- The option
+ [services.networking.networkmanager.enableFccUnlock](#opt-networking.networkmanager.enableFccUnlock)
+ was added to support FCC unlock procedures. Since release 1.18.4, the ModemManager
+ daemon no longer automatically performs the FCC unlock procedure by default. See
+ [the docs](https://modemmanager.org/docs/modemmanager/fcc-unlock/) for more details.
+
+- `programs.tmux` has a new option `plugins` that accepts a list of packages from the `tmuxPlugins` group. The specified packages are added to the system and loaded by `tmux`.
+
+- The polkit service, available at `security.polkit.enable`, is now disabled by default. It will automatically be enabled through services and desktop environments as needed.
+
+- The `hadoop` package has added support for `aarch64-linux` and `aarch64-darwin` as of 3.3.1 ([#158613](https://github.com/NixOS/nixpkgs/pull/158613)).
+
+- The `R` package now builds again on `aarch64-darwin` ([#158992](https://github.com/NixOS/nixpkgs/pull/158992)).
+
+- The `spark3` package has been updated from 3.1.2 to 3.2.1 ([#160075](https://github.com/NixOS/nixpkgs/pull/160075)):
+
+ - Testing has been enabled for `aarch64-linux` in addition to `x86_64-linux`.
+ - The `spark3` package is now usable on `aarch64-darwin` as a result of [#158613](https://github.com/NixOS/nixpkgs/pull/158613) and [#158992](https://github.com/NixOS/nixpkgs/pull/158992).
+
+- The `programs.nncp` options were added for generating host-global NNCP configuration.
+
diff --git a/nixos/lib/eval-config.nix b/nixos/lib/eval-config.nix
index e3eb88a60eba..2daaa8a11863 100644
--- a/nixos/lib/eval-config.nix
+++ b/nixos/lib/eval-config.nix
@@ -21,6 +21,7 @@ evalConfigArgs@
, # !!! See comment about args in lib/modules.nix
specialArgs ? {}
, modules
+, modulesLocation ? (builtins.unsafeGetAttrPos "modules" evalConfigArgs).file or null
, # !!! See comment about check in lib/modules.nix
check ? true
, prefix ? []
@@ -74,7 +75,18 @@ let
_module.check = lib.mkDefault check;
};
};
- allUserModules = modules ++ legacyModules;
+
+ allUserModules =
+ let
+ # Add the invoking file (or specified modulesLocation) as error message location
+ # for modules that don't have their own locations; presumably inline modules.
+ locatedModules =
+ if modulesLocation == null then
+ modules
+ else
+ map (lib.setDefaultModuleLocation modulesLocation) modules;
+ in
+ locatedModules ++ legacyModules;
noUserModules = evalModulesMinimal ({
inherit prefix specialArgs;
diff --git a/nixos/lib/make-options-doc/mergeJSON.py b/nixos/lib/make-options-doc/mergeJSON.py
index 029787a31586..8e2ea322dc89 100644
--- a/nixos/lib/make-options-doc/mergeJSON.py
+++ b/nixos/lib/make-options-doc/mergeJSON.py
@@ -66,14 +66,21 @@ for (k, v) in overrides.items():
elif ov is not None or cur.get(ok, None) is None:
cur[ok] = ov
+severity = "error" if warningsAreErrors else "warning"
+
# check that every option has a description
hasWarnings = False
for (k, v) in options.items():
if v.value.get('description', None) is None:
- severity = "error" if warningsAreErrors else "warning"
hasWarnings = True
print(f"\x1b[1;31m{severity}: option {v.name} has no description\x1b[0m", file=sys.stderr)
v.value['description'] = "This option has no description."
+ if v.value.get('type', "unspecified") == "unspecified":
+ hasWarnings = True
+ print(
+ f"\x1b[1;31m{severity}: option {v.name} has no type. Please specify a valid type, see " +
+ "https://nixos.org/manual/nixos/stable/index.html#sec-option-types\x1b[0m", file=sys.stderr)
+
if hasWarnings and warningsAreErrors:
print(
"\x1b[1;31m" +
diff --git a/nixos/lib/qemu-common.nix b/nixos/lib/qemu-common.nix
index 964814e8c602..20bbe9ff5d99 100644
--- a/nixos/lib/qemu-common.nix
+++ b/nixos/lib/qemu-common.nix
@@ -22,7 +22,7 @@ rec {
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
qemuBinary = qemuPkg: {
- x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu qemu64";
+ x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu max";
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -enable-kvm -machine virt -cpu host";
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -enable-kvm -machine virt,gic-version=host -cpu host";
powerpc64le-linux = "${qemuPkg}/bin/qemu-system-ppc64 -machine powernv";
diff --git a/nixos/lib/systemd-lib.nix b/nixos/lib/systemd-lib.nix
index db4c35511871..37900b0b16f6 100644
--- a/nixos/lib/systemd-lib.nix
+++ b/nixos/lib/systemd-lib.nix
@@ -5,12 +5,16 @@ with lib;
let
cfg = config.systemd;
lndir = "${pkgs.buildPackages.xorg.lndir}/bin/lndir";
+ systemd = cfg.package;
in rec {
shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s);
mkPathSafeName = lib.replaceChars ["@" ":" "\\" "[" "]"] ["-" "-" "-" "" ""];
+ # a type for options that take a unit name
+ unitNameType = types.strMatching "[a-zA-Z0-9@%:_.\\-]+[.](service|socket|device|mount|automount|swap|target|path|timer|scope|slice)";
+
makeUnit = name: unit:
if unit.enable then
pkgs.runCommand "unit-${mkPathSafeName name}"
@@ -19,8 +23,9 @@ in rec {
inherit (unit) text;
}
''
- mkdir -p $out
- echo -n "$text" > $out/${shellEscape name}
+ name=${shellEscape name}
+ mkdir -p "$out/$(dirname "$name")"
+ echo -n "$text" > "$out/$name"
''
else
pkgs.runCommand "unit-${mkPathSafeName name}-disabled"
@@ -28,8 +33,9 @@ in rec {
allowSubstitutes = false;
}
''
- mkdir -p $out
- ln -s /dev/null $out/${shellEscape name}
+ name=${shellEscape name}
+ mkdir -p "$out/$(dirname "$name")"
+ ln -s /dev/null "$out/$name"
'';
boolValues = [true false "yes" "no"];
@@ -232,4 +238,205 @@ in rec {
''}
''; # */
+ makeJobScript = name: text:
+ let
+ scriptName = replaceChars [ "\\" "@" ] [ "-" "_" ] (shellEscape name);
+ out = (pkgs.writeShellScriptBin scriptName ''
+ set -e
+ ${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}";
+
+ unitConfig = { config, options, ... }: {
+ config = {
+ unitConfig =
+ optionalAttrs (config.requires != [])
+ { Requires = toString config.requires; }
+ // optionalAttrs (config.wants != [])
+ { Wants = toString config.wants; }
+ // optionalAttrs (config.after != [])
+ { After = toString config.after; }
+ // optionalAttrs (config.before != [])
+ { Before = toString config.before; }
+ // optionalAttrs (config.bindsTo != [])
+ { BindsTo = toString config.bindsTo; }
+ // optionalAttrs (config.partOf != [])
+ { PartOf = toString config.partOf; }
+ // optionalAttrs (config.conflicts != [])
+ { Conflicts = toString config.conflicts; }
+ // optionalAttrs (config.requisite != [])
+ { Requisite = toString config.requisite; }
+ // optionalAttrs (config.restartTriggers != [])
+ { X-Restart-Triggers = toString config.restartTriggers; }
+ // optionalAttrs (config.reloadTriggers != [])
+ { X-Reload-Triggers = toString config.reloadTriggers; }
+ // optionalAttrs (config.description != "") {
+ Description = config.description; }
+ // optionalAttrs (config.documentation != []) {
+ Documentation = toString config.documentation; }
+ // optionalAttrs (config.onFailure != []) {
+ OnFailure = toString config.onFailure; }
+ // optionalAttrs (options.startLimitIntervalSec.isDefined) {
+ StartLimitIntervalSec = toString config.startLimitIntervalSec;
+ } // optionalAttrs (options.startLimitBurst.isDefined) {
+ StartLimitBurst = toString config.startLimitBurst;
+ };
+ };
+ };
+
+ serviceConfig = { name, config, ... }: {
+ config = mkMerge
+ [ { # Default path for systemd services. Should be quite minimal.
+ path = mkAfter
+ [ pkgs.coreutils
+ pkgs.findutils
+ pkgs.gnugrep
+ pkgs.gnused
+ systemd
+ ];
+ environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
+ }
+ (mkIf (config.preStart != "")
+ { serviceConfig.ExecStartPre =
+ [ (makeJobScript "${name}-pre-start" config.preStart) ];
+ })
+ (mkIf (config.script != "")
+ { serviceConfig.ExecStart =
+ makeJobScript "${name}-start" config.script + " " + config.scriptArgs;
+ })
+ (mkIf (config.postStart != "")
+ { serviceConfig.ExecStartPost =
+ [ (makeJobScript "${name}-post-start" config.postStart) ];
+ })
+ (mkIf (config.reload != "")
+ { serviceConfig.ExecReload =
+ makeJobScript "${name}-reload" config.reload;
+ })
+ (mkIf (config.preStop != "")
+ { serviceConfig.ExecStop =
+ makeJobScript "${name}-pre-stop" config.preStop;
+ })
+ (mkIf (config.postStop != "")
+ { serviceConfig.ExecStopPost =
+ makeJobScript "${name}-post-stop" config.postStop;
+ })
+ ];
+ };
+
+ mountConfig = { config, ... }: {
+ config = {
+ mountConfig =
+ { What = config.what;
+ Where = config.where;
+ } // optionalAttrs (config.type != "") {
+ Type = config.type;
+ } // optionalAttrs (config.options != "") {
+ Options = config.options;
+ };
+ };
+ };
+
+ automountConfig = { config, ... }: {
+ config = {
+ automountConfig =
+ { Where = config.where;
+ };
+ };
+ };
+
+ commonUnitText = def: ''
+ [Unit]
+ ${attrsToSection def.unitConfig}
+ '';
+
+ targetToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text =
+ ''
+ [Unit]
+ ${attrsToSection def.unitConfig}
+ '';
+ };
+
+ serviceToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Service]
+ ${let env = cfg.globalEnvironment // def.environment;
+ in concatMapStrings (n:
+ let s = optionalString (env.${n} != null)
+ "Environment=${builtins.toJSON "${n}=${env.${n}}"}\n";
+ # systemd max line length is now 1MiB
+ # https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af
+ in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
+ ${if def.reloadIfChanged then ''
+ X-ReloadIfChanged=true
+ '' else if !def.restartIfChanged then ''
+ X-RestartIfChanged=false
+ '' else ""}
+ ${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
+ ${attrsToSection def.serviceConfig}
+ '';
+ };
+
+ socketToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Socket]
+ ${attrsToSection def.socketConfig}
+ ${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)}
+ ${concatStringsSep "\n" (map (s: "ListenDatagram=${s}") def.listenDatagrams)}
+ '';
+ };
+
+ timerToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Timer]
+ ${attrsToSection def.timerConfig}
+ '';
+ };
+
+ pathToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Path]
+ ${attrsToSection def.pathConfig}
+ '';
+ };
+
+ mountToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Mount]
+ ${attrsToSection def.mountConfig}
+ '';
+ };
+
+ automountToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Automount]
+ ${attrsToSection def.automountConfig}
+ '';
+ };
+
+ sliceToUnit = name: def:
+ { inherit (def) aliases wantedBy requiredBy enable;
+ text = commonUnitText def +
+ ''
+ [Slice]
+ ${attrsToSection def.sliceConfig}
+ '';
+ };
}
diff --git a/nixos/lib/systemd-unit-options.nix b/nixos/lib/systemd-unit-options.nix
index 01f954a4d3e0..8029ba0e3f6c 100644
--- a/nixos/lib/systemd-unit-options.nix
+++ b/nixos/lib/systemd-unit-options.nix
@@ -45,7 +45,7 @@ in rec {
requiredBy = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
Units that require (i.e. depend on and need to go down with)
this unit. The discussion under wantedBy
@@ -56,7 +56,7 @@ in rec {
wantedBy = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
Units that want (i.e. depend on) this unit. The standard way
to make a unit start by default at boot is to set this option
@@ -73,7 +73,7 @@ in rec {
aliases = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = "Aliases of that unit.";
};
@@ -98,7 +98,7 @@ in rec {
description = mkOption {
default = "";
- type = types.str;
+ type = types.singleLineStr;
description = "Description of this unit used in systemd messages and progress indicators.";
};
@@ -110,7 +110,7 @@ in rec {
requires = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
Start the specified units when this unit is started, and stop
this unit when the specified units are stopped or fail.
@@ -119,7 +119,7 @@ in rec {
wants = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
Start the specified units when this unit is started.
'';
@@ -127,7 +127,7 @@ in rec {
after = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
If the specified units are started at the same time as
this unit, delay this unit until they have started.
@@ -136,7 +136,7 @@ in rec {
before = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
If the specified units are started at the same time as
this unit, delay them until this unit has started.
@@ -145,7 +145,7 @@ in rec {
bindsTo = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
Like ‘requires’, but in addition, if the specified units
unexpectedly disappear, this unit will be stopped as well.
@@ -154,7 +154,7 @@ in rec {
partOf = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
If the specified units are stopped or restarted, then this
unit is stopped or restarted as well.
@@ -163,7 +163,7 @@ in rec {
conflicts = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
If the specified units are started, then this unit is stopped
and vice versa.
@@ -172,7 +172,7 @@ in rec {
requisite = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
Similar to requires. However if the units listed are not started,
they will not be started and the transaction will fail.
@@ -201,9 +201,20 @@ in rec {
'';
};
+ reloadTriggers = mkOption {
+ default = [];
+ type = types.listOf unitOption;
+ description = ''
+ An arbitrary list of items such as derivations. If any item
+ in the list changes between reconfigurations, the service will
+ be reloaded. If anything but a reload trigger changes in the
+ unit file, the unit will be restarted instead.
+ '';
+ };
+
onFailure = mkOption {
default = [];
- type = types.listOf types.str;
+ type = types.listOf unitNameType;
description = ''
A list of one or more units that are activated when
this unit enters the "failed" state.
@@ -338,6 +349,11 @@ in rec {
configuration switch if its definition has changed. If
enabled, the value of is
ignored.
+
+ This option should not be used anymore in favor of
+ which allows more granular
+ control of when a service is reloaded and when a service
+ is restarted.
'';
};
diff --git a/nixos/lib/test-driver/test_driver/__init__.py b/nixos/lib/test-driver/test_driver/__init__.py
index 5477ab5cd038..61d91c9ed654 100755
--- a/nixos/lib/test-driver/test_driver/__init__.py
+++ b/nixos/lib/test-driver/test_driver/__init__.py
@@ -33,6 +33,22 @@ class EnvDefault(argparse.Action):
setattr(namespace, self.dest, values)
+def writeable_dir(arg: str) -> Path:
+ """Raises an ArgumentTypeError if the given argument isn't a writeable directory
+ Note: We want to fail as early as possible if a directory isn't writeable,
+ since an executed nixos-test could fail (very late) because of the test-driver
+ writing in a directory without proper permissions.
+ """
+ path = Path(arg)
+ if not path.is_dir():
+ raise argparse.ArgumentTypeError("{0} is not a directory".format(path))
+ if not os.access(path, os.W_OK):
+ raise argparse.ArgumentTypeError(
+ "{0} is not a writeable directory".format(path)
+ )
+ return path
+
+
def main() -> None:
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
arg_parser.add_argument(
@@ -45,7 +61,7 @@ def main() -> None:
"-I",
"--interactive",
help="drop into a python repl and run the tests interactively",
- action="store_true",
+ action=argparse.BooleanOptionalAction,
)
arg_parser.add_argument(
"--start-scripts",
@@ -63,6 +79,14 @@ def main() -> None:
nargs="*",
help="vlans to span by the driver",
)
+ arg_parser.add_argument(
+ "-o",
+ "--output_directory",
+ help="""The path to the directory where outputs copied from the VM will be placed.
+ By e.g. Machine.copy_from_vm or Machine.screenshot""",
+ default=Path.cwd(),
+ type=writeable_dir,
+ )
arg_parser.add_argument(
"testscript",
action=EnvDefault,
@@ -77,7 +101,11 @@ def main() -> None:
rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state")
with Driver(
- args.start_scripts, args.vlans, args.testscript.read_text(), args.keep_vm_state
+ args.start_scripts,
+ args.vlans,
+ args.testscript.read_text(),
+ args.output_directory.resolve(),
+ args.keep_vm_state,
) as driver:
if args.interactive:
ptpython.repl.embed(driver.test_symbols(), {})
@@ -94,7 +122,7 @@ def generate_driver_symbols() -> None:
in user's test scripts. That list is then used by pyflakes to lint those
scripts.
"""
- d = Driver([], [], "")
+ d = Driver([], [], "", Path())
test_symbols = d.test_symbols()
with open("driver-symbols", "w") as fp:
fp.write(",".join(test_symbols.keys()))
diff --git a/nixos/lib/test-driver/test_driver/driver.py b/nixos/lib/test-driver/test_driver/driver.py
index 49a42fe5fb4e..0e5f013193fe 100644
--- a/nixos/lib/test-driver/test_driver/driver.py
+++ b/nixos/lib/test-driver/test_driver/driver.py
@@ -10,6 +10,28 @@ from test_driver.vlan import VLan
from test_driver.polling_condition import PollingCondition
+def get_tmp_dir() -> Path:
+ """Returns a temporary directory that is defined by TMPDIR, TEMP, TMP or CWD
+ Raises an exception in case the retrieved temporary directory is not writeable
+ See https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir
+ """
+ tmp_dir = Path(tempfile.gettempdir())
+ tmp_dir.mkdir(mode=0o700, exist_ok=True)
+ if not tmp_dir.is_dir():
+ raise NotADirectoryError(
+ "The directory defined by TMPDIR, TEMP, TMP or CWD: {0} is not a directory".format(
+ tmp_dir
+ )
+ )
+ if not os.access(tmp_dir, os.W_OK):
+ raise PermissionError(
+ "The directory defined by TMPDIR, TEMP, TMP, or CWD: {0} is not writeable".format(
+ tmp_dir
+ )
+ )
+ return tmp_dir
+
+
class Driver:
"""A handle to the driver that sets up the environment
and runs the tests"""
@@ -24,14 +46,16 @@ class Driver:
start_scripts: List[str],
vlans: List[int],
tests: str,
+ out_dir: Path,
keep_vm_state: bool = False,
):
self.tests = tests
+ self.out_dir = out_dir
- tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
- tmp_dir.mkdir(mode=0o700, exist_ok=True)
+ tmp_dir = get_tmp_dir()
with rootlog.nested("start all VLans"):
+ vlans = list(set(vlans))
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
@@ -47,6 +71,7 @@ class Driver:
name=cmd.machine_name,
tmp_dir=tmp_dir,
callbacks=[self.check_polling_conditions],
+ out_dir=self.out_dir,
)
for cmd in cmd(start_scripts)
]
@@ -141,8 +166,8 @@ class Driver:
"Using legacy create_machine(), please instantiate the"
"Machine class directly, instead"
)
- tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
- tmp_dir.mkdir(mode=0o700, exist_ok=True)
+
+ tmp_dir = get_tmp_dir()
if args.get("startCommand"):
start_command: str = args.get("startCommand", "")
@@ -154,6 +179,7 @@ class Driver:
return Machine(
tmp_dir=tmp_dir,
+ out_dir=self.out_dir,
start_command=cmd,
name=name,
keep_vm_state=args.get("keep_vm_state", False),
diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py
index e050cbd7d990..f3e615fe5bf9 100644
--- a/nixos/lib/test-driver/test_driver/machine.py
+++ b/nixos/lib/test-driver/test_driver/machine.py
@@ -198,7 +198,7 @@ class StartCommand:
) -> subprocess.Popen:
return subprocess.Popen(
self.cmd(monitor_socket_path, shell_socket_path),
- stdin=subprocess.DEVNULL,
+ stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True,
@@ -241,9 +241,15 @@ class LegacyStartCommand(StartCommand):
cdrom: Optional[str] = None,
usb: Optional[str] = None,
bios: Optional[str] = None,
+ qemuBinary: Optional[str] = None,
qemuFlags: Optional[str] = None,
):
- self._cmd = "qemu-kvm -m 384"
+ if qemuBinary is not None:
+ self._cmd = qemuBinary
+ else:
+ self._cmd = "qemu-kvm"
+
+ self._cmd += " -m 384"
# networking
net_backend = "-netdev user,id=net0"
@@ -297,6 +303,7 @@ class Machine:
the machine lifecycle with the help of a start script / command."""
name: str
+ out_dir: Path
tmp_dir: Path
shared_dir: Path
state_dir: Path
@@ -325,6 +332,7 @@ class Machine:
def __init__(
self,
+ out_dir: Path,
tmp_dir: Path,
start_command: StartCommand,
name: str = "machine",
@@ -332,6 +340,7 @@ class Machine:
allow_reboot: bool = False,
callbacks: Optional[List[Callable]] = None,
) -> None:
+ self.out_dir = out_dir
self.tmp_dir = tmp_dir
self.keep_vm_state = keep_vm_state
self.allow_reboot = allow_reboot
@@ -378,6 +387,7 @@ class Machine:
cdrom=args.get("cdrom"),
usb=args.get("usb"),
bios=args.get("bios"),
+ qemuBinary=args.get("qemuBinary"),
qemuFlags=args.get("qemuFlags"),
)
@@ -540,14 +550,36 @@ class Machine:
Should only be used during test development, not in the production test."""
self.connect()
- self.log("Terminal is ready (there is no prompt):")
+ self.log("Terminal is ready (there is no initial prompt):")
assert self.shell
subprocess.run(
- ["socat", "READLINE", f"FD:{self.shell.fileno()}"],
+ ["socat", "READLINE,prompt=$ ", f"FD:{self.shell.fileno()}"],
pass_fds=[self.shell.fileno()],
)
+ def console_interact(self) -> None:
+ """Allows you to interact with QEMU's stdin
+
+ The shell can be exited with Ctrl+D. Note that Ctrl+C is not allowed to be used.
+ QEMU's stdout is read line-wise.
+
+ Should only be used during test development, not in the production test."""
+ self.log("Terminal is ready (there is no prompt):")
+
+ assert self.process
+ assert self.process.stdin
+
+ while True:
+ try:
+ char = sys.stdin.buffer.read(1)
+ except KeyboardInterrupt:
+ break
+ if char == b"": # ctrl+d
+ self.log("Closing connection to the console")
+ break
+ self.send_console(char.decode())
+
def succeed(self, *commands: str, timeout: Optional[int] = None) -> str:
"""Execute each command and check that it succeeds."""
output = ""
@@ -702,10 +734,9 @@ class Machine:
self.connected = True
def screenshot(self, filename: str) -> None:
- out_dir = os.environ.get("out", os.getcwd())
word_pattern = re.compile(r"^\w+$")
if word_pattern.match(filename):
- filename = os.path.join(out_dir, "{}.png".format(filename))
+ filename = os.path.join(self.out_dir, "{}.png".format(filename))
tmp = "{}.ppm".format(filename)
with self.nested(
@@ -756,7 +787,6 @@ class Machine:
all the VMs (using a temporary directory).
"""
# Compute the source, target, and intermediate shared file names
- out_dir = Path(os.environ.get("out", os.getcwd()))
vm_src = Path(source)
with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td:
shared_temp = Path(shared_td)
@@ -766,7 +796,7 @@ class Machine:
# Copy the file to the shared directory inside VM
self.succeed(make_command(["mkdir", "-p", vm_shared_temp]))
self.succeed(make_command(["cp", "-r", vm_src, vm_intermediate]))
- abs_target = out_dir / target_dir / vm_src.name
+ abs_target = self.out_dir / target_dir / vm_src.name
abs_target.parent.mkdir(exist_ok=True, parents=True)
# Copy the file from the shared directory outside VM
if intermediate.is_dir():
@@ -826,6 +856,12 @@ class Machine:
self.send_monitor_command("sendkey {}".format(key))
time.sleep(0.01)
+ def send_console(self, chars: str) -> None:
+ assert self.process
+ assert self.process.stdin
+ self.process.stdin.write(chars.encode())
+ self.process.stdin.flush()
+
def start(self) -> None:
if self.booted:
return
diff --git a/nixos/lib/testing-python.nix b/nixos/lib/testing-python.nix
index a67040468136..facc7a253a75 100644
--- a/nixos/lib/testing-python.nix
+++ b/nixos/lib/testing-python.nix
@@ -30,7 +30,7 @@ rec {
# effectively mute the XMLLogger
export LOGFILE=/dev/null
- ${driver}/bin/nixos-test-driver
+ ${driver}/bin/nixos-test-driver -o $out
'';
passthru = driver.passthru // {
@@ -51,6 +51,7 @@ rec {
, enableOCR ? false
, skipLint ? false
, passthru ? {}
+ , interactive ? false
}:
let
# Reifies and correctly wraps the python test driver for
@@ -139,31 +140,34 @@ rec {
wrapProgram $out/bin/nixos-test-driver \
--set startScripts "''${vmStartScripts[*]}" \
--set testScript "$out/test-script" \
- --set vlans '${toString vlans}'
+ --set vlans '${toString vlans}' \
+ ${lib.optionalString (interactive) "--add-flags --interactive"}
'');
# Make a full-blown test
makeTest =
- { testScript
+ { machine ? null
+ , nodes ? {}
+ , testScript
, enableOCR ? false
, name ? "unnamed"
# Skip linting (mainly intended for faster dev cycles)
, skipLint ? false
, passthru ? {}
+ , meta ? {}
, # For meta.position
pos ? # position used in error messages and for meta.position
- (if t.meta.description or null != null
- then builtins.unsafeGetAttrPos "description" t.meta
+ (if meta.description or null != null
+ then builtins.unsafeGetAttrPos "description" meta
else builtins.unsafeGetAttrPos "testScript" t)
- , ...
} @ t:
let
- nodes = qemu_pkg:
+ mkNodes = qemu_pkg:
let
testScript' =
# Call the test script with the computed nodes.
if lib.isFunction testScript
- then testScript { nodes = nodes qemu_pkg; }
+ then testScript { nodes = mkNodes qemu_pkg; }
else testScript;
build-vms = import ./build-vms.nix {
@@ -203,32 +207,29 @@ rec {
};
in
build-vms.buildVirtualNetwork (
- t.nodes or (if t ? machine then { machine = t.machine; } else { })
+ nodes // lib.optionalAttrs (machine != null) { inherit machine; }
);
driver = setupDriverForTest {
inherit testScript enableOCR skipLint passthru;
testName = name;
qemu_pkg = pkgs.qemu_test;
- nodes = nodes pkgs.qemu_test;
+ nodes = mkNodes pkgs.qemu_test;
};
driverInteractive = setupDriverForTest {
inherit testScript enableOCR skipLint passthru;
testName = name;
qemu_pkg = pkgs.qemu;
- nodes = nodes pkgs.qemu;
+ nodes = mkNodes pkgs.qemu;
+ interactive = true;
};
- test =
- let
- passMeta = drv: drv // lib.optionalAttrs (t ? meta) {
- meta = (drv.meta or { }) // t.meta;
- };
- in passMeta (runTests { inherit driver pos driverInteractive; });
+ test = lib.addMetaAttrs meta (runTests { inherit driver pos driverInteractive; });
in
test // {
- inherit test driver driverInteractive nodes;
+ inherit test driver driverInteractive;
+ inherit (driver) nodes;
};
abortForFunction = functionName: abort ''The ${functionName} function was
diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix
index bbebf8ba35a0..ae68c3920c5b 100644
--- a/nixos/lib/utils.nix
+++ b/nixos/lib/utils.nix
@@ -45,6 +45,26 @@ rec {
replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"]
(removePrefix "/" s);
+ # Quotes an argument for use in Exec* service lines.
+ # systemd accepts "-quoted strings with escape sequences, toJSON produces
+ # a subset of these.
+ # Additionally we escape % to disallow expansion of % specifiers. Any lone ;
+ # in the input will be turned it ";" and thus lose its special meaning.
+ # Every $ is escaped to $$, this makes it unnecessary to disable environment
+ # substitution for the directive.
+ escapeSystemdExecArg = arg:
+ let
+ s = if builtins.isPath arg then "${arg}"
+ else if builtins.isString arg then arg
+ else if builtins.isInt arg || builtins.isFloat arg then toString arg
+ else throw "escapeSystemdExecArg only allows strings, paths and numbers";
+ in
+ replaceChars [ "%" "$" ] [ "%%" "$$" ] (builtins.toJSON s);
+
+ # Quotes a list of arguments into a single string for use in a Exec*
+ # line.
+ escapeSystemdExecArgs = concatMapStringsSep " " escapeSystemdExecArg;
+
# Returns a system path for a given shell package
toShellPath = shell:
if types.shellPackage.check shell then
@@ -149,10 +169,17 @@ rec {
if [[ -h '${output}' ]]; then
rm '${output}'
fi
+
+ inherit_errexit_enabled=0
+ shopt -pq inherit_errexit && inherit_errexit_enabled=1
+ shopt -s inherit_errexit
''
+ concatStringsSep
"\n"
- (imap1 (index: name: "export secret${toString index}=$(<'${secrets.${name}}')")
+ (imap1 (index: name: ''
+ secret${toString index}=$(<'${secrets.${name}}')
+ export secret${toString index}
+ '')
(attrNames secrets))
+ "\n"
+ "${pkgs.jq}/bin/jq >'${output}' '"
@@ -164,6 +191,7 @@ rec {
' <<'EOF'
${builtins.toJSON set}
EOF
+ (( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit
'';
systemdUtils = {
diff --git a/nixos/maintainers/scripts/azure-new/examples/basic/system.nix b/nixos/maintainers/scripts/azure-new/examples/basic/system.nix
index 855bd3bab719..d283742701d1 100644
--- a/nixos/maintainers/scripts/azure-new/examples/basic/system.nix
+++ b/nixos/maintainers/scripts/azure-new/examples/basic/system.nix
@@ -17,7 +17,7 @@ in
description = "Azure NixOS Test User";
openssh.authorizedKeys.keys = [ (builtins.readFile ~/.ssh/id_ed25519.pub) ];
};
- nix.trustedUsers = [ username ];
+ nix.settings.trusted-users = [ username ];
virtualisation.azureImage.diskSize = 2500;
diff --git a/nixos/modules/config/fonts/fonts.nix b/nixos/modules/config/fonts/fonts.nix
index 04952898cb76..adc6654afc79 100644
--- a/nixos/modules/config/fonts/fonts.nix
+++ b/nixos/modules/config/fonts/fonts.nix
@@ -39,11 +39,6 @@ let
defaultXFonts =
[ (if hasHidpi then fontcursormisc_hidpi else pkgs.xorg.fontcursormisc)
pkgs.xorg.fontmiscmisc
- ] ++ optionals (config.nixpkgs.config.allowUnfree or false)
- [ # these are unfree, and will make usage with xserver fail
- pkgs.xorg.fontbhlucidatypewriter100dpi
- pkgs.xorg.fontbhlucidatypewriter75dpi
- pkgs.xorg.fontbh100dpi
];
in
diff --git a/nixos/modules/config/resolvconf.nix b/nixos/modules/config/resolvconf.nix
index cd0ed491383c..4499481811fd 100644
--- a/nixos/modules/config/resolvconf.nix
+++ b/nixos/modules/config/resolvconf.nix
@@ -47,8 +47,8 @@ in
enable = mkOption {
type = types.bool;
- default = false;
- internal = true;
+ default = !(config.environment.etc ? "resolv.conf");
+ defaultText = literalExpression ''!(config.environment.etc ? "resolv.conf")'';
description = ''
DNS configuration is managed by resolvconf.
'';
@@ -110,8 +110,6 @@ in
config = mkMerge [
{
- networking.resolvconf.enable = !(config.environment.etc ? "resolv.conf");
-
environment.etc."resolvconf.conf".text =
if !cfg.enable then
# Force-stop any attempts to use resolvconf
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 2470d8b5bfec..b0f96c754fa5 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -449,16 +449,10 @@ in {
imports = [
(mkAliasOptionModule [ "users" "extraUsers" ] [ "users" "users" ])
(mkAliasOptionModule [ "users" "extraGroups" ] [ "users" "groups" ])
- (mkChangedOptionModule
- [ "security" "initialRootPassword" ]
- [ "users" "users" "root" "initialHashedPassword" ]
- (cfg: if cfg.security.initialRootPassword == "!"
- then null
- else cfg.security.initialRootPassword))
+ (mkRenamedOptionModule ["security" "initialRootPassword"] ["users" "users" "root" "initialHashedPassword"])
];
###### interface
-
options = {
users.mutableUsers = mkOption {
@@ -526,6 +520,17 @@ in {
'';
};
+
+ users.allowNoPasswordLogin = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Disable checking that at least the root user or a user in the wheel group can log in using
+ a password or an SSH key.
+
+ WARNING: enabling this can lock you out of your system. Enable this only if you know what are you doing.
+ '';
+ };
};
@@ -540,6 +545,7 @@ in {
home = "/root";
shell = mkDefault cfg.defaultUserShell;
group = "root";
+ initialHashedPassword = mkDefault "!";
};
nobody = {
uid = ids.uids.nobody;
@@ -616,9 +622,11 @@ in {
# there is at least one "privileged" account that has a
# password or an SSH authorized key. Privileged accounts are
# root and users in the wheel group.
- assertion = !cfg.mutableUsers ->
- any id ((mapAttrsToList (_: cfg:
- (cfg.name == "root"
+ # The check does not apply when users.disableLoginPossibilityAssertion
+ # The check does not apply when users.mutableUsers
+ assertion = !cfg.mutableUsers -> !cfg.allowNoPasswordLogin ->
+ any id (mapAttrsToList (name: cfg:
+ (name == "root"
|| cfg.group == "wheel"
|| elem "wheel" cfg.extraGroups)
&&
@@ -627,12 +635,16 @@ in {
|| cfg.passwordFile != null
|| cfg.openssh.authorizedKeys.keys != []
|| cfg.openssh.authorizedKeys.keyFiles != [])
- ) cfg.users) ++ [
+ ) cfg.users ++ [
config.security.googleOsLogin.enable
]);
message = ''
Neither the root account nor any wheel user has a password or SSH authorized key.
- You must set one to prevent being locked out of your system.'';
+ You must set one to prevent being locked out of your system.
+ If you really want to be locked out of your system, set users.allowNoPasswordLogin = true;
+ However you are most probably better off by setting users.mutableUsers = true; and
+ manually running passwd root to set the root password.
+ '';
}
] ++ flatten (flip mapAttrsToList cfg.users (name: user:
[
diff --git a/nixos/modules/config/xdg/portal.nix b/nixos/modules/config/xdg/portal.nix
index 80ec3126ca54..088f2af59e22 100644
--- a/nixos/modules/config/xdg/portal.nix
+++ b/nixos/modules/config/xdg/portal.nix
@@ -1,4 +1,4 @@
-{ config, pkgs ,lib ,... }:
+{ config, pkgs, lib, ... }:
with lib;
@@ -13,13 +13,13 @@ with lib;
options.xdg.portal = {
enable =
- mkEnableOption "xdg desktop integration"//{
+ mkEnableOption "xdg desktop integration" // {
default = false;
};
extraPortals = mkOption {
type = types.listOf types.package;
- default = [];
+ default = [ ];
description = ''
List of additional portals to add to path. Portals allow interaction
with system, like choosing files or taking screenshots. At minimum,
@@ -46,25 +46,36 @@ with lib;
let
cfg = config.xdg.portal;
packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
- joinedPortals = pkgs.symlinkJoin {
+ joinedPortals = pkgs.buildEnv {
name = "xdg-portals";
- paths = cfg.extraPortals;
+ paths = packages;
+ pathsToLink = [ "/share/xdg-desktop-portal/portals" "/share/applications" ];
};
- in mkIf cfg.enable {
+ in
+ mkIf cfg.enable {
assertions = [
- { assertion = (cfg.gtkUsePortal -> cfg.extraPortals != []);
- message = "Setting xdg.portal.gtkUsePortal to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
+ {
+ assertion = cfg.extraPortals != [ ];
+ message = "Setting xdg.portal.enable to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
}
];
- services.dbus.packages = packages;
+ services.dbus.packages = packages;
systemd.packages = packages;
- environment.sessionVariables = {
- GTK_USE_PORTAL = mkIf cfg.gtkUsePortal "1";
- XDG_DESKTOP_PORTAL_DIR = "${joinedPortals}/share/xdg-desktop-portal/portals";
+ environment = {
+ # fixes screen sharing on plasmawayland on non-chromium apps by linking
+ # share/applications/*.desktop files
+ # see https://github.com/NixOS/nixpkgs/issues/145174
+ systemPackages = [ joinedPortals ];
+ pathsToLink = [ "/share/applications" ];
+
+ sessionVariables = {
+ GTK_USE_PORTAL = mkIf cfg.gtkUsePortal "1";
+ XDG_DESKTOP_PORTAL_DIR = "${joinedPortals}/share/xdg-desktop-portal/portals";
+ };
};
};
}
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index 24d5b7bc2b29..5b60b17312f9 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -57,7 +57,6 @@ in {
rtl8723bs-firmware
rtl8761b-firmware
rtw88-firmware
- rtw89-firmware
zd1211fw
alsa-firmware
sof-firmware
@@ -65,6 +64,8 @@ in {
] ++ optional (pkgs.stdenv.hostPlatform.isAarch32 || pkgs.stdenv.hostPlatform.isAarch64) raspberrypiWirelessFirmware
++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [
rtl8723bs-firmware
+ ] ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "5.16") [
+ rtw89-firmware
];
hardware.wirelessRegulatoryDatabase = true;
})
@@ -82,6 +83,7 @@ in {
b43Firmware_5_1_138
b43Firmware_6_30_163_46
b43FirmwareCutter
+ xow_dongle-firmware
] ++ optional pkgs.stdenv.hostPlatform.isx86 facetimehd-firmware;
})
(mkIf cfg.wirelessRegulatoryDatabase {
diff --git a/nixos/modules/hardware/network/b43.nix b/nixos/modules/hardware/network/b43.nix
index e63f2d04d1a6..eb03bf223ccf 100644
--- a/nixos/modules/hardware/network/b43.nix
+++ b/nixos/modules/hardware/network/b43.nix
@@ -24,10 +24,6 @@ let kernelVersion = config.boot.kernelPackages.kernel.version; in
###### implementation
config = mkIf config.networking.enableB43Firmware {
- assertions = singleton
- { assertion = lessThan 0 (builtins.compareVersions kernelVersion "3.2");
- message = "b43 firmware for kernels older than 3.2 not packaged yet!";
- };
hardware.firmware = [ pkgs.b43Firmware_5_1_138 ];
};
diff --git a/nixos/modules/hardware/video/capture/mwprocapture.nix b/nixos/modules/hardware/video/capture/mwprocapture.nix
index 61bab533edaf..76cb4c6ee9bf 100644
--- a/nixos/modules/hardware/video/capture/mwprocapture.nix
+++ b/nixos/modules/hardware/video/capture/mwprocapture.nix
@@ -16,11 +16,6 @@ in
config = mkIf cfg.enable {
- assertions = singleton {
- assertion = versionAtLeast kernelPackages.kernel.version "3.2";
- message = "Magewell Pro Capture family module is not supported for kernels older than 3.2";
- };
-
boot.kernelModules = [ "ProCapture" ];
environment.systemPackages = [ kernelPackages.mwprocapture ];
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index ff4225dc29ad..6de5b99a1ee6 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -178,11 +178,6 @@ in
igpuBusId = if pCfg.intelBusId != "" then pCfg.intelBusId else pCfg.amdgpuBusId;
in mkIf enabled {
assertions = [
- {
- assertion = with config.services.xserver.displayManager; (gdm.enable && gdm.nvidiaWayland) -> cfg.modesetting.enable;
- message = "You cannot use wayland with GDM without modesetting enabled for NVIDIA drivers, set `hardware.nvidia.modesetting.enable = true`";
- }
-
{
assertion = primeEnabled -> pCfg.intelBusId == "" || pCfg.amdgpuBusId == "";
message = ''
@@ -249,7 +244,7 @@ in
modules = optional (igpuDriver == "amdgpu") [ pkgs.xorg.xf86videoamdgpu ];
deviceSection = ''
BusID "${igpuBusId}"
- ${optionalString syncCfg.enable ''Option "AccelMethod" "none"''}
+ ${optionalString (syncCfg.enable && igpuDriver != "amdgpu") ''Option "AccelMethod" "none"''}
'';
} ++ singleton {
name = "nvidia";
@@ -274,9 +269,15 @@ in
Option "AllowNVIDIAGPUScreens"
'';
- services.xserver.displayManager.setupCommands = optionalString syncCfg.enable ''
+ services.xserver.displayManager.setupCommands = let
+ sinkGpuProviderName = if igpuDriver == "amdgpu" then
+ # find the name of the provider if amdgpu
+ "`${pkgs.xorg.xrandr}/bin/xrandr --listproviders | ${pkgs.gnugrep}/bin/grep -i AMD | ${pkgs.gnused}/bin/sed -n 's/^.*name://p'`"
+ else
+ igpuDriver;
+ in optionalString syncCfg.enable ''
# Added by nvidia configuration module for Optimus/PRIME.
- ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource ${igpuDriver} NVIDIA-0
+ ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource "${sinkGpuProviderName}" NVIDIA-0
${pkgs.xorg.xrandr}/bin/xrandr --auto
'';
@@ -288,10 +289,14 @@ in
environment.etc."egl/egl_external_platform.d".source =
"/run/opengl-driver/share/egl/egl_external_platform.d/";
- hardware.opengl.package = mkIf (!offloadCfg.enable) nvidia_x11.out;
- hardware.opengl.package32 = mkIf (!offloadCfg.enable) nvidia_x11.lib32;
- hardware.opengl.extraPackages = optional offloadCfg.enable nvidia_x11.out;
- hardware.opengl.extraPackages32 = optional offloadCfg.enable nvidia_x11.lib32;
+ hardware.opengl.extraPackages = [
+ nvidia_x11.out
+ pkgs.nvidia-vaapi-driver
+ ];
+ hardware.opengl.extraPackages32 = [
+ nvidia_x11.lib32
+ pkgs.pkgsi686Linux.nvidia-vaapi-driver
+ ];
environment.systemPackages = [ nvidia_x11.bin ]
++ optionals cfg.nvidiaSettings [ nvidia_x11.settings ]
diff --git a/nixos/modules/hardware/xone.nix b/nixos/modules/hardware/xone.nix
new file mode 100644
index 000000000000..89690d8c6fb1
--- /dev/null
+++ b/nixos/modules/hardware/xone.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.hardware.xone;
+in
+{
+ options.hardware.xone = {
+ enable = mkEnableOption "the xone driver for Xbox One and Xbobx Series X|S accessories";
+ };
+
+ config = mkIf cfg.enable {
+ boot = {
+ blacklistedKernelModules = [ "xpad" "mt76x2u" ];
+ extraModulePackages = with config.boot.kernelPackages; [ xone ];
+ };
+ hardware.firmware = [ pkgs.xow_dongle-firmware ];
+ };
+
+ meta = {
+ maintainers = with maintainers; [ rhysmdnz ];
+ };
+}
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
index 12ad8a4ae004..303493741f3d 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix
@@ -10,10 +10,10 @@ with lib;
isoImage.edition = "gnome";
services.xserver.desktopManager.gnome = {
- # Add firefox to favorite-apps
+ # Add Firefox and other tools useful for installation to the launcher
favoriteAppsOverride = ''
[org.gnome.shell]
- favorite-apps=[ 'firefox.desktop', 'org.gnome.Geary.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop' ]
+ favorite-apps=[ 'firefox.desktop', 'nixos-manual.desktop', 'org.gnome.Terminal.desktop', 'org.gnome.Nautilus.desktop', 'gparted.desktop' ]
'';
enable = true;
};
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 3ff1b3d670e9..860e240b43d4 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -91,29 +91,9 @@ let
SERIAL 0 115200
TIMEOUT ${builtins.toString syslinuxTimeout}
UI vesamenu.c32
- MENU TITLE NixOS
MENU BACKGROUND /isolinux/background.png
- MENU RESOLUTION 800 600
- MENU CLEAR
- MENU ROWS 6
- MENU CMDLINEROW -4
- MENU TIMEOUTROW -3
- MENU TABMSGROW -2
- MENU HELPMSGROW -1
- MENU HELPMSGENDROW -1
- MENU MARGIN 0
- # FG:AARRGGBB BG:AARRGGBB shadow
- MENU COLOR BORDER 30;44 #00000000 #00000000 none
- MENU COLOR SCREEN 37;40 #FF000000 #00E2E8FF none
- MENU COLOR TABMSG 31;40 #80000000 #00000000 none
- MENU COLOR TIMEOUT 1;37;40 #FF000000 #00000000 none
- MENU COLOR TIMEOUT_MSG 37;40 #FF000000 #00000000 none
- MENU COLOR CMDMARK 1;36;40 #FF000000 #00000000 none
- MENU COLOR CMDLINE 37;40 #FF000000 #00000000 none
- MENU COLOR TITLE 1;36;44 #00000000 #00000000 none
- MENU COLOR UNSEL 37;44 #FF000000 #00000000 none
- MENU COLOR SEL 7;37;40 #FFFFFFFF #FF5277C3 std
+ ${config.isoImage.syslinuxTheme}
DEFAULT boot
@@ -601,6 +581,37 @@ in
'';
};
+ isoImage.syslinuxTheme = mkOption {
+ default = ''
+ MENU TITLE NixOS
+ MENU RESOLUTION 800 600
+ MENU CLEAR
+ MENU ROWS 6
+ MENU CMDLINEROW -4
+ MENU TIMEOUTROW -3
+ MENU TABMSGROW -2
+ MENU HELPMSGROW -1
+ MENU HELPMSGENDROW -1
+ MENU MARGIN 0
+
+ # FG:AARRGGBB BG:AARRGGBB shadow
+ MENU COLOR BORDER 30;44 #00000000 #00000000 none
+ MENU COLOR SCREEN 37;40 #FF000000 #00E2E8FF none
+ MENU COLOR TABMSG 31;40 #80000000 #00000000 none
+ MENU COLOR TIMEOUT 1;37;40 #FF000000 #00000000 none
+ MENU COLOR TIMEOUT_MSG 37;40 #FF000000 #00000000 none
+ MENU COLOR CMDMARK 1;36;40 #FF000000 #00000000 none
+ MENU COLOR CMDLINE 37;40 #FF000000 #00000000 none
+ MENU COLOR TITLE 1;36;44 #00000000 #00000000 none
+ MENU COLOR UNSEL 37;44 #FF000000 #00000000 none
+ MENU COLOR SEL 7;37;40 #FFFFFFFF #FF5277C3 std
+ '';
+ type = types.str;
+ description = ''
+ The syslinux theme used for BIOS boot.
+ '';
+ };
+
isoImage.appendToMenuLabel = mkOption {
default = " Installer";
example = " Live System";
diff --git a/nixos/modules/installer/sd-card/sd-image-aarch64.nix b/nixos/modules/installer/sd-card/sd-image-aarch64.nix
index 165e2aac27b4..321793882f4c 100644
--- a/nixos/modules/installer/sd-card/sd-image-aarch64.nix
+++ b/nixos/modules/installer/sd-card/sd-image-aarch64.nix
@@ -24,6 +24,9 @@
[pi3]
kernel=u-boot-rpi3.bin
+ [pi02]
+ kernel=u-boot-rpi3.bin
+
[pi4]
kernel=u-boot-rpi4.bin
enable_gic=1
@@ -33,6 +36,9 @@
# what the pi3 firmware does by default.
disable_overscan=1
+ # Supported in newer board revisions
+ arm_boost=1
+
[all]
# Boot in 64-bit mode.
arm_64bit=1
diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix
index 065cea470fbb..dfafda77cb56 100644
--- a/nixos/modules/installer/tools/nix-fallback-paths.nix
+++ b/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -1,7 +1,7 @@
{
- x86_64-linux = "/nix/store/hapw7q1fkjxvprnkcgw9ppczavg4daj2-nix-2.4";
- i686-linux = "/nix/store/8qlvh8pp5j8wgrzj3is2jlbhgrwgsiy9-nix-2.4";
- aarch64-linux = "/nix/store/h48lkygcqj4hdibbdnpl67q7ks6vkrd6-nix-2.4";
- x86_64-darwin = "/nix/store/c3mvzszvyzakvcp9spnjvsb8m2bpjk7m-nix-2.4";
- aarch64-darwin = "/nix/store/hbfqs62r0hga2yr4zi5kc7fzhf71bq9n-nix-2.4";
+ x86_64-linux = "/nix/store/0n2wfvi1i3fg97cjc54wslvk0804y0sn-nix-2.7.0";
+ i686-linux = "/nix/store/4p27c1k9z99pli6x8cxfph20yfyzn9nh-nix-2.7.0";
+ aarch64-linux = "/nix/store/r9yr8ijsb0gi9r7y92y3yzyld59yp0kj-nix-2.7.0";
+ x86_64-darwin = "/nix/store/hyfj5imsd0c4amlcjpf8l6w4q2draaj3-nix-2.7.0";
+ aarch64-darwin = "/nix/store/9l96qllhbb6xrsjaai76dn74ap7rq92n-nix-2.7.0";
}
diff --git a/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix b/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
index 8aedce2fb49c..b4a94f62ad93 100644
--- a/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
+++ b/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix
@@ -25,4 +25,7 @@ pkgs.runCommand "nixos-build-vms" { nativeBuildInputs = [ pkgs.makeWrapper ]; }
ln -s ${interactiveDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
wrapProgram $out/bin/nixos-test-driver \
--add-flags "--interactive"
+ wrapProgram $out/bin/nixos-run-vms \
+ --set testScript "${pkgs.writeText "start-all" "start_all(); join_all();"}" \
+ --add-flags "--no-interactive"
''
diff --git a/nixos/modules/installer/tools/nixos-enter.sh b/nixos/modules/installer/tools/nixos-enter.sh
index 115b3d7a7c5e..89beeee7cf9e 100644
--- a/nixos/modules/installer/tools/nixos-enter.sh
+++ b/nixos/modules/installer/tools/nixos-enter.sh
@@ -63,32 +63,32 @@ mount --rbind /sys "$mountPoint/sys"
# modified from https://github.com/archlinux/arch-install-scripts/blob/bb04ab435a5a89cd5e5ee821783477bc80db797f/arch-chroot.in#L26-L52
chroot_add_resolv_conf() {
- local chrootdir=$1 resolv_conf=$1/etc/resolv.conf
+ local chrootDir="$1" resolvConf="$1/etc/resolv.conf"
[[ -e /etc/resolv.conf ]] || return 0
# Handle resolv.conf as a symlink to somewhere else.
- if [[ -L $chrootdir/etc/resolv.conf ]]; then
+ if [[ -L "$resolvConf" ]]; then
# readlink(1) should always give us *something* since we know at this point
# it's a symlink. For simplicity, ignore the case of nested symlinks.
- # We also ignore the possibility if `../`s escaping the root.
- resolv_conf=$(readlink "$chrootdir/etc/resolv.conf")
- if [[ $resolv_conf = /* ]]; then
- resolv_conf=$chrootdir$resolv_conf
+ # We also ignore the possibility of `../`s escaping the root.
+ resolvConf="$(readlink "$resolvConf")"
+ if [[ "$resolvConf" = /* ]]; then
+ resolvConf="$chrootDir$resolvConf"
else
- resolv_conf=$chrootdir/etc/$resolv_conf
+ resolvConf="$chrootDir/etc/$resolvConf"
fi
fi
# ensure file exists to bind mount over
- if [[ ! -f $resolv_conf ]]; then
- install -Dm644 /dev/null "$resolv_conf" || return 1
+ if [[ ! -f "$resolvConf" ]]; then
+ install -Dm644 /dev/null "$resolvConf" || return 1
fi
- mount --bind /etc/resolv.conf "$resolv_conf"
+ mount --bind /etc/resolv.conf "$resolvConf"
}
-chroot_add_resolv_conf "$mountPoint" || print "ERROR: failed to set up resolv.conf"
+chroot_add_resolv_conf "$mountPoint" || echo "$0: failed to set up resolv.conf" >&2
(
# If silent, write both stdout and stderr of activation script to /dev/null
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index fe8c4fb1a6b5..fb5d3ba47325 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -51,7 +51,9 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
$n++;
$rootDir = $ARGV[$n];
die "$0: ‘--root’ requires an argument\n" unless defined $rootDir;
+ die "$0: no need to specify `/` with `--root`, it is the default\n" if $rootDir eq "/";
$rootDir =~ s/\/*$//; # remove trailing slashes
+ $rootDir = File::Spec->rel2abs($rootDir); # resolve absolute path
}
elsif ($arg eq "--force") {
$force = 1;
@@ -279,7 +281,7 @@ if (`lsblk -o TYPE` =~ "lvm") {
push @initrdKernelModules, "dm-snapshot";
}
-my $virt = `systemd-detect-virt`;
+my $virt = `@detectvirt@`;
chomp $virt;
@@ -398,7 +400,7 @@ foreach my $fs (read_file("/proc/self/mountinfo")) {
# Maybe this is a bind-mount of a filesystem we saw earlier?
if (defined $fsByDev{$fields[2]}) {
# Make sure this isn't a btrfs subvolume.
- my $msg = `btrfs subvol show $rootDir$mountPoint`;
+ my $msg = `@btrfs@ subvol show $rootDir$mountPoint`;
if ($? != 0 || $msg =~ /ERROR:/s) {
my $path = $fields[3]; $path = "" if $path eq "/";
my $base = $fsByDev{$fields[2]};
@@ -436,7 +438,7 @@ EOF
# Is this a btrfs filesystem?
if ($fsType eq "btrfs") {
- my ($status, @info) = runCommand("btrfs subvol show $rootDir$mountPoint");
+ my ($status, @info) = runCommand("@btrfs@ subvol show $rootDir$mountPoint");
if ($status != 0 || join("", @info) =~ /ERROR:/) {
die "Failed to retrieve subvolume info for $mountPoint\n";
}
@@ -558,6 +560,8 @@ if (!$noFilesystems) {
$fsAndSwap .= "swapDevices =" . multiLineList(" ", @swapDevices) . ";\n";
}
+my $networkingDhcpConfig = generateNetworkingDhcpConfig();
+
my $hwConfig = <rel2abs($outDir);
+ $outDir =~ s/\/*$//; # remove trailing slashes
+ }
my $fn = "$outDir/hardware-configuration.nix";
print STDERR "writing $fn...\n";
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index 2f3b0cdd48f2..2e088b977710 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -33,8 +33,9 @@ let
nixos-generate-config = makeProg {
name = "nixos-generate-config";
src = ./nixos-generate-config.pl;
- path = lib.optionals (lib.elem "btrfs" config.boot.supportedFilesystems) [ pkgs.btrfs-progs ];
perl = "${pkgs.perl.withPackages (p: [ p.FileSlurp ])}/bin/perl";
+ detectvirt = "${pkgs.systemd}/bin/systemd-detect-virt";
+ btrfs = "${pkgs.btrfs-progs}/bin/btrfs";
inherit (config.system.nixos-generate-config) configuration desktopConfiguration;
xserverEnabled = config.services.xserver.enable;
};
@@ -116,7 +117,7 @@ in
'';
};
- config = lib.mkIf (!config.system.disableInstallerTools) {
+ config = lib.mkIf (config.nix.enable && !config.system.disableInstallerTools) {
system.nixos-generate-config.configuration = mkDefault ''
# Edit this configuration file to define what should be installed on
@@ -133,12 +134,13 @@ in
$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";
- $networkingDhcpConfig
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password\@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
@@ -148,6 +150,7 @@ in
# console = {
# font = "Lat2-Terminus16";
# keyMap = "us";
+ # useXkbConfig = true; # use xkbOptions in tty.
# };
$xserverConfig
@@ -155,7 +158,10 @@ in
$desktopConfiguration
# Configure keymap in X11
# services.xserver.layout = "us";
- # services.xserver.xkbOptions = "eurosign:e";
+ # services.xserver.xkbOptions = {
+ # "eurosign:e";
+ # "caps:escape" # map caps to escape.
+ # };
# Enable CUPS to print documents.
# services.printing.enable = true;
diff --git a/nixos/modules/installer/virtualbox-demo.nix b/nixos/modules/installer/virtualbox-demo.nix
index 2768e17590b3..27a7651382b2 100644
--- a/nixos/modules/installer/virtualbox-demo.nix
+++ b/nixos/modules/installer/virtualbox-demo.nix
@@ -25,7 +25,7 @@ with lib;
installer.cloneConfigExtra = ''
# Let demo build as a trusted user.
- # nix.trustedUsers = [ "demo" ];
+ # nix.settings.trusted-users = [ "demo" ];
# Mount a VirtualBox shared folder.
# This is configurable in the VirtualBox menu at
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index 2afa43a3fe71..9304c307af2f 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -61,85 +61,17 @@ let
in scrubbedEval.options;
baseOptionsJSON =
let
- filterIntoStore =
+ filter =
builtins.filterSource
(n: t:
(t == "directory" -> baseNameOf n != "tests")
&& (t == "file" -> hasSuffix ".nix" n)
);
-
- # Figure out if Nix runs in pure evaluation mode. May return true in
- # impure mode, but this is highly unlikely.
- # We need to know because of https://github.com/NixOS/nix/issues/1888
- # and https://github.com/NixOS/nix/issues/5868
- isPureEval = builtins.getEnv "PATH" == "" && builtins.getEnv "_" == "";
-
- # Return a nixpkgs subpath with minimal copying.
- #
- # The sources for the base options json derivation can come in one of
- # two forms:
- # - single source: a store path with all of nixpkgs, postfix with
- # subpaths to access various directories. This has the benefit of
- # not creating copies of these subtrees in the Nix store, but
- # can cause unnecessary rebuilds if you update the Nixpkgs `pkgs`
- # tree often.
- # - split sources: multiple store paths with subdirectories of
- # nixpkgs that exclude the bulk of the pkgs directory.
- # This requires more copying and hashing during evaluation but
- # requires fewer files to be copied. This method produces fewer
- # unnecessary rebuilds of the base options json.
- #
- # Flake
- #
- # Flakes always put a copy of the full nixpkgs sources in the store,
- # so we can use the "single source" method. This method is ideal
- # for using nixpkgs as a dependency, as the base options json will be
- # substitutable from cache.nixos.org.
- #
- # This requires that the `self.outPath` is wired into `pkgs` correctly,
- # which is done for you if `pkgs` comes from the `lib.nixosSystem` or
- # `legacyPackages` flake attributes.
- #
- # Other Nixpkgs invocation
- #
- # If you do not use the known-correct flake attributes, but rather
- # invoke Nixpkgs yourself, set `config.path` to the correct path value,
- # e.g. `import nixpkgs { config.path = nixpkgs; }`.
- #
- # Choosing between single or split source paths
- #
- # We make assumptions based on the type and contents of `pkgs.path`.
- # By passing a different `config.path` to Nixpkgs, you can influence
- # how your documentation cache is evaluated and rebuilt.
- #
- # Single source
- # - If pkgs.path is a string containing a store path, the code has no
- # choice but to create this store path, if it hasn't already been.
- # We assume that the "single source" method is most efficient.
- # - If pkgs.path is a path value containing that is a store path,
- # we try to convert it to a string with context without copying.
- # This occurs for example when nixpkgs was fetched and using its
- # default `config.path`, which is `./.`.
- # Nix currently does not allow this conversion when evaluating in
- # pure mode. If the conversion is not possible, we use the
- # "split source" method.
- #
- # Split source
- # - If pkgs.path is a path value that is not a store path, we assume
- # that it's unlikely for all of nixpkgs to end up in the store for
- # other reasons and try to keep both the copying and rebuilds low.
- pull =
- if builtins.typeOf pkgs.path == "string" && isStorePath pkgs.path then
- dir: "${pkgs.path}/${dir}"
- else if !isPureEval && isStorePath pkgs.path then
- dir: "${builtins.storePath pkgs.path}/${dir}"
- else
- dir: filterIntoStore "${toString pkgs.path}/${dir}";
in
pkgs.runCommand "lazy-options.json" {
- libPath = pull "lib";
- pkgsLibPath = pull "pkgs/pkgs-lib";
- nixosPath = pull "nixos";
+ libPath = filter "${toString pkgs.path}/lib";
+ pkgsLibPath = filter "${toString pkgs.path}/pkgs/pkgs-lib";
+ nixosPath = filter "${toString pkgs.path}/nixos";
modules = map (p: ''"${removePrefix "${modulesPath}/" (toString p)}"'') docModules.lazy;
} ''
export NIX_STORE_DIR=$TMPDIR/store
@@ -197,7 +129,7 @@ let
genericName = "View NixOS documentation in a web browser";
icon = "nix-snowflake";
exec = "nixos-help";
- categories = "System";
+ categories = ["System"];
};
in pkgs.symlinkJoin {
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 9d620084308b..7d1faa50f4bf 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -82,14 +82,14 @@ in
git = 41;
#fourstore = 42; # dropped in 20.03
#fourstorehttp = 43; # dropped in 20.03
- virtuoso = 44;
+ #virtuoso = 44; dropped module
#rtkit = 45; # dynamically allocated 2021-09-03
dovecot2 = 46;
dovenull2 = 47;
prayer = 49;
mpd = 50;
clamav = 51;
- fprot = 52;
+ #fprot = 52; # unused
# bind = 53; #dynamically allocated as of 2021-09-03
wwwrun = 54;
#adm = 55; # unused
@@ -412,7 +412,7 @@ in
prayer = 49;
mpd = 50;
clamav = 51;
- fprot = 52;
+ #fprot = 52; # unused
#bind = 53; # unused
wwwrun = 54;
adm = 55;
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index 66a49b0b888f..204a89143008 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -183,7 +183,11 @@ in
pruneNames = mkOption {
type = listOf str;
- default = [ ".bzr" ".cache" ".git" ".hg" ".svn" ];
+ default = lib.optionals (!isFindutils) [ ".bzr" ".cache" ".git" ".hg" ".svn" ];
+ defaultText = literalDocBook ''
+ [ ".bzr" ".cache" ".git" ".hg" ".svn" ], if
+ supported by the locate implementation (i.e. mlocate or plocate).
+ '';
description = ''
Directory components which should exclude paths containing them from indexing
'';
diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix
index 14dd1d816dbe..69967c8a7601 100644
--- a/nixos/modules/misc/nixpkgs.nix
+++ b/nixos/modules/misc/nixpkgs.nix
@@ -59,8 +59,6 @@ let
inherit (cfg) config overlays localSystem crossSystem;
};
- # NOTE: flake.nix assumes that nixpkgs.config is only used with ../../..
- # as nixpkgs.config.path should be equivalent to ../../..
finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs;
in
diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix
index 6c526f6d4f2d..d825f4beb301 100644
--- a/nixos/modules/misc/version.nix
+++ b/nixos/modules/misc/version.nix
@@ -1,12 +1,21 @@
{ config, lib, options, pkgs, ... }:
-with lib;
-
let
cfg = config.system.nixos;
opt = options.system.nixos;
-in
+ inherit (lib)
+ concatStringsSep mapAttrsToList toLower
+ literalExpression mkRenamedOptionModule mkDefault mkOption trivial types;
+
+ needsEscaping = s: null != builtins.match "[a-zA-Z0-9]+" s;
+ escapeIfNeccessary = s: if needsEscaping s then s else ''"${lib.escape [ "\$" "\"" "\\" "\`" ] s}"'';
+ attrsToText = attrs:
+ concatStringsSep "\n" (
+ mapAttrsToList (n: v: ''${n}=${escapeIfNeccessary (toString v)}'') attrs
+ );
+
+in
{
imports = [
(mkRenamedOptionModule [ "system" "nixosVersion" ] [ "system" "nixos" "version" ])
@@ -101,22 +110,30 @@ in
# Generate /etc/os-release. See
# https://www.freedesktop.org/software/systemd/man/os-release.html for the
# format.
- environment.etc.os-release.text =
- ''
- NAME=NixOS
- ID=nixos
- VERSION="${cfg.release} (${cfg.codeName})"
- VERSION_CODENAME=${toLower cfg.codeName}
- VERSION_ID="${cfg.release}"
- BUILD_ID="${cfg.version}"
- PRETTY_NAME="NixOS ${cfg.release} (${cfg.codeName})"
- LOGO="nix-snowflake"
- HOME_URL="https://nixos.org/"
- DOCUMENTATION_URL="https://nixos.org/learn.html"
- SUPPORT_URL="https://nixos.org/community.html"
- BUG_REPORT_URL="https://github.com/NixOS/nixpkgs/issues"
- '';
+ environment.etc = {
+ "lsb-release".text = attrsToText {
+ LSB_VERSION = "${cfg.release} (${cfg.codeName})";
+ DISTRIB_ID = "nixos";
+ DISTRIB_RELEASE = cfg.release;
+ DISTRIB_CODENAME = toLower cfg.codeName;
+ DISTRIB_DESCRIPTION = "NixOS ${cfg.release} (${cfg.codeName})";
+ };
+ "os-release".text = attrsToText {
+ NAME = "NixOS";
+ ID = "nixos";
+ VERSION = "${cfg.release} (${cfg.codeName})";
+ VERSION_CODENAME = toLower cfg.codeName;
+ VERSION_ID = cfg.release;
+ BUILD_ID = cfg.version;
+ PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})";
+ LOGO = "nix-snowflake";
+ HOME_URL = "https://nixos.org/";
+ DOCUMENTATION_URL = "https://nixos.org/learn.html";
+ SUPPORT_URL = "https://nixos.org/community.html";
+ BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues";
+ };
+ };
};
# uses version info nixpkgs, which requires a full nixpkgs path
diff --git a/nixos/modules/misc/wordlist.nix b/nixos/modules/misc/wordlist.nix
new file mode 100644
index 000000000000..988b522d7431
--- /dev/null
+++ b/nixos/modules/misc/wordlist.nix
@@ -0,0 +1,59 @@
+{ 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
+ '';
+in
+{
+ options = {
+ environment.wordlist = {
+ enable = mkEnableOption "environment variables for lists of words";
+
+ lists = mkOption {
+ type = types.attrsOf (types.nonEmptyListOf types.path);
+
+ default = {
+ WORDLIST = [ "${pkgs.scowl}/share/dict/words.txt" ];
+ };
+
+ defaultText = literalExpression ''
+ {
+ WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ];
+ }
+ '';
+
+ description = ''
+ A set with the key names being the environment variable you'd like to
+ set and the values being a list of paths to text documents containing
+ lists of words. The various files will be merged, sorted, duplicates
+ removed, and extraneous spacing removed.
+
+ If you have a handful of words that you want to add to an already
+ existing wordlist, you may find `builtins.toFile` useful for this
+ task.
+ '';
+
+ example = literalExpression ''
+ {
+ WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ];
+ AUGMENTED_WORDLIST = [
+ "''${pkgs.scowl}/share/dict/words.txt"
+ "''${pkgs.scowl}/share/dict/words.variants.txt"
+ (builtins.toFile "extra-words" '''
+ desynchonization
+ oobleck''')
+ ];
+ }
+ '';
+ };
+ };
+ };
+
+ config = mkIf config.environment.wordlist.enable {
+ environment.variables =
+ lib.mapAttrs
+ (name: value: "${concatAndSort "wordlist-${name}" value}")
+ config.environment.wordlist.lists;
+ };
+}
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 4b2cb803e20e..adeddbf139a3 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -91,6 +91,7 @@
./hardware/video/switcheroo-control.nix
./hardware/video/uvcvideo/default.nix
./hardware/video/webcam/facetimehd.nix
+ ./hardware/xone.nix
./hardware/xpadneo.nix
./i18n/input-method/default.nix
./i18n/input-method/fcitx.nix
@@ -115,7 +116,10 @@
./misc/nixpkgs.nix
./misc/passthru.nix
./misc/version.nix
+ ./misc/wordlist.nix
./misc/nixops-autoluks.nix
+ ./programs/_1password.nix
+ ./programs/_1password-gui.nix
./programs/adb.nix
./programs/appgate-sdp.nix
./programs/atop.nix
@@ -166,6 +170,8 @@
./programs/iftop.nix
./programs/iotop.nix
./programs/java.nix
+ ./programs/k40-whisperer.nix
+ ./programs/kclock.nix
./programs/kdeconnect.nix
./programs/kbdlight.nix
./programs/less.nix
@@ -176,8 +182,11 @@
./programs/msmtp.nix
./programs/mtr.nix
./programs/nano.nix
+ ./programs/nbd.nix
+ ./programs/nix-ld.nix
./programs/neovim.nix
./programs/nm-applet.nix
+ ./programs/nncp.nix
./programs/npm.nix
./programs/noisetorch.nix
./programs/oblogout.nix
@@ -203,7 +212,6 @@
./programs/sway.nix
./programs/system-config-printer.nix
./programs/thefuck.nix
- ./programs/tilp2.nix
./programs/tmux.nix
./programs/traceroute.nix
./programs/tsm-client.nix
@@ -253,6 +261,7 @@
./security/tpm2.nix
./services/admin/meshcentral.nix
./services/admin/oxidized.nix
+ ./services/admin/pgadmin.nix
./services/admin/salt/master.nix
./services/admin/salt/minion.nix
./services/amqp/activemq/default.nix
@@ -297,6 +306,7 @@
./services/backup/znapzend.nix
./services/blockchain/ethereum/geth.nix
./services/backup/zrepl.nix
+ ./services/cluster/corosync/default.nix
./services/cluster/hadoop/default.nix
./services/cluster/k3s/default.nix
./services/cluster/kubernetes/addons/dns.nix
@@ -309,6 +319,7 @@
./services/cluster/kubernetes/pki.nix
./services/cluster/kubernetes/proxy.nix
./services/cluster/kubernetes/scheduler.nix
+ ./services/cluster/pacemaker/default.nix
./services/cluster/spark/default.nix
./services/computing/boinc/client.nix
./services/computing/foldingathome/client.nix
@@ -350,14 +361,12 @@
./services/databases/redis.nix
./services/databases/riak.nix
./services/databases/victoriametrics.nix
- ./services/databases/virtuoso.nix
./services/desktops/accountsservice.nix
./services/desktops/bamf.nix
./services/desktops/blueman.nix
./services/desktops/cpupower-gui.nix
./services/desktops/dleyna-renderer.nix
./services/desktops/dleyna-server.nix
- ./services/desktops/pantheon/files.nix
./services/desktops/espanso.nix
./services/desktops/flatpak.nix
./services/desktops/geoclue2.nix
@@ -396,6 +405,7 @@
./services/development/jupyterhub/default.nix
./services/development/rstudio-server/default.nix
./services/development/lorri.nix
+ ./services/development/zammad.nix
./services/display-managers/greetd.nix
./services/editors/emacs.nix
./services/editors/infinoted.nix
@@ -452,6 +462,8 @@
./services/hardware/undervolt.nix
./services/hardware/vdr.nix
./services/hardware/xow.nix
+ ./services/home-automation/home-assistant.nix
+ ./services/home-automation/zigbee2mqtt.nix
./services/logging/SystemdJournal2Gelf.nix
./services/logging/awstats.nix
./services/logging/filebeat.nix
@@ -496,6 +508,7 @@
./services/mail/roundcube.nix
./services/mail/sympa.nix
./services/mail/nullmailer.nix
+ ./services/matrix/matrix-synapse.nix
./services/matrix/mjolnir.nix
./services/matrix/pantalaimon.nix
./services/misc/ananicy.nix
@@ -547,8 +560,8 @@
./services/misc/headphones.nix
./services/misc/heisenbridge.nix
./services/misc/greenclip.nix
- ./services/misc/home-assistant.nix
./services/misc/ihaskell.nix
+ ./services/misc/input-remapper.nix
./services/misc/irkerd.nix
./services/misc/jackett.nix
./services/misc/jellyfin.nix
@@ -562,7 +575,6 @@
./services/misc/matrix-appservice-discord.nix
./services/misc/matrix-appservice-irc.nix
./services/misc/matrix-conduit.nix
- ./services/misc/matrix-synapse.nix
./services/misc/mautrix-facebook.nix
./services/misc/mautrix-telegram.nix
./services/misc/mbpfan.nix
@@ -597,6 +609,7 @@
./services/misc/redmine.nix
./services/misc/rippled.nix
./services/misc/ripple-data-api.nix
+ ./services/misc/rmfakecloud.nix
./services/misc/serviio.nix
./services/misc/safeeyes.nix
./services/misc/sdrplay.nix
@@ -622,7 +635,6 @@
./services/misc/weechat.nix
./services/misc/xmr-stak.nix
./services/misc/xmrig.nix
- ./services/misc/zigbee2mqtt.nix
./services/misc/zoneminder.nix
./services/misc/zookeeper.nix
./services/monitoring/alerta.nix
@@ -684,6 +696,7 @@
./services/network-filesystems/litestream/default.nix
./services/network-filesystems/netatalk.nix
./services/network-filesystems/nfsd.nix
+ ./services/network-filesystems/moosefs.nix
./services/network-filesystems/openafs/client.nix
./services/network-filesystems/openafs/server.nix
./services/network-filesystems/orangefs/server.nix
@@ -717,6 +730,7 @@
./services/networking/bird.nix
./services/networking/bitlbee.nix
./services/networking/blockbook-frontend.nix
+ ./services/networking/blocky.nix
./services/networking/charybdis.nix
./services/networking/cjdns.nix
./services/networking/cntlm.nix
@@ -760,12 +774,13 @@
./services/networking/go-neb.nix
./services/networking/go-shadowsocks2.nix
./services/networking/gobgpd.nix
- ./services/networking/gogoclient.nix
./services/networking/gvpe.nix
./services/networking/hans.nix
./services/networking/haproxy.nix
+ ./services/networking/headscale.nix
./services/networking/hostapd.nix
./services/networking/htpdate.nix
+ ./services/networking/https-dns-proxy.nix
./services/networking/hylafax/default.nix
./services/networking/i2pd.nix
./services/networking/i2p.nix
@@ -812,6 +827,7 @@
./services/networking/nar-serve.nix
./services/networking/nat.nix
./services/networking/nats.nix
+ ./services/networking/nbd.nix
./services/networking/ndppd.nix
./services/networking/nebula.nix
./services/networking/networkmanager.nix
@@ -852,7 +868,6 @@
./services/networking/quassel.nix
./services/networking/quorum.nix
./services/networking/quicktun.nix
- ./services/networking/racoon.nix
./services/networking/radicale.nix
./services/networking/radvd.nix
./services/networking/rdnssd.nix
@@ -872,6 +887,7 @@
./services/networking/shorewall6.nix
./services/networking/shout.nix
./services/networking/sniproxy.nix
+ ./services/networking/snowflake-proxy.nix
./services/networking/smartdns.nix
./services/networking/smokeping.nix
./services/networking/softether.nix
@@ -896,6 +912,7 @@
./services/networking/tcpcrypt.nix
./services/networking/teamspeak3.nix
./services/networking/tedicross.nix
+ ./services/networking/tetrd.nix
./services/networking/teleport.nix
./services/networking/thelounge.nix
./services/networking/tinc.nix
@@ -915,6 +932,7 @@
./services/networking/vsftpd.nix
./services/networking/wasabibackend.nix
./services/networking/websockify.nix
+ ./services/networking/wg-netmanager.nix
./services/networking/wg-quick.nix
./services/networking/wireguard.nix
./services/networking/wpa_supplicant.nix
@@ -944,7 +962,6 @@
./services/security/clamav.nix
./services/security/fail2ban.nix
./services/security/fprintd.nix
- ./services/security/fprot.nix
./services/security/haka.nix
./services/security/haveged.nix
./services/security/hockeypuck.nix
@@ -977,6 +994,7 @@
./services/system/nscd.nix
./services/system/saslauthd.nix
./services/system/self-deploy.nix
+ ./services/system/systembus-notify.nix
./services/system/uptimed.nix
./services/torrent/deluge.nix
./services/torrent/flexget.nix
@@ -1006,6 +1024,7 @@
./services/web-apps/documize.nix
./services/web-apps/dokuwiki.nix
./services/web-apps/engelsystem.nix
+ ./services/web-apps/ethercalc.nix
./services/web-apps/fluidd.nix
./services/web-apps/galene.nix
./services/web-apps/gerrit.nix
@@ -1055,6 +1074,7 @@
./services/web-apps/wordpress.nix
./services/web-apps/youtrack.nix
./services/web-apps/zabbix.nix
+ ./services/web-servers/agate.nix
./services/web-servers/apache-httpd/default.nix
./services/web-servers/caddy/default.nix
./services/web-servers/darkhttpd.nix
@@ -1074,7 +1094,6 @@
./services/web-servers/phpfpm/default.nix
./services/web-servers/pomerium.nix
./services/web-servers/unit/default.nix
- ./services/web-servers/shellinabox.nix
./services/web-servers/tomcat.nix
./services/web-servers/traefik.nix
./services/web-servers/trafficserver/default.nix
@@ -1154,15 +1173,21 @@
./system/boot/stage-1.nix
./system/boot/stage-2.nix
./system/boot/systemd.nix
- ./system/boot/systemd-nspawn.nix
+ ./system/boot/systemd/coredump.nix
+ ./system/boot/systemd/journald.nix
+ ./system/boot/systemd/logind.nix
+ ./system/boot/systemd/nspawn.nix
+ ./system/boot/systemd/tmpfiles.nix
+ ./system/boot/systemd/user.nix
./system/boot/timesyncd.nix
./system/boot/tmp.nix
- ./system/etc/etc.nix
+ ./system/etc/etc-activation.nix
./tasks/auto-upgrade.nix
./tasks/bcache.nix
./tasks/cpu-freq.nix
./tasks/encrypted-devices.nix
./tasks/filesystems.nix
+ ./tasks/filesystems/apfs.nix
./tasks/filesystems/bcachefs.nix
./tasks/filesystems/btrfs.nix
./tasks/filesystems/cifs.nix
diff --git a/nixos/modules/profiles/hardened.nix b/nixos/modules/profiles/hardened.nix
index 3f8f78f012a7..856ee480fc0b 100644
--- a/nixos/modules/profiles/hardened.nix
+++ b/nixos/modules/profiles/hardened.nix
@@ -17,7 +17,7 @@ with lib;
boot.kernelPackages = mkDefault pkgs.linuxPackages_hardened;
- nix.allowedUsers = mkDefault [ "@users" ];
+ nix.settings.allowed-users = mkDefault [ "@users" ];
environment.memoryAllocator.provider = mkDefault "scudo";
environment.variables.SCUDO_OPTIONS = mkDefault "ZeroContents=1";
diff --git a/nixos/modules/programs/_1password-gui.nix b/nixos/modules/programs/_1password-gui.nix
new file mode 100644
index 000000000000..f57de44bb9e2
--- /dev/null
+++ b/nixos/modules/programs/_1password-gui.nix
@@ -0,0 +1,69 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.programs._1password-gui;
+
+in {
+ options = {
+ programs._1password-gui = {
+ enable = mkEnableOption "The 1Password Desktop application with browser integration";
+
+ groupId = mkOption {
+ type = types.int;
+ example = literalExpression "5000";
+ description = ''
+ The GroupID to assign to the onepassword group, which is needed for browser integration. The group ID must be 1000 or greater.
+ '';
+ };
+
+ polkitPolicyOwners = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = literalExpression "[\"user1\" \"user2\" \"user3\"]";
+ description = ''
+ A list of users who should be able to integrate 1Password with polkit-based authentication mechanisms. By default, no users will have such access.
+ '';
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs._1password-gui;
+ defaultText = literalExpression "pkgs._1password-gui";
+ example = literalExpression "pkgs._1password-gui";
+ description = ''
+ The 1Password derivation to use. This can be used to upgrade from the stable release that we keep in nixpkgs to the betas.
+ '';
+ };
+ };
+ };
+
+ config = let
+ package = cfg.package.override {
+ polkitPolicyOwners = cfg.polkitPolicyOwners;
+ };
+ in mkIf cfg.enable {
+ environment.systemPackages = [ package ];
+ users.groups.onepassword.gid = cfg.groupId;
+
+ security.wrappers = {
+ "1Password-BrowserSupport" =
+ { source = "${cfg.package}/share/1password/1Password-BrowserSupport";
+ owner = "root";
+ group = "onepassword";
+ setuid = false;
+ setgid = true;
+ };
+
+ "1Password-KeyringHelper" =
+ { source = "${cfg.package}/share/1password/1Password-KeyringHelper";
+ owner = "root";
+ group = "onepassword";
+ setuid = true;
+ setgid = true;
+ };
+ };
+
+ };
+}
diff --git a/nixos/modules/programs/_1password.nix b/nixos/modules/programs/_1password.nix
new file mode 100644
index 000000000000..eae518e61ca7
--- /dev/null
+++ b/nixos/modules/programs/_1password.nix
@@ -0,0 +1,46 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.programs._1password;
+in {
+ options = {
+ programs._1password = {
+ enable = mkEnableOption "The 1Password CLI tool with biometric unlock and integration with the 1Password GUI.";
+
+ groupId = mkOption {
+ type = types.int;
+ example = literalExpression "5001";
+ description = ''
+ The GroupID to assign to the onepassword-cli group, which is needed for integration with the 1Password GUI. The group ID must be 1000 or greater.
+ '';
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs._1password;
+ defaultText = literalExpression "pkgs._1password";
+ example = literalExpression "pkgs._1password";
+ description = ''
+ The 1Password CLI derivation to use.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment.systemPackages = [ cfg.package ];
+ users.groups.onepassword-cli.gid = cfg.groupId;
+
+ security.wrappers = {
+ "op" = {
+ source = "${cfg.package}/bin/op";
+ owner = "root";
+ group = "onepassword-cli";
+ setuid = false;
+ setgid = true;
+ };
+ };
+ };
+}
diff --git a/nixos/modules/programs/calls.nix b/nixos/modules/programs/calls.nix
index 59961625e5d9..08a223b408d4 100644
--- a/nixos/modules/programs/calls.nix
+++ b/nixos/modules/programs/calls.nix
@@ -14,6 +14,8 @@ in {
};
config = mkIf cfg.enable {
+ programs.dconf.enable = true;
+
environment.systemPackages = [
pkgs.calls
];
diff --git a/nixos/modules/programs/captive-browser.nix b/nixos/modules/programs/captive-browser.nix
index dc054504ea48..aad554c2bd66 100644
--- a/nixos/modules/programs/captive-browser.nix
+++ b/nixos/modules/programs/captive-browser.nix
@@ -1,8 +1,12 @@
{ config, lib, pkgs, ... }:
-with lib;
let
cfg = config.programs.captive-browser;
+
+ inherit (lib)
+ concatStringsSep escapeShellArgs optionalString
+ literalExpression mkEnableOption mkIf mkOption mkOptionDefault types;
+
browserDefault = chromium: concatStringsSep " " [
''env XDG_CONFIG_HOME="$PREV_CONFIG_HOME"''
''${chromium}/bin/chromium''
@@ -15,6 +19,15 @@ let
''-no-default-browser-check''
''http://cache.nixos.org/''
];
+
+ desktopItem = pkgs.makeDesktopItem {
+ name = "captive-browser";
+ desktopName = "Captive Portal Browser";
+ exec = "/run/wrappers/bin/captive-browser";
+ icon = "nix-snowflake";
+ categories = [ "Network" ];
+ };
+
in
{
###### interface
@@ -84,6 +97,11 @@ in
###### implementation
config = mkIf cfg.enable {
+ environment.systemPackages = [
+ (pkgs.runCommandNoCC "captive-browser-desktop-item" { } ''
+ install -Dm444 -t $out/share/applications ${desktopItem}/share/applications/*.desktop
+ '')
+ ];
programs.captive-browser.dhcp-dns =
let
diff --git a/nixos/modules/programs/command-not-found/command-not-found.pl b/nixos/modules/programs/command-not-found/command-not-found.pl
index 220d057b7f4f..72e246c81ae9 100644
--- a/nixos/modules/programs/command-not-found/command-not-found.pl
+++ b/nixos/modules/programs/command-not-found/command-not-found.pl
@@ -21,11 +21,24 @@ my $res = $dbh->selectall_arrayref(
"select package from Programs where system = ? and name = ?",
{ Slice => {} }, $system, $program);
-if (!defined $res || scalar @$res == 0) {
+my $len = !defined $res ? 0 : scalar @$res;
+
+if ($len == 0) {
print STDERR "$program: command not found\n";
-} elsif (scalar @$res == 1) {
+} elsif ($len == 1) {
my $package = @$res[0]->{package};
if ($ENV{"NIX_AUTO_RUN"} // "") {
+ if ($ENV{"NIX_AUTO_RUN_INTERACTIVE"} // "") {
+ while (1) {
+ print STDERR "'$program' from package '$package' will be run, confirm? [yn]: ";
+ chomp(my $comfirm = );
+ if (lc $comfirm eq "n") {
+ exit 0;
+ } elsif (lc $comfirm eq "y") {
+ last;
+ }
+ }
+ }
exec("nix-shell", "-p", $package, "--run", shell_quote("exec", @ARGV));
} else {
print STDERR <{package}\n";
+ }
+ my $choice = 0;
+ while (1) { # exec will break this loop
+ no warnings "numeric";
+ print STDERR "Your choice [1-${len}]: ";
+ # 0 can be invalid user input like non-number string
+ # so we start from 1
+ $choice = + 0;
+ if (1 <= $choice && $choice <= $len) {
+ exec("nix-shell", "-p", @$res[$choice - 1]->{package},
+ "--run", shell_quote("exec", @ARGV));
+ }
+ }
+ } else {
+ print STDERR <{package}\n" foreach @$res;
+ print STDERR " nix-shell -p $_->{package}\n" foreach @$res;
+ }
}
exit 127;
diff --git a/nixos/modules/programs/dconf.nix b/nixos/modules/programs/dconf.nix
index 298abac8afa9..265c41cbbbc9 100644
--- a/nixos/modules/programs/dconf.nix
+++ b/nixos/modules/programs/dconf.nix
@@ -60,7 +60,7 @@ in
environment.systemPackages = [ pkgs.dconf ];
# Needed for unwrapped applications
- environment.variables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.dconf.lib}/lib/gio/modules" ];
+ environment.sessionVariables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.dconf.lib}/lib/gio/modules" ];
};
}
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
index d552c751afd7..a448727be778 100644
--- a/nixos/modules/programs/environment.nix
+++ b/nixos/modules/programs/environment.nix
@@ -40,13 +40,15 @@ in
KDEDIRS = [ "" ];
QT_PLUGIN_PATH = [ "/lib/qt4/plugins" "/lib/kde4/plugins" ];
QTWEBKIT_PLUGIN_PATH = [ "/lib/mozilla/plugins/" ];
- GTK_PATH = [ "/lib/gtk-2.0" "/lib/gtk-3.0" ];
+ GTK_PATH = [ "/lib/gtk-2.0" "/lib/gtk-3.0" "/lib/gtk-4.0" ];
XDG_CONFIG_DIRS = [ "/etc/xdg" ];
XDG_DATA_DIRS = [ "/share" ];
MOZ_PLUGIN_PATH = [ "/lib/mozilla/plugins" ];
LIBEXEC_PATH = [ "/lib/libexec" ];
};
+ environment.pathsToLink = [ "/lib/gtk-2.0" "/lib/gtk-3.0" "/lib/gtk-4.0" ];
+
environment.extraInit =
''
unset ASPELL_CONF
diff --git a/nixos/modules/programs/firejail.nix b/nixos/modules/programs/firejail.nix
index 8c10d7c4df39..76b42168c198 100644
--- a/nixos/modules/programs/firejail.nix
+++ b/nixos/modules/programs/firejail.nix
@@ -17,8 +17,8 @@ let
then value
else { executable = value; profile = null; extraArgs = []; };
args = lib.escapeShellArgs (
- (optional (opts.profile != null) "--profile=${toString opts.profile}")
- ++ opts.extraArgs
+ opts.extraArgs
+ ++ (optional (opts.profile != null) "--profile=${toString opts.profile}")
);
in
''
diff --git a/nixos/modules/programs/k40-whisperer.nix b/nixos/modules/programs/k40-whisperer.nix
new file mode 100644
index 000000000000..3163e45f57e4
--- /dev/null
+++ b/nixos/modules/programs/k40-whisperer.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.programs.k40-whisperer;
+ pkg = cfg.package.override {
+ udevGroup = cfg.group;
+ };
+in
+{
+ options.programs.k40-whisperer = {
+ enable = mkEnableOption "K40-Whisperer";
+
+ group = mkOption {
+ type = types.str;
+ description = ''
+ Group assigned to the device when connected.
+ '';
+ default = "k40";
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.k40-whisperer;
+ defaultText = literalExpression "pkgs.k40-whisperer";
+ example = literalExpression "pkgs.k40-whisperer";
+ description = ''
+ K40 Whisperer package to use.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ users.groups.${cfg.group} = {};
+
+ environment.systemPackages = [ pkg ];
+ services.udev.packages = [ pkg ];
+ };
+}
diff --git a/nixos/modules/programs/kclock.nix b/nixos/modules/programs/kclock.nix
new file mode 100644
index 000000000000..42d81d2798ba
--- /dev/null
+++ b/nixos/modules/programs/kclock.nix
@@ -0,0 +1,13 @@
+{ lib, pkgs, config, ... }:
+with lib;
+let
+ cfg = config.programs.kclock;
+ kclockPkg = pkgs.libsForQt5.kclock;
+in {
+ options.programs.kclock = { enable = mkEnableOption "Enable KClock"; };
+
+ config = mkIf cfg.enable {
+ services.dbus.packages = [ kclockPkg ];
+ environment.systemPackages = [ kclockPkg ];
+ };
+}
diff --git a/nixos/modules/programs/nbd.nix b/nixos/modules/programs/nbd.nix
new file mode 100644
index 000000000000..fea9bc1ff71a
--- /dev/null
+++ b/nixos/modules/programs/nbd.nix
@@ -0,0 +1,19 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.programs.nbd;
+in
+{
+ options = {
+ programs.nbd = {
+ enable = mkEnableOption "Network Block Device (nbd) support";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment.systemPackages = with pkgs; [ nbd ];
+ boot.kernelModules = [ "nbd" ];
+ };
+}
diff --git a/nixos/modules/programs/nix-ld.nix b/nixos/modules/programs/nix-ld.nix
new file mode 100644
index 000000000000..810a74ab50b7
--- /dev/null
+++ b/nixos/modules/programs/nix-ld.nix
@@ -0,0 +1,12 @@
+{ pkgs, lib, config, ... }:
+{
+ meta.maintainers = [ lib.maintainers.mic92 ];
+ options = {
+ programs.nix-ld.enable = lib.mkEnableOption ''nix-ld, Documentation: '';
+ };
+ config = lib.mkIf config.programs.nix-ld.enable {
+ systemd.tmpfiles.rules = [
+ "L+ ${pkgs.nix-ld.ldPath} - - - - ${pkgs.nix-ld}/libexec/nix-ld"
+ ];
+ };
+}
diff --git a/nixos/modules/programs/nncp.nix b/nixos/modules/programs/nncp.nix
new file mode 100644
index 000000000000..29a703eadf10
--- /dev/null
+++ b/nixos/modules/programs/nncp.nix
@@ -0,0 +1,101 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ nncpCfgFile = "/run/nncp.hjson";
+ programCfg = config.programs.nncp;
+ settingsFormat = pkgs.formats.json { };
+ jsonCfgFile = settingsFormat.generate "nncp.json" programCfg.settings;
+ pkg = programCfg.package;
+in {
+ options.programs.nncp = {
+
+ enable =
+ mkEnableOption "NNCP (Node to Node copy) utilities and configuration";
+
+ group = mkOption {
+ type = types.str;
+ default = "uucp";
+ description = ''
+ The group under which NNCP files shall be owned.
+ Any member of this group may access the secret keys
+ of this NNCP node.
+ '';
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.nncp;
+ defaultText = literalExpression "pkgs.nncp";
+ description = "The NNCP package to use system-wide.";
+ };
+
+ secrets = mkOption {
+ type = with types; listOf str;
+ example = [ "/run/keys/nncp.hjson" ];
+ description = ''
+ A list of paths to NNCP configuration files that should not be
+ in the Nix store. These files are layered on top of the values at
+ .
+ '';
+ };
+
+ settings = mkOption {
+ type = settingsFormat.type;
+ description = ''
+ NNCP configuration, see
+ .
+ At runtime these settings will be overlayed by the contents of
+ into the file
+ ${nncpCfgFile}. Node keypairs go in
+ secrets, do not specify them in
+ settings as they will be leaked into
+ /nix/store!
+ '';
+ default = { };
+ };
+
+ };
+
+ config = mkIf programCfg.enable {
+
+ environment = {
+ systemPackages = [ pkg ];
+ etc."nncp.hjson".source = nncpCfgFile;
+ };
+
+ programs.nncp.settings = {
+ spool = mkDefault "/var/spool/nncp";
+ log = mkDefault "/var/spool/nncp/log";
+ };
+
+ systemd.tmpfiles.rules = [
+ "d ${programCfg.settings.spool} 0770 root ${programCfg.group}"
+ "f ${programCfg.settings.log} 0770 root ${programCfg.group}"
+ ];
+
+ systemd.services.nncp-config = {
+ path = [ pkg ];
+ description = "Generate NNCP configuration";
+ wantedBy = [ "basic.target" ];
+ serviceConfig.Type = "oneshot";
+ script = ''
+ umask u=rw
+ nncpCfgDir=$(mktemp --directory nncp.XXX)
+ for f in ${jsonCfgFile} ${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
+ chgrp ${programCfg.group} ${nncpCfgFile}
+ chmod g+r ${nncpCfgFile}
+ '';
+ };
+ };
+
+ meta.maintainers = with lib.maintainers; [ ehmry ];
+}
diff --git a/nixos/modules/programs/phosh.nix b/nixos/modules/programs/phosh.nix
index cba3f73768ec..ad875616ac9e 100644
--- a/nixos/modules/programs/phosh.nix
+++ b/nixos/modules/programs/phosh.nix
@@ -8,18 +8,17 @@ let
# Based on https://source.puri.sm/Librem5/librem5-base/-/blob/4596c1056dd75ac7f043aede07887990fd46f572/default/sm.puri.OSK0.desktop
oskItem = pkgs.makeDesktopItem {
name = "sm.puri.OSK0";
- type = "Application";
desktopName = "On-screen keyboard";
exec = "${pkgs.squeekboard}/bin/squeekboard";
- categories = "GNOME;Core;";
- extraEntries = ''
- OnlyShowIn=GNOME;
- NoDisplay=true
- X-GNOME-Autostart-Phase=Panel
- X-GNOME-Provides=inputmethod
- X-GNOME-Autostart-Notify=true
- X-GNOME-AutoRestart=true
- '';
+ categories = [ "GNOME" "Core" ];
+ onlyShowIn = [ "GNOME" ];
+ noDisplay = true;
+ extraConfig = {
+ X-GNOME-Autostart-Phase = "Panel";
+ X-GNOME-Provides = "inputmethod";
+ X-GNOME-Autostart-Notify = "true";
+ X-GNOME-AutoRestart = "true";
+ };
};
phocConfigType = types.submodule {
diff --git a/nixos/modules/programs/spacefm.nix b/nixos/modules/programs/spacefm.nix
index 822fca3ecec7..f71abcaa3325 100644
--- a/nixos/modules/programs/spacefm.nix
+++ b/nixos/modules/programs/spacefm.nix
@@ -27,13 +27,11 @@ in
default = {
tmp_dir = "/tmp";
terminal_su = "${pkgs.sudo}/bin/sudo";
- graphical_su = "${pkgs.gksu}/bin/gksu";
};
defaultText = literalExpression ''
{
tmp_dir = "/tmp";
terminal_su = "''${pkgs.sudo}/bin/sudo";
- graphical_su = "''${pkgs.gksu}/bin/gksu";
}
'';
description = ''
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index bb9904d19560..01b047281344 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -134,6 +134,7 @@ in {
'';
};
};
+ security.polkit.enable = true;
security.pam.services.swaylock = {};
hardware.opengl.enable = mkDefault true;
fonts.enableDefaultFonts = mkDefault true;
diff --git a/nixos/modules/programs/tilp2.nix b/nixos/modules/programs/tilp2.nix
deleted file mode 100644
index da9e32e3e6c6..000000000000
--- a/nixos/modules/programs/tilp2.nix
+++ /dev/null
@@ -1,28 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with lib;
-
-let
- cfg = config.programs.tilp2;
-
-in {
- options.programs.tilp2 = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enable tilp2 and udev rules for supported calculators.
- '';
- };
- };
-
- config = mkIf cfg.enable {
- services.udev.packages = [
- pkgs.libticables2
- ];
-
- environment.systemPackages = [
- pkgs.tilp2
- ];
- };
-}
diff --git a/nixos/modules/programs/tmux.nix b/nixos/modules/programs/tmux.nix
index c39908751d29..74b3fbd9ac06 100644
--- a/nixos/modules/programs/tmux.nix
+++ b/nixos/modules/programs/tmux.nix
@@ -52,6 +52,12 @@ let
set -s escape-time ${toString cfg.escapeTime}
set -g history-limit ${toString cfg.historyLimit}
+ ${lib.optionalString (cfg.plugins != []) ''
+ # Run plugins
+ ${lib.concatMapStringsSep "\n" (x: "run-shell ${x.rtp}") cfg.plugins}
+
+ ''}
+
${cfg.extraConfig}
'';
@@ -165,6 +171,13 @@ in {
downside it doesn't survive user logout.
'';
};
+
+ plugins = mkOption {
+ default = [];
+ type = types.listOf types.package;
+ description = "List of plugins to install.";
+ example = lib.literalExpression "[ pkgs.tmuxPlugins.nord ]";
+ };
};
};
@@ -174,7 +187,7 @@ in {
environment = {
etc."tmux.conf".text = tmuxConf;
- systemPackages = [ pkgs.tmux ];
+ systemPackages = [ pkgs.tmux ] ++ cfg.plugins;
variables = {
TMUX_TMPDIR = lib.optional cfg.secureSocket ''''${XDG_RUNTIME_DIR:-"/run/user/$(id -u)"}'';
diff --git a/nixos/modules/programs/zsh/zsh-autosuggestions.nix b/nixos/modules/programs/zsh/zsh-autosuggestions.nix
index fee324cc7326..2e53e907d547 100644
--- a/nixos/modules/programs/zsh/zsh-autosuggestions.nix
+++ b/nixos/modules/programs/zsh/zsh-autosuggestions.nix
@@ -22,17 +22,18 @@ in
};
strategy = mkOption {
- type = types.enum [ "history" "match_prev_cmd" ];
- default = "history";
+ type = types.listOf (types.enum [ "history" "completion" "match_prev_cmd" ]);
+ default = [ "history" ];
description = ''
- Set ZSH_AUTOSUGGEST_STRATEGY to choose the strategy for generating suggestions.
- There are currently two to choose from:
+ `ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated.
+ The strategies in the array are tried successively until a suggestion is found.
+ There are currently three built-in strategies to choose from:
- * history: Chooses the most recent match.
- * match_prev_cmd: Chooses the most recent match whose preceding history item matches
- the most recently executed command (more info). Note that this strategy won't work as
- expected with ZSH options that don't preserve the history order such as
- HIST_IGNORE_ALL_DUPS or HIST_EXPIRE_DUPS_FIRST.
+ - `history`: Chooses the most recent match from history.
+ - `completion`: Chooses a suggestion based on what tab-completion would suggest. (requires `zpty` module)
+ - `match_prev_cmd`: Like `history`, but chooses the most recent match whose preceding history item matches
+ the most recently executed command. Note that this strategy won't work as expected with ZSH options that
+ don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`.
'';
};
@@ -62,7 +63,7 @@ in
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.highlightStyle}"
- export ZSH_AUTOSUGGEST_STRATEGY=("${cfg.strategy}")
+ export ZSH_AUTOSUGGEST_STRATEGY=(${concatStringsSep " " cfg.strategy})
${optionalString (!cfg.async) "unset ZSH_AUTOSUGGEST_USE_ASYNC"}
${concatStringsSep "\n" (mapAttrsToList (key: value: ''export ${key}="${value}"'') cfg.extraConfig)}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index b9a2f47f3f5a..195cf87e6a85 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -32,6 +32,7 @@ with lib;
'')
(mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.")
(mkRemovedOptionModule [ "networking" "wicd" ] "The corresponding package was removed from nixpkgs.")
+ (mkRemovedOptionModule [ "programs" "tilp2" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " +
"https://way-cooler.org/blog/2020/01/09/way-cooler-post-mortem.html"))
(mkRemovedOptionModule [ "security" "hideProcessInformation" ] ''
@@ -49,6 +50,7 @@ with lib;
(mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.")
(mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed")
(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" "kippo" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "mailpile" ] "The corresponding package was removed from nixpkgs.")
@@ -59,6 +61,9 @@ with lib;
(mkRemovedOptionModule [ "services" "moinmoin" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "mwlib" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "osquery" ] "The osquery module has been removed")
+ (mkRemovedOptionModule [ "services" "pantheon" "files" ] ''
+ This module was removed, please add pkgs.pantheon.elementary-files to environment.systemPackages directly.
+ '')
(mkRemovedOptionModule [ "services" "prey" ] ''
prey-bash-client is deprecated upstream
'')
@@ -80,6 +85,12 @@ with lib;
libinput and synaptics.
'')
(mkRemovedOptionModule [ "virtualisation" "rkt" ] "The rkt module has been removed, it was archived by upstream")
+ (mkRemovedOptionModule [ "services" "racoon" ] ''
+ The racoon module has been removed, because the software project was abandoned upstream.
+ '')
+ (mkRemovedOptionModule [ "services" "shellinabox" ] "The corresponding package was removed from nixpkgs.")
+ (mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.")
+ (mkRemovedOptionModule [ "services" "virtuoso" ] "The corresponding package was removed from nixpkgs.")
# Do NOT add any option renames here, see top of the file
];
diff --git a/nixos/modules/security/google_oslogin.nix b/nixos/modules/security/google_oslogin.nix
index c2889a0f0d1d..cf416035ef60 100644
--- a/nixos/modules/security/google_oslogin.nix
+++ b/nixos/modules/security/google_oslogin.nix
@@ -5,7 +5,7 @@ with lib;
let
cfg = config.security.googleOsLogin;
- package = pkgs.google-compute-engine-oslogin;
+ package = pkgs.google-guest-oslogin;
in
@@ -17,7 +17,7 @@ in
type = types.bool;
default = false;
description = ''
- Whether to enable Google OS Login
+ Whether to enable Google OS Login.
The OS Login package enables the following components:
AuthorizedKeysCommand to query valid SSH keys from the user's OS Login
@@ -36,7 +36,7 @@ in
security.pam.services.sshd = {
makeHomeDir = true;
googleOsLoginAccountVerification = true;
- # disabled for now: googleOsLoginAuthentication = true;
+ googleOsLoginAuthentication = true;
};
security.sudo.extraConfig = ''
@@ -47,6 +47,9 @@ in
"d /var/google-users.d 750 root root -"
];
+ systemd.packages = [ package ];
+ systemd.timers.google-oslogin-cache.wantedBy = [ "timers.target" ];
+
# enable the nss module, so user lookups etc. work
system.nssModules = [ package ];
system.nssDatabases.passwd = [ "cache_oslogin" "oslogin" ];
diff --git a/nixos/modules/security/misc.nix b/nixos/modules/security/misc.nix
index e7abc1e0d597..c20e067b8cc7 100644
--- a/nixos/modules/security/misc.nix
+++ b/nixos/modules/security/misc.nix
@@ -123,8 +123,8 @@ with lib;
boot.kernel.sysctl."user.max_user_namespaces" = 0;
assertions = [
- { assertion = config.nix.useSandbox -> config.security.allowUserNamespaces;
- message = "`nix.useSandbox = true` conflicts with `!security.allowUserNamespaces`.";
+ { assertion = config.nix.settings.sandbox -> config.security.allowUserNamespaces;
+ message = "`nix.settings.sandbox = true` conflicts with `!security.allowUserNamespaces`.";
}
];
})
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 964cfe7040c1..c0ef8b5f30bd 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -444,15 +444,15 @@ let
account sufficient ${pam_krb5}/lib/security/pam_krb5.so
'' +
optionalString cfg.googleOsLoginAccountVerification ''
- account [success=ok ignore=ignore default=die] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so
- account [success=ok default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so
+ account [success=ok ignore=ignore default=die] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
+ account [success=ok default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so
'' +
''
# Authentication management.
'' +
optionalString cfg.googleOsLoginAuthentication ''
- auth [success=done perm_denied=bad default=ignore] ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so
+ auth [success=done perm_denied=die default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
'' +
optionalString cfg.rootOK ''
auth sufficient pam_rootok.so
@@ -518,7 +518,7 @@ let
auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
'' +
optionalString cfg.googleAuthenticator.enable ''
- auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
+ auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
'' +
optionalString cfg.duoSecurity.enable ''
auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
@@ -1091,11 +1091,11 @@ in
mr ${pam_ccreds}/lib/security/pam_ccreds.so,
'' +
optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
- mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
- mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so,
+ mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
+ mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so,
'' +
optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
- mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
+ mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
'' +
optionalString (config.security.pam.enableSSHAgentAuth
&& isEnabled (cfg: cfg.sshAgentAuth)) ''
diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix
index d9c58152f1fa..1ba149745c65 100644
--- a/nixos/modules/security/polkit.nix
+++ b/nixos/modules/security/polkit.nix
@@ -12,11 +12,7 @@ in
options = {
- security.polkit.enable = mkOption {
- type = types.bool;
- default = true;
- description = "Whether to enable PolKit.";
- };
+ security.polkit.enable = mkEnableOption "polkit";
security.polkit.extraConfig = mkOption {
type = types.lines;
diff --git a/nixos/modules/security/systemd-confinement.nix b/nixos/modules/security/systemd-confinement.nix
index 0e3ec5af323e..f3a2de3bf87a 100644
--- a/nixos/modules/security/systemd-confinement.nix
+++ b/nixos/modules/security/systemd-confinement.nix
@@ -175,8 +175,8 @@ in {
serviceName = "${name}.service";
excludedPath = rootPaths;
} ''
- mkdir -p "$out/lib/systemd/system"
- serviceFile="$out/lib/systemd/system/$serviceName"
+ mkdir -p "$out/lib/systemd/system/$serviceName.d"
+ serviceFile="$out/lib/systemd/system/$serviceName.d/confinement.conf"
echo '[Service]' > "$serviceFile"
diff --git a/nixos/modules/security/wrappers/default.nix b/nixos/modules/security/wrappers/default.nix
index 66a47bcaab6c..e63f19010de8 100644
--- a/nixos/modules/security/wrappers/default.nix
+++ b/nixos/modules/security/wrappers/default.nix
@@ -92,7 +92,6 @@ let
, permissions
, ...
}:
- assert (lib.versionAtLeast (lib.getVersion config.boot.kernelPackages.kernel) "4.3");
''
cp ${securityWrapper}/bin/security-wrapper "$wrapperDir/${program}"
echo -n "${source}" > "$wrapperDir/${program}.real"
diff --git a/nixos/modules/services/admin/pgadmin.nix b/nixos/modules/services/admin/pgadmin.nix
new file mode 100644
index 000000000000..80b681454104
--- /dev/null
+++ b/nixos/modules/services/admin/pgadmin.nix
@@ -0,0 +1,127 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ pkg = pkgs.pgadmin4;
+ cfg = config.services.pgadmin;
+
+ _base = with types; [ int bool str ];
+ base = with types; oneOf ([ (listOf (oneOf _base)) (attrsOf (oneOf _base)) ] ++ _base);
+
+ formatAttrset = attr:
+ "{${concatStringsSep "\n" (mapAttrsToList (key: value: "${builtins.toJSON key}: ${formatPyValue value},") attr)}}";
+
+ formatPyValue = value:
+ if builtins.isString value then builtins.toJSON value
+ else if value ? _expr then value._expr
+ 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 throw "Unrecognized type";
+
+ formatPy = attrs:
+ concatStringsSep "\n" (mapAttrsToList (key: value: "${key} = ${formatPyValue value}") attrs);
+
+ pyType = with types; attrsOf (oneOf [ (attrsOf base) (listOf base) base ]);
+in
+{
+ options.services.pgadmin = {
+ enable = mkEnableOption "PostgreSQL Admin 4";
+
+ port = mkOption {
+ description = "Port for pgadmin4 to run on";
+ type = types.port;
+ default = 5050;
+ };
+
+ initialEmail = mkOption {
+ description = "Initial email for the pgAdmin account.";
+ type = types.str;
+ };
+
+ initialPasswordFile = mkOption {
+ description = ''
+ Initial password file for the pgAdmin account.
+ NOTE: Should be string not a store path, to prevent the password from being world readable.
+ '';
+ type = types.path;
+ };
+
+ openFirewall = mkEnableOption "firewall passthrough for pgadmin4";
+
+ settings = mkOption {
+ description = ''
+ Settings for pgadmin4.
+ Documentation.
+ '';
+ type = pyType;
+ default= {};
+ };
+ };
+
+ config = mkIf (cfg.enable) {
+ networking.firewall.allowedTCPPorts = mkIf (cfg.openFirewall) [ cfg.port ];
+
+ services.pgadmin.settings = {
+ DEFAULT_SERVER_PORT = cfg.port;
+ SERVER_MODE = true;
+ } // (optionalAttrs cfg.openFirewall {
+ DEFAULT_SERVER = mkDefault "::";
+ });
+
+ systemd.services.pgadmin = {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ requires = [ "network.target" ];
+ # we're adding this optionally so just in case there's any race it'll be caught
+ # in case postgres doesn't start, pgadmin will just start normally
+ wants = [ "postgresql.service" ];
+
+ path = [ config.services.postgresql.package pkgs.coreutils pkgs.bash ];
+
+ preStart = ''
+ # NOTE: this is idempotent (aka running it twice has no effect)
+ (
+ # Email address:
+ echo ${escapeShellArg cfg.initialEmail}
+
+ # file might not contain newline. echo hack fixes that.
+ PW=$(cat ${escapeShellArg cfg.initialPasswordFile})
+
+ # Password:
+ echo "$PW"
+ # Retype password:
+ echo "$PW"
+ ) | ${pkg}/bin/pgadmin4-setup
+ '';
+
+ restartTriggers = [
+ "/etc/pgadmin/config_system.py"
+ ];
+
+ serviceConfig = {
+ User = "pgadmin";
+ DynamicUser = true;
+ LogsDirectory = "pgadmin";
+ StateDirectory = "pgadmin";
+ ExecStart = "${pkg}/bin/pgadmin4";
+ };
+ };
+
+ users.users.pgadmin = {
+ isSystemUser = true;
+ group = "pgadmin";
+ };
+
+ users.groups.pgadmin = {};
+
+ environment.etc."pgadmin/config_system.py" = {
+ text = formatPy cfg.settings;
+ mode = "0600";
+ user = "pgadmin";
+ group = "pgadmin";
+ };
+ };
+}
diff --git a/nixos/modules/services/audio/jmusicbot.nix b/nixos/modules/services/audio/jmusicbot.nix
index f573bd2ab8dd..e0f8d461af07 100644
--- a/nixos/modules/services/audio/jmusicbot.nix
+++ b/nixos/modules/services/audio/jmusicbot.nix
@@ -9,6 +9,13 @@ in
services.jmusicbot = {
enable = mkEnableOption "jmusicbot, a Discord music bot that's easy to set up and run yourself";
+ package = mkOption {
+ type = types.package;
+ default = pkgs.jmusicbot;
+ defaultText = literalExpression "pkgs.jmusicbot";
+ description = "JMusicBot package to use";
+ };
+
stateDir = mkOption {
type = types.path;
description = ''
@@ -27,7 +34,7 @@ in
after = [ "network-online.target" ];
description = "Discord music bot that's easy to set up and run yourself!";
serviceConfig = mkMerge [{
- ExecStart = "${pkgs.jmusicbot}/bin/JMusicBot";
+ ExecStart = "${cfg.package}/bin/JMusicBot";
WorkingDirectory = cfg.stateDir;
Restart = "always";
RestartSec = 20;
diff --git a/nixos/modules/services/audio/snapserver.nix b/nixos/modules/services/audio/snapserver.nix
index b82aca3976f0..6d5ce98df895 100644
--- a/nixos/modules/services/audio/snapserver.nix
+++ b/nixos/modules/services/audio/snapserver.nix
@@ -44,24 +44,24 @@ let
optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams
# global options
- ++ [ "--stream.bind_to_address ${cfg.listenAddress}" ]
- ++ [ "--stream.port ${toString cfg.port}" ]
- ++ optionalNull cfg.sampleFormat "--stream.sampleformat ${cfg.sampleFormat}"
- ++ optionalNull cfg.codec "--stream.codec ${cfg.codec}"
- ++ optionalNull cfg.streamBuffer "--stream.stream_buffer ${toString cfg.streamBuffer}"
- ++ optionalNull cfg.buffer "--stream.buffer ${toString cfg.buffer}"
+ ++ [ "--stream.bind_to_address=${cfg.listenAddress}" ]
+ ++ [ "--stream.port=${toString cfg.port}" ]
+ ++ optionalNull cfg.sampleFormat "--stream.sampleformat=${cfg.sampleFormat}"
+ ++ 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"
# tcp json rpc
- ++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ]
+ ++ [ "--tcp.enabled=${toString cfg.tcp.enable}" ]
++ optionals cfg.tcp.enable [
- "--tcp.bind_to_address ${cfg.tcp.listenAddress}"
- "--tcp.port ${toString cfg.tcp.port}" ]
+ "--tcp.bind_to_address=${cfg.tcp.listenAddress}"
+ "--tcp.port=${toString cfg.tcp.port}" ]
# http json rpc
- ++ [ "--http.enabled ${toString cfg.http.enable}" ]
+ ++ [ "--http.enabled=${toString cfg.http.enable}" ]
++ 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}\"");
+ "--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}\"");
in {
imports = [
diff --git a/nixos/modules/services/audio/squeezelite.nix b/nixos/modules/services/audio/squeezelite.nix
index 05506f5bcc7a..36295e21c60f 100644
--- a/nixos/modules/services/audio/squeezelite.nix
+++ b/nixos/modules/services/audio/squeezelite.nix
@@ -1,50 +1,46 @@
{ config, lib, pkgs, ... }:
-with lib;
-
let
+ inherit (lib) mkEnableOption mkIf mkOption optionalString types;
+
dataDir = "/var/lib/squeezelite";
cfg = config.services.squeezelite;
+ pkg = if cfg.pulseAudio then pkgs.squeezelite-pulse else pkgs.squeezelite;
+ bin = "${pkg}/bin/${pkg.pname}";
-in {
+in
+{
###### interface
- options = {
+ options.services.squeezelite = {
+ enable = mkEnableOption "Squeezelite, a software Squeezebox emulator";
- services.squeezelite= {
-
- enable = mkEnableOption "Squeezelite, a software Squeezebox emulator";
-
- extraArguments = mkOption {
- default = "";
- type = types.str;
- description = ''
- Additional command line arguments to pass to Squeezelite.
- '';
- };
+ pulseAudio = mkEnableOption "pulseaudio support";
+ extraArguments = mkOption {
+ default = "";
+ type = types.str;
+ description = ''
+ Additional command line arguments to pass to Squeezelite.
+ '';
};
-
};
###### implementation
config = mkIf cfg.enable {
-
- systemd.services.squeezelite= {
+ systemd.services.squeezelite = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "sound.target" ];
description = "Software Squeezebox emulator";
serviceConfig = {
DynamicUser = true;
- ExecStart = "${pkgs.squeezelite}/bin/squeezelite -N ${dataDir}/player-name ${cfg.extraArguments}";
+ ExecStart = "${bin} -N ${dataDir}/player-name ${cfg.extraArguments}";
StateDirectory = builtins.baseNameOf dataDir;
SupplementaryGroups = "audio";
};
};
-
};
-
}
diff --git a/nixos/modules/services/backup/mysql-backup.nix b/nixos/modules/services/backup/mysql-backup.nix
index 9fca21002733..c40a0b5abc40 100644
--- a/nixos/modules/services/backup/mysql-backup.nix
+++ b/nixos/modules/services/backup/mysql-backup.nix
@@ -113,9 +113,10 @@ in
};
};
services.mysql-backup = {
- description = "Mysql backup service";
+ description = "MySQL backup service";
enable = true;
serviceConfig = {
+ Type = "oneshot";
User = cfg.user;
};
script = backupScript;
diff --git a/nixos/modules/services/cluster/corosync/default.nix b/nixos/modules/services/cluster/corosync/default.nix
new file mode 100644
index 000000000000..b4144917feea
--- /dev/null
+++ b/nixos/modules/services/cluster/corosync/default.nix
@@ -0,0 +1,112 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.corosync;
+in
+{
+ # interface
+ options.services.corosync = {
+ enable = mkEnableOption "corosync";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.corosync;
+ defaultText = literalExpression "pkgs.corosync";
+ description = "Package that should be used for corosync.";
+ };
+
+ clusterName = mkOption {
+ type = types.str;
+ default = "nixcluster";
+ description = "Name of the corosync cluster.";
+ };
+
+ extraOptions = mkOption {
+ type = with types; listOf str;
+ default = [];
+ description = "Additional options with which to start corosync.";
+ };
+
+ nodelist = mkOption {
+ description = "Corosync nodelist: all cluster members.";
+ default = [];
+ type = with types; listOf (submodule {
+ options = {
+ nodeid = mkOption {
+ type = int;
+ description = "Node ID number";
+ };
+ name = mkOption {
+ type = str;
+ description = "Node name";
+ };
+ ring_addrs = mkOption {
+ type = listOf str;
+ description = "List of addresses, one for each ring.";
+ };
+ };
+ });
+ };
+ };
+
+ # implementation
+ config = mkIf cfg.enable {
+ environment.systemPackages = [ cfg.package ];
+
+ environment.etc."corosync/corosync.conf".text = ''
+ totem {
+ version: 2
+ secauth: on
+ cluster_name: ${cfg.clusterName}
+ transport: knet
+ }
+
+ nodelist {
+ ${concatMapStrings ({ nodeid, name, ring_addrs }: ''
+ node {
+ nodeid: ${toString nodeid}
+ name: ${name}
+ ${concatStrings (imap0 (i: addr: ''
+ ring${toString i}_addr: ${addr}
+ '') ring_addrs)}
+ }
+ '') cfg.nodelist}
+ }
+
+ quorum {
+ # only corosync_votequorum is supported
+ provider: corosync_votequorum
+ wait_for_all: 0
+ ${optionalString (builtins.length cfg.nodelist < 3) ''
+ two_node: 1
+ ''}
+ }
+
+ logging {
+ to_syslog: yes
+ }
+ '';
+
+ environment.etc."corosync/uidgid.d/root".text = ''
+ # allow pacemaker connection by root
+ uidgid {
+ uid: 0
+ gid: 0
+ }
+ '';
+
+ systemd.packages = [ cfg.package ];
+ systemd.services.corosync = {
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ StateDirectory = "corosync";
+ StateDirectoryMode = "0700";
+ };
+ };
+
+ environment.etc."sysconfig/corosync".text = lib.optionalString (cfg.extraOptions != []) ''
+ COROSYNC_OPTIONS="${lib.escapeShellArgs cfg.extraOptions}"
+ '';
+ };
+}
diff --git a/nixos/modules/services/cluster/hadoop/conf.nix b/nixos/modules/services/cluster/hadoop/conf.nix
index 0caec5cfc203..e3c26a0d5505 100644
--- a/nixos/modules/services/cluster/hadoop/conf.nix
+++ b/nixos/modules/services/cluster/hadoop/conf.nix
@@ -1,6 +1,6 @@
{ cfg, pkgs, lib }:
let
- propertyXml = name: value: ''
+ propertyXml = name: value: lib.optionalString (value != null) ''
${name}
${builtins.toString value}
@@ -29,16 +29,16 @@ let
export HADOOP_LOG_DIR=/tmp/hadoop/$USER
'';
in
-pkgs.runCommand "hadoop-conf" {} ''
+pkgs.runCommand "hadoop-conf" {} (with cfg; ''
mkdir -p $out/
- cp ${siteXml "core-site.xml" cfg.coreSite}/* $out/
- cp ${siteXml "hdfs-site.xml" cfg.hdfsSite}/* $out/
- cp ${siteXml "mapred-site.xml" cfg.mapredSite}/* $out/
- cp ${siteXml "yarn-site.xml" cfg.yarnSite}/* $out/
- cp ${siteXml "httpfs-site.xml" cfg.httpfsSite}/* $out/
- cp ${cfgFile "container-executor.cfg" cfg.containerExecutorCfg}/* $out/
+ cp ${siteXml "core-site.xml" (coreSite // coreSiteInternal)}/* $out/
+ cp ${siteXml "hdfs-site.xml" (hdfsSiteDefault // hdfsSite // hdfsSiteInternal)}/* $out/
+ cp ${siteXml "mapred-site.xml" (mapredSiteDefault // mapredSite)}/* $out/
+ cp ${siteXml "yarn-site.xml" (yarnSiteDefault // yarnSite // yarnSiteInternal)}/* $out/
+ cp ${siteXml "httpfs-site.xml" httpfsSite}/* $out/
+ cp ${cfgFile "container-executor.cfg" containerExecutorCfg}/* $out/
cp ${pkgs.writeTextDir "hadoop-user-functions.sh" userFunctions}/* $out/
cp ${pkgs.writeTextDir "hadoop-env.sh" hadoopEnv}/* $out/
- cp ${cfg.log4jProperties} $out/log4j.properties
- ${lib.concatMapStringsSep "\n" (dir: "cp -r ${dir}/* $out/") cfg.extraConfDirs}
-''
+ cp ${log4jProperties} $out/log4j.properties
+ ${lib.concatMapStringsSep "\n" (dir: "cp -r ${dir}/* $out/") extraConfDirs}
+'')
diff --git a/nixos/modules/services/cluster/hadoop/default.nix b/nixos/modules/services/cluster/hadoop/default.nix
index a1a95fe31cac..a4fdea81037c 100644
--- a/nixos/modules/services/cluster/hadoop/default.nix
+++ b/nixos/modules/services/cluster/hadoop/default.nix
@@ -21,24 +21,50 @@ with lib;
'';
};
+ coreSiteInternal = mkOption {
+ default = {};
+ type = types.attrsOf types.anything;
+ internal = true;
+ description = ''
+ Internal option to add configs to core-site.xml based on module options
+ '';
+ };
- hdfsSite = mkOption {
+ hdfsSiteDefault = mkOption {
default = {
"dfs.namenode.rpc-bind-host" = "0.0.0.0";
+ "dfs.namenode.http-address" = "0.0.0.0:9870";
+ "dfs.namenode.servicerpc-bind-host" = "0.0.0.0";
+ "dfs.namenode.http-bind-host" = "0.0.0.0";
};
type = types.attrsOf types.anything;
+ description = ''
+ Default options for hdfs-site.xml
+ '';
+ };
+ hdfsSite = mkOption {
+ default = {};
+ type = types.attrsOf types.anything;
example = literalExpression ''
{
"dfs.nameservices" = "namenode1";
}
'';
description = ''
- Hadoop hdfs-site.xml definition
+ Additional options and overrides for hdfs-site.xml
'';
};
+ hdfsSiteInternal = mkOption {
+ default = {};
+ type = types.attrsOf types.anything;
+ internal = true;
+ description = ''
+ Internal option to add configs to hdfs-site.xml based on module options
+ '';
+ };
- mapredSite = mkOption {
+ mapredSiteDefault = mkOption {
default = {
"mapreduce.framework.name" = "yarn";
"yarn.app.mapreduce.am.env" = "HADOOP_MAPRED_HOME=${cfg.package}/lib/${cfg.package.untarDir}";
@@ -54,18 +80,25 @@ with lib;
}
'';
type = types.attrsOf types.anything;
+ description = ''
+ Default options for mapred-site.xml
+ '';
+ };
+ mapredSite = mkOption {
+ default = {};
+ type = types.attrsOf types.anything;
example = literalExpression ''
- options.services.hadoop.mapredSite.default // {
+ {
"mapreduce.map.java.opts" = "-Xmx900m -XX:+UseParallelGC";
}
'';
description = ''
- Hadoop mapred-site.xml definition
+ Additional options and overrides for mapred-site.xml
'';
};
- yarnSite = mkOption {
+ yarnSiteDefault = mkOption {
default = {
"yarn.nodemanager.admin-env" = "PATH=$PATH";
"yarn.nodemanager.aux-services" = "mapreduce_shuffle";
@@ -77,19 +110,34 @@ with lib;
"yarn.nodemanager.linux-container-executor.path" = "/run/wrappers/yarn-nodemanager/bin/container-executor";
"yarn.nodemanager.log-dirs" = "/var/log/hadoop/yarn/nodemanager";
"yarn.resourcemanager.bind-host" = "0.0.0.0";
- "yarn.resourcemanager.scheduler.class" = "org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler";
+ "yarn.resourcemanager.scheduler.class" = "org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler";
};
type = types.attrsOf types.anything;
+ description = ''
+ Default options for yarn-site.xml
+ '';
+ };
+ yarnSite = mkOption {
+ default = {};
+ type = types.attrsOf types.anything;
example = literalExpression ''
- options.services.hadoop.yarnSite.default // {
+ {
"yarn.resourcemanager.hostname" = "''${config.networking.hostName}";
}
'';
description = ''
- Hadoop yarn-site.xml definition
+ Additional options and overrides for yarn-site.xml
'';
};
+ yarnSiteInternal = mkOption {
+ default = {};
+ type = types.attrsOf types.anything;
+ internal = true;
+ description = ''
+ Internal option to add configs to yarn-site.xml based on module options
+ '';
+ };
httpfsSite = mkOption {
default = { };
@@ -123,6 +171,7 @@ with lib;
"yarn.nodemanager.linux-container-executor.group"="hadoop";
"min.user.id"=1000;
"feature.terminal.enabled"=1;
+ "feature.mount-cgroup.enabled" = 1;
};
type = types.attrsOf types.anything;
example = literalExpression ''
@@ -148,6 +197,8 @@ with lib;
description = "Directories containing additional config files to be added to HADOOP_CONF_DIR";
};
+ gatewayRole.enable = mkEnableOption "gateway role for deploying hadoop configs";
+
package = mkOption {
type = types.package;
default = pkgs.hadoop;
@@ -157,20 +208,16 @@ with lib;
};
- config = mkMerge [
- (mkIf (builtins.hasAttr "yarn" config.users.users ||
- builtins.hasAttr "hdfs" config.users.users ||
- builtins.hasAttr "httpfs" config.users.users) {
- users.groups.hadoop = {
- gid = config.ids.gids.hadoop;
- };
- environment = {
- systemPackages = [ cfg.package ];
- etc."hadoop-conf".source = let
- hadoopConf = "${import ./conf.nix { inherit cfg pkgs lib; }}/";
- in "${hadoopConf}";
- };
- })
-
- ];
+ config = mkIf cfg.gatewayRole.enable {
+ users.groups.hadoop = {
+ gid = config.ids.gids.hadoop;
+ };
+ environment = {
+ systemPackages = [ cfg.package ];
+ etc."hadoop-conf".source = let
+ hadoopConf = "${import ./conf.nix { inherit cfg pkgs lib; }}/";
+ in "${hadoopConf}";
+ variables.HADOOP_CONF_DIR = "/etc/hadoop-conf/";
+ };
+ };
}
diff --git a/nixos/modules/services/cluster/hadoop/hdfs.nix b/nixos/modules/services/cluster/hadoop/hdfs.nix
index be667aa82d8a..325a002ad32f 100644
--- a/nixos/modules/services/cluster/hadoop/hdfs.nix
+++ b/nixos/modules/services/cluster/hadoop/hdfs.nix
@@ -1,191 +1,191 @@
-{ config, lib, pkgs, ...}:
+{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.hadoop;
+
+ # Config files for hadoop services
hadoopConf = "${import ./conf.nix { inherit cfg pkgs lib; }}/";
- restartIfChanged = mkOption {
- type = types.bool;
- description = ''
- Automatically restart the service on config change.
- This can be set to false to defer restarts on clusters running critical applications.
- Please consider the security implications of inadvertently running an older version,
- and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
- '';
- default = false;
- };
+
+ # Generator for HDFS service options
+ hadoopServiceOption = { serviceName, firewallOption ? true, extraOpts ? null }: {
+ enable = mkEnableOption serviceName;
+ restartIfChanged = mkOption {
+ type = types.bool;
+ description = ''
+ Automatically restart the service on config change.
+ This can be set to false to defer restarts on clusters running critical applications.
+ Please consider the security implications of inadvertently running an older version,
+ and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
+ '';
+ default = false;
+ };
+ extraFlags = mkOption{
+ type = with types; listOf str;
+ default = [];
+ description = "Extra command line flags to pass to ${serviceName}";
+ example = [
+ "-Dcom.sun.management.jmxremote"
+ "-Dcom.sun.management.jmxremote.port=8010"
+ ];
+ };
+ extraEnv = mkOption{
+ type = with types; attrsOf str;
+ default = {};
+ description = "Extra environment variables for ${serviceName}";
+ };
+ } // (optionalAttrs firewallOption {
+ openFirewall = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Open firewall ports for ${serviceName}.";
+ };
+ }) // (optionalAttrs (extraOpts != null) extraOpts);
+
+ # Generator for HDFS service configs
+ hadoopServiceConfig =
+ { name
+ , serviceOptions ? cfg.hdfs."${toLower name}"
+ , description ? "Hadoop HDFS ${name}"
+ , User ? "hdfs"
+ , allowedTCPPorts ? [ ]
+ , preStart ? ""
+ , environment ? { }
+ , extraConfig ? { }
+ }: (
+
+ mkIf serviceOptions.enable ( mkMerge [{
+ systemd.services."hdfs-${toLower name}" = {
+ inherit description preStart;
+ environment = environment // serviceOptions.extraEnv;
+ wantedBy = [ "multi-user.target" ];
+ inherit (serviceOptions) restartIfChanged;
+ serviceConfig = {
+ inherit User;
+ SyslogIdentifier = "hdfs-${toLower name}";
+ ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} ${toLower name} ${escapeShellArgs serviceOptions.extraFlags}";
+ Restart = "always";
+ };
+ };
+
+ services.hadoop.gatewayRole.enable = true;
+
+ networking.firewall.allowedTCPPorts = mkIf
+ ((builtins.hasAttr "openFirewall" serviceOptions) && serviceOptions.openFirewall)
+ allowedTCPPorts;
+ } extraConfig])
+ );
+
in
{
options.services.hadoop.hdfs = {
- namenode = {
- enable = mkEnableOption "Whether to run the HDFS NameNode";
+
+ namenode = hadoopServiceOption { serviceName = "HDFS NameNode"; } // {
formatOnInit = mkOption {
type = types.bool;
default = false;
description = ''
- Format HDFS namenode on first start. This is useful for quickly spinning up ephemeral HDFS clusters with a single namenode.
- For HA clusters, initialization involves multiple steps across multiple nodes. Follow [this guide](https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html)
- to initialize an HA cluster manually.
- '';
- };
- inherit restartIfChanged;
- openFirewall = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Open firewall ports for namenode
+ Format HDFS namenode on first start. This is useful for quickly spinning up
+ ephemeral HDFS clusters with a single namenode.
+ For HA clusters, initialization involves multiple steps across multiple nodes.
+ Follow this guide to initialize an HA cluster manually:
+
'';
};
};
- datanode = {
- enable = mkEnableOption "Whether to run the HDFS DataNode";
- inherit restartIfChanged;
- openFirewall = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Open firewall ports for datanode
- '';
+
+ datanode = hadoopServiceOption { serviceName = "HDFS DataNode"; } // {
+ dataDirs = mkOption {
+ default = null;
+ description = "Tier and path definitions for datanode storage.";
+ type = with types; nullOr (listOf (submodule {
+ options = {
+ type = mkOption {
+ type = enum [ "SSD" "DISK" "ARCHIVE" "RAM_DISK" ];
+ description = ''
+ Storage types ([SSD]/[DISK]/[ARCHIVE]/[RAM_DISK]) for HDFS storage policies.
+ '';
+ };
+ path = mkOption {
+ type = path;
+ example = [ "/var/lib/hadoop/hdfs/dn" ];
+ description = "Determines where on the local filesystem a data node should store its blocks.";
+ };
+ };
+ }));
};
};
- journalnode = {
- enable = mkEnableOption "Whether to run the HDFS JournalNode";
- inherit restartIfChanged;
- openFirewall = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Open firewall ports for journalnode
- '';
- };
+
+ journalnode = hadoopServiceOption { serviceName = "HDFS JournalNode"; };
+
+ zkfc = hadoopServiceOption {
+ serviceName = "HDFS ZooKeeper failover controller";
+ firewallOption = false;
};
- zkfc = {
- enable = mkEnableOption "Whether to run the HDFS ZooKeeper failover controller";
- inherit restartIfChanged;
- };
- httpfs = {
- enable = mkEnableOption "Whether to run the HDFS HTTPfs server";
+
+ httpfs = hadoopServiceOption { serviceName = "HDFS JournalNode"; } // {
tempPath = mkOption {
type = types.path;
default = "/tmp/hadoop/httpfs";
- description = ''
- HTTPFS_TEMP path used by HTTPFS
- '';
- };
- inherit restartIfChanged;
- openFirewall = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Open firewall ports for HTTPFS
- '';
+ description = "HTTPFS_TEMP path used by HTTPFS";
};
};
+
};
config = mkMerge [
- (mkIf cfg.hdfs.namenode.enable {
- systemd.services.hdfs-namenode = {
- description = "Hadoop HDFS NameNode";
- wantedBy = [ "multi-user.target" ];
- inherit (cfg.hdfs.namenode) restartIfChanged;
-
- preStart = (mkIf cfg.hdfs.namenode.formatOnInit ''
- ${cfg.package}/bin/hdfs --config ${hadoopConf} namenode -format -nonInteractive || true
- '');
-
- serviceConfig = {
- User = "hdfs";
- SyslogIdentifier = "hdfs-namenode";
- ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} namenode";
- Restart = "always";
- };
- };
-
- networking.firewall.allowedTCPPorts = (mkIf cfg.hdfs.namenode.openFirewall [
+ (hadoopServiceConfig {
+ name = "NameNode";
+ allowedTCPPorts = [
9870 # namenode.http-address
8020 # namenode.rpc-address
- 8022 # namenode. servicerpc-address
- ]);
+ 8022 # namenode.servicerpc-address
+ 8019 # dfs.ha.zkfc.port
+ ];
+ preStart = (mkIf cfg.hdfs.namenode.formatOnInit
+ "${cfg.package}/bin/hdfs --config ${hadoopConf} namenode -format -nonInteractive || true"
+ );
})
- (mkIf cfg.hdfs.datanode.enable {
- systemd.services.hdfs-datanode = {
- description = "Hadoop HDFS DataNode";
- wantedBy = [ "multi-user.target" ];
- inherit (cfg.hdfs.datanode) restartIfChanged;
- serviceConfig = {
- User = "hdfs";
- SyslogIdentifier = "hdfs-datanode";
- ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} datanode";
- Restart = "always";
- };
- };
-
- networking.firewall.allowedTCPPorts = (mkIf cfg.hdfs.datanode.openFirewall [
+ (hadoopServiceConfig {
+ name = "DataNode";
+ # port numbers for datanode changed between hadoop 2 and 3
+ allowedTCPPorts = if versionAtLeast cfg.package.version "3" then [
9864 # datanode.http.address
9866 # datanode.address
9867 # datanode.ipc.address
- ]);
+ ] else [
+ 50075 # datanode.http.address
+ 50010 # datanode.address
+ 50020 # datanode.ipc.address
+ ];
+ extraConfig.services.hadoop.hdfsSiteInternal."dfs.datanode.data.dir" = let d = cfg.hdfs.datanode.dataDirs; in
+ if (d!= null) then (concatMapStringsSep "," (x: "["+x.type+"]file://"+x.path) cfg.hdfs.datanode.dataDirs) else d;
})
- (mkIf cfg.hdfs.journalnode.enable {
- systemd.services.hdfs-journalnode = {
- description = "Hadoop HDFS JournalNode";
- wantedBy = [ "multi-user.target" ];
- inherit (cfg.hdfs.journalnode) restartIfChanged;
- serviceConfig = {
- User = "hdfs";
- SyslogIdentifier = "hdfs-journalnode";
- ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} journalnode";
- Restart = "always";
- };
- };
-
- networking.firewall.allowedTCPPorts = (mkIf cfg.hdfs.journalnode.openFirewall [
+ (hadoopServiceConfig {
+ name = "JournalNode";
+ allowedTCPPorts = [
8480 # dfs.journalnode.http-address
8485 # dfs.journalnode.rpc-address
- ]);
+ ];
})
- (mkIf cfg.hdfs.zkfc.enable {
- systemd.services.hdfs-zkfc = {
- description = "Hadoop HDFS ZooKeeper failover controller";
- wantedBy = [ "multi-user.target" ];
- inherit (cfg.hdfs.zkfc) restartIfChanged;
- serviceConfig = {
- User = "hdfs";
- SyslogIdentifier = "hdfs-zkfc";
- ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} zkfc";
- Restart = "always";
- };
- };
+ (hadoopServiceConfig {
+ name = "zkfc";
+ description = "Hadoop HDFS ZooKeeper failover controller";
})
- (mkIf cfg.hdfs.httpfs.enable {
- systemd.services.hdfs-httpfs = {
- description = "Hadoop httpfs";
- wantedBy = [ "multi-user.target" ];
- inherit (cfg.hdfs.httpfs) restartIfChanged;
- environment.HTTPFS_TEMP = cfg.hdfs.httpfs.tempPath;
-
- preStart = ''
- mkdir -p $HTTPFS_TEMP
- '';
-
- serviceConfig = {
- User = "httpfs";
- SyslogIdentifier = "hdfs-httpfs";
- ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} httpfs";
- Restart = "always";
- };
- };
- networking.firewall.allowedTCPPorts = (mkIf cfg.hdfs.httpfs.openFirewall [
+ (hadoopServiceConfig {
+ name = "HTTPFS";
+ environment.HTTPFS_TEMP = cfg.hdfs.httpfs.tempPath;
+ preStart = "mkdir -p $HTTPFS_TEMP";
+ User = "httpfs";
+ allowedTCPPorts = [
14000 # httpfs.http.port
- ]);
+ ];
})
- (mkIf (
- cfg.hdfs.namenode.enable || cfg.hdfs.datanode.enable || cfg.hdfs.journalnode.enable || cfg.hdfs.zkfc.enable
- ) {
+
+ (mkIf cfg.gatewayRole.enable {
users.users.hdfs = {
description = "Hadoop HDFS user";
group = "hadoop";
@@ -199,5 +199,6 @@ in
isSystemUser = true;
};
})
+
];
}
diff --git a/nixos/modules/services/cluster/hadoop/yarn.nix b/nixos/modules/services/cluster/hadoop/yarn.nix
index 37c26ea10f76..74e16bdec687 100644
--- a/nixos/modules/services/cluster/hadoop/yarn.nix
+++ b/nixos/modules/services/cluster/hadoop/yarn.nix
@@ -13,23 +13,77 @@ let
'';
default = false;
};
+ extraFlags = mkOption{
+ type = with types; listOf str;
+ default = [];
+ description = "Extra command line flags to pass to the service";
+ example = [
+ "-Dcom.sun.management.jmxremote"
+ "-Dcom.sun.management.jmxremote.port=8010"
+ ];
+ };
+ extraEnv = mkOption{
+ type = with types; attrsOf str;
+ default = {};
+ description = "Extra environment variables";
+ };
in
{
options.services.hadoop.yarn = {
resourcemanager = {
- enable = mkEnableOption "Whether to run the Hadoop YARN ResourceManager";
- inherit restartIfChanged;
+ enable = mkEnableOption "Hadoop YARN ResourceManager";
+ inherit restartIfChanged extraFlags extraEnv;
+
openFirewall = mkOption {
type = types.bool;
- default = true;
+ default = false;
description = ''
Open firewall ports for resourcemanager
'';
};
};
nodemanager = {
- enable = mkEnableOption "Whether to run the Hadoop YARN NodeManager";
- inherit restartIfChanged;
+ enable = mkEnableOption "Hadoop YARN NodeManager";
+ inherit restartIfChanged extraFlags extraEnv;
+
+ resource = {
+ cpuVCores = mkOption {
+ description = "Number of vcores that can be allocated for containers.";
+ type = with types; nullOr ints.positive;
+ default = null;
+ };
+ maximumAllocationVCores = mkOption {
+ description = "The maximum virtual CPU cores any container can be allocated.";
+ type = with types; nullOr ints.positive;
+ default = null;
+ };
+ memoryMB = mkOption {
+ description = "Amount of physical memory, in MB, that can be allocated for containers.";
+ type = with types; nullOr ints.positive;
+ default = null;
+ };
+ maximumAllocationMB = mkOption {
+ description = "The maximum physical memory any container can be allocated.";
+ type = with types; nullOr ints.positive;
+ default = null;
+ };
+ };
+
+ useCGroups = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Use cgroups to enforce resource limits on containers
+ '';
+ };
+
+ localDir = mkOption {
+ description = "List of directories to store localized files in.";
+ type = with types; nullOr (listOf path);
+ example = [ "/var/lib/hadoop/yarn/nm" ];
+ default = null;
+ };
+
addBinBash = mkOption {
type = types.bool;
default = true;
@@ -39,7 +93,7 @@ in
};
openFirewall = mkOption {
type = types.bool;
- default = true;
+ default = false;
description = ''
Open firewall ports for nodemanager.
Because containers can listen on any ephemeral port, TCP ports 1024–65535 will be opened.
@@ -49,10 +103,7 @@ in
};
config = mkMerge [
- (mkIf (
- cfg.yarn.resourcemanager.enable || cfg.yarn.nodemanager.enable
- ) {
-
+ (mkIf cfg.gatewayRole.enable {
users.users.yarn = {
description = "Hadoop YARN user";
group = "hadoop";
@@ -65,15 +116,19 @@ in
description = "Hadoop YARN ResourceManager";
wantedBy = [ "multi-user.target" ];
inherit (cfg.yarn.resourcemanager) restartIfChanged;
+ environment = cfg.yarn.resourcemanager.extraEnv;
serviceConfig = {
User = "yarn";
SyslogIdentifier = "yarn-resourcemanager";
ExecStart = "${cfg.package}/bin/yarn --config ${hadoopConf} " +
- " resourcemanager";
+ " resourcemanager ${escapeShellArgs cfg.yarn.resourcemanager.extraFlags}";
Restart = "always";
};
};
+
+ services.hadoop.gatewayRole.enable = true;
+
networking.firewall.allowedTCPPorts = (mkIf cfg.yarn.resourcemanager.openFirewall [
8088 # resourcemanager.webapp.address
8030 # resourcemanager.scheduler.address
@@ -94,6 +149,7 @@ in
description = "Hadoop YARN NodeManager";
wantedBy = [ "multi-user.target" ];
inherit (cfg.yarn.nodemanager) restartIfChanged;
+ environment = cfg.yarn.nodemanager.extraEnv;
preStart = ''
# create log dir
@@ -101,8 +157,9 @@ in
chown yarn:hadoop /var/log/hadoop/yarn/nodemanager
# set up setuid container executor binary
+ umount /run/wrappers/yarn-nodemanager/cgroup/cpu || true
rm -rf /run/wrappers/yarn-nodemanager/ || true
- mkdir -p /run/wrappers/yarn-nodemanager/{bin,etc/hadoop}
+ mkdir -p /run/wrappers/yarn-nodemanager/{bin,etc/hadoop,cgroup/cpu}
cp ${cfg.package}/lib/${cfg.package.untarDir}/bin/container-executor /run/wrappers/yarn-nodemanager/bin/
chgrp hadoop /run/wrappers/yarn-nodemanager/bin/container-executor
chmod 6050 /run/wrappers/yarn-nodemanager/bin/container-executor
@@ -114,11 +171,26 @@ in
SyslogIdentifier = "yarn-nodemanager";
PermissionsStartOnly = true;
ExecStart = "${cfg.package}/bin/yarn --config ${hadoopConf} " +
- " nodemanager";
+ " nodemanager ${escapeShellArgs cfg.yarn.nodemanager.extraFlags}";
Restart = "always";
};
};
+ services.hadoop.gatewayRole.enable = true;
+
+ services.hadoop.yarnSiteInternal = with cfg.yarn.nodemanager; {
+ "yarn.nodemanager.local-dirs" = localDir;
+ "yarn.scheduler.maximum-allocation-vcores" = resource.maximumAllocationVCores;
+ "yarn.scheduler.maximum-allocation-mb" = resource.maximumAllocationMB;
+ "yarn.nodemanager.resource.cpu-vcores" = resource.cpuVCores;
+ "yarn.nodemanager.resource.memory-mb" = resource.memoryMB;
+ } // mkIf useCGroups {
+ "yarn.nodemanager.linux-container-executor.cgroups.hierarchy" = "/hadoop-yarn";
+ "yarn.nodemanager.linux-container-executor.resources-handler.class" = "org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler";
+ "yarn.nodemanager.linux-container-executor.cgroups.mount" = "true";
+ "yarn.nodemanager.linux-container-executor.cgroups.mount-path" = "/run/wrappers/yarn-nodemanager/cgroup";
+ };
+
networking.firewall.allowedTCPPortRanges = [
(mkIf (cfg.yarn.nodemanager.openFirewall) {from = 1024; to = 65535;})
];
diff --git a/nixos/modules/services/cluster/k3s/default.nix b/nixos/modules/services/cluster/k3s/default.nix
index 50b6780bbe66..3a36cfa3f37b 100644
--- a/nixos/modules/services/cluster/k3s/default.nix
+++ b/nixos/modules/services/cluster/k3s/default.nix
@@ -91,11 +91,6 @@ in
virtualisation.docker = mkIf cfg.docker {
enable = mkDefault true;
};
-
- # TODO: disable this once k3s supports cgroupsv2, either by docker
- # supporting it, or their bundled containerd
- systemd.enableUnifiedCgroupHierarchy = false;
-
environment.systemPackages = [ config.services.k3s.package ];
systemd.services.k3s = {
@@ -119,6 +114,7 @@ in
[
"${cfg.package}/bin/k3s ${cfg.role}"
] ++ (optional cfg.docker "--docker")
+ ++ (optional (cfg.docker && config.systemd.enableUnifiedCgroupHierarchy) "--kubelet-arg=cgroup-driver=systemd")
++ (optional cfg.disableAgent "--disable-agent")
++ (optional (cfg.serverAddr != "") "--server ${cfg.serverAddr}")
++ (optional (cfg.token != "") "--token ${cfg.token}")
diff --git a/nixos/modules/services/cluster/kubernetes/pki.nix b/nixos/modules/services/cluster/kubernetes/pki.nix
index 88bde4e91557..7d9198d20e8c 100644
--- a/nixos/modules/services/cluster/kubernetes/pki.nix
+++ b/nixos/modules/services/cluster/kubernetes/pki.nix
@@ -266,7 +266,7 @@ in
in
''
export KUBECONFIG=${clusterAdminKubeconfig}
- ${kubectl}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files}
+ ${kubernetes}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files}
'';
})]);
diff --git a/nixos/modules/services/cluster/kubernetes/scheduler.nix b/nixos/modules/services/cluster/kubernetes/scheduler.nix
index 2a522f1db89c..2d95528a6ead 100644
--- a/nixos/modules/services/cluster/kubernetes/scheduler.nix
+++ b/nixos/modules/services/cluster/kubernetes/scheduler.nix
@@ -66,12 +66,12 @@ in
serviceConfig = {
Slice = "kubernetes.slice";
ExecStart = ''${top.package}/bin/kube-scheduler \
- --address=${cfg.address} \
+ --bind-address=${cfg.address} \
${optionalString (cfg.featureGates != [])
"--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \
--kubeconfig=${top.lib.mkKubeConfig "kube-scheduler" cfg.kubeconfig} \
--leader-elect=${boolToString cfg.leaderElect} \
- --port=${toString cfg.port} \
+ --secure-port=${toString cfg.port} \
${optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \
${cfg.extraOpts}
'';
diff --git a/nixos/modules/services/cluster/pacemaker/default.nix b/nixos/modules/services/cluster/pacemaker/default.nix
new file mode 100644
index 000000000000..7eeadffcc586
--- /dev/null
+++ b/nixos/modules/services/cluster/pacemaker/default.nix
@@ -0,0 +1,52 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.pacemaker;
+in
+{
+ # interface
+ options.services.pacemaker = {
+ enable = mkEnableOption "pacemaker";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.pacemaker;
+ defaultText = literalExpression "pkgs.pacemaker";
+ description = "Package that should be used for pacemaker.";
+ };
+ };
+
+ # implementation
+ config = mkIf cfg.enable {
+ assertions = [ {
+ assertion = config.services.corosync.enable;
+ message = ''
+ Enabling services.pacemaker requires a services.corosync configuration.
+ '';
+ } ];
+
+ environment.systemPackages = [ cfg.package ];
+
+ # required by pacemaker
+ users.users.hacluster = {
+ isSystemUser = true;
+ group = "pacemaker";
+ home = "/var/lib/pacemaker";
+ };
+ users.groups.pacemaker = {};
+
+ systemd.tmpfiles.rules = [
+ "d /var/log/pacemaker 0700 hacluster pacemaker -"
+ ];
+
+ systemd.packages = [ cfg.package ];
+ systemd.services.pacemaker = {
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ StateDirectory = "pacemaker";
+ StateDirectoryMode = "0700";
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix
index 7686ff99bfc0..8cbe54c60604 100644
--- a/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixos/modules/services/computing/slurm/slurm.nix
@@ -362,6 +362,7 @@ in
wantedBy = [ "multi-user.target" ];
after = [ "systemd-tmpfiles-clean.service" ];
+ requires = [ "network.target" ];
serviceConfig = {
Type = "forking";
@@ -371,12 +372,12 @@ in
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
LimitMEMLOCK = "infinity";
};
-
- preStart = ''
- mkdir -p /var/spool
- '';
};
+ systemd.tmpfiles.rules = mkIf cfg.client.enable [
+ "d /var/spool/slurmd 755 root root -"
+ ];
+
services.openssh.forwardX11 = mkIf cfg.client.enable (mkDefault true);
systemd.services.slurmctld = mkIf (cfg.server.enable) {
diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix
index aaa159d3cb18..80c6c6abfd0b 100644
--- a/nixos/modules/services/continuous-integration/buildbot/master.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/master.nix
@@ -64,7 +64,7 @@ in {
description = "Factory Steps";
default = [];
example = [
- "steps.Git(repourl='git://github.com/buildbot/pyflakes.git', mode='incremental')"
+ "steps.Git(repourl='https://github.com/buildbot/pyflakes.git', mode='incremental')"
"steps.ShellCommand(command=['trial', 'pyflakes'])"
];
};
@@ -74,7 +74,7 @@ in {
description = "List of Change Sources.";
default = [];
example = [
- "changes.GitPoller('git://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
+ "changes.GitPoller('https://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
];
};
diff --git a/nixos/modules/services/continuous-integration/github-runner.nix b/nixos/modules/services/continuous-integration/github-runner.nix
index afd85c972b56..a7645e1f56e9 100644
--- a/nixos/modules/services/continuous-integration/github-runner.nix
+++ b/nixos/modules/services/continuous-integration/github-runner.nix
@@ -34,6 +34,14 @@ in
Repository to add the runner to.
Changing this option triggers a new runner registration.
+
+ IMPORTANT: If your token is org-wide (not per repository), you need to
+ provide a github org link, not a single repository, so do it like this
+ https://github.com/nixos, not like this
+ https://github.com/nixos/nixpkgs.
+ Otherwise, you are going to get a 404 NotFound
+ from POST https://api.github.com/actions/runner-registration
+ in the configure script.
'';
example = "https://github.com/nixos/nixpkgs";
};
@@ -208,6 +216,7 @@ in
token=$(< "$STATE_DIRECTORY"/${newConfigTokenFilename})
RUNNER_ROOT="$STATE_DIRECTORY" ${cfg.package}/bin/config.sh \
--unattended \
+ --disableupdate \
--work "$RUNTIME_DIRECTORY" \
--url ${escapeShellArg cfg.url} \
--token "$token" \
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
index d4b8541c6a1b..dc58c6345239 100644
--- a/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -147,7 +147,7 @@ in
concurrent = mkOption {
type = types.int;
default = 1;
- example = literalExpression "config.nix.maxJobs";
+ example = literalExpression "config.nix.settings.max-jobs";
description = ''
Limits how many jobs globally can be run concurrently.
The most upper limit of jobs using all defined runners.
diff --git a/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix b/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
index 968bc8f1e54e..ef1933e12284 100644
--- a/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
+++ b/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix
@@ -67,7 +67,7 @@ in
# Trusted user allows simplified configuration and better performance
# when operating in a cluster.
- nix.trustedUsers = [ config.systemd.services.hercules-ci-agent.serviceConfig.User ];
+ nix.settings.trusted-users = [ config.systemd.services.hercules-ci-agent.serviceConfig.User ];
services.hercules-ci-agent = {
settings = {
nixUserIsTrusted = true;
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index ccb7cc21734e..cc5de97d6d10 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -258,8 +258,6 @@ in
uid = config.ids.uids.hydra-www;
};
- nix.trustedUsers = [ "hydra-queue-runner" ];
-
services.hydra.extraConfig =
''
using_frontend_proxy = 1
@@ -277,16 +275,21 @@ in
environment.variables = hydraEnv;
- nix.extraOptions = ''
- keep-outputs = true
- keep-derivations = true
+ nix.settings = mkMerge [
+ {
+ keep-outputs = true;
+ keep-derivations = true;
+ trusted-users = [ "hydra-queue-runner" ];
+ }
-
- '' + optionalString (versionOlder (getVersion config.nix.package.out) "2.4pre") ''
- # The default (`true') slows Nix down a lot since the build farm
- # has so many GC roots.
- gc-check-reachability = false
- '';
+ (mkIf (versionOlder (getVersion config.nix.package.out) "2.4pre")
+ {
+ # The default (`true') slows Nix down a lot since the build farm
+ # has so many GC roots.
+ gc-check-reachability = false;
+ }
+ )
+ ];
systemd.services.hydra-init =
{ wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index e0269a962fdd..a1bd73c9e371 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -81,7 +81,9 @@ in {
user = mkOption {
type = types.str;
default = redisName name;
- defaultText = "\"redis\" or \"redis-\${name}\" if name != \"\"";
+ defaultText = literalExpression ''
+ if name == "" then "redis" else "redis-''${name}"
+ '';
description = "The username and groupname for redis-server.";
};
@@ -105,8 +107,7 @@ in {
bind = mkOption {
type = with types; nullOr str;
- default = if name == "" then "127.0.0.1" else null;
- defaultText = literalExpression ''if name == "" then "127.0.0.1" else null'';
+ default = "127.0.0.1";
description = ''
The IP interface to bind to.
null means "all interfaces".
@@ -117,7 +118,9 @@ in {
unixSocket = mkOption {
type = with types; nullOr path;
default = "/run/${redisName name}/redis.sock";
- defaultText = "\"/run/redis/redis.sock\" or \"/run/redis-\${name}/redis.sock\" if name != \"\"";
+ defaultText = literalExpression ''
+ if name == "" then "/run/redis/redis.sock" else "/run/redis-''${name}/redis.sock"
+ '';
description = "The path to the socket to bind to.";
};
@@ -370,7 +373,7 @@ in {
ProtectKernelTunables = true;
ProtectControlGroups = true;
RestrictAddressFamilies =
- optionals (conf.bind != null) ["AF_INET" "AF_INET6"] ++
+ optionals (conf.port != 0) ["AF_INET" "AF_INET6"] ++
optional (conf.unixSocket != null) "AF_UNIX";
RestrictNamespaces = true;
LockPersonality = true;
diff --git a/nixos/modules/services/databases/virtuoso.nix b/nixos/modules/services/databases/virtuoso.nix
deleted file mode 100644
index 8b01622ecb03..000000000000
--- a/nixos/modules/services/databases/virtuoso.nix
+++ /dev/null
@@ -1,99 +0,0 @@
-{ config, lib, pkgs, ... }:
-let
- cfg = config.services.virtuoso;
- virtuosoUser = "virtuoso";
- stateDir = "/var/lib/virtuoso";
-in
-with lib;
-{
-
- ###### interface
-
- options = {
-
- services.virtuoso = {
-
- enable = mkEnableOption "Virtuoso Opensource database server";
-
- config = mkOption {
- type = types.lines;
- default = "";
- description = "Extra options to put into Virtuoso configuration file.";
- };
-
- parameters = mkOption {
- type = types.lines;
- default = "";
- description = "Extra options to put into [Parameters] section of Virtuoso configuration file.";
- };
-
- listenAddress = mkOption {
- type = types.str;
- default = "1111";
- example = "myserver:1323";
- description = "ip:port or port to listen on.";
- };
-
- httpListenAddress = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "myserver:8080";
- description = "ip:port or port for Virtuoso HTTP server to listen on.";
- };
-
- dirsAllowed = mkOption {
- type = types.nullOr types.str; # XXX Maybe use a list in the future?
- default = null;
- example = "/www, /home/";
- description = "A list of directories Virtuoso is allowed to access";
- };
- };
-
- };
-
-
- ###### implementation
-
- config = mkIf cfg.enable {
-
- users.users.${virtuosoUser} =
- { uid = config.ids.uids.virtuoso;
- description = "virtuoso user";
- home = stateDir;
- };
-
- systemd.services.virtuoso = {
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
-
- preStart = ''
- mkdir -p ${stateDir}
- chown ${virtuosoUser} ${stateDir}
- '';
-
- script = ''
- cd ${stateDir}
- ${pkgs.virtuoso}/bin/virtuoso-t +foreground +configfile ${pkgs.writeText "virtuoso.ini" cfg.config}
- '';
- };
-
- services.virtuoso.config = ''
- [Database]
- DatabaseFile=${stateDir}/x-virtuoso.db
- TransactionFile=${stateDir}/x-virtuoso.trx
- ErrorLogFile=${stateDir}/x-virtuoso.log
- xa_persistent_file=${stateDir}/x-virtuoso.pxa
-
- [Parameters]
- ServerPort=${cfg.listenAddress}
- RunAs=${virtuosoUser}
- ${optionalString (cfg.dirsAllowed != null) "DirsAllowed=${cfg.dirsAllowed}"}
- ${cfg.parameters}
-
- [HTTPServer]
- ${optionalString (cfg.httpListenAddress != null) "ServerPort=${cfg.httpListenAddress}"}
- '';
-
- };
-
-}
diff --git a/nixos/modules/services/desktops/flatpak.nix b/nixos/modules/services/desktops/flatpak.nix
index 7da92cc9f264..5fecc64b4f70 100644
--- a/nixos/modules/services/desktops/flatpak.nix
+++ b/nixos/modules/services/desktops/flatpak.nix
@@ -30,6 +30,8 @@ in {
environment.systemPackages = [ pkgs.flatpak ];
+ security.polkit.enable = true;
+
services.dbus.packages = [ pkgs.flatpak ];
systemd.packages = [ pkgs.flatpak ];
diff --git a/nixos/modules/services/desktops/gnome/glib-networking.nix b/nixos/modules/services/desktops/gnome/glib-networking.nix
index 4288b6b5de61..1039605391ab 100644
--- a/nixos/modules/services/desktops/gnome/glib-networking.nix
+++ b/nixos/modules/services/desktops/gnome/glib-networking.nix
@@ -38,7 +38,7 @@ with lib;
systemd.packages = [ pkgs.glib-networking ];
- environment.variables.GIO_EXTRA_MODULES = [ "${pkgs.glib-networking.out}/lib/gio/modules" ];
+ environment.sessionVariables.GIO_EXTRA_MODULES = [ "${pkgs.glib-networking.out}/lib/gio/modules" ];
};
diff --git a/nixos/modules/services/desktops/gvfs.nix b/nixos/modules/services/desktops/gvfs.nix
index 27864fad4f26..1aa64ea37db5 100644
--- a/nixos/modules/services/desktops/gvfs.nix
+++ b/nixos/modules/services/desktops/gvfs.nix
@@ -57,7 +57,7 @@ in
services.udev.packages = [ pkgs.libmtp.out ];
# Needed for unwrapped applications
- environment.variables.GIO_EXTRA_MODULES = [ "${cfg.package}/lib/gio/modules" ];
+ environment.sessionVariables.GIO_EXTRA_MODULES = [ "${cfg.package}/lib/gio/modules" ];
};
diff --git a/nixos/modules/services/desktops/pantheon/files.nix b/nixos/modules/services/desktops/pantheon/files.nix
deleted file mode 100644
index 8cee9f42b62f..000000000000
--- a/nixos/modules/services/desktops/pantheon/files.nix
+++ /dev/null
@@ -1,13 +0,0 @@
-# pantheon files daemon.
-
-{ config, pkgs, lib, ... }:
-
-with lib;
-
-{
-
- imports = [
- (mkRemovedOptionModule [ "services" "pantheon" "files" "enable" ] "Use `environment.systemPackages [ pkgs.pantheon.elementary-files ];`")
- ];
-
-}
diff --git a/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json b/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json
index 284d8c394a61..9aa51b61431d 100644
--- a/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json
+++ b/nixos/modules/services/desktops/pipewire/daemon/client-rt.conf.json
@@ -8,7 +8,7 @@
},
"context.modules": [
{
- "name": "libpipewire-module-rtkit",
+ "name": "libpipewire-module-rt",
"args": {},
"flags": [
"ifexists",
diff --git a/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json b/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json
new file mode 100644
index 000000000000..c7f58fd5799a
--- /dev/null
+++ b/nixos/modules/services/desktops/pipewire/daemon/minimal.conf.json
@@ -0,0 +1,118 @@
+{
+ "context.properties": {
+ "link.max-buffers": 16,
+ "core.daemon": true,
+ "core.name": "pipewire-0",
+ "settings.check-quantum": true,
+ "settings.check-rate": true,
+ "vm.overrides": {
+ "default.clock.min-quantum": 1024
+ }
+ },
+ "context.spa-libs": {
+ "audio.convert.*": "audioconvert/libspa-audioconvert",
+ "api.alsa.*": "alsa/libspa-alsa",
+ "support.*": "support/libspa-support"
+ },
+ "context.modules": [
+ {
+ "name": "libpipewire-module-rt",
+ "args": {
+ "nice.level": -11
+ },
+ "flags": [
+ "ifexists",
+ "nofail"
+ ]
+ },
+ {
+ "name": "libpipewire-module-protocol-native"
+ },
+ {
+ "name": "libpipewire-module-profiler"
+ },
+ {
+ "name": "libpipewire-module-metadata"
+ },
+ {
+ "name": "libpipewire-module-spa-node-factory"
+ },
+ {
+ "name": "libpipewire-module-client-node"
+ },
+ {
+ "name": "libpipewire-module-access",
+ "args": {}
+ },
+ {
+ "name": "libpipewire-module-adapter"
+ },
+ {
+ "name": "libpipewire-module-link-factory"
+ }
+ ],
+ "context.objects": [
+ {
+ "factory": "metadata",
+ "args": {
+ "metadata.name": "default"
+ }
+ },
+ {
+ "factory": "spa-node-factory",
+ "args": {
+ "factory.name": "support.node.driver",
+ "node.name": "Dummy-Driver",
+ "node.group": "pipewire.dummy",
+ "priority.driver": 20000
+ }
+ },
+ {
+ "factory": "spa-node-factory",
+ "args": {
+ "factory.name": "support.node.driver",
+ "node.name": "Freewheel-Driver",
+ "priority.driver": 19000,
+ "node.group": "pipewire.freewheel",
+ "node.freewheel": true
+ }
+ },
+ {
+ "factory": "adapter",
+ "args": {
+ "factory.name": "api.alsa.pcm.source",
+ "node.name": "system",
+ "node.description": "system",
+ "media.class": "Audio/Source",
+ "api.alsa.path": "hw:0",
+ "node.suspend-on-idle": true,
+ "resample.disable": true,
+ "channelmix.disable": true,
+ "adapter.auto-port-config": {
+ "mode": "dsp",
+ "monitor": false,
+ "position": "unknown"
+ }
+ }
+ },
+ {
+ "factory": "adapter",
+ "args": {
+ "factory.name": "api.alsa.pcm.sink",
+ "node.name": "system",
+ "node.description": "system",
+ "media.class": "Audio/Sink",
+ "api.alsa.path": "hw:0",
+ "node.suspend-on-idle": true,
+ "resample.disable": true,
+ "channelmix.disable": true,
+ "adapter.auto-port-config": {
+ "mode": "dsp",
+ "monitor": false,
+ "position": "unknown"
+ }
+ }
+ }
+ ],
+ "context.exec": []
+}
diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json
index 3ed994f11145..df0f62556dff 100644
--- a/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json
+++ b/nixos/modules/services/desktops/pipewire/daemon/pipewire-pulse.conf.json
@@ -6,8 +6,10 @@
},
"context.modules": [
{
- "name": "libpipewire-module-rtkit",
- "args": {},
+ "name": "libpipewire-module-rt",
+ "args": {
+ "nice.level": -11
+ },
"flags": [
"ifexists",
"nofail"
@@ -37,6 +39,61 @@
}
}
],
- "context.exec": [],
- "stream.properties": {}
+ "context.exec": [
+ {
+ "path": "pactl",
+ "args": "load-module module-always-sink"
+ }
+ ],
+ "stream.properties": {},
+ "pulse.rules": [
+ {
+ "matches": [
+ {}
+ ],
+ "actions": {
+ "update-props": {}
+ }
+ },
+ {
+ "matches": [
+ {
+ "application.process.binary": "teams"
+ },
+ {
+ "application.process.binary": "skypeforlinux"
+ }
+ ],
+ "actions": {
+ "quirks": [
+ "force-s16-info"
+ ]
+ }
+ },
+ {
+ "matches": [
+ {
+ "application.process.binary": "firefox"
+ }
+ ],
+ "actions": {
+ "quirks": [
+ "remove-capture-dont-move"
+ ]
+ }
+ },
+ {
+ "matches": [
+ {
+ "application.name": "~speech-dispatcher*"
+ }
+ ],
+ "actions": {
+ "update-props": {
+ "pulse.min.req": "1024/48000",
+ "pulse.min.quantum": "1024/48000"
+ }
+ }
+ }
+ ]
}
diff --git a/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json b/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json
index a923ab4db235..7c79f0168c02 100644
--- a/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json
+++ b/nixos/modules/services/desktops/pipewire/daemon/pipewire.conf.json
@@ -3,6 +3,7 @@
"link.max-buffers": 16,
"core.daemon": true,
"core.name": "pipewire-0",
+ "default.clock.min-quantum": 16,
"vm.overrides": {
"default.clock.min-quantum": 1024
}
@@ -19,8 +20,10 @@
},
"context.modules": [
{
- "name": "libpipewire-module-rtkit",
- "args": {},
+ "name": "libpipewire-module-rt",
+ "args": {
+ "nice.level": -11
+ },
"flags": [
"ifexists",
"nofail"
diff --git a/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix b/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
index f7a03a4a3eaf..6027e4f3d4bf 100644
--- a/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
+++ b/nixos/modules/services/desktops/pipewire/pipewire-media-session.nix
@@ -38,9 +38,8 @@ in {
services.pipewire.media-session = {
enable = mkOption {
type = types.bool;
- default = config.services.pipewire.enable;
- defaultText = literalExpression "config.services.pipewire.enable";
- description = "Example pipewire session manager";
+ default = false;
+ description = "Whether to enable the deprecated example Pipewire session manager";
};
package = mkOption {
@@ -111,6 +110,11 @@ in {
source = json.generate "v4l2-monitor.conf" configs.v4l2-monitor;
};
+ environment.etc."pipewire/media-session.d/with-audio" =
+ mkIf config.services.pipewire.audio.enable {
+ text = "";
+ };
+
environment.etc."pipewire/media-session.d/with-alsa" =
mkIf config.services.pipewire.alsa.enable {
text = "";
diff --git a/nixos/modules/services/desktops/pipewire/pipewire.nix b/nixos/modules/services/desktops/pipewire/pipewire.nix
index c3cfd46e61c2..1323336d866e 100644
--- a/nixos/modules/services/desktops/pipewire/pipewire.nix
+++ b/nixos/modules/services/desktops/pipewire/pipewire.nix
@@ -25,15 +25,18 @@ let
client = lib.importJSON ./daemon/client.conf.json;
client-rt = lib.importJSON ./daemon/client-rt.conf.json;
jack = lib.importJSON ./daemon/jack.conf.json;
+ minimal = lib.importJSON ./daemon/minimal.conf.json;
pipewire = lib.importJSON ./daemon/pipewire.conf.json;
pipewire-pulse = lib.importJSON ./daemon/pipewire-pulse.conf.json;
};
+ useSessionManager = cfg.wireplumber.enable || cfg.media-session.enable;
+
configs = {
client = recursiveUpdate defaults.client cfg.config.client;
client-rt = recursiveUpdate defaults.client-rt cfg.config.client-rt;
jack = recursiveUpdate defaults.jack cfg.config.jack;
- pipewire = recursiveUpdate defaults.pipewire cfg.config.pipewire;
+ pipewire = recursiveUpdate (if useSessionManager then defaults.pipewire else defaults.minimal) cfg.config.pipewire;
pipewire-pulse = recursiveUpdate defaults.pipewire-pulse cfg.config.pipewire-pulse;
};
in {
@@ -113,6 +116,16 @@ in {
};
};
+ audio = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ # this is for backwards compatibility
+ default = cfg.alsa.enable || cfg.jack.enable || cfg.pulse.enable;
+ defaultText = lib.literalExpression "config.services.pipewire.alsa.enable || config.services.pipewire.jack.enable || config.services.pipewire.pulse.enable";
+ description = "Whether to use PipeWire as the primary sound server";
+ };
+ };
+
alsa = {
enable = mkEnableOption "ALSA support";
support32Bit = mkEnableOption "32-bit ALSA support on 64-bit systems";
@@ -149,13 +162,18 @@ in {
config = mkIf cfg.enable {
assertions = [
{
- assertion = cfg.pulse.enable -> !config.hardware.pulseaudio.enable;
- message = "PipeWire based PulseAudio server emulation replaces PulseAudio. This option requires `hardware.pulseaudio.enable` to be set to false";
+ assertion = cfg.audio.enable -> !config.hardware.pulseaudio.enable;
+ message = "Using PipeWire as the sound server conflicts with PulseAudio. This option requires `hardware.pulseaudio.enable` to be set to false";
}
{
assertion = cfg.jack.enable -> !config.services.jack.jackd.enable;
message = "PipeWire based JACK emulation doesn't use the JACK service. This option requires `services.jack.jackd.enable` to be set to false";
}
+ {
+ # JACK intentionally not checked, as PW-on-JACK setups are a thing that some people may want
+ assertion = (cfg.alsa.enable || cfg.pulse.enable) -> cfg.audio.enable;
+ message = "Using PipeWire's ALSA/PulseAudio compatibility layers requires running PipeWire as the sound server. Set `services.pipewire.audio.enable` to true.";
+ }
];
environment.systemPackages = [ cfg.package ]
diff --git a/nixos/modules/services/desktops/pipewire/wireplumber.nix b/nixos/modules/services/desktops/pipewire/wireplumber.nix
index ad96dc1f9745..32206ccb4e60 100644
--- a/nixos/modules/services/desktops/pipewire/wireplumber.nix
+++ b/nixos/modules/services/desktops/pipewire/wireplumber.nix
@@ -1,22 +1,27 @@
{ config, lib, pkgs, ... }:
let
- cfg = config.services.pipewire.wireplumber;
+ pwCfg = config.services.pipewire;
+ cfg = pwCfg.wireplumber;
+ pwUsedForAudio = pwCfg.audio.enable;
in
{
meta.maintainers = [ lib.maintainers.k900 ];
options = {
services.pipewire.wireplumber = {
- enable = lib.mkEnableOption "A modular session / policy manager for PipeWire";
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = config.services.pipewire.enable;
+ defaultText = lib.literalExpression "config.services.pipewire.enable";
+ description = "Whether to enable Wireplumber, a modular session / policy manager for PipeWire";
+ };
package = lib.mkOption {
type = lib.types.package;
default = pkgs.wireplumber;
defaultText = lib.literalExpression "pkgs.wireplumber";
- description = ''
- The wireplumber derivation to use.
- '';
+ description = "The wireplumber derivation to use.";
};
};
};
@@ -30,6 +35,14 @@ in
];
environment.systemPackages = [ cfg.package ];
+
+ environment.etc."wireplumber/main.lua.d/80-nixos.lua" = lib.mkIf (!pwUsedForAudio) {
+ text = ''
+ # Pipewire is not used for audio, so prevent it from grabbing audio devices
+ alsa_monitor.enable = function() end
+ '';
+ };
+
systemd.packages = [ cfg.package ];
systemd.services.wireplumber.enable = config.services.pipewire.systemWide;
diff --git a/nixos/modules/services/development/zammad.nix b/nixos/modules/services/development/zammad.nix
new file mode 100644
index 000000000000..d457a6071873
--- /dev/null
+++ b/nixos/modules/services/development/zammad.nix
@@ -0,0 +1,323 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.zammad;
+ settingsFormat = pkgs.formats.yaml { };
+ filterNull = filterAttrs (_: v: v != null);
+ serviceConfig = {
+ Type = "simple";
+ Restart = "always";
+
+ User = "zammad";
+ Group = "zammad";
+ PrivateTmp = true;
+ StateDirectory = "zammad";
+ WorkingDirectory = cfg.dataDir;
+ };
+ environment = {
+ RAILS_ENV = "production";
+ NODE_ENV = "production";
+ RAILS_SERVE_STATIC_FILES = "true";
+ RAILS_LOG_TO_STDOUT = "true";
+ };
+ databaseConfig = settingsFormat.generate "database.yml" cfg.database.settings;
+in
+{
+
+ options = {
+ services.zammad = {
+ enable = mkEnableOption "Zammad, a web-based, open source user support/ticketing solution.";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.zammad;
+ defaultText = literalExpression "pkgs.zammad";
+ description = "Zammad package to use.";
+ };
+
+ dataDir = mkOption {
+ type = types.path;
+ default = "/var/lib/zammad";
+ description = ''
+ Path to a folder that will contain Zammad working directory.
+ '';
+ };
+
+ host = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ example = "192.168.23.42";
+ description = "Host address.";
+ };
+
+ openPorts = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Whether to open firewall ports for Zammad";
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 3000;
+ description = "Web service port.";
+ };
+
+ websocketPort = mkOption {
+ type = types.port;
+ default = 6042;
+ description = "Websocket service port.";
+ };
+
+ database = {
+ type = mkOption {
+ type = types.enum [ "PostgreSQL" "MySQL" ];
+ default = "PostgreSQL";
+ example = "MySQL";
+ description = "Database engine to use.";
+ };
+
+ host = mkOption {
+ type = types.nullOr types.str;
+ default = {
+ PostgreSQL = "/run/postgresql";
+ MySQL = "localhost";
+ }.${cfg.database.type};
+ defaultText = literalExpression ''
+ {
+ PostgreSQL = "/run/postgresql";
+ MySQL = "localhost";
+ }.''${config.services.zammad.database.type};
+ '';
+ description = ''
+ Database host address.
+ '';
+ };
+
+ port = mkOption {
+ type = types.nullOr types.port;
+ default = null;
+ description = "Database port. Use null for default port.";
+ };
+
+ name = mkOption {
+ type = types.str;
+ default = "zammad";
+ description = ''
+ Database name.
+ '';
+ };
+
+ user = mkOption {
+ type = types.nullOr types.str;
+ default = "zammad";
+ description = "Database user.";
+ };
+
+ passwordFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = "/run/keys/zammad-dbpassword";
+ description = ''
+ A file containing the password for .
+ '';
+ };
+
+ createLocally = mkOption {
+ type = types.bool;
+ default = true;
+ description = "Whether to create a local database automatically.";
+ };
+
+ settings = mkOption {
+ type = settingsFormat.type;
+ default = { };
+ example = literalExpression ''
+ {
+ }
+ '';
+ description = ''
+ The database.yml configuration file as key value set.
+ See
+ for list of configuration parameters.
+ '';
+ };
+ };
+
+ secretKeyBaseFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = "/run/keys/secret_key_base";
+ description = ''
+ The path to a file containing the
+ secret_key_base secret.
+
+ Zammad uses secret_key_base to encrypt
+ the cookie store, which contains session data, and to digest
+ user auth tokens.
+
+ Needs to be a 64 byte long string of hexadecimal
+ characters. You can generate one by running
+
+
+ $ openssl rand -hex 64 >/path/to/secret_key_base_file
+
+
+ This should be a string, not a nix path, since nix paths are
+ copied into the world-readable nix store.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+
+ services.zammad.database.settings = {
+ production = mapAttrs (_: v: mkDefault v) (filterNull {
+ adapter = {
+ PostgreSQL = "postgresql";
+ MySQL = "mysql2";
+ }.${cfg.database.type};
+ database = cfg.database.name;
+ pool = 50;
+ timeout = 5000;
+ encoding = "utf8";
+ username = cfg.database.user;
+ host = cfg.database.host;
+ port = cfg.database.port;
+ });
+ };
+
+ networking.firewall.allowedTCPPorts = mkIf cfg.openPorts [
+ config.services.zammad.port
+ config.services.zammad.websocketPort
+ ];
+
+ users.users.zammad = {
+ isSystemUser = true;
+ home = cfg.dataDir;
+ group = "zammad";
+ };
+
+ users.groups.zammad = { };
+
+ assertions = [
+ {
+ assertion = cfg.database.createLocally -> cfg.database.user == "zammad";
+ message = "services.zammad.database.user must be set to \"zammad\" if services.zammad.database.createLocally is set to true";
+ }
+ {
+ assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
+ message = "a password cannot be specified if services.zammad.database.createLocally is set to true";
+ }
+ ];
+
+ services.mysql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") {
+ enable = true;
+ package = mkDefault pkgs.mariadb;
+ ensureDatabases = [ cfg.database.name ];
+ ensureUsers = [
+ {
+ name = cfg.database.user;
+ ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
+ }
+ ];
+ };
+
+ services.postgresql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "PostgreSQL") {
+ enable = true;
+ ensureDatabases = [ cfg.database.name ];
+ ensureUsers = [
+ {
+ name = cfg.database.user;
+ ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
+ }
+ ];
+ };
+
+ systemd.services.zammad-web = {
+ inherit environment;
+ serviceConfig = serviceConfig // {
+ # loading all the gems takes time
+ TimeoutStartSec = 1200;
+ };
+ after = [
+ "network.target"
+ "postgresql.service"
+ ];
+ requires = [
+ "postgresql.service"
+ ];
+ description = "Zammad web";
+ wantedBy = [ "multi-user.target" ];
+ preStart = ''
+ # Blindly copy the whole project here.
+ chmod -R +w .
+ rm -rf ./public/assets/*
+ rm -rf ./tmp/*
+ rm -rf ./log/*
+ cp -r --no-preserve=owner ${cfg.package}/* .
+ chmod -R +w .
+ # config file
+ cp ${databaseConfig} ./config/database.yml
+ chmod -R +w .
+ ${optionalString (cfg.database.passwordFile != null) ''
+ {
+ echo -n " password: "
+ cat ${cfg.database.passwordFile}
+ } >> ./config/database.yml
+ ''}
+ ${optionalString (cfg.secretKeyBaseFile != null) ''
+ {
+ echo "production: "
+ echo -n " secret_key_base: "
+ cat ${cfg.secretKeyBaseFile}
+ } > ./config/secrets.yml
+ ''}
+
+ if [ `${config.services.postgresql.package}/bin/psql \
+ --host ${cfg.database.host} \
+ ${optionalString
+ (cfg.database.port != null)
+ "--port ${toString cfg.database.port}"} \
+ --username ${cfg.database.user} \
+ --dbname ${cfg.database.name} \
+ --command "SELECT COUNT(*) FROM pg_class c \
+ JOIN pg_namespace s ON s.oid = c.relnamespace \
+ WHERE s.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema') \
+ AND s.nspname NOT LIKE 'pg_temp%';" | sed -n 3p` -eq 0 ]; then
+ echo "Initialize database"
+ ./bin/rake --no-system db:migrate
+ ./bin/rake --no-system db:seed
+ else
+ echo "Migrate database"
+ ./bin/rake --no-system db:migrate
+ fi
+ echo "Done"
+ '';
+ script = "./script/rails server -b ${cfg.host} -p ${toString cfg.port}";
+ };
+
+ systemd.services.zammad-websocket = {
+ inherit serviceConfig environment;
+ after = [ "zammad-web.service" ];
+ requires = [ "zammad-web.service" ];
+ description = "Zammad websocket";
+ wantedBy = [ "multi-user.target" ];
+ script = "./script/websocket-server.rb -b ${cfg.host} -p ${toString cfg.websocketPort} start";
+ };
+
+ systemd.services.zammad-scheduler = {
+ inherit environment;
+ serviceConfig = serviceConfig // { Type = "forking"; };
+ after = [ "zammad-web.service" ];
+ requires = [ "zammad-web.service" ];
+ description = "Zammad scheduler";
+ wantedBy = [ "multi-user.target" ];
+ script = "./script/scheduler.rb start";
+ };
+ };
+
+ meta.maintainers = with lib.maintainers; [ garbas taeer ];
+}
diff --git a/nixos/modules/services/games/factorio.nix b/nixos/modules/services/games/factorio.nix
index 96fcd6d2c8b3..ff73d7a46ed3 100644
--- a/nixos/modules/services/games/factorio.nix
+++ b/nixos/modules/services/games/factorio.nix
@@ -53,6 +53,14 @@ in
'';
};
+ bind = mkOption {
+ type = types.str;
+ default = "0.0.0.0";
+ description = ''
+ The address to which the service should bind.
+ '';
+ };
+
admins = mkOption {
type = types.listOf types.str;
default = [];
@@ -241,6 +249,7 @@ in
"${cfg.package}/bin/factorio"
"--config=${cfg.configFile}"
"--port=${toString cfg.port}"
+ "--bind=${cfg.bind}"
"--start-server=${mkSavePath cfg.saveName}"
"--server-settings=${serverSettingsFile}"
(optionalString (cfg.mods != []) "--mod-directory=${modDir}")
diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix
index 5bb8eff57629..8233962c1a2c 100644
--- a/nixos/modules/services/games/minecraft-server.nix
+++ b/nixos/modules/services/games/minecraft-server.nix
@@ -153,7 +153,7 @@ in {
type = types.separatedString " ";
default = "-Xmx2048M -Xms2048M";
# Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script
- example = "-Xmx2048M -Xms4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing "
+ example = "-Xms4092M -Xmx4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing "
+ "-XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 "
+ "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10";
description = "JVM options for the Minecraft server.";
diff --git a/nixos/modules/services/hardware/ddccontrol.nix b/nixos/modules/services/hardware/ddccontrol.nix
index 766bf12ee9f0..f0b5a9c81960 100644
--- a/nixos/modules/services/hardware/ddccontrol.nix
+++ b/nixos/modules/services/hardware/ddccontrol.nix
@@ -20,6 +20,9 @@ in
###### implementation
config = lib.mkIf cfg.enable {
+ # Load the i2c-dev module
+ boot.kernelModules = [ "i2c_dev" ];
+
# Give users access to the "gddccontrol" tool
environment.systemPackages = [
pkgs.ddccontrol
diff --git a/nixos/modules/services/hardware/joycond.nix b/nixos/modules/services/hardware/joycond.nix
index ffef4f8a4e18..d81c1bb6d63d 100644
--- a/nixos/modules/services/hardware/joycond.nix
+++ b/nixos/modules/services/hardware/joycond.nix
@@ -22,13 +22,9 @@ with lib;
};
config = mkIf cfg.enable {
- environment.systemPackages = [
- kernelPackages.hid-nintendo
- cfg.package
- ];
+ environment.systemPackages = [ cfg.package ];
- boot.extraModulePackages = [ kernelPackages.hid-nintendo ];
- boot.kernelModules = [ "hid_nintendo" ];
+ boot.extraModulePackages = optional (versionOlder kernelPackages.kernel.version "5.16") kernelPackages.hid-nintendo;
services.udev.packages = [ cfg.package ];
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index d48b5444677c..61448af2d33b 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -317,7 +317,8 @@ in
(isYes "NET")
];
- boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}/lib/firmware";
+ # We don't place this into `extraModprobeConfig` so that stage-1 ramdisk doesn't bloat.
+ environment.etc."modprobe.d/firmware.conf".text = "options firmware_class path=${config.hardware.firmware}/lib/firmware";
system.activationScripts.udevd =
''
diff --git a/nixos/modules/services/hardware/udisks2.nix b/nixos/modules/services/hardware/udisks2.nix
index e898f3260585..6be23f39754e 100644
--- a/nixos/modules/services/hardware/udisks2.nix
+++ b/nixos/modules/services/hardware/udisks2.nix
@@ -32,6 +32,8 @@ with lib;
environment.systemPackages = [ pkgs.udisks2 ];
+ security.polkit.enable = true;
+
services.dbus.packages = [ pkgs.udisks2 ];
systemd.tmpfiles.rules = [ "d /var/lib/udisks2 0755 root root -" ];
diff --git a/nixos/modules/services/hardware/undervolt.nix b/nixos/modules/services/hardware/undervolt.nix
index 212c0227c0d0..a743bbf21c8c 100644
--- a/nixos/modules/services/hardware/undervolt.nix
+++ b/nixos/modules/services/hardware/undervolt.nix
@@ -164,8 +164,6 @@ in
environment.systemPackages = [ cfg.package ];
systemd.services.undervolt = {
- path = [ pkgs.undervolt ];
-
description = "Intel Undervolting Service";
# Apply undervolt on boot, nixos generation switch and resume
@@ -175,7 +173,7 @@ in
serviceConfig = {
Type = "oneshot";
Restart = "no";
- ExecStart = "${pkgs.undervolt}/bin/undervolt ${toString cliArgs}";
+ ExecStart = "${cfg.package}/bin/undervolt ${toString cliArgs}";
};
};
diff --git a/nixos/modules/services/hardware/upower.nix b/nixos/modules/services/hardware/upower.nix
index 92c060147bfc..81bf497c993d 100644
--- a/nixos/modules/services/hardware/upower.nix
+++ b/nixos/modules/services/hardware/upower.nix
@@ -155,8 +155,8 @@ in
default = 1200;
description = ''
When usePercentageForPolicy is
- false, the time remaining at which UPower will
- consider the battery low.
+ false, the time remaining in seconds at which
+ UPower will consider the battery low.
If any value (of timeLow,
timeCritical and timeAction) is
@@ -169,8 +169,8 @@ in
default = 300;
description = ''
When usePercentageForPolicy is
- false, the time remaining at which UPower will
- consider the battery critical.
+ false, the time remaining in seconds at which
+ UPower will consider the battery critical.
If any value (of timeLow,
timeCritical and timeAction) is
@@ -183,8 +183,8 @@ in
default = 120;
description = ''
When usePercentageForPolicy is
- false, the time remaining at which UPower will
- take action for the critical battery level.
+ false, the time remaining in seconds at which
+ UPower will take action for the critical battery level.
If any value (of timeLow,
timeCritical and timeAction) is
diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix
similarity index 51%
rename from nixos/modules/services/misc/home-assistant.nix
rename to nixos/modules/services/home-automation/home-assistant.nix
index ac4c0222aac3..6022227f6ea8 100644
--- a/nixos/modules/services/misc/home-assistant.nix
+++ b/nixos/modules/services/home-automation/home-assistant.nix
@@ -4,35 +4,27 @@ with lib;
let
cfg = config.services.home-assistant;
+ format = pkgs.formats.yaml {};
- # cfg.config != null can be assumed here
- configJSON = pkgs.writeText "configuration.json"
- (builtins.toJSON (if cfg.applyDefaultConfig then
- (recursiveUpdate defaultConfig cfg.config) else cfg.config));
+ # Render config attribute sets to YAML
+ # Values that are null will be filtered from the output, so this is one way to have optional
+ # options shown in settings.
+ # We post-process the result to add support for YAML functions, like secrets or includes, see e.g.
+ # https://www.home-assistant.io/docs/configuration/secrets/
+ filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ null ])) cfg.config or {};
configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
- ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
- # Hack to support custom yaml objects,
- # i.e. secrets: https://www.home-assistant.io/docs/configuration/secrets/
+ cp ${format.generate "configuration.yaml" filteredConfig} $out
sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out
'';
+ lovelaceConfig = cfg.lovelaceConfig or {};
+ lovelaceConfigFile = format.generate "ui-lovelace.yaml" lovelaceConfig;
- lovelaceConfigJSON = pkgs.writeText "ui-lovelace.json"
- (builtins.toJSON cfg.lovelaceConfig);
- lovelaceConfigFile = pkgs.runCommand "ui-lovelace.yaml" { preferLocalBuild = true; } ''
- ${pkgs.remarshal}/bin/json2yaml -i ${lovelaceConfigJSON} -o $out
- '';
-
+ # Components advertised by the home-assistant package
availableComponents = cfg.package.availableComponents;
+ # Components that were added by overriding the package
explicitComponents = cfg.package.extraComponents;
-
- usedPlatforms = config:
- if isAttrs config then
- optional (config ? platform) config.platform
- ++ concatMap usedPlatforms (attrValues config)
- else if isList config then
- concatMap usedPlatforms config
- else [ ];
+ useExplicitComponent = component: elem component explicitComponents;
# Given a component "platform", looks up whether it is used in the config
# as `platform = "platform";`.
@@ -42,33 +34,45 @@ let
# platform = "mqtt";
# ...
# } ];
+ usedPlatforms = config:
+ if isAttrs config then
+ optional (config ? platform) config.platform
+ ++ concatMap usedPlatforms (attrValues config)
+ else if isList config then
+ concatMap usedPlatforms config
+ else [ ];
+
useComponentPlatform = component: elem component (usedPlatforms cfg.config);
- useExplicitComponent = component: elem component explicitComponents;
-
- # Returns whether component is used in config or explicitly passed into package
+ # Returns whether component is used in config, explicitly passed into package or
+ # configured in the module.
useComponent = component:
hasAttrByPath (splitString "." component) cfg.config
|| useComponentPlatform component
- || useExplicitComponent component;
+ || useExplicitComponent component
+ || builtins.elem component cfg.extraComponents;
- # List of components used in config
+ # Final list of components passed into the package to include required dependencies
extraComponents = filter useComponent availableComponents;
- package = if (cfg.autoExtraComponents && cfg.config != null)
- then (cfg.package.override { inherit extraComponents; })
- else cfg.package;
-
- # If you are changing this, please update the description in applyDefaultConfig
- defaultConfig = {
- homeassistant.time_zone = config.time.timeZone;
- http.server_port = cfg.port;
- } // optionalAttrs (cfg.lovelaceConfig != null) {
- lovelace.mode = "yaml";
- };
-
+ package = (cfg.package.override (oldArgs: {
+ # Respect overrides that already exist in the passed package and
+ # concat it with values passed via the module.
+ extraComponents = oldArgs.extraComponents or [] ++ extraComponents;
+ extraPackages = ps: (oldArgs.extraPackages or (_: []) ps) ++ (cfg.extraPackages ps);
+ }));
in {
- meta.maintainers = teams.home-assistant.members;
+ imports = [
+ # Migrations in NixOS 22.05
+ (mkRemovedOptionModule [ "services" "home-assistant" "applyDefaultConfig" ] "The default config was migrated into services.home-assistant.config")
+ (mkRemovedOptionModule [ "services" "home-assistant" "autoExtraComponents" ] "Components are now parsed from services.home-assistant.config unconditionally")
+ (mkRenamedOptionModule [ "services" "home-assistant" "port" ] [ "services" "home-assistant" "config" "http" "server_port" ])
+ ];
+
+ meta = {
+ buildDocsInSandbox = false;
+ maintainers = teams.home-assistant.members;
+ };
options.services.home-assistant = {
# Running home-assistant on NixOS is considered an installation method that is unsupported by the upstream project.
@@ -81,42 +85,166 @@ in {
description = "The config directory, where your configuration.yaml is located.";
};
- port = mkOption {
- default = 8123;
- type = types.port;
- description = "The port on which to listen.";
+ extraComponents = mkOption {
+ type = types.listOf (types.enum availableComponents);
+ default = [
+ # List of components required to complete the onboarding
+ "default_config"
+ "met"
+ "esphome"
+ ] ++ optionals (pkgs.stdenv.hostPlatform.isAarch32 || pkgs.stdenv.hostPlatform.isAarch64) [
+ # Use the platform as an indicator that we might be running on a RaspberryPi and include
+ # relevant components
+ "rpi_power"
+ ];
+ example = literalExpression ''
+ [
+ "analytics"
+ "default_config"
+ "esphome"
+ "my"
+ "shopping_list"
+ "wled"
+ ]
+ '';
+ description = ''
+ List of components that have their dependencies included in the package.
+
+ The component name can be found in the URL, for example https://www.home-assistant.io/integrations/ffmpeg/ would map to ffmpeg.
+ '';
};
- applyDefaultConfig = mkOption {
- default = true;
- type = types.bool;
+ extraPackages = mkOption {
+ type = types.functionTo (types.listOf types.package);
+ default = _: [];
+ defaultText = literalExpression ''
+ python3Packages: with python3Packages; [];
+ '';
+ example = literalExpression ''
+ python3Packages: with python3Packages; [
+ # postgresql support
+ psycopg2
+ ];
+ '';
description = ''
- Setting this option enables a few configuration options for HA based on NixOS configuration (such as time zone) to avoid having to manually specify configuration we already have.
-
-
- Currently one side effect of enabling this is that the http component will be enabled.
-
-
- This only takes effect if config != null in order to ensure that a manually managed configuration.yaml is not overwritten.
+ List of packages to add to propagatedBuildInputs.
+
+ A popular example is python3Packages.psycopg2
+ for PostgreSQL support in the recorder component.
'';
};
config = mkOption {
- default = null;
- # Migrate to new option types later: https://github.com/NixOS/nixpkgs/pull/75584
- type = with lib.types; let
- valueType = nullOr (oneOf [
- bool
- int
- float
- str
- (lazyAttrsOf valueType)
- (listOf valueType)
- ]) // {
- description = "Yaml value";
- emptyValue.value = {};
+ type = types.nullOr (types.submodule {
+ freeformType = format.type;
+ options = {
+ # This is a partial selection of the most common options, so new users can quickly
+ # pick up how to match home-assistants config structure to ours. It also lets us preset
+ # config values intelligently.
+
+ homeassistant = {
+ # https://www.home-assistant.io/docs/configuration/basic/
+ name = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "Home";
+ description = ''
+ Name of the location where Home Assistant is running.
+ '';
+ };
+
+ latitude = mkOption {
+ type = types.nullOr (types.either types.float types.str);
+ default = null;
+ example = 52.3;
+ description = ''
+ Latitude of your location required to calculate the time the sun rises and sets.
+ '';
+ };
+
+ longitude = mkOption {
+ type = types.nullOr (types.either types.float types.str);
+ default = null;
+ example = 4.9;
+ description = ''
+ Longitude of your location required to calculate the time the sun rises and sets.
+ '';
+ };
+
+ unit_system = mkOption {
+ type = types.nullOr (types.enum [ "metric" "imperial" ]);
+ default = null;
+ example = "metric";
+ description = ''
+ The unit system to use. This also sets temperature_unit, Celsius for Metric and Fahrenheit for Imperial.
+ '';
+ };
+
+ temperature_unit = mkOption {
+ type = types.nullOr (types.enum [ "C" "F" ]);
+ default = null;
+ example = "C";
+ description = ''
+ Override temperature unit set by unit_system. C for Celsius, F for Fahrenheit.
+ '';
+ };
+
+ time_zone = mkOption {
+ type = types.nullOr types.str;
+ default = config.time.timeZone or null;
+ defaultText = literalExpression ''
+ config.time.timeZone or null
+ '';
+ example = "Europe/Amsterdam";
+ description = ''
+ Pick your time zone from the column TZ of Wikipedia’s list of tz database time zones.
+ '';
+ };
};
- in valueType;
+
+ http = {
+ # https://www.home-assistant.io/integrations/http/
+ server_host = mkOption {
+ type = types.either types.str (types.listOf types.str);
+ default = [
+ "0.0.0.0"
+ "::"
+ ];
+ example = "::1";
+ description = ''
+ Only listen to incoming requests on specific IP/host. The default listed assumes support for IPv4 and IPv6.
+ '';
+ };
+
+ server_port = mkOption {
+ default = 8123;
+ type = types.port;
+ description = ''
+ The port on which to listen.
+ '';
+ };
+ };
+
+ lovelace = {
+ # https://www.home-assistant.io/lovelace/dashboards/
+ mode = mkOption {
+ type = types.enum [ "yaml" "storage" ];
+ default = if cfg.lovelaceConfig != null
+ then "yaml"
+ else "storage";
+ defaultText = literalExpression ''
+ if cfg.lovelaceConfig != null
+ then "yaml"
+ else "storage";
+ '';
+ example = "yaml";
+ description = ''
+ In what mode should the main Lovelace panel be, yaml or storage (UI managed).
+ '';
+ };
+ };
+ };
+ });
example = literalExpression ''
{
homeassistant = {
@@ -130,15 +258,19 @@ in {
frontend = {
themes = "!include_dir_merge_named themes";
};
- http = { };
+ http = {};
feedreader.urls = [ "https://nixos.org/blogs.xml" ];
}
'';
description = ''
Your configuration.yaml as a Nix attribute set.
- Beware that setting this option will delete your previous configuration.yaml.
- Secrets
- are encoded as strings as shown in the example.
+
+ YAML functions like secrets
+ can be passed as a string and will be unquoted automatically.
+
+ Unless this option is explicitly set to null
+ we assume your configuration.yaml is
+ managed through this module and thereby overwritten on startup.
'';
};
@@ -147,16 +279,18 @@ in {
type = types.bool;
description = ''
Whether to make configuration.yaml writable.
- This only has an effect if is set.
+
This will allow you to edit it from Home Assistant's web interface.
+
+ This only has an effect if is set.
However, bear in mind that it will be overwritten at every start of the service.
'';
};
lovelaceConfig = mkOption {
default = null;
- type = with types; nullOr attrs;
- # from https://www.home-assistant.io/lovelace/yaml-mode/
+ type = types.nullOr format.type;
+ # from https://www.home-assistant.io/lovelace/dashboards/
example = literalExpression ''
{
title = "My Awesome Home";
@@ -172,8 +306,8 @@ in {
'';
description = ''
Your ui-lovelace.yaml as a Nix attribute set.
- Setting this option will automatically add
- lovelace.mode = "yaml"; to your .
+ Setting this option will automatically set lovelace.mode to yaml.
+
Beware that setting this option will delete your previous ui-lovelace.yaml
'';
};
@@ -183,8 +317,10 @@ in {
type = types.bool;
description = ''
Whether to make ui-lovelace.yaml writable.
- This only has an effect if is set.
+
This will allow you to edit it from Home Assistant's web interface.
+
+ This only has an effect if is set.
However, bear in mind that it will be overwritten at every start of the service.
'';
};
@@ -201,30 +337,18 @@ in {
type = types.package;
example = literalExpression ''
pkgs.home-assistant.override {
- extraPackages = ps: with ps; [ colorlog ];
+ extraPackages = python3Packages: with python3Packages; [
+ psycopg2
+ ];
+ extraComponents = [
+ "default_config"
+ "esphome"
+ "met"
+ ];
}
'';
description = ''
- Home Assistant package to use. By default the tests are disabled, as they take a considerable amout of time to complete.
- Override extraPackages or extraComponents in order to add additional dependencies.
- If you specify and do not set
- to false, overriding extraComponents will have no effect.
- Avoid home-assistant.overridePythonAttrs if you use autoExtraComponents.
- '';
- };
-
- autoExtraComponents = mkOption {
- default = true;
- type = types.bool;
- description = ''
- If set to true, the components used in config
- are set as the specified package's extraComponents.
- This in turn adds all packaged dependencies to the derivation.
- You might still see import errors in your log.
- In this case, you will need to package the necessary dependencies yourself
- or ask for someone else to package them.
- If a dependency is packaged but not automatically added to this list,
- you might need to specify it in extraPackages.
+ The Home Assistant package to use.
'';
};
@@ -240,18 +364,30 @@ in {
systemd.services.home-assistant = {
description = "Home Assistant";
- after = [ "network.target" ];
- preStart = optionalString (cfg.config != null) (if cfg.configWritable then ''
- cp --no-preserve=mode ${configFile} "${cfg.configDir}/configuration.yaml"
- '' else ''
- rm -f "${cfg.configDir}/configuration.yaml"
- ln -s ${configFile} "${cfg.configDir}/configuration.yaml"
- '') + optionalString (cfg.lovelaceConfig != null) (if cfg.lovelaceConfigWritable then ''
- cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
- '' else ''
- rm -f "${cfg.configDir}/ui-lovelace.yaml"
- ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
- '');
+ after = [
+ "network-online.target"
+
+ # prevent races with database creation
+ "mysql.service"
+ "postgresql.service"
+ ];
+ preStart = let
+ copyConfig = if cfg.configWritable then ''
+ cp --no-preserve=mode ${configFile} "${cfg.configDir}/configuration.yaml"
+ '' else ''
+ rm -f "${cfg.configDir}/configuration.yaml"
+ ln -s ${configFile} "${cfg.configDir}/configuration.yaml"
+ '';
+ copyLovelaceConfig = if cfg.lovelaceConfigWritable then ''
+ cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
+ '' else ''
+ rm -f "${cfg.configDir}/ui-lovelace.yaml"
+ ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
+ '';
+ in
+ (optionalString (cfg.config != null) copyConfig) +
+ (optionalString (cfg.lovelaceConfig != null) copyLovelaceConfig)
+ ;
serviceConfig = let
# List of capabilities to equip home-assistant with, depending on configured components
capabilities = [
@@ -329,7 +465,7 @@ in {
"zwave_js"
];
in {
- ExecStart = "${package}/bin/hass --runner --config '${cfg.configDir}'";
+ ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
User = "hass";
Group = "hass";
diff --git a/nixos/modules/services/misc/zigbee2mqtt.nix b/nixos/modules/services/home-automation/zigbee2mqtt.nix
similarity index 100%
rename from nixos/modules/services/misc/zigbee2mqtt.nix
rename to nixos/modules/services/home-automation/zigbee2mqtt.nix
diff --git a/nixos/modules/services/logging/graylog.nix b/nixos/modules/services/logging/graylog.nix
index e6a23233ba28..28e2d18bf031 100644
--- a/nixos/modules/services/logging/graylog.nix
+++ b/nixos/modules/services/logging/graylog.nix
@@ -132,7 +132,7 @@ in
description = "Graylog server daemon user";
};
};
- users.groups = mkIf (cfg.user == "graylog") {};
+ users.groups = mkIf (cfg.user == "graylog") { graylog = {}; };
systemd.tmpfiles.rules = [
"d '${cfg.messageJournalDir}' - ${cfg.user} - - -"
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index 8cef4e8c083a..082cf92ff4ef 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -4,7 +4,6 @@ with lib;
let
cfg = config.services.logrotate;
- inherit (config.users) groups;
pathOpts = { name, ... }: {
options = {
@@ -85,10 +84,6 @@ let
};
config.name = name;
- config.extraConfig = ''
- missingok
- notifempty
- '';
};
mkConf = pathOpts: ''
@@ -102,7 +97,11 @@ let
'';
paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths));
- configFile = pkgs.writeText "logrotate.conf" (concatStringsSep "\n" ((map mkConf paths) ++ [ cfg.extraConfig ]));
+ configFile = pkgs.writeText "logrotate.conf" (
+ concatStringsSep "\n" (
+ [ "missingok" "notifempty" cfg.extraConfig ] ++ (map mkConf paths)
+ )
+ );
in
{
@@ -112,7 +111,10 @@ in
options = {
services.logrotate = {
- enable = mkEnableOption "the logrotate systemd service";
+ enable = mkEnableOption "the logrotate systemd service" // {
+ default = foldr (n: a: a || n.enable) false (attrValues cfg.paths);
+ defaultText = literalExpression "cfg.paths != {}";
+ };
paths = mkOption {
type = with types; attrsOf (submodule pathOpts);
@@ -163,28 +165,8 @@ in
}
) cfg.paths;
- services.logrotate = {
- paths = {
- "/var/log/btmp" = {
- frequency = mkDefault "monthly";
- keep = mkDefault 1;
- extraConfig = ''
- create 0660 root ${groups.utmp.name}
- '';
- };
- "/var/log/wtmp" = {
- frequency = mkDefault "monthly";
- keep = mkDefault 1;
- extraConfig = ''
- create 0664 root ${groups.utmp.name}
- '';
- };
- };
- };
-
systemd.services.logrotate = {
description = "Logrotate Service";
- wantedBy = [ "multi-user.target" ];
startAt = "hourly";
serviceConfig = {
diff --git a/nixos/modules/services/logging/promtail.nix b/nixos/modules/services/logging/promtail.nix
index 95c83796ece6..a34bc07b6ab2 100644
--- a/nixos/modules/services/logging/promtail.nix
+++ b/nixos/modules/services/logging/promtail.nix
@@ -45,7 +45,7 @@ in {
Restart = "on-failure";
TimeoutStopSec = 10;
- ExecStart = "${pkgs.grafana-loki}/bin/promtail -config.file=${prettyJSON cfg.configuration} ${escapeShellArgs cfg.extraFlags}";
+ ExecStart = "${pkgs.promtail}/bin/promtail -config.file=${prettyJSON cfg.configuration} ${escapeShellArgs cfg.extraFlags}";
ProtectSystem = "strict";
ProtectHome = true;
diff --git a/nixos/modules/services/mail/postfixadmin.nix b/nixos/modules/services/mail/postfixadmin.nix
index f5c8efb3076c..a0846ad52902 100644
--- a/nixos/modules/services/mail/postfixadmin.nix
+++ b/nixos/modules/services/mail/postfixadmin.nix
@@ -114,7 +114,7 @@ in
location ~* \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${fpm.socket};
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
include ${pkgs.nginx}/conf/fastcgi.conf;
}
'';
diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix
index ac192c56aa60..1dd393da8822 100644
--- a/nixos/modules/services/mail/roundcube.nix
+++ b/nixos/modules/services/mail/roundcube.nix
@@ -153,7 +153,7 @@ in
location ~* \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${fpm.socket};
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
include ${pkgs.nginx}/conf/fastcgi.conf;
}
'';
diff --git a/nixos/modules/services/misc/matrix-synapse-log_config.yaml b/nixos/modules/services/matrix/matrix-synapse-log_config.yaml
similarity index 100%
rename from nixos/modules/services/misc/matrix-synapse-log_config.yaml
rename to nixos/modules/services/matrix/matrix-synapse-log_config.yaml
diff --git a/nixos/modules/services/matrix/matrix-synapse.nix b/nixos/modules/services/matrix/matrix-synapse.nix
new file mode 100644
index 000000000000..c4d14dbd547e
--- /dev/null
+++ b/nixos/modules/services/matrix/matrix-synapse.nix
@@ -0,0 +1,773 @@
+{ config, lib, options, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.matrix-synapse;
+ format = pkgs.formats.yaml {};
+
+ # remove null values from the final configuration
+ finalSettings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings;
+ configFile = format.generate "homeserver.yaml" finalSettings;
+ logConfigFile = format.generate "log_config.yaml" cfg.logConfig;
+
+ pluginsEnv = cfg.package.python.buildEnv.override {
+ extraLibs = cfg.plugins;
+ };
+
+ usePostgresql = cfg.settings.database.name == "psycopg2";
+ hasLocalPostgresDB = let args = cfg.settings.database.args; in
+ usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
+
+ registerNewMatrixUser =
+ let
+ isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
+ listener =
+ lib.findFirst (
+ listener: lib.any (
+ resource: lib.any (
+ name: name == "client"
+ ) resource.names
+ ) listener.resources
+ ) (lib.last cfg.settings.listeners) cfg.settings.listeners;
+ # FIXME: Handle cases with missing client listener properly,
+ # don't rely on lib.last, this will not work.
+
+ # add a tail, so that without any bind_addresses we still have a useable address
+ bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]);
+ listenerProtocol = if listener.tls
+ then "https"
+ else "http";
+ in
+ pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
+ exec ${cfg.package}/bin/register_new_matrix_user \
+ $@ \
+ ${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \
+ "${listenerProtocol}://${
+ if (isIpv6 bindAddress) then
+ "[${bindAddress}]"
+ else
+ "${bindAddress}"
+ }:${builtins.toString listener.port}/"
+ '';
+in {
+
+ imports = [
+
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] ''
+ The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0
+ as the behavior is now obsolete.
+ '')
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] ''
+ Database configuration must be done manually. An exemplary setup is demonstrated in
+
+ '')
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "")
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] ''
+ You may add additional event types via
+ `services.matrix-synapse.room_prejoin_state.additional_event_types` and
+ disable the default events via
+ `services.matrix-synapse.room_prejoin_state.disable_default_event_types`.
+ '')
+
+ # options that don't exist in synapse anymore
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "bind_host" ] "Use listener settings instead." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "bind_port" ] "Use listener settings instead." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "expire_access_tokens" ] "" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "no_tls" ] "It is no longer supported by synapse." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_dh_param_path" ] "It was removed from synapse." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "unsecure_port" ] "Use settings.listeners instead." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "user_creation_max_duration" ] "It is no longer supported by synapse." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "verbose" ] "Use a log config instead." )
+
+ # options that were moved into rfc42 style settigns
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "app_service_config_files" ] "Use settings.app_service_config_Files instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "database_args" ] "Use settings.database.args instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "database_name" ] "Use settings.database.args.database instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "database_type" ] "Use settings.database.name instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "database_user" ] "Use settings.database.args.user instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "dynamic_thumbnails" ] "Use settings.dynamic_thumbnails instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_metrics" ] "Use settings.enable_metrics instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration" ] "Use settings.enable_registration instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "extraConfig" ] "Use settings instead." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "listeners" ] "Use settings.listeners instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "logConfig" ] "Use settings.log_config instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "max_image_pixels" ] "Use settings.max_image_pixels instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "max_upload_size" ] "Use settings.max_upload_size instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "presence" "enabled" ] "Use settings.presence.enabled instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "public_baseurl" ] "Use settings.public_baseurl instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "report_stats" ] "Use settings.report_stats instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "server_name" ] "Use settings.server_name instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "servers" ] "Use settings.trusted_key_servers instead." )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_certificate_path" ] "Use settings.tls_certificate_path instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_private_key_path" ] "Use settings.tls_private_key_path instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_shared_secret" ] "Use settings.turn_shared_secret instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_uris" ] "Use settings.turn_uris instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_user_lifetime" ] "Use settings.turn_user_lifetime instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_enabled" ] "Use settings.url_preview_enabled instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_blacklist" ] "Use settings.url_preview_ip_range_blacklist instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_whitelist" ] "Use settings.url_preview_ip_range_whitelist instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_url_blacklist" ] "Use settings.url_preview_url_blacklist instead" )
+
+ # options that are too specific to mention them explicitly in settings
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "email" ] "Use settings.account_threepid_delegates.email instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "msisdn" ] "Use settings.account_threepid_delegates.msisdn instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "allow_guest_access" ] "Use settings.allow_guest_access instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "bcrypt_rounds" ] "Use settings.bcrypt_rounds instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration_captcha" ] "Use settings.enable_registration_captcha instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "event_cache_size" ] "Use settings.event_cache_size instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_concurrent" ] "Use settings.rc_federation.concurrent instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_reject_limit" ] "Use settings.rc_federation.reject_limit instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_delay" ] "Use settings.rc_federation.sleep_delay instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_limit" ] "Use settings.rc_federation.sleep_limit instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_window_size" ] "Use settings.rc_federation.window_size instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "key_refresh_interval" ] "Use settings.key_refresh_interval instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_burst_count" ] "Use settings.rc_messages.burst_count instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_per_second" ] "Use settings.rc_messages.per_second instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_private_key" ] "Use settings.recaptcha_private_key instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_public_key" ] "Use settings.recaptcha_public_key instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "redaction_retention_period" ] "Use settings.redaction_retention_period instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "additional_event_types" ] "Use settings.room_prejoin_state.additional_event_types instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "disable_default_event_types" ] "Use settings.room_prejoin-state.disable_default_event_types instead" )
+
+ # Options that should be passed via extraConfigFiles, so they are not persisted into the nix store
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "macaroon_secret_key" ] "Pass this value via extraConfigFiles instead" )
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "registration_shared_secret" ] "Pass this value via extraConfigFiles instead" )
+
+ ];
+
+ options = {
+ services.matrix-synapse = {
+ enable = mkEnableOption "matrix.org synapse";
+
+ configFile = mkOption {
+ type = types.str;
+ readOnly = true;
+ description = ''
+ Path to the configuration file on the target system. Useful to configure e.g. workers
+ that also need this.
+ '';
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.matrix-synapse;
+ defaultText = literalExpression "pkgs.matrix-synapse";
+ description = ''
+ Overridable attribute of the matrix synapse server package to use.
+ '';
+ };
+
+ plugins = mkOption {
+ type = types.listOf types.package;
+ default = [ ];
+ example = literalExpression ''
+ with config.services.matrix-synapse.package.plugins; [
+ matrix-synapse-ldap3
+ matrix-synapse-pam
+ ];
+ '';
+ description = ''
+ List of additional Matrix plugins to make available.
+ '';
+ };
+
+ withJemalloc = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to preload jemalloc to reduce memory fragmentation and overall usage.
+ '';
+ };
+
+ dataDir = mkOption {
+ type = types.str;
+ default = "/var/lib/matrix-synapse";
+ description = ''
+ The directory where matrix-synapse stores its stateful data such as
+ certificates, media and uploads.
+ '';
+ };
+
+ settings = mkOption {
+ default = {};
+ description = ''
+ The primary synapse configuration. See the
+ sample configuration
+ for possible values.
+
+ Secrets should be passed in by using the extraConfigFiles option.
+ '';
+ type = with types; submodule {
+ freeformType = format.type;
+ options = {
+ # This is a reduced set of popular options and defaults
+ # Do not add every available option here, they can be specified
+ # by the user at their own discretion. This is a freeform type!
+
+ server_name = mkOption {
+ type = types.str;
+ example = "example.com";
+ default = config.networking.hostName;
+ defaultText = literalExpression "config.networking.hostName";
+ description = ''
+ The domain name of the server, with optional explicit port.
+ This is used by remote servers to look up the server address.
+ This is also the last part of your UserID.
+
+ The server_name cannot be changed later so it is important to configure this correctly before you start Synapse.
+ '';
+ };
+
+ enable_registration = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable registration for new users.
+ '';
+ };
+
+ registration_shared_secret = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ If set, allows registration by anyone who also has the shared
+ secret, even if registration is otherwise disabled.
+
+ Secrets should be passed in via extraConfigFiles!
+ '';
+ };
+
+ macaroon_secret_key = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ Secret key for authentication tokens. If none is specified,
+ the registration_shared_secret is used, if one is given; otherwise,
+ a secret key is derived from the signing key.
+
+ Secrets should be passed in via extraConfigFiles!
+ '';
+ };
+
+ enable_metrics = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable collection and rendering of performance metrics
+ '';
+ };
+
+ report_stats = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether or not to report anonymized homeserver usage statistics.
+ '';
+ };
+
+ signing_key_path = mkOption {
+ type = types.path;
+ default = "${cfg.dataDir}/homeserver.signing.key";
+ description = ''
+ Path to the signing key to sign messages with.
+ '';
+ };
+
+ pid_file = mkOption {
+ type = types.path;
+ default = "/run/matrix-synapse.pid";
+ readOnly = true;
+ description = ''
+ The file to store the PID in.
+ '';
+ };
+
+ log_config = mkOption {
+ type = types.path;
+ default = ./matrix-synapse-log_config.yaml;
+ description = ''
+ The file that holds the logging configuration.
+ '';
+ };
+
+ media_store_path = mkOption {
+ type = types.path;
+ default = if lib.versionAtLeast config.system.stateVersion "22.05"
+ then "${cfg.dataDir}/media_store"
+ else "${cfg.dataDir}/media";
+ description = ''
+ Directory where uploaded images and attachments are stored.
+ '';
+ };
+
+ public_baseurl = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "https://example.com:8448/";
+ description = ''
+ The public-facing base URL for the client API (not including _matrix/...)
+ '';
+ };
+
+ tls_certificate_path = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "/var/lib/acme/example.com/fullchain.pem";
+ description = ''
+ PEM encoded X509 certificate for TLS.
+ You can replace the self-signed certificate that synapse
+ autogenerates on launch with your own SSL certificate + key pair
+ if you like. Any required intermediary certificates can be
+ appended after the primary certificate in hierarchical order.
+ '';
+ };
+
+ tls_private_key_path = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "/var/lib/acme/example.com/key.pem";
+ description = ''
+ PEM encoded private key for TLS. Specify null if synapse is not
+ speaking TLS directly.
+ '';
+ };
+
+ presence.enabled = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Whether to enable presence tracking.
+
+ Presence tracking allows users to see the state (e.g online/offline)
+ of other local and remote users.
+ '';
+ };
+
+ listeners = mkOption {
+ type = types.listOf (types.submodule {
+ options = {
+ port = mkOption {
+ type = types.port;
+ example = 8448;
+ description = ''
+ The port to listen for HTTP(S) requests on.
+ '';
+ };
+
+ bind_addresses = mkOption {
+ type = types.listOf types.str;
+ default = [
+ "::1"
+ "127.0.0.1"
+ ];
+ example = literalExpression ''
+ [
+ "::"
+ "0.0.0.0"
+ ]
+ '';
+ description = ''
+ IP addresses to bind the listener to.
+ '';
+ };
+
+ type = mkOption {
+ type = types.enum [
+ "http"
+ "manhole"
+ "metrics"
+ "replication"
+ ];
+ default = "http";
+ example = "metrics";
+ description = ''
+ The type of the listener, usually http.
+ '';
+ };
+
+ tls = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Whether to enable TLS on the listener socket.
+ '';
+ };
+
+ x_forwarded = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Use the X-Forwarded-For (XFF) header as the client IP and not the
+ actual client IP.
+ '';
+ };
+
+ resources = mkOption {
+ type = types.listOf (types.submodule {
+ options = {
+ names = mkOption {
+ type = types.listOf (types.enum [
+ "client"
+ "consent"
+ "federation"
+ "keys"
+ "media"
+ "metrics"
+ "openid"
+ "replication"
+ "static"
+ ]);
+ description = ''
+ List of resources to host on this listener.
+ '';
+ example = [
+ "client"
+ ];
+ };
+ compress = mkOption {
+ type = types.bool;
+ description = ''
+ Should synapse compress HTTP responses to clients that support it?
+ This should be disabled if running synapse behind a load balancer
+ that can do automatic compression.
+ '';
+ };
+ };
+ });
+ description = ''
+ List of HTTP resources to serve on this listener.
+ '';
+ };
+ };
+ });
+ default = [ {
+ port = 8008;
+ bind_addresses = [ "127.0.0.1" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [ {
+ names = [ "client" ];
+ compress = true;
+ } {
+ names = [ "federation" ];
+ compress = false;
+ } ];
+ } ];
+ description = ''
+ List of ports that Synapse should listen on, their purpose and their configuration.
+ '';
+ };
+
+ database.name = mkOption {
+ type = types.enum [
+ "sqlite3"
+ "psycopg2"
+ ];
+ default = if versionAtLeast config.system.stateVersion "18.03"
+ then "psycopg2"
+ else "sqlite3";
+ defaultText = literalExpression ''
+ if versionAtLeast config.system.stateVersion "18.03"
+ then "psycopg2"
+ else "sqlite3"
+ '';
+ description = ''
+ The database engine name. Can be sqlite3 or psycopg2.
+ '';
+ };
+
+ database.args.database = mkOption {
+ type = types.str;
+ default = {
+ sqlite3 = "${cfg.dataDir}/homeserver.db";
+ psycopg2 = "matrix-synapse";
+ }.${cfg.settings.database.name};
+ defaultText = literalExpression ''
+ {
+ sqlite3 = "''${${options.services.matrix-synapse.dataDir}}/homeserver.db";
+ psycopg2 = "matrix-synapse";
+ }.''${${options.services.matrix-synapse.settings}.database.name};
+ '';
+ description = ''
+ Name of the database when using the psycopg2 backend,
+ path to the database location when using sqlite3.
+ '';
+ };
+
+ database.args.user = mkOption {
+ type = types.nullOr types.str;
+ default = {
+ sqlite3 = null;
+ psycopg2 = "matrix-synapse";
+ }.${cfg.settings.database.name};
+ description = ''
+ Username to connect with psycopg2, set to null
+ when using sqlite3.
+ '';
+ };
+
+ url_preview_enabled = mkOption {
+ type = types.bool;
+ default = true;
+ example = false;
+ description = ''
+ Is the preview URL API enabled? If enabled, you *must* specify an
+ explicit url_preview_ip_range_blacklist of IPs that the spider is
+ denied from accessing.
+ '';
+ };
+
+ url_preview_ip_range_blacklist = mkOption {
+ type = types.listOf types.str;
+ default = [
+ "10.0.0.0/8"
+ "100.64.0.0/10"
+ "127.0.0.0/8"
+ "169.254.0.0/16"
+ "172.16.0.0/12"
+ "192.0.0.0/24"
+ "192.0.2.0/24"
+ "192.168.0.0/16"
+ "192.88.99.0/24"
+ "198.18.0.0/15"
+ "198.51.100.0/24"
+ "2001:db8::/32"
+ "203.0.113.0/24"
+ "224.0.0.0/4"
+ "::1/128"
+ "fc00::/7"
+ "fe80::/10"
+ "fec0::/10"
+ "ff00::/8"
+ ];
+ description = ''
+ List of IP address CIDR ranges that the URL preview spider is denied
+ from accessing.
+ '';
+ };
+
+ url_preview_ip_range_whitelist = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ List of IP address CIDR ranges that the URL preview spider is allowed
+ to access even if they are specified in url_preview_ip_range_blacklist.
+ '';
+ };
+
+ url_preview_url_blacklist = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ Optional list of URL matches that the URL preview spider is
+ denied from accessing.
+ '';
+ };
+
+ max_upload_size = mkOption {
+ type = types.str;
+ default = "50M";
+ example = "100M";
+ description = ''
+ The largest allowed upload size in bytes
+ '';
+ };
+
+ max_image_pixels = mkOption {
+ type = types.str;
+ default = "32M";
+ example = "64M";
+ description = ''
+ Maximum number of pixels that will be thumbnailed
+ '';
+ };
+
+ dynamic_thumbnails = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether to generate new thumbnails on the fly to precisely match
+ the resolution requested by the client. If true then whenever
+ a new resolution is requested by the client the server will
+ generate a new thumbnail. If false the server will pick a thumbnail
+ from a precalculated list.
+ '';
+ };
+
+ turn_uris = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [
+ "turn:turn.example.com:3487?transport=udp"
+ "turn:turn.example.com:3487?transport=tcp"
+ "turns:turn.example.com:5349?transport=udp"
+ "turns:turn.example.com:5349?transport=tcp"
+ ];
+ description = ''
+ The public URIs of the TURN server to give to clients
+ '';
+ };
+ turn_shared_secret = mkOption {
+ type = types.str;
+ default = "";
+ example = literalExpression ''
+ config.services.coturn.static-auth-secret
+ '';
+ description = ''
+ The shared secret used to compute passwords for the TURN server.
+
+ Secrets should be passed in via extraConfigFiles!
+ '';
+ };
+
+ trusted_key_servers = mkOption {
+ type = types.listOf (types.submodule {
+ options = {
+ server_name = mkOption {
+ type = types.str;
+ example = "matrix.org";
+ description = ''
+ Hostname of the trusted server.
+ '';
+ };
+
+ verify_keys = mkOption {
+ type = types.nullOr (types.attrsOf types.str);
+ default = null;
+ example = literalExpression ''
+ {
+ "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
+ }
+ '';
+ description = ''
+ Attribute set from key id to base64 encoded public key.
+
+ If specified synapse will check that the response is signed
+ by at least one of the given keys.
+ '';
+ };
+ };
+ });
+ default = [ {
+ server_name = "matrix.org";
+ verify_keys = {
+ "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
+ };
+ } ];
+ description = ''
+ The trusted servers to download signing keys from.
+ '';
+ };
+
+ app_service_config_files = mkOption {
+ type = types.listOf types.path;
+ default = [ ];
+ description = ''
+ A list of application service config file to use
+ '';
+ };
+
+ };
+ };
+ };
+
+ extraConfigFiles = mkOption {
+ type = types.listOf types.path;
+ default = [];
+ description = ''
+ Extra config files to include.
+
+ The configuration files will be included based on the command line
+ argument --config-path. This allows to configure secrets without
+ having to go through the Nix store, e.g. based on deployment keys if
+ NixOps is in use.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ { assertion = hasLocalPostgresDB -> config.services.postgresql.enable;
+ message = ''
+ Cannot deploy matrix-synapse with a configuration for a local postgresql database
+ and a missing postgresql service. Since 20.03 it's mandatory to manually configure the
+ database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for
+ further reference).
+
+ If you
+ - try to deploy a fresh synapse, you need to configure the database yourself. An example
+ for this can be found in
+ - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true`
+ to your configuration.
+
+ For further information about this update, please read the release-notes of 20.03 carefully.
+ '';
+ }
+ ];
+
+ services.matrix-synapse.configFile = configFile;
+
+ users.users.matrix-synapse = {
+ group = "matrix-synapse";
+ home = cfg.dataDir;
+ createHome = true;
+ shell = "${pkgs.bash}/bin/bash";
+ uid = config.ids.uids.matrix-synapse;
+ };
+
+ users.groups.matrix-synapse = {
+ gid = config.ids.gids.matrix-synapse;
+ };
+
+ systemd.services.matrix-synapse = {
+ description = "Synapse Matrix homeserver";
+ after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
+ wantedBy = [ "multi-user.target" ];
+ preStart = ''
+ ${cfg.package}/bin/synapse_homeserver \
+ --config-path ${configFile} \
+ --keys-directory ${cfg.dataDir} \
+ --generate-keys
+ '';
+ environment = {
+ PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ];
+ } // optionalAttrs (cfg.withJemalloc) {
+ LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
+ };
+ serviceConfig = {
+ Type = "notify";
+ User = "matrix-synapse";
+ Group = "matrix-synapse";
+ WorkingDirectory = cfg.dataDir;
+ ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" ''
+ chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key
+ chmod 0600 ${cfg.dataDir}/homeserver.signing.key
+ '')) ];
+ ExecStart = ''
+ ${cfg.package}/bin/synapse_homeserver \
+ ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) }
+ --keys-directory ${cfg.dataDir}
+ '';
+ ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
+ Restart = "on-failure";
+ UMask = "0077";
+ };
+ };
+
+ environment.systemPackages = [ registerNewMatrixUser ];
+ };
+
+ meta = {
+ buildDocsInSandbox = false;
+ doc = ./matrix-synapse.xml;
+ maintainers = teams.matrix.members;
+ };
+
+}
diff --git a/nixos/modules/services/misc/matrix-synapse.xml b/nixos/modules/services/matrix/matrix-synapse.xml
similarity index 85%
rename from nixos/modules/services/misc/matrix-synapse.xml
rename to nixos/modules/services/matrix/matrix-synapse.xml
index 41a56df0f2b5..cf33957d58ec 100644
--- a/nixos/modules/services/misc/matrix-synapse.xml
+++ b/nixos/modules/services/matrix/matrix-synapse.xml
@@ -115,20 +115,21 @@ in {
};
services.matrix-synapse = {
enable = true;
- server_name = config.networking.domain;
- listeners = [
+ server_name = config.networking.domain;
+ listeners = [
{
- port = 8008;
- bind_address = "::1";
- type = "http";
- tls = false;
- x_forwarded = true;
- resources = [
- {
- names = [ "client" "federation" ];
- compress = false;
- }
- ];
+ port = 8008;
+ bind_addresses = [ "::1" ];
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [ {
+ names = [ "client" ];
+ compress = true;
+ } {
+ names = [ "federation" ];
+ compress = false;
+ } ];
}
];
};
@@ -151,11 +152,11 @@ in {
If you want to run a server with public registration by anybody, you can
- then enable services.matrix-synapse.enable_registration =
+ then enable services.matrix-synapse.settings.enable_registration =
true;. Otherwise, or you can generate a registration secret with
pwgen -s 64 1 and set it with
- . To
- create a new user or admin, run the following after you have set the secret
+ .
+ To create a new user or admin, run the following after you have set the secret
and have rebuilt NixOS:
$ nix run nixpkgs.matrix-synapse
@@ -170,7 +171,7 @@ Success!
@your-username:example.org. Note that the registration
secret ends up in the nix store and therefore is world-readable by any user
on your machine, so it makes sense to only temporarily activate the
- registration_shared_secret
+ registration_shared_secret
option until a better solution for NixOS is in place.
diff --git a/nixos/modules/services/matrix/mjolnir.xml b/nixos/modules/services/matrix/mjolnir.xml
index d462ddf7b01b..b07abe339791 100644
--- a/nixos/modules/services/matrix/mjolnir.xml
+++ b/nixos/modules/services/matrix/mjolnir.xml
@@ -98,7 +98,7 @@
To use the Antispam Module, add matrix-synapse-plugins.matrix-synapse-mjolnir-antispam
- to the Synapse plugin list and enable the mjolnir.AntiSpam module.
+ to the Synapse plugin list and enable the mjolnir.Module module.
{
@@ -108,7 +108,7 @@
];
extraConfig = ''
modules:
- - module: mjolnir.AntiSpam
+ - module: mjolnir.Module
config:
# Prevent servers/users in the ban lists from inviting users on this
# server to rooms. Default true.
diff --git a/nixos/modules/services/misc/airsonic.nix b/nixos/modules/services/misc/airsonic.nix
index 5a5c30a41233..2b9c6d80abbd 100644
--- a/nixos/modules/services/misc/airsonic.nix
+++ b/nixos/modules/services/misc/airsonic.nix
@@ -39,9 +39,11 @@ in {
default = "127.0.0.1";
description = ''
The host name or IP address on which to bind Airsonic.
- Only relevant if you have multiple network interfaces and want
- to make Airsonic available on only one of them. The default value
- will bind Airsonic to all available network interfaces.
+ The default value is appropriate for first launch, when the
+ default credentials are easy to guess. It is also appropriate
+ if you intend to use the virtualhost option in the service
+ module. In other cases, you may want to change this to a
+ specific IP or 0.0.0.0 to listen on all interfaces.
'';
};
diff --git a/nixos/modules/services/misc/autorandr.nix b/nixos/modules/services/misc/autorandr.nix
index 95cee5046e81..ef799e9ce3b6 100644
--- a/nixos/modules/services/misc/autorandr.nix
+++ b/nixos/modules/services/misc/autorandr.nix
@@ -5,6 +5,243 @@ with lib;
let
cfg = config.services.autorandr;
+ hookType = types.lines;
+
+ matrixOf = n: m: elemType:
+ 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;
+ in listOfSize n xss
+ && all (xs: listOfSize m xs && all elemType.check xs) xss;
+ merge = mergeOneOption;
+ getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" "*" ]);
+ getSubModules = elemType.getSubModules;
+ substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
+ functor = (defaultFunctor name) // { wrapped = elemType; };
+ };
+
+ profileModule = types.submodule {
+ options = {
+ fingerprint = mkOption {
+ type = types.attrsOf types.str;
+ description = ''
+ Output name to EDID mapping.
+ Use autorandr --fingerprint to get current setup values.
+ '';
+ default = { };
+ };
+
+ config = mkOption {
+ type = types.attrsOf configModule;
+ description = "Per output profile configuration.";
+ default = { };
+ };
+
+ hooks = mkOption {
+ type = hooksModule;
+ description = "Profile hook scripts.";
+ default = { };
+ };
+ };
+ };
+
+ configModule = types.submodule {
+ options = {
+ enable = mkOption {
+ type = types.bool;
+ description = "Whether to enable the output.";
+ default = true;
+ };
+
+ crtc = mkOption {
+ type = types.nullOr types.ints.unsigned;
+ description = "Output video display controller.";
+ default = null;
+ example = 0;
+ };
+
+ primary = mkOption {
+ type = types.bool;
+ description = "Whether output should be marked as primary";
+ default = false;
+ };
+
+ position = mkOption {
+ type = types.str;
+ description = "Output position";
+ default = "";
+ example = "5760x0";
+ };
+
+ mode = mkOption {
+ type = types.str;
+ description = "Output resolution.";
+ default = "";
+ example = "3840x2160";
+ };
+
+ rate = mkOption {
+ type = types.str;
+ description = "Output framerate.";
+ default = "";
+ example = "60.00";
+ };
+
+ gamma = mkOption {
+ type = 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" ]);
+ description = "Output rotate configuration.";
+ default = null;
+ example = "left";
+ };
+
+ transform = mkOption {
+ type = types.nullOr (matrixOf 3 3 types.float);
+ default = null;
+ example = literalExpression ''
+ [
+ [ 0.6 0.0 0.0 ]
+ [ 0.0 0.6 0.0 ]
+ [ 0.0 0.0 1.0 ]
+ ]
+ '';
+ description = ''
+ Refer to
+
+ xrandr
+ 1
+
+ for the documentation of the transform matrix.
+ '';
+ };
+
+ dpi = mkOption {
+ type = types.nullOr types.ints.positive;
+ description = "Output DPI configuration.";
+ default = null;
+ example = 96;
+ };
+
+ scale = mkOption {
+ type = types.nullOr (types.submodule {
+ options = {
+ method = mkOption {
+ type = types.enum [ "factor" "pixel" ];
+ description = "Output scaling method.";
+ default = "factor";
+ example = "pixel";
+ };
+
+ x = mkOption {
+ type = types.either types.float types.ints.positive;
+ description = "Horizontal scaling factor/pixels.";
+ };
+
+ y = mkOption {
+ type = types.either types.float types.ints.positive;
+ description = "Vertical scaling factor/pixels.";
+ };
+ };
+ });
+ description = ''
+ Output scale configuration.
+
+ Either configure by pixels or a scaling factor. When using pixel method the
+
+ xrandr
+ 1
+
+ option
+ --scale-from
+ will be used; when using factor method the option
+ --scale
+ will be used.
+
+ This option is a shortcut version of the transform option and they are mutually
+ exclusive.
+ '';
+ default = null;
+ example = literalExpression ''
+ {
+ x = 1.25;
+ y = 1.25;
+ }
+ '';
+ };
+ };
+ };
+
+ hooksModule = types.submodule {
+ options = {
+ postswitch = mkOption {
+ type = types.attrsOf hookType;
+ description = "Postswitch hook executed after mode switch.";
+ default = { };
+ };
+
+ preswitch = mkOption {
+ type = types.attrsOf hookType;
+ description = "Preswitch hook executed before mode switch.";
+ default = { };
+ };
+
+ predetect = mkOption {
+ type = types.attrsOf hookType;
+ description = ''
+ Predetect hook executed before autorandr attempts to run xrandr.
+ '';
+ default = { };
+ };
+ };
+ };
+
+ hookToFile = folder: name: hook:
+ nameValuePair "xdg/autorandr/${folder}/${name}" {
+ source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook";
+ };
+ profileToFiles = name: profile:
+ with profile;
+ mkMerge ([
+ {
+ "xdg/autorandr/${name}/setup".text = concatStringsSep "\n"
+ (mapAttrsToList fingerprintToString fingerprint);
+ "xdg/autorandr/${name}/config".text =
+ concatStringsSep "\n" (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)
+ ]);
+ 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)
+ ((if config.scale.method == "factor" then "scale" else "scale-from")
+ + " ${toString config.scale.x}x${toString config.scale.y}"))
+ else ''
+ output ${name}
+ off
+ '';
in {
@@ -22,6 +259,67 @@ in {
for further reference.
'';
};
+
+ hooks = mkOption {
+ type = hooksModule;
+ description = "Global hook scripts";
+ default = { };
+ example = ''
+ {
+ postswitch = {
+ "notify-i3" = "''${pkgs.i3}/bin/i3-msg restart";
+ "change-background" = readFile ./change-background.sh;
+ "change-dpi" = '''
+ case "$AUTORANDR_CURRENT_PROFILE" in
+ default)
+ DPI=120
+ ;;
+ home)
+ DPI=192
+ ;;
+ work)
+ DPI=144
+ ;;
+ *)
+ echo "Unknown profle: $AUTORANDR_CURRENT_PROFILE"
+ exit 1
+ esac
+ echo "Xft.dpi: $DPI" | ''${pkgs.xorg.xrdb}/bin/xrdb -merge
+ '''
+ };
+ }
+ '';
+ };
+ profiles = mkOption {
+ type = types.attrsOf profileModule;
+ description = "Autorandr profiles specification.";
+ default = { };
+ example = literalExpression ''
+ {
+ "work" = {
+ fingerprint = {
+ eDP1 = "";
+ DP1 = "";
+ };
+ config = {
+ eDP1.enable = false;
+ DP1 = {
+ enable = true;
+ crtc = 0;
+ primary = true;
+ position = "0x0";
+ mode = "3840x2160";
+ gamma = "1.0:0.909:0.833";
+ rate = "60.00";
+ rotate = "left";
+ };
+ };
+ hooks.postswitch = readFile ./work-postswitch.sh;
+ };
+ }
+ '';
+ };
+
};
};
@@ -30,7 +328,15 @@ in {
services.udev.packages = [ pkgs.autorandr ];
- environment.systemPackages = [ 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))
+ ]);
+ };
systemd.services.autorandr = {
wantedBy = [ "sleep.target" ];
@@ -43,10 +349,11 @@ in {
ExecStart = "${pkgs.autorandr}/bin/autorandr --batch --change --default ${cfg.defaultTarget}";
Type = "oneshot";
RemainAfterExit = false;
+ KillMode = "process";
};
};
};
- meta.maintainers = with maintainers; [ ];
+ meta.maintainers = with maintainers; [ alexnortung ];
}
diff --git a/nixos/modules/services/misc/dendrite.nix b/nixos/modules/services/misc/dendrite.nix
index c967fc3a362a..89bb989a09ec 100644
--- a/nixos/modules/services/misc/dendrite.nix
+++ b/nixos/modules/services/misc/dendrite.nix
@@ -110,6 +110,15 @@ in
'';
};
};
+ options.app_service_api.database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:federationapi.db";
+ description = ''
+ Database for the Appservice API.
+ '';
+ };
+ };
options.client_api = {
registration_disabled = lib.mkOption {
type = lib.types.bool;
@@ -120,6 +129,91 @@ in
'';
};
};
+ options.federation_api.database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:federationapi.db";
+ description = ''
+ Database for the Federation API.
+ '';
+ };
+ };
+ options.key_server.database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:keyserver.db";
+ description = ''
+ Database for the Key Server (for end-to-end encryption).
+ '';
+ };
+ };
+ options.media_api = {
+ database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:mediaapi.db";
+ description = ''
+ Database for the Media API.
+ '';
+ };
+ };
+ base_path = lib.mkOption {
+ type = lib.types.str;
+ default = "${workingDir}/media_store";
+ description = ''
+ Storage path for uploaded media.
+ '';
+ };
+ };
+ options.room_server.database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:roomserver.db";
+ description = ''
+ Database for the Room Server.
+ '';
+ };
+ };
+ options.sync_api.database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:syncserver.db";
+ description = ''
+ Database for the Sync API.
+ '';
+ };
+ };
+ options.user_api = {
+ account_database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:userapi_accounts.db";
+ description = ''
+ Database for the User API, accounts.
+ '';
+ };
+ };
+ device_database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:userapi_devices.db";
+ description = ''
+ Database for the User API, devices.
+ '';
+ };
+ };
+ };
+ options.mscs = {
+ database = {
+ connection_string = lib.mkOption {
+ type = lib.types.str;
+ default = "file:mscs.db";
+ description = ''
+ Database for exerimental MSC's.
+ '';
+ };
+ };
+ };
};
default = { };
description = ''
@@ -154,14 +248,11 @@ in
RuntimeDirectory = "dendrite";
RuntimeDirectoryMode = "0700";
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
- ExecStartPre =
- if (cfg.environmentFile != null) then ''
- ${pkgs.envsubst}/bin/envsubst \
- -i ${configurationYaml} \
- -o /run/dendrite/dendrite.yaml
- '' else ''
- ${pkgs.coreutils}/bin/cp ${configurationYaml} /run/dendrite/dendrite.yaml
- '';
+ ExecStartPre = ''
+ ${pkgs.envsubst}/bin/envsubst \
+ -i ${configurationYaml} \
+ -o /run/dendrite/dendrite.yaml
+ '';
ExecStart = lib.strings.concatStringsSep " " ([
"${pkgs.dendrite}/bin/dendrite-monolith-server"
"--config /run/dendrite/dendrite.yaml"
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 6f6a9e3110ad..e48444f71612 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -72,7 +72,7 @@ let
redis = {
bin = "${pkgs.redis}/bin/redis-cli";
host = "127.0.0.1";
- port = 6379;
+ port = config.services.redis.servers.gitlab.port;
database = 0;
namespace = "resque:gitlab";
};
@@ -450,7 +450,8 @@ in {
redisUrl = mkOption {
type = types.str;
- default = "redis://localhost:6379/";
+ default = "redis://localhost:${toString config.services.redis.servers.gitlab.port}/";
+ defaultText = literalExpression ''redis://localhost:''${toString config.services.redis.servers.gitlab.port}/'';
description = "Redis URL for all GitLab services except gitlab-shell";
};
@@ -961,7 +962,11 @@ in {
};
# Redis is required for the sidekiq queue runner.
- services.redis.enable = mkDefault true;
+ services.redis.servers.gitlab = {
+ enable = mkDefault true;
+ port = mkDefault 31636;
+ bind = mkDefault "127.0.0.1";
+ };
# We use postgres as the main data store.
services.postgresql = optionalAttrs databaseActuallyCreateLocally {
@@ -1131,8 +1136,8 @@ in {
ExecStartPre = let
preStartFullPrivileges = ''
- shopt -s dotglob nullglob
- set -eu
+ set -o errexit -o pipefail -o nounset
+ shopt -s dotglob nullglob inherit_errexit
chown --no-dereference '${cfg.user}':'${cfg.group}' '${cfg.statePath}'/*
if [[ -n "$(ls -A '${cfg.statePath}'/config/)" ]]; then
@@ -1142,7 +1147,8 @@ in {
in "+${pkgs.writeShellScript "gitlab-pre-start-full-privileges" preStartFullPrivileges}";
ExecStart = pkgs.writeShellScript "gitlab-config" ''
- set -eu
+ set -o errexit -o pipefail -o nounset
+ shopt -s inherit_errexit
umask u=rwx,g=rx,o=
@@ -1171,7 +1177,8 @@ in {
rm -f '${cfg.statePath}/config/database.yml'
${if cfg.databasePasswordFile != null then ''
- export db_password="$(<'${cfg.databasePasswordFile}')"
+ db_password="$(<'${cfg.databasePasswordFile}')"
+ export db_password
if [[ -z "$db_password" ]]; then
>&2 echo "Database password was an empty string!"
@@ -1195,10 +1202,11 @@ in {
rm -f '${cfg.statePath}/config/secrets.yml'
- export secret="$(<'${cfg.secrets.secretFile}')"
- export db="$(<'${cfg.secrets.dbFile}')"
- export otp="$(<'${cfg.secrets.otpFile}')"
- export jws="$(<'${cfg.secrets.jwsFile}')"
+ secret="$(<'${cfg.secrets.secretFile}')"
+ db="$(<'${cfg.secrets.dbFile}')"
+ otp="$(<'${cfg.secrets.otpFile}')"
+ jws="$(<'${cfg.secrets.jwsFile}')"
+ export secret db otp jws
jq -n '{production: {secret_key_base: $ENV.secret,
otp_key_base: $ENV.otp,
db_key_base: $ENV.db,
@@ -1232,7 +1240,8 @@ in {
RemainAfterExit = true;
ExecStart = pkgs.writeShellScript "gitlab-db-config" ''
- set -eu
+ set -o errexit -o pipefail -o nounset
+ shopt -s inherit_errexit
umask u=rwx,g=rx,o=
initial_root_password="$(<'${cfg.initialRootPasswordFile}')"
@@ -1245,13 +1254,13 @@ in {
systemd.services.gitlab-sidekiq = {
after = [
"network.target"
- "redis.service"
+ "redis-gitlab.service"
"postgresql.service"
"gitlab-config.service"
"gitlab-db-config.service"
];
bindsTo = [
- "redis.service"
+ "redis-gitlab.service"
"gitlab-config.service"
"gitlab-db-config.service"
] ++ optional (cfg.databaseHost == "") "postgresql.service";
@@ -1366,7 +1375,7 @@ in {
systemd.services.gitlab-mailroom = mkIf (gitlabConfig.production.incoming_email.enabled or false) {
description = "GitLab incoming mail daemon";
- after = [ "network.target" "redis.service" "gitlab-config.service" ];
+ after = [ "network.target" "redis-gitlab.service" "gitlab-config.service" ];
bindsTo = [ "gitlab-config.service" ];
wantedBy = [ "gitlab.target" ];
partOf = [ "gitlab.target" ];
@@ -1387,12 +1396,12 @@ in {
after = [
"gitlab-workhorse.service"
"network.target"
- "redis.service"
+ "redis-gitlab.service"
"gitlab-config.service"
"gitlab-db-config.service"
];
bindsTo = [
- "redis.service"
+ "redis-gitlab.service"
"gitlab-config.service"
"gitlab-db-config.service"
] ++ optional (cfg.databaseHost == "") "postgresql.service";
diff --git a/nixos/modules/services/misc/input-remapper.nix b/nixos/modules/services/misc/input-remapper.nix
new file mode 100644
index 000000000000..f5fb2bf53086
--- /dev/null
+++ b/nixos/modules/services/misc/input-remapper.nix
@@ -0,0 +1,30 @@
+{ 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 = options.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 {
+ default = [ "graphical.target" ];
+ example = [ "multi-user.target" ];
+ type = types.listOf types.str;
+ description = "Specifies the WantedBy setting for the input-remapper service.";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.udev.packages = mkIf cfg.enableUdevRules [ cfg.package ];
+ services.dbus.packages = [ cfg.package ];
+ systemd.packages = [ cfg.package ];
+ environment.systemPackages = [ cfg.package ];
+ systemd.services.input-remapper.wantedBy = cfg.serviceWantedBy;
+ };
+
+ meta.maintainers = with lib.maintainers; [ LunNova ];
+}
diff --git a/nixos/modules/services/misc/jellyfin.nix b/nixos/modules/services/misc/jellyfin.nix
index b9d54f27edc2..04cf82f8a46b 100644
--- a/nixos/modules/services/misc/jellyfin.nix
+++ b/nixos/modules/services/misc/jellyfin.nix
@@ -70,10 +70,12 @@ in
LockPersonality = true;
PrivateTmp = true;
- PrivateDevices = true;
+ # Disabled to allow Jellyfin to access hw accel devices endpoints
+ # PrivateDevices = true;
PrivateUsers = true;
- ProtectClock = true;
+ # Disabled as it does not allow Jellyfin to interface with CUDA devices
+ # ProtectClock = true;
ProtectControlGroups = true;
ProtectHostname = true;
ProtectKernelLogs = true;
@@ -84,7 +86,7 @@ in
RestrictNamespaces = true;
# AF_NETLINK needed because Jellyfin monitors the network connection
- RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" ];
+ RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" "AF_UNIX" ];
RestrictRealtime = true;
RestrictSUIDSGID = true;
diff --git a/nixos/modules/services/misc/matrix-conduit.nix b/nixos/modules/services/misc/matrix-conduit.nix
index d6cd575ee9a3..108f64de7aa9 100644
--- a/nixos/modules/services/misc/matrix-conduit.nix
+++ b/nixos/modules/services/misc/matrix-conduit.nix
@@ -86,6 +86,15 @@ in
and is set to be read only.
'';
};
+ global.database_backend = mkOption {
+ type = types.enum [ "sqlite" "rocksdb" ];
+ default = "sqlite";
+ example = "rocksdb";
+ description = ''
+ The database backend for the service. Switching it on an existing
+ instance will require manual migration of data.
+ '';
+ };
};
};
default = {};
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
deleted file mode 100644
index feca4c5465ff..000000000000
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ /dev/null
@@ -1,844 +0,0 @@
-{ config, lib, options, pkgs, ... }:
-
-with lib;
-
-let
- cfg = config.services.matrix-synapse;
- opt = options.services.matrix-synapse;
- pg = config.services.postgresql;
- usePostgresql = cfg.database_type == "psycopg2";
- logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig;
- mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${boolToString r.compress}}'';
- mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${boolToString l.tls}, x_forwarded: ${boolToString l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
- pluginsEnv = cfg.package.python.buildEnv.override {
- extraLibs = cfg.plugins;
- };
- configFile = pkgs.writeText "homeserver.yaml" ''
-${optionalString (cfg.tls_certificate_path != null) ''
-tls_certificate_path: "${cfg.tls_certificate_path}"
-''}
-${optionalString (cfg.tls_private_key_path != null) ''
-tls_private_key_path: "${cfg.tls_private_key_path}"
-''}
-${optionalString (cfg.tls_dh_params_path != null) ''
-tls_dh_params_path: "${cfg.tls_dh_params_path}"
-''}
-no_tls: ${boolToString cfg.no_tls}
-${optionalString (cfg.bind_port != null) ''
-bind_port: ${toString cfg.bind_port}
-''}
-${optionalString (cfg.unsecure_port != null) ''
-unsecure_port: ${toString cfg.unsecure_port}
-''}
-${optionalString (cfg.bind_host != null) ''
-bind_host: "${cfg.bind_host}"
-''}
-server_name: "${cfg.server_name}"
-pid_file: "/run/matrix-synapse.pid"
-${optionalString (cfg.public_baseurl != null) ''
-public_baseurl: "${cfg.public_baseurl}"
-''}
-listeners: [${concatStringsSep "," (map mkListener cfg.listeners)}]
-database: {
- name: "${cfg.database_type}",
- args: {
- ${concatStringsSep ",\n " (
- mapAttrsToList (n: v: "\"${n}\": ${builtins.toJSON v}") cfg.database_args
- )}
- }
-}
-event_cache_size: "${cfg.event_cache_size}"
-verbose: ${cfg.verbose}
-log_config: "${logConfigFile}"
-rc_messages_per_second: ${cfg.rc_messages_per_second}
-rc_message_burst_count: ${cfg.rc_message_burst_count}
-federation_rc_window_size: ${cfg.federation_rc_window_size}
-federation_rc_sleep_limit: ${cfg.federation_rc_sleep_limit}
-federation_rc_sleep_delay: ${cfg.federation_rc_sleep_delay}
-federation_rc_reject_limit: ${cfg.federation_rc_reject_limit}
-federation_rc_concurrent: ${cfg.federation_rc_concurrent}
-media_store_path: "${cfg.dataDir}/media"
-uploads_path: "${cfg.dataDir}/uploads"
-max_upload_size: "${cfg.max_upload_size}"
-max_image_pixels: "${cfg.max_image_pixels}"
-dynamic_thumbnails: ${boolToString cfg.dynamic_thumbnails}
-url_preview_enabled: ${boolToString cfg.url_preview_enabled}
-${optionalString (cfg.url_preview_enabled == true) ''
-url_preview_ip_range_blacklist: ${builtins.toJSON cfg.url_preview_ip_range_blacklist}
-url_preview_ip_range_whitelist: ${builtins.toJSON cfg.url_preview_ip_range_whitelist}
-url_preview_url_blacklist: ${builtins.toJSON cfg.url_preview_url_blacklist}
-''}
-recaptcha_private_key: "${cfg.recaptcha_private_key}"
-recaptcha_public_key: "${cfg.recaptcha_public_key}"
-enable_registration_captcha: ${boolToString cfg.enable_registration_captcha}
-turn_uris: ${builtins.toJSON cfg.turn_uris}
-turn_shared_secret: "${cfg.turn_shared_secret}"
-enable_registration: ${boolToString cfg.enable_registration}
-${optionalString (cfg.registration_shared_secret != null) ''
-registration_shared_secret: "${cfg.registration_shared_secret}"
-''}
-recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify"
-turn_user_lifetime: "${cfg.turn_user_lifetime}"
-user_creation_max_duration: ${cfg.user_creation_max_duration}
-bcrypt_rounds: ${cfg.bcrypt_rounds}
-allow_guest_access: ${boolToString cfg.allow_guest_access}
-
-account_threepid_delegates:
- ${optionalString (cfg.account_threepid_delegates.email != null) "email: ${cfg.account_threepid_delegates.email}"}
- ${optionalString (cfg.account_threepid_delegates.msisdn != null) "msisdn: ${cfg.account_threepid_delegates.msisdn}"}
-
-room_prejoin_state:
- disable_default_event_types: ${boolToString cfg.room_prejoin_state.disable_default_event_types}
- additional_event_types: ${builtins.toJSON cfg.room_prejoin_state.additional_event_types}
-${optionalString (cfg.macaroon_secret_key != null) ''
- macaroon_secret_key: "${cfg.macaroon_secret_key}"
-''}
-expire_access_token: ${boolToString cfg.expire_access_token}
-enable_metrics: ${boolToString cfg.enable_metrics}
-report_stats: ${boolToString cfg.report_stats}
-signing_key_path: "${cfg.dataDir}/homeserver.signing.key"
-key_refresh_interval: "${cfg.key_refresh_interval}"
-perspectives:
- servers: {
- ${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
- "${n}": {
- "verify_keys": {
- ${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
- "${n}": {
- "key": "${v}"
- }'') v)}
- }
- '') cfg.servers)}
- }
- }
-redaction_retention_period: ${toString cfg.redaction_retention_period}
-app_service_config_files: ${builtins.toJSON cfg.app_service_config_files}
-
-${cfg.extraConfig}
-'';
-
- hasLocalPostgresDB = let args = cfg.database_args; in
- usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
-
- registerNewMatrixUser =
- let
- isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
- listener =
- lib.findFirst (
- listener: lib.any (
- resource: lib.any (
- name: name == "client"
- ) resource.names
- ) listener.resources
- ) (lib.last cfg.listeners) cfg.listeners;
- in
- pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
- exec ${cfg.package}/bin/register_new_matrix_user \
- $@ \
- ${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \
- "${listener.type}://${
- if (isIpv6 listener.bind_address) then
- "[${listener.bind_address}]"
- else
- "${listener.bind_address}"
- }:${builtins.toString listener.port}/"
- '';
-in {
- options = {
- services.matrix-synapse = {
- enable = mkEnableOption "matrix.org synapse";
- configFile = mkOption {
- type = types.str;
- readOnly = true;
- description = ''
- Path to the configuration file on the target system. Useful to configure e.g. workers
- that also need this.
- '';
- };
- package = mkOption {
- type = types.package;
- default = pkgs.matrix-synapse;
- defaultText = literalExpression "pkgs.matrix-synapse";
- description = ''
- Overridable attribute of the matrix synapse server package to use.
- '';
- };
- plugins = mkOption {
- type = types.listOf types.package;
- default = [ ];
- example = literalExpression ''
- with config.services.matrix-synapse.package.plugins; [
- matrix-synapse-ldap3
- matrix-synapse-pam
- ];
- '';
- description = ''
- List of additional Matrix plugins to make available.
- '';
- };
- withJemalloc = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to preload jemalloc to reduce memory fragmentation and overall usage.
- '';
- };
- no_tls = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Don't bind to the https port
- '';
- };
- bind_port = mkOption {
- type = types.nullOr types.int;
- default = null;
- example = 8448;
- description = ''
- DEPRECATED: Use listeners instead.
- The port to listen for HTTPS requests on.
- For when matrix traffic is sent directly to synapse.
- '';
- };
- unsecure_port = mkOption {
- type = types.nullOr types.int;
- default = null;
- example = 8008;
- description = ''
- DEPRECATED: Use listeners instead.
- The port to listen for HTTP requests on.
- For when matrix traffic passes through loadbalancer that unwraps TLS.
- '';
- };
- bind_host = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- DEPRECATED: Use listeners instead.
- Local interface to listen on.
- The empty string will cause synapse to listen on all interfaces.
- '';
- };
- tls_certificate_path = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "/var/lib/matrix-synapse/homeserver.tls.crt";
- description = ''
- PEM encoded X509 certificate for TLS.
- You can replace the self-signed certificate that synapse
- autogenerates on launch with your own SSL certificate + key pair
- if you like. Any required intermediary certificates can be
- appended after the primary certificate in hierarchical order.
- '';
- };
- tls_private_key_path = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "/var/lib/matrix-synapse/homeserver.tls.key";
- description = ''
- PEM encoded private key for TLS. Specify null if synapse is not
- speaking TLS directly.
- '';
- };
- tls_dh_params_path = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "/var/lib/matrix-synapse/homeserver.tls.dh";
- description = ''
- PEM dh parameters for ephemeral keys
- '';
- };
- server_name = mkOption {
- type = types.str;
- example = "example.com";
- default = config.networking.hostName;
- defaultText = literalExpression "config.networking.hostName";
- description = ''
- The domain name of the server, with optional explicit port.
- This is used by remote servers to look up the server address.
- This is also the last part of your UserID.
-
- The server_name cannot be changed later so it is important to configure this correctly before you start Synapse.
- '';
- };
- public_baseurl = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "https://example.com:8448/";
- description = ''
- The public-facing base URL for the client API (not including _matrix/...)
- '';
- };
- listeners = mkOption {
- type = types.listOf (types.submodule {
- options = {
- port = mkOption {
- type = types.port;
- example = 8448;
- description = ''
- The port to listen for HTTP(S) requests on.
- '';
- };
- bind_address = mkOption {
- type = types.str;
- default = "";
- example = "203.0.113.42";
- description = ''
- Local interface to listen on.
- The empty string will cause synapse to listen on all interfaces.
- '';
- };
- type = mkOption {
- type = types.str;
- default = "http";
- description = ''
- Type of listener.
- '';
- };
- tls = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to listen for HTTPS connections rather than HTTP.
- '';
- };
- x_forwarded = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Use the X-Forwarded-For (XFF) header as the client IP and not the
- actual client IP.
- '';
- };
- resources = mkOption {
- type = types.listOf (types.submodule {
- options = {
- names = mkOption {
- type = types.listOf types.str;
- description = ''
- List of resources to host on this listener.
- '';
- example = ["client" "federation"];
- };
- compress = mkOption {
- type = types.bool;
- description = ''
- Should synapse compress HTTP responses to clients that support it?
- This should be disabled if running synapse behind a load balancer
- that can do automatic compression.
- '';
- };
- };
- });
- description = ''
- List of HTTP resources to serve on this listener.
- '';
- };
- };
- });
- default = [{
- port = 8448;
- bind_address = "";
- type = "http";
- tls = true;
- x_forwarded = false;
- resources = [
- { names = ["client"]; compress = true; }
- { names = ["federation"]; compress = false; }
- ];
- }];
- description = ''
- List of ports that Synapse should listen on, their purpose and their configuration.
- '';
- };
- verbose = mkOption {
- type = types.str;
- default = "0";
- description = "Logging verbosity level.";
- };
- rc_messages_per_second = mkOption {
- type = types.str;
- default = "0.2";
- description = "Number of messages a client can send per second";
- };
- rc_message_burst_count = mkOption {
- type = types.str;
- default = "10.0";
- description = "Number of message a client can send before being throttled";
- };
- federation_rc_window_size = mkOption {
- type = types.str;
- default = "1000";
- description = "The federation window size in milliseconds";
- };
- federation_rc_sleep_limit = mkOption {
- type = types.str;
- default = "10";
- description = ''
- The number of federation requests from a single server in a window
- before the server will delay processing the request.
- '';
- };
- federation_rc_sleep_delay = mkOption {
- type = types.str;
- default = "500";
- description = ''
- The duration in milliseconds to delay processing events from
- remote servers by if they go over the sleep limit.
- '';
- };
- federation_rc_reject_limit = mkOption {
- type = types.str;
- default = "50";
- description = ''
- The maximum number of concurrent federation requests allowed
- from a single server
- '';
- };
- federation_rc_concurrent = mkOption {
- type = types.str;
- default = "3";
- description = "The number of federation requests to concurrently process from a single server";
- };
- database_type = mkOption {
- type = types.enum [ "sqlite3" "psycopg2" ];
- default = if versionAtLeast config.system.stateVersion "18.03"
- then "psycopg2"
- else "sqlite3";
- defaultText = literalExpression ''
- if versionAtLeast config.system.stateVersion "18.03"
- then "psycopg2"
- else "sqlite3"
- '';
- description = ''
- The database engine name. Can be sqlite or psycopg2.
- '';
- };
- database_name = mkOption {
- type = types.str;
- default = "matrix-synapse";
- description = "Database name.";
- };
- database_user = mkOption {
- type = types.str;
- default = "matrix-synapse";
- description = "Database user name.";
- };
- database_args = mkOption {
- type = types.attrs;
- default = {
- sqlite3 = { database = "${cfg.dataDir}/homeserver.db"; };
- psycopg2 = {
- user = cfg.database_user;
- database = cfg.database_name;
- };
- }.${cfg.database_type};
- defaultText = literalDocBook ''
-
-
- using sqlite3
-
-
- { database = "''${config.${opt.dataDir}}/homeserver.db"; }
-
-
-
-
- using psycopg2
-
-
- psycopg2 = {
- user = config.${opt.database_user};
- database = config.${opt.database_name};
- }
-
-
-
-
- '';
- description = ''
- Arguments to pass to the engine.
- '';
- };
- event_cache_size = mkOption {
- type = types.str;
- default = "10K";
- description = "Number of events to cache in memory.";
- };
- url_preview_enabled = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Is the preview URL API enabled? If enabled, you *must* specify an
- explicit url_preview_ip_range_blacklist of IPs that the spider is
- denied from accessing.
- '';
- };
- url_preview_ip_range_blacklist = mkOption {
- type = types.listOf types.str;
- default = [
- "127.0.0.0/8"
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "100.64.0.0/10"
- "169.254.0.0/16"
- "::1/128"
- "fe80::/64"
- "fc00::/7"
- ];
- description = ''
- List of IP address CIDR ranges that the URL preview spider is denied
- from accessing.
- '';
- };
- url_preview_ip_range_whitelist = mkOption {
- type = types.listOf types.str;
- default = [];
- description = ''
- List of IP address CIDR ranges that the URL preview spider is allowed
- to access even if they are specified in
- url_preview_ip_range_blacklist.
- '';
- };
- url_preview_url_blacklist = mkOption {
- type = types.listOf types.str;
- default = [];
- description = ''
- Optional list of URL matches that the URL preview spider is
- denied from accessing.
- '';
- };
- recaptcha_private_key = mkOption {
- type = types.str;
- default = "";
- description = ''
- This Home Server's ReCAPTCHA private key.
- '';
- };
- recaptcha_public_key = mkOption {
- type = types.str;
- default = "";
- description = ''
- This Home Server's ReCAPTCHA public key.
- '';
- };
- enable_registration_captcha = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enables ReCaptcha checks when registering, preventing signup
- unless a captcha is answered. Requires a valid ReCaptcha
- public/private key.
- '';
- };
- turn_uris = mkOption {
- type = types.listOf types.str;
- default = [];
- description = ''
- The public URIs of the TURN server to give to clients
- '';
- };
- turn_shared_secret = mkOption {
- type = types.str;
- default = "";
- description = ''
- The shared secret used to compute passwords for the TURN server
- '';
- };
- turn_user_lifetime = mkOption {
- type = types.str;
- default = "1h";
- description = "How long generated TURN credentials last";
- };
- enable_registration = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enable registration for new users.
- '';
- };
- registration_shared_secret = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- If set, allows registration by anyone who also has the shared
- secret, even if registration is otherwise disabled.
- '';
- };
- enable_metrics = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enable collection and rendering of performance metrics
- '';
- };
- report_stats = mkOption {
- type = types.bool;
- default = false;
- description = "";
- };
- servers = mkOption {
- type = types.attrsOf (types.attrsOf types.str);
- default = {
- "matrix.org" = {
- "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
- };
- };
- description = ''
- The trusted servers to download signing keys from.
- '';
- };
- max_upload_size = mkOption {
- type = types.str;
- default = "10M";
- description = "The largest allowed upload size in bytes";
- };
- max_image_pixels = mkOption {
- type = types.str;
- default = "32M";
- description = "Maximum number of pixels that will be thumbnailed";
- };
- dynamic_thumbnails = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to generate new thumbnails on the fly to precisely match
- the resolution requested by the client. If true then whenever
- a new resolution is requested by the client the server will
- generate a new thumbnail. If false the server will pick a thumbnail
- from a precalculated list.
- '';
- };
- user_creation_max_duration = mkOption {
- type = types.str;
- default = "1209600000";
- description = ''
- Sets the expiry for the short term user creation in
- milliseconds. The default value is two weeks.
- '';
- };
- bcrypt_rounds = mkOption {
- type = types.str;
- default = "12";
- description = ''
- Set the number of bcrypt rounds used to generate password hash.
- Larger numbers increase the work factor needed to generate the hash.
- '';
- };
- allow_guest_access = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Allows users to register as guests without a password/email/etc, and
- participate in rooms hosted on this server which have been made
- accessible to anonymous users.
- '';
- };
- account_threepid_delegates.email = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Delegate email sending to https://example.org
- '';
- };
- account_threepid_delegates.msisdn = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Delegate SMS sending to this local process (https://localhost:8090)
- '';
- };
- room_prejoin_state.additional_event_types = mkOption {
- default = [];
- type = types.listOf types.str;
- description = ''
- Additional events to share with users who received an invite.
- '';
- };
- room_prejoin_state.disable_default_event_types = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Whether to disable the default state-event types for users invited to a room.
- These are:
-
-
- m.room.join_rules
- m.room.canonical_alias
- m.room.avatar
- m.room.encryption
- m.room.name
- m.room.create
-
- '';
- };
- macaroon_secret_key = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Secret key for authentication tokens
- '';
- };
- expire_access_token = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to enable access token expiration.
- '';
- };
- key_refresh_interval = mkOption {
- type = types.str;
- default = "1d";
- description = ''
- How long key response published by this server is valid for.
- Used to set the valid_until_ts in /key/v2 APIs.
- Determines how quickly servers will query to check which keys
- are still valid.
- '';
- };
- app_service_config_files = mkOption {
- type = types.listOf types.path;
- default = [ ];
- description = ''
- A list of application service config file to use
- '';
- };
- redaction_retention_period = mkOption {
- type = types.int;
- default = 7;
- description = ''
- How long to keep redacted events in unredacted form in the database.
- '';
- };
- extraConfig = mkOption {
- type = types.lines;
- default = "";
- description = ''
- Extra config options for matrix-synapse.
- '';
- };
- extraConfigFiles = mkOption {
- type = types.listOf types.path;
- default = [];
- description = ''
- Extra config files to include.
-
- The configuration files will be included based on the command line
- argument --config-path. This allows to configure secrets without
- having to go through the Nix store, e.g. based on deployment keys if
- NixOPS is in use.
- '';
- };
- logConfig = mkOption {
- type = types.lines;
- default = readFile ./matrix-synapse-log_config.yaml;
- description = ''
- A yaml python logging config file
- '';
- };
- dataDir = mkOption {
- type = types.str;
- default = "/var/lib/matrix-synapse";
- description = ''
- The directory where matrix-synapse stores its stateful data such as
- certificates, media and uploads.
- '';
- };
- };
- };
-
- config = mkIf cfg.enable {
- assertions = [
- { assertion = hasLocalPostgresDB -> config.services.postgresql.enable;
- message = ''
- Cannot deploy matrix-synapse with a configuration for a local postgresql database
- and a missing postgresql service. Since 20.03 it's mandatory to manually configure the
- database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for
- further reference).
-
- If you
- - try to deploy a fresh synapse, you need to configure the database yourself. An example
- for this can be found in
- - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true`
- to your configuration.
-
- For further information about this update, please read the release-notes of 20.03 carefully.
- '';
- }
- ];
-
- services.matrix-synapse.configFile = "${configFile}";
-
- users.users.matrix-synapse = {
- group = "matrix-synapse";
- home = cfg.dataDir;
- createHome = true;
- shell = "${pkgs.bash}/bin/bash";
- uid = config.ids.uids.matrix-synapse;
- };
-
- users.groups.matrix-synapse = {
- gid = config.ids.gids.matrix-synapse;
- };
-
- systemd.services.matrix-synapse = {
- description = "Synapse Matrix homeserver";
- after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
- wantedBy = [ "multi-user.target" ];
- preStart = ''
- ${cfg.package}/bin/synapse_homeserver \
- --config-path ${configFile} \
- --keys-directory ${cfg.dataDir} \
- --generate-keys
- '';
- environment = {
- PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ];
- } // optionalAttrs (cfg.withJemalloc) {
- LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
- };
- serviceConfig = {
- Type = "notify";
- User = "matrix-synapse";
- Group = "matrix-synapse";
- WorkingDirectory = cfg.dataDir;
- ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" ''
- chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key
- chmod 0600 ${cfg.dataDir}/homeserver.signing.key
- '')) ];
- ExecStart = ''
- ${cfg.package}/bin/synapse_homeserver \
- ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) }
- --keys-directory ${cfg.dataDir}
- '';
- ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
- Restart = "on-failure";
- UMask = "0077";
- };
- };
-
- environment.systemPackages = [ registerNewMatrixUser ];
- };
-
- imports = [
- (mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] ''
- The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0
- as the behavior is now obsolete.
- '')
- (mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] ''
- Database configuration must be done manually. An exemplary setup is demonstrated in
-
- '')
- (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "")
- (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] ''
- You may add additional event types via
- `services.matrix-synapse.room_prejoin_state.additional_event_types` and
- disable the default events via
- `services.matrix-synapse.room_prejoin_state.disable_default_event_types`.
- '')
- ];
-
- meta.doc = ./matrix-synapse.xml;
- meta.maintainers = teams.matrix.members;
-
-}
diff --git a/nixos/modules/services/misc/mbpfan.nix b/nixos/modules/services/misc/mbpfan.nix
index d2b0f0da2ad9..e0a4d8a13e75 100644
--- a/nixos/modules/services/misc/mbpfan.nix
+++ b/nixos/modules/services/misc/mbpfan.nix
@@ -6,7 +6,7 @@ let
cfg = config.services.mbpfan;
verbose = if cfg.verbose then "v" else "";
settingsFormat = pkgs.formats.ini {};
- settingsFile = settingsFormat.generate "config.conf" cfg.settings;
+ settingsFile = settingsFormat.generate "mbpfan.ini" cfg.settings;
in {
options.services.mbpfan = {
@@ -36,29 +36,35 @@ in {
freeformType = settingsFormat.type;
options.general.min_fan1_speed = mkOption {
- type = types.int;
+ type = types.nullOr types.int;
default = 2000;
- description = "The minimum fan speed.";
+ description = ''
+ The minimum fan speed. Setting to null enables automatic detection.
+ Check minimum fan limits with "cat /sys/devices/platform/applesmc.768/fan*_min".
+ '';
};
options.general.max_fan1_speed = mkOption {
- type = types.int;
+ type = types.nullOr types.int;
default = 6199;
- description = "The maximum fan speed.";
+ description = ''
+ The maximum fan speed. Setting to null enables automatic detection.
+ Check maximum fan limits with "cat /sys/devices/platform/applesmc.768/fan*_max".
+ '';
};
options.general.low_temp = mkOption {
type = types.int;
default = 55;
- description = "The low temperature.";
+ description = "Temperature below which fan speed will be at minimum. Try ranges 55-63.";
};
options.general.high_temp = mkOption {
type = types.int;
default = 58;
- description = "The high temperature.";
+ description = "Fan will increase speed when higher than this temperature. Try ranges 58-66.";
};
options.general.max_temp = mkOption {
type = types.int;
default = 86;
- description = "The maximum temperature.";
+ description = "Fan will run at full speed above this temperature. Do not set it > 90.";
};
options.general.polling_interval = mkOption {
type = types.int;
diff --git a/nixos/modules/services/misc/mediatomb.nix b/nixos/modules/services/misc/mediatomb.nix
index ea9ffbb86775..ee5c0ef8d277 100644
--- a/nixos/modules/services/misc/mediatomb.nix
+++ b/nixos/modules/services/misc/mediatomb.nix
@@ -217,7 +217,6 @@ in {
package = mkOption {
type = types.package;
- example = literalExpression "pkgs.mediatomb";
default = pkgs.gerbera;
defaultText = literalExpression "pkgs.gerbera";
description = ''
@@ -367,6 +366,7 @@ in {
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${binaryCommand} --port ${toString cfg.port} ${interfaceFlag} ${configFlag} --home ${cfg.dataDir}";
serviceConfig.User = cfg.user;
+ serviceConfig.Group = cfg.group;
};
users.groups = optionalAttrs (cfg.group == "mediatomb") {
diff --git a/nixos/modules/services/misc/moonraker.nix b/nixos/modules/services/misc/moonraker.nix
index ae57aaa6d479..b75227effa04 100644
--- a/nixos/modules/services/misc/moonraker.nix
+++ b/nixos/modules/services/misc/moonraker.nix
@@ -79,6 +79,19 @@ in {
for supported values.
'';
};
+
+ allowSystemControl = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to allow Moonraker to perform system-level operations.
+
+ Moonraker exposes APIs to perform system-level operations, such as
+ reboot, shutdown, and management of systemd units. See the
+ documentation
+ for details on what clients are able to do.
+ '';
+ };
};
};
@@ -86,6 +99,13 @@ in {
warnings = optional (cfg.settings ? update_manager)
''Enabling update_manager is not supported on NixOS and will lead to non-removable warnings in some clients.'';
+ assertions = [
+ {
+ assertion = cfg.allowSystemControl -> config.security.polkit.enable;
+ message = "services.moonraker.allowSystemControl requires polkit to be enabled (security.polkit.enable).";
+ }
+ ];
+
users.users = optionalAttrs (cfg.user == "moonraker") {
moonraker = {
group = cfg.group;
@@ -128,11 +148,31 @@ in {
exec ${pkg}/bin/moonraker -c ${cfg.configDir}/moonraker-temp.cfg
'';
+ # Needs `ip` command
+ path = [ pkgs.iproute2 ];
+
serviceConfig = {
WorkingDirectory = cfg.stateDir;
Group = cfg.group;
User = cfg.user;
};
};
+
+ security.polkit.extraConfig = lib.optionalString cfg.allowSystemControl ''
+ // nixos/moonraker: Allow Moonraker to perform system-level operations
+ //
+ // This was enabled via services.moonraker.allowSystemControl.
+ polkit.addRule(function(action, subject) {
+ if ((action.id == "org.freedesktop.systemd1.manage-units" ||
+ action.id == "org.freedesktop.login1.power-off" ||
+ action.id == "org.freedesktop.login1.power-off-multiple-sessions" ||
+ action.id == "org.freedesktop.login1.reboot" ||
+ action.id == "org.freedesktop.login1.reboot-multiple-sessions" ||
+ action.id.startsWith("org.freedesktop.packagekit.")) &&
+ subject.user == "${cfg.user}") {
+ return polkit.Result.YES;
+ }
+ });
+ '';
};
}
diff --git a/nixos/modules/services/misc/mx-puppet-discord.nix b/nixos/modules/services/misc/mx-puppet-discord.nix
index b6f5e04511ae..6214f7f7eb6b 100644
--- a/nixos/modules/services/misc/mx-puppet-discord.nix
+++ b/nixos/modules/services/misc/mx-puppet-discord.nix
@@ -79,10 +79,7 @@ in {
config = mkIf cfg.enable {
systemd.services.mx-puppet-discord = {
- description = ''
- mx-puppet-discord is a discord puppeting bridge for matrix.
- It handles bridging private and group DMs, as well as Guilds (servers).
- '';
+ description = "Matrix to Discord puppeting bridge";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
diff --git a/nixos/modules/services/misc/nitter.nix b/nixos/modules/services/misc/nitter.nix
index 6a9eeb02095c..97005c9d914f 100644
--- a/nixos/modules/services/misc/nitter.nix
+++ b/nixos/modules/services/misc/nitter.nix
@@ -49,6 +49,13 @@ in
services.nitter = {
enable = mkEnableOption "If enabled, start Nitter.";
+ package = mkOption {
+ default = pkgs.nitter;
+ type = types.package;
+ defaultText = literalExpression "pkgs.nitter";
+ description = "The nitter derivation to use.";
+ };
+
server = {
address = mkOption {
type = types.str;
@@ -78,8 +85,8 @@ in
staticDir = mkOption {
type = types.path;
- default = "${pkgs.nitter}/share/nitter/public";
- defaultText = literalExpression ''"''${pkgs.nitter}/share/nitter/public"'';
+ default = "${cfg.package}/share/nitter/public";
+ defaultText = literalExpression ''"''${config.services.nitter.package}/share/nitter/public"'';
description = "Path to the static files directory.";
};
@@ -306,8 +313,8 @@ in
Environment = [ "NITTER_CONF_FILE=/var/lib/nitter/nitter.conf" ];
# Some parts of Nitter expect `public` folder in working directory,
# see https://github.com/zedeus/nitter/issues/414
- WorkingDirectory = "${pkgs.nitter}/share/nitter";
- ExecStart = "${pkgs.nitter}/bin/nitter";
+ WorkingDirectory = "${cfg.package}/share/nitter";
+ ExecStart = "${cfg.package}/bin/nitter";
ExecStartPre = "${preStart}";
AmbientCapabilities = lib.mkIf (cfg.server.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
Restart = "on-failure";
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 869feb05eb7b..4bc5b04d3a08 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -6,20 +6,20 @@ let
cfg = config.nix;
- nix = cfg.package.out;
+ nixPackage = cfg.package.out;
- nixVersion = getVersion nix;
-
- isNix23 = versionAtLeast nixVersion "2.3pre";
+ isNixAtLeast = versionAtLeast (getVersion nixPackage);
makeNixBuildUser = nr: {
- name = "nixbld${toString nr}";
+ name = "nixbld${toString nr}";
value = {
description = "Nix build user ${toString nr}";
- /* For consistency with the setgid(2), setuid(2), and setgroups(2)
- calls in `libstore/build.cc', don't add any supplementary group
- here except "nixbld". */
+ /*
+ For consistency with the setgid(2), setuid(2), and setgroups(2)
+ calls in `libstore/build.cc', don't add any supplementary group
+ here except "nixbld".
+ */
uid = builtins.add config.ids.uids.nixbld nr;
isSystemUser = true;
group = "nixbld";
@@ -30,53 +30,93 @@ let
nixbldUsers = listToAttrs (map makeNixBuildUser (range 1 cfg.nrBuildUsers));
nixConf =
- assert versionAtLeast nixVersion "2.2";
- pkgs.runCommand "nix.conf" { preferLocalBuild = true; extraOptions = cfg.extraOptions; } (
- ''
- cat > $out </dev/null
- '')
- );
+ ${mkKeyValuePairs cfg.settings}
+ ${cfg.extraOptions}
+ '';
+ checkPhase =
+ if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
+ echo "Ignoring validation for cross-compilation"
+ ''
+ else ''
+ echo "Validating generated nix.conf"
+ ln -s $out ./nix.conf
+ set -e
+ set +o pipefail
+ NIX_CONF_DIR=$PWD \
+ ${cfg.package}/bin/nix show-config ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \
+ ${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \
+ |& sed -e 's/^warning:/error:/' \
+ | (! grep '${if cfg.checkConfig then "^error:" else "^error: unknown setting"}')
+ set -o pipefail
+ '';
+ };
+
+ legacyConfMappings = {
+ useSandbox = "sandbox";
+ buildCores = "cores";
+ maxJobs = "max-jobs";
+ sandboxPaths = "extra-sandbox-paths";
+ binaryCaches = "substituters";
+ trustedBinaryCaches = "trusted-substituters";
+ binaryCachePublicKeys = "trusted-public-keys";
+ autoOptimiseStore = "auto-optimise-store";
+ requireSignedBinaryCaches = "require-sigs";
+ trustedUsers = "trusted-users";
+ allowedUsers = "allowed-users";
+ systemFeatures = "system-features";
+ };
+
+ semanticConfType = with types;
+ let
+ confAtom = nullOr
+ (oneOf [
+ bool
+ int
+ float
+ str
+ path
+ package
+ ]) // {
+ description = "Nix config atom (null, bool, int, float, str, path or package)";
+ };
+ in
+ attrsOf (either confAtom (listOf confAtom));
in
{
imports = [
- (mkRenamedOptionModule [ "nix" "useChroot" ] [ "nix" "useSandbox" ])
- (mkRenamedOptionModule [ "nix" "chrootDirs" ] [ "nix" "sandboxPaths" ])
- (mkRenamedOptionModule [ "nix" "daemonIONiceLevel" ] [ "nix" "daemonIOSchedPriority" ])
+ (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "useChroot" ]; to = [ "nix" "useSandbox" ]; })
+ (mkRenamedOptionModuleWith { sinceRelease = 2003; from = [ "nix" "chrootDirs" ]; to = [ "nix" "sandboxPaths" ]; })
+ (mkRenamedOptionModuleWith { sinceRelease = 2205; from = [ "nix" "daemonIONiceLevel" ]; to = [ "nix" "daemonIOSchedPriority" ]; })
(mkRemovedOptionModule [ "nix" "daemonNiceLevel" ] "Consider nix.daemonCPUSchedPolicy instead.")
- ];
+ ] ++ mapAttrsToList (oldConf: newConf: mkRenamedOptionModuleWith { sinceRelease = 2205; from = [ "nix" oldConf ]; to = [ "nix" "settings" newConf ]; }) legacyConfMappings;
###### interface
@@ -102,81 +142,6 @@ in
'';
};
- maxJobs = mkOption {
- type = types.either types.int (types.enum ["auto"]);
- default = "auto";
- example = 64;
- description = ''
- This option defines the maximum number of jobs that Nix will try to
- build in parallel. The default is auto, which means it will use all
- available logical cores. It is recommend to set it to the total
- number of logical cores in your system (e.g., 16 for two CPUs with 4
- cores each and hyper-threading).
- '';
- };
-
- autoOptimiseStore = mkOption {
- type = types.bool;
- default = false;
- example = true;
- description = ''
- If set to true, Nix automatically detects files in the store that have
- identical contents, and replaces them with hard links to a single copy.
- This saves disk space. If set to false (the default), you can still run
- nix-store --optimise to get rid of duplicate files.
- '';
- };
-
- buildCores = mkOption {
- type = types.int;
- default = 0;
- example = 64;
- description = ''
- This option defines the maximum number of concurrent tasks during
- one build. It affects, e.g., -j option for make.
- The special value 0 means that the builder should use all
- available CPU cores in the system. Some builds may become
- non-deterministic with this option; use with care! Packages will
- only be affected if enableParallelBuilding is set for them.
- '';
- };
-
- useSandbox = mkOption {
- type = types.either types.bool (types.enum ["relaxed"]);
- default = true;
- description = "
- If set, Nix will perform builds in a sandboxed environment that it
- will set up automatically for each build. This prevents impurities
- in builds by disallowing access to dependencies outside of the Nix
- store by using network and mount namespaces in a chroot environment.
- This is enabled by default even though it has a possible performance
- impact due to the initial setup time of a sandbox for each build. It
- doesn't affect derivation hashes, so changing this option will not
- trigger a rebuild of packages.
- ";
- };
-
- sandboxPaths = mkOption {
- type = types.listOf types.str;
- default = [];
- example = [ "/dev" "/proc" ];
- description =
- ''
- Directories from the host filesystem to be included
- in the sandbox.
- '';
- };
-
- extraOptions = mkOption {
- type = types.lines;
- default = "";
- example = ''
- keep-outputs = true
- keep-derivations = true
- '';
- description = "Additional text appended to nix.conf.";
- };
-
distributedBuilds = mkOption {
type = types.bool;
default = false;
@@ -187,7 +152,7 @@ in
};
daemonCPUSchedPolicy = mkOption {
- type = types.enum ["other" "batch" "idle"];
+ type = types.enum [ "other" "batch" "idle" ];
default = "other";
example = "batch";
description = ''
@@ -218,7 +183,7 @@ in
};
daemonIOSchedClass = mkOption {
- type = types.enum ["best-effort" "idle"];
+ type = types.enum [ "best-effort" "idle" ];
default = "best-effort";
example = "idle";
description = ''
@@ -250,11 +215,11 @@ in
scheduling policy: With idle, priorities are not used in scheduling
decisions. best-effort supports values in the range 0 (high) to 7
(low).
- '';
+ '';
};
buildMachines = mkOption {
- type = types.listOf (types.submodule ({
+ type = types.listOf (types.submodule {
options = {
hostName = mkOption {
type = types.str;
@@ -276,7 +241,7 @@ in
};
systems = mkOption {
type = types.listOf types.str;
- default = [];
+ default = [ ];
example = [ "x86_64-linux" "aarch64-linux" ];
description = ''
The system types the build machine can execute derivations on.
@@ -293,7 +258,7 @@ in
The username to log in as on the remote host. This user must be
able to log in and run nix commands non-interactively. It must
also be privileged to build derivations, so must be included in
- .
+ .
'';
};
sshKey = mkOption {
@@ -331,7 +296,7 @@ in
};
mandatoryFeatures = mkOption {
type = types.listOf types.str;
- default = [];
+ default = [ ];
example = [ "big-parallel" ];
description = ''
A list of features mandatory for this builder. The builder will
@@ -342,7 +307,7 @@ in
};
supportedFeatures = mkOption {
type = types.listOf types.str;
- default = [];
+ default = [ ];
example = [ "kvm" "big-parallel" ];
description = ''
A list of features supported by this builder. The builder will
@@ -350,9 +315,18 @@ in
list.
'';
};
+ publicHostKey = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ The (base64-encoded) public host key of this builder. The field
+ is calculated via base64 -w0 /etc/ssh/ssh_host_type_key.pub.
+ If null, SSH will use its regular known-hosts file when connecting.
+ '';
+ };
};
- }));
- default = [];
+ });
+ default = [ ];
description = ''
This option lists the machines to be used if distributed builds are
enabled (see ).
@@ -366,7 +340,7 @@ in
envVars = mkOption {
type = types.attrs;
internal = true;
- default = {};
+ default = { };
description = "Environment variables used by Nix.";
};
@@ -391,92 +365,13 @@ in
'';
};
- binaryCaches = mkOption {
- type = types.listOf types.str;
- description = ''
- List of binary cache URLs used to obtain pre-built binaries
- of Nix packages.
-
- By default https://cache.nixos.org/ is added,
- to override it use lib.mkForce [].
- '';
- };
-
- trustedBinaryCaches = mkOption {
- type = types.listOf types.str;
- default = [ ];
- example = [ "https://hydra.nixos.org/" ];
- description = ''
- List of binary cache URLs that non-root users can use (in
- addition to those specified using
- ) by passing
- --option binary-caches to Nix commands.
- '';
- };
-
- requireSignedBinaryCaches = mkOption {
- type = types.bool;
- default = true;
- description = ''
- If enabled (the default), Nix will only download binaries from binary caches if
- they are cryptographically signed with any of the keys listed in
- . If disabled, signatures are neither
- required nor checked, so it's strongly recommended that you use only
- trustworthy caches and https to prevent man-in-the-middle attacks.
- '';
- };
-
- binaryCachePublicKeys = mkOption {
- type = types.listOf types.str;
- example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ];
- description = ''
- List of public keys used to sign binary caches. If
- is enabled,
- then Nix will use a binary from a binary cache if and only
- if it is signed by any of the keys
- listed here. By default, only the key for
- cache.nixos.org is included.
- '';
- };
-
- trustedUsers = mkOption {
- type = types.listOf types.str;
- default = [ "root" ];
- example = [ "root" "alice" "@wheel" ];
- description = ''
- A list of names of users that have additional rights when
- connecting to the Nix daemon, such as the ability to specify
- additional binary caches, or to import unsigned NARs. You
- can also specify groups by prefixing them with
- @; for instance,
- @wheel means all users in the wheel
- group.
- '';
- };
-
- allowedUsers = mkOption {
- type = types.listOf types.str;
- default = [ "*" ];
- example = [ "@wheel" "@builders" "alice" "bob" ];
- description = ''
- A list of names of users (separated by whitespace) that are
- allowed to connect to the Nix daemon. As with
- , you can specify groups by
- prefixing them with @. Also, you can
- allow all users by specifying *. The
- default is *. Note that trusted users are
- always allowed to connect.
- '';
- };
-
nixPath = mkOption {
type = types.listOf types.str;
- default =
- [
- "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos"
- "nixos-config=/etc/nixos/configuration.nix"
- "/nix/var/nix/profiles/per-user/root/channels"
- ];
+ default = [
+ "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos"
+ "nixos-config=/etc/nixos/configuration.nix"
+ "/nix/var/nix/profiles/per-user/root/channels"
+ ];
description = ''
The default Nix expression search path, used by the Nix
evaluator to look up paths enclosed in angle brackets
@@ -484,45 +379,44 @@ in
'';
};
- systemFeatures = mkOption {
- type = types.listOf types.str;
- example = [ "kvm" "big-parallel" "gccarch-skylake" ];
- description = ''
- The supported features of a machine
- '';
- };
-
checkConfig = mkOption {
type = types.bool;
default = true;
description = ''
- If enabled (the default), checks that Nix can parse the generated nix.conf.
+ If enabled (the default), checks for data type mismatches and that Nix
+ can parse the generated nix.conf.
'';
};
registry = mkOption {
type = types.attrsOf (types.submodule (
let
- inputAttrs = types.attrsOf (types.oneOf [types.str types.int types.bool types.package]);
+ referenceAttrs = with types; attrsOf (oneOf [
+ str
+ int
+ bool
+ package
+ ]);
in
{ config, name, ... }:
- { options = {
+ {
+ options = {
from = mkOption {
- type = inputAttrs;
+ type = referenceAttrs;
example = { type = "indirect"; id = "nixpkgs"; };
description = "The flake reference to be rewritten.";
};
to = mkOption {
- type = inputAttrs;
+ type = referenceAttrs;
example = { type = "github"; owner = "my-org"; repo = "my-nixpkgs"; };
- description = "The flake reference to which is to be rewritten.";
+ description = "The flake reference is rewritten to.";
};
flake = mkOption {
type = types.nullOr types.attrs;
default = null;
example = literalExpression "nixpkgs";
description = ''
- The flake input to which is to be rewritten.
+ The flake input is rewritten to.
'';
};
exact = mkOption {
@@ -537,35 +431,232 @@ in
};
config = {
from = mkDefault { type = "indirect"; id = name; };
- to = mkIf (config.flake != null)
- ({ type = "path";
- path = config.flake.outPath;
- } // lib.filterAttrs
- (n: v: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash")
- config.flake);
+ to = mkIf (config.flake != null) (mkDefault
+ {
+ type = "path";
+ path = config.flake.outPath;
+ } // filterAttrs
+ (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash")
+ config.flake);
};
}
));
- default = {};
+ default = { };
description = ''
A system-wide flake registry.
'';
};
- };
+ extraOptions = mkOption {
+ type = types.lines;
+ default = "";
+ example = ''
+ keep-outputs = true
+ keep-derivations = true
+ '';
+ description = "Additional text appended to nix.conf.";
+ };
+ settings = mkOption {
+ type = types.submodule {
+ freeformType = semanticConfType;
+
+ options = {
+ max-jobs = mkOption {
+ type = types.either types.int (types.enum [ "auto" ]);
+ default = "auto";
+ example = 64;
+ description = ''
+ This option defines the maximum number of jobs that Nix will try to
+ build in parallel. The default is auto, which means it will use all
+ available logical cores. It is recommend to set it to the total
+ number of logical cores in your system (e.g., 16 for two CPUs with 4
+ cores each and hyper-threading).
+ '';
+ };
+
+ auto-optimise-store = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ If set to true, Nix automatically detects files in the store that have
+ identical contents, and replaces them with hard links to a single copy.
+ This saves disk space. If set to false (the default), you can still run
+ nix-store --optimise to get rid of duplicate files.
+ '';
+ };
+
+ cores = mkOption {
+ type = types.int;
+ default = 0;
+ example = 64;
+ description = ''
+ This option defines the maximum number of concurrent tasks during
+ one build. It affects, e.g., -j option for make.
+ The special value 0 means that the builder should use all
+ available CPU cores in the system. Some builds may become
+ non-deterministic with this option; use with care! Packages will
+ only be affected if enableParallelBuilding is set for them.
+ '';
+ };
+
+ sandbox = mkOption {
+ type = types.either types.bool (types.enum [ "relaxed" ]);
+ default = true;
+ description = ''
+ If set, Nix will perform builds in a sandboxed environment that it
+ will set up automatically for each build. This prevents impurities
+ in builds by disallowing access to dependencies outside of the Nix
+ store by using network and mount namespaces in a chroot environment.
+ This is enabled by default even though it has a possible performance
+ impact due to the initial setup time of a sandbox for each build. It
+ doesn't affect derivation hashes, so changing this option will not
+ trigger a rebuild of packages.
+ '';
+ };
+
+ extra-sandbox-paths = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ example = [ "/dev" "/proc" ];
+ description = ''
+ Directories from the host filesystem to be included
+ in the sandbox.
+ '';
+ };
+
+ substituters = mkOption {
+ type = types.listOf types.str;
+ description = ''
+ List of binary cache URLs used to obtain pre-built binaries
+ of Nix packages.
+
+ By default https://cache.nixos.org/ is added.
+ '';
+ };
+
+ trusted-substituters = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ example = [ "https://hydra.nixos.org/" ];
+ description = ''
+ List of binary cache URLs that non-root users can use (in
+ addition to those specified using
+ ) by passing
+ --option binary-caches to Nix commands.
+ '';
+ };
+
+ require-sigs = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ If enabled (the default), Nix will only download binaries from binary caches if
+ they are cryptographically signed with any of the keys listed in
+ . If disabled, signatures are neither
+ required nor checked, so it's strongly recommended that you use only
+ trustworthy caches and https to prevent man-in-the-middle attacks.
+ '';
+ };
+
+ trusted-public-keys = mkOption {
+ type = types.listOf types.str;
+ example = [ "hydra.nixos.org-1:CNHJZBh9K4tP3EKF6FkkgeVYsS3ohTl+oS0Qa8bezVs=" ];
+ description = ''
+ List of public keys used to sign binary caches. If
+ is enabled,
+ then Nix will use a binary from a binary cache if and only
+ if it is signed by any of the keys
+ listed here. By default, only the key for
+ cache.nixos.org is included.
+ '';
+ };
+
+ trusted-users = mkOption {
+ type = types.listOf types.str;
+ default = [ "root" ];
+ example = [ "root" "alice" "@wheel" ];
+ description = ''
+ A list of names of users that have additional rights when
+ connecting to the Nix daemon, such as the ability to specify
+ additional binary caches, or to import unsigned NARs. You
+ can also specify groups by prefixing them with
+ @; for instance,
+ @wheel means all users in the wheel
+ group.
+ '';
+ };
+
+ system-features = mkOption {
+ type = types.listOf types.str;
+ example = [ "kvm" "big-parallel" "gccarch-skylake" ];
+ description = ''
+ The set of features supported by the machine. Derivations
+ can express dependencies on system features through the
+ requiredSystemFeatures attribute.
+
+ By default, pseudo-features nixos-test, benchmark,
+ and big-parallel used in Nixpkgs are set, kvm
+ is also included in it is avaliable.
+ '';
+ };
+
+ allowed-users = mkOption {
+ type = types.listOf types.str;
+ default = [ "*" ];
+ example = [ "@wheel" "@builders" "alice" "bob" ];
+ description = ''
+ A list of names of users (separated by whitespace) that are
+ allowed to connect to the Nix daemon. As with
+ , you can specify groups by
+ prefixing them with @. Also, you can
+ allow all users by specifying *. The
+ default is *. Note that trusted users are
+ always allowed to connect.
+ '';
+ };
+ };
+ };
+ default = { };
+ example = literalExpression ''
+ {
+ use-sandbox = true;
+ show-trace = true;
+
+ system-features = [ "big-parallel" "kvm" "recursive-nix" ];
+ sandbox-paths = { "/bin/sh" = "''${pkgs.busybox-sandbox-shell.out}/bin/busybox"; };
+ }
+ '';
+ description = ''
+ Configuration for Nix, see
+ or
+
+ nix.conf
+ 5
+ for avalaible options.
+ The value declared here will be translated directly to the key-value pairs Nix expects.
+
+
+ You can use nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.nix.settings
+ to view the current value. By default it is empty.
+
+
+ Nix configurations defined under will be translated and applied to this
+ option. In addition, configuration specified in which will be appended
+ verbatim to the resulting config file.
+ '';
+ };
+ };
};
###### implementation
config = mkIf cfg.enable {
-
- nix.binaryCachePublicKeys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
- nix.binaryCaches = [ "https://cache.nixos.org/" ];
-
environment.systemPackages =
- [ nix
+ [
+ nixPackage
pkgs.nix-info
]
++ optional (config.programs.bash.enableCompletion) pkgs.nix-bash-completions;
@@ -579,44 +670,49 @@ in
# List of machines for distributed Nix builds in the format
# expected by build-remote.pl.
- environment.etc."nix/machines" =
- { enable = cfg.buildMachines != [];
- text =
- concatMapStrings (machine:
- "${if machine.sshUser != null then "${machine.sshUser}@" else ""}${machine.hostName} "
- + (if machine.system != null then machine.system else concatStringsSep "," machine.systems)
- + " ${if machine.sshKey != null then machine.sshKey else "-"} ${toString machine.maxJobs} "
- + toString (machine.speedFactor)
- + " "
- + concatStringsSep "," (machine.mandatoryFeatures ++ machine.supportedFeatures)
- + " "
- + concatStringsSep "," machine.mandatoryFeatures
+ environment.etc."nix/machines" = mkIf (cfg.buildMachines != [ ]) {
+ text =
+ concatMapStrings
+ (machine:
+ (concatStringsSep " " ([
+ "${optionalString (machine.sshUser != null) "${machine.sshUser}@"}${machine.hostName}"
+ (if machine.system != null then machine.system else if machine.systems != [ ] then concatStringsSep "," machine.systems else "-")
+ (if machine.sshKey != null then machine.sshKey else "-")
+ (toString machine.maxJobs)
+ (toString machine.speedFactor)
+ (concatStringsSep "," (machine.supportedFeatures ++ machine.mandatoryFeatures))
+ (concatStringsSep "," machine.mandatoryFeatures)
+ ]
+ ++ optional (isNixAtLeast "2.4pre") (if machine.publicHostKey != null then machine.publicHostKey else "-")))
+ "\n"
- ) cfg.buildMachines;
- };
+ )
+ cfg.buildMachines;
+ };
+
assertions =
- let badMachine = m: m.system == null && m.systems == [];
- in [
+ let badMachine = m: m.system == null && m.systems == [ ];
+ in
+ [
{
- assertion = !(builtins.any badMachine cfg.buildMachines);
+ assertion = !(any badMachine cfg.buildMachines);
message = ''
At least one system type (via system or
systems) must be set for every build machine.
Invalid machine specifications:
'' + " " +
- (builtins.concatStringsSep "\n "
- (builtins.map (m: m.hostName)
- (builtins.filter (badMachine) cfg.buildMachines)));
+ (concatStringsSep "\n "
+ (map (m: m.hostName)
+ (filter (badMachine) cfg.buildMachines)));
}
];
-
- systemd.packages = [ nix ];
+ systemd.packages = [ nixPackage ];
systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ];
systemd.services.nix-daemon =
- { path = [ nix pkgs.util-linux config.programs.ssh.package ]
+ {
+ path = [ nixPackage pkgs.util-linux config.programs.ssh.package ]
++ optionals cfg.distributedBuilds [ pkgs.gzip ];
environment = cfg.envVars
@@ -626,19 +722,52 @@ in
unitConfig.RequiresMountsFor = "/nix/store";
serviceConfig =
- { CPUSchedulingPolicy = cfg.daemonCPUSchedPolicy;
+ {
+ CPUSchedulingPolicy = cfg.daemonCPUSchedPolicy;
IOSchedulingClass = cfg.daemonIOSchedClass;
IOSchedulingPriority = cfg.daemonIOSchedPriority;
LimitNOFILE = 4096;
};
restartTriggers = [ nixConf ];
+
+ # `stopIfChanged = false` changes to switch behavior
+ # from stop -> update units -> start
+ # to update units -> restart
+ #
+ # The `stopIfChanged` setting therefore controls a trade-off between a
+ # more predictable lifecycle, which runs the correct "version" of
+ # the `ExecStop` line, and on the other hand the availability of
+ # sockets during the switch, as the effectiveness of the stop operation
+ # depends on the socket being stopped as well.
+ #
+ # As `nix-daemon.service` does not make use of `ExecStop`, we prefer
+ # to keep the socket up and available. This is important for machines
+ # that run Nix-based services, such as automated build, test, and deploy
+ # services, that expect the daemon socket to be available at all times.
+ #
+ # Notably, the Nix client does not retry on failure to connect to the
+ # daemon socket, and the in-process RemoteStore instance will disable
+ # itself. This makes retries infeasible even for services that are
+ # aware of the issue. Failure to connect can affect not only new client
+ # processes, but also new RemoteStore instances in existing processes,
+ # as well as existing RemoteStore instances that have not saturated
+ # their connection pool.
+ #
+ # Also note that `stopIfChanged = true` does not kill existing
+ # connection handling daemons, as one might wish to happen before a
+ # breaking Nix upgrade (which is rare). The daemon forks that handle
+ # the individual connections split off into their own sessions, causing
+ # them not to be stopped by systemd.
+ # If a Nix upgrade does require all existing daemon processes to stop,
+ # nix-daemon must do so on its own accord, and only when the new version
+ # starts and detects that Nix's persistent state needs an upgrade.
+ stopIfChanged = false;
+
};
# Set up the environment variables for running Nix.
- environment.sessionVariables = cfg.envVars //
- { NIX_PATH = cfg.nixPath;
- };
+ environment.sessionVariables = cfg.envVars // { NIX_PATH = cfg.nixPath; };
environment.extraInit =
''
@@ -647,7 +776,7 @@ in
fi
'';
- nix.nrBuildUsers = mkDefault (lib.max 32 (if cfg.maxJobs == "auto" then 0 else cfg.maxJobs));
+ nix.nrBuildUsers = mkDefault (max 32 (if cfg.settings.max-jobs == "auto" then 0 else cfg.settings.max-jobs));
users.users = nixbldUsers;
@@ -663,14 +792,26 @@ in
fi
'';
- nix.systemFeatures = mkDefault (
- [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ++
- optionals (pkgs.hostPlatform ? gcc.arch) (
- # a builder can run code for `gcc.arch` and inferior architectures
- [ "gccarch-${pkgs.hostPlatform.gcc.arch}" ] ++
- map (x: "gccarch-${x}") lib.systems.architectures.inferiors.${pkgs.hostPlatform.gcc.arch}
- )
- );
+ # Legacy configuration conversion.
+ nix.settings = mkMerge [
+ {
+ trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
+ substituters = mkAfter [ "https://cache.nixos.org/" ];
+
+ system-features = mkDefault (
+ [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ++
+ optionals (pkgs.hostPlatform ? gcc.arch) (
+ # a builder can run code for `gcc.arch` and inferior architectures
+ [ "gccarch-${pkgs.hostPlatform.gcc.arch}" ] ++
+ map (x: "gccarch-${x}") systems.architectures.inferiors.${pkgs.hostPlatform.gcc.arch}
+ )
+ );
+ }
+
+ (mkIf (!cfg.distributedBuilds) { builders = null; })
+
+ (mkIf (isNixAtLeast "2.3pre") { sandbox-fallback = false; })
+ ];
};
diff --git a/nixos/modules/services/misc/nix-gc.nix b/nixos/modules/services/misc/nix-gc.nix
index a7a6a3b59644..b4b4b55a6c82 100644
--- a/nixos/modules/services/misc/nix-gc.nix
+++ b/nixos/modules/services/misc/nix-gc.nix
@@ -81,8 +81,14 @@ in
###### implementation
config = {
+ assertions = [
+ {
+ assertion = cfg.automatic -> config.nix.enable;
+ message = ''nix.gc.automatic requires nix.enable'';
+ }
+ ];
- systemd.services.nix-gc = {
+ systemd.services.nix-gc = lib.mkIf config.nix.enable {
description = "Nix Garbage Collector";
script = "exec ${config.nix.package.out}/bin/nix-collect-garbage ${cfg.options}";
startAt = optional cfg.automatic cfg.dates;
diff --git a/nixos/modules/services/misc/nix-optimise.nix b/nixos/modules/services/misc/nix-optimise.nix
index e02026d5f76c..acf8177b146a 100644
--- a/nixos/modules/services/misc/nix-optimise.nix
+++ b/nixos/modules/services/misc/nix-optimise.nix
@@ -37,8 +37,14 @@ in
###### implementation
config = {
+ assertions = [
+ {
+ assertion = cfg.automatic -> config.nix.enable;
+ message = ''nix.optimise.automatic requires nix.enable'';
+ }
+ ];
- systemd.services.nix-optimise =
+ systemd.services.nix-optimise = lib.mkIf config.nix.enable
{ description = "Nix Store Optimiser";
# No point this if the nix daemon (and thus the nix store) is outside
unitConfig.ConditionPathIsReadWrite = "/nix/var/nix/daemon-socket";
diff --git a/nixos/modules/services/misc/nix-ssh-serve.nix b/nixos/modules/services/misc/nix-ssh-serve.nix
index d5c64fdb2647..355fad5db468 100644
--- a/nixos/modules/services/misc/nix-ssh-serve.nix
+++ b/nixos/modules/services/misc/nix-ssh-serve.nix
@@ -20,7 +20,7 @@ in {
write = mkOption {
type = 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 nix.trustedUsers option in most use cases, such as allowing remote building of derivations.";
+ 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 in most use cases, such as allowing remote building of derivations.";
};
keys = mkOption {
diff --git a/nixos/modules/services/misc/packagekit.nix b/nixos/modules/services/misc/packagekit.nix
index 93bd206bd983..9191078ef9ca 100644
--- a/nixos/modules/services/misc/packagekit.nix
+++ b/nixos/modules/services/misc/packagekit.nix
@@ -13,7 +13,7 @@ let
(iniFmt.generate "PackageKit.conf" (recursiveUpdate
{
Daemon = {
- DefaultBackend = "test_nop";
+ DefaultBackend = "nix";
KeepCache = false;
};
}
@@ -35,7 +35,7 @@ let
in
{
imports = [
- (mkRemovedOptionModule [ "services" "packagekit" "backend" ] "The only backend that doesn't blow up is `test_nop`.")
+ (mkRemovedOptionModule [ "services" "packagekit" "backend" ] "Always set to Nix.")
];
options.services.packagekit = {
@@ -62,6 +62,8 @@ in
services.dbus.packages = with pkgs; [ packagekit ];
+ environment.systemPackages = with pkgs; [ packagekit ];
+
systemd.packages = with pkgs; [ packagekit ];
environment.etc = listToAttrs (map
diff --git a/nixos/modules/services/misc/paperless-ng.nix b/nixos/modules/services/misc/paperless-ng.nix
index db8082f072c3..11e44f5ece57 100644
--- a/nixos/modules/services/misc/paperless-ng.nix
+++ b/nixos/modules/services/misc/paperless-ng.nix
@@ -6,12 +6,18 @@ let
defaultUser = "paperless";
+ hasCustomRedis = hasAttr "PAPERLESS_REDIS" cfg.extraConfig;
+
env = {
PAPERLESS_DATA_DIR = cfg.dataDir;
PAPERLESS_MEDIA_ROOT = cfg.mediaDir;
PAPERLESS_CONSUMPTION_DIR = cfg.consumptionDir;
GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}";
- } // lib.mapAttrs (_: toString) cfg.extraConfig;
+ } // (
+ lib.mapAttrs (_: toString) cfg.extraConfig
+ ) // (optionalAttrs (!hasCustomRedis) {
+ PAPERLESS_REDIS = "unix://${config.services.redis.servers.paperless-ng.unixSocket}";
+ });
manage = let
setupEnv = lib.concatStringsSep "\n" (mapAttrsToList (name: val: "export ${name}=\"${val}\"") env);
@@ -30,7 +36,7 @@ let
"-/etc/hosts"
"-/etc/localtime"
"-/run/postgresql"
- ];
+ ] ++ (optional (!hasCustomRedis) config.services.redis.servers.paperless-ng.unixSocket);
BindPaths = [
cfg.consumptionDir
cfg.dataDir
@@ -44,8 +50,7 @@ let
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
- # Needs to connect to redis
- # PrivateNetwork = true;
+ PrivateNetwork = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
@@ -65,6 +70,7 @@ let
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
+ SupplementaryGroups = optional (!hasCustomRedis) config.services.redis.servers.paperless-ng.user;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged @resources @setuid @keyring" ];
# Does not work well with the temporary root
@@ -190,7 +196,7 @@ in
config = mkIf cfg.enable {
# Enable redis if no special url is set
- services.redis.enable = mkIf (!hasAttr "PAPERLESS_REDIS" env) true;
+ services.redis.servers.paperless-ng.enable = mkIf (!hasCustomRedis) true;
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
@@ -208,6 +214,8 @@ in
User = cfg.user;
ExecStart = "${cfg.package}/bin/paperless-ng qcluster";
Restart = "on-failure";
+ # The `mbind` syscall is needed for running the classifier.
+ SystemCallFilter = defaultServiceConfig.SystemCallFilter ++ [ "mbind" ];
};
environment = env;
wantedBy = [ "multi-user.target" ];
@@ -234,6 +242,8 @@ in
echo "$superuserState" > "$superuserStateFile"
fi
'';
+ } // optionalAttrs (!hasCustomRedis) {
+ after = [ "redis-paperless-ng.service" ];
};
# Password copying can't be implemented as a privileged preStart script
@@ -248,6 +258,8 @@ in
'${cfg.passwordFile}' '${cfg.dataDir}/superuser-password'
'';
Type = "oneshot";
+ # Needs to talk to mail server for automated import rules
+ PrivateNetwork = false;
};
};
@@ -279,6 +291,8 @@ in
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
# gunicorn needs setuid
SystemCallFilter = defaultServiceConfig.SystemCallFilter ++ [ "@setuid" ];
+ # Needs to serve web page
+ PrivateNetwork = false;
};
environment = env // {
PATH = mkForce cfg.package.path;
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index 2ae4e80d5c3f..1cd8da768f48 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -6,6 +6,10 @@ let
cfg = config.services.plex;
in
{
+ imports = [
+ (mkRemovedOptionModule [ "services" "plex" "managePlugins" ] "Please omit or define the option: `services.plex.extraPlugins' instead.")
+ ];
+
options = {
services.plex = {
enable = mkEnableOption "Plex Media Server";
@@ -42,16 +46,6 @@ in
'';
};
- managePlugins = mkOption {
- type = types.bool;
- default = true;
- description = ''
- If set to true, this option will cause all of the symlinks in Plex's
- plugin directory to be removed and symlinks for paths specified in
- to be added.
- '';
- };
-
extraPlugins = mkOption {
type = types.listOf types.path;
default = [];
@@ -59,9 +53,20 @@ in
A list of paths to extra plugin bundles to install in Plex's plugin
directory. Every time the systemd unit for Plex starts up, all of the
symlinks in Plex's plugin directory will be cleared and this module
- will symlink all of the paths specified here to that directory. If
- this behavior is undesired, set to
- false.
+ will symlink all of the paths specified here to that directory.
+ '';
+ example = literalExpression ''
+ [
+ (builtins.path {
+ name = "Audnexus.bundle";
+ path = pkgs.fetchFromGitHub {
+ owner = "djdembeck";
+ repo = "Audnexus.bundle";
+ rev = "v0.2.8";
+ sha256 = "sha256-IWOSz3vYL7zhdHan468xNc6C/eQ2C2BukQlaJNLXh7E=";
+ };
+ })
+ ]
'';
};
diff --git a/nixos/modules/services/misc/rmfakecloud.nix b/nixos/modules/services/misc/rmfakecloud.nix
new file mode 100644
index 000000000000..fe522653c216
--- /dev/null
+++ b/nixos/modules/services/misc/rmfakecloud.nix
@@ -0,0 +1,147 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.rmfakecloud;
+ serviceDataDir = "/var/lib/rmfakecloud";
+
+in {
+ options = {
+ services.rmfakecloud = {
+ enable = mkEnableOption "rmfakecloud remarkable self-hosted cloud";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.rmfakecloud;
+ defaultText = literalExpression "pkgs.rmfakecloud";
+ description = ''
+ rmfakecloud package to use.
+
+ The default does not include the web user interface.
+ '';
+ };
+
+ storageUrl = mkOption {
+ type = types.str;
+ example = "https://local.appspot.com";
+ description = ''
+ URL used by the tablet to access the rmfakecloud service.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 3000;
+ description = ''
+ Listening port number.
+ '';
+ };
+
+ logLevel = mkOption {
+ type = types.enum [ "info" "debug" "warn" "error" ];
+ default = "info";
+ description = ''
+ Logging level.
+ '';
+ };
+
+ extraSettings = mkOption {
+ type = with types; attrsOf str;
+ default = { };
+ example = { DATADIR = "/custom/path/for/rmfakecloud/data"; };
+ description = ''
+ Extra settings in the form of a set of key-value pairs.
+ For tokens and secrets, use `environmentFile` instead.
+
+ Available settings are listed on
+ https://ddvk.github.io/rmfakecloud/install/configuration/.
+ '';
+ };
+
+ environmentFile = mkOption {
+ type = with types; nullOr path;
+ default = null;
+ example = "/etc/secrets/rmfakecloud.env";
+ description = ''
+ Path to an environment file loaded for the rmfakecloud service.
+
+ This can be used to securely store tokens and secrets outside of the
+ world-readable Nix store. Since this file is read by systemd, it may
+ have permission 0400 and be owned by root.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.rmfakecloud = {
+ description = "rmfakecloud remarkable self-hosted cloud";
+
+ environment = {
+ STORAGE_URL = cfg.storageUrl;
+ PORT = toString cfg.port;
+ LOGLEVEL = cfg.logLevel;
+ } // cfg.extraSettings;
+
+ preStart = ''
+ # Generate the secret key used to sign client session tokens.
+ # Replacing it invalidates the previously established sessions.
+ if [ -z "$JWT_SECRET_KEY" ] && [ ! -f jwt_secret_key ]; then
+ (umask 077; touch jwt_secret_key)
+ cat /dev/urandom | tr -cd '[:alnum:]' | head -c 48 >> jwt_secret_key
+ fi
+ '';
+
+ script = ''
+ if [ -z "$JWT_SECRET_KEY" ]; then
+ export JWT_SECRET_KEY="$(cat jwt_secret_key)"
+ fi
+
+ ${cfg.package}/bin/rmfakecloud
+ '';
+
+ wantedBy = [ "multi-user.target" ];
+ wants = [ "network-online.target" ];
+ after = [ "network-online.target" ];
+
+ serviceConfig = {
+ Type = "simple";
+ Restart = "always";
+
+ EnvironmentFile =
+ mkIf (cfg.environmentFile != null) cfg.environmentFile;
+
+ AmbientCapabilities =
+ mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
+
+ DynamicUser = true;
+ PrivateDevices = true;
+ ProtectHome = true;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ CapabilityBoundingSet = [ "" ];
+ DevicePolicy = "closed";
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ ProtectClock = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectProc = "invisible";
+ ProcSubset = "pid";
+ RemoveIPC = true;
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ WorkingDirectory = serviceDataDir;
+ StateDirectory = baseNameOf serviceDataDir;
+ UMask = 0027;
+ };
+ };
+ };
+
+ meta.maintainers = with maintainers; [ pacien ];
+}
diff --git a/nixos/modules/services/misc/sourcehut/git.nix b/nixos/modules/services/misc/sourcehut/git.nix
index 5ce16df8cd87..ff110905d184 100644
--- a/nixos/modules/services/misc/sourcehut/git.nix
+++ b/nixos/modules/services/misc/sourcehut/git.nix
@@ -207,7 +207,7 @@ in
fastcgi_param PATH_INFO $uri;
fastcgi_param GIT_PROJECT_ROOT $document_root;
fastcgi_read_timeout 500s;
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
gzip off;
}
'';
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index a894caed1a34..ff63c41e193c 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -106,7 +106,7 @@ let
certtool = "${pkgs.gnutls.bin}/bin/certtool";
- nixos-taskserver = pkgs.pythonPackages.buildPythonApplication {
+ nixos-taskserver = with pkgs.python2.pkgs; buildPythonApplication {
name = "nixos-taskserver";
src = pkgs.runCommand "nixos-taskserver-src" { preferLocalBuild = true; } ''
@@ -129,7 +129,7 @@ let
EOF
'';
- propagatedBuildInputs = [ pkgs.pythonPackages.click ];
+ propagatedBuildInputs = [ click ];
};
in {
@@ -138,12 +138,13 @@ in {
enable = mkOption {
type = types.bool;
default = false;
- description = ''
+ description = let
+ url = "https://nixos.org/manual/nixos/stable/index.html#module-services-taskserver";
+ in ''
Whether to enable the Taskwarrior server.
More instructions about NixOS in conjuction with Taskserver can be
- found in the NixOS manual at
- .
+ found in the NixOS manual.
'';
};
diff --git a/nixos/modules/services/misc/taskserver/doc.xml b/nixos/modules/services/misc/taskserver/doc.xml
index 5656bb85b373..f6ead7c37857 100644
--- a/nixos/modules/services/misc/taskserver/doc.xml
+++ b/nixos/modules/services/misc/taskserver/doc.xml
@@ -1,7 +1,7 @@
+ xml:id="module-services-taskserver">
Taskserver
Taskserver is the server component of
diff --git a/nixos/modules/services/misc/zoneminder.nix b/nixos/modules/services/misc/zoneminder.nix
index 407742f72ad5..a557e742b7cf 100644
--- a/nixos/modules/services/misc/zoneminder.nix
+++ b/nixos/modules/services/misc/zoneminder.nix
@@ -254,7 +254,7 @@ in {
location /cgi-bin {
gzip off;
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME ${pkg}/libexec/zoneminder/${zms};
fastcgi_param HTTP_PROXY "";
fastcgi_intercept_errors on;
@@ -270,7 +270,7 @@ in {
try_files $uri =404;
fastcgi_index index.php;
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param HTTP_PROXY "";
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index 81fca33f5fec..b959379d331a 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -214,6 +214,11 @@ let
type = types.path;
description = "Path grafana will watch for dashboards.";
};
+ foldersFromFilesStructure = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Use folder names from filesystem to create folders in Grafana.";
+ };
};
};
};
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index d29d50706ef6..41302d6d3ceb 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -29,6 +29,7 @@ let
"blackbox"
"buildkite-agent"
"collectd"
+ "dmarc"
"dnsmasq"
"domain"
"dovecot"
@@ -55,6 +56,7 @@ let
"postfix"
"postgres"
"process"
+ "pve"
"py-air-control"
"redis"
"rspamd"
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix b/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix
new file mode 100644
index 000000000000..330610a15d9e
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/dmarc.nix
@@ -0,0 +1,117 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+ cfg = config.services.prometheus.exporters.dmarc;
+
+ json = builtins.toJSON {
+ inherit (cfg) folders port;
+ listen_addr = cfg.listenAddress;
+ storage_path = "$STATE_DIRECTORY";
+ imap = (builtins.removeAttrs cfg.imap [ "passwordFile" ]) // { password = "$IMAP_PASSWORD"; use_ssl = true; };
+ poll_interval_seconds = cfg.pollIntervalSeconds;
+ deduplication_max_seconds = cfg.deduplicationMaxSeconds;
+ logging = {
+ version = 1;
+ disable_existing_loggers = false;
+ };
+ };
+in {
+ port = 9797;
+ extraOpts = {
+ imap = {
+ host = mkOption {
+ type = types.str;
+ default = "localhost";
+ description = ''
+ Hostname of IMAP server to connect to.
+ '';
+ };
+ port = mkOption {
+ type = types.port;
+ default = 993;
+ description = ''
+ Port of the IMAP server to connect to.
+ '';
+ };
+ username = mkOption {
+ type = types.str;
+ example = "postmaster@example.org";
+ description = ''
+ Login username for the IMAP connection.
+ '';
+ };
+ passwordFile = mkOption {
+ type = types.str;
+ example = "/run/secrets/dovecot_pw";
+ description = ''
+ File containing the login password for the IMAP connection.
+ '';
+ };
+ };
+ folders = {
+ inbox = mkOption {
+ type = types.str;
+ default = "INBOX";
+ description = ''
+ IMAP mailbox that is checked for incoming DMARC aggregate reports
+ '';
+ };
+ done = mkOption {
+ type = types.str;
+ default = "Archive";
+ description = ''
+ IMAP mailbox that successfully processed reports are moved to.
+ '';
+ };
+ error = mkOption {
+ type = types.str;
+ default = "Invalid";
+ description = ''
+ IMAP mailbox that emails are moved to that could not be processed.
+ '';
+ };
+ };
+ pollIntervalSeconds = mkOption {
+ type = types.ints.unsigned;
+ default = 60;
+ description = ''
+ How often to poll the IMAP server in seconds.
+ '';
+ };
+ deduplicationMaxSeconds = mkOption {
+ type = types.ints.unsigned;
+ default = 604800;
+ defaultText = "7 days (in seconds)";
+ description = ''
+ How long individual report IDs will be remembered to avoid
+ counting double delivered reports twice.
+ '';
+ };
+ debug = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to declare enable --debug.
+ '';
+ };
+ };
+ serviceOpts = {
+ path = with pkgs; [ envsubst coreutils ];
+ serviceConfig = {
+ StateDirectory = "prometheus-dmarc-exporter";
+ WorkingDirectory = "/var/lib/prometheus-dmarc-exporter";
+ ExecStart = "${pkgs.writeShellScript "setup-cfg" ''
+ export IMAP_PASSWORD="$(<${cfg.imap.passwordFile})"
+ envsubst \
+ -i ${pkgs.writeText "dmarc-exporter.json.template" json} \
+ -o ''${STATE_DIRECTORY}/dmarc-exporter.json
+
+ exec ${pkgs.prometheus-dmarc-exporter}/bin/prometheus-dmarc-exporter \
+ --configuration /var/lib/prometheus-dmarc-exporter/dmarc-exporter.json \
+ ${optionalString cfg.debug "--debug"}
+ ''}";
+ };
+ };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/kea.nix b/nixos/modules/services/monitoring/prometheus/exporters/kea.nix
index 27aeb9096243..e0ee90d9b97d 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/kea.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/kea.nix
@@ -25,6 +25,10 @@ in {
};
};
serviceOpts = {
+ after = [
+ "kea-dhcp4-server.service"
+ "kea-dhcp6-server.service"
+ ];
serviceConfig = {
User = "kea";
ExecStart = ''
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/pve.nix b/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
new file mode 100644
index 000000000000..ef708414c95e
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/pve.nix
@@ -0,0 +1,118 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+let
+ cfg = config.services.prometheus.exporters.pve;
+
+ # pve exporter requires a config file so create an empty one if configFile is not provided
+ emptyConfigFile = pkgs.writeTextFile {
+ name = "pve.yml";
+ text = "default:";
+ };
+
+ computedConfigFile = "${if cfg.configFile == null then emptyConfigFile else cfg.configFile}";
+in
+{
+ port = 9221;
+ extraOpts = {
+ package = mkOption {
+ type = types.package;
+ default = pkgs.prometheus-pve-exporter;
+ defaultText = literalExpression "pkgs.prometheus-pve-exporter";
+ example = literalExpression "pkgs.prometheus-pve-exporter";
+ description = ''
+ The package to use for prometheus-pve-exporter
+ '';
+ };
+
+ environmentFile = mkOption {
+ type = with types; nullOr path;
+ default = null;
+ example = "/etc/prometheus-pve-exporter/pve.env";
+ description = ''
+ Path to the service's environment file. This path can either be a computed path in /nix/store or a path in the local filesystem.
+
+ The environment file should NOT be stored in /nix/store as it contains passwords and/or keys in plain text.
+
+ Environment reference: https://github.com/prometheus-pve/prometheus-pve-exporter#authentication
+ '';
+ };
+
+ configFile = mkOption {
+ type = with types; nullOr path;
+ default = null;
+ example = "/etc/prometheus-pve-exporter/pve.yml";
+ description = ''
+ Path to the service's config file. This path can either be a computed path in /nix/store or a path in the local filesystem.
+
+ The config file should NOT be stored in /nix/store as it will contain passwords and/or keys in plain text.
+
+ If both configFile and environmentFile are provided, the configFile option will be ignored.
+
+ Configuration reference: https://github.com/prometheus-pve/prometheus-pve-exporter/#authentication
+ '';
+ };
+
+ collectors = {
+ status = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Collect Node/VM/CT status
+ '';
+ };
+ version = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Collect PVE version info
+ '';
+ };
+ node = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Collect PVE node info
+ '';
+ };
+ cluster = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Collect PVE cluster info
+ '';
+ };
+ resources = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Collect PVE resources info
+ '';
+ };
+ config = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Collect PVE onboot status
+ '';
+ };
+ };
+ };
+ serviceOpts = {
+ serviceConfig = {
+ ExecStart = ''
+ ${cfg.package}/bin/pve_exporter \
+ --${if cfg.collectors.status == true then "" else "no-"}collector.status \
+ --${if cfg.collectors.version == true then "" else "no-"}collector.version \
+ --${if cfg.collectors.node == true then "" else "no-"}collector.node \
+ --${if cfg.collectors.cluster == true then "" else "no-"}collector.cluster \
+ --${if cfg.collectors.resources == true then "" else "no-"}collector.resources \
+ --${if cfg.collectors.config == true then "" else "no-"}collector.config \
+ ${computedConfigFile} \
+ ${toString cfg.port} ${cfg.listenAddress}
+ '';
+ } // optionalAttrs (cfg.environmentFile != null) {
+ EnvironmentFile = cfg.environmentFile;
+ };
+ };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix b/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix
index b6416b93e69c..bac98364538d 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/smartctl.nix
@@ -25,7 +25,8 @@ in {
[ "/dev/sda", "/dev/nvme0n1" ];
'';
description = ''
- Paths to disks that will be monitored.
+ Paths to the disks that will be monitored. Will autodiscover
+ all disks if none given.
'';
};
maxInterval = mkOption {
@@ -41,13 +42,23 @@ in {
serviceOpts = {
serviceConfig = {
AmbientCapabilities = [
+ "CAP_SYS_RAWIO"
"CAP_SYS_ADMIN"
];
CapabilityBoundingSet = [
+ "CAP_SYS_RAWIO"
"CAP_SYS_ADMIN"
];
DevicePolicy = "closed";
- DeviceAllow = lib.mkForce cfg.devices;
+ DeviceAllow = lib.mkOverride 100 (
+ if cfg.devices != [] then
+ cfg.devices
+ else [
+ "block-blkext rw"
+ "block-sd rw"
+ "char-nvme rw"
+ ]
+ );
ExecStart = ''
${pkgs.prometheus-smartctl-exporter}/bin/smartctl_exporter -config ${configFile}
'';
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix b/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix
index c0a50f07d717..2edd1de83e1b 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/systemd.nix
@@ -11,7 +11,7 @@ in {
serviceConfig = {
ExecStart = ''
${pkgs.prometheus-systemd-exporter}/bin/systemd_exporter \
- --web.listen-address ${cfg.listenAddress}:${toString cfg.port}
+ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} ${concatStringsSep " " cfg.extraFlags}
'';
RestrictAddressFamilies = [
# Need AF_UNIX to collect data
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix b/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix
index 5b5a6e18fcd6..ede6028933a4 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix
@@ -45,7 +45,8 @@ in
};
instance = mkOption {
type = types.nullOr types.str;
- default = null;
+ default = config.services.varnish.stateDir;
+ defaultText = lib.literalExpression "config.services.varnish.stateDir";
description = ''
varnishstat -n value.
'';
@@ -66,7 +67,7 @@ in
};
};
serviceOpts = {
- path = [ pkgs.varnish ];
+ path = [ config.services.varnish.package ];
serviceConfig = {
RestartSec = mkDefault 1;
DynamicUser = false;
diff --git a/nixos/modules/services/network-filesystems/ceph.nix b/nixos/modules/services/network-filesystems/ceph.nix
index e313589134f1..7a1444decafa 100644
--- a/nixos/modules/services/network-filesystems/ceph.nix
+++ b/nixos/modules/services/network-filesystems/ceph.nix
@@ -181,8 +181,8 @@ in
rgwMimeTypesFile = mkOption {
type = with types; nullOr path;
- default = "${pkgs.mime-types}/etc/mime.types";
- defaultText = literalExpression ''"''${pkgs.mime-types}/etc/mime.types"'';
+ default = "${pkgs.mailcap}/etc/mime.types";
+ defaultText = literalExpression ''"''${pkgs.mailcap}/etc/mime.types"'';
description = ''
Path to mime types used by radosgw.
'';
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
index 5482b2aaf88c..7e96179b3cab 100644
--- a/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -1,16 +1,17 @@
-{ config, lib, pkgs, options, ... }:
+{ config, lib, pkgs, options, utils, ... }:
with lib;
let
cfg = config.services.ipfs;
opt = options.services.ipfs;
- ipfsFlags = toString ([
- (optionalString cfg.autoMount "--mount")
- (optionalString cfg.enableGC "--enable-gc")
- (optionalString (cfg.serviceFdlimit != null) "--manage-fdlimit=false")
- (optionalString (cfg.defaultMode == "offline") "--offline")
- (optionalString (cfg.defaultMode == "norouting") "--routing=none")
- ] ++ cfg.extraFlags);
+ ipfsFlags = 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" ++
+ cfg.extraFlags
+ );
profile =
if cfg.localDiscovery
@@ -239,7 +240,10 @@ in
"d '${cfg.ipnsMountDir}' - ${cfg.user} ${cfg.group} - -"
];
- systemd.packages = [ cfg.package ];
+ # The hardened systemd unit breaks the fuse-mount function according to documentation in the unit file itself
+ systemd.packages = if cfg.autoMount
+ then [ cfg.package.systemd_unit ]
+ else [ cfg.package.systemd_unit_hardened ];
systemd.services.ipfs = {
path = [ "/run/wrappers" cfg.package ];
@@ -259,29 +263,24 @@ in
ipfs --offline config Mounts.IPFS ${cfg.ipfsMountDir}
ipfs --offline config Mounts.IPNS ${cfg.ipnsMountDir}
'' + optionalString cfg.autoMigrate ''
- ${pkgs.ipfs-migrator}/bin/fs-repo-migrations -y
- '' + concatStringsSep "\n" (collect
- isString
- (mapAttrsRecursive
- (path: value:
- # Using heredoc below so that the value is never improperly quoted
- ''
- read value <mfsmaster-init on a freshly installed master server to
+ initialize the DATA_PATH direcory.
+ '';
+ default = false;
+ };
+
+ exports = mkOption {
+ type = with types; listOf str;
+ default = null;
+ description = "Paths to export (see mfsexports.cfg).";
+ example = [
+ "* / rw,alldirs,admin,maproot=0:0"
+ "* . rw"
+ ];
+ };
+
+ openFirewall = mkOption {
+ type = types.bool;
+ description = "Whether to automatically open the necessary ports in the firewall.";
+ default = false;
+ };
+
+ settings = mkOption {
+ type = types.submodule {
+ freeformType = settingsFormat.type;
+
+ options.DATA_PATH = mkOption {
+ type = types.str;
+ default = "/var/lib/mfs";
+ description = "Data storage directory.";
+ };
+ };
+
+ description = "Contents of config file (mfsmaster.cfg).";
+ };
+ };
+
+ metalogger = {
+ enable = mkEnableOption "Moosefs metalogger daemon.";
+
+ settings = mkOption {
+ type = types.submodule {
+ freeformType = settingsFormat.type;
+
+ options.DATA_PATH = mkOption {
+ type = types.str;
+ default = "/var/lib/mfs";
+ description = "Data storage directory";
+ };
+ };
+
+ description = "Contents of metalogger config file (mfsmetalogger.cfg).";
+ };
+ };
+
+ chunkserver = {
+ enable = mkEnableOption "Moosefs chunkserver daemon.";
+
+ openFirewall = mkOption {
+ type = types.bool;
+ description = "Whether to automatically open the necessary ports in the firewall.";
+ default = false;
+ };
+
+ hdds = mkOption {
+ type = with 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 {
+ freeformType = settingsFormat.type;
+
+ options.DATA_PATH = mkOption {
+ type = types.str;
+ default = "/var/lib/mfs";
+ description = "Directory for lock file.";
+ };
+ };
+
+ description = "Contents of chunkserver config file (mfschunkserver.cfg).";
+ };
+ };
+ };
+ };
+
+ ###### implementation
+
+ config = 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.") ];
+
+ # Service settings
+ services.moosefs = {
+ master.settings = mkIf cfg.master.enable {
+ WORKING_USER = mfsUser;
+ EXPORTS_FILENAME = toString ( pkgs.writeText "mfsexports.cfg"
+ (concatStringsSep "\n" cfg.master.exports));
+ };
+
+ metalogger.settings = mkIf cfg.metalogger.enable {
+ WORKING_USER = mfsUser;
+ MASTER_HOST = cfg.masterHost;
+ };
+
+ chunkserver.settings = mkIf cfg.chunkserver.enable {
+ WORKING_USER = mfsUser;
+ MASTER_HOST = cfg.masterHost;
+ HDD_CONF_FILENAME = toString ( pkgs.writeText "mfshdd.cfg"
+ (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.moosefs = {
+ isSystemUser = true;
+ description = "moosefs daemon user";
+ group = "moosefs";
+ };
+ groups.moosefs = {};
+ };
+
+ environment.systemPackages =
+ (lib.optional cfg.client.enable pkgs.moosefs) ++
+ (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 =
+ 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}";
+
+ # Service definitions
+ systemd.services.mfs-master = mkIf cfg.master.enable
+ ( systemdService "master" {
+ TimeoutStartSec = 1800;
+ TimeoutStopSec = 1800;
+ Restart = "no";
+ } masterCfg );
+
+ systemd.services.mfs-metalogger = mkIf cfg.metalogger.enable
+ ( systemdService "metalogger" { Restart = "on-abnormal"; } metaloggerCfg );
+
+ systemd.services.mfs-chunkserver = mkIf cfg.chunkserver.enable
+ ( systemdService "chunkserver" { Restart = "on-abnormal"; } chunkserverCfg );
+ };
+}
diff --git a/nixos/modules/services/network-filesystems/rsyncd.nix b/nixos/modules/services/network-filesystems/rsyncd.nix
index edac86eb0e30..e72f9b54cd6f 100644
--- a/nixos/modules/services/network-filesystems/rsyncd.nix
+++ b/nixos/modules/services/network-filesystems/rsyncd.nix
@@ -79,7 +79,7 @@ in {
in {
services.rsync = {
enable = !cfg.socketActivated;
- aliases = [ "rsyncd" ];
+ aliases = [ "rsyncd.service" ];
description = "fast remote file copy program daemon";
after = [ "network.target" ];
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 9ed755d0465c..992f948e8cd5 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -224,6 +224,7 @@ in
targets.samba = {
description = "Samba Server";
after = [ "network.target" ];
+ wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
};
# Refer to https://github.com/samba-team/samba/tree/master/packaging/systemd
diff --git a/nixos/modules/services/networking/amuled.nix b/nixos/modules/services/networking/amuled.nix
index e55ac7a6b18b..aa72a047526b 100644
--- a/nixos/modules/services/networking/amuled.nix
+++ b/nixos/modules/services/networking/amuled.nix
@@ -76,7 +76,7 @@ in
script = ''
${pkgs.su}/bin/su -s ${pkgs.runtimeShell} ${user} \
- -c 'HOME="${cfg.dataDir}" ${pkgs.amuleDaemon}/bin/amuled'
+ -c 'HOME="${cfg.dataDir}" ${pkgs.amule-daemon}/bin/amuled'
'';
};
};
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix
index fc06cdaa6e58..3049c4f2bce9 100644
--- a/nixos/modules/services/networking/bird.nix
+++ b/nixos/modules/services/networking/bird.nix
@@ -3,103 +3,101 @@
let
inherit (lib) mkEnableOption mkIf mkOption optionalString types;
- generic = variant:
- let
- cfg = config.services.${variant};
- pkg = pkgs.${variant};
- birdBin = if variant == "bird6" then "bird6" else "bird";
- birdc = if variant == "bird6" then "birdc6" else "birdc";
- descr =
- { bird = "1.6.x with IPv4 support";
- bird6 = "1.6.x with IPv6 support";
- bird2 = "2.x";
- }.${variant};
- in {
- ###### interface
- options = {
- services.${variant} = {
- enable = mkEnableOption "BIRD Internet Routing Daemon (${descr})";
- config = mkOption {
- type = types.lines;
- description = ''
- BIRD Internet Routing Daemon configuration file.
-
- '';
- };
- checkConfig = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether the config should be checked at build time.
- When the config can't be checked during build time, for example when it includes
- other files, either disable this option or use preCheckConfig to create
- the included files before checking.
- '';
- };
- preCheckConfig = mkOption {
- type = types.lines;
- default = "";
- example = ''
- echo "cost 100;" > include.conf
- '';
- description = ''
- Commands to execute before the config file check. The file to be checked will be
- available as ${variant}.conf in the current directory.
-
- Files created with this option will not be available at service runtime, only during
- build time checking.
- '';
- };
- };
+ cfg = config.services.bird2;
+ caps = [ "CAP_NET_ADMIN" "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ];
+in
+{
+ ###### interface
+ options = {
+ services.bird2 = {
+ enable = mkEnableOption "BIRD Internet Routing Daemon";
+ config = mkOption {
+ type = types.lines;
+ description = ''
+ BIRD Internet Routing Daemon configuration file.
+
+ '';
};
+ checkConfig = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether the config should be checked at build time.
+ When the config can't be checked during build time, for example when it includes
+ other files, either disable this option or use preCheckConfig to create
+ the included files before checking.
+ '';
+ };
+ preCheckConfig = mkOption {
+ type = types.lines;
+ default = "";
+ example = ''
+ echo "cost 100;" > include.conf
+ '';
+ description = ''
+ Commands to execute before the config file check. The file to be checked will be
+ available as bird2.conf in the current directory.
- ###### implementation
- config = mkIf cfg.enable {
- environment.systemPackages = [ pkg ];
-
- environment.etc."bird/${variant}.conf".source = pkgs.writeTextFile {
- name = "${variant}.conf";
- text = cfg.config;
- checkPhase = optionalString cfg.checkConfig ''
- ln -s $out ${variant}.conf
- ${cfg.preCheckConfig}
- ${pkg}/bin/${birdBin} -d -p -c ${variant}.conf
- '';
- };
-
- systemd.services.${variant} = {
- description = "BIRD Internet Routing Daemon (${descr})";
- wantedBy = [ "multi-user.target" ];
- reloadIfChanged = true;
- restartTriggers = [ config.environment.etc."bird/${variant}.conf".source ];
- serviceConfig = {
- Type = "forking";
- Restart = "on-failure";
- ExecStart = "${pkg}/bin/${birdBin} -c /etc/bird/${variant}.conf -u ${variant} -g ${variant}";
- ExecReload = "/bin/sh -c '${pkg}/bin/${birdBin} -c /etc/bird/${variant}.conf -p && ${pkg}/bin/${birdc} configure'";
- ExecStop = "${pkg}/bin/${birdc} down";
- CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_SETUID" "CAP_SETGID"
- # see bird/sysdep/linux/syspriv.h
- "CAP_NET_BIND_SERVICE" "CAP_NET_BROADCAST" "CAP_NET_ADMIN" "CAP_NET_RAW" ];
- ProtectSystem = "full";
- ProtectHome = "yes";
- SystemCallFilter="~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
- MemoryDenyWriteExecute = "yes";
- };
- };
- users = {
- users.${variant} = {
- description = "BIRD Internet Routing Daemon user";
- group = variant;
- isSystemUser = true;
- };
- groups.${variant} = {};
- };
+ Files created with this option will not be available at service runtime, only during
+ build time checking.
+ '';
};
};
+ };
-in
-{
- imports = map generic [ "bird" "bird6" "bird2" ];
+ imports = [
+ (lib.mkRemovedOptionModule [ "services" "bird" ] "Use services.bird2 instead")
+ (lib.mkRemovedOptionModule [ "services" "bird6" ] "Use services.bird2 instead")
+ ];
+
+ ###### implementation
+ config = mkIf cfg.enable {
+ environment.systemPackages = [ pkgs.bird ];
+
+ environment.etc."bird/bird2.conf".source = pkgs.writeTextFile {
+ name = "bird2";
+ text = cfg.config;
+ checkPhase = optionalString cfg.checkConfig ''
+ ln -s $out bird2.conf
+ ${cfg.preCheckConfig}
+ ${pkgs.bird}/bin/bird -d -p -c bird2.conf
+ '';
+ };
+
+ systemd.services.bird2 = {
+ description = "BIRD Internet Routing Daemon";
+ wantedBy = [ "multi-user.target" ];
+ reloadIfChanged = true;
+ restartTriggers = [ config.environment.etc."bird/bird2.conf".source ];
+ serviceConfig = {
+ Type = "forking";
+ Restart = "on-failure";
+ User = "bird2";
+ Group = "bird2";
+ ExecStart = "${pkgs.bird}/bin/bird -c /etc/bird/bird2.conf";
+ ExecReload = "${pkgs.bird}/bin/birdc configure";
+ ExecStop = "${pkgs.bird}/bin/birdc down";
+ RuntimeDirectory = "bird";
+ CapabilityBoundingSet = caps;
+ AmbientCapabilities = caps;
+ ProtectSystem = "full";
+ ProtectHome = "yes";
+ ProtectKernelTunables = true;
+ ProtectControlGroups = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
+ MemoryDenyWriteExecute = "yes";
+ };
+ };
+ users = {
+ users.bird2 = {
+ description = "BIRD Internet Routing Daemon user";
+ group = "bird2";
+ isSystemUser = true;
+ };
+ groups.bird2 = { };
+ };
+ };
}
diff --git a/nixos/modules/services/networking/blocky.nix b/nixos/modules/services/networking/blocky.nix
new file mode 100644
index 000000000000..7488e05fc033
--- /dev/null
+++ b/nixos/modules/services/networking/blocky.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.blocky;
+
+ format = pkgs.formats.yaml { };
+ configFile = format.generate "config.yaml" cfg.settings;
+in
+{
+ options.services.blocky = {
+ enable = mkEnableOption "Fast and lightweight DNS proxy as ad-blocker for local network with many features";
+
+ settings = mkOption {
+ type = format.type;
+ default = { };
+ description = ''
+ Blocky configuration. Refer to
+
+ for details on supported values.
+ '';
+ };
+ };
+
+ config = 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 = "${pkgs.blocky}/bin/blocky --config ${configFile}";
+
+ AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+ CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index 8886e7a30f1f..9945dc83a279 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -127,7 +127,7 @@ in {
description = "ConnMan VPN service";
wantedBy = [ "multi-user.target" ];
after = [ "syslog.target" ];
- before = [ "connman" ];
+ before = [ "connman.service" ];
serviceConfig = {
Type = "dbus";
BusName = "net.connman.vpn";
@@ -140,7 +140,7 @@ in {
description = "D-BUS Service";
serviceConfig = {
Name = "net.connman.vpn";
- before = [ "connman" ];
+ before = [ "connman.service" ];
ExecStart = "${cfg.package}/sbin/connman-vpnd -n";
User = "root";
SystemdService = "connman-vpn.service";
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index 2c339350acd3..3eb7ca99eafd 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -183,6 +183,20 @@ in
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`.
+ '';
+ } ];
+
systemd.services.dhcpcd = let
cfgN = config.networking;
hasDefaultGatewaySet = (cfgN.defaultGateway != null && cfgN.defaultGateway.address != "")
diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix
index 54e4f9002859..49950efc0a1b 100644
--- a/nixos/modules/services/networking/dhcpd.nix
+++ b/nixos/modules/services/networking/dhcpd.nix
@@ -7,7 +7,7 @@ let
cfg4 = config.services.dhcpd4;
cfg6 = config.services.dhcpd6;
- writeConfig = cfg: pkgs.writeText "dhcpd.conf"
+ writeConfig = postfix: cfg: pkgs.writeText "dhcpd.conf"
''
default-lease-time 600;
max-lease-time 7200;
@@ -21,45 +21,54 @@ let
(machine: ''
host ${machine.hostName} {
hardware ethernet ${machine.ethernetAddress};
- fixed-address ${machine.ipAddress};
+ fixed-address${
+ optionalString (postfix == "6") postfix
+ } ${machine.ipAddress};
}
'')
cfg.machines
}
'';
- dhcpdService = postfix: cfg: optionalAttrs cfg.enable {
- "dhcpd${postfix}" = {
- description = "DHCPv${postfix} server";
- wantedBy = [ "multi-user.target" ];
- after = [ "network.target" ];
+ dhcpdService = postfix: cfg:
+ let
+ configFile =
+ if cfg.configFile != null
+ then cfg.configFile
+ else writeConfig postfix cfg;
+ leaseFile = "/var/lib/dhcpd${postfix}/dhcpd.leases";
+ args = [
+ "@${pkgs.dhcp}/sbin/dhcpd" "dhcpd${postfix}" "-${postfix}"
+ "-pf" "/run/dhcpd${postfix}/dhcpd.pid"
+ "-cf" configFile
+ "-lf" leaseFile
+ ] ++ cfg.extraFlags
+ ++ cfg.interfaces;
+ in
+ optionalAttrs cfg.enable {
+ "dhcpd${postfix}" = {
+ description = "DHCPv${postfix} server";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
- preStart = ''
- mkdir -m 755 -p ${cfg.stateDir}
- chown dhcpd:nogroup ${cfg.stateDir}
- touch ${cfg.stateDir}/dhcpd.leases
- '';
-
- serviceConfig =
- let
- configFile = if cfg.configFile != null then cfg.configFile else writeConfig cfg;
- args = [ "@${pkgs.dhcp}/sbin/dhcpd" "dhcpd${postfix}" "-${postfix}"
- "-pf" "/run/dhcpd${postfix}/dhcpd.pid"
- "-cf" "${configFile}"
- "-lf" "${cfg.stateDir}/dhcpd.leases"
- "-user" "dhcpd" "-group" "nogroup"
- ] ++ cfg.extraFlags
- ++ cfg.interfaces;
-
- in {
- ExecStart = concatMapStringsSep " " escapeShellArg args;
- Type = "forking";
- Restart = "always";
- RuntimeDirectory = [ "dhcpd${postfix}" ];
- PIDFile = "/run/dhcpd${postfix}/dhcpd.pid";
+ preStart = "touch ${leaseFile}";
+ serviceConfig = {
+ ExecStart = concatMapStringsSep " " escapeShellArg args;
+ Type = "forking";
+ Restart = "always";
+ DynamicUser = true;
+ User = "dhcpd";
+ Group = "dhcpd";
+ AmbientCapabilities = [
+ "CAP_NET_RAW" # to send ICMP messages
+ "CAP_NET_BIND_SERVICE" # to bind on DHCP port (67)
+ ];
+ StateDirectory = "dhcpd${postfix}";
+ RuntimeDirectory = "dhcpd${postfix}";
+ PIDFile = "/run/dhcpd${postfix}/dhcpd.pid";
+ };
};
- };
- };
+ };
machineOpts = { ... }: {
@@ -102,15 +111,6 @@ let
'';
};
- stateDir = mkOption {
- type = types.path;
- # We use /var/lib/dhcp for DHCPv4 to save backwards compatibility.
- default = "/var/lib/dhcp${if postfix == "4" then "" else postfix}";
- description = ''
- State directory for the DHCP server.
- '';
- };
-
extraConfig = mkOption {
type = types.lines;
default = "";
@@ -194,7 +194,13 @@ in
imports = [
(mkRenamedOptionModule [ "services" "dhcpd" ] [ "services" "dhcpd4" ])
- ];
+ ] ++ flip map [ "4" "6" ] (postfix:
+ mkRemovedOptionModule [ "services" "dhcpd${postfix}" "stateDir" ] ''
+ The DHCP server state directory is now managed with the systemd's DynamicUser mechanism.
+ This means the directory is named after the service (dhcpd${postfix}), created under
+ /var/lib/private/ and symlinked to /var/lib/.
+ ''
+ );
###### interface
@@ -210,15 +216,6 @@ in
config = mkIf (cfg4.enable || cfg6.enable) {
- users = {
- users.dhcpd = {
- isSystemUser = true;
- group = "dhcpd";
- description = "DHCP daemon user";
- };
- groups.dhcpd = {};
- };
-
systemd.services = dhcpdService "4" cfg4 // dhcpdService "6" cfg6;
};
diff --git a/nixos/modules/services/networking/eternal-terminal.nix b/nixos/modules/services/networking/eternal-terminal.nix
index 88b4cd90540f..0dcf3d28f4e0 100644
--- a/nixos/modules/services/networking/eternal-terminal.nix
+++ b/nixos/modules/services/networking/eternal-terminal.nix
@@ -90,6 +90,6 @@ in
};
meta = {
- maintainers = with lib.maintainers; [ pingiun ];
+ maintainers = with lib.maintainers; [ ];
};
}
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index ff023a888f26..c213a5516a49 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -179,10 +179,6 @@ let
) cfg.allowedUDPPortRanges
) allInterfaces)}
- # Accept IPv4 multicast. Not a big security risk since
- # probably nobody is listening anyway.
- #iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept
-
# Optionally respond to ICMPv4 pings.
${optionalString cfg.allowPing ''
iptables -w -A nixos-fw -p icmp --icmp-type echo-request ${optionalString (cfg.pingLimit != null)
@@ -326,7 +322,7 @@ in
type = types.package;
default = pkgs.iptables;
defaultText = literalExpression "pkgs.iptables";
- example = literalExpression "pkgs.iptables-nftables-compat";
+ example = literalExpression "pkgs.iptables-legacy";
description =
''
The iptables package to use for running the firewall service."
@@ -437,8 +433,6 @@ in
drop the packet if the source address is not reachable via any
interface) or false. Defaults to the value of
kernelHasRPFilter.
-
- (needs kernel 3.3+)
'';
};
diff --git a/nixos/modules/services/networking/gogoclient.nix b/nixos/modules/services/networking/gogoclient.nix
deleted file mode 100644
index 1205321818b9..000000000000
--- a/nixos/modules/services/networking/gogoclient.nix
+++ /dev/null
@@ -1,87 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let cfg = config.services.gogoclient;
-in
-
-{
-
- ###### interface
-
- options = {
- services.gogoclient = {
- enable = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Enable the gogoCLIENT IPv6 tunnel.
- '';
- };
- autorun = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to automatically start the tunnel.
- '';
- };
-
- username = mkOption {
- default = "";
- type = types.str;
- description = ''
- Your Gateway6 login name, if any.
- '';
- };
-
- password = mkOption {
- default = "";
- type = types.str;
- description = ''
- Path to a file (as a string), containing your gogoNET password, if any.
- '';
- };
-
- server = mkOption {
- type = types.str;
- default = "anonymous.freenet6.net";
- example = "broker.freenet6.net";
- description = "The Gateway6 server to be used.";
- };
- };
- };
-
- ###### implementation
-
- config = mkIf cfg.enable {
- boot.kernelModules = [ "tun" ];
-
- networking.enableIPv6 = true;
-
- systemd.services.gogoclient = {
- description = "ipv6 tunnel";
-
- after = [ "network.target" ];
- requires = [ "network.target" ];
-
- unitConfig.RequiresMountsFor = "/var/lib/gogoc";
-
- script = let authMethod = if cfg.password == "" then "anonymous" else "any"; in ''
- mkdir -p -m 700 /var/lib/gogoc
- cat ${pkgs.gogoclient}/share/${pkgs.gogoclient.name}/gogoc.conf.sample | \
- ${pkgs.gnused}/bin/sed \
- -e "s|^userid=|&${cfg.username}|" \
- -e "s|^passwd=|&${optionalString (cfg.password != "") "$(cat ${cfg.password})"}|" \
- -e "s|^server=.*|server=${cfg.server}|" \
- -e "s|^auth_method=.*|auth_method=${authMethod}|" \
- -e "s|^#log_file=|log_file=1|" > /var/lib/gogoc/gogoc.conf
- cd /var/lib/gogoc
- exec ${pkgs.gogoclient}/bin/gogoc -y -f /var/lib/gogoc/gogoc.conf
- '';
- } // optionalAttrs cfg.autorun {
- wantedBy = [ "multi-user.target" ];
- };
-
- };
-
-}
diff --git a/nixos/modules/services/networking/headscale.nix b/nixos/modules/services/networking/headscale.nix
new file mode 100644
index 000000000000..091d2a938cd4
--- /dev/null
+++ b/nixos/modules/services/networking/headscale.nix
@@ -0,0 +1,490 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ cfg = config.services.headscale;
+
+ dataDir = "/var/lib/headscale";
+ runDir = "/run/headscale";
+
+ settingsFormat = pkgs.formats.yaml { };
+ configFile = settingsFormat.generate "headscale.yaml" cfg.settings;
+in
+{
+ options = {
+ services.headscale = {
+ enable = mkEnableOption "headscale, Open Source coordination server for Tailscale";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.headscale;
+ defaultText = literalExpression "pkgs.headscale";
+ description = ''
+ Which headscale package to use for the running server.
+ '';
+ };
+
+ user = mkOption {
+ default = "headscale";
+ type = types.str;
+ description = ''
+ User account under which headscale runs.
+
+ 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 headscale service starts.
+
+ '';
+ };
+
+ group = mkOption {
+ default = "headscale";
+ type = types.str;
+ description = ''
+ Group under which headscale runs.
+
+ If left as the default value this group will automatically be created
+ on system activation, otherwise you are responsible for
+ ensuring the user exists before the headscale service starts.
+
+ '';
+ };
+
+ serverUrl = mkOption {
+ type = types.str;
+ default = "http://127.0.0.1:8080";
+ description = ''
+ The url clients will connect to.
+ '';
+ example = "https://myheadscale.example.com:443";
+ };
+
+ address = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = ''
+ Listening address of headscale.
+ '';
+ example = "0.0.0.0";
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 8080;
+ description = ''
+ Listening port of headscale.
+ '';
+ example = 443;
+ };
+
+ privateKeyFile = mkOption {
+ type = types.path;
+ default = "${dataDir}/private.key";
+ description = ''
+ Path to private key file, generated automatically if it does not exist.
+ '';
+ };
+
+ derp = {
+ urls = mkOption {
+ type = types.listOf types.str;
+ default = [ "https://controlplane.tailscale.com/derpmap/default" ];
+ description = ''
+ List of urls containing DERP maps.
+ See How Tailscale works for more information on DERP maps.
+ '';
+ };
+
+ paths = mkOption {
+ type = types.listOf types.path;
+ default = [ ];
+ description = ''
+ List of file paths containing DERP maps.
+ See How Tailscale works for more information on DERP maps.
+ '';
+ };
+
+
+ autoUpdate = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to automatically update DERP maps on a set frequency.
+ '';
+ example = false;
+ };
+
+ updateFrequency = mkOption {
+ type = types.str;
+ default = "24h";
+ description = ''
+ Frequency to update DERP maps.
+ '';
+ example = "5m";
+ };
+
+ };
+
+ ephemeralNodeInactivityTimeout = mkOption {
+ type = types.str;
+ default = "30m";
+ description = ''
+ Time before an inactive ephemeral node is deleted.
+ '';
+ example = "5m";
+ };
+
+ database = {
+ type = mkOption {
+ type = types.enum [ "sqlite3" "postgres" ];
+ example = "postgres";
+ default = "sqlite3";
+ description = "Database engine to use.";
+ };
+
+ host = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "127.0.0.1";
+ description = "Database host address.";
+ };
+
+ port = mkOption {
+ type = types.nullOr types.port;
+ default = null;
+ example = 3306;
+ description = "Database host port.";
+ };
+
+ name = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "headscale";
+ description = "Database name.";
+ };
+
+ user = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "headscale";
+ description = "Database user.";
+ };
+
+ passwordFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = "/run/keys/headscale-dbpassword";
+ description = ''
+ A file containing the password corresponding to
+ .
+ '';
+ };
+
+ path = mkOption {
+ type = types.nullOr types.str;
+ default = "${dataDir}/db.sqlite";
+ description = "Path to the sqlite3 database file.";
+ };
+ };
+
+ logLevel = mkOption {
+ type = types.str;
+ default = "info";
+ description = ''
+ headscale log level.
+ '';
+ example = "debug";
+ };
+
+ dns = {
+ nameservers = mkOption {
+ type = types.listOf types.str;
+ default = [ "1.1.1.1" ];
+ description = ''
+ List of nameservers to pass to Tailscale clients.
+ '';
+ };
+
+ domains = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ description = ''
+ Search domains to inject to Tailscale clients.
+ '';
+ example = [ "mydomain.internal" ];
+ };
+
+ magicDns = 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;
+ };
+
+ baseDomain = mkOption {
+ type = types.str;
+ default = "";
+ description = ''
+ Defines the base domain to create the hostnames for MagicDNS.
+ 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).
+ '';
+ };
+ };
+
+ openIdConnect = {
+ issuer = mkOption {
+ type = types.str;
+ default = "";
+ description = ''
+ URL to OpenID issuer.
+ '';
+ example = "https://openid.example.com";
+ };
+
+ clientId = mkOption {
+ type = types.str;
+ default = "";
+ description = ''
+ OpenID Connect client ID.
+ '';
+ };
+
+ clientSecretFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ Path to OpenID Connect client secret file.
+ '';
+ };
+
+ domainMap = mkOption {
+ type = types.attrsOf types.str;
+ default = { };
+ description = ''
+ Domain map is used to map incomming users (by their email) to
+ a namespace. The key can be a string, or regex.
+ '';
+ example = {
+ ".*" = "default-namespace";
+ };
+ };
+
+ };
+
+ tls = {
+ letsencrypt = {
+ hostname = mkOption {
+ type = types.nullOr types.str;
+ default = "";
+ description = ''
+ Domain name to request a TLS certificate for.
+ '';
+ };
+ challengeType = mkOption {
+ type = types.enum [ "TLS_ALPN-01" "HTTP-01" ];
+ default = "HTTP-01";
+ description = ''
+ Type of ACME challenge to use, currently supported types:
+ HTTP-01 or TLS_ALPN-01.
+ '';
+ };
+ httpListen = mkOption {
+ type = types.nullOr types.str;
+ default = ":http";
+ description = ''
+ When HTTP-01 challenge is chosen, letsencrypt must set up a
+ verification endpoint, and it will be listening on:
+ :http = port 80.
+ '';
+ };
+ };
+
+ certFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ Path to already created certificate.
+ '';
+ };
+ keyFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ Path to key for already created certificate.
+ '';
+ };
+ };
+
+ aclPolicyFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ Path to a file containg ACL policies.
+ '';
+ };
+
+ settings = mkOption {
+ type = settingsFormat.type;
+ default = { };
+ description = ''
+ Overrides to config.yaml as a Nix attribute set.
+ This option is ideal for overriding settings not exposed as Nix options.
+ Check the example config
+ for possible options.
+ '';
+ };
+
+
+ };
+
+ };
+ config = mkIf cfg.enable {
+
+ services.headscale.settings = {
+ server_url = mkDefault cfg.serverUrl;
+ listen_addr = mkDefault "${cfg.address}:${toString cfg.port}";
+
+ private_key_path = mkDefault cfg.privateKeyFile;
+
+ derp = {
+ urls = mkDefault cfg.derp.urls;
+ paths = mkDefault cfg.derp.paths;
+ auto_update_enable = mkDefault cfg.derp.autoUpdate;
+ update_frequency = mkDefault cfg.derp.updateFrequency;
+ };
+
+ # Turn off update checks since the origin of our package
+ # is nixpkgs and not Github.
+ disable_check_updates = true;
+
+ ephemeral_node_inactivity_timeout = mkDefault cfg.ephemeralNodeInactivityTimeout;
+
+ db_type = mkDefault cfg.database.type;
+ db_path = mkDefault cfg.database.path;
+
+ log_level = mkDefault cfg.logLevel;
+
+ dns_config = {
+ nameservers = mkDefault cfg.dns.nameservers;
+ domains = mkDefault cfg.dns.domains;
+ magic_dns = mkDefault cfg.dns.magicDns;
+ base_domain = mkDefault cfg.dns.baseDomain;
+ };
+
+ unix_socket = "${runDir}/headscale.sock";
+
+ # OpenID Connect
+ oidc = {
+ issuer = mkDefault cfg.openIdConnect.issuer;
+ client_id = mkDefault cfg.openIdConnect.clientId;
+ domain_map = mkDefault cfg.openIdConnect.domainMap;
+ };
+
+ tls_letsencrypt_cache_dir = "${dataDir}/.cache";
+
+ } // optionalAttrs (cfg.database.host != null) {
+ db_host = mkDefault cfg.database.host;
+ } // optionalAttrs (cfg.database.port != null) {
+ db_port = mkDefault cfg.database.port;
+ } // optionalAttrs (cfg.database.name != null) {
+ db_name = mkDefault cfg.database.name;
+ } // optionalAttrs (cfg.database.user != null) {
+ db_user = mkDefault cfg.database.user;
+ } // optionalAttrs (cfg.tls.letsencrypt.hostname != null) {
+ tls_letsencrypt_hostname = mkDefault cfg.tls.letsencrypt.hostname;
+ } // optionalAttrs (cfg.tls.letsencrypt.challengeType != null) {
+ tls_letsencrypt_challenge_type = mkDefault cfg.tls.letsencrypt.challengeType;
+ } // optionalAttrs (cfg.tls.letsencrypt.httpListen != null) {
+ tls_letsencrypt_listen = mkDefault cfg.tls.letsencrypt.httpListen;
+ } // optionalAttrs (cfg.tls.certFile != null) {
+ tls_cert_path = mkDefault cfg.tls.certFile;
+ } // optionalAttrs (cfg.tls.keyFile != null) {
+ tls_key_path = mkDefault cfg.tls.keyFile;
+ } // optionalAttrs (cfg.aclPolicyFile != null) {
+ acl_policy_path = mkDefault cfg.aclPolicyFile;
+ };
+
+ # 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.
+ environment.etc."headscale/config.yaml".source = configFile;
+
+ users.groups.headscale = mkIf (cfg.group == "headscale") { };
+
+ users.users.headscale = mkIf (cfg.user == "headscale") {
+ description = "headscale user";
+ home = dataDir;
+ group = cfg.group;
+ isSystemUser = true;
+ };
+
+ systemd.services.headscale = {
+ description = "headscale coordination server for Tailscale";
+ after = [ "network-online.target" ];
+ wantedBy = [ "multi-user.target" ];
+ restartTriggers = [ configFile ];
+
+ script = ''
+ ${optionalString (cfg.database.passwordFile != null) ''
+ export HEADSCALE_DB_PASS="$(head -n1 ${escapeShellArg cfg.database.passwordFile})"
+ ''}
+
+ export HEADSCALE_OIDC_CLIENT_SECRET="$(head -n1 ${escapeShellArg cfg.openIdConnect.clientSecretFile})"
+ exec ${cfg.package}/bin/headscale serve
+ '';
+
+ serviceConfig =
+ let
+ capabilityBoundingSet = [ "CAP_CHOWN" ] ++ optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE";
+ in
+ {
+ Restart = "always";
+ Type = "simple";
+ User = cfg.user;
+ Group = cfg.group;
+
+ # Hardening options
+ RuntimeDirectory = "headscale";
+ # Allow headscale group access so users can be added and use the CLI.
+ RuntimeDirectoryMode = "0750";
+
+ StateDirectory = "headscale";
+ StateDirectoryMode = "0750";
+
+ ProtectSystem = "strict";
+ ProtectHome = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ ProtectKernelTunables = true;
+ ProtectControlGroups = true;
+ RestrictSUIDSGID = true;
+ PrivateMounts = true;
+ ProtectKernelModules = true;
+ ProtectKernelLogs = true;
+ ProtectHostname = true;
+ ProtectClock = true;
+ ProtectProc = "invisible";
+ ProcSubset = "pid";
+ RestrictNamespaces = true;
+ RemoveIPC = true;
+ UMask = "0077";
+
+ CapabilityBoundingSet = capabilityBoundingSet;
+ AmbientCapabilities = capabilityBoundingSet;
+ NoNewPrivileges = true;
+ LockPersonality = true;
+ RestrictRealtime = true;
+ SystemCallFilter = [ "@system-service" "~@priviledged" "@chown" ];
+ SystemCallArchitectures = "native";
+ RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
+ };
+ };
+ };
+
+ meta.maintainers = with maintainers; [ kradalby ];
+}
diff --git a/nixos/modules/services/networking/https-dns-proxy.nix b/nixos/modules/services/networking/https-dns-proxy.nix
new file mode 100644
index 000000000000..85d6c362b466
--- /dev/null
+++ b/nixos/modules/services/networking/https-dns-proxy.nix
@@ -0,0 +1,128 @@
+{ config, lib, pkgs, ... }:
+
+let
+ inherit (lib)
+ concatStringsSep
+ mkEnableOption mkIf mkOption types;
+
+ cfg = config.services.https-dns-proxy;
+
+ providers = {
+ cloudflare = {
+ ips = [ "1.1.1.1" "1.0.0.1" ];
+ url = "https://cloudflare-dns.com/dns-query";
+ };
+ google = {
+ ips = [ "8.8.8.8" "8.8.4.4" ];
+ url = "https://dns.google/dns-query";
+ };
+ quad9 = {
+ ips = [ "9.9.9.9" "149.112.112.112" ];
+ url = "https://dns.quad9.net/dns-query";
+ };
+ };
+
+ defaultProvider = "quad9";
+
+ providerCfg =
+ let
+ isCustom = cfg.provider.kind == "custom";
+ in
+ lib.concatStringsSep " " [
+ "-b"
+ (concatStringsSep "," (if isCustom then cfg.provider.ips else providers."${cfg.provider.kind}".ips))
+ "-r"
+ (if isCustom then cfg.provider.url else providers."${cfg.provider.kind}".url)
+ ];
+
+in
+{
+ meta.maintainers = with lib.maintainers; [ peterhoeg ];
+
+ ###### interface
+
+ options.services.https-dns-proxy = {
+ enable = mkEnableOption "https-dns-proxy daemon";
+
+ address = mkOption {
+ description = "The address on which to listen";
+ type = types.str;
+ default = "127.0.0.1";
+ };
+
+ port = mkOption {
+ description = "The port on which to listen";
+ type = types.port;
+ default = 5053;
+ };
+
+ provider = {
+ kind = mkOption {
+ description = ''
+ The upstream provider to use or custom in case you do not trust any of
+ the predefined providers or just want to use your own.
+
+ The default is ${defaultProvider} and there are privacy and security trade-offs
+ when using any upstream provider. Please consider that before using any
+ of them.
+
+ If you pick a custom provider, you will need to provide the bootstrap
+ IP addresses as well as the resolver https URL.
+ '';
+ type = types.enum ((builtins.attrNames providers) ++ [ "custom" ]);
+ default = defaultProvider;
+ };
+
+ ips = mkOption {
+ description = "The custom provider IPs";
+ type = types.listOf types.str;
+ };
+
+ url = mkOption {
+ description = "The custom provider URL";
+ type = types.str;
+ };
+ };
+
+ preferIPv4 = mkOption {
+ description = ''
+ https_dns_proxy will by default use IPv6 and fail if it is not available.
+ To play it safe, we choose IPv4.
+ '';
+ type = types.bool;
+ default = true;
+ };
+
+ extraArgs = mkOption {
+ description = "Additional arguments to pass to the process.";
+ type = types.listOf types.str;
+ default = [ "-v" ];
+ };
+ };
+
+ ###### implementation
+
+ config = lib.mkIf cfg.enable {
+ systemd.services.https-dns-proxy = {
+ description = "DNS to DNS over HTTPS (DoH) proxy";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = rec {
+ Type = "exec";
+ DynamicUser = true;
+ ExecStart = lib.concatStringsSep " " (
+ [
+ "${pkgs.https-dns-proxy}/bin/https_dns_proxy"
+ "-a ${toString cfg.address}"
+ "-p ${toString cfg.port}"
+ "-l -"
+ providerCfg
+ ]
+ ++ lib.optional cfg.preferIPv4 "-4"
+ ++ cfg.extraArgs
+ );
+ Restart = "on-failure";
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/hylafax/options.nix b/nixos/modules/services/networking/hylafax/options.nix
index 8e59c68054d2..8f621b61002f 100644
--- a/nixos/modules/services/networking/hylafax/options.nix
+++ b/nixos/modules/services/networking/hylafax/options.nix
@@ -3,7 +3,7 @@
let
inherit (lib.options) literalExpression mkEnableOption mkOption;
- inherit (lib.types) bool enum ints lines attrsOf nullOr path str submodule;
+ inherit (lib.types) bool enum ints lines attrsOf nonEmptyStr nullOr path str submodule;
inherit (lib.modules) mkDefault mkIf mkMerge;
commonDescr = ''
@@ -17,8 +17,6 @@ let
configuration to yield an operational system.
'';
- str1 = lib.types.addCheck str (s: s!=""); # non-empty string
-
configAttrType =
# Options in HylaFAX configuration files can be
# booleans, strings, integers, or list thereof
@@ -37,7 +35,7 @@ let
modemConfigOptions = { name, config, ... }: {
options = {
name = mkOption {
- type = str1;
+ type = nonEmptyStr;
example = "ttyS1";
description = ''
Name of modem device,
@@ -45,7 +43,7 @@ let
'';
};
type = mkOption {
- type = str1;
+ type = nonEmptyStr;
example = "cirrus";
description = ''
Name of modem configuration file,
@@ -135,14 +133,14 @@ in
};
countryCode = mkOption {
- type = nullOr str1;
+ type = nullOr nonEmptyStr;
default = null;
example = "49";
description = "Country code for server and all modems.";
};
areaCode = mkOption {
- type = nullOr str1;
+ type = nullOr nonEmptyStr;
default = null;
example = "30";
description = "Area code for server and all modems.";
@@ -279,7 +277,7 @@ in
each time the spooling area is initialized.
'';
faxcron.enable.frequency = mkOption {
- type = nullOr str1;
+ type = nullOr nonEmptyStr;
default = null;
example = "daily";
description = ''
@@ -319,7 +317,7 @@ in
each time the spooling area is initialized.
'';
faxqclean.enable.frequency = mkOption {
- type = nullOr str1;
+ type = nullOr nonEmptyStr;
default = null;
example = "daily";
description = ''
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index e1a31a0c2ee0..34fda57b23d2 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -222,14 +222,12 @@ let
in concatStringsSep "\n" inTunOpts))];
in pkgs.writeText "i2pd-tunnels.conf" opts;
- i2pdSh = pkgs.writeScriptBin "i2pd" ''
- #!/bin/sh
- exec ${cfg.package}/bin/i2pd \
- ${if cfg.address == null then "" else "--host="+cfg.address} \
- --service \
- --conf=${i2pdConf} \
- --tunconf=${tunnelConf}
- '';
+ i2pdFlags = concatStringsSep " " (
+ optional (cfg.address != null) ("--host=" + cfg.address) ++ [
+ "--service"
+ ("--conf=" + i2pdConf)
+ ("--tunconf=" + tunnelConf)
+ ]);
in
@@ -686,7 +684,7 @@ in
User = "i2pd";
WorkingDirectory = homeDir;
Restart = "on-abort";
- ExecStart = "${i2pdSh}/bin/i2pd";
+ ExecStart = "${cfg.package}/bin/i2pd ${i2pdFlags}";
};
};
};
diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix
index 8835f7f9372d..5c1480e7e2fb 100644
--- a/nixos/modules/services/networking/iwd.nix
+++ b/nixos/modules/services/networking/iwd.nix
@@ -1,12 +1,21 @@
{ config, lib, pkgs, ... }:
-with lib;
-
let
+ inherit (lib)
+ mkEnableOption mkIf mkOption types
+ recursiveUpdate;
+
cfg = config.networking.wireless.iwd;
ini = pkgs.formats.ini { };
- configFile = ini.generate "main.conf" cfg.settings;
-in {
+ defaults = {
+ # without UseDefaultInterface, sometimes wlan0 simply goes AWOL with NetworkManager
+ # https://iwd.wiki.kernel.org/interface_lifecycle#interface_management_in_iwd
+ General.UseDefaultInterface = with config.networking.networkmanager; (enable && (wifi.backend == "iwd"));
+ };
+ configFile = ini.generate "main.conf" (recursiveUpdate defaults cfg.settings);
+
+in
+{
options.networking.wireless.iwd = {
enable = mkEnableOption "iwd";
@@ -38,10 +47,10 @@ in {
'';
}];
- environment.etc."iwd/main.conf".source = configFile;
+ environment.etc."iwd/${configFile.name}".source = configFile;
# for iwctl
- environment.systemPackages = [ pkgs.iwd ];
+ environment.systemPackages = [ pkgs.iwd ];
services.dbus.packages = [ pkgs.iwd ];
diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix
index 16011573f8bb..28b8be7a9a0d 100644
--- a/nixos/modules/services/networking/kresd.nix
+++ b/nixos/modules/services/networking/kresd.nix
@@ -9,7 +9,7 @@ let
# On Nix level we don't attempt to precisely validate the address specifications.
# The optional IPv6 scope spec comes *after* port, perhaps surprisingly.
mkListen = kind: addr: let
- al_v4 = builtins.match "([0-9.]+):([0-9]+)()" addr;
+ 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)
diff --git a/nixos/modules/services/networking/multipath.nix b/nixos/modules/services/networking/multipath.nix
index 1cc2ad1fc849..1a44184ff6dc 100644
--- a/nixos/modules/services/networking/multipath.nix
+++ b/nixos/modules/services/networking/multipath.nix
@@ -242,21 +242,6 @@ in {
'';
};
- retain_attached_hw_handler = mkOption {
- type = nullOr (enum [ "yes" "no" ]);
- default = null; # real default: "yes"
- description = ''
- (Obsolete for kernels >= 4.3) If set to "yes" and the SCSI layer has
- already attached a hardware_handler to the device, multipath will not
- force the device to use the hardware_handler specified by mutipath.conf.
- If the SCSI layer has not attached a hardware handler, multipath will
- continue to use its configured hardware handler.
-
- Important Note: Linux kernel 4.3 or newer always behaves as if
- "retain_attached_hw_handler yes" was set.
- '';
- };
-
detect_prio = mkOption {
type = nullOr (enum [ "yes" "no" ]);
default = null; # real default: "yes"
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index bbbe1e181bba..06ec04dbbf16 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -294,7 +294,7 @@ in
systemd.services.murmur = {
description = "Murmur Chat Service";
wantedBy = [ "multi-user.target" ];
- after = [ "network-online.target "];
+ after = [ "network-online.target" ];
preStart = ''
${pkgs.envsubst}/bin/envsubst \
-o /run/murmur/murmurd.ini \
@@ -306,7 +306,7 @@ in
Type = if forking then "forking" else "simple";
PIDFile = mkIf forking "/run/murmur/murmurd.pid";
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
- ExecStart = "${cfg.package}/bin/murmurd -ini /run/murmur/murmurd.ini";
+ ExecStart = "${cfg.package}/bin/mumble-server -ini /run/murmur/murmurd.ini";
Restart = "always";
RuntimeDirectory = "murmur";
RuntimeDirectoryMode = "0700";
diff --git a/nixos/modules/services/networking/nbd.nix b/nixos/modules/services/networking/nbd.nix
new file mode 100644
index 000000000000..87f8c41a8e5c
--- /dev/null
+++ b/nixos/modules/services/networking/nbd.nix
@@ -0,0 +1,146 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.nbd;
+ configFormat = pkgs.formats.ini { };
+ iniFields = with types; attrsOf (oneOf [ bool int float str ]);
+ serverConfig = configFormat.generate "nbd-server-config"
+ ({
+ generic =
+ (cfg.server.extraOptions // {
+ user = "root";
+ group = "root";
+ port = cfg.server.listenPort;
+ } // (optionalAttrs (cfg.server.listenAddress != null) {
+ listenaddr = cfg.server.listenAddress;
+ }));
+ }
+ // (mapAttrs
+ (_: { path, allowAddresses, extraOptions }:
+ extraOptions // {
+ exportname = path;
+ } // (optionalAttrs (allowAddresses != null) {
+ authfile = pkgs.writeText "authfile" (concatStringsSep "\n" allowAddresses);
+ }))
+ cfg.server.exports)
+ );
+ splitLists =
+ partition
+ (path: hasPrefix "/dev/" path)
+ (mapAttrsToList (_: { path, ... }: path) cfg.server.exports);
+ allowedDevices = splitLists.right;
+ boundPaths = splitLists.wrong;
+in
+{
+ options = {
+ services.nbd = {
+ server = {
+ enable = mkEnableOption "the Network Block Device (nbd) server";
+
+ listenPort = mkOption {
+ type = types.port;
+ default = 10809;
+ description = "Port to listen on. The port is NOT automatically opened in the firewall.";
+ };
+
+ extraOptions = mkOption {
+ type = iniFields;
+ default = {
+ allowlist = false;
+ };
+ description = ''
+ Extra options for the server. See
+ nbd-server
+ 5.
+ '';
+ };
+
+ exports = mkOption {
+ description = "Files or block devices to make available over the network.";
+ default = { };
+ type = with types; attrsOf
+ (submodule {
+ options = {
+ path = mkOption {
+ type = str;
+ description = "File or block device to export.";
+ example = "/dev/sdb1";
+ };
+
+ allowAddresses = mkOption {
+ type = nullOr (listOf str);
+ default = null;
+ example = [ "10.10.0.0/24" "127.0.0.1" ];
+ description = "IPs and subnets that are authorized to connect for this device. If not specified, the server will allow all connections.";
+ };
+
+ extraOptions = mkOption {
+ type = iniFields;
+ default = {
+ flush = true;
+ fua = true;
+ };
+ description = ''
+ Extra options for this export. See
+ nbd-server
+ 5.
+ '';
+ };
+ };
+ });
+ };
+
+ listenAddress = mkOption {
+ type = with types; nullOr str;
+ description = "Address to listen on. If not specified, the server will listen on all interfaces.";
+ default = null;
+ example = "10.10.0.1";
+ };
+ };
+ };
+ };
+
+ config = mkIf cfg.server.enable {
+ boot.kernelModules = [ "nbd" ];
+
+ systemd.services.nbd-server = {
+ after = [ "network-online.target" ];
+ before = [ "multi-user.target" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ ExecStart = "${pkgs.nbd}/bin/nbd-server -C ${serverConfig}";
+ Type = "forking";
+
+ DeviceAllow = map (path: "${path} rw") allowedDevices;
+ BindPaths = boundPaths;
+
+ CapabilityBoundingSet = "";
+ DevicePolicy = "closed";
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ PrivateDevices = false;
+ PrivateMounts = true;
+ PrivateTmp = true;
+ PrivateUsers = true;
+ ProcSubset = "pid";
+ 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;
+ UMask = "0077";
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index 73e63e2ee99b..7a9d9e5428a7 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -384,6 +384,17 @@ in {
so you don't need to to that yourself.
'';
};
+
+ enableFccUnlock = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable FCC unlock procedures. Since release 1.18.4, the ModemManager daemon no longer
+ automatically performs the FCC unlock procedure by default. See
+ the docs
+ for more details.
+ '';
+ };
};
};
@@ -438,7 +449,13 @@ in {
"NetworkManager/VPN/nm-sstp-service.name".source =
"${networkmanager-sstp}/lib/NetworkManager/VPN/nm-sstp-service.name";
+
}
+ // optionalAttrs cfg.enableFccUnlock
+ {
+ "ModemManager/fcc-unlock.d".source =
+ "${pkgs.modemmanager}/share/ModemManager/fcc-unlock.available.d/*";
+ }
// optionalAttrs (cfg.appendNameservers != [] || cfg.insertNameservers != [])
{
"NetworkManager/dispatcher.d/02overridedns".source = overrideNameserversScript;
@@ -539,6 +556,7 @@ in {
boot.kernelModules = [ "ctr" ];
+ security.polkit.enable = true;
security.polkit.extraConfig = polkitConf;
services.dbus.packages = cfg.packages
diff --git a/nixos/modules/services/networking/nftables.nix b/nixos/modules/services/networking/nftables.nix
index eb74d373b0af..b911f97491eb 100644
--- a/nixos/modules/services/networking/nftables.nix
+++ b/nixos/modules/services/networking/nftables.nix
@@ -25,9 +25,10 @@ in
for more information.
There are other programs that use iptables internally too, such as
- libvirt.
+ libvirt. For information on how the two firewalls interact, see [2].
[1]: https://github.com/NixOS/nixpkgs/issues/24318#issuecomment-289216273
+ [2]: https://wiki.nftables.org/wiki-nftables/index.php/Troubleshooting#Question_4._How_do_nftables_and_iptables_interact_when_used_on_the_same_system.3F
'';
};
networking.nftables.ruleset = mkOption {
@@ -118,20 +119,11 @@ in
flush ruleset
include "${cfg.rulesetFile}"
'';
- checkScript = pkgs.writeScript "nftables-check" ''
- #! ${pkgs.runtimeShell} -e
- if $(${pkgs.kmod}/bin/lsmod | grep -q ip_tables); then
- echo "Unload ip_tables before using nftables!" 1>&2
- exit 1
- else
- ${rulesScript}
- fi
- '';
in {
Type = "oneshot";
RemainAfterExit = true;
- ExecStart = checkScript;
- ExecReload = checkScript;
+ ExecStart = rulesScript;
+ ExecReload = rulesScript;
ExecStop = "${pkgs.nftables}/bin/nft flush ruleset";
};
};
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index cf6c9661dc1b..a51fc5345342 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -194,19 +194,8 @@ let
zone.children
);
- # fighting infinite recursion
- zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
- zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false;
- zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false;
- zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false;
- zoneOptions4 = zoneOptionsRaw // childConfig zoneOptions5 false;
- zoneOptions5 = zoneOptionsRaw // childConfig zoneOptions6 false;
- zoneOptions6 = zoneOptionsRaw // childConfig null false;
-
- childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; };
-
# options are ordered alphanumerically
- zoneOptionsRaw = types.submodule {
+ zoneOptions = types.submodule {
options = {
allowAXFRFallback = mkOption {
@@ -246,6 +235,13 @@ let
};
children = mkOption {
+ # TODO: This relies on the fact that `types.anything` doesn't set any
+ # values of its own to any defaults, because in the above zoneConfigs',
+ # values from children override ones from parents, but only if the
+ # attributes are defined. Because of this, we can't replace the element
+ # type here with `zoneConfigs`, since that would set all the attributes
+ # to default values, breaking the parent inheriting function.
+ type = types.attrsOf types.anything;
default = {};
description = ''
Children zones inherit all options of their parents. Attributes
diff --git a/nixos/modules/services/networking/ntopng.nix b/nixos/modules/services/networking/ntopng.nix
index 77a004e8ab3a..022fc923edaa 100644
--- a/nixos/modules/services/networking/ntopng.nix
+++ b/nixos/modules/services/networking/ntopng.nix
@@ -6,7 +6,13 @@ let
cfg = config.services.ntopng;
opt = options.services.ntopng;
- redisCfg = config.services.redis;
+
+ createRedis = cfg.redis.createInstance != null;
+ redisService =
+ if cfg.redis.createInstance == "" then
+ "redis.service"
+ else
+ "redis-${cfg.redis.createInstance}.service";
configFile = if cfg.configText != "" then
pkgs.writeText "ntopng.conf" ''
@@ -15,8 +21,10 @@ let
else
pkgs.writeText "ntopng.conf" ''
${concatStringsSep " " (map (e: "--interface=" + e) cfg.interfaces)}
- --http-port=${toString cfg.http-port}
- --redis=localhost:${toString redisCfg.port}
+ --http-port=${toString cfg.httpPort}
+ --redis=${cfg.redis.address}
+ --data-dir=/var/lib/ntopng
+ --user=ntopng
${cfg.extraConfig}
'';
@@ -24,6 +32,10 @@ in
{
+ imports = [
+ (mkRenamedOptionModule [ "services" "ntopng" "http-port" ] [ "services" "ntopng" "httpPort" ])
+ ];
+
options = {
services.ntopng = {
@@ -56,7 +68,7 @@ in
'';
};
- http-port = mkOption {
+ httpPort = mkOption {
default = 3000;
type = types.int;
description = ''
@@ -64,6 +76,24 @@ in
'';
};
+ redis.address = mkOption {
+ type = types.str;
+ example = literalExpression "config.services.redis.ntopng.unixSocket";
+ description = ''
+ Redis address - may be a Unix socket or a network host and port.
+ '';
+ };
+
+ redis.createInstance = mkOption {
+ type = types.nullOr types.str;
+ default = if versionAtLeast config.system.stateVersion "22.05" then "ntopng" else "";
+ description = ''
+ Local Redis instance name. Set to null to disable
+ local Redis instance. Defaults to "" for
+ system.stateVersion older than 22.05.
+ '';
+ };
+
configText = mkOption {
default = "";
example = ''
@@ -95,23 +125,36 @@ in
config = mkIf cfg.enable {
# ntopng uses redis for data storage
- services.redis.enable = true;
+ services.ntopng.redis.address =
+ mkIf createRedis config.services.redis.servers.${cfg.redis.createInstance}.unixSocket;
+
+ services.redis.servers = mkIf createRedis {
+ ${cfg.redis.createInstance} = {
+ enable = true;
+ user = mkIf (cfg.redis.createInstance == "ntopng") "ntopng";
+ };
+ };
# nice to have manual page and ntopng command in PATH
environment.systemPackages = [ pkgs.ntopng ];
+ systemd.tmpfiles.rules = [ "d /var/lib/ntopng 0700 ntopng ntopng -" ];
+
systemd.services.ntopng = {
description = "Ntopng Network Monitor";
- requires = [ "redis.service" ];
- after = [ "network.target" "redis.service" ];
+ requires = optional createRedis redisService;
+ after = [ "network.target" ] ++ optional createRedis redisService;
wantedBy = [ "multi-user.target" ];
- preStart = "mkdir -p /var/lib/ntopng/";
serviceConfig.ExecStart = "${pkgs.ntopng}/bin/ntopng ${configFile}";
unitConfig.Documentation = "man:ntopng(8)";
};
- # ntopng drops priveleges to user "nobody" and that user is already defined
- # in users-groups.nix.
+ users.extraUsers.ntopng = {
+ group = "ntopng";
+ isSystemUser = true;
+ };
+
+ users.extraGroups.ntopng = { };
};
}
diff --git a/nixos/modules/services/networking/pleroma.nix b/nixos/modules/services/networking/pleroma.nix
index 9b8382392c0a..c6d4c14dcb7e 100644
--- a/nixos/modules/services/networking/pleroma.nix
+++ b/nixos/modules/services/networking/pleroma.nix
@@ -1,6 +1,7 @@
{ config, options, lib, pkgs, stdenv, ... }:
let
cfg = config.services.pleroma;
+ cookieFile = "/var/lib/pleroma/.cookie";
in {
options = {
services.pleroma = with lib; {
@@ -8,7 +9,7 @@ in {
package = mkOption {
type = types.package;
- default = pkgs.pleroma;
+ default = pkgs.pleroma.override { inherit cookieFile; };
defaultText = literalExpression "pkgs.pleroma";
description = "Pleroma package to use.";
};
@@ -100,7 +101,6 @@ in {
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;
@@ -118,10 +118,10 @@ in {
# Better be safe than sorry migration-wise.
ExecStartPre =
let preScript = pkgs.writers.writeBashBin "pleromaStartPre" ''
- if [ ! -f /var/lib/pleroma/.cookie ]
+ if [ ! -f "${cookieFile}" ] || [ ! -s "${cookieFile}" ]
then
echo "Creating cookie file"
- dd if=/dev/urandom bs=1 count=16 | hexdump -e '16/1 "%02x"' > /var/lib/pleroma/.cookie
+ dd if=/dev/urandom bs=1 count=16 | ${pkgs.hexdump}/bin/hexdump -e '16/1 "%02x"' > "${cookieFile}"
fi
${cfg.package}/bin/pleroma_ctl migrate
'';
diff --git a/nixos/modules/services/networking/powerdns.nix b/nixos/modules/services/networking/powerdns.nix
index 8cae61b83543..b035698456c0 100644
--- a/nixos/modules/services/networking/powerdns.nix
+++ b/nixos/modules/services/networking/powerdns.nix
@@ -24,14 +24,14 @@ in {
config = mkIf cfg.enable {
- systemd.packages = [ pkgs.powerdns ];
+ systemd.packages = [ pkgs.pdns ];
systemd.services.pdns = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "mysql.service" "postgresql.service" "openldap.service" ];
serviceConfig = {
- ExecStart = [ "" "${pkgs.powerdns}/bin/pdns_server --config-dir=${configDir} --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no" ];
+ ExecStart = [ "" "${pkgs.pdns}/bin/pdns_server --config-dir=${configDir} --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no" ];
};
};
diff --git a/nixos/modules/services/networking/racoon.nix b/nixos/modules/services/networking/racoon.nix
deleted file mode 100644
index 328f4cb1497f..000000000000
--- a/nixos/modules/services/networking/racoon.nix
+++ /dev/null
@@ -1,45 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
- cfg = config.services.racoon;
-in {
- options.services.racoon = {
- enable = mkEnableOption "racoon";
-
- config = mkOption {
- description = "Contents of racoon configuration file.";
- default = "";
- type = types.str;
- };
-
- configPath = mkOption {
- description = "Location of racoon config if config is not provided.";
- default = "/etc/racoon/racoon.conf";
- type = types.path;
- };
- };
-
- config = mkIf cfg.enable {
- systemd.services.racoon = {
- description = "Racoon Daemon";
- wantedBy = [ "multi-user.target" ];
- after = [ "network.target" ];
- serviceConfig = {
- ExecStart = "${pkgs.ipsecTools}/bin/racoon -f ${
- if (cfg.config != "") then pkgs.writeText "racoon.conf" cfg.config
- else cfg.configPath
- }";
- ExecReload = "${pkgs.ipsecTools}/bin/racoonctl reload-config";
- PIDFile = "/run/racoon.pid";
- Type = "forking";
- Restart = "always";
- };
- preStart = ''
- rm /run/racoon.pid || true
- mkdir -p /var/racoon
- '';
- };
- };
-}
diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix
index d7fb22edebed..2839ffb60a1f 100644
--- a/nixos/modules/services/networking/seafile.nix
+++ b/nixos/modules/services/networking/seafile.nix
@@ -1,7 +1,6 @@
{ config, lib, pkgs, ... }:
with lib;
let
- python = pkgs.python3Packages.python;
cfg = config.services.seafile;
settingsFormat = pkgs.formats.ini { };
@@ -221,9 +220,7 @@ in {
'';
};
- seahub = let
- penv = (pkgs.python3.withPackages (ps: with ps; [ gunicorn seahub ]));
- in {
+ seahub = {
description = "Seafile Server Web Frontend";
wantedBy = [ "seafile.target" ];
partOf = [ "seafile.target" ];
@@ -231,8 +228,7 @@ in {
requires = [ "seaf-server.service" ];
restartTriggers = [ seahubSettings ];
environment = {
- PYTHONPATH =
- "${pkgs.python3Packages.seahub}/thirdpart:${pkgs.python3Packages.seahub}:${penv}/${python.sitePackages}";
+ PYTHONPATH = "${pkgs.seahub.pythonPath}:${pkgs.seahub}/thirdpart:${pkgs.seahub}";
DJANGO_SETTINGS_MODULE = "seahub.settings";
CCNET_CONF_DIR = ccnetDir;
SEAFILE_CONF_DIR = dataDir;
@@ -249,7 +245,7 @@ in {
LogsDirectory = "seafile";
ConfigurationDirectory = "seafile";
ExecStart = ''
- ${penv}/bin/gunicorn seahub.wsgi:application \
+ ${pkgs.seahub.python.pkgs.gunicorn}/bin/gunicorn seahub.wsgi:application \
--name seahub \
--workers ${toString cfg.workers} \
--log-level=info \
@@ -262,27 +258,27 @@ in {
preStart = ''
mkdir -p ${seahubDir}/media
# Link all media except avatars
- for m in `find ${pkgs.python3Packages.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do
+ for m in `find ${pkgs.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do
ln -sf $m ${seahubDir}/media/
done
if [ ! -e "${seafRoot}/.seahubSecret" ]; then
- ${penv}/bin/python ${pkgs.python3Packages.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret
+ ${pkgs.seahub.python}/bin/python ${pkgs.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret
chmod 400 ${seafRoot}/.seahubSecret
fi
if [ ! -f "${seafRoot}/seahub-setup" ]; then
# avatars directory should be writable
- install -D -t ${seahubDir}/media/avatars/ ${pkgs.python3Packages.seahub}/media/avatars/default.png
- install -D -t ${seahubDir}/media/avatars/groups ${pkgs.python3Packages.seahub}/media/avatars/groups/default.png
+ 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
# init database
- ${pkgs.python3Packages.seahub}/manage.py migrate
+ ${pkgs.seahub}/manage.py migrate
# create admin account
- ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.python3Packages.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.python3Packages.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
+ ${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"
fi
- if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.python3Packages.seahub.version}" ]; then
+ if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.seahub.version}" ]; then
# update database
- ${pkgs.python3Packages.seahub}/manage.py migrate
- echo "${pkgs.python3Packages.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
+ ${pkgs.seahub}/manage.py migrate
+ echo "${pkgs.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
fi
'';
};
diff --git a/nixos/modules/services/networking/snowflake-proxy.nix b/nixos/modules/services/networking/snowflake-proxy.nix
new file mode 100644
index 000000000000..2124644ed9b5
--- /dev/null
+++ b/nixos/modules/services/networking/snowflake-proxy.nix
@@ -0,0 +1,81 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.snowflake-proxy;
+in
+{
+ options = {
+ services.snowflake-proxy = {
+ enable = mkEnableOption "System to defeat internet censorship";
+
+ broker = mkOption {
+ description = "Broker URL (default \"https://snowflake-broker.torproject.net/\")";
+ type = with types; nullOr str;
+ default = null;
+ };
+
+ capacity = mkOption {
+ description = "Limits the amount of maximum concurrent clients allowed.";
+ type = with types; nullOr int;
+ default = null;
+ };
+
+ relay = mkOption {
+ description = "websocket relay URL (default \"wss://snowflake.bamsoftware.com/\")";
+ type = with types; nullOr str;
+ default = null;
+ };
+
+ stun = mkOption {
+ description = "STUN broker URL (default \"stun:stun.stunprotocol.org:3478\")";
+ type = with types; nullOr str;
+ default = null;
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.snowflake-proxy = {
+ wantedBy = [ "network-online.target" ];
+ serviceConfig = {
+ ExecStart =
+ "${pkgs.snowflake}/bin/proxy " + concatStringsSep " " (
+ optional (cfg.broker != null) "-broker ${cfg.broker}"
+ ++ optional (cfg.capacity != null) "-capacity ${builtins.toString cfg.capacity}"
+ ++ optional (cfg.relay != null) "-relay ${cfg.relay}"
+ ++ optional (cfg.stun != null) "-stun ${cfg.stun}"
+ );
+
+ # Security Hardening
+ # Refer to systemd.exec(5) for option descriptions.
+ CapabilityBoundingSet = "";
+
+ # implies RemoveIPC=, PrivateTmp=, NoNewPrivileges=, RestrictSUIDSGID=,
+ # ProtectSystem=strict, ProtectHome=read-only
+ DynamicUser = true;
+ LockPersonality = true;
+ PrivateDevices = true;
+ PrivateUsers = true;
+ ProcSubset = "pid";
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectProc = "invisible";
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = "~@clock @cpu-emulation @debug @mount @obsolete @reboot @swap @privileged @resources";
+ UMask = "0077";
+ };
+ };
+ };
+
+ meta.maintainers = with maintainers; [ yayayayaka ];
+}
diff --git a/nixos/modules/services/networking/squid.nix b/nixos/modules/services/networking/squid.nix
index 9d063b92aa1e..db4f0d26b6f4 100644
--- a/nixos/modules/services/networking/squid.nix
+++ b/nixos/modules/services/networking/squid.nix
@@ -81,7 +81,9 @@ let
http_access deny all
# Squid normally listens to port 3128
- http_port ${toString cfg.proxyPort}
+ http_port ${
+ optionalString (cfg.proxyAddress != null) "${cfg.proxyAddress}:"
+ }${toString cfg.proxyPort}
# Leave coredumps in the first cache dir
coredump_dir /var/cache/squid
@@ -109,6 +111,19 @@ in
description = "Whether to run squid web proxy.";
};
+ package = mkOption {
+ default = pkgs.squid;
+ defaultText = literalExpression "pkgs.squid";
+ type = types.package;
+ description = "Squid package to use.";
+ };
+
+ proxyAddress = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = "IP address on which squid will listen.";
+ };
+
proxyPort = mkOption {
type = types.int;
default = 3128;
@@ -149,17 +164,21 @@ in
users.groups.squid = {};
systemd.services.squid = {
- description = "Squid caching web proxy";
+ description = "Squid caching proxy";
+ documentation = [ "man:squid(8)" ];
after = [ "network.target" "nss-lookup.target" ];
wantedBy = [ "multi-user.target"];
preStart = ''
mkdir -p "/var/log/squid"
chown squid:squid "/var/log/squid"
+ ${cfg.package}/bin/squid --foreground -z -f ${squidConfig}
'';
serviceConfig = {
- Type="forking";
PIDFile="/run/squid.pid";
- ExecStart = "${pkgs.squid}/bin/squid -YCs -f ${squidConfig}";
+ ExecStart = "${cfg.package}/bin/squid --foreground -YCs -f ${squidConfig}";
+ ExecReload="kill -HUP $MAINPID";
+ KillMode="mixed";
+ NotifyAccess="all";
};
};
diff --git a/nixos/modules/services/networking/syncplay.nix b/nixos/modules/services/networking/syncplay.nix
index 27a16fb2e29f..b6faf2d3f772 100644
--- a/nixos/modules/services/networking/syncplay.nix
+++ b/nixos/modules/services/networking/syncplay.nix
@@ -68,7 +68,7 @@ in
systemd.services.syncplay = {
description = "Syncplay Service";
wantedBy = [ "multi-user.target" ];
- after = [ "network-online.target "];
+ after = [ "network-online.target" ];
serviceConfig = {
ExecStart = "${pkgs.syncplay}/bin/syncplay-server ${escapeShellArgs cmdArgs}";
diff --git a/nixos/modules/services/networking/tetrd.nix b/nixos/modules/services/networking/tetrd.nix
index ead73c497764..0801ce129246 100644
--- a/nixos/modules/services/networking/tetrd.nix
+++ b/nixos/modules/services/networking/tetrd.nix
@@ -1,7 +1,7 @@
{ config, lib, pkgs, ... }:
{
- options.services.tetrd.enable = lib.mkEnableOption pkgs.tetrd.meta.description;
+ options.services.tetrd.enable = lib.mkEnableOption "tetrd";
config = lib.mkIf config.services.tetrd.enable {
environment = {
diff --git a/nixos/modules/services/networking/tox-node.nix b/nixos/modules/services/networking/tox-node.nix
index c24e7fd12850..c6e5c2d6e819 100644
--- a/nixos/modules/services/networking/tox-node.nix
+++ b/nixos/modules/services/networking/tox-node.nix
@@ -8,12 +8,7 @@ let
homeDir = "/var/lib/tox-node";
configFile = let
- # fetchurl should be switched to getting this file from tox-node.src once
- # the dpkg directory is in a release
- src = pkgs.fetchurl {
- url = "https://raw.githubusercontent.com/tox-rs/tox-node/master/dpkg/config.yml";
- sha256 = "1431wzpzm786mcvyzk1rp7ar418n45dr75hdggxvlm7pkpam31xa";
- };
+ src = "${pkg.src}/dpkg/config.yml";
confJSON = pkgs.writeText "config.json" (
builtins.toJSON {
log-type = cfg.logType;
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index f6e963490924..87873c8c1e83 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -62,6 +62,7 @@ in {
};
stateDir = mkOption {
+ type = types.path;
default = "/var/lib/unbound";
description = "Directory holding all state for unbound to run.";
};
diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix
index 710c2d9ca17b..d205302051e1 100644
--- a/nixos/modules/services/networking/vsftpd.nix
+++ b/nixos/modules/services/networking/vsftpd.nix
@@ -153,6 +153,7 @@ in
userlist = mkOption {
default = [];
+ type = types.listOf types.str;
description = "See .";
};
diff --git a/nixos/modules/services/networking/wg-netmanager.nix b/nixos/modules/services/networking/wg-netmanager.nix
new file mode 100644
index 000000000000..493ff7ceba9f
--- /dev/null
+++ b/nixos/modules/services/networking/wg-netmanager.nix
@@ -0,0 +1,42 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.wg-netmanager;
+in
+{
+
+ options = {
+ services.wg-netmanager = {
+ enable = mkEnableOption "Wireguard network manager";
+ };
+ };
+
+ ###### implementation
+ config = mkIf cfg.enable {
+ # NOTE: wg-netmanager runs as root
+ systemd.services.wg-netmanager = {
+ description = "Wireguard network manager";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ path = with pkgs; [ wireguard-tools iproute2 wireguard-go ];
+ serviceConfig = {
+ Type = "simple";
+ Restart = "on-failure";
+ ExecStart = "${pkgs.wg-netmanager}/bin/wg_netmanager";
+ ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ ExecStop = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+
+ ReadWritePaths = [
+ "/tmp" # wg-netmanager creates files in /tmp before deleting them after use
+ ];
+ };
+ unitConfig = {
+ ConditionPathExists = ["/etc/wg_netmanager/network.yaml" "/etc/wg_netmanager/peer.yaml"];
+ };
+ };
+ };
+
+ meta.maintainers = with maintainers; [ gin66 ];
+}
diff --git a/nixos/modules/services/networking/wg-quick.nix b/nixos/modules/services/networking/wg-quick.nix
index 414775fc3577..61e9fe5096b1 100644
--- a/nixos/modules/services/networking/wg-quick.nix
+++ b/nixos/modules/services/networking/wg-quick.nix
@@ -17,6 +17,13 @@ let
description = "The IP addresses of the interface.";
};
+ autostart = mkOption {
+ description = "Whether to bring up this interface automatically during boot.";
+ default = true;
+ example = false;
+ type = types.bool;
+ };
+
dns = mkOption {
example = [ "192.168.2.2" ];
default = [];
@@ -247,7 +254,7 @@ let
description = "wg-quick WireGuard Tunnel - ${name}";
requires = [ "network-online.target" ];
after = [ "network.target" "network-online.target" ];
- wantedBy = [ "multi-user.target" ];
+ wantedBy = optional values.autostart "multi-user.target";
environment.DEVICE = name;
path = [ pkgs.kmod pkgs.wireguard-tools ];
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 07dec8ea7181..c2e1d37e28bf 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -10,14 +10,45 @@ let
cfg = config.networking.wireless;
opt = options.networking.wireless;
+ wpa3Protocols = [ "SAE" "FT-SAE" ];
+ hasMixedWPA = opts:
+ let
+ hasWPA3 = !mutuallyExclusive opts.authProtocols wpa3Protocols;
+ others = subtractLists wpa3Protocols opts.authProtocols;
+ in hasWPA3 && others != [];
+
+ # Gives a WPA3 network higher priority
+ increaseWPA3Priority = opts:
+ opts // optionalAttrs (hasMixedWPA opts)
+ { priority = if opts.priority == null
+ then 1
+ else opts.priority + 1;
+ };
+
+ # Creates a WPA2 fallback network
+ mkWPA2Fallback = opts:
+ opts // { authProtocols = subtractLists wpa3Protocols opts.authProtocols; };
+
+ # Networks attrset as a list
+ networkList = mapAttrsToList (ssid: opts: opts // { inherit ssid; })
+ cfg.networks;
+
+ # List of all networks (normal + generated fallbacks)
+ allNetworks =
+ if cfg.fallbackToWPA2
+ then map increaseWPA3Priority networkList
+ ++ map mkWPA2Fallback (filter hasMixedWPA networkList)
+ else networkList;
+
# Content of wpa_supplicant.conf
generatedConfig = concatStringsSep "\n" (
- (mapAttrsToList mkNetwork cfg.networks)
+ (map mkNetwork allNetworks)
++ optional cfg.userControlled.enable (concatStringsSep "\n"
[ "ctrl_interface=/run/wpa_supplicant"
"ctrl_interface_group=${cfg.userControlled.group}"
"update_config=1"
])
+ ++ [ "pmf=1" ]
++ optional cfg.scanOnLowSignal ''bgscan="simple:30:-70:3600"''
++ optional (cfg.extraConfig != "") cfg.extraConfig);
@@ -33,7 +64,7 @@ let
finalConfig = ''"$RUNTIME_DIRECTORY"/wpa_supplicant.conf'';
# Creates a network block for wpa_supplicant.conf
- mkNetwork = ssid: opts:
+ mkNetwork = opts:
let
quote = x: ''"${x}"'';
indent = x: " " + x;
@@ -43,7 +74,7 @@ let
else opts.pskRaw;
options = [
- "ssid=${quote ssid}"
+ "ssid=${quote opts.ssid}"
(if pskString != null || opts.auth != null
then "key_mgmt=${concatStringsSep " " opts.authProtocols}"
else "key_mgmt=NONE")
@@ -175,6 +206,18 @@ in {
'';
};
+ fallbackToWPA2 = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to fall back to WPA2 authentication protocols if WPA3 failed.
+ This allows old wireless cards (that lack recent features required by
+ WPA3) to connect to mixed WPA2/WPA3 access points.
+
+ To avoid possible downgrade attacks, disable this options.
+ '';
+ };
+
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
diff --git a/nixos/modules/services/networking/yggdrasil.xml b/nixos/modules/services/networking/yggdrasil.xml
index c012cd4a9294..a341d5d8153b 100644
--- a/nixos/modules/services/networking/yggdrasil.xml
+++ b/nixos/modules/services/networking/yggdrasil.xml
@@ -84,7 +84,6 @@ in {
interface eth0
{
AdvSendAdvert on;
- AdvDefaultLifetime 0;
prefix ${prefix}::/64 {
AdvOnLink on;
AdvAutonomous on;
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index 98c35a7ec84b..041d0b3c43fd 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -143,6 +143,17 @@ in
example = lib.literalExpression "[ pkgs.elasticsearchPlugins.discovery-ec2 ]";
};
+ restartIfChanged = mkOption {
+ type = types.bool;
+ description = ''
+ Automatically restart the service on config change.
+ This can be set to false to defer restarts on a server or cluster.
+ Please consider the security implications of inadvertently running an older version,
+ and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option.
+ '';
+ default = true;
+ };
+
};
###### implementation
@@ -153,6 +164,7 @@ in
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
path = [ pkgs.inetutils ];
+ inherit (cfg) restartIfChanged;
environment = {
ES_HOME = cfg.dataDir;
ES_JAVA_OPTS = toString cfg.extraJavaOptions;
@@ -163,6 +175,8 @@ in
User = "elasticsearch";
PermissionsStartOnly = true;
LimitNOFILE = "1024000";
+ Restart = "always";
+ TimeoutStartSec = "infinity";
};
preStart = ''
${optionalString (!config.boot.isContainer) ''
diff --git a/nixos/modules/services/security/cfssl.nix b/nixos/modules/services/security/cfssl.nix
index e5bed0a9987c..6df2343b84d2 100644
--- a/nixos/modules/services/security/cfssl.nix
+++ b/nixos/modules/services/security/cfssl.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, ... }:
+{ config, options, lib, pkgs, ... }:
with lib;
@@ -11,7 +11,16 @@ in {
dataDir = mkOption {
default = "/var/lib/cfssl";
type = types.path;
- description = "Cfssl work directory.";
+ description = ''
+ The work directory for CFSSL.
+
+
+ If left as the default value this directory will automatically be
+ created before the CFSSL server starts, otherwise you are
+ responsible for ensuring the directory exists with appropriate
+ ownership and permissions.
+
+ '';
};
address = mkOption {
@@ -22,7 +31,7 @@ in {
port = mkOption {
default = 8888;
- type = types.ints.u16;
+ type = types.port;
description = "Port to bind.";
};
@@ -147,13 +156,12 @@ in {
};
config = mkIf cfg.enable {
- users.extraGroups.cfssl = {
+ users.groups.cfssl = {
gid = config.ids.gids.cfssl;
};
- users.extraUsers.cfssl = {
+ users.users.cfssl = {
description = "cfssl user";
- createHome = true;
home = cfg.dataDir;
group = "cfssl";
uid = config.ids.uids.cfssl;
@@ -164,41 +172,46 @@ in {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
- serviceConfig = {
- WorkingDirectory = cfg.dataDir;
- StateDirectory = cfg.dataDir;
- StateDirectoryMode = 700;
- Restart = "always";
- User = "cfssl";
+ serviceConfig = lib.mkMerge [
+ {
+ WorkingDirectory = cfg.dataDir;
+ Restart = "always";
+ User = "cfssl";
+ Group = "cfssl";
- ExecStart = with cfg; let
- opt = n: v: optionalString (v != null) ''-${n}="${v}"'';
- in
- lib.concatStringsSep " \\\n" [
- "${pkgs.cfssl}/bin/cfssl serve"
- (opt "address" address)
- (opt "port" (toString port))
- (opt "ca" ca)
- (opt "ca-key" caKey)
- (opt "ca-bundle" caBundle)
- (opt "int-bundle" intBundle)
- (opt "int-dir" intDir)
- (opt "metadata" metadata)
- (opt "remote" remote)
- (opt "config" configFile)
- (opt "responder" responder)
- (opt "responder-key" responderKey)
- (opt "tls-key" tlsKey)
- (opt "tls-cert" tlsCert)
- (opt "mutual-tls-ca" mutualTlsCa)
- (opt "mutual-tls-cn" mutualTlsCn)
- (opt "mutual-tls-client-key" mutualTlsClientKey)
- (opt "mutual-tls-client-cert" mutualTlsClientCert)
- (opt "tls-remote-ca" tlsRemoteCa)
- (opt "db-config" dbConfig)
- (opt "loglevel" (toString logLevel))
- ];
- };
+ ExecStart = with cfg; let
+ opt = n: v: optionalString (v != null) ''-${n}="${v}"'';
+ in
+ lib.concatStringsSep " \\\n" [
+ "${pkgs.cfssl}/bin/cfssl serve"
+ (opt "address" address)
+ (opt "port" (toString port))
+ (opt "ca" ca)
+ (opt "ca-key" caKey)
+ (opt "ca-bundle" caBundle)
+ (opt "int-bundle" intBundle)
+ (opt "int-dir" intDir)
+ (opt "metadata" metadata)
+ (opt "remote" remote)
+ (opt "config" configFile)
+ (opt "responder" responder)
+ (opt "responder-key" responderKey)
+ (opt "tls-key" tlsKey)
+ (opt "tls-cert" tlsCert)
+ (opt "mutual-tls-ca" mutualTlsCa)
+ (opt "mutual-tls-cn" mutualTlsCn)
+ (opt "mutual-tls-client-key" mutualTlsClientKey)
+ (opt "mutual-tls-client-cert" mutualTlsClientCert)
+ (opt "tls-remote-ca" tlsRemoteCa)
+ (opt "db-config" dbConfig)
+ (opt "loglevel" (toString logLevel))
+ ];
+ }
+ (mkIf (cfg.dataDir == options.services.cfssl.dataDir.default) {
+ StateDirectory = baseNameOf cfg.dataDir;
+ StateDirectoryMode = 700;
+ })
+ ];
};
services.cfssl = {
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index 340cbbf02fb4..95a0ad8770e2 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -9,7 +9,7 @@ let
pkg = pkgs.clamav;
toKeyValue = generators.toKeyValue {
- mkKeyValue = generators.mkKeyValueDefault {} " ";
+ mkKeyValue = generators.mkKeyValueDefault { } " ";
listsAsDuplicateKeys = true;
};
@@ -30,7 +30,7 @@ in
settings = mkOption {
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
- default = {};
+ default = { };
description = ''
ClamAV configuration. Refer to ,
for details on supported values.
@@ -59,7 +59,7 @@ in
settings = mkOption {
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
- default = {};
+ default = { };
description = ''
freshclam configuration. Refer to ,
for details on supported values.
@@ -104,7 +104,6 @@ in
systemd.services.clamav-daemon = mkIf cfg.daemon.enable {
description = "ClamAV daemon (clamd)";
after = optional cfg.updater.enable "clamav-freshclam.service";
- requires = optional cfg.updater.enable "clamav-freshclam.service";
wantedBy = [ "multi-user.target" ];
restartTriggers = [ clamdConfigFile ];
@@ -134,7 +133,7 @@ in
systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
description = "ClamAV virus database updater (freshclam)";
restartTriggers = [ freshclamConfigFile ];
-
+ after = [ "network-online.target" ];
preStart = ''
mkdir -m 0755 -p ${stateDir}
chown ${clamavUser}:${clamavGroup} ${stateDir}
diff --git a/nixos/modules/services/security/fprot.nix b/nixos/modules/services/security/fprot.nix
deleted file mode 100644
index df60d553e85b..000000000000
--- a/nixos/modules/services/security/fprot.nix
+++ /dev/null
@@ -1,82 +0,0 @@
-{ config, lib, pkgs, ... }:
-with lib;
-let
- fprotUser = "fprot";
- stateDir = "/var/lib/fprot";
- fprotGroup = fprotUser;
- cfg = config.services.fprot;
-in {
- options = {
-
- services.fprot = {
- updater = {
- enable = mkEnableOption "automatic F-Prot virus definitions database updates";
-
- productData = mkOption {
- description = ''
- product.data file. Defaults to the one supplied with installation package.
- '';
- type = types.path;
- };
-
- frequency = mkOption {
- default = 30;
- type = types.int;
- description = ''
- Update virus definitions every X minutes.
- '';
- };
-
- licenseKeyfile = mkOption {
- type = types.path;
- description = ''
- License keyfile. Defaults to the one supplied with installation package.
- '';
- };
-
- };
- };
- };
-
- ###### implementation
-
- config = mkIf cfg.updater.enable {
-
- services.fprot.updater.productData = mkDefault "${pkgs.fprot}/opt/f-prot/product.data";
- services.fprot.updater.licenseKeyfile = mkDefault "${pkgs.fprot}/opt/f-prot/license.key";
-
- environment.systemPackages = [ pkgs.fprot ];
- environment.etc."f-prot.conf" = {
- source = "${pkgs.fprot}/opt/f-prot/f-prot.conf";
- };
-
- users.users.${fprotUser} =
- { uid = config.ids.uids.fprot;
- description = "F-Prot daemon user";
- home = stateDir;
- };
-
- users.groups.${fprotGroup} =
- { gid = config.ids.gids.fprot; };
-
- services.cron.systemCronJobs = [ "*/${toString cfg.updater.frequency} * * * * root start fprot-updater" ];
-
- systemd.services.fprot-updater = {
- serviceConfig = {
- Type = "oneshot";
- RemainAfterExit = false;
- };
- wantedBy = [ "multi-user.target" ];
-
- # have to copy fpupdate executable because it insists on storing the virus database in the same dir
- preStart = ''
- mkdir -m 0755 -p ${stateDir}
- chown ${fprotUser}:${fprotGroup} ${stateDir}
- cp ${pkgs.fprot}/opt/f-prot/fpupdate ${stateDir}
- ln -sf ${cfg.updater.productData} ${stateDir}/product.data
- '';
-
- script = "/var/lib/fprot/fpupdate --keyfile ${cfg.updater.licenseKeyfile}";
- };
- };
-}
diff --git a/nixos/modules/services/security/haveged.nix b/nixos/modules/services/security/haveged.nix
index 22ece1883446..57cef7e44d50 100644
--- a/nixos/modules/services/security/haveged.nix
+++ b/nixos/modules/services/security/haveged.nix
@@ -3,12 +3,10 @@
with lib;
let
-
cfg = config.services.haveged;
in
-
{
###### interface
@@ -17,14 +15,11 @@ in
services.haveged = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to enable to haveged entropy daemon, which refills
- /dev/random when low.
- '';
- };
+ enable = mkEnableOption ''
+ haveged entropy daemon, which refills /dev/random when low.
+ NOTE: does nothing on kernels newer than 5.6.
+ '';
+ # source for the note https://github.com/jirka-h/haveged/issues/57
refill_threshold = mkOption {
type = types.int;
@@ -39,29 +34,44 @@ in
};
-
- ###### implementation
-
config = mkIf cfg.enable {
- systemd.services.haveged =
- { description = "Entropy Harvesting Daemon";
- unitConfig.Documentation = "man:haveged(8)";
- wantedBy = [ "multi-user.target" ];
+ # https://github.com/jirka-h/haveged/blob/a4b69d65a8dfc5a9f52ff8505c7f58dcf8b9234f/contrib/Fedora/haveged.service
+ systemd.services.haveged = {
+ description = "Entropy Daemon based on the HAVEGE algorithm";
+ unitConfig = {
+ Documentation = "man:haveged(8)";
+ DefaultDependencies = false;
+ ConditionKernelVersion = "<5.6";
+ };
+ wantedBy = [ "sysinit.target" ];
+ after = [ "systemd-tmpfiles-setup-dev.service" ];
+ before = [ "sysinit.target" "shutdown.target" "systemd-journald.service" ];
- path = [ pkgs.haveged ];
-
- serviceConfig = {
- ExecStart = "${pkgs.haveged}/bin/haveged -F -w ${toString cfg.refill_threshold} -v 1";
- SuccessExitStatus = 143;
- PrivateTmp = true;
- PrivateDevices = true;
- PrivateNetwork = true;
- ProtectSystem = "full";
- ProtectHome = true;
- };
+ serviceConfig = {
+ ExecStart = "${pkgs.haveged}/bin/haveged -w ${toString cfg.refill_threshold} --Foreground -v 1";
+ Restart = "always";
+ SuccessExitStatus = "137 143";
+ SecureBits = "noroot-locked";
+ CapabilityBoundingSet = [ "CAP_SYS_ADMIN" "CAP_SYS_CHROOT" ];
+ # We can *not* set PrivateTmp=true as it can cause an ordering cycle.
+ PrivateTmp = false;
+ PrivateDevices = true;
+ ProtectSystem = "full";
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [ "@system-service" "newuname" "~@mount" ];
+ SystemCallErrorNumber = "EPERM";
};
+ };
};
}
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
index 4d3562424170..ce295bd4ba3b 100644
--- a/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -102,17 +102,19 @@ in
# Taken from: https://github.com/oauth2-proxy/oauth2-proxy/blob/master/providers/providers.go
provider = mkOption {
type = types.enum [
- "google"
+ "adfs"
"azure"
+ "bitbucket"
+ "digitalocean"
"facebook"
"github"
- "keycloak"
"gitlab"
+ "google"
+ "keycloak"
+ "keycloak-oidc"
"linkedin"
"login.gov"
- "bitbucket"
"nextcloud"
- "digitalocean"
"oidc"
];
default = "google";
diff --git a/nixos/modules/services/security/opensnitch.nix b/nixos/modules/services/security/opensnitch.nix
index 919346cf2bb1..f9b4985e1991 100644
--- a/nixos/modules/services/security/opensnitch.nix
+++ b/nixos/modules/services/security/opensnitch.nix
@@ -3,22 +3,123 @@
with lib;
let
- name = "opensnitch";
cfg = config.services.opensnitch;
+ format = pkgs.formats.json {};
in {
options = {
services.opensnitch = {
enable = mkEnableOption "Opensnitch application firewall";
+ settings = mkOption {
+ type = types.submodule {
+ freeformType = format.type;
+
+ options = {
+ Server = {
+
+ Address = mkOption {
+ type = types.str;
+ description = ''
+ Unix socket path (unix:///tmp/osui.sock, the "unix:///" part is
+ mandatory) or TCP socket (192.168.1.100:50051).
+ '';
+ };
+
+ LogFile = mkOption {
+ type = types.path;
+ description = ''
+ File to write logs to (use /dev/stdout to write logs to standard
+ output).
+ '';
+ };
+
+ };
+
+ DefaultAction = mkOption {
+ type = types.enum [ "allow" "deny" ];
+ description = ''
+ Default action whether to block or allow application internet
+ access.
+ '';
+ };
+
+ DefaultDuration = mkOption {
+ type = types.enum [
+ "once" "always" "until restart" "30s" "5m" "15m" "30m" "1h"
+ ];
+ description = ''
+ Default duration of firewall rule.
+ '';
+ };
+
+ InterceptUnknown = mkOption {
+ type = types.bool;
+ description = ''
+ Wheter to intercept spare connections.
+ '';
+ };
+
+ ProcMonitorMethod = mkOption {
+ type = types.enum [ "ebpf" "proc" "ftrace" "audit" ];
+ description = ''
+ Which process monitoring method to use.
+ '';
+ };
+
+ LogLevel = mkOption {
+ type = types.enum [ 0 1 2 3 4 ];
+ description = ''
+ Default log level from 0 to 4 (debug, info, important, warning,
+ error).
+ '';
+ };
+
+ Firewall = mkOption {
+ type = types.enum [ "iptables" "nftables" ];
+ description = ''
+ Which firewall backend to use.
+ '';
+ };
+
+ Stats = {
+
+ MaxEvents = mkOption {
+ type = types.int;
+ description = ''
+ Max events to send to the GUI.
+ '';
+ };
+
+ MaxStats = mkOption {
+ type = types.int;
+ description = ''
+ Max stats per item to keep in backlog.
+ '';
+ };
+
+ };
+ };
+ };
+ description = ''
+ opensnitchd configuration. Refer to
+
+ for details on supported values.
+ '';
+ };
};
};
config = mkIf cfg.enable {
+ # pkg.opensnitch is referred to elsewhere in the module so we don't need to worry about it being garbage collected
+ services.opensnitch.settings = mapAttrs (_: v: mkDefault v) (builtins.fromJSON (builtins.unsafeDiscardStringContext (builtins.readFile "${pkgs.opensnitch}/etc/default-config.json")));
+
systemd = {
packages = [ pkgs.opensnitch ];
services.opensnitchd.wantedBy = [ "multi-user.target" ];
};
+ environment.etc."opensnitchd/default-config.json".source = format.generate "default-config.json" cfg.settings;
+
};
}
diff --git a/nixos/modules/services/security/sslmate-agent.nix b/nixos/modules/services/security/sslmate-agent.nix
new file mode 100644
index 000000000000..c850eb22a031
--- /dev/null
+++ b/nixos/modules/services/security/sslmate-agent.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.sslmate-agent;
+
+in {
+ meta.maintainers = with maintainers; [ wolfangaukang ];
+
+ options = {
+ services.sslmate-agent = {
+ enable = mkEnableOption "sslmate-agent, a daemon for managing SSL/TLS certificates on a server";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment.systemPackages = with pkgs; [ sslmate-agent ];
+
+ systemd = {
+ packages = [ pkgs.sslmate-agent ];
+ services.sslmate-agent = {
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ ConfigurationDirectory = "sslmate-agent";
+ LogsDirectory = "sslmate-agent";
+ StateDirectory = "sslmate-agent";
+ };
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/security/step-ca.nix b/nixos/modules/services/security/step-ca.nix
index 27b2ceed1a43..95183078d7b6 100644
--- a/nixos/modules/services/security/step-ca.nix
+++ b/nixos/modules/services/security/step-ca.nix
@@ -1,4 +1,4 @@
-{ config, lib, pkgs, nixosTests, ... }:
+{ config, lib, pkgs, ... }:
let
cfg = config.services.step-ca;
settingsFormat = (pkgs.formats.json { });
@@ -82,8 +82,6 @@ in
});
in
{
- passthru.tests.step-ca = nixosTests.step-ca;
-
assertions =
[
{
@@ -108,6 +106,9 @@ in
ConditionFileNotEmpty = ""; # override upstream
};
serviceConfig = {
+ User = "step-ca";
+ Group = "step-ca";
+ UMask = "0077";
Environment = "HOME=%S/step-ca";
WorkingDirectory = ""; # override upstream
ReadWriteDirectories = ""; # override upstream
@@ -129,6 +130,14 @@ in
};
};
+ users.users.step-ca = {
+ home = "/var/lib/step-ca";
+ group = "step-ca";
+ isSystemUser = true;
+ };
+
+ users.groups.step-ca = {};
+
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix
index cafb44e12429..a5822c02794d 100644
--- a/nixos/modules/services/security/tor.nix
+++ b/nixos/modules/services/security/tor.nix
@@ -910,6 +910,11 @@ in
ORPort = mkForce [];
PublishServerDescriptor = mkForce false;
})
+ (mkIf (!cfg.client.enable) {
+ # Make sure application connections via SOCKS are disabled
+ # when services.tor.client.enable is false
+ SOCKSPort = mkForce [ 0 ];
+ })
(mkIf cfg.client.enable (
{ SOCKSPort = [ cfg.client.socksListenAddress ];
} // optionalAttrs cfg.client.transparentProxy.enable {
@@ -962,7 +967,7 @@ in
'') onion.authorizedClients ++
optional (onion.secretKey != null) ''
install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path}
- key="$(cut -f1 -d: ${escapeShellArg onion.secretKey})"
+ key="$(cut -f1 -d: ${escapeShellArg onion.secretKey} | head -1)"
case "$key" in
("== ed25519v"*"-secret")
install -o tor -g tor -m 0400 ${escapeShellArg onion.secretKey} ${escapeShellArg onion.path}/hs_ed25519_secret_key;;
@@ -1008,7 +1013,11 @@ in
#InaccessiblePaths = [ "-+${runDir}/root" ];
UMask = "0066";
BindPaths = [ stateDir ];
- BindReadOnlyPaths = [ storeDir "/etc" ];
+ BindReadOnlyPaths = [ storeDir "/etc" ] ++
+ optionals config.services.resolved.enable [
+ "/run/systemd/resolve/stub-resolv.conf"
+ "/run/systemd/resolve/resolv.conf"
+ ];
AmbientCapabilities = [""] ++ lib.optional bindsPrivilegedPort "CAP_NET_BIND_SERVICE";
CapabilityBoundingSet = [""] ++ lib.optional bindsPrivilegedPort "CAP_NET_BIND_SERVICE";
# ProtectClock= adds DeviceAllow=char-rtc r
diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix
index 71088fc4dcd8..8277f493639c 100644
--- a/nixos/modules/services/security/vaultwarden/default.nix
+++ b/nixos/modules/services/security/vaultwarden/default.nix
@@ -131,7 +131,7 @@ in {
users.groups.vaultwarden = { };
systemd.services.vaultwarden = {
- aliases = [ "bitwarden_rs" ];
+ aliases = [ "bitwarden_rs.service" ];
after = [ "network.target" ];
path = with pkgs; [ openssl ];
serviceConfig = {
@@ -151,7 +151,7 @@ in {
};
systemd.services.backup-vaultwarden = mkIf (cfg.backupDir != null) {
- aliases = [ "backup-bitwarden_rs" ];
+ aliases = [ "backup-bitwarden_rs.service" ];
description = "Backup vaultwarden";
environment = {
DATA_FOLDER = "/var/lib/bitwarden_rs";
@@ -169,7 +169,7 @@ in {
};
systemd.timers.backup-vaultwarden = mkIf (cfg.backupDir != null) {
- aliases = [ "backup-bitwarden_rs" ];
+ aliases = [ "backup-bitwarden_rs.service" ];
description = "Backup vaultwarden on time";
timerConfig = {
OnCalendar = mkDefault "23:00";
diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix
index eb82b738e492..8c6a6e294ebb 100644
--- a/nixos/modules/services/system/cloud-init.nix
+++ b/nixos/modules/services/system/cloud-init.nix
@@ -52,11 +52,22 @@ in
'';
};
+ network.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Allow the cloud-init service to configure network interfaces
+ through systemd-networkd.
+ '';
+ };
+
config = mkOption {
type = types.str;
default = ''
system_info:
distro: nixos
+ network:
+ renderers: [ 'networkd' ]
users:
- root
@@ -109,9 +120,12 @@ in
environment.etc."cloud/cloud.cfg".text = cfg.config;
+ systemd.network.enable = cfg.network.enable;
+
systemd.services.cloud-init-local =
{ description = "Initial cloud-init job (pre-networking)";
wantedBy = [ "multi-user.target" ];
+ before = ["systemd-networkd.service"];
path = path;
serviceConfig =
{ Type = "oneshot";
@@ -129,7 +143,7 @@ in
"sshd.service" "sshd-keygen.service" ];
after = [ "network-online.target" "cloud-init-local.service" ];
before = [ "sshd.service" "sshd-keygen.service" ];
- requires = [ "network.target "];
+ requires = [ "network.target"];
path = path;
serviceConfig =
{ Type = "oneshot";
diff --git a/nixos/modules/services/system/earlyoom.nix b/nixos/modules/services/system/earlyoom.nix
index 452efc736439..629358559890 100644
--- a/nixos/modules/services/system/earlyoom.nix
+++ b/nixos/modules/services/system/earlyoom.nix
@@ -1,124 +1,160 @@
{ config, lib, pkgs, ... }:
-with lib;
-
let
- ecfg = config.services.earlyoom;
+ cfg = config.services.earlyoom;
+
+ inherit (lib)
+ mkDefault mkEnableOption mkIf mkOption types
+ mkRemovedOptionModule literalExpression
+ escapeShellArg concatStringsSep optional optionalString;
+
in
{
- options = {
- services.earlyoom = {
+ options.services.earlyoom = {
+ enable = mkEnableOption "Early out of memory killing";
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enable early out of memory killing.
- '';
- };
+ freeMemThreshold = mkOption {
+ type = types.ints.between 1 100;
+ default = 10;
+ description = ''
+ Minimum available memory (in percent).
- freeMemThreshold = mkOption {
- type = types.int;
- default = 10;
- description = ''
- Minimum of availabe memory (in percent).
- If the free memory falls below this threshold and the analog is true for
-
- the killing begins.
- '';
- };
+ If the available memory falls below this threshold (and the analog is true for
+ ) the killing begins.
+ SIGTERM is sent first to the process that uses the most memory; then, if the available
+ memory falls below (and the analog is true for
+ ), SIGKILL is sent.
- freeSwapThreshold = mkOption {
- type = types.int;
- default = 10;
- description = ''
- Minimum of availabe swap space (in percent).
- If the available swap space falls below this threshold and the analog
- is true for
- the killing begins.
- '';
- };
+ See README for details.
+ '';
+ };
- useKernelOOMKiller= mkOption {
- type = types.bool;
- default = false;
- description = ''
- Use kernel OOM killer instead of own user-space implementation.
- '';
- };
+ freeMemKillThreshold = mkOption {
+ type = types.nullOr (types.ints.between 1 100);
+ default = null;
+ description = ''
+ Minimum available memory (in percent) before sending SIGKILL.
+ If unset, this defaults to half of .
- ignoreOOMScoreAdjust = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Ignore oom_score_adjust values of processes.
- User-space implementation only.
- '';
- };
+ See the description of .
+ '';
+ };
- enableDebugInfo = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enable debugging messages.
- '';
- };
+ freeSwapThreshold = mkOption {
+ type = types.ints.between 1 100;
+ default = 10;
+ description = ''
+ Minimum free swap space (in percent) before sending SIGTERM.
- notificationsCommand = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- This option is deprecated and ignored by earlyoom since 1.6.
- Use instead.
- '';
- };
+ See the description of .
+ '';
+ };
- enableNotifications = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Send notifications about killed processes via the system d-bus.
- To actually see the notifications in your GUI session, you need to have
- systembus-notify running as your user.
+ freeSwapKillThreshold = mkOption {
+ type = types.nullOr (types.ints.between 1 100);
+ default = null;
+ description = ''
+ Minimum free swap space (in percent) before sending SIGKILL.
+ If unset, this defaults to half of .
- See README for details.
- '';
- };
+ See the description of .
+ '';
+ };
+
+ enableDebugInfo = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable debugging messages.
+ '';
+ };
+
+ enableNotifications = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Send notifications about killed processes via the system d-bus.
+
+ WARNING: enabling this option (while convenient) should *not* be done on a
+ machine where you do not trust the other users as it allows any other
+ local user to DoS your session by spamming notifications.
+
+ To actually see the notifications in your GUI session, you need to have
+ systembus-notify running as your user, which this
+ option handles by enabling .
+
+ See README for details.
+ '';
+ };
+
+ killHook = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = literalExpression ''
+ pkgs.writeShellScript "earlyoom-kill-hook" '''
+ echo "Process $EARLYOOM_NAME ($EARLYOOM_PID) was killed" >> /path/to/log
+ '''
+ '';
+ description = ''
+ An absolute path to an executable to be run for each process killed.
+ Some environment variables are available, see
+ README and
+ the man page
+ for details.
+ '';
+ };
+
+ reportInterval = mkOption {
+ type = types.int;
+ default = 3600;
+ example = 0;
+ description = "Interval (in seconds) at which a memory report is printed (set to 0 to disable).";
+ };
+
+ extraArgs = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "-g" "--prefer '(^|/)(java|chromium)$'" ];
+ description = "Extra command-line arguments to be passed to earlyoom.";
};
};
- config = mkIf ecfg.enable {
- assertions = [
- { assertion = ecfg.freeMemThreshold > 0 && ecfg.freeMemThreshold <= 100;
- message = "Needs to be a positive percentage"; }
- { assertion = ecfg.freeSwapThreshold > 0 && ecfg.freeSwapThreshold <= 100;
- message = "Needs to be a positive percentage"; }
- { assertion = !ecfg.useKernelOOMKiller || !ecfg.ignoreOOMScoreAdjust;
- message = "Both options in conjunction do not make sense"; }
- ];
+ imports = [
+ (mkRemovedOptionModule [ "services" "earlyoom" "useKernelOOMKiller" ] ''
+ This option is deprecated and ignored by earlyoom since 1.2.
+ '')
+ (mkRemovedOptionModule [ "services" "earlyoom" "notificationsCommand" ] ''
+ This option was removed in earlyoom 1.6, but was reimplemented in 1.7
+ and is available as the new option `services.earlyoom.killHook`.
+ '')
+ (mkRemovedOptionModule [ "services" "earlyoom" "ignoreOOMScoreAdjust" ] ''
+ This option is deprecated and ignored by earlyoom since 1.7.
+ '')
+ ];
- warnings = optional (ecfg.notificationsCommand != null)
- "`services.earlyoom.notificationsCommand` is deprecated and ignored by earlyoom since 1.6.";
+ config = mkIf cfg.enable {
+ services.systembus-notify.enable = mkDefault cfg.enableNotifications;
systemd.services.earlyoom = {
description = "Early OOM Daemon for Linux";
wantedBy = [ "multi-user.target" ];
- path = optional ecfg.enableNotifications pkgs.dbus;
+ path = optional cfg.enableNotifications pkgs.dbus;
serviceConfig = {
- StandardOutput = "null";
StandardError = "journal";
- ExecStart = ''
- ${pkgs.earlyoom}/bin/earlyoom \
- -m ${toString ecfg.freeMemThreshold} \
- -s ${toString ecfg.freeSwapThreshold} \
- ${optionalString ecfg.useKernelOOMKiller "-k"} \
- ${optionalString ecfg.ignoreOOMScoreAdjust "-i"} \
- ${optionalString ecfg.enableDebugInfo "-d"} \
- ${optionalString ecfg.enableNotifications "-n"}
- '';
+ ExecStart = concatStringsSep " " ([
+ "${pkgs.earlyoom}/bin/earlyoom"
+ ("-m ${toString cfg.freeMemThreshold}"
+ + optionalString (cfg.freeMemKillThreshold != null) ",${toString cfg.freeMemKillThreshold}")
+ ("-s ${toString cfg.freeSwapThreshold}"
+ + optionalString (cfg.freeSwapKillThreshold != null) ",${toString cfg.freeSwapKillThreshold}")
+ "-r ${toString cfg.reportInterval}"
+ ]
+ ++ optional cfg.enableDebugInfo "-d"
+ ++ optional cfg.enableNotifications "-n"
+ ++ optional (cfg.killHook != null) "-N ${escapeShellArg cfg.killHook}"
+ ++ cfg.extraArgs
+ );
};
};
-
- environment.systemPackages = optional ecfg.enableNotifications pkgs.systembus-notify;
};
}
diff --git a/nixos/modules/services/system/self-deploy.nix b/nixos/modules/services/system/self-deploy.nix
index 33d15e08f4aa..d7130a13c731 100644
--- a/nixos/modules/services/system/self-deploy.nix
+++ b/nixos/modules/services/system/self-deploy.nix
@@ -126,6 +126,8 @@ in
config = lib.mkIf cfg.enable {
systemd.services.self-deploy = {
+ inherit (cfg) startAt;
+
wantedBy = [ "multi-user.target" ];
requires = lib.mkIf (!(isPathType cfg.repository)) [ "network-online.target" ];
@@ -138,8 +140,7 @@ in
path = with pkgs; [
git
nix
- systemd
- ];
+ ] ++ lib.optionals (cfg.switchCommand == "boot") [ systemd ];
script = ''
if [ ! -e ${repositoryDirectory} ]; then
diff --git a/nixos/modules/services/system/systembus-notify.nix b/nixos/modules/services/system/systembus-notify.nix
new file mode 100644
index 000000000000..e918bc552ece
--- /dev/null
+++ b/nixos/modules/services/system/systembus-notify.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+let
+ cfg = config.services.systembus-notify;
+
+ inherit (lib) mkEnableOption mkIf;
+
+in
+{
+ options.services.systembus-notify = {
+ enable = mkEnableOption ''
+ System bus notification support
+
+ WARNING: enabling this option (while convenient) should *not* be done on a
+ machine where you do not trust the other users as it allows any other
+ local user to DoS your session by spamming notifications.
+ '';
+ };
+
+ config = mkIf cfg.enable {
+ systemd = {
+ packages = with pkgs; [ systembus-notify ];
+
+ user.services.systembus-notify.wantedBy = [ "graphical-session.target" ];
+ };
+ };
+}
diff --git a/nixos/modules/services/video/epgstation/default.nix b/nixos/modules/services/video/epgstation/default.nix
index 41613dcbb3ba..191f6eb52e57 100644
--- a/nixos/modules/services/video/epgstation/default.nix
+++ b/nixos/modules/services/video/epgstation/default.nix
@@ -1,30 +1,40 @@
{ config, lib, options, pkgs, ... }:
-with lib;
-
let
cfg = config.services.epgstation;
opt = options.services.epgstation;
+ description = "EPGStation: DVR system for Mirakurun-managed TV tuners";
+
username = config.users.users.epgstation.name;
groupname = config.users.users.epgstation.group;
+ mirakurun = {
+ sock = config.services.mirakurun.unixSocket;
+ option = options.services.mirakurun.unixSocket;
+ };
- settingsFmt = pkgs.formats.json {};
- settingsTemplate = settingsFmt.generate "config.json" cfg.settings;
+ yaml = pkgs.formats.yaml { };
+ settingsTemplate = yaml.generate "config.yml" cfg.settings;
preStartScript = pkgs.writeScript "epgstation-prestart" ''
#!${pkgs.runtimeShell}
- PASSWORD="$(head -n1 "${cfg.basicAuth.passwordFile}")"
- DB_PASSWORD="$(head -n1 "${cfg.database.passwordFile}")"
+ DB_PASSWORD_FILE=${lib.escapeShellArg cfg.database.passwordFile}
+
+ if [[ ! -f "$DB_PASSWORD_FILE" ]]; then
+ printf "[FATAL] File containing the DB password was not found in '%s'. Double check the NixOS option '%s'." \
+ "$DB_PASSWORD_FILE" ${lib.escapeShellArg opt.database.passwordFile} >&2
+ exit 1
+ fi
+
+ DB_PASSWORD="$(head -n1 ${lib.escapeShellArg cfg.database.passwordFile})"
# setup configuration
- touch /etc/epgstation/config.json
- chmod 640 /etc/epgstation/config.json
+ touch /etc/epgstation/config.yml
+ chmod 640 /etc/epgstation/config.yml
sed \
- -e "s,@password@,$PASSWORD,g" \
-e "s,@dbPassword@,$DB_PASSWORD,g" \
- ${settingsTemplate} > /etc/epgstation/config.json
- chown "${username}:${groupname}" /etc/epgstation/config.json
+ ${settingsTemplate} > /etc/epgstation/config.yml
+ chown "${username}:${groupname}" /etc/epgstation/config.yml
# NOTE: Use password authentication, since mysqljs does not yet support auth_socket
if [ ! -e /var/lib/epgstation/db-created ]; then
@@ -35,7 +45,7 @@ let
'';
streamingConfig = lib.importJSON ./streaming.json;
- logConfig = {
+ logConfig = yaml.generate "logConfig.yml" {
appenders.stdout.type = "stdout";
categories = {
default = { appenders = [ "stdout" ]; level = "info"; };
@@ -45,53 +55,51 @@ let
};
};
- defaultPassword = "INSECURE_GO_CHECK_CONFIGURATION_NIX\n";
+ # Deprecate top level options that are redundant.
+ deprecateTopLevelOption = config:
+ lib.mkRenamedOptionModule
+ ([ "services" "epgstation" ] ++ config)
+ ([ "services" "epgstation" "settings" ] ++ config);
+
+ removeOption = config: instruction:
+ lib.mkRemovedOptionModule
+ ([ "services" "epgstation" ] ++ config)
+ instruction;
in
{
- options.services.epgstation = {
- enable = mkEnableOption "EPGStation: DTV Software in Japan";
+ meta.maintainers = with lib.maintainers; [ midchildan ];
- usePreconfiguredStreaming = mkOption {
- type = types.bool;
+ imports = [
+ (deprecateTopLevelOption [ "port" ])
+ (deprecateTopLevelOption [ "socketioPort" ])
+ (deprecateTopLevelOption [ "clientSocketioPort" ])
+ (removeOption [ "basicAuth" ]
+ "Use a TLS-terminated reverse proxy with authentication instead.")
+ ];
+
+ options.services.epgstation = {
+ enable = lib.mkEnableOption description;
+
+ package = lib.mkOption {
+ default = pkgs.epgstation;
+ type = lib.types.package;
+ defaultText = lib.literalExpression "pkgs.epgstation";
+ description = "epgstation package to use";
+ };
+
+ usePreconfiguredStreaming = lib.mkOption {
+ type = lib.types.bool;
default = true;
description = ''
Use preconfigured default streaming options.
Upstream defaults:
-
+
'';
};
- port = mkOption {
- type = types.port;
- default = 20772;
- description = ''
- HTTP port for EPGStation to listen on.
- '';
- };
-
- socketioPort = mkOption {
- type = types.port;
- default = cfg.port + 1;
- defaultText = literalExpression "config.${opt.port} + 1";
- description = ''
- Socket.io port for EPGStation to listen on.
- '';
- };
-
- clientSocketioPort = mkOption {
- type = types.port;
- default = cfg.socketioPort;
- defaultText = literalExpression "config.${opt.socketioPort}";
- description = ''
- Socket.io port that the web client is going to connect to. This may be
- different from if EPGStation is hidden
- behind a reverse proxy.
- '';
- };
-
- openFirewall = mkOption {
- type = types.bool;
+ openFirewall = lib.mkOption {
+ type = lib.types.bool;
default = false;
description = ''
Open ports in the firewall for the EPGStation web interface.
@@ -106,50 +114,17 @@ in
'';
};
- basicAuth = {
- user = mkOption {
- type = with types; nullOr str;
- default = null;
- example = "epgstation";
- description = ''
- Basic auth username for EPGStation. If null, basic
- auth will be disabled.
-
-
-
- Basic authentication has known weaknesses, the most critical being
- that it sends passwords over the network in clear text. Use this
- feature to control access to EPGStation within your family and
- friends, but don't rely on it for security.
-
-
- '';
- };
-
- passwordFile = mkOption {
- type = types.path;
- default = pkgs.writeText "epgstation-password" defaultPassword;
- defaultText = literalDocBook ''a file containing ${defaultPassword}'';
- example = "/run/keys/epgstation-password";
- description = ''
- A file containing the password for .
- '';
- };
- };
-
- database = {
- name = mkOption {
- type = types.str;
+ database = {
+ name = lib.mkOption {
+ type = lib.types.str;
default = "epgstation";
description = ''
Name of the MySQL database that holds EPGStation's data.
'';
};
- passwordFile = mkOption {
- type = types.path;
- default = pkgs.writeText "epgstation-db-password" defaultPassword;
- defaultText = literalDocBook ''a file containing ${defaultPassword}'';
+ passwordFile = lib.mkOption {
+ type = lib.types.path;
example = "/run/keys/epgstation-db-password";
description = ''
A file containing the password for the database named
@@ -158,69 +133,106 @@ in
};
};
- settings = mkOption {
+ # The defaults for some options come from the upstream template
+ # configuration, which is the one that users would get if they follow the
+ # upstream instructions. This is, in some cases, different from the
+ # application defaults. Some options like encodeProcessNum and
+ # concurrentEncodeNum doesn't have an optimal default value that works for
+ # all hardware setups and/or performance requirements. For those kind of
+ # options, the application default wouldn't always result in the expected
+ # out-of-the-box behavior because it's the responsibility of the user to
+ # configure them according to their needs. In these cases, the value in the
+ # upstream template configuration should serve as a "good enough" default.
+ settings = lib.mkOption {
description = ''
- Options to add to config.json.
+ Options to add to config.yml.
Documentation:
'';
- default = {};
+ default = { };
example = {
recPriority = 20;
conflictPriority = 10;
};
- type = types.submodule {
- freeformType = settingsFmt.type;
+ type = lib.types.submodule {
+ freeformType = yaml.type;
- options.readOnlyOnce = mkOption {
- type = types.bool;
- default = false;
- description = "Don't reload configuration files at runtime.";
+ options.port = lib.mkOption {
+ type = lib.types.port;
+ default = 20772;
+ description = ''
+ HTTP port for EPGStation to listen on.
+ '';
};
- options.mirakurunPath = mkOption (let
- sockPath = config.services.mirakurun.unixSocket;
- in {
- type = types.str;
- default = "http+unix://${replaceStrings ["/"] ["%2F"] sockPath}";
- defaultText = literalExpression ''
- "http+unix://''${replaceStrings ["/"] ["%2F"] config.${options.services.mirakurun.unixSocket}}"
+ options.socketioPort = lib.mkOption {
+ type = lib.types.port;
+ default = cfg.settings.port + 1;
+ defaultText = lib.literalExpression "config.${opt.settings}.port + 1";
+ description = ''
+ Socket.io port for EPGStation to listen on. It is valid to share
+ ports with .
+ '';
+ };
+
+ options.clientSocketioPort = lib.mkOption {
+ type = lib.types.port;
+ default = cfg.settings.socketioPort;
+ defaultText = lib.literalExpression "config.${opt.settings}.socketioPort";
+ description = ''
+ Socket.io port that the web client is going to connect to. This may
+ be different from if
+ EPGStation is hidden behind a reverse proxy.
+ '';
+ };
+
+ options.mirakurunPath = with mirakurun; lib.mkOption {
+ type = lib.types.str;
+ default = "http+unix://${lib.replaceStrings ["/"] ["%2F"] sock}";
+ defaultText = lib.literalExpression ''
+ "http+unix://''${lib.replaceStrings ["/"] ["%2F"] config.${option}}"
'';
example = "http://localhost:40772";
description = "URL to connect to Mirakurun.";
- });
+ };
- options.encode = mkOption {
- type = with types; listOf attrs;
+ options.encodeProcessNum = lib.mkOption {
+ type = lib.types.ints.positive;
+ default = 4;
+ description = ''
+ The maximum number of processes that EPGStation would allow to run
+ at the same time for encoding or streaming videos.
+ '';
+ };
+
+ options.concurrentEncodeNum = lib.mkOption {
+ type = lib.types.ints.positive;
+ default = 1;
+ description = ''
+ The maximum number of encoding jobs that EPGStation would run at the
+ same time.
+ '';
+ };
+
+ options.encode = lib.mkOption {
+ type = with lib.types; listOf attrs;
description = "Encoding presets for recorded videos.";
default = [
{
- name = "H264";
- cmd = "${pkgs.epgstation}/libexec/enc.sh main";
+ name = "H.264";
+ cmd = "%NODE% ${cfg.package}/libexec/enc.js";
suffix = ".mp4";
- default = true;
- }
- {
- name = "H264-sub";
- cmd = "${pkgs.epgstation}/libexec/enc.sh sub";
- suffix = "-sub.mp4";
}
];
- defaultText = literalExpression ''
+ defaultText = lib.literalExpression ''
[
{
- name = "H264";
- cmd = "''${pkgs.epgstation}/libexec/enc.sh main";
+ name = "H.264";
+ cmd = "%NODE% config.${opt.package}/libexec/enc.js";
suffix = ".mp4";
- default = true;
- }
- {
- name = "H264-sub";
- cmd = "''${pkgs.epgstation}/libexec/enc.sh sub";
- suffix = "-sub.mp4";
}
]
'';
@@ -229,14 +241,25 @@ in
};
};
- config = mkIf cfg.enable {
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = !(lib.hasAttr "readOnlyOnce" cfg.settings);
+ message = ''
+ The option config.${opt.settings}.readOnlyOnce can no longer be used
+ since it's been removed. No replacements are available.
+ '';
+ }
+ ];
+
environment.etc = {
- "epgstation/operatorLogConfig.json".text = builtins.toJSON logConfig;
- "epgstation/serviceLogConfig.json".text = builtins.toJSON logConfig;
+ "epgstation/epgUpdaterLogConfig.yml".source = logConfig;
+ "epgstation/operatorLogConfig.yml".source = logConfig;
+ "epgstation/serviceLogConfig.yml".source = logConfig;
};
- networking.firewall = mkIf cfg.openFirewall {
- allowedTCPPorts = with cfg; [ port socketioPort ];
+ networking.firewall = lib.mkIf cfg.openFirewall {
+ allowedTCPPorts = with cfg.settings; [ port socketioPort ];
};
users.users.epgstation = {
@@ -245,13 +268,13 @@ in
isSystemUser = true;
};
- users.groups.epgstation = {};
+ users.groups.epgstation = { };
- services.mirakurun.enable = mkDefault true;
+ services.mirakurun.enable = lib.mkDefault true;
services.mysql = {
- enable = mkDefault true;
- package = mkDefault pkgs.mariadb;
+ enable = lib.mkDefault true;
+ package = lib.mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.database.name ];
# FIXME: enable once mysqljs supports auth_socket
# ensureUsers = [ {
@@ -260,39 +283,28 @@ in
# } ];
};
- services.epgstation.settings = let
- defaultSettings = {
- serverPort = cfg.port;
- socketioPort = cfg.socketioPort;
- clientSocketioPort = cfg.clientSocketioPort;
+ services.epgstation.settings =
+ let
+ defaultSettings = {
+ dbtype = lib.mkDefault "mysql";
+ mysql = {
+ socketPath = lib.mkDefault "/run/mysqld/mysqld.sock";
+ user = username;
+ password = lib.mkDefault "@dbPassword@";
+ database = cfg.database.name;
+ };
- dbType = mkDefault "mysql";
- mysql = {
- user = username;
- database = cfg.database.name;
- socketPath = mkDefault "/run/mysqld/mysqld.sock";
- password = mkDefault "@dbPassword@";
- connectTimeout = mkDefault 1000;
- connectionLimit = mkDefault 10;
+ ffmpeg = lib.mkDefault "${pkgs.ffmpeg-full}/bin/ffmpeg";
+ ffprobe = lib.mkDefault "${pkgs.ffmpeg-full}/bin/ffprobe";
+
+ # for disambiguation with TypeScript files
+ recordedFileExtension = lib.mkDefault ".m2ts";
};
-
- basicAuth = mkIf (cfg.basicAuth.user != null) {
- user = mkDefault cfg.basicAuth.user;
- password = mkDefault "@password@";
- };
-
- ffmpeg = mkDefault "${pkgs.ffmpeg-full}/bin/ffmpeg";
- ffprobe = mkDefault "${pkgs.ffmpeg-full}/bin/ffprobe";
-
- fileExtension = mkDefault ".m2ts";
- maxEncode = mkDefault 2;
- maxStreaming = mkDefault 2;
- };
- in
- mkMerge [
- defaultSettings
- (mkIf cfg.usePreconfiguredStreaming streamingConfig)
- ];
+ in
+ lib.mkMerge [
+ defaultSettings
+ (lib.mkIf cfg.usePreconfiguredStreaming streamingConfig)
+ ];
systemd.tmpfiles.rules = [
"d '/var/lib/epgstation/streamfiles' - ${username} ${groupname} - -"
@@ -301,15 +313,15 @@ in
];
systemd.services.epgstation = {
- description = pkgs.epgstation.meta.description;
+ inherit description;
+
wantedBy = [ "multi-user.target" ];
- after = [
- "network.target"
- ] ++ optional config.services.mirakurun.enable "mirakurun.service"
- ++ optional config.services.mysql.enable "mysql.service";
+ after = [ "network.target" ]
+ ++ lib.optional config.services.mirakurun.enable "mirakurun.service"
+ ++ lib.optional config.services.mysql.enable "mysql.service";
serviceConfig = {
- ExecStart = "${pkgs.epgstation}/bin/epgstation start";
+ ExecStart = "${cfg.package}/bin/epgstation start";
ExecStartPre = "+${preStartScript}";
User = username;
Group = groupname;
diff --git a/nixos/modules/services/video/epgstation/streaming.json b/nixos/modules/services/video/epgstation/streaming.json
index 8eb99cf85584..7f8df0817fc3 100644
--- a/nixos/modules/services/video/epgstation/streaming.json
+++ b/nixos/modules/services/video/epgstation/streaming.json
@@ -1,119 +1,140 @@
{
- "liveHLS": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ "urlscheme": {
+ "m2ts": {
+ "ios": "vlc-x-callback://x-callback-url/stream?url=PROTOCOL://ADDRESS",
+ "android": "intent://ADDRESS#Intent;package=org.videolan.vlc;type=video;scheme=PROTOCOL;end"
},
- {
- "name": "480p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ "video": {
+ "ios": "infuse://x-callback-url/play?url=PROTOCOL://ADDRESS",
+ "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=PROTOCOL;end"
},
- {
- "name": "180p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%"
+ "download": {
+ "ios": "vlc-x-callback://x-callback-url/download?url=PROTOCOL://ADDRESS&filename=FILENAME"
}
- ],
- "liveMP4": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
- },
- {
- "name": "480p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
- }
- ],
- "liveWebM": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
- },
- {
- "name": "480p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
- }
- ],
- "mpegTsStreaming": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1"
- },
- {
- "name": "480p",
- "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1"
- },
- {
- "name": "Original"
- }
- ],
- "mpegTsViewer": {
- "ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS",
- "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end"
},
- "recordedDownloader": {
- "ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME",
- "android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end"
- },
- "recordedStreaming": {
- "webm": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
- "vb": "3000k",
- "ab": "192k"
- },
- {
- "name": "360p",
- "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
- "vb": "1500k",
- "ab": "128k"
+ "stream": {
+ "live": {
+ "ts": {
+ "m2ts": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1"
+ },
+ {
+ "name": "無変換"
+ }
+ ],
+ "m2tsll": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1 -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1 -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1"
+ }
+ ],
+ "webm": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
+ }
+ ],
+ "mp4": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
+ }
+ ],
+ "hls": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ }
+ ]
}
- ],
- "mp4": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
- "vb": "3000k",
- "ab": "192k"
- },
- {
- "name": "360p",
- "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
- "vb": "1500k",
- "ab": "128k"
- }
- ],
- "mpegTs": [
- {
- "name": "720p (H.264)",
- "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
- "vb": "3000k",
- "ab": "192k"
- },
- {
- "name": "360p (H.264)",
- "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
- "vb": "1500k",
- "ab": "128k"
- }
- ]
- },
- "recordedHLS": [
- {
- "name": "720p",
- "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
},
- {
- "name": "480p",
- "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%"
- },
- {
- "name": "480p(h265)",
- "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%"
+ "recorded": {
+ "ts": {
+ "webm": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
+ }
+ ],
+ "mp4": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
+ }
+ ],
+ "hls": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ }
+ ]
+ },
+ "encoded": {
+ "webm": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1"
+ }
+ ],
+ "mp4": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1"
+ }
+ ],
+ "hls": [
+ {
+ "name": "720p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ },
+ {
+ "name": "480p",
+ "cmd": "%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%"
+ }
+ ]
+ }
}
- ],
- "recordedViewer": {
- "ios": "infuse://x-callback-url/play?url=http://ADDRESS",
- "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end"
}
}
diff --git a/nixos/modules/services/video/unifi-video.nix b/nixos/modules/services/video/unifi-video.nix
index 43208a9fe4cf..11d9fe305470 100644
--- a/nixos/modules/services/video/unifi-video.nix
+++ b/nixos/modules/services/video/unifi-video.nix
@@ -16,7 +16,7 @@ let
-pidfile ${cfg.pidFile} \
-procname unifi-video \
-Djava.security.egd=file:/dev/./urandom \
- -Xmx${cfg.maximumJavaHeapSize}M \
+ -Xmx${toString cfg.maximumJavaHeapSize}M \
-Xss512K \
-XX:+UseG1GC \
-XX:+UseStringDeduplication \
@@ -91,98 +91,102 @@ let
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.
- '';
- };
+ options.services.unifi-video = {
- jrePackage = mkOption {
- type = types.package;
- default = pkgs.jre8;
- defaultText = literalExpression "pkgs.jre8";
- description = ''
- The JRE package to use. Check the release notes to ensure it is supported.
- '';
- };
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether or not to enable the unifi-video service.
+ '';
+ };
- unifiVideoPackage = mkOption {
- type = types.package;
- default = pkgs.unifi-video;
- defaultText = literalExpression "pkgs.unifi-video";
- description = ''
- The unifi-video package to use.
- '';
- };
+ jrePackage = mkOption {
+ type = types.package;
+ default = pkgs.jre8;
+ defaultText = literalExpression "pkgs.jre8";
+ description = ''
+ The JRE package to use. Check the release notes to ensure it is supported.
+ '';
+ };
- mongodbPackage = mkOption {
- type = types.package;
- default = pkgs.mongodb-4_0;
- defaultText = literalExpression "pkgs.mongodb";
- description = ''
- The mongodb package to use.
- '';
- };
+ unifiVideoPackage = mkOption {
+ type = types.package;
+ default = pkgs.unifi-video;
+ defaultText = literalExpression "pkgs.unifi-video";
+ description = ''
+ The unifi-video package to use.
+ '';
+ };
- logDir = mkOption {
- type = types.str;
- default = "${stateDir}/logs";
- description = ''
- Where to store the logs.
- '';
- };
+ mongodbPackage = mkOption {
+ type = types.package;
+ default = pkgs.mongodb-4_0;
+ defaultText = literalExpression "pkgs.mongodb";
+ description = ''
+ The mongodb package to use.
+ '';
+ };
- dataDir = mkOption {
- type = types.str;
- default = "${stateDir}/data";
- description = ''
- Where to store the database and other data.
- '';
- };
+ logDir = mkOption {
+ type = types.str;
+ default = "${stateDir}/logs";
+ description = ''
+ Where to store the logs.
+ '';
+ };
- openPorts = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether or not to open the required ports on the firewall.
- '';
- };
+ dataDir = mkOption {
+ type = types.str;
+ default = "${stateDir}/data";
+ description = ''
+ Where to store the database and other data.
+ '';
+ };
- maximumJavaHeapSize = mkOption {
- type = types.nullOr types.int;
- default = 1024;
- example = 4096;
- description = ''
- Set the maximimum heap size for the JVM in MB.
- '';
- };
+ openFirewall = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether or not to open the required ports on the firewall.
+ '';
+ };
- 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.";
- };
+ maximumJavaHeapSize = mkOption {
+ type = types.nullOr types.int;
+ default = 1024;
+ example = 4096;
+ description = ''
+ Set the maximimum 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 {
- users = {
- users.unifi-video = {
+ };
+
+ 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;
};
- groups.unifi-video = {};
- };
+ users.groups.unifi-video = {};
- networking.firewall = mkIf cfg.openPorts {
+ networking.firewall = mkIf cfg.openFirewall {
# https://help.ui.com/hc/en-us/articles/217875218-UniFi-Video-Ports-Used
allowedTCPPorts = [
7080 # HTTP portal
@@ -237,7 +241,6 @@ config = mkIf cfg.enable {
"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 = {
@@ -258,10 +261,11 @@ config = mkIf cfg.enable {
WorkingDirectory = "${stateDir}";
};
};
-
};
- meta = {
- maintainers = with lib.maintainers; [ rsynnest ];
- };
+ imports = [
+ (mkRenamedOptionModule [ "services" "unifi-video" "openPorts" ] [ "services" "unifi-video" "openFirewall" ])
+ ];
+
+ meta.maintainers = with lib.maintainers; [ rsynnest ];
}
diff --git a/nixos/modules/services/wayland/cage.nix b/nixos/modules/services/wayland/cage.nix
index d2bbc4fc057b..a32b81a916fc 100644
--- a/nixos/modules/services/wayland/cage.nix
+++ b/nixos/modules/services/wayland/cage.nix
@@ -81,6 +81,8 @@ in {
};
};
+ security.polkit.enable = true;
+
security.pam.services.cage.text = ''
auth required pam_unix.so nullok
account required pam_unix.so
diff --git a/nixos/modules/services/web-apps/bookstack.nix b/nixos/modules/services/web-apps/bookstack.nix
index 54eaea63b6eb..64a2767fab6e 100644
--- a/nixos/modules/services/web-apps/bookstack.nix
+++ b/nixos/modules/services/web-apps/bookstack.nix
@@ -385,13 +385,13 @@ in {
else if isString v then v
else if true == v then "true"
else if false == v then "false"
- else if isSecret v then v._secret
+ else if isSecret v then hashString "sha256" v._secret
else throw "unsupported type ${typeOf v}: ${(lib.generators.toPretty {}) v}";
};
};
secretPaths = lib.mapAttrsToList (_: v: v._secret) (lib.filterAttrs (_: isSecret) cfg.config);
mkSecretReplacement = file: ''
- replace-secret ${escapeShellArgs [ file file "${cfg.dataDir}/.env" ]}
+ replace-secret ${escapeShellArgs [ (builtins.hashString "sha256" file) file "${cfg.dataDir}/.env" ]}
'';
secretReplacements = lib.concatMapStrings mkSecretReplacement secretPaths;
filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! elem v [ {} null ])) cfg.config;
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix
index 30913ced8849..1f8ca742db95 100644
--- a/nixos/modules/services/web-apps/dokuwiki.nix
+++ b/nixos/modules/services/web-apps/dokuwiki.nix
@@ -376,7 +376,7 @@ in
"~ \\.php$" = {
extraConfig = ''
try_files $uri $uri/ /doku.php;
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param REDIRECT_STATUS 200;
fastcgi_pass unix:${config.services.phpfpm.pools."dokuwiki-${hostName}".socket};
diff --git a/nixos/modules/services/web-apps/ethercalc.nix b/nixos/modules/services/web-apps/ethercalc.nix
new file mode 100644
index 000000000000..d74def59c6c3
--- /dev/null
+++ b/nixos/modules/services/web-apps/ethercalc.nix
@@ -0,0 +1,62 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.ethercalc;
+in {
+ options = {
+ services.ethercalc = {
+ enable = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ ethercalc, an online collaborative spreadsheet server.
+
+ Persistent state will be maintained under
+ /var/lib/ethercalc. Upstream supports using a
+ redis server for storage and recommends the redis backend for
+ intensive use; however, the Nix module doesn't currently support
+ redis.
+
+ Note that while ethercalc is a good and robust project with an active
+ issue tracker, there haven't been new commits since the end of 2020.
+ '';
+ };
+
+ package = mkOption {
+ default = pkgs.ethercalc;
+ defaultText = literalExpression "pkgs.ethercalc";
+ type = types.package;
+ description = "Ethercalc package to use.";
+ };
+
+ host = mkOption {
+ type = types.str;
+ default = "0.0.0.0";
+ description = "Address to listen on (use 0.0.0.0 to allow access from any address).";
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 8000;
+ description = "Port to bind to.";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.ethercalc = {
+ description = "Ethercalc service";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ serviceConfig = {
+ DynamicUser = true;
+ ExecStart = "${cfg.package}/bin/ethercalc --host ${cfg.host} --port ${toString cfg.port}";
+ Restart = "always";
+ StateDirectory = "ethercalc";
+ WorkingDirectory = "/var/lib/ethercalc";
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/web-apps/jirafeau.nix b/nixos/modules/services/web-apps/jirafeau.nix
index a95e2b4f82a9..328c61c8e646 100644
--- a/nixos/modules/services/web-apps/jirafeau.nix
+++ b/nixos/modules/services/web-apps/jirafeau.nix
@@ -136,7 +136,7 @@ in
'';
locations = {
"~ \\.php$".extraConfig = ''
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_index index.php;
fastcgi_pass unix:${config.services.phpfpm.pools.jirafeau.socket};
diff --git a/nixos/modules/services/web-apps/keycloak.nix b/nixos/modules/services/web-apps/keycloak.nix
index a01f0049b2c7..c4a2127663a9 100644
--- a/nixos/modules/services/web-apps/keycloak.nix
+++ b/nixos/modules/services/web-apps/keycloak.nix
@@ -129,6 +129,14 @@ in
'';
};
+ plugins = lib.mkOption {
+ type = lib.types.listOf lib.types.path;
+ default = [];
+ description = ''
+ Keycloak plugin jar, ear files or derivations with them
+ '';
+ };
+
database = {
type = mkOption {
type = enum [ "mysql" "postgresql" ];
@@ -693,6 +701,7 @@ in
RemainAfterExit = true;
User = "postgres";
Group = "postgres";
+ LoadCredential = [ "db_password:${cfg.database.passwordFile}" ];
};
script = ''
set -o errexit -o pipefail -o nounset -o errtrace
@@ -701,7 +710,8 @@ in
create_role="$(mktemp)"
trap 'rm -f "$create_role"' ERR EXIT
- echo "CREATE ROLE keycloak WITH LOGIN PASSWORD '$(<'${cfg.database.passwordFile}')' CREATEDB" > "$create_role"
+ db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")"
+ echo "CREATE ROLE keycloak WITH LOGIN PASSWORD '$db_password' CREATEDB" > "$create_role"
psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='keycloak'" | grep -q 1 || psql -tA --file="$create_role"
psql -tAc "SELECT 1 FROM pg_database WHERE datname = 'keycloak'" | grep -q 1 || psql -tAc 'CREATE DATABASE "keycloak" OWNER "keycloak"'
'';
@@ -717,14 +727,14 @@ in
RemainAfterExit = true;
User = config.services.mysql.user;
Group = config.services.mysql.group;
+ LoadCredential = [ "db_password:${cfg.database.passwordFile}" ];
};
script = ''
set -o errexit -o pipefail -o nounset -o errtrace
shopt -s inherit_errexit
-
- db_password="$(<'${cfg.database.passwordFile}')"
+ db_password="$(<"$CREDENTIALS_DIRECTORY/db_password")"
( echo "CREATE USER IF NOT EXISTS 'keycloak'@'localhost' IDENTIFIED BY '$db_password';"
- echo "CREATE DATABASE keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;"
+ echo "CREATE DATABASE IF NOT EXISTS keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;"
echo "GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';"
) | mysql -N
'';
@@ -785,6 +795,14 @@ in
umask u=rwx,g=,o=
+ install_plugin() {
+ if [ -d "$1" ]; then
+ find "$1" -type f \( -iname \*.ear -o -iname \*.jar \) -exec install -m 0500 -o keycloak -g keycloak "{}" "/run/keycloak/deployments/" \;
+ else
+ install -m 0500 -o keycloak -g keycloak "$1" "/run/keycloak/deployments/"
+ fi
+ }
+
install -m 0600 ${cfg.package}/standalone/configuration/*.properties /run/keycloak/configuration
install -T -m 0600 ${keycloakConfig} /run/keycloak/configuration/standalone.xml
@@ -792,7 +810,9 @@ in
export JAVA_OPTS=-Djboss.server.config.user.dir=/run/keycloak/configuration
add-user-keycloak.sh -u admin -p '${cfg.initialAdminPassword}'
- '' + optionalString (cfg.sslCertificate != null && cfg.sslCertificateKey != null) ''
+ ''
+ + lib.optionalString (cfg.plugins != []) (lib.concatStringsSep "\n" (map (pl: "install_plugin ${lib.escapeShellArg pl}") cfg.plugins)) + "\n"
+ + optionalString (cfg.sslCertificate != null && cfg.sslCertificateKey != null) ''
pushd /run/keycloak/ssl/
cat "$CREDENTIALS_DIRECTORY/ssl_cert" <(echo) \
"$CREDENTIALS_DIRECTORY/ssl_key" <(echo) \
diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix
index 1e3c7e53c175..8208c85bfd70 100644
--- a/nixos/modules/services/web-apps/mastodon.nix
+++ b/nixos/modules/services/web-apps/mastodon.nix
@@ -92,6 +92,7 @@ let
mastodonEnv = pkgs.writeShellScriptBin "mastodon-env" ''
set -a
+ export RAILS_ROOT="${cfg.package}"
source "${envFile}"
source /var/lib/mastodon/.secrets_env
eval -- "\$@"
diff --git a/nixos/modules/services/web-apps/matomo.nix b/nixos/modules/services/web-apps/matomo.nix
index 8a0ca33b51f0..c6d4ed6d39de 100644
--- a/nixos/modules/services/web-apps/matomo.nix
+++ b/nixos/modules/services/web-apps/matomo.nix
@@ -192,6 +192,7 @@ in {
# Copy config folder
chmod g+s "${dataDir}"
cp -r "${cfg.package}/share/config" "${dataDir}/"
+ mkdir -p "${dataDir}/misc"
chmod -R u+rwX,g+rwX,o-rwx "${dataDir}"
# check whether user setup has already been done
diff --git a/nixos/modules/services/web-apps/miniflux.nix b/nixos/modules/services/web-apps/miniflux.nix
index 026bde2a92df..641c9be85d8c 100644
--- a/nixos/modules/services/web-apps/miniflux.nix
+++ b/nixos/modules/services/web-apps/miniflux.nix
@@ -4,34 +4,22 @@ with lib;
let
cfg = config.services.miniflux;
- dbUser = "miniflux";
- dbPassword = "miniflux";
- dbHost = "localhost";
- dbName = "miniflux";
+ defaultAddress = "localhost:8080";
- defaultCredentials = pkgs.writeText "miniflux-admin-credentials" ''
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=password
- '';
+ dbUser = "miniflux";
+ dbName = "miniflux";
pgbin = "${config.services.postgresql.package}/bin";
preStart = pkgs.writeScript "miniflux-pre-start" ''
#!${pkgs.runtimeShell}
- db_exists() {
- [ "$(${pgbin}/psql -Atc "select 1 from pg_database where datname='$1'")" == "1" ]
- }
- if ! db_exists "${dbName}"; then
- ${pgbin}/psql postgres -c "CREATE ROLE ${dbUser} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${dbPassword}'"
- ${pgbin}/createdb --owner "${dbUser}" "${dbName}"
- ${pgbin}/psql "${dbName}" -c "CREATE EXTENSION IF NOT EXISTS hstore"
- fi
+ ${pgbin}/psql "${dbName}" -c "CREATE EXTENSION IF NOT EXISTS hstore"
'';
in
{
options = {
services.miniflux = {
- enable = mkEnableOption "miniflux";
+ enable = mkEnableOption "miniflux and creates a local postgres database for it";
config = mkOption {
type = types.attrsOf types.str;
@@ -45,15 +33,17 @@ in
Configuration for Miniflux, refer to
for documentation on the supported values.
+
+ Correct configuration for the database is already provided.
+ By default, listens on ${defaultAddress}.
'';
};
adminCredentialsFile = mkOption {
- type = types.nullOr types.path;
- default = null;
+ type = types.path;
description = ''
- File containing the ADMIN_USERNAME, default is "admin", and
- ADMIN_PASSWORD (length >= 6), default is "password"; in the format of
+ File containing the ADMIN_USERNAME and
+ ADMIN_PASSWORD (length >= 6) in the format of
an EnvironmentFile=, as described by systemd.exec(5).
'';
example = "/etc/nixos/miniflux-admin-credentials";
@@ -64,17 +54,25 @@ in
config = mkIf cfg.enable {
services.miniflux.config = {
- LISTEN_ADDR = mkDefault "localhost:8080";
- DATABASE_URL = "postgresql://${dbUser}:${dbPassword}@${dbHost}/${dbName}?sslmode=disable";
+ LISTEN_ADDR = mkDefault defaultAddress;
+ DATABASE_URL = "user=${dbUser} host=/run/postgresql dbname=${dbName}";
RUN_MIGRATIONS = "1";
CREATE_ADMIN = "1";
};
- services.postgresql.enable = true;
+ services.postgresql = {
+ enable = true;
+ ensureUsers = [ {
+ name = dbUser;
+ ensurePermissions = {
+ "DATABASE ${dbName}" = "ALL PRIVILEGES";
+ };
+ } ];
+ ensureDatabases = [ dbName ];
+ };
systemd.services.miniflux-dbsetup = {
description = "Miniflux database setup";
- wantedBy = [ "multi-user.target" ];
requires = [ "postgresql.service" ];
after = [ "network.target" "postgresql.service" ];
serviceConfig = {
@@ -87,17 +85,16 @@ in
systemd.services.miniflux = {
description = "Miniflux service";
wantedBy = [ "multi-user.target" ];
- requires = [ "postgresql.service" ];
+ requires = [ "miniflux-dbsetup.service" ];
after = [ "network.target" "postgresql.service" "miniflux-dbsetup.service" ];
serviceConfig = {
ExecStart = "${pkgs.miniflux}/bin/miniflux";
+ User = dbUser;
DynamicUser = true;
RuntimeDirectory = "miniflux";
RuntimeDirectoryMode = "0700";
- EnvironmentFile = if cfg.adminCredentialsFile == null
- then defaultCredentials
- else cfg.adminCredentialsFile;
+ EnvironmentFile = cfg.adminCredentialsFile;
# Hardening
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "" ];
@@ -114,7 +111,7 @@ in
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
- RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix
index 739ba1ea12f6..b32220a5e579 100644
--- a/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixos/modules/services/web-apps/nextcloud.nix
@@ -153,7 +153,7 @@ in {
package = mkOption {
type = types.package;
description = "Which package to use for the Nextcloud instance.";
- relatedPackages = [ "nextcloud21" "nextcloud22" "nextcloud23" ];
+ relatedPackages = [ "nextcloud22" "nextcloud23" ];
};
phpPackage = mkOption {
type = types.package;
@@ -571,15 +571,6 @@ in {
nextcloud defined in an overlay, please set `services.nextcloud.package` to
`pkgs.nextcloud`.
''
- # 21.03 will not be an official release - it was instead 21.05.
- # This versionOlder statement remains set to 21.03 for backwards compatibility.
- # See https://github.com/NixOS/nixpkgs/pull/108899 and
- # https://github.com/NixOS/rfcs/blob/master/rfcs/0080-nixos-release-schedule.md.
- # FIXME(@Ma27) remove this else-if as soon as 21.05 is EOL! This is only here
- # to ensure that users who are on Nextcloud 19 with a stateVersion <21.05 with
- # no explicit services.nextcloud.package don't upgrade to v21 by accident (
- # nextcloud20 throws an eval-error because it's dropped).
- else if versionOlder stateVersion "21.03" then nextcloud20
else if versionOlder stateVersion "21.11" then nextcloud21
else if versionOlder stateVersion "22.05" then nextcloud22
else nextcloud23
@@ -599,6 +590,8 @@ in {
timerConfig.Unit = "nextcloud-cron.service";
};
+ systemd.tmpfiles.rules = ["d ${cfg.home} 0750 nextcloud nextcloud"];
+
systemd.services = {
# When upgrading the Nextcloud package, Nextcloud can report errors such as
# "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly"
@@ -720,8 +713,6 @@ in {
before = [ "phpfpm-nextcloud.service" ];
path = [ occ ];
script = ''
- chmod og+x ${cfg.home}
-
${optionalString (c.dbpassFile != null) ''
if [ ! -r "${c.dbpassFile}" ]; then
echo "dbpassFile ${c.dbpassFile} is not readable by nextcloud:nextcloud! Aborting..."
@@ -814,7 +805,6 @@ in {
users.users.nextcloud = {
home = "${cfg.home}";
group = "nextcloud";
- createHome = true;
isSystemUser = true;
};
users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ];
diff --git a/nixos/modules/services/web-apps/peertube.nix b/nixos/modules/services/web-apps/peertube.nix
index a65428018260..e195e6e6e824 100644
--- a/nixos/modules/services/web-apps/peertube.nix
+++ b/nixos/modules/services/web-apps/peertube.nix
@@ -320,6 +320,7 @@ in {
};
storage = {
tmp = lib.mkDefault "/var/lib/peertube/storage/tmp/";
+ bin = lib.mkDefault "/var/lib/peertube/storage/bin/";
avatars = lib.mkDefault "/var/lib/peertube/storage/avatars/";
videos = lib.mkDefault "/var/lib/peertube/storage/videos/";
streaming_playlists = lib.mkDefault "/var/lib/peertube/storage/streaming-playlists/";
@@ -333,6 +334,15 @@ in {
plugins = lib.mkDefault "/var/lib/peertube/storage/plugins/";
client_overrides = lib.mkDefault "/var/lib/peertube/storage/client-overrides/";
};
+ import = {
+ videos = {
+ http = {
+ youtube_dl_release = {
+ python_path = "${pkgs.python3}/bin/python";
+ };
+ };
+ };
+ };
}
(lib.mkIf cfg.redis.enableUnixSocket { redis = { socket = "/run/redis/redis.sock"; }; })
];
@@ -380,7 +390,7 @@ in {
environment = env;
- path = with pkgs; [ bashInteractive ffmpeg nodejs-16_x openssl yarn youtube-dl ];
+ path = with pkgs; [ bashInteractive ffmpeg nodejs-16_x openssl yarn python3 ];
script = ''
#!/bin/sh
diff --git a/nixos/modules/services/web-apps/plantuml-server.nix b/nixos/modules/services/web-apps/plantuml-server.nix
index f4bf43f56b98..9ea37b8a4cad 100644
--- a/nixos/modules/services/web-apps/plantuml-server.nix
+++ b/nixos/modules/services/web-apps/plantuml-server.nix
@@ -20,6 +20,21 @@ in
description = "PlantUML server package to use";
};
+ packages = {
+ jdk = mkOption {
+ type = types.package;
+ default = pkgs.jdk;
+ defaultText = literalExpression "pkgs.jdk";
+ description = "JDK package to use for the server";
+ };
+ jetty = mkOption {
+ type = types.package;
+ default = pkgs.jetty;
+ defaultText = literalExpression "pkgs.jetty";
+ description = "Jetty package to use for the server";
+ };
+ };
+
user = mkOption {
type = types.str;
default = "plantuml";
@@ -105,10 +120,10 @@ in
ALLOW_PLANTUML_INCLUDE = if cfg.allowPlantumlInclude then "true" else "false";
};
script = ''
- ${pkgs.jre}/bin/java \
- -jar ${pkgs.jetty}/start.jar \
+ ${cfg.packages.jdk}/bin/java \
+ -jar ${cfg.packages.jetty}/start.jar \
--module=deploy,http,jsp \
- jetty.home=${pkgs.jetty} \
+ jetty.home=${cfg.packages.jetty} \
jetty.base=${cfg.package} \
jetty.http.host=${cfg.listenHost} \
jetty.http.port=${builtins.toString cfg.listenPort}
diff --git a/nixos/modules/services/web-apps/plausible.nix b/nixos/modules/services/web-apps/plausible.nix
index b6c48186a1d3..5d550ae5ca86 100644
--- a/nixos/modules/services/web-apps/plausible.nix
+++ b/nixos/modules/services/web-apps/plausible.nix
@@ -10,8 +10,7 @@ in {
enable = mkEnableOption "plausible";
releaseCookiePath = mkOption {
- default = null;
- type = with types; nullOr (either str path);
+ type = with types; either str path;
description = ''
The path to the file with release cookie. (used for remote connection to the running node).
'';
@@ -235,6 +234,8 @@ in {
script = ''
export CONFIG_DIR=$CREDENTIALS_DIRECTORY
+ export RELEASE_COOKIE="$(< $CREDENTIALS_DIRECTORY/RELEASE_COOKIE )"
+
# setup
${pkgs.plausible}/createdb.sh
${pkgs.plausible}/migrate.sh
@@ -243,10 +244,8 @@ in {
psql -d plausible <<< "UPDATE users SET email_verified=true;"
fi
''}
- ${optionalString (cfg.releaseCookiePath != null) ''
- export RELEASE_COOKIE="$(< $CREDENTIALS_DIRECTORY/RELEASE_COOKIE )"
- ''}
- plausible start
+
+ exec plausible start
'';
serviceConfig = {
@@ -257,8 +256,8 @@ in {
LoadCredential = [
"ADMIN_USER_PWD:${cfg.adminUser.passwordFile}"
"SECRET_KEY_BASE:${cfg.server.secretKeybaseFile}"
- ] ++ lib.optionals (cfg.mail.smtp.passwordFile != null) [ "SMTP_USER_PWD:${cfg.mail.smtp.passwordFile}"]
- ++ lib.optionals (cfg.releaseCookiePath != null) [ "RELEASE_COOKIE:${cfg.releaseCookiePath}"];
+ "RELEASE_COOKIE:${cfg.releaseCookiePath}"
+ ] ++ lib.optionals (cfg.mail.smtp.passwordFile != null) [ "SMTP_USER_PWD:${cfg.mail.smtp.passwordFile}"];
};
};
}
diff --git a/nixos/modules/services/web-apps/restya-board.nix b/nixos/modules/services/web-apps/restya-board.nix
index fd97ab76a5f6..4b36cc8754c6 100644
--- a/nixos/modules/services/web-apps/restya-board.nix
+++ b/nixos/modules/services/web-apps/restya-board.nix
@@ -235,7 +235,7 @@ in
locations."~ \\.php$" = {
tryFiles = "$uri =404";
extraConfig = ''
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_pass unix:${fpm.socket};
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
diff --git a/nixos/modules/services/web-apps/rss-bridge.nix b/nixos/modules/services/web-apps/rss-bridge.nix
index 456ca00416fe..f2b6d9559823 100644
--- a/nixos/modules/services/web-apps/rss-bridge.nix
+++ b/nixos/modules/services/web-apps/rss-bridge.nix
@@ -111,7 +111,7 @@ in
locations."~ ^/index.php(/|$)" = {
extraConfig = ''
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${config.services.phpfpm.pools.${cfg.pool}.socket};
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
diff --git a/nixos/modules/services/web-servers/agate.nix b/nixos/modules/services/web-servers/agate.nix
new file mode 100644
index 000000000000..3afdb561c0b0
--- /dev/null
+++ b/nixos/modules/services/web-servers/agate.nix
@@ -0,0 +1,148 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.agate;
+in
+{
+ options = {
+ services.agate = {
+ enable = mkEnableOption "Agate Server";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.agate;
+ defaultText = literalExpression "pkgs.agate";
+ description = "The package to use";
+ };
+
+ addresses = mkOption {
+ type = types.listOf types.str;
+ default = [ "0.0.0.0:1965" ];
+ description = ''
+ Addresses to listen on, IP:PORT, if you haven't disabled forwarding
+ only set IPv4.
+ '';
+ };
+
+ contentDir = mkOption {
+ default = "/var/lib/agate/content";
+ type = types.path;
+ description = "Root of the content directory.";
+ };
+
+ certificatesDir = mkOption {
+ default = "/var/lib/agate/certificates";
+ type = types.path;
+ description = "Root of the certificate directory.";
+ };
+
+ hostnames = mkOption {
+ default = [ ];
+ type = types.listOf types.str;
+ description = ''
+ Domain name of this Gemini server, enables checking hostname and port
+ in requests. (multiple occurences means basic vhosts)
+ '';
+ };
+
+ language = mkOption {
+ default = null;
+ type = types.nullOr types.str;
+ description = "RFC 4646 Language code for text/gemini documents.";
+ };
+
+ onlyTls_1_3 = mkOption {
+ default = false;
+ type = types.bool;
+ description = "Only use TLSv1.3 (default also allows TLSv1.2).";
+ };
+
+ extraArgs = mkOption {
+ type = types.listOf types.str;
+ default = [ "" ];
+ example = [ "--log-ip" ];
+ description = "Extra arguments to use running agate.";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ # available for generating certs by hand
+ # it can be a bit arduous with openssl
+ environment.systemPackages = [ cfg.package ];
+
+ systemd.services.agate = {
+ description = "Agate";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" "network-online.target" ];
+
+ script =
+ let
+ prefixKeyList = key: list: concatMap (v: [ key v ]) list;
+ addresses = prefixKeyList "--addr" cfg.addresses;
+ hostnames = prefixKeyList "--hostname" cfg.hostnames;
+ in
+ ''
+ exec ${cfg.package}/bin/agate ${
+ escapeShellArgs (
+ [
+ "--content" "${cfg.contentDir}"
+ "--certs" "${cfg.certificatesDir}"
+ ] ++
+ addresses ++
+ (optionals (cfg.hostnames != []) hostnames) ++
+ (optionals (cfg.language != null) [ "--lang" cfg.language ]) ++
+ (optionals cfg.onlyTls_1_3 [ "--only-tls13" ]) ++
+ (optionals (cfg.extraArgs != []) cfg.extraArgs)
+ )
+ }
+ '';
+
+ serviceConfig = {
+ Restart = "always";
+ RestartSec = "5s";
+ DynamicUser = true;
+ StateDirectory = "agate";
+
+ # Security options:
+ AmbientCapabilities = "";
+ CapabilityBoundingSet = "";
+
+ # ProtectClock= adds DeviceAllow=char-rtc r
+ DeviceAllow = "";
+
+ LockPersonality = true;
+
+ PrivateTmp = true;
+ PrivateDevices = true;
+ PrivateUsers = true;
+
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+
+ RestrictNamespaces = true;
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+ RestrictRealtime = true;
+
+ SystemCallArchitectures = "native";
+ SystemCallErrorNumber = "EPERM";
+ SystemCallFilter = [
+ "@system-service"
+ "~@cpu-emulation"
+ "~@debug"
+ "~@keyring"
+ "~@memlock"
+ "~@obsolete"
+ "~@privileged"
+ "~@setuid"
+ ];
+ };
+ };
+ };
+}
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index a8610047f5f3..e046c28dd6bb 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -924,7 +924,8 @@ in
PrivateMounts = true;
# System Call Filtering
SystemCallArchitectures = "native";
- SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid @mincore" ] ++ optionals (cfg.package != pkgs.tengine) [ "~@ipc" ];
+ SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" ]
+ ++ optionals ((cfg.package != pkgs.tengine) && (!lib.any (mod: (mod.disableIPC or false)) cfg.package.modules)) [ "~@ipc" ];
};
};
@@ -988,5 +989,17 @@ in
nginx.gid = config.ids.gids.nginx;
};
+ services.logrotate.paths.nginx = mapAttrs (_: mkDefault) {
+ path = "/var/log/nginx/*.log";
+ frequency = "weekly";
+ keep = 26;
+ extraConfig = ''
+ compress
+ delaycompress
+ postrotate
+ [ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`
+ endscript
+ '';
+ };
};
}
diff --git a/nixos/modules/services/web-servers/nginx/gitweb.nix b/nixos/modules/services/web-servers/nginx/gitweb.nix
index 11bf2a309ea8..db45577a46d1 100644
--- a/nixos/modules/services/web-servers/nginx/gitweb.nix
+++ b/nixos/modules/services/web-servers/nginx/gitweb.nix
@@ -79,7 +79,7 @@ in
};
locations."${cfg.location}/" = {
extraConfig = ''
- include ${pkgs.nginx}/conf/fastcgi_params;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
fastcgi_param GITWEB_CONFIG ${gitwebConfig.gitwebConfigFile};
fastcgi_pass unix:/run/gitweb/gitweb.sock;
'';
diff --git a/nixos/modules/services/web-servers/pomerium.nix b/nixos/modules/services/web-servers/pomerium.nix
index 2bc7d01c7c28..0b460755f50e 100644
--- a/nixos/modules/services/web-servers/pomerium.nix
+++ b/nixos/modules/services/web-servers/pomerium.nix
@@ -69,11 +69,16 @@ in
CERTIFICATE_KEY_FILE = "key.pem";
};
startLimitIntervalSec = 60;
+ script = ''
+ if [[ -v CREDENTIALS_DIRECTORY ]]; then
+ cd "$CREDENTIALS_DIRECTORY"
+ fi
+ exec "${pkgs.pomerium}/bin/pomerium" -config "${cfgFile}"
+ '';
serviceConfig = {
DynamicUser = true;
StateDirectory = [ "pomerium" ];
- ExecStart = "${pkgs.pomerium}/bin/pomerium -config ${cfgFile}";
PrivateUsers = false; # breaks CAP_NET_BIND_SERVICE
MemoryDenyWriteExecute = false; # breaks LuaJIT
@@ -99,7 +104,6 @@ in
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
- WorkingDirectory = mkIf (cfg.useACMEHost != null) "$CREDENTIALS_DIRECTORY";
LoadCredential = optionals (cfg.useACMEHost != null) [
"fullchain.pem:/var/lib/acme/${cfg.useACMEHost}/fullchain.pem"
"key.pem:/var/lib/acme/${cfg.useACMEHost}/key.pem"
@@ -124,7 +128,7 @@ in
Type = "oneshot";
TimeoutSec = 60;
ExecCondition = "/run/current-system/systemd/bin/systemctl -q is-active pomerium.service";
- ExecStart = "/run/current-system/systemd/bin/systemctl restart pomerium.service";
+ ExecStart = "/run/current-system/systemd/bin/systemctl --no-block restart pomerium.service";
};
};
});
diff --git a/nixos/modules/services/web-servers/shellinabox.nix b/nixos/modules/services/web-servers/shellinabox.nix
deleted file mode 100644
index c7c51f873eba..000000000000
--- a/nixos/modules/services/web-servers/shellinabox.nix
+++ /dev/null
@@ -1,122 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
- cfg = config.services.shellinabox;
-
- # If a certificate file is specified, shellinaboxd requires
- # a file descriptor to retrieve it
- fd = "3";
- createFd = optionalString (cfg.certFile != null) "${fd}<${cfg.certFile}";
-
- # Command line arguments for the shellinabox daemon
- args = [ "--background" ]
- ++ optional (! cfg.enableSSL) "--disable-ssl"
- ++ optional (cfg.certFile != null) "--cert-fd=${fd}"
- ++ optional (cfg.certDirectory != null) "--cert=${cfg.certDirectory}"
- ++ cfg.extraOptions;
-
- # Command to start shellinaboxd
- cmd = "${pkgs.shellinabox}/bin/shellinaboxd ${concatStringsSep " " args}";
-
- # Command to start shellinaboxd if certFile is specified
- wrappedCmd = "${pkgs.bash}/bin/bash -c 'exec ${createFd} && ${cmd}'";
-
-in
-
-{
-
- ###### interface
-
- options = {
- services.shellinabox = {
- enable = mkEnableOption "shellinabox daemon";
-
- user = mkOption {
- type = types.str;
- default = "root";
- description = ''
- User to run shellinaboxd as. If started as root, the server drops
- privileges by changing to nobody, unless overridden by the
- --user option.
- '';
- };
-
- enableSSL = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether or not to enable SSL (https) support.
- '';
- };
-
- certDirectory = mkOption {
- type = types.nullOr types.path;
- default = null;
- example = "/var/certs";
- description = ''
- The daemon will look in this directory far any certificates.
- If the browser negotiated a Server Name Identification the daemon
- will look for a matching certificate-SERVERNAME.pem file. If no SNI
- handshake takes place, it will fall back on using the certificate in the
- certificate.pem file.
-
- If no suitable certificate is installed, shellinaboxd will attempt to
- create a new self-signed certificate. This will only succeed if, after
- dropping privileges, shellinaboxd has write permissions for this
- directory.
- '';
- };
-
- certFile = mkOption {
- type = types.nullOr types.path;
- default = null;
- example = "/var/certificate.pem";
- description = "Path to server SSL certificate.";
- };
-
- extraOptions = mkOption {
- type = types.listOf types.str;
- default = [ ];
- example = [ "--port=443" "--service /:LOGIN" ];
- description = ''
- A list of strings to be appended to the command line arguments
- for shellinaboxd. Please see the manual page
-
- for a full list of available arguments.
- '';
- };
-
- };
- };
-
- ###### implementation
-
- config = mkIf cfg.enable {
-
- assertions =
- [ { assertion = cfg.enableSSL == true
- -> cfg.certDirectory != null || cfg.certFile != null;
- message = "SSL is enabled for shellinabox, but no certDirectory or certFile has been specefied."; }
- { assertion = ! (cfg.certDirectory != null && cfg.certFile != null);
- message = "Cannot set both certDirectory and certFile for shellinabox."; }
- ];
-
- systemd.services.shellinaboxd = {
- description = "Shellinabox Web Server Daemon";
-
- wantedBy = [ "multi-user.target" ];
- requires = [ "sshd.service" ];
- after = [ "sshd.service" ];
-
- serviceConfig = {
- Type = "forking";
- User = "${cfg.user}";
- ExecStart = "${if cfg.certFile == null then "${cmd}" else "${wrappedCmd}"}";
- ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
- };
- };
- };
-}
diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix
index f9446fe125a3..877097cf3781 100644
--- a/nixos/modules/services/web-servers/tomcat.nix
+++ b/nixos/modules/services/web-servers/tomcat.nix
@@ -23,8 +23,8 @@ in
package = mkOption {
type = types.package;
- default = pkgs.tomcat85;
- defaultText = literalExpression "pkgs.tomcat85";
+ default = pkgs.tomcat9;
+ defaultText = literalExpression "pkgs.tomcat9";
example = lib.literalExpression "pkgs.tomcat9";
description = ''
Which tomcat package to use.
@@ -127,7 +127,7 @@ in
webapps = mkOption {
type = types.listOf types.path;
default = [ tomcat.webapps ];
- defaultText = literalExpression "[ pkgs.tomcat85.webapps ]";
+ defaultText = literalExpression "[ config.services.tomcat.package.webapps ]";
description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat";
};
@@ -201,6 +201,7 @@ in
{ uid = config.ids.uids.tomcat;
description = "Tomcat user";
home = "/homeless-shelter";
+ group = "tomcat";
extraGroups = cfg.extraGroups;
};
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 6ee5b0fc54f7..8247a7e381c9 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -19,7 +19,7 @@ in
# E.g., if Plasma 5 is enabled, it supersedes xterm.
imports = [
./none.nix ./xterm.nix ./xfce.nix ./plasma5.nix ./lumina.nix
- ./lxqt.nix ./enlightenment.nix ./gnome.nix ./kodi.nix
+ ./lxqt.nix ./enlightenment.nix ./gnome.nix ./retroarch.nix ./kodi.nix
./mate.nix ./pantheon.nix ./surf-display.nix ./cde.nix
./cinnamon.nix
];
diff --git a/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixos/modules/services/x11/desktop-managers/gnome.nix
index efc9bd39b366..f87258ac8dc5 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome.nix
@@ -132,6 +132,10 @@ in
[ "environment" "gnome3" "excludePackages" ]
[ "environment" "gnome" "excludePackages" ]
)
+ (mkRemovedOptionModule
+ [ "services" "gnome" "experimental-features" "realtime-scheduling" ]
+ "Set `security.rtkit.enable = true;` to make realtime scheduling possible. (Still needs to be enabled using GSettings.)"
+ )
];
options = {
@@ -142,38 +146,6 @@ in
core-utilities.enable = mkEnableOption "GNOME core utilities";
core-developer-tools.enable = mkEnableOption "GNOME core developer tools";
games.enable = mkEnableOption "GNOME games";
-
- experimental-features = {
- realtime-scheduling = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Makes mutter (which propagates to gnome-shell) request a low priority real-time
- scheduling which is only available on the wayland session.
- To enable this experimental feature it requires a restart of the compositor.
- Note that enabling this option only enables the capability
- for realtime-scheduling to be used. It doesn't automatically set the gsetting
- so that mutter actually uses realtime-scheduling. This would require adding
- rt-scheduler to /org/gnome/mutter/experimental-features
- with dconf-editor. You cannot use extraGSettingsOverrides because that will only
- change the default value of the setting.
-
- Please be aware of these known issues with the feature in nixos:
-
-
-
- NixOS/nixpkgs#90201
-
-
-
-
- NixOS/nixpkgs#86730
-
-
-
- '';
- };
- };
};
services.xserver.desktopManager.gnome = {
@@ -414,7 +386,6 @@ in
services.gnome.rygel.enable = mkDefault true;
services.gvfs.enable = true;
services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
- services.telepathy.enable = mkDefault true;
systemd.packages = with pkgs.gnome; [
gnome-session
@@ -480,29 +451,6 @@ in
];
})
- # Enable soft realtime scheduling, only supported on wayland
- (mkIf serviceCfg.experimental-features.realtime-scheduling {
- security.wrappers.".gnome-shell-wrapped" = {
- source = "${pkgs.gnome.gnome-shell}/bin/.gnome-shell-wrapped";
- owner = "root";
- group = "root";
- capabilities = "cap_sys_nice=ep";
- };
-
- systemd.user.services.gnome-shell-wayland = let
- gnomeShellRT = with pkgs.gnome; pkgs.runCommand "gnome-shell-rt" {} ''
- mkdir -p $out/bin/
- cp ${gnome-shell}/bin/gnome-shell $out/bin
- sed -i "s@${gnome-shell}/bin/@${config.security.wrapperDir}/@" $out/bin/gnome-shell
- '';
- in {
- # Note we need to clear ExecStart before overriding it
- serviceConfig.ExecStart = ["" "${gnomeShellRT}/bin/gnome-shell"];
- # Do not use the default environment, it provides a broken PATH
- environment = mkForce {};
- };
- })
-
# Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-utilities.bst
(mkIf serviceCfg.core-utilities.enable {
environment.systemPackages =
@@ -513,18 +461,18 @@ in
cheese
eog
epiphany
- gedit
+ pkgs.gnome-text-editor
gnome-calculator
gnome-calendar
gnome-characters
gnome-clocks
+ pkgs.gnome-console
gnome-contacts
gnome-font-viewer
gnome-logs
gnome-maps
gnome-music
pkgs.gnome-photos
- gnome-screenshot
gnome-system-monitor
gnome-weather
nautilus
@@ -547,10 +495,13 @@ in
programs.file-roller.enable = notExcluded pkgs.gnome.file-roller;
programs.geary.enable = notExcluded pkgs.gnome.geary;
programs.gnome-disks.enable = notExcluded pkgs.gnome.gnome-disk-utility;
- programs.gnome-terminal.enable = notExcluded pkgs.gnome.gnome-terminal;
programs.seahorse.enable = notExcluded pkgs.gnome.seahorse;
services.gnome.sushi.enable = notExcluded pkgs.gnome.sushi;
+ # VTE shell integration for gnome-console
+ programs.bash.vteIntegration = mkDefault true;
+ programs.zsh.vteIntegration = mkDefault true;
+
# Let nautilus find extensions
# TODO: Create nautilus-with-extensions package
environment.sessionVariables.NAUTILUS_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-3.0";
@@ -569,6 +520,7 @@ in
atomix
five-or-more
four-in-a-row
+ pkgs.gnome-2048
gnome-chess
gnome-klotski
gnome-mahjongg
diff --git a/nixos/modules/services/x11/desktop-managers/gnome.xml b/nixos/modules/services/x11/desktop-managers/gnome.xml
index e5da7740196e..807c9d64e204 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome.xml
+++ b/nixos/modules/services/x11/desktop-managers/gnome.xml
@@ -249,14 +249,5 @@ services.xserver.desktopManager.gnome = {
See this issue.
-
-
- Why does nixos-rebuild switch sometimes kill my session?
-
-
- This is a known issue without any workarounds.
- If you are doing a fairly large upgrade, it is probably safer to use nixos-rebuild boot.
-
-
diff --git a/nixos/modules/services/x11/desktop-managers/mate.nix b/nixos/modules/services/x11/desktop-managers/mate.nix
index f8f47a061452..a7fda4be9796 100644
--- a/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -74,11 +74,9 @@ in
# Debugging
environment.sessionVariables.MATE_SESSION_DEBUG = mkIf cfg.debug "1";
- environment.systemPackages =
- pkgs.mate.basePackages ++
- (pkgs.gnome.removePackagesByName
- pkgs.mate.extraPackages
- config.environment.mate.excludePackages) ++
+ environment.systemPackages = pkgs.gnome.removePackagesByName
+ (pkgs.mate.basePackages ++
+ pkgs.mate.extraPackages ++
[
pkgs.desktop-file-utils
pkgs.glib
@@ -87,7 +85,8 @@ in
pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
pkgs.mate.mate-settings-daemon
pkgs.yelp # for 'Contents' in 'Help' menus
- ];
+ ])
+ config.environment.mate.excludePackages;
programs.dconf.enable = true;
# Shell integration for VTE terminals
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 980a6b939d5a..48e119a86187 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -135,6 +135,7 @@ in
services.bamf.enable = true;
services.colord.enable = mkDefault true;
services.fwupd.enable = mkDefault true;
+ services.packagekit.enable = mkDefault true;
services.touchegg.enable = mkDefault true;
services.touchegg.package = pkgs.pantheon.touchegg;
services.tumbler.enable = mkDefault true;
@@ -219,14 +220,12 @@ in
] config.environment.pantheon.excludePackages);
programs.evince.enable = mkDefault true;
- programs.evince.package = pkgs.pantheon.evince;
programs.file-roller.enable = mkDefault true;
- programs.file-roller.package = pkgs.pantheon.file-roller;
# Settings from elementary-default-settings
- environment.sessionVariables.GTK_CSD = "1";
environment.etc."gtk-3.0/settings.ini".source = "${pkgs.pantheon.elementary-default-settings}/etc/gtk-3.0/settings.ini";
+ xdg.portal.enable = true;
xdg.portal.extraPortals = with pkgs.pantheon; [
elementary-files
elementary-settings-daemon
@@ -273,7 +272,7 @@ in
})
(mkIf serviceCfg.apps.enable {
- environment.systemPackages = (with pkgs.pantheon; pkgs.gnome.removePackagesByName [
+ environment.systemPackages = with pkgs.pantheon; pkgs.gnome.removePackagesByName ([
elementary-calculator
elementary-calendar
elementary-camera
@@ -287,7 +286,11 @@ in
elementary-terminal
elementary-videos
epiphany
- ] config.environment.pantheon.excludePackages);
+ ] ++ lib.optionals config.services.flatpak.enable [
+ # Only install appcenter if flatpak is enabled before
+ # https://github.com/NixOS/nixpkgs/issues/15932 is resolved.
+ appcenter
+ ]) config.environment.pantheon.excludePackages;
# needed by screenshot
fonts.fonts = [
@@ -299,7 +302,6 @@ in
environment.systemPackages = with pkgs.pantheon; [
contractor
file-roller-contract
- gnome-bluetooth-contract
];
environment.pathsToLink = [
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.xml b/nixos/modules/services/x11/desktop-managers/pantheon.xml
index fe0a1c496223..202909d398f0 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.xml
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.xml
@@ -105,10 +105,10 @@ switchboard-with-plugs.override {
- AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. Starting from 21.11, the Flatpak backend should work so you can install some Flatpak applications using it. See this issue.
+ AppCenter has been available since 20.03. Starting from 21.11, the Flatpak backend should work so you can install some Flatpak applications using it. However, due to missing appstream metadata, the Packagekit backend does not function currently. See this issue.
- To use AppCenter on NixOS, add pantheon.appcenter to , enable Flatpak support and optionally add the appcenter Flatpak remote:
+ If you are using Pantheon, AppCenter should be installed by default if you have Flatpak support enabled. If you also wish to add the appcenter Flatpak remote:
$ flatpak remote-add --if-not-exists appcenter https://flatpak.elementary.io/repo.flatpakrepo
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 9bacdaa9be98..3ca044ad5bc8 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -394,7 +394,8 @@ in
# Extra UDEV rules used by Solid
services.udev.packages = [
- pkgs.libmtp
+ # libmtp has "bin", "dev", "out" outputs. UDEV rules file is in "out".
+ pkgs.libmtp.out
pkgs.media-player-info
];
@@ -518,7 +519,7 @@ in
with plasma5; with kdeApplications; with kdeFrameworks;
[
# Basic packages without which Plasma Mobile fails to work properly.
- plasma-phone-components
+ plasma-mobile
plasma-nano
pkgs.maliit-framework
pkgs.maliit-keyboard
@@ -572,7 +573,7 @@ in
};
};
- services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-phone-components ];
+ services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-mobile ];
})
];
}
diff --git a/nixos/modules/services/x11/desktop-managers/retroarch.nix b/nixos/modules/services/x11/desktop-managers/retroarch.nix
new file mode 100644
index 000000000000..d471673d4521
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/retroarch.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.xserver.desktopManager.retroarch;
+
+in {
+ options.services.xserver.desktopManager.retroarch = {
+ enable = mkEnableOption "RetroArch";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.retroarch;
+ defaultText = literalExpression "pkgs.retroarch";
+ example = literalExpression "pkgs.retroarch-full";
+ description = "RetroArch package to use.";
+ };
+
+ extraArgs = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ example = [ "--verbose" "--host" ];
+ description = "Extra arguments to pass to RetroArch.";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.xserver.desktopManager.session = [{
+ name = "RetroArch";
+ start = ''
+ ${cfg.package}/bin/retroarch -f ${escapeShellArgs cfg.extraArgs} &
+ waitPID=$!
+ '';
+ }];
+
+ environment.systemPackages = [ cfg.package ];
+ };
+
+ meta.maintainers = with maintainers; [ j0hax ];
+}
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 92b3af8527f1..a5db3dd5dd45 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -219,6 +219,7 @@ in
session = mkOption {
default = [];
+ type = types.listOf types.attrs;
example = literalExpression
''
[ { manage = "desktop";
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 6f0d645725e9..70ae6b8978d0 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -53,6 +53,8 @@ in
"autoLogin"
"user"
])
+
+ (mkRemovedOptionModule [ "services" "xserver" "displayManager" "gdm" "nvidiaWayland" ] "We defer to GDM whether Wayland should be enabled.")
];
meta = {
@@ -83,17 +85,6 @@ in
default = true;
description = ''
Allow GDM to run on Wayland instead of Xserver.
- Note to enable Wayland with Nvidia the
- must not be disabled.
- '';
- };
-
- nvidiaWayland = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to allow wayland to be used with the proprietary
- NVidia graphics driver.
'';
};
@@ -149,7 +140,8 @@ in
environment = {
GDM_X_SERVER_EXTRA_ARGS = toString
(filter (arg: arg != "-terminate") cfg.xserverArgs);
- XDG_DATA_DIRS = "${cfg.sessionData.desktops}/share/";
+ # GDM is needed for gnome-login.session
+ XDG_DATA_DIRS = "${gdm}/share:${cfg.sessionData.desktops}/share:${pkgs.gnome.gnome-control-center}/share";
} // optionalAttrs (xSessionWrapper != null) {
# Make GDM use this wrapper before running the session, which runs the
# configured setupCommands. This relies on a patched GDM which supports
@@ -230,19 +222,6 @@ in
services.dbus.packages = [ gdm ];
- # We duplicate upstream's udev rules manually to make wayland with nvidia configurable
- services.udev.extraRules = ''
- # disable Wayland on Cirrus chipsets
- ATTR{vendor}=="0x1013", ATTR{device}=="0x00b8", ATTR{subsystem_vendor}=="0x1af4", ATTR{subsystem_device}=="0x1100", RUN+="${gdm}/libexec/gdm-runtime-config set daemon WaylandEnable false"
- # disable Wayland on Hi1710 chipsets
- ATTR{vendor}=="0x19e5", ATTR{device}=="0x1711", RUN+="${gdm}/libexec/gdm-runtime-config set daemon WaylandEnable false"
- ${optionalString (!cfg.gdm.nvidiaWayland) ''
- DRIVER=="nvidia", RUN+="${gdm}/libexec/gdm-runtime-config set daemon WaylandEnable false"
- ''}
- # disable Wayland when modesetting is disabled
- IMPORT{cmdline}="nomodeset", RUN+="${gdm}/libexec/gdm-runtime-config set daemon WaylandEnable false"
- '';
-
systemd.user.services.dbus.wantedBy = [ "default.target" ];
programs.dconf.profiles.gdm =
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 84b75c83aeab..27dfed3cc14c 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -267,6 +267,8 @@ in
# Enable the accounts daemon to find lightdm's dbus interface
environment.systemPackages = [ lightdm ];
+ security.polkit.enable = true;
+
security.pam.services.lightdm.text = ''
auth substack login
account include login
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index ec6d86d59bdf..0c50d82b23be 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -620,9 +620,6 @@ in
in optional (driver != null) ({ inherit name; modules = []; driverName = name; display = true; } // driver));
assertions = [
- { assertion = config.security.polkit.enable;
- message = "X11 requires Polkit to be enabled (‘security.polkit.enable = true’).";
- }
(let primaryHeads = filter (x: x.primary) cfg.xrandrHeads; in {
assertion = length primaryHeads < 2;
message = "Only one head is allowed to be primary in "
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
old mode 100644
new mode 100755
index 93fff889d6bc..9e5b760434a0
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -2,40 +2,63 @@
use strict;
use warnings;
+use Config::IniFiles;
use File::Path qw(make_path);
use File::Basename;
-use File::Slurp;
+use File::Slurp qw(read_file write_file edit_file);
use Net::DBus;
use Sys::Syslog qw(:standard :macros);
-use Cwd 'abs_path';
+use Cwd qw(abs_path);
+## no critic(ControlStructures::ProhibitDeepNests)
+## no critic(ErrorHandling::RequireCarping)
+## no critic(CodeLayout::ProhibitParensWithBuiltins)
+## no critic(Variables::ProhibitPunctuationVars, Variables::RequireLocalizedPunctuationVars)
+## no critic(InputOutput::RequireCheckedSyscalls, InputOutput::RequireBracedFileHandleWithPrint, InputOutput::RequireBriefOpen)
+## no critic(ValuesAndExpressions::ProhibitNoisyQuotes, ValuesAndExpressions::ProhibitMagicNumbers, ValuesAndExpressions::ProhibitEmptyQuotes, ValuesAndExpressions::ProhibitInterpolationOfLiterals)
+## no critic(RegularExpressions::ProhibitEscapedMetacharacters)
+
+# System closure path to switch to
my $out = "@out@";
-
-my $curSystemd = abs_path("/run/current-system/sw/bin");
+# Path to the directory containing systemd tools of the old system
+my $cur_systemd = abs_path("/run/current-system/sw/bin");
+# Path to the systemd store path of the new system
+my $new_systemd = "@systemd@";
# To be robust against interruption, record what units need to be started etc.
-my $startListFile = "/run/nixos/start-list";
-my $restartListFile = "/run/nixos/restart-list";
-my $reloadListFile = "/run/nixos/reload-list";
+# We read these files again every time this script starts to make sure we continue
+# where the old (interrupted) script left off.
+my $start_list_file = "/run/nixos/start-list";
+my $restart_list_file = "/run/nixos/restart-list";
+my $reload_list_file = "/run/nixos/reload-list";
# Parse restart/reload requests by the activation script.
-# Activation scripts may write newline-separated units to this
+# Activation scripts may write newline-separated units to the restart
# file and switch-to-configuration will handle them. While
# `stopIfChanged = true` is ignored, switch-to-configuration will
# handle `restartIfChanged = false` and `reloadIfChanged = true`.
-my $restartByActivationFile = "/run/nixos/activation-restart-list";
-my $dryRestartByActivationFile = "/run/nixos/dry-activation-restart-list";
+# This is the same as specifying a restart trigger in the NixOS module.
+#
+# The reload file asks the script to reload a unit. This is the same as
+# specifying a reload trigger in the NixOS module and can be ignored if
+# the unit is restarted in this activation.
+my $restart_by_activation_file = "/run/nixos/activation-restart-list";
+my $reload_by_activation_file = "/run/nixos/activation-reload-list";
+my $dry_restart_by_activation_file = "/run/nixos/dry-activation-restart-list";
+my $dry_reload_by_activation_file = "/run/nixos/dry-activation-reload-list";
-make_path("/run/nixos", { mode => oct(755) });
-
-my $action = shift @ARGV;
+# The action that is to be performed (like switch, boot, test, dry-activate)
+# Also exposed via environment variable from now on
+my $action = shift(@ARGV);
+$ENV{NIXOS_ACTION} = $action;
+# Expose the locale archive as an environment variable for systemctl and the activation script
if ("@localeArchive@" ne "") {
$ENV{LOCALE_ARCHIVE} = "@localeArchive@";
}
-if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) {
- print STDERR < 'quiet') // "") =~ /ID=nixos/s;
+if (!-f "/etc/NIXOS" && (read_file("/etc/os-release", err_mode => "quiet") // "") !~ /^ID="?nixos"?/msx) {
+ die("This is not a NixOS installation!\n");
+}
+make_path("/run/nixos", { mode => oct(755) });
openlog("nixos", "", LOG_USER);
# Install or update the bootloader.
if ($action eq "switch" || $action eq "boot") {
- system("@installBootLoader@ $out") == 0 or exit 1;
+ chomp(my $install_boot_loader = <<'EOFBOOTLOADER');
+@installBootLoader@
+EOFBOOTLOADER
+ system("$install_boot_loader $out") == 0 or exit 1;
}
# Just in case the new configuration hangs the system, do a sync now.
-system("@coreutils@/bin/sync", "-f", "/nix/store") unless ($ENV{"NIXOS_NO_SYNC"} // "") eq "1";
+if (($ENV{"NIXOS_NO_SYNC"} // "") ne "1") {
+ system("@coreutils@/bin/sync", "-f", "/nix/store");
+}
-exit 0 if $action eq "boot";
+if ($action eq "boot") {
+ exit(0);
+}
# Check if we can activate the new configuration.
-my $oldVersion = read_file("/run/current-system/init-interface-version", err_mode => 'quiet') // "";
-my $newVersion = read_file("$out/init-interface-version");
+my $cur_init_interface_version = read_file("/run/current-system/init-interface-version", err_mode => "quiet") // "";
+my $new_init_interface_version = read_file("$out/init-interface-version");
-if ($newVersion ne $oldVersion) {
- print STDERR <system->get_service("org.freedesktop.systemd1")->get_object("/org/freedesktop/systemd1");
my $units = $mgr->ListUnitsByPatterns([], []);
my $res = {};
- for my $item (@$units) {
+ for my $item (@{$units}) {
my ($id, $description, $load_state, $active_state, $sub_state,
- $following, $unit_path, $job_id, $job_type, $job_path) = @$item;
- next unless $following eq '';
- next if $job_id == 0 and $active_state eq 'inactive';
+ $following, $unit_path, $job_id, $job_type, $job_path) = @{$item};
+ if ($following ne "") {
+ next;
+ }
+ if ($job_id == 0 and $active_state eq "inactive") {
+ next;
+ }
$res->{$id} = { load => $load_state, state => $active_state, substate => $sub_state };
}
return $res;
}
-sub parseFstab {
+# Asks the currently running systemd instance whether a unit is currently active.
+# Takes the name of the unit as an argument and returns a bool whether the unit is active or not.
+sub unit_is_active {
+ my ($unit_name) = @_;
+
+ my $mgr = Net::DBus->system->get_service("org.freedesktop.systemd1")->get_object("/org/freedesktop/systemd1");
+ my $units = $mgr->ListUnitsByNames([$unit_name]);
+ if (scalar(@{$units}) == 0) {
+ return 0;
+ }
+ my $active_state = $units->[0]->[3];
+ return $active_state eq "active" || $active_state eq "activating";
+}
+
+# Parse a fstab file, given its path.
+# Returns a tuple of filesystems and swaps.
+#
+# Filesystems is a hash of mountpoint and { device, fsType, options }
+# Swaps is a hash of device and { options }
+sub parse_fstab {
my ($filename) = @_;
my ($fss, $swaps);
- foreach my $line (read_file($filename, err_mode => 'quiet')) {
- chomp $line;
- $line =~ s/^\s*#.*//;
- next if $line =~ /^\s*$/;
- my @xs = split / /, $line;
+ foreach my $line (read_file($filename, err_mode => "quiet")) {
+ chomp($line);
+ $line =~ s/^\s*\#.*//msx;
+ if ($line =~ /^\s*$/msx) {
+ next;
+ }
+ my @xs = split(/\s+/msx, $line);
if ($xs[2] eq "swap") {
$swaps->{$xs[0]} = { options => $xs[3] // "" };
} else {
@@ -113,94 +171,297 @@ sub parseFstab {
return ($fss, $swaps);
}
-sub parseUnit {
- my ($filename) = @_;
- my $info = {};
- parseKeyValues($info, read_file($filename)) if -f $filename;
- parseKeyValues($info, read_file("${filename}.d/overrides.conf")) if -f "${filename}.d/overrides.conf";
- return $info;
-}
+# This subroutine takes a single ini file that specified systemd configuration
+# like unit configuration and parses it into a hash where the keys are the sections
+# of the unit file and the values are hashes themselves. These hashes have the unit file
+# keys as their keys (left side of =) and an array of all values that were set as their
+# values. If a value is empty (for example `ExecStart=`), then all current definitions are
+# removed.
+#
+# Instead of returning the hash, this subroutine takes a hashref to return the data in. This
+# allows calling the subroutine multiple times with the same hash to parse override files.
+sub parse_systemd_ini {
+ my ($unit_contents, $path) = @_;
+ # Tie the ini file to a hash for easier access
+ tie(my %file_contents, "Config::IniFiles", (-file => $path, -allowempty => 1, -allowcontinue => 1)); ## no critic(Miscellanea::ProhibitTies)
-sub parseKeyValues {
- my $info = shift;
- foreach my $line (@_) {
- # FIXME: not quite correct.
- $line =~ /^([^=]+)=(.*)$/ or next;
- $info->{$1} = $2;
+ # Copy over all sections
+ foreach my $section_name (keys(%file_contents)) {
+ if ($section_name eq "Install") {
+ # Skip the [Install] section because it has no relevant keys for us
+ next;
+ }
+ # Copy over all keys
+ foreach my $ini_key (keys(%{$file_contents{$section_name}})) {
+ # Ensure the value is an array so it's easier to work with
+ my $ini_value = $file_contents{$section_name}{$ini_key};
+ my @ini_values;
+ if (ref($ini_value) eq "ARRAY") {
+ @ini_values = @{$ini_value};
+ } else {
+ @ini_values = $ini_value;
+ }
+ # Go over all values
+ for my $ini_value (@ini_values) {
+ # If a value is empty, it's an override that tells us to clean the value
+ if ($ini_value eq "") {
+ delete $unit_contents->{$section_name}->{$ini_key};
+ next;
+ }
+ push(@{$unit_contents->{$section_name}->{$ini_key}}, $ini_value);
+ }
+ }
}
+ return;
}
-sub boolIsTrue {
- my ($s) = @_;
- return $s eq "yes" || $s eq "true";
+# This subroutine takes the path to a systemd configuration file (like a unit configuration),
+# parses it, and returns a hash that contains the contents. The contents of this hash are
+# explained in the `parse_systemd_ini` subroutine. Neither the sections nor the keys inside
+# the sections are consistently sorted.
+#
+# If a directory with the same basename ending in .d exists next to the unit file, it will be
+# assumed to contain override files which will be parsed as well and handled properly.
+sub parse_unit {
+ my ($unit_path) = @_;
+
+ # Parse the main unit and all overrides
+ my %unit_data;
+ # Replace \ with \\ so glob() still works with units that have a \ in them
+ # Valid characters in unit names are ASCII letters, digits, ":", "-", "_", ".", and "\"
+ $unit_path =~ s/\\/\\\\/gmsx;
+ foreach (glob("${unit_path}{,.d/*.conf}")) {
+ parse_systemd_ini(\%unit_data, "$_")
+ }
+ return %unit_data;
}
-sub recordUnit {
+# Checks whether a specified boolean in a systemd unit is true
+# or false, with a default that is applied when the value is not set.
+sub parse_systemd_bool {
+ my ($unit_config, $section_name, $bool_name, $default) = @_;
+
+ my @values = @{$unit_config->{$section_name}{$bool_name} // []};
+ # Return default if value is not set
+ if ((scalar(@values) < 1) || (not defined($values[-1]))) {
+ return $default;
+ }
+ # If value is defined multiple times, use the last definition
+ my $last_value = $values[-1];
+ # These are valid values as of systemd.syntax(7)
+ return $last_value eq "1" || $last_value eq "yes" || $last_value eq "true" || $last_value eq "on";
+}
+
+# Writes a unit name into a given file to be more resilient against
+# crashes of the script. Does nothing when the action is dry-activate.
+sub record_unit {
my ($fn, $unit) = @_;
- write_file($fn, { append => 1 }, "$unit\n") if $action ne "dry-activate";
+ if ($action ne "dry-activate") {
+ write_file($fn, { append => 1 }, "$unit\n");
+ }
+ return;
}
-# As a fingerprint for determining whether a unit has changed, we use
-# its absolute path. If it has an override file, we append *its*
-# absolute path as well.
-sub fingerprintUnit {
- my ($s) = @_;
- return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
+# The opposite of record_unit, removes a unit name from a file
+sub unrecord_unit {
+ my ($fn, $unit) = @_;
+ if ($action ne "dry-activate") {
+ edit_file(sub { s/^$unit\n//msx }, $fn);
+ }
+ return;
}
-sub handleModifiedUnit {
- my ($unit, $baseName, $newUnitFile, $activePrev, $unitsToStop, $unitsToStart, $unitsToReload, $unitsToRestart, $unitsToSkip) = @_;
+# Compare the contents of two unit files and return whether the unit
+# needs to be restarted or reloaded. If the units differ, the service
+# is restarted unless the only difference is `X-Reload-Triggers` in the
+# `Unit` section. If this is the only modification, the unit is reloaded
+# instead of restarted.
+# Returns:
+# - 0 if the units are equal
+# - 1 if the units are different and a restart action is required
+# - 2 if the units are different and a reload action is required
+sub compare_units { ## no critic(Subroutines::ProhibitExcessComplexity)
+ my ($cur_unit, $new_unit) = @_;
+ my $ret = 0;
+ # Keys to ignore in the [Unit] section
+ my %unit_section_ignores = map { $_ => 1 } qw(
+ X-Reload-Triggers
+ Description Documentation
+ OnFailure OnSuccess OnFailureJobMode
+ IgnoreOnIsolate StopWhenUnneeded
+ RefuseManualStart RefuseManualStop
+ AllowIsolate CollectMode
+ SourcePath
+ );
- if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
+ my $comp_array = sub {
+ my ($a, $b) = @_;
+ return join("\0", @{$a}) eq join("\0", @{$b});
+ };
+
+ # Comparison hash for the sections
+ my %section_cmp = map { $_ => 1 } keys(%{$new_unit});
+ # Iterate over the sections
+ foreach my $section_name (keys(%{$cur_unit})) {
+ # Missing section in the new unit?
+ if (not exists($section_cmp{$section_name})) {
+ # If the [Unit] section was removed, make sure that only keys
+ # were in it that are ignored
+ if ($section_name eq "Unit") {
+ foreach my $ini_key (keys(%{$cur_unit->{"Unit"}})) {
+ if (not defined($unit_section_ignores{$ini_key})) {
+ return 1;
+ }
+ }
+ next; # check the next section
+ } else {
+ return 1;
+ }
+ if ($section_name eq "Unit" and %{$cur_unit->{"Unit"}} == 1 and defined(%{$cur_unit->{"Unit"}}{"X-Reload-Triggers"})) {
+ # If a new [Unit] section was removed that only contained X-Reload-Triggers,
+ # do nothing.
+ next;
+ } else {
+ return 1;
+ }
+ }
+ delete $section_cmp{$section_name};
+ # Comparison hash for the section contents
+ my %ini_cmp = map { $_ => 1 } keys(%{$new_unit->{$section_name}});
+ # Iterate over the keys of the section
+ foreach my $ini_key (keys(%{$cur_unit->{$section_name}})) {
+ delete $ini_cmp{$ini_key};
+ my @cur_value = @{$cur_unit->{$section_name}{$ini_key}};
+ # If the key is missing in the new unit, they are different...
+ if (not $new_unit->{$section_name}{$ini_key}) {
+ # ... unless the key that is now missing is one of the ignored keys
+ if ($section_name eq "Unit" and defined($unit_section_ignores{$ini_key})) {
+ next;
+ }
+ return 1;
+ }
+ my @new_value = @{$new_unit->{$section_name}{$ini_key}};
+ # If the contents are different, the units are different
+ if (not $comp_array->(\@cur_value, \@new_value)) {
+ # Check if only the reload triggers changed or one of the ignored keys
+ if ($section_name eq "Unit") {
+ if ($ini_key eq "X-Reload-Triggers") {
+ $ret = 2;
+ next;
+ } elsif (defined($unit_section_ignores{$ini_key})) {
+ next;
+ }
+ }
+ return 1;
+ }
+ }
+ # A key was introduced that was missing in the previous unit
+ if (%ini_cmp) {
+ if ($section_name eq "Unit") {
+ foreach my $ini_key (keys(%ini_cmp)) {
+ if ($ini_key eq "X-Reload-Triggers") {
+ $ret = 2;
+ } elsif (defined($unit_section_ignores{$ini_key})) {
+ next;
+ } else {
+ return 1;
+ }
+ }
+ } else {
+ return 1;
+ }
+ };
+ }
+ # A section was introduced that was missing in the previous unit
+ if (%section_cmp) {
+ if (%section_cmp == 1 and defined($section_cmp{"Unit"})) {
+ foreach my $ini_key (keys(%{$new_unit->{"Unit"}})) {
+ if (not defined($unit_section_ignores{$ini_key})) {
+ return 1;
+ } elsif ($ini_key eq "X-Reload-Triggers") {
+ $ret = 2;
+ }
+ }
+ } else {
+ return 1;
+ }
+ }
+
+ return $ret;
+}
+
+# Called when a unit exists in both the old systemd and the new system and the units
+# differ. This figures out of what units are to be stopped, restarted, reloaded, started, and skipped.
+sub handle_modified_unit { ## no critic(Subroutines::ProhibitManyArgs, Subroutines::ProhibitExcessComplexity)
+ my ($unit, $base_name, $new_unit_file, $new_unit_info, $active_cur, $units_to_stop, $units_to_start, $units_to_reload, $units_to_restart, $units_to_skip) = @_;
+
+ if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target" || $unit =~ /\.path$/msx || $unit =~ /\.slice$/msx) {
# Do nothing. These cannot be restarted directly.
# Slices and Paths don't have to be restarted since
# properties (resource limits and inotify watches)
# seem to get applied on daemon-reload.
- } elsif ($unit =~ /\.mount$/) {
+ } elsif ($unit =~ /\.mount$/msx) {
# Reload the changed mount unit to force a remount.
- $unitsToReload->{$unit} = 1;
- recordUnit($reloadListFile, $unit);
- } elsif ($unit =~ /\.socket$/) {
+ # FIXME: only reload when Options= changed, restart otherwise
+ $units_to_reload->{$unit} = 1;
+ record_unit($reload_list_file, $unit);
+ } elsif ($unit =~ /\.socket$/msx) {
# FIXME: do something?
# Attempt to fix this: https://github.com/NixOS/nixpkgs/pull/141192
# Revert of the attempt: https://github.com/NixOS/nixpkgs/pull/147609
# More details: https://github.com/NixOS/nixpkgs/issues/74899#issuecomment-981142430
} else {
- my $unitInfo = parseUnit($newUnitFile);
- if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
- $unitsToReload->{$unit} = 1;
- recordUnit($reloadListFile, $unit);
+ my %new_unit_info = $new_unit_info ? %{$new_unit_info} : parse_unit($new_unit_file);
+ if (parse_systemd_bool(\%new_unit_info, "Service", "X-ReloadIfChanged", 0) and not $units_to_restart->{$unit} and not $units_to_stop->{$unit}) {
+ $units_to_reload->{$unit} = 1;
+ record_unit($reload_list_file, $unit);
}
- elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
- $unitsToSkip->{$unit} = 1;
+ elsif (!parse_systemd_bool(\%new_unit_info, "Service", "X-RestartIfChanged", 1) || parse_systemd_bool(\%new_unit_info, "Unit", "RefuseManualStop", 0) || parse_systemd_bool(\%new_unit_info, "Unit", "X-OnlyManualStart", 0)) {
+ $units_to_skip->{$unit} = 1;
} else {
# It doesn't make sense to stop and start non-services because
# they can't have ExecStop=
- if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes") || $unit !~ /\.service$/) {
+ if (!parse_systemd_bool(\%new_unit_info, "Service", "X-StopIfChanged", 1) || $unit !~ /\.service$/msx) {
# This unit should be restarted instead of
# stopped and started.
- $unitsToRestart->{$unit} = 1;
- recordUnit($restartListFile, $unit);
+ $units_to_restart->{$unit} = 1;
+ record_unit($restart_list_file, $unit);
+ # Remove from units to reload so we don't restart and reload
+ if ($units_to_reload->{$unit}) {
+ delete $units_to_reload->{$unit};
+ unrecord_unit($reload_list_file, $unit);
+ }
} else {
# If this unit is socket-activated, then stop the
# socket unit(s) as well, and restart the
# socket(s) instead of the service.
- my $socketActivated = 0;
- if ($unit =~ /\.service$/) {
- my @sockets = split / /, ($unitInfo->{Sockets} // "");
- if (scalar @sockets == 0) {
- @sockets = ("$baseName.socket");
+ my $socket_activated = 0;
+ if ($unit =~ /\.service$/msx) {
+ my @sockets = split(/\s+/msx, join(" ", @{$new_unit_info{Service}{Sockets} // []}));
+ if (scalar(@sockets) == 0) {
+ @sockets = ("$base_name.socket");
}
foreach my $socket (@sockets) {
- if (defined $activePrev->{$socket}) {
- $unitsToStop->{$socket} = 1;
+ if (defined($active_cur->{$socket})) {
+ # We can now be sure this is a socket-activate unit
+
+ $units_to_stop->{$socket} = 1;
# Only restart sockets that actually
# exist in new configuration:
if (-e "$out/etc/systemd/system/$socket") {
- $unitsToStart->{$socket} = 1;
- recordUnit($startListFile, $socket);
- $socketActivated = 1;
+ $units_to_start->{$socket} = 1;
+ if ($units_to_start eq $units_to_restart) {
+ record_unit($restart_list_file, $socket);
+ } else {
+ record_unit($start_list_file, $socket);
+ }
+ $socket_activated = 1;
+ }
+ # Remove from units to reload so we don't restart and reload
+ if ($units_to_reload->{$unit}) {
+ delete $units_to_reload->{$unit};
+ unrecord_unit($reload_list_file, $unit);
}
}
}
@@ -210,56 +471,68 @@ sub handleModifiedUnit {
# that this unit needs to be started below.
# We write this to a file to ensure that the
# service gets restarted if we're interrupted.
- if (!$socketActivated) {
- $unitsToStart->{$unit} = 1;
- recordUnit($startListFile, $unit);
+ if (!$socket_activated) {
+ $units_to_start->{$unit} = 1;
+ if ($units_to_start eq $units_to_restart) {
+ record_unit($restart_list_file, $unit);
+ } else {
+ record_unit($start_list_file, $unit);
+ }
}
- $unitsToStop->{$unit} = 1;
+ $units_to_stop->{$unit} = 1;
+ # Remove from units to reload so we don't restart and reload
+ if ($units_to_reload->{$unit}) {
+ delete $units_to_reload->{$unit};
+ unrecord_unit($reload_list_file, $unit);
+ }
}
}
}
+ return;
}
# Figure out what units need to be stopped, started, restarted or reloaded.
-my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
+my (%units_to_stop, %units_to_skip, %units_to_start, %units_to_restart, %units_to_reload);
-my %unitsToFilter; # units not shown
+my %units_to_filter; # units not shown
-$unitsToStart{$_} = 1 foreach
- split('\n', read_file($startListFile, err_mode => 'quiet') // "");
+%units_to_start = map { $_ => 1 }
+ split(/\n/msx, read_file($start_list_file, err_mode => "quiet") // "");
-$unitsToRestart{$_} = 1 foreach
- split('\n', read_file($restartListFile, err_mode => 'quiet') // "");
+%units_to_restart = map { $_ => 1 }
+ split(/\n/msx, read_file($restart_list_file, err_mode => "quiet") // "");
-$unitsToReload{$_} = 1 foreach
- split('\n', read_file($reloadListFile, err_mode => 'quiet') // "");
+%units_to_reload = map { $_ => 1 }
+ split(/\n/msx, read_file($reload_list_file, err_mode => "quiet") // "");
-my $activePrev = getActiveUnits;
-while (my ($unit, $state) = each %{$activePrev}) {
- my $baseUnit = $unit;
+my $active_cur = get_active_units();
+while (my ($unit, $state) = each(%{$active_cur})) {
+ my $base_unit = $unit;
- my $prevUnitFile = "/etc/systemd/system/$baseUnit";
- my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
+ my $cur_unit_file = "/etc/systemd/system/$base_unit";
+ my $new_unit_file = "$out/etc/systemd/system/$base_unit";
# Detect template instances.
- if (!-e $prevUnitFile && !-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
- $baseUnit = "$1\@.$2";
- $prevUnitFile = "/etc/systemd/system/$baseUnit";
- $newUnitFile = "$out/etc/systemd/system/$baseUnit";
+ if (!-e $cur_unit_file && !-e $new_unit_file && $unit =~ /^(.*)@[^\.]*\.(.*)$/msx) {
+ $base_unit = "$1\@.$2";
+ $cur_unit_file = "/etc/systemd/system/$base_unit";
+ $new_unit_file = "$out/etc/systemd/system/$base_unit";
}
- my $baseName = $baseUnit;
- $baseName =~ s/\.[a-z]*$//;
+ my $base_name = $base_unit;
+ $base_name =~ s/\.[[:lower:]]*$//msx;
- if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) {
- if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") {
- my $unitInfo = parseUnit($prevUnitFile);
- $unitsToStop{$unit} = 1 if boolIsTrue($unitInfo->{'X-StopOnRemoval'} // "yes");
+ if (-e $cur_unit_file && ($state->{state} eq "active" || $state->{state} eq "activating")) {
+ if (! -e $new_unit_file || abs_path($new_unit_file) eq "/dev/null") {
+ my %cur_unit_info = parse_unit($cur_unit_file);
+ if (parse_systemd_bool(\%cur_unit_info, "Unit", "X-StopOnRemoval", 1)) {
+ $units_to_stop{$unit} = 1;
+ }
}
- elsif ($unit =~ /\.target$/) {
- my $unitInfo = parseUnit($newUnitFile);
+ elsif ($unit =~ /\.target$/msx) {
+ my %new_unit_info = parse_unit($new_unit_file);
# Cause all active target units to be restarted below.
# This should start most changed units we stop here as
@@ -268,11 +541,11 @@ while (my ($unit, $state) = each %{$activePrev}) {
# active after the system has resumed, which probably
# should not be the case. Just ignore it.
if ($unit ne "suspend.target" && $unit ne "hibernate.target" && $unit ne "hybrid-sleep.target") {
- unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no") || boolIsTrue($unitInfo->{'X-OnlyManualStart'} // "no")) {
- $unitsToStart{$unit} = 1;
- recordUnit($startListFile, $unit);
+ if (!(parse_systemd_bool(\%new_unit_info, "Unit", "RefuseManualStart", 0) || parse_systemd_bool(\%new_unit_info, "Unit", "X-OnlyManualStart", 0))) {
+ $units_to_start{$unit} = 1;
+ record_unit($start_list_file, $unit);
# Don't spam the user with target units that always get started.
- $unitsToFilter{$unit} = 1;
+ $units_to_filter{$unit} = 1;
}
}
@@ -287,163 +560,188 @@ while (my ($unit, $state) = each %{$activePrev}) {
# Stopping a target generally has no effect on other units
# (unless there is a PartOf dependency), so this is just a
# bookkeeping thing to get systemd to do the right thing.
- if (boolIsTrue($unitInfo->{'X-StopOnReconfiguration'} // "no")) {
- $unitsToStop{$unit} = 1;
+ if (parse_systemd_bool(\%new_unit_info, "Unit", "X-StopOnReconfiguration", 0)) {
+ $units_to_stop{$unit} = 1;
}
}
- elsif (fingerprintUnit($prevUnitFile) ne fingerprintUnit($newUnitFile)) {
- handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip);
+ else {
+ my %cur_unit_info = parse_unit($cur_unit_file);
+ my %new_unit_info = parse_unit($new_unit_file);
+ my $diff = compare_units(\%cur_unit_info, \%new_unit_info);
+ if ($diff == 1) {
+ handle_modified_unit($unit, $base_name, $new_unit_file, \%new_unit_info, $active_cur, \%units_to_stop, \%units_to_start, \%units_to_reload, \%units_to_restart, \%units_to_skip);
+ } elsif ($diff == 2 and not $units_to_restart{$unit}) {
+ $units_to_reload{$unit} = 1;
+ record_unit($reload_list_file, $unit);
+ }
}
}
}
-sub pathToUnitName {
+# Converts a path to the name of a systemd mount unit that would be responsible
+# for mounting this path.
+sub path_to_unit_name {
my ($path) = @_;
# Use current version of systemctl binary before daemon is reexeced.
- open my $cmd, "-|", "$curSystemd/systemd-escape", "--suffix=mount", "-p", $path
+ open(my $cmd, "-|", "$cur_systemd/systemd-escape", "--suffix=mount", "-p", $path)
or die "Unable to escape $path!\n";
- my $escaped = join "", <$cmd>;
- chomp $escaped;
- close $cmd or die;
+ my $escaped = do { local $/ = undef; <$cmd> };
+ chomp($escaped);
+ close($cmd) or die("Unable to close systemd-escape pipe");
return $escaped;
}
-sub unique {
- my %seen;
- my @res;
- foreach my $name (@_) {
- next if $seen{$name};
- $seen{$name} = 1;
- push @res, $name;
- }
- return @res;
-}
-
# Compare the previous and new fstab to figure out which filesystems
# need a remount or need to be unmounted. New filesystems are mounted
# automatically by starting local-fs.target. FIXME: might be nicer if
# we generated units for all mounts; then we could unify this with the
# unit checking code above.
-my ($prevFss, $prevSwaps) = parseFstab "/etc/fstab";
-my ($newFss, $newSwaps) = parseFstab "$out/etc/fstab";
-foreach my $mountPoint (keys %$prevFss) {
- my $prev = $prevFss->{$mountPoint};
- my $new = $newFss->{$mountPoint};
- my $unit = pathToUnitName($mountPoint);
- if (!defined $new) {
+my ($cur_fss, $cur_swaps) = parse_fstab("/etc/fstab");
+my ($new_fss, $new_swaps) = parse_fstab("$out/etc/fstab");
+foreach my $mount_point (keys(%{$cur_fss})) {
+ my $cur = $cur_fss->{$mount_point};
+ my $new = $new_fss->{$mount_point};
+ my $unit = path_to_unit_name($mount_point);
+ if (!defined($new)) {
# Filesystem entry disappeared, so unmount it.
- $unitsToStop{$unit} = 1;
- } elsif ($prev->{fsType} ne $new->{fsType} || $prev->{device} ne $new->{device}) {
+ $units_to_stop{$unit} = 1;
+ } elsif ($cur->{fsType} ne $new->{fsType} || $cur->{device} ne $new->{device}) {
# Filesystem type or device changed, so unmount and mount it.
- $unitsToStop{$unit} = 1;
- $unitsToStart{$unit} = 1;
- recordUnit($startListFile, $unit);
- } elsif ($prev->{options} ne $new->{options}) {
+ $units_to_stop{$unit} = 1;
+ $units_to_start{$unit} = 1;
+ record_unit($start_list_file, $unit);
+ } elsif ($cur->{options} ne $new->{options}) {
# Mount options changes, so remount it.
- $unitsToReload{$unit} = 1;
- recordUnit($reloadListFile, $unit);
+ $units_to_reload{$unit} = 1;
+ record_unit($reload_list_file, $unit);
}
}
# Also handles swap devices.
-foreach my $device (keys %$prevSwaps) {
- my $prev = $prevSwaps->{$device};
- my $new = $newSwaps->{$device};
- if (!defined $new) {
+foreach my $device (keys(%{$cur_swaps})) {
+ my $cur = $cur_swaps->{$device};
+ my $new = $new_swaps->{$device};
+ if (!defined($new)) {
# Swap entry disappeared, so turn it off. Can't use
# "systemctl stop" here because systemd has lots of alias
# units that prevent a stop from actually calling
# "swapoff".
- print STDERR "stopping swap device: $device\n";
- system("@utillinux@/sbin/swapoff", $device);
+ if ($action ne "dry-activate") {
+ print STDERR "would stop swap device: $device\n";
+ } else {
+ print STDERR "stopping swap device: $device\n";
+ system("@utillinux@/sbin/swapoff", $device);
+ }
}
# FIXME: update swap options (i.e. its priority).
}
# Should we have systemd re-exec itself?
-my $prevSystemd = abs_path("/proc/1/exe") // "/unknown";
-my $prevSystemdSystemConfig = abs_path("/etc/systemd/system.conf") // "/unknown";
-my $newSystemd = abs_path("@systemd@/lib/systemd/systemd") or die;
-my $newSystemdSystemConfig = abs_path("$out/etc/systemd/system.conf") // "/unknown";
+my $cur_pid1_path = abs_path("/proc/1/exe") // "/unknown";
+my $cur_systemd_system_config = abs_path("/etc/systemd/system.conf") // "/unknown";
+my $new_pid1_path = abs_path("$new_systemd/lib/systemd/systemd") or die;
+my $new_systemd_system_config = abs_path("$out/etc/systemd/system.conf") // "/unknown";
-my $restartSystemd = $prevSystemd ne $newSystemd;
-if ($prevSystemdSystemConfig ne $newSystemdSystemConfig) {
- $restartSystemd = 1;
+my $restart_systemd = $cur_pid1_path ne $new_pid1_path;
+if ($cur_systemd_system_config ne $new_systemd_system_config) {
+ $restart_systemd = 1;
}
-
-sub filterUnits {
+# Takes an array of unit names and returns an array with the same elements,
+# except all units that are also in the global variable `unitsToFilter`.
+sub filter_units {
my ($units) = @_;
my @res;
- foreach my $unit (sort(keys %{$units})) {
- push @res, $unit if !defined $unitsToFilter{$unit};
+ foreach my $unit (sort(keys(%{$units}))) {
+ if (!defined($units_to_filter{$unit})) {
+ push(@res, $unit);
+ }
}
return @res;
}
-my @unitsToStopFiltered = filterUnits(\%unitsToStop);
+my @units_to_stop_filtered = filter_units(\%units_to_stop);
# Show dry-run actions.
if ($action eq "dry-activate") {
- print STDERR "would stop the following units: ", join(", ", @unitsToStopFiltered), "\n"
- if scalar @unitsToStopFiltered > 0;
- print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
- if scalar(keys %unitsToSkip) > 0;
+ if (scalar(@units_to_stop_filtered) > 0) {
+ print STDERR "would stop the following units: ", join(", ", @units_to_stop_filtered), "\n";
+ }
+ if (scalar(keys(%units_to_skip)) > 0) {
+ print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys(%units_to_skip))), "\n";
+ }
print STDERR "would activate the configuration...\n";
system("$out/dry-activate", "$out");
# Handle the activation script requesting the restart or reload of a unit.
- foreach (split('\n', read_file($dryRestartByActivationFile, err_mode => 'quiet') // "")) {
+ foreach (split(/\n/msx, read_file($dry_restart_by_activation_file, err_mode => "quiet") // "")) {
my $unit = $_;
- my $baseUnit = $unit;
- my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
+ my $base_unit = $unit;
+ my $new_unit_file = "$out/etc/systemd/system/$base_unit";
# Detect template instances.
- if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
- $baseUnit = "$1\@.$2";
- $newUnitFile = "$out/etc/systemd/system/$baseUnit";
+ if (!-e $new_unit_file && $unit =~ /^(.*)@[^\.]*\.(.*)$/msx) {
+ $base_unit = "$1\@.$2";
+ $new_unit_file = "$out/etc/systemd/system/$base_unit";
}
- my $baseName = $baseUnit;
- $baseName =~ s/\.[a-z]*$//;
+ my $base_name = $base_unit;
+ $base_name =~ s/\.[[:lower:]]*$//msx;
# Start units if they were not active previously
- if (not defined $activePrev->{$unit}) {
- $unitsToStart{$unit} = 1;
+ if (not defined($active_cur->{$unit})) {
+ $units_to_start{$unit} = 1;
next;
}
- handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToRestart, \%unitsToRestart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip);
+ handle_modified_unit($unit, $base_name, $new_unit_file, undef, $active_cur, \%units_to_restart, \%units_to_restart, \%units_to_reload, \%units_to_restart, \%units_to_skip);
}
- unlink($dryRestartByActivationFile);
+ unlink($dry_restart_by_activation_file);
- print STDERR "would restart systemd\n" if $restartSystemd;
- print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n"
- if scalar(keys %unitsToReload) > 0;
- print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"
- if scalar(keys %unitsToRestart) > 0;
- my @unitsToStartFiltered = filterUnits(\%unitsToStart);
- print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n"
- if scalar @unitsToStartFiltered;
+ foreach (split(/\n/msx, read_file($dry_reload_by_activation_file, err_mode => "quiet") // "")) {
+ my $unit = $_;
+
+ if (defined($active_cur->{$unit}) and not $units_to_restart{$unit} and not $units_to_stop{$unit}) {
+ $units_to_reload{$unit} = 1;
+ record_unit($reload_list_file, $unit);
+ }
+ }
+ unlink($dry_reload_by_activation_file);
+
+ if ($restart_systemd) {
+ print STDERR "would restart systemd\n";
+ }
+ if (scalar(keys(%units_to_reload)) > 0) {
+ print STDERR "would reload the following units: ", join(", ", sort(keys(%units_to_reload))), "\n";
+ }
+ if (scalar(keys(%units_to_restart)) > 0) {
+ print STDERR "would restart the following units: ", join(", ", sort(keys(%units_to_restart))), "\n";
+ }
+ my @units_to_start_filtered = filter_units(\%units_to_start);
+ if (scalar(@units_to_start_filtered)) {
+ print STDERR "would start the following units: ", join(", ", @units_to_start_filtered), "\n";
+ }
exit 0;
}
syslog(LOG_NOTICE, "switching to system configuration $out");
-if (scalar (keys %unitsToStop) > 0) {
- print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n"
- if scalar @unitsToStopFiltered;
+if (scalar(keys(%units_to_stop)) > 0) {
+ if (scalar(@units_to_stop_filtered)) {
+ print STDERR "stopping the following units: ", join(", ", @units_to_stop_filtered), "\n";
+ }
# Use current version of systemctl binary before daemon is reexeced.
- system("$curSystemd/systemctl", "stop", "--", sort(keys %unitsToStop));
+ system("$cur_systemd/systemctl", "stop", "--", sort(keys(%units_to_stop)));
}
-print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
- if scalar(keys %unitsToSkip) > 0;
+if (scalar(keys(%units_to_skip)) > 0) {
+ print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys(%units_to_skip))), "\n";
+}
# Activate the new configuration (i.e., update /etc, make accounts,
# and so on).
@@ -452,79 +750,110 @@ print STDERR "activating the configuration...\n";
system("$out/activate", "$out") == 0 or $res = 2;
# Handle the activation script requesting the restart or reload of a unit.
-foreach (split('\n', read_file($restartByActivationFile, err_mode => 'quiet') // "")) {
+foreach (split(/\n/msx, read_file($restart_by_activation_file, err_mode => "quiet") // "")) {
my $unit = $_;
- my $baseUnit = $unit;
- my $newUnitFile = "$out/etc/systemd/system/$baseUnit";
+ my $base_unit = $unit;
+ my $new_unit_file = "$out/etc/systemd/system/$base_unit";
# Detect template instances.
- if (!-e $newUnitFile && $unit =~ /^(.*)@[^\.]*\.(.*)$/) {
- $baseUnit = "$1\@.$2";
- $newUnitFile = "$out/etc/systemd/system/$baseUnit";
+ if (!-e $new_unit_file && $unit =~ /^(.*)@[^\.]*\.(.*)$/msx) {
+ $base_unit = "$1\@.$2";
+ $new_unit_file = "$out/etc/systemd/system/$base_unit";
}
- my $baseName = $baseUnit;
- $baseName =~ s/\.[a-z]*$//;
+ my $base_name = $base_unit;
+ $base_name =~ s/\.[[:lower:]]*$//msx;
# Start units if they were not active previously
- if (not defined $activePrev->{$unit}) {
- $unitsToStart{$unit} = 1;
- recordUnit($startListFile, $unit);
+ if (not defined($active_cur->{$unit})) {
+ $units_to_start{$unit} = 1;
+ record_unit($start_list_file, $unit);
next;
}
- handleModifiedUnit($unit, $baseName, $newUnitFile, $activePrev, \%unitsToRestart, \%unitsToRestart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip);
+ handle_modified_unit($unit, $base_name, $new_unit_file, undef, $active_cur, \%units_to_restart, \%units_to_restart, \%units_to_reload, \%units_to_restart, \%units_to_skip);
}
# We can remove the file now because it has been propagated to the other restart/reload files
-unlink($restartByActivationFile);
+unlink($restart_by_activation_file);
+
+foreach (split(/\n/msx, read_file($reload_by_activation_file, err_mode => "quiet") // "")) {
+ my $unit = $_;
+
+ if (defined($active_cur->{$unit}) and not $units_to_restart{$unit} and not $units_to_stop{$unit}) {
+ $units_to_reload{$unit} = 1;
+ record_unit($reload_list_file, $unit);
+ }
+}
+# We can remove the file now because it has been propagated to the other reload file
+unlink($reload_by_activation_file);
# Restart systemd if necessary. Note that this is done using the
# current version of systemd, just in case the new one has trouble
# communicating with the running pid 1.
-if ($restartSystemd) {
+if ($restart_systemd) {
print STDERR "restarting systemd...\n";
- system("$curSystemd/systemctl", "daemon-reexec") == 0 or $res = 2;
+ system("$cur_systemd/systemctl", "daemon-reexec") == 0 or $res = 2;
}
# Forget about previously failed services.
-system("@systemd@/bin/systemctl", "reset-failed");
+system("$new_systemd/bin/systemctl", "reset-failed");
# Make systemd reload its units.
-system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3;
+system("$new_systemd/bin/systemctl", "daemon-reload") == 0 or $res = 3;
# Reload user units
-open my $listActiveUsers, '-|', '@systemd@/bin/loginctl', 'list-users', '--no-legend';
-while (my $f = <$listActiveUsers>) {
- next unless $f =~ /^\s*(?\d+)\s+(?\S+)/;
+open(my $list_active_users, "-|", "$new_systemd/bin/loginctl", "list-users", "--no-legend") || die("Unable to call loginctl");
+while (my $f = <$list_active_users>) {
+ if ($f !~ /^\s*(?\d+)\s+(?\S+)/msx) {
+ next;
+ }
my ($uid, $name) = ($+{uid}, $+{user});
print STDERR "reloading user units for $name...\n";
system("@su@", "-s", "@shell@", "-l", $name, "-c",
"export XDG_RUNTIME_DIR=/run/user/$uid; " .
- "$curSystemd/systemctl --user daemon-reexec; " .
- "@systemd@/bin/systemctl --user start nixos-activation.service");
+ "$cur_systemd/systemctl --user daemon-reexec; " .
+ "$new_systemd/bin/systemctl --user start nixos-activation.service");
}
-close $listActiveUsers;
+close($list_active_users) || die("Unable to close the file handle to loginctl");
# Set the new tmpfiles
print STDERR "setting up tmpfiles\n";
-system("@systemd@/bin/systemd-tmpfiles", "--create", "--remove", "--exclude-prefix=/dev") == 0 or $res = 3;
+system("$new_systemd/bin/systemd-tmpfiles", "--create", "--remove", "--exclude-prefix=/dev") == 0 or $res = 3;
+# Before reloading we need to ensure that the units are still active. They may have been
+# deactivated because one of their requirements got stopped. If they are inactive
+# but should have been reloaded, the user probably expects them to be started.
+if (scalar(keys(%units_to_reload)) > 0) {
+ for my $unit (keys(%units_to_reload)) {
+ if (!unit_is_active($unit)) {
+ # Figure out if we need to start the unit
+ my %unit_info = parse_unit("$out/etc/systemd/system/$unit");
+ if (!(parse_systemd_bool(\%unit_info, "Unit", "RefuseManualStart", 0) || parse_systemd_bool(\%unit_info, "Unit", "X-OnlyManualStart", 0))) {
+ $units_to_start{$unit} = 1;
+ record_unit($start_list_file, $unit);
+ }
+ # Don't reload the unit, reloading would fail
+ delete %units_to_reload{$unit};
+ unrecord_unit($reload_list_file, $unit);
+ }
+ }
+}
# Reload units that need it. This includes remounting changed mount
# units.
-if (scalar(keys %unitsToReload) > 0) {
- print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n";
- system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4;
- unlink($reloadListFile);
+if (scalar(keys(%units_to_reload)) > 0) {
+ print STDERR "reloading the following units: ", join(", ", sort(keys(%units_to_reload))), "\n";
+ system("$new_systemd/bin/systemctl", "reload", "--", sort(keys(%units_to_reload))) == 0 or $res = 4;
+ unlink($reload_list_file);
}
# Restart changed services (those that have to be restarted rather
# than stopped and started).
-if (scalar(keys %unitsToRestart) > 0) {
- print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n";
- system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4;
- unlink($restartListFile);
+if (scalar(keys(%units_to_restart)) > 0) {
+ print STDERR "restarting the following units: ", join(", ", sort(keys(%units_to_restart))), "\n";
+ system("$new_systemd/bin/systemctl", "restart", "--", sort(keys(%units_to_restart))) == 0 or $res = 4;
+ unlink($restart_list_file);
}
# Start all active targets, as well as changed units we stopped above.
@@ -533,46 +862,52 @@ if (scalar(keys %unitsToRestart) > 0) {
# that are symlinks to other units. We shouldn't start both at the
# same time because we'll get a "Failed to add path to set" error from
# systemd.
-my @unitsToStartFiltered = filterUnits(\%unitsToStart);
-print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n"
- if scalar @unitsToStartFiltered;
-system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4;
-unlink($startListFile);
+my @units_to_start_filtered = filter_units(\%units_to_start);
+if (scalar(@units_to_start_filtered)) {
+ print STDERR "starting the following units: ", join(", ", @units_to_start_filtered), "\n"
+}
+system("$new_systemd/bin/systemctl", "start", "--", sort(keys(%units_to_start))) == 0 or $res = 4;
+unlink($start_list_file);
# Print failed and new units.
my (@failed, @new);
-my $activeNew = getActiveUnits;
-while (my ($unit, $state) = each %{$activeNew}) {
+my $active_new = get_active_units();
+while (my ($unit, $state) = each(%{$active_new})) {
if ($state->{state} eq "failed") {
- push @failed, $unit;
+ push(@failed, $unit);
+ next;
}
- elsif ($state->{state} eq "auto-restart") {
- # A unit in auto-restart state is a failure *if* it previously failed to start
- my $lines = `@systemd@/bin/systemctl show '$unit'`;
- my $info = {};
- parseKeyValues($info, split("\n", $lines));
- if ($info->{ExecMainStatus} ne '0') {
- push @failed, $unit;
+ if ($state->{substate} eq "auto-restart") {
+ # A unit in auto-restart substate is a failure *if* it previously failed to start
+ open(my $main_status_fd, "-|", "$new_systemd/bin/systemctl", "show", "--value", "--property=ExecMainStatus", $unit) || die("Unable to call 'systemctl show'");
+ my $main_status = do { local $/ = undef; <$main_status_fd> };
+ close($main_status_fd) || die("Unable to close 'systemctl show' fd");
+ chomp($main_status);
+
+ if ($main_status ne "0") {
+ push(@failed, $unit);
+ next;
}
}
+
# Ignore scopes since they are not managed by this script but rather
# created and managed by third-party services via the systemd dbus API.
- elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit} && $unit !~ /\.scope$/) {
- push @new, $unit;
+ # This only lists units that are not failed (including ones that are in auto-restart but have not failed previously)
+ if ($state->{state} ne "failed" && !defined($active_cur->{$unit}) && $unit !~ /\.scope$/msx) {
+ push(@new, $unit);
}
}
-print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n"
- if scalar @new > 0;
+if (scalar(@new) > 0) {
+ print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n"
+}
-if (scalar @failed > 0) {
- print STDERR "warning: the following units failed: ", join(", ", sort(@failed)), "\n";
- foreach my $unit (@failed) {
- print STDERR "\n";
- system("COLUMNS=1000 @systemd@/bin/systemctl status --no-pager '$unit' >&2");
- }
+if (scalar(@failed) > 0) {
+ my @failed_sorted = sort(@failed);
+ print STDERR "warning: the following units failed: ", join(", ", @failed_sorted), "\n\n";
+ system("$new_systemd/bin/systemctl status --no-pager --full '" . join("' '", @failed_sorted) . "' >&2");
$res = 4;
}
@@ -582,4 +917,4 @@ if ($res == 0) {
syslog(LOG_ERR, "switching to system configuration $out failed (status $res)");
}
-exit $res;
+exit($res);
diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix
index 18ac717f5dd6..b8aeee8c11b3 100644
--- a/nixos/modules/system/activation/top-level.nix
+++ b/nixos/modules/system/activation/top-level.nix
@@ -117,7 +117,7 @@ let
configurationName = config.boot.loader.grub.configurationName;
# Needed by switch-to-configuration.
- perl = pkgs.perl.withPackages (p: with p; [ FileSlurp NetDBus XMLParser XMLTwig ]);
+ perl = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp NetDBus ]);
};
# Handle assertions and warnings
@@ -156,7 +156,7 @@ in
specialisation = mkOption {
default = {};
- example = lib.literalExpression "{ fewJobsManyCores.configuration = { nix.buildCores = 0; nix.maxJobs = 1; }; }";
+ example = lib.literalExpression "{ fewJobsManyCores.configuration = { nix.settings = { core = 0; max-jobs = 1; }; }";
description = ''
Additional configurations to build. If
inheritParentConfig is true, the system
diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix
index 5bc603530f7e..33748358e45b 100644
--- a/nixos/modules/system/boot/binfmt.nix
+++ b/nixos/modules/system/boot/binfmt.nix
@@ -300,18 +300,15 @@ in {
interpreterSandboxPath = dirOf (dirOf interpreterReg);
} // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}"));
}) cfg.emulatedSystems);
- # TODO: add a nix.extraPlatforms option to NixOS!
- nix.extraOptions = lib.mkIf (cfg.emulatedSystems != []) ''
- extra-platforms = ${toString (cfg.emulatedSystems ++ lib.optional pkgs.stdenv.hostPlatform.isx86_64 "i686-linux")}
- '';
- nix.sandboxPaths = lib.mkIf (cfg.emulatedSystems != []) (
- let
+ nix.settings = lib.mkIf (cfg.emulatedSystems != []) {
+ extra-platforms = cfg.emulatedSystems ++ lib.optional pkgs.stdenv.hostPlatform.isx86_64 "i686-linux";
+ extra-sandbox-paths = let
ruleFor = system: cfg.registrations.${system};
hasWrappedRule = lib.any (system: (ruleFor system).wrapInterpreterInShell) cfg.emulatedSystems;
in [ "/run/binfmt" ]
++ lib.optional hasWrappedRule "${pkgs.bash}"
- ++ (map (system: (ruleFor system).interpreterSandboxPath) cfg.emulatedSystems)
- );
+ ++ (map (system: (ruleFor system).interpreterSandboxPath) cfg.emulatedSystems);
+ };
environment.etc."binfmt.d/nixos.conf".source = builtins.toFile "binfmt_nixos.conf"
(lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine config.boot.binfmt.registrations));
diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix
index d147155d796c..db00244ca0af 100644
--- a/nixos/modules/system/boot/kernel.nix
+++ b/nixos/modules/system/boot/kernel.nix
@@ -36,7 +36,7 @@ in
boot.kernelPackages = mkOption {
default = pkgs.linuxPackages;
- type = types.unspecified // { merge = mergeEqualOption; };
+ type = types.raw;
apply = kernelPackages: kernelPackages.extend (self: super: {
kernel = super.kernel.override (originalArgs: {
inherit randstructSeed;
diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index adc893063098..fa879437fd81 100644
--- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -15,9 +15,12 @@ import re
import datetime
import glob
import os.path
-from typing import Tuple, List, Optional
+from typing import NamedTuple, List, Optional
-SystemIdentifier = Tuple[Optional[str], int, Optional[str]]
+class SystemIdentifier(NamedTuple):
+ profile: Optional[str]
+ generation: int
+ specialisation: Optional[str]
def copy_if_not_exists(source: str, dest: str) -> None:
@@ -151,7 +154,14 @@ def get_generations(profile: Optional[str] = None) -> List[SystemIdentifier]:
gen_lines.pop()
configurationLimit = @configurationLimit@
- configurations: List[SystemIdentifier] = [ (profile, int(line.split()[0]), None) for line in gen_lines ]
+ configurations = [
+ SystemIdentifier(
+ profile=profile,
+ generation=int(line.split()[0]),
+ specialisation=None
+ )
+ for line in gen_lines
+ ]
return configurations[-configurationLimit:]
@@ -160,7 +170,7 @@ def get_specialisations(profile: Optional[str], generation: int, _: Optional[str
system_dir(profile, generation, None), "specialisation")
if not os.path.exists(specialisations_dir):
return []
- return [(profile, generation, spec) for spec in os.listdir(specialisations_dir)]
+ return [SystemIdentifier(profile, generation, spec) for spec in os.listdir(specialisations_dir)]
def remove_old_entries(gens: List[SystemIdentifier]) -> None:
@@ -271,7 +281,8 @@ def main() -> None:
if os.readlink(system_dir(*gen)) == args.default_config:
write_loader_conf(*gen)
except OSError as e:
- print("ignoring generation '{}' in the list of boot entries because of the following error:\n{}".format(*gen, e), file=sys.stderr)
+ profile = f"profile '{gen.profile}'" if gen.profile else "default profile"
+ print("ignoring {} in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr)
for root, _, files in os.walk('@efiSysMountPoint@/efi/nixos/.extra-files', topdown=False):
relative_root = root.removeprefix("@efiSysMountPoint@/efi/nixos/.extra-files").removeprefix("/")
diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix
index 7426d148891f..e683d1817297 100644
--- a/nixos/modules/system/boot/modprobe.nix
+++ b/nixos/modules/system/boot/modprobe.nix
@@ -34,23 +34,6 @@ with lib;
type = types.lines;
};
- boot.initrd.extraModprobeConfig = mkOption {
- default = "";
- example =
- ''
- options zfs zfs_arc_max=1073741824
- '';
- description = ''
- Does exactly the same thing as
- , except
- that the generated modprobe.conf
- file is also included in the initrd.
- This is useful for setting module options for kernel
- modules that are loaded during early boot in the initrd.
- '';
- type = types.lines;
- };
-
};
@@ -67,11 +50,10 @@ with lib;
'')}
${config.boot.extraModprobeConfig}
'';
- environment.etc."modprobe.d/nixos-initrd.conf".text = ''
- ${config.boot.initrd.extraModprobeConfig}
- '';
environment.etc."modprobe.d/debian.conf".source = pkgs.kmod-debian-aliases;
+ environment.etc."modprobe.d/systemd.conf".source = "${pkgs.systemd}/lib/modprobe.d/systemd.conf";
+
environment.systemPackages = [ pkgs.kmod ];
system.activationScripts.modprobe = stringAfter ["specialfs"]
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index f86d4641228c..8fcc1f029723 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -282,6 +282,9 @@ checkFS() {
# Don't check resilient COWs as they validate the fs structures at mount time
if [ "$fsType" = btrfs -o "$fsType" = zfs -o "$fsType" = bcachefs ]; then return 0; fi
+ # Skip fsck for apfs as the fsck utility does not support repairing the filesystem (no -a option)
+ if [ "$fsType" = apfs ]; then return 0; fi
+
# Skip fsck for nilfs2 - not needed by design and no fsck tool for this filesystem.
if [ "$fsType" = nilfs2 ]; then return 0; fi
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 9c684fbada2c..8b011d91563f 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -338,9 +338,6 @@ let
{ object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf;
symlink = "/etc/mdadm.conf";
}
- { object = config.environment.etc."modprobe.d/nixos-initrd.conf".source;
- symlink = "/etc/modprobe.d/nixos-initrd.conf";
- }
{ object = pkgs.runCommand "initrd-kmod-blacklist-ubuntu" {
src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf";
preferLocalBuild = true;
@@ -350,6 +347,9 @@ let
'';
symlink = "/etc/modprobe.d/ubuntu.conf";
}
+ { object = config.environment.etc."modprobe.d/nixos.conf".source;
+ symlink = "/etc/modprobe.d/nixos.conf";
+ }
{ object = pkgs.kmod-debian-aliases;
symlink = "/etc/modprobe.d/debian.conf";
}
@@ -578,7 +578,7 @@ in
else "gzip"
);
defaultText = literalDocBook "zstd if the kernel supports it (5.9+), gzip if not";
- type = types.unspecified; # We don't have a function type...
+ type = types.either types.str (types.functionTo types.str);
description = ''
The compressor to use on the initrd image. May be any of:
diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix
index f6b6a8e4b0b4..fa2bf938df4f 100644
--- a/nixos/modules/system/boot/stage-2.nix
+++ b/nixos/modules/system/boot/stage-2.nix
@@ -47,36 +47,6 @@ in
'';
};
- devSize = mkOption {
- default = "5%";
- example = "32m";
- type = types.str;
- description = ''
- Size limit for the /dev tmpfs. Look at mount(8), tmpfs size option,
- for the accepted syntax.
- '';
- };
-
- devShmSize = mkOption {
- default = "50%";
- example = "256m";
- type = types.str;
- description = ''
- Size limit for the /dev/shm tmpfs. Look at mount(8), tmpfs size option,
- for the accepted syntax.
- '';
- };
-
- runSize = mkOption {
- default = "25%";
- example = "256m";
- type = types.str;
- description = ''
- Size limit for the /run tmpfs. Look at mount(8), tmpfs size option,
- for the accepted syntax.
- '';
- };
-
systemdExecutable = mkOption {
default = "systemd";
type = types.str;
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 76c59c047e0f..057474c607ac 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -2,7 +2,6 @@
with utils;
with systemdUtils.unitOptions;
-with systemdUtils.lib;
with lib;
let
@@ -11,6 +10,24 @@ let
systemd = cfg.package;
+ inherit (systemdUtils.lib)
+ makeUnit
+ generateUnits
+ makeJobScript
+ unitConfig
+ serviceConfig
+ mountConfig
+ automountConfig
+ commonUnitText
+ targetToUnit
+ serviceToUnit
+ socketToUnit
+ timerToUnit
+ pathToUnit
+ mountToUnit
+ automountToUnit
+ sliceToUnit;
+
upstreamSystemUnits =
[ # Targets.
"basic.target"
@@ -25,9 +42,11 @@ let
"nss-lookup.target"
"nss-user-lookup.target"
"time-sync.target"
+ ] ++ (optionals cfg.package.withCryptsetup [
"cryptsetup.target"
"cryptsetup-pre.target"
"remote-cryptsetup.target"
+ ]) ++ [
"sigpwr.target"
"timers.target"
"paths.target"
@@ -61,32 +80,6 @@ let
"printer.target"
"smartcard.target"
- # Login stuff.
- "systemd-logind.service"
- "autovt@.service"
- "systemd-user-sessions.service"
- "dbus-org.freedesktop.import1.service"
- "dbus-org.freedesktop.machine1.service"
- "dbus-org.freedesktop.login1.service"
- "user@.service"
- "user-runtime-dir@.service"
-
- # Journal.
- "systemd-journald.socket"
- "systemd-journald@.socket"
- "systemd-journald-varlink@.socket"
- "systemd-journald.service"
- "systemd-journald@.service"
- "systemd-journal-flush.service"
- "systemd-journal-catalog-update.service"
- ] ++ (optional (!config.boot.isContainer) "systemd-journald-audit.socket") ++ [
- "systemd-journald-dev-log.socket"
- "syslog.socket"
-
- # Coredumps.
- "systemd-coredump.socket"
- "systemd-coredump@.service"
-
# Kernel module loading.
"systemd-modules-load.service"
"kmod-static-nodes.service"
@@ -147,19 +140,12 @@ let
# Slices / containers.
"slices.target"
- "user.slice"
"machine.slice"
"machines.target"
"systemd-importd.service"
"systemd-machined.service"
"systemd-nspawn@.service"
- # Temporary file creation / cleanup.
- "systemd-tmpfiles-clean.service"
- "systemd-tmpfiles-clean.timer"
- "systemd-tmpfiles-setup.service"
- "systemd-tmpfiles-setup-dev.service"
-
# Misc.
"systemd-sysctl.service"
"dbus-org.freedesktop.timedate1.service"
@@ -170,9 +156,6 @@ let
"systemd-hostnamed.service"
"systemd-exit.service"
"systemd-update-done.service"
- ] ++ optionals config.services.journald.enableHttpGateway [
- "systemd-journal-gatewayd.socket"
- "systemd-journal-gatewayd.service"
] ++ cfg.additionalUpstreamSystemUnits;
upstreamSystemWants =
@@ -183,235 +166,6 @@ let
"timers.target.wants"
];
- upstreamUserUnits = [
- "app.slice"
- "background.slice"
- "basic.target"
- "bluetooth.target"
- "default.target"
- "exit.target"
- "graphical-session-pre.target"
- "graphical-session.target"
- "paths.target"
- "printer.target"
- "session.slice"
- "shutdown.target"
- "smartcard.target"
- "sockets.target"
- "sound.target"
- "systemd-exit.service"
- "systemd-tmpfiles-clean.service"
- "systemd-tmpfiles-clean.timer"
- "systemd-tmpfiles-setup.service"
- "timers.target"
- "xdg-desktop-autostart.target"
- ];
-
- makeJobScript = name: text:
- let
- scriptName = replaceChars [ "\\" "@" ] [ "-" "_" ] (shellEscape name);
- out = (pkgs.writeShellScriptBin scriptName ''
- set -e
- ${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}";
-
- unitConfig = { config, options, ... }: {
- config = {
- unitConfig =
- optionalAttrs (config.requires != [])
- { Requires = toString config.requires; }
- // optionalAttrs (config.wants != [])
- { Wants = toString config.wants; }
- // optionalAttrs (config.after != [])
- { After = toString config.after; }
- // optionalAttrs (config.before != [])
- { Before = toString config.before; }
- // optionalAttrs (config.bindsTo != [])
- { BindsTo = toString config.bindsTo; }
- // optionalAttrs (config.partOf != [])
- { PartOf = toString config.partOf; }
- // optionalAttrs (config.conflicts != [])
- { Conflicts = toString config.conflicts; }
- // optionalAttrs (config.requisite != [])
- { Requisite = toString config.requisite; }
- // optionalAttrs (config.restartTriggers != [])
- { X-Restart-Triggers = toString config.restartTriggers; }
- // optionalAttrs (config.description != "") {
- Description = config.description; }
- // optionalAttrs (config.documentation != []) {
- Documentation = toString config.documentation; }
- // optionalAttrs (config.onFailure != []) {
- OnFailure = toString config.onFailure; }
- // optionalAttrs (options.startLimitIntervalSec.isDefined) {
- StartLimitIntervalSec = toString config.startLimitIntervalSec;
- } // optionalAttrs (options.startLimitBurst.isDefined) {
- StartLimitBurst = toString config.startLimitBurst;
- };
- };
- };
-
- serviceConfig = { name, config, ... }: {
- config = mkMerge
- [ { # Default path for systemd services. Should be quite minimal.
- path = mkAfter
- [ pkgs.coreutils
- pkgs.findutils
- pkgs.gnugrep
- pkgs.gnused
- systemd
- ];
- environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
- }
- (mkIf (config.preStart != "")
- { serviceConfig.ExecStartPre =
- [ (makeJobScript "${name}-pre-start" config.preStart) ];
- })
- (mkIf (config.script != "")
- { serviceConfig.ExecStart =
- makeJobScript "${name}-start" config.script + " " + config.scriptArgs;
- })
- (mkIf (config.postStart != "")
- { serviceConfig.ExecStartPost =
- [ (makeJobScript "${name}-post-start" config.postStart) ];
- })
- (mkIf (config.reload != "")
- { serviceConfig.ExecReload =
- makeJobScript "${name}-reload" config.reload;
- })
- (mkIf (config.preStop != "")
- { serviceConfig.ExecStop =
- makeJobScript "${name}-pre-stop" config.preStop;
- })
- (mkIf (config.postStop != "")
- { serviceConfig.ExecStopPost =
- makeJobScript "${name}-post-stop" config.postStop;
- })
- ];
- };
-
- mountConfig = { config, ... }: {
- config = {
- mountConfig =
- { What = config.what;
- Where = config.where;
- } // optionalAttrs (config.type != "") {
- Type = config.type;
- } // optionalAttrs (config.options != "") {
- Options = config.options;
- };
- };
- };
-
- automountConfig = { config, ... }: {
- config = {
- automountConfig =
- { Where = config.where;
- };
- };
- };
-
- commonUnitText = def: ''
- [Unit]
- ${attrsToSection def.unitConfig}
- '';
-
- targetToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text =
- ''
- [Unit]
- ${attrsToSection def.unitConfig}
- '';
- };
-
- serviceToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Service]
- ${let env = cfg.globalEnvironment // def.environment;
- in concatMapStrings (n:
- let s = optionalString (env.${n} != null)
- "Environment=${builtins.toJSON "${n}=${env.${n}}"}\n";
- # systemd max line length is now 1MiB
- # https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af
- in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
- ${if def.reloadIfChanged then ''
- X-ReloadIfChanged=true
- '' else if !def.restartIfChanged then ''
- X-RestartIfChanged=false
- '' else ""}
- ${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
- ${attrsToSection def.serviceConfig}
- '';
- };
-
- socketToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Socket]
- ${attrsToSection def.socketConfig}
- ${concatStringsSep "\n" (map (s: "ListenStream=${s}") def.listenStreams)}
- ${concatStringsSep "\n" (map (s: "ListenDatagram=${s}") def.listenDatagrams)}
- '';
- };
-
- timerToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Timer]
- ${attrsToSection def.timerConfig}
- '';
- };
-
- pathToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Path]
- ${attrsToSection def.pathConfig}
- '';
- };
-
- mountToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Mount]
- ${attrsToSection def.mountConfig}
- '';
- };
-
- automountToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Automount]
- ${attrsToSection def.automountConfig}
- '';
- };
-
- sliceToUnit = name: def:
- { inherit (def) aliases wantedBy requiredBy enable;
- text = commonUnitText def +
- ''
- [Slice]
- ${attrsToSection def.sliceConfig}
- '';
- };
-
- logindHandlerType = types.enum [
- "ignore" "poweroff" "reboot" "halt" "kexec" "suspend"
- "hibernate" "hybrid-sleep" "suspend-then-hibernate" "lock"
- ];
-
proxy_env = config.networking.proxy.envVars;
in
@@ -564,26 +318,6 @@ in
'';
};
- systemd.coredump.enable = mkOption {
- default = true;
- type = types.bool;
- description = ''
- Whether core dumps should be processed by
- systemd-coredump. If disabled, core dumps
- appear in the current directory of the crashing process.
- '';
- };
-
- systemd.coredump.extraConfig = mkOption {
- default = "";
- type = types.lines;
- example = "Storage=journal";
- description = ''
- Extra config options for systemd-coredump. See coredump.conf(5) man page
- for available options.
- '';
- };
-
systemd.extraConfig = mkOption {
default = "";
type = types.lines;
@@ -594,142 +328,6 @@ in
'';
};
- services.journald.console = mkOption {
- default = "";
- type = types.str;
- description = "If non-empty, write log messages to the specified TTY device.";
- };
-
- services.journald.rateLimitInterval = mkOption {
- default = "30s";
- type = types.str;
- description = ''
- Configures the rate limiting interval that is applied to all
- messages generated on the system. This rate limiting is applied
- per-service, so that two services which log do not interfere with
- each other's limit. The value may be specified in the following
- units: s, min, h, ms, us. To turn off any kind of rate limiting,
- set either value to 0.
-
- See for important
- considerations when setting this value.
- '';
- };
-
- services.journald.rateLimitBurst = mkOption {
- default = 10000;
- type = types.int;
- description = ''
- Configures the rate limiting burst limit (number of messages per
- interval) that is applied to all messages generated on the system.
- This rate limiting is applied per-service, so that two services
- which log do not interfere with each other's limit.
-
- Note that the effective rate limit is multiplied by a factor derived
- from the available free disk space for the journal as described on
-
- journald.conf(5).
-
- Note that the total amount of logs stored is limited by journald settings
- such as SystemMaxUse, which defaults to a 4 GB cap.
-
- It is thus recommended to compute what period of time that you will be
- able to store logs for when an application logs at full burst rate.
- With default settings for log lines that are 100 Bytes long, this can
- amount to just a few hours.
- '';
- };
-
- services.journald.extraConfig = mkOption {
- default = "";
- type = types.lines;
- example = "Storage=volatile";
- description = ''
- Extra config options for systemd-journald. See man journald.conf
- for available options.
- '';
- };
-
- services.journald.enableHttpGateway = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Whether to enable the HTTP gateway to the journal.
- '';
- };
-
- services.journald.forwardToSyslog = mkOption {
- default = config.services.rsyslogd.enable || config.services.syslog-ng.enable;
- defaultText = literalExpression "services.rsyslogd.enable || services.syslog-ng.enable";
- type = types.bool;
- description = ''
- Whether to forward log messages to syslog.
- '';
- };
-
- services.logind.extraConfig = mkOption {
- default = "";
- type = types.lines;
- example = "IdleAction=lock";
- description = ''
- Extra config options for systemd-logind. See
-
- logind.conf(5) for available options.
- '';
- };
-
- services.logind.killUserProcesses = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Specifies whether the processes of a user should be killed
- when the user logs out. If true, the scope unit corresponding
- to the session and all processes inside that scope will be
- terminated. If false, the scope is "abandoned" (see
-
- systemd.scope(5)), and processes are not killed.
-
-
-
- See logind.conf(5)
- for more details.
- '';
- };
-
- services.logind.lidSwitch = mkOption {
- default = "suspend";
- example = "ignore";
- type = logindHandlerType;
-
- description = ''
- Specifies what to be done when the laptop lid is closed.
- '';
- };
-
- services.logind.lidSwitchDocked = mkOption {
- default = "ignore";
- example = "suspend";
- type = logindHandlerType;
-
- description = ''
- Specifies what to be done when the laptop lid is closed
- and another screen is added.
- '';
- };
-
- services.logind.lidSwitchExternalPower = mkOption {
- default = config.services.logind.lidSwitch;
- defaultText = literalExpression "services.logind.lidSwitch";
- example = "ignore";
- type = logindHandlerType;
-
- description = ''
- Specifies what to do when the laptop lid is closed and the system is
- on external power. By default use the same action as specified in
- services.logind.lidSwitch.
- '';
- };
-
systemd.sleep.extraConfig = mkOption {
default = "";
type = types.lines;
@@ -740,95 +338,6 @@ in
'';
};
- systemd.user.extraConfig = mkOption {
- default = "";
- type = types.lines;
- example = "DefaultCPUAccounting=yes";
- description = ''
- Extra config options for systemd user instances. See man systemd-user.conf for
- available options.
- '';
- };
-
- systemd.tmpfiles.rules = mkOption {
- type = types.listOf types.str;
- default = [];
- example = [ "d /tmp 1777 root root 10d" ];
- description = ''
- Rules for creation, deletion and cleaning of volatile and temporary files
- automatically. See
- tmpfiles.d5
- for the exact format.
- '';
- };
-
- systemd.tmpfiles.packages = mkOption {
- type = types.listOf types.package;
- default = [];
- example = literalExpression "[ pkgs.lvm2 ]";
- apply = map getLib;
- description = ''
- List of packages containing systemd-tmpfiles rules.
-
- All files ending in .conf found in
- pkg/lib/tmpfiles.d
- will be included.
- If this folder does not exist or does not contain any files an error will be returned instead.
-
- If a lib output is available, rules are searched there and only there.
- If there is no lib output it will fall back to out
- and if that does not exist either, the default output will be used.
- '';
- };
-
- systemd.user.units = mkOption {
- description = "Definition of systemd per-user units.";
- default = {};
- type = with types; attrsOf (submodule (
- { name, config, ... }:
- { options = concreteUnitOptions;
- config = {
- unit = mkDefault (makeUnit name config);
- };
- }));
- };
-
- systemd.user.paths = mkOption {
- default = {};
- type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]);
- description = "Definition of systemd per-user path units.";
- };
-
- systemd.user.services = mkOption {
- default = {};
- type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ] );
- description = "Definition of systemd per-user service units.";
- };
-
- systemd.user.slices = mkOption {
- default = {};
- type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig ] );
- description = "Definition of systemd per-user slice units.";
- };
-
- systemd.user.sockets = mkOption {
- default = {};
- type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ] );
- description = "Definition of systemd per-user socket units.";
- };
-
- systemd.user.targets = mkOption {
- default = {};
- type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] );
- description = "Definition of systemd per-user target units.";
- };
-
- systemd.user.timers = mkOption {
- default = {};
- type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ] );
- description = "Definition of systemd per-user timer units.";
- };
-
systemd.additionalUpstreamSystemUnits = mkOption {
default = [ ];
type = types.listOf types.str;
@@ -915,6 +424,9 @@ in
(optional hasDeprecated
"Service '${name}.service' uses the attribute 'StartLimitInterval' in the Service section, which is deprecated. See https://github.com/NixOS/nixpkgs/issues/45786."
)
+ (optional (service.reloadIfChanged && service.reloadTriggers != [])
+ "Service '${name}.service' has both 'reloadIfChanged' and 'reloadTriggers' set. This is probably not what you want, because 'reloadTriggers' behave the same whay as 'restartTriggers' if 'reloadIfChanged' is set."
+ )
]
)
cfg.services
@@ -961,8 +473,6 @@ in
in ({
"systemd/system".source = generateUnits "system" enabledUnits enabledUpstreamSystemUnits upstreamSystemWants;
- "systemd/user".source = generateUnits "user" cfg.user.units upstreamUserUnits [];
-
"systemd/system.conf".text = ''
[Manager]
${optionalString config.systemd.enableCgroupAccounting ''
@@ -988,76 +498,17 @@ in
${config.systemd.extraConfig}
'';
- "systemd/user.conf".text = ''
- [Manager]
- ${config.systemd.user.extraConfig}
- '';
-
- "systemd/journald.conf".text = ''
- [Journal]
- Storage=persistent
- RateLimitInterval=${config.services.journald.rateLimitInterval}
- RateLimitBurst=${toString config.services.journald.rateLimitBurst}
- ${optionalString (config.services.journald.console != "") ''
- ForwardToConsole=yes
- TTYPath=${config.services.journald.console}
- ''}
- ${optionalString (config.services.journald.forwardToSyslog) ''
- ForwardToSyslog=yes
- ''}
- ${config.services.journald.extraConfig}
- '';
-
- "systemd/coredump.conf".text =
- ''
- [Coredump]
- ${config.systemd.coredump.extraConfig}
- '';
-
- "systemd/logind.conf".text = ''
- [Login]
- KillUserProcesses=${if config.services.logind.killUserProcesses then "yes" else "no"}
- HandleLidSwitch=${config.services.logind.lidSwitch}
- HandleLidSwitchDocked=${config.services.logind.lidSwitchDocked}
- HandleLidSwitchExternalPower=${config.services.logind.lidSwitchExternalPower}
- ${config.services.logind.extraConfig}
- '';
-
"systemd/sleep.conf".text = ''
[Sleep]
${config.systemd.sleep.extraConfig}
'';
- # install provided sysctl snippets
- "sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf";
- "sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf";
-
- "tmpfiles.d".source = (pkgs.symlinkJoin {
- name = "tmpfiles.d";
- paths = map (p: p + "/lib/tmpfiles.d") cfg.tmpfiles.packages;
- postBuild = ''
- for i in $(cat $pathsPath); do
- (test -d "$i" && test $(ls "$i"/*.conf | wc -l) -ge 1) || (
- echo "ERROR: The path '$i' from systemd.tmpfiles.packages contains no *.conf files."
- exit 1
- )
- done
- '' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) ''
- rm -f $out/${removePrefix "tmpfiles.d/" name}
- '') config.system.build.etc.passthru.targets;
- }) + "/*";
-
"systemd/system-generators" = { source = hooks "generators" cfg.generators; };
"systemd/system-shutdown" = { source = hooks "shutdown" cfg.shutdown; };
});
services.dbus.enable = true;
- users.users.systemd-coredump = {
- uid = config.ids.uids.systemd-coredump;
- group = "systemd-coredump";
- };
- users.groups.systemd-coredump = {};
users.users.systemd-network = {
uid = config.ids.uids.systemd-network;
group = "systemd-network";
@@ -1077,36 +528,6 @@ in
unitConfig.X-StopOnReconfiguration = true;
};
- systemd.tmpfiles.packages = [
- # Default tmpfiles rules provided by systemd
- (pkgs.runCommand "systemd-default-tmpfiles" {} ''
- mkdir -p $out/lib/tmpfiles.d
- cd $out/lib/tmpfiles.d
-
- ln -s "${systemd}/example/tmpfiles.d/home.conf"
- ln -s "${systemd}/example/tmpfiles.d/journal-nocow.conf"
- ln -s "${systemd}/example/tmpfiles.d/static-nodes-permissions.conf"
- ln -s "${systemd}/example/tmpfiles.d/systemd.conf"
- ln -s "${systemd}/example/tmpfiles.d/systemd-nologin.conf"
- ln -s "${systemd}/example/tmpfiles.d/systemd-nspawn.conf"
- ln -s "${systemd}/example/tmpfiles.d/systemd-tmp.conf"
- ln -s "${systemd}/example/tmpfiles.d/tmp.conf"
- ln -s "${systemd}/example/tmpfiles.d/var.conf"
- ln -s "${systemd}/example/tmpfiles.d/x11.conf"
- '')
- # User-specified tmpfiles rules
- (pkgs.writeTextFile {
- name = "nixos-tmpfiles.d";
- destination = "/lib/tmpfiles.d/00-nixos.conf";
- text = ''
- # This file is created automatically and should not be modified.
- # Please change the option ‘systemd.tmpfiles.rules’ instead.
-
- ${concatStringsSep "\n" cfg.tmpfiles.rules}
- '';
- })
- ];
-
systemd.units =
mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths
// mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
@@ -1121,14 +542,6 @@ in
(v: let n = escapeSystemdPath v.where;
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
- systemd.user.units =
- mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.user.paths
- // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services
- // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.user.slices
- // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.user.sockets
- // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.user.targets
- // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.user.timers;
-
system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled
[ "DEVTMPFS" "CGROUPS" "INOTIFY_USER" "SIGNALFD" "TIMERFD" "EPOLL" "NET"
"SYSFS" "PROC_FS" "FHANDLE" "CRYPTO_USER_API_HASH" "CRYPTO_HMAC"
@@ -1136,11 +549,6 @@ in
"TMPFS_XATTR" "SECCOMP"
];
- users.groups.systemd-journal.gid = config.ids.gids.systemd-journal;
- users.users.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
- users.users.systemd-journal-gateway.group = "systemd-journal-gateway";
- users.groups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
-
# Generate timer units for all services that have a ‘startAt’ value.
systemd.timers =
mapAttrs (name: service:
@@ -1157,42 +565,14 @@ in
})
(filterAttrs (name: service: service.startAt != []) cfg.user.services);
- systemd.sockets.systemd-journal-gatewayd.wantedBy =
- optional config.services.journald.enableHttpGateway "sockets.target";
-
- # Provide the systemd-user PAM service, required to run systemd
- # user instances.
- security.pam.services.systemd-user =
- { # Ensure that pam_systemd gets included. This is special-cased
- # in systemd to provide XDG_RUNTIME_DIR.
- startSession = true;
- };
-
# Some overrides to upstream units.
systemd.services."systemd-backlight@".restartIfChanged = false;
systemd.services."systemd-fsck@".restartIfChanged = false;
systemd.services."systemd-fsck@".path = [ config.system.path ];
- systemd.services."user@".restartIfChanged = false;
- systemd.services.systemd-journal-flush.restartIfChanged = false;
systemd.services.systemd-random-seed.restartIfChanged = false;
systemd.services.systemd-remount-fs.restartIfChanged = false;
systemd.services.systemd-update-utmp.restartIfChanged = false;
- systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
systemd.services.systemd-udev-settle.restartIfChanged = false; # Causes long delays in nixos-rebuild
- # Restarting systemd-logind breaks X11
- # - upstream commit: https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101
- # - systemd announcement: https://github.com/systemd/systemd/blob/22043e4317ecd2bc7834b48a6d364de76bb26d91/NEWS#L103-L112
- # - this might be addressed in the future by xorg
- #systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
- systemd.services.systemd-logind.restartIfChanged = false;
- systemd.services.systemd-logind.stopIfChanged = false;
- # The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions.
- systemd.services."user-runtime-dir@".stopIfChanged = false;
- systemd.services."user-runtime-dir@".restartIfChanged = false;
- systemd.services.systemd-journald.restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
- systemd.services.systemd-journald.stopIfChanged = false;
- systemd.services."systemd-journald@".restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
- systemd.services."systemd-journald@".stopIfChanged = false;
systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true;
systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true;
systemd.targets.network-online.wantedBy = [ "multi-user.target" ];
@@ -1203,13 +583,30 @@ in
systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container";
systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container";
- boot.kernel.sysctl."kernel.core_pattern" = mkIf (!cfg.coredump.enable) "core";
-
# Increase numeric PID range (set directly instead of copying a one-line file from systemd)
# https://github.com/systemd/systemd/pull/12226
boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304);
boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0";
+
+ services.logrotate.paths = {
+ "/var/log/btmp" = mapAttrs (_: mkDefault) {
+ frequency = "monthly";
+ keep = 1;
+ extraConfig = ''
+ create 0660 root ${config.users.groups.utmp.name}
+ minsize 1M
+ '';
+ };
+ "/var/log/wtmp" = mapAttrs (_: mkDefault) {
+ frequency = "monthly";
+ keep = 1;
+ extraConfig = ''
+ create 0664 root ${config.users.groups.utmp.name}
+ minsize 1M
+ '';
+ };
+ };
};
# FIXME: Remove these eventually.
diff --git a/nixos/modules/system/boot/systemd/coredump.nix b/nixos/modules/system/boot/systemd/coredump.nix
new file mode 100644
index 000000000000..b6ee2cff1f9a
--- /dev/null
+++ b/nixos/modules/system/boot/systemd/coredump.nix
@@ -0,0 +1,57 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+ cfg = config.systemd.coredump;
+ systemd = config.systemd.package;
+in {
+ options = {
+ systemd.coredump.enable = mkOption {
+ default = true;
+ type = types.bool;
+ description = ''
+ Whether core dumps should be processed by
+ systemd-coredump. If disabled, core dumps
+ appear in the current directory of the crashing process.
+ '';
+ };
+
+ systemd.coredump.extraConfig = mkOption {
+ default = "";
+ type = types.lines;
+ example = "Storage=journal";
+ description = ''
+ Extra config options for systemd-coredump. See coredump.conf(5) man page
+ for available options.
+ '';
+ };
+ };
+
+ config = {
+ systemd.additionalUpstreamSystemUnits = [
+ "systemd-coredump.socket"
+ "systemd-coredump@.service"
+ ];
+
+ environment.etc = {
+ "systemd/coredump.conf".text =
+ ''
+ [Coredump]
+ ${cfg.extraConfig}
+ '';
+
+ # install provided sysctl snippets
+ "sysctl.d/50-coredump.conf".source = "${systemd}/example/sysctl.d/50-coredump.conf";
+ "sysctl.d/50-default.conf".source = "${systemd}/example/sysctl.d/50-default.conf";
+ };
+
+ users.users.systemd-coredump = {
+ uid = config.ids.uids.systemd-coredump;
+ group = "systemd-coredump";
+ };
+ users.groups.systemd-coredump = {};
+
+ boot.kernel.sysctl."kernel.core_pattern" = mkIf (!cfg.enable) "core";
+ };
+}
diff --git a/nixos/modules/system/boot/systemd/journald.nix b/nixos/modules/system/boot/systemd/journald.nix
new file mode 100644
index 000000000000..7e14c8ae4077
--- /dev/null
+++ b/nixos/modules/system/boot/systemd/journald.nix
@@ -0,0 +1,131 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.journald;
+in {
+ options = {
+ services.journald.console = mkOption {
+ default = "";
+ type = types.str;
+ description = "If non-empty, write log messages to the specified TTY device.";
+ };
+
+ services.journald.rateLimitInterval = mkOption {
+ default = "30s";
+ type = types.str;
+ description = ''
+ Configures the rate limiting interval that is applied to all
+ messages generated on the system. This rate limiting is applied
+ per-service, so that two services which log do not interfere with
+ each other's limit. The value may be specified in the following
+ units: s, min, h, ms, us. To turn off any kind of rate limiting,
+ set either value to 0.
+
+ See for important
+ considerations when setting this value.
+ '';
+ };
+
+ services.journald.rateLimitBurst = mkOption {
+ default = 10000;
+ type = types.int;
+ description = ''
+ Configures the rate limiting burst limit (number of messages per
+ interval) that is applied to all messages generated on the system.
+ This rate limiting is applied per-service, so that two services
+ which log do not interfere with each other's limit.
+
+ Note that the effective rate limit is multiplied by a factor derived
+ from the available free disk space for the journal as described on
+
+ journald.conf(5).
+
+ Note that the total amount of logs stored is limited by journald settings
+ such as SystemMaxUse, which defaults to a 4 GB cap.
+
+ It is thus recommended to compute what period of time that you will be
+ able to store logs for when an application logs at full burst rate.
+ With default settings for log lines that are 100 Bytes long, this can
+ amount to just a few hours.
+ '';
+ };
+
+ services.journald.extraConfig = mkOption {
+ default = "";
+ type = types.lines;
+ example = "Storage=volatile";
+ description = ''
+ Extra config options for systemd-journald. See man journald.conf
+ for available options.
+ '';
+ };
+
+ services.journald.enableHttpGateway = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Whether to enable the HTTP gateway to the journal.
+ '';
+ };
+
+ services.journald.forwardToSyslog = mkOption {
+ default = config.services.rsyslogd.enable || config.services.syslog-ng.enable;
+ defaultText = literalExpression "services.rsyslogd.enable || services.syslog-ng.enable";
+ type = types.bool;
+ description = ''
+ Whether to forward log messages to syslog.
+ '';
+ };
+ };
+
+ config = {
+ systemd.additionalUpstreamSystemUnits = [
+ "systemd-journald.socket"
+ "systemd-journald@.socket"
+ "systemd-journald-varlink@.socket"
+ "systemd-journald.service"
+ "systemd-journald@.service"
+ "systemd-journal-flush.service"
+ "systemd-journal-catalog-update.service"
+ ] ++ (optional (!config.boot.isContainer) "systemd-journald-audit.socket") ++ [
+ "systemd-journald-dev-log.socket"
+ "syslog.socket"
+ ] ++ optionals cfg.enableHttpGateway [
+ "systemd-journal-gatewayd.socket"
+ "systemd-journal-gatewayd.service"
+ ];
+
+ environment.etc = {
+ "systemd/journald.conf".text = ''
+ [Journal]
+ Storage=persistent
+ RateLimitInterval=${cfg.rateLimitInterval}
+ RateLimitBurst=${toString cfg.rateLimitBurst}
+ ${optionalString (cfg.console != "") ''
+ ForwardToConsole=yes
+ TTYPath=${cfg.console}
+ ''}
+ ${optionalString (cfg.forwardToSyslog) ''
+ ForwardToSyslog=yes
+ ''}
+ ${cfg.extraConfig}
+ '';
+ };
+
+ users.groups.systemd-journal.gid = config.ids.gids.systemd-journal;
+ users.users.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
+ users.users.systemd-journal-gateway.group = "systemd-journal-gateway";
+ users.groups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
+
+ systemd.sockets.systemd-journal-gatewayd.wantedBy =
+ optional cfg.enableHttpGateway "sockets.target";
+
+ systemd.services.systemd-journal-flush.restartIfChanged = false;
+ systemd.services.systemd-journald.restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
+ systemd.services.systemd-journald.stopIfChanged = false;
+ systemd.services."systemd-journald@".restartTriggers = [ config.environment.etc."systemd/journald.conf".source ];
+ systemd.services."systemd-journald@".stopIfChanged = false;
+ };
+}
diff --git a/nixos/modules/system/boot/systemd/logind.nix b/nixos/modules/system/boot/systemd/logind.nix
new file mode 100644
index 000000000000..c1e6cfe61d04
--- /dev/null
+++ b/nixos/modules/system/boot/systemd/logind.nix
@@ -0,0 +1,114 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+ cfg = config.services.logind;
+
+ logindHandlerType = types.enum [
+ "ignore" "poweroff" "reboot" "halt" "kexec" "suspend"
+ "hibernate" "hybrid-sleep" "suspend-then-hibernate" "lock"
+ ];
+in
+{
+ options = {
+ services.logind.extraConfig = mkOption {
+ default = "";
+ type = types.lines;
+ example = "IdleAction=lock";
+ description = ''
+ Extra config options for systemd-logind. See
+
+ logind.conf(5) for available options.
+ '';
+ };
+
+ services.logind.killUserProcesses = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Specifies whether the processes of a user should be killed
+ when the user logs out. If true, the scope unit corresponding
+ to the session and all processes inside that scope will be
+ terminated. If false, the scope is "abandoned" (see
+
+ systemd.scope(5)), and processes are not killed.
+
+
+
+ See logind.conf(5)
+ for more details.
+ '';
+ };
+
+ services.logind.lidSwitch = mkOption {
+ default = "suspend";
+ example = "ignore";
+ type = logindHandlerType;
+
+ description = ''
+ Specifies what to be done when the laptop lid is closed.
+ '';
+ };
+
+ services.logind.lidSwitchDocked = mkOption {
+ default = "ignore";
+ example = "suspend";
+ type = logindHandlerType;
+
+ description = ''
+ Specifies what to be done when the laptop lid is closed
+ and another screen is added.
+ '';
+ };
+
+ services.logind.lidSwitchExternalPower = mkOption {
+ default = cfg.lidSwitch;
+ defaultText = literalExpression "services.logind.lidSwitch";
+ example = "ignore";
+ type = logindHandlerType;
+
+ description = ''
+ Specifies what to do when the laptop lid is closed and the system is
+ on external power. By default use the same action as specified in
+ services.logind.lidSwitch.
+ '';
+ };
+ };
+
+ config = {
+ systemd.additionalUpstreamSystemUnits = [
+ "systemd-logind.service"
+ "autovt@.service"
+ "systemd-user-sessions.service"
+ "dbus-org.freedesktop.import1.service"
+ "dbus-org.freedesktop.machine1.service"
+ "dbus-org.freedesktop.login1.service"
+ "user@.service"
+ "user-runtime-dir@.service"
+ ];
+
+ environment.etc = {
+ "systemd/logind.conf".text = ''
+ [Login]
+ KillUserProcesses=${if cfg.killUserProcesses then "yes" else "no"}
+ HandleLidSwitch=${cfg.lidSwitch}
+ HandleLidSwitchDocked=${cfg.lidSwitchDocked}
+ HandleLidSwitchExternalPower=${cfg.lidSwitchExternalPower}
+ ${cfg.extraConfig}
+ '';
+ };
+
+ # Restarting systemd-logind breaks X11
+ # - upstream commit: https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101
+ # - systemd announcement: https://github.com/systemd/systemd/blob/22043e4317ecd2bc7834b48a6d364de76bb26d91/NEWS#L103-L112
+ # - this might be addressed in the future by xorg
+ #systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ];
+ systemd.services.systemd-logind.restartIfChanged = false;
+ systemd.services.systemd-logind.stopIfChanged = false;
+
+ # The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions.
+ systemd.services."user-runtime-dir@".stopIfChanged = false;
+ systemd.services."user-runtime-dir@".restartIfChanged = false;
+ };
+}
diff --git a/nixos/modules/system/boot/systemd-nspawn.nix b/nixos/modules/system/boot/systemd/nspawn.nix
similarity index 86%
rename from nixos/modules/system/boot/systemd-nspawn.nix
rename to nixos/modules/system/boot/systemd/nspawn.nix
index 02d2660add89..0c6822319a5b 100644
--- a/nixos/modules/system/boot/systemd-nspawn.nix
+++ b/nixos/modules/system/boot/systemd/nspawn.nix
@@ -120,14 +120,6 @@ in {
})
{
systemd.targets.multi-user.wants = [ "machines.target" ];
-
- # Workaround for https://github.com/NixOS/nixpkgs/pull/67232#issuecomment-531315437 and https://github.com/systemd/systemd/issues/13622
- # Once systemd fixes this upstream, we can re-enable -U
- systemd.services."systemd-nspawn@".serviceConfig.ExecStart = [
- "" # deliberately empty. signals systemd to override the ExecStart
- # Only difference between upstream is that we do not pass the -U flag
- "${config.systemd.package}/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth --settings=override --machine=%i"
- ];
}
];
}
diff --git a/nixos/modules/system/boot/systemd/tmpfiles.nix b/nixos/modules/system/boot/systemd/tmpfiles.nix
new file mode 100644
index 000000000000..57d44c8591ed
--- /dev/null
+++ b/nixos/modules/system/boot/systemd/tmpfiles.nix
@@ -0,0 +1,104 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+ cfg = config.systemd.tmpfiles;
+ systemd = config.systemd.package;
+in
+{
+ options = {
+ systemd.tmpfiles.rules = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "d /tmp 1777 root root 10d" ];
+ description = ''
+ Rules for creation, deletion and cleaning of volatile and temporary files
+ automatically. See
+ tmpfiles.d5
+ for the exact format.
+ '';
+ };
+
+ systemd.tmpfiles.packages = mkOption {
+ type = types.listOf types.package;
+ default = [];
+ example = literalExpression "[ pkgs.lvm2 ]";
+ apply = map getLib;
+ description = ''
+ List of packages containing systemd-tmpfiles rules.
+
+ All files ending in .conf found in
+ pkg/lib/tmpfiles.d
+ will be included.
+ If this folder does not exist or does not contain any files an error will be returned instead.
+
+ If a lib output is available, rules are searched there and only there.
+ If there is no lib output it will fall back to out
+ and if that does not exist either, the default output will be used.
+ '';
+ };
+ };
+
+ config = {
+ systemd.additionalUpstreamSystemUnits = [
+ "systemd-tmpfiles-clean.service"
+ "systemd-tmpfiles-clean.timer"
+ "systemd-tmpfiles-setup.service"
+ "systemd-tmpfiles-setup-dev.service"
+ ];
+
+ systemd.additionalUpstreamUserUnits = [
+ "systemd-tmpfiles-clean.service"
+ "systemd-tmpfiles-clean.timer"
+ "systemd-tmpfiles-setup.service"
+ ];
+
+ environment.etc = {
+ "tmpfiles.d".source = (pkgs.symlinkJoin {
+ name = "tmpfiles.d";
+ paths = map (p: p + "/lib/tmpfiles.d") cfg.packages;
+ postBuild = ''
+ for i in $(cat $pathsPath); do
+ (test -d "$i" && test $(ls "$i"/*.conf | wc -l) -ge 1) || (
+ echo "ERROR: The path '$i' from systemd.tmpfiles.packages contains no *.conf files."
+ exit 1
+ )
+ done
+ '' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) ''
+ rm -f $out/${removePrefix "tmpfiles.d/" name}
+ '') config.system.build.etc.passthru.targets;
+ }) + "/*";
+ };
+
+ systemd.tmpfiles.packages = [
+ # Default tmpfiles rules provided by systemd
+ (pkgs.runCommand "systemd-default-tmpfiles" {} ''
+ mkdir -p $out/lib/tmpfiles.d
+ cd $out/lib/tmpfiles.d
+
+ ln -s "${systemd}/example/tmpfiles.d/home.conf"
+ ln -s "${systemd}/example/tmpfiles.d/journal-nocow.conf"
+ ln -s "${systemd}/example/tmpfiles.d/static-nodes-permissions.conf"
+ ln -s "${systemd}/example/tmpfiles.d/systemd.conf"
+ ln -s "${systemd}/example/tmpfiles.d/systemd-nologin.conf"
+ ln -s "${systemd}/example/tmpfiles.d/systemd-nspawn.conf"
+ ln -s "${systemd}/example/tmpfiles.d/systemd-tmp.conf"
+ ln -s "${systemd}/example/tmpfiles.d/tmp.conf"
+ ln -s "${systemd}/example/tmpfiles.d/var.conf"
+ ln -s "${systemd}/example/tmpfiles.d/x11.conf"
+ '')
+ # User-specified tmpfiles rules
+ (pkgs.writeTextFile {
+ name = "nixos-tmpfiles.d";
+ destination = "/lib/tmpfiles.d/00-nixos.conf";
+ text = ''
+ # This file is created automatically and should not be modified.
+ # Please change the option ‘systemd.tmpfiles.rules’ instead.
+
+ ${concatStringsSep "\n" cfg.rules}
+ '';
+ })
+ ];
+ };
+}
diff --git a/nixos/modules/system/boot/systemd/user.nix b/nixos/modules/system/boot/systemd/user.nix
new file mode 100644
index 000000000000..e30f83f3457f
--- /dev/null
+++ b/nixos/modules/system/boot/systemd/user.nix
@@ -0,0 +1,158 @@
+{ config, lib, pkgs, utils, ... }:
+with utils;
+with systemdUtils.unitOptions;
+with lib;
+
+let
+ cfg = config.systemd.user;
+
+ systemd = config.systemd.package;
+
+ inherit
+ (systemdUtils.lib)
+ makeUnit
+ generateUnits
+ makeJobScript
+ unitConfig
+ serviceConfig
+ commonUnitText
+ targetToUnit
+ serviceToUnit
+ socketToUnit
+ timerToUnit
+ pathToUnit;
+
+ upstreamUserUnits = [
+ "app.slice"
+ "background.slice"
+ "basic.target"
+ "bluetooth.target"
+ "default.target"
+ "exit.target"
+ "graphical-session-pre.target"
+ "graphical-session.target"
+ "paths.target"
+ "printer.target"
+ "session.slice"
+ "shutdown.target"
+ "smartcard.target"
+ "sockets.target"
+ "sound.target"
+ "systemd-exit.service"
+ "timers.target"
+ "xdg-desktop-autostart.target"
+ ] ++ config.systemd.additionalUpstreamUserUnits;
+in {
+ options = {
+ systemd.user.extraConfig = mkOption {
+ default = "";
+ type = types.lines;
+ example = "DefaultCPUAccounting=yes";
+ description = ''
+ Extra config options for systemd user instances. See man systemd-user.conf for
+ available options.
+ '';
+ };
+
+ systemd.user.units = mkOption {
+ description = "Definition of systemd per-user units.";
+ default = {};
+ type = with types; attrsOf (submodule (
+ { name, config, ... }:
+ { options = concreteUnitOptions;
+ config = {
+ unit = mkDefault (makeUnit name config);
+ };
+ }));
+ };
+
+ systemd.user.paths = mkOption {
+ default = {};
+ type = with types; attrsOf (submodule [ { options = pathOptions; } unitConfig ]);
+ description = "Definition of systemd per-user path units.";
+ };
+
+ systemd.user.services = mkOption {
+ default = {};
+ type = with types; attrsOf (submodule [ { options = serviceOptions; } unitConfig serviceConfig ] );
+ description = "Definition of systemd per-user service units.";
+ };
+
+ systemd.user.slices = mkOption {
+ default = {};
+ type = with types; attrsOf (submodule [ { options = sliceOptions; } unitConfig ] );
+ description = "Definition of systemd per-user slice units.";
+ };
+
+ systemd.user.sockets = mkOption {
+ default = {};
+ type = with types; attrsOf (submodule [ { options = socketOptions; } unitConfig ] );
+ description = "Definition of systemd per-user socket units.";
+ };
+
+ systemd.user.targets = mkOption {
+ default = {};
+ type = with types; attrsOf (submodule [ { options = targetOptions; } unitConfig] );
+ description = "Definition of systemd per-user target units.";
+ };
+
+ systemd.user.timers = mkOption {
+ default = {};
+ type = with types; attrsOf (submodule [ { options = timerOptions; } unitConfig ] );
+ description = "Definition of systemd per-user timer units.";
+ };
+
+ systemd.additionalUpstreamUserUnits = mkOption {
+ default = [];
+ type = types.listOf types.str;
+ example = [];
+ description = ''
+ Additional units shipped with systemd that should be enabled for per-user systemd instances.
+ '';
+ internal = true;
+ };
+ };
+
+ config = {
+ systemd.additionalUpstreamSystemUnits = [
+ "user.slice"
+ ];
+
+ environment.etc = {
+ "systemd/user".source = generateUnits "user" cfg.units upstreamUserUnits [];
+
+ "systemd/user.conf".text = ''
+ [Manager]
+ ${cfg.extraConfig}
+ '';
+ };
+
+ systemd.user.units =
+ mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit n v)) cfg.paths
+ // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
+ // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit n v)) cfg.slices
+ // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets
+ // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
+ // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit n v)) cfg.timers;
+
+ # Generate timer units for all services that have a ‘startAt’ value.
+ systemd.user.timers =
+ mapAttrs (name: service: {
+ wantedBy = ["timers.target"];
+ timerConfig.OnCalendar = service.startAt;
+ })
+ (filterAttrs (name: service: service.startAt != []) cfg.services);
+
+ # Provide the systemd-user PAM service, required to run systemd
+ # user instances.
+ security.pam.services.systemd-user =
+ { # Ensure that pam_systemd gets included. This is special-cased
+ # in systemd to provide XDG_RUNTIME_DIR.
+ startSession = true;
+ };
+
+ # Some overrides to upstream units.
+ systemd.services."user@".restartIfChanged = false;
+ systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
+ };
+}
diff --git a/nixos/modules/system/boot/tmp.nix b/nixos/modules/system/boot/tmp.nix
index 6edafd6695b6..cf6d19eb5f0e 100644
--- a/nixos/modules/system/boot/tmp.nix
+++ b/nixos/modules/system/boot/tmp.nix
@@ -48,7 +48,12 @@ in
what = "tmpfs";
where = "/tmp";
type = "tmpfs";
- mountConfig.Options = [ "mode=1777" "strictatime" "rw" "nosuid" "nodev" "size=${toString cfg.tmpOnTmpfsSize}" ];
+ mountConfig.Options = concatStringsSep "," [ "mode=1777"
+ "strictatime"
+ "rw"
+ "nosuid"
+ "nodev"
+ "size=${toString cfg.tmpOnTmpfsSize}" ];
}
];
diff --git a/nixos/modules/system/etc/etc-activation.nix b/nixos/modules/system/etc/etc-activation.nix
new file mode 100644
index 000000000000..780104950186
--- /dev/null
+++ b/nixos/modules/system/etc/etc-activation.nix
@@ -0,0 +1,12 @@
+{ config, lib, ... }:
+let
+ inherit (lib) stringAfter;
+in {
+
+ imports = [ ./etc.nix ];
+
+ config = {
+ system.activationScripts.etc =
+ stringAfter [ "users" "groups" ] config.system.build.etcActivationCommands;
+ };
+}
diff --git a/nixos/modules/system/etc/etc.nix b/nixos/modules/system/etc/etc.nix
index 6cc8c341e6df..ed552fecec53 100644
--- a/nixos/modules/system/etc/etc.nix
+++ b/nixos/modules/system/etc/etc.nix
@@ -66,6 +66,8 @@ in
{
+ imports = [ ../build.nix ];
+
###### interface
options = {
@@ -188,14 +190,12 @@ in
config = {
system.build.etc = etc;
-
- system.activationScripts.etc = stringAfter [ "users" "groups" ]
+ system.build.etcActivationCommands =
''
# Set up the statically computed bits of /etc.
echo "setting up /etc..."
${pkgs.perl.withPackages (p: [ p.FileSlurp ])}/bin/perl ${./setup-etc.pl} ${etc}/etc
'';
-
};
}
diff --git a/nixos/modules/system/etc/test.nix b/nixos/modules/system/etc/test.nix
new file mode 100644
index 000000000000..5e43b155038d
--- /dev/null
+++ b/nixos/modules/system/etc/test.nix
@@ -0,0 +1,70 @@
+{ lib
+, coreutils
+, fakechroot
+, fakeroot
+, evalMinimalConfig
+, pkgsModule
+, runCommand
+, util-linux
+, vmTools
+, writeText
+}:
+let
+ node = evalMinimalConfig ({ config, ... }: {
+ imports = [ pkgsModule ../etc/etc.nix ];
+ environment.etc."passwd" = {
+ text = passwdText;
+ };
+ environment.etc."hosts" = {
+ text = hostsText;
+ mode = "0751";
+ };
+ });
+ passwdText = ''
+ root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash
+ '';
+ hostsText = ''
+ 127.0.0.1 localhost
+ ::1 localhost
+ # testing...
+ '';
+in
+lib.recurseIntoAttrs {
+ test-etc-vm =
+ vmTools.runInLinuxVM (runCommand "test-etc-vm" { } ''
+ mkdir -p /etc
+ ${node.config.system.build.etcActivationCommands}
+ set -x
+ [[ -L /etc/passwd ]]
+ diff /etc/passwd ${writeText "expected-passwd" passwdText}
+ [[ 751 = $(stat --format %a /etc/hosts) ]]
+ diff /etc/hosts ${writeText "expected-hosts" hostsText}
+ set +x
+ touch $out
+ '');
+
+ # fakeroot is behaving weird
+ test-etc-fakeroot =
+ runCommand "test-etc"
+ {
+ nativeBuildInputs = [
+ fakeroot
+ fakechroot
+ # for chroot
+ coreutils
+ # fakechroot needs getopt, which is provided by util-linux
+ util-linux
+ ];
+ fakeRootCommands = ''
+ mkdir -p /etc
+ ${node.config.system.build.etcActivationCommands}
+ diff /etc/hosts ${writeText "expected-hosts" hostsText}
+ touch $out
+ '';
+ } ''
+ mkdir fake-root
+ export FAKECHROOT_EXCLUDE_PATH=/dev:/proc:/sys:${builtins.storeDir}:$out
+ fakechroot fakeroot chroot $PWD/fake-root bash -c 'source $stdenv/setup; eval "$fakeRootCommands"'
+ '';
+
+}
diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix
index b931b27ad817..1404dcbaf7c0 100644
--- a/nixos/modules/tasks/auto-upgrade.nix
+++ b/nixos/modules/tasks/auto-upgrade.nix
@@ -80,6 +80,7 @@ in {
Reboot the system into the new generation instead of a switch
if the new generation uses a different kernel, kernel modules
or initrd than the booted system.
+ See for configuring the times at which a reboot is allowed.
'';
};
@@ -96,6 +97,32 @@ in {
'';
};
+ rebootWindow = mkOption {
+ description = ''
+ Define a lower and upper time value (in HH:MM format) which
+ constitute a time window during which reboots are allowed after an upgrade.
+ This option only has an effect when is enabled.
+ The default value of null means that reboots are allowed at any time.
+ '';
+ default = null;
+ example = { lower = "01:00"; upper = "05:00"; };
+ type = with types; nullOr (submodule {
+ options = {
+ lower = mkOption {
+ description = "Lower limit of the reboot window";
+ type = types.strMatching "[[:digit:]]{2}:[[:digit:]]{2}";
+ example = "01:00";
+ };
+
+ upper = mkOption {
+ description = "Upper limit of the reboot window";
+ type = types.strMatching "[[:digit:]]{2}:[[:digit:]]{2}";
+ example = "05:00";
+ };
+ };
+ });
+ };
+
};
};
@@ -110,12 +137,10 @@ in {
}];
system.autoUpgrade.flags = (if cfg.flake == null then
- [ "--no-build-output" ] ++ (if cfg.channel == null then
- [ "--upgrade" ]
- else [
+ [ "--no-build-output" ] ++ optionals (cfg.channel != null) [
"-I"
"nixpkgs=${cfg.channel}/nixexprs.tar.xz"
- ])
+ ]
else
[ "--flake ${cfg.flake}" ]);
@@ -143,19 +168,52 @@ in {
];
script = let
- nixos-rebuild =
- "${config.system.build.nixos-rebuild}/bin/nixos-rebuild";
+ nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild";
+ date = "${pkgs.coreutils}/bin/date";
+ readlink = "${pkgs.coreutils}/bin/readlink";
+ shutdown = "${pkgs.systemd}/bin/shutdown";
+ upgradeFlag = optional (cfg.channel == null) "--upgrade";
in if cfg.allowReboot then ''
- ${nixos-rebuild} boot ${toString cfg.flags}
- booted="$(readlink /run/booted-system/{initrd,kernel,kernel-modules})"
- built="$(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
- if [ "$booted" = "$built" ]; then
+ ${nixos-rebuild} boot ${toString (cfg.flags ++ upgradeFlag)}
+ booted="$(${readlink} /run/booted-system/{initrd,kernel,kernel-modules})"
+ built="$(${readlink} /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
+
+ ${optionalString (cfg.rebootWindow != null) ''
+ current_time="$(${date} +%H:%M)"
+
+ lower="${cfg.rebootWindow.lower}"
+ upper="${cfg.rebootWindow.upper}"
+
+ if [[ "''${lower}" < "''${upper}" ]]; then
+ if [[ "''${current_time}" > "''${lower}" ]] && \
+ [[ "''${current_time}" < "''${upper}" ]]; then
+ do_reboot="true"
+ else
+ do_reboot="false"
+ fi
+ else
+ # lower > upper, so we are crossing midnight (e.g. lower=23h, upper=6h)
+ # we want to reboot if cur > 23h or cur < 6h
+ if [[ "''${current_time}" < "''${upper}" ]] || \
+ [[ "''${current_time}" > "''${lower}" ]]; then
+ do_reboot="true"
+ else
+ do_reboot="false"
+ fi
+ fi
+ ''}
+
+ if [ "''${booted}" = "''${built}" ]; then
${nixos-rebuild} switch ${toString cfg.flags}
+ ${optionalString (cfg.rebootWindow != null) ''
+ elif [ "''${do_reboot}" != true ]; then
+ echo "Outside of configured reboot window, skipping."
+ ''}
else
- /run/current-system/sw/bin/shutdown -r +1
+ ${shutdown} -r +1
fi
'' else ''
- ${nixos-rebuild} switch ${toString cfg.flags}
+ ${nixos-rebuild} switch ${toString (cfg.flags ++ upgradeFlag)}
'';
startAt = cfg.dates;
@@ -167,3 +225,4 @@ in {
};
}
+
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index 225bcbe58e01..d68edd8d7d39 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -215,6 +215,35 @@ in
'';
};
+ boot.devSize = mkOption {
+ default = "5%";
+ example = "32m";
+ type = types.str;
+ description = ''
+ Size limit for the /dev tmpfs. Look at mount(8), tmpfs size option,
+ for the accepted syntax.
+ '';
+ };
+
+ boot.devShmSize = mkOption {
+ default = "50%";
+ example = "256m";
+ type = types.str;
+ description = ''
+ Size limit for the /dev/shm tmpfs. Look at mount(8), tmpfs size option,
+ for the accepted syntax.
+ '';
+ };
+
+ boot.runSize = mkOption {
+ default = "25%";
+ example = "256m";
+ type = types.str;
+ description = ''
+ Size limit for the /run tmpfs. Look at mount(8), tmpfs size option,
+ for the accepted syntax.
+ '';
+ };
};
@@ -250,7 +279,7 @@ in
environment.etc.fstab.text =
let
- fsToSkipCheck = [ "none" "bindfs" "btrfs" "zfs" "tmpfs" "nfs" "vboxsf" "glusterfs" ];
+ fsToSkipCheck = [ "none" "bindfs" "btrfs" "zfs" "tmpfs" "nfs" "vboxsf" "glusterfs" "apfs" ];
skipCheck = fs: fs.noCheck || fs.device == "none" || builtins.elem fs.fsType fsToSkipCheck;
# https://wiki.archlinux.org/index.php/fstab#Filepath_spaces
escape = string: builtins.replaceStrings [ " " "\t" ] [ "\\040" "\\011" ] string;
diff --git a/nixos/modules/tasks/filesystems/apfs.nix b/nixos/modules/tasks/filesystems/apfs.nix
new file mode 100644
index 000000000000..2f2be351df61
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/apfs.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ inInitrd = any (fs: fs == "apfs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+ config = mkIf (any (fs: fs == "apfs") config.boot.supportedFilesystems) {
+
+ system.fsPackages = [ pkgs.apfsprogs ];
+
+ boot.extraModulePackages = [ config.boot.kernelPackages.apfs ];
+
+ boot.initrd.kernelModules = mkIf inInitrd [ "apfs" ];
+
+ # Don't copy apfsck into the initramfs since it does not support repairing the filesystem
+ };
+}
diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index 19f2be2c4a25..b0f160c1dbf9 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -535,6 +535,7 @@ let
createGreDevice = n: v: nameValuePair "${n}-netdev"
(let
deps = deviceDependency v.dev;
+ ttlarg = if lib.hasPrefix "ip6" v.type then "hoplimit" else "ttl";
in
{ description = "GRE Tunnel Interface ${n}";
wantedBy = [ "network-setup.service" (subsystemDevice n) ];
@@ -551,6 +552,7 @@ let
ip link add name "${n}" type ${v.type} \
${optionalString (v.remote != null) "remote \"${v.remote}\""} \
${optionalString (v.local != null) "local \"${v.local}\""} \
+ ${optionalString (v.ttl != null) "${ttlarg} ${toString v.ttl}"} \
${optionalString (v.dev != null) "dev \"${v.dev}\""}
ip link set "${n}" up
'';
diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix
index 8a5e1b5af114..8654539b6629 100644
--- a/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -318,6 +318,8 @@ in
Remote = gre.remote;
}) // (optionalAttrs (gre.local != null) {
Local = gre.local;
+ }) // (optionalAttrs (gre.ttl != null) {
+ TTL = gre.ttl;
});
};
networks = mkIf (gre.dev != null) {
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 1dac405ac309..8ca4ad7b7d86 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -305,7 +305,7 @@ let
enable = mkOption {
type = types.bool;
default = false;
- description = "Wether to enable wol on this interface.";
+ description = "Whether to enable wol on this interface.";
};
};
};
@@ -1020,6 +1020,14 @@ in
local = "10.0.0.22";
dev = "enp4s0f0";
type = "tap";
+ ttl = 255;
+ };
+ gre6Tunnel = {
+ remote = "fd7a:5634::1";
+ local = "fd7a:5634::2";
+ dev = "enp4s0f0";
+ type = "tun6";
+ ttl = 255;
};
}
'';
@@ -1057,11 +1065,25 @@ in
'';
};
+ ttl = mkOption {
+ type = types.nullOr types.int;
+ default = null;
+ example = 255;
+ description = ''
+ The time-to-live/hoplimit of the connection to the remote tunnel endpoint.
+ '';
+ };
+
type = mkOption {
- type = with types; enum [ "tun" "tap" ];
+ type = with types; enum [ "tun" "tap" "tun6" "tap6" ];
default = "tap";
example = "tap";
- apply = v: if v == "tun" then "gre" else "gretap";
+ apply = v: {
+ tun = "gre";
+ tap = "gretap";
+ tun6 = "ip6gre";
+ tap6 = "ip6gretap";
+ }.${v};
description = ''
Whether the tunnel routes layer 2 (tap) or layer 3 (tun) traffic.
'';
@@ -1325,22 +1347,13 @@ in
val = tempaddrValues.${opt}.sysctl;
in nameValuePair "net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr" val));
- # Capabilities won't work unless we have at-least a 4.3 Linux
- # kernel because we need the ambient capability
- security.wrappers = if (versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.3") then {
+ security.wrappers = {
ping = {
owner = "root";
group = "root";
capabilities = "cap_net_raw+p";
source = "${pkgs.iputils.out}/bin/ping";
};
- } else {
- ping = {
- setuid = true;
- owner = "root";
- group = "root";
- source = "${pkgs.iputils.out}/bin/ping";
- };
};
security.apparmor.policies."bin.ping".profile = lib.mkIf config.security.apparmor.policies."bin.ping".enable (lib.mkAfter ''
/run/wrappers/bin/ping {
@@ -1438,7 +1451,7 @@ in
sysctl-value = tempaddrValues.${cfg.tempAddresses}.sysctl;
in ''
# enable and prefer IPv6 privacy addresses by default
- ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo ${sysctl-value} > /proc/sys/net/ipv6/conf/%k/use_tempaddr'"
+ ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo ${sysctl-value} > /proc/sys/net/ipv6/conf/$name/use_tempaddr'"
'';
})
(pkgs.writeTextFile rec {
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index a7011be7e042..01447e6ada87 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -109,6 +109,10 @@ in
# Allow very slow start
DefaultTimeoutStartSec=300
'';
+ systemd.user.extraConfig = ''
+ # Allow very slow start
+ DefaultTimeoutStartSec=300
+ '';
boot.consoleLogLevel = 7;
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index fe248a94488b..9a56b6950155 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -37,8 +37,13 @@ in
{ assertion = cfg.efi -> cfg.hvm;
message = "EC2 instances using EFI must be HVM instances.";
}
+ { assertion = versionOlder config.boot.kernelPackages.kernel.version "5.15";
+ message = "ENA driver fails to build with kernel >= 5.15";
+ }
];
+ boot.kernelPackages = pkgs.linuxKernel.packages.linux_5_10;
+
boot.growPartition = cfg.hvm;
fileSystems."/" = mkIf (!cfg.zfs.enable) {
@@ -155,7 +160,7 @@ in
systemd.services."serial-getty@ttyS0".enable = true;
# Creates symlinks for block device names.
- services.udev.packages = [ pkgs.ec2-utils ];
+ services.udev.packages = [ pkgs.amazon-ec2-utils ];
# Force getting the hostname from EC2.
networking.hostName = mkDefault "";
diff --git a/nixos/modules/virtualisation/containerd.nix b/nixos/modules/virtualisation/containerd.nix
index 898a66e7b04e..ea89a994b172 100644
--- a/nixos/modules/virtualisation/containerd.nix
+++ b/nixos/modules/virtualisation/containerd.nix
@@ -53,6 +53,7 @@ in
virtualisation.containerd = {
args.config = toString containerdConfigChecked;
settings = {
+ version = 2;
plugins."io.containerd.grpc.v1.cri" = {
containerd.snapshotter =
lib.mkIf config.boot.zfs.enabled (lib.mkOptionDefault "zfs");
diff --git a/nixos/modules/virtualisation/docker-rootless.nix b/nixos/modules/virtualisation/docker-rootless.nix
index 0e7f05031420..d371f67ecdc8 100644
--- a/nixos/modules/virtualisation/docker-rootless.nix
+++ b/nixos/modules/virtualisation/docker-rootless.nix
@@ -76,7 +76,11 @@ in
# needs newuidmap from pkgs.shadow
path = [ "/run/wrappers" ];
environment = proxy_env;
- unitConfig.StartLimitInterval = "60s";
+ unitConfig = {
+ # docker-rootless doesn't support running as root.
+ ConditionUser = "!root";
+ StartLimitInterval = "60s";
+ };
serviceConfig = {
Type = "notify";
ExecStart = "${cfg.package}/bin/dockerd-rootless --config-file=${daemonSettingsFile}";
diff --git a/nixos/modules/virtualisation/fetch-instance-ssh-keys.bash b/nixos/modules/virtualisation/fetch-instance-ssh-keys.bash
deleted file mode 100644
index 4a8601961115..000000000000
--- a/nixos/modules/virtualisation/fetch-instance-ssh-keys.bash
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-WGET() {
- wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google' "$@"
-}
-
-# When dealing with cryptographic keys, we want to keep things private.
-umask 077
-mkdir -p /root/.ssh
-
-echo "Fetching authorized keys..."
-WGET -O /tmp/auth_keys http://metadata.google.internal/computeMetadata/v1/instance/attributes/sshKeys
-
-# Read keys one by one, split in case Google decided
-# to append metadata (it does sometimes) and add to
-# authorized_keys if not already present.
-touch /root/.ssh/authorized_keys
-while IFS='' read -r line || [[ -n "$line" ]]; do
- keyLine=$(echo -n "$line" | cut -d ':' -f2)
- IFS=' ' read -r -a array <<<"$keyLine"
- if [[ ${#array[@]} -ge 3 ]]; then
- echo "${array[@]:0:3}" >>/tmp/new_keys
- echo "Added ${array[*]:2} to authorized_keys"
- fi
-done image attribute, as it
- will be used as the image name for docker to start a container.
+ The image attribute must match the name and
+ tag of the image contained in this file, as they will be used to
+ run the container with that image. If they do not match, the
+ image will be pulled from the registry as usual.
'';
example = literalExpression "pkgs.dockerTools.buildImage {...};";
};
diff --git a/nixos/modules/virtualisation/openstack-metadata-fetcher.nix b/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
index 133cd4c0e9f9..25104bb47667 100644
--- a/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
+++ b/nixos/modules/virtualisation/openstack-metadata-fetcher.nix
@@ -15,7 +15,8 @@
}
wget_imds -O "$metaDir/ami-manifest-path" http://169.254.169.254/1.0/meta-data/ami-manifest-path
- (umask 077 && wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data)
+ # When no user-data is provided, the OpenStack metadata server doesn't expose the user-data route.
+ (umask 077 && wget_imds -O "$metaDir/user-data" http://169.254.169.254/1.0/user-data || rm -f "$metaDir/user-data")
wget_imds -O "$metaDir/hostname" http://169.254.169.254/1.0/meta-data/hostname
wget_imds -O "$metaDir/public-keys-0-openssh-key" http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
''
diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix
index 325f6f5b43f4..436a375fb5eb 100644
--- a/nixos/modules/virtualisation/openvswitch.nix
+++ b/nixos/modules/virtualisation/openvswitch.nix
@@ -36,17 +36,6 @@ in {
Open vSwitch package to use.
'';
};
-
- ipsec = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to start racoon service for openvswitch.
- Supported only if openvswitch version is less than 2.6.0.
- Use virtualisation.vswitch.package = pkgs.openvswitch-lts
- for a version that supports ipsec over GRE.
- '';
- };
};
config = mkIf cfg.enable (let
@@ -65,7 +54,7 @@ in {
installPhase = "mkdir -p $out";
};
- in (mkMerge [{
+ in {
environment.systemPackages = [ cfg.package ];
boot.kernelModules = [ "tun" "openvswitch" ];
@@ -142,48 +131,14 @@ in {
};
};
- }
- (mkIf (cfg.ipsec && (versionOlder cfg.package.version "2.6.0")) {
- environment.systemPackages = [ pkgs.ipsecTools ];
+ });
- services.racoon.enable = true;
- services.racoon.configPath = "${runDir}/ipsec/etc/racoon/racoon.conf";
-
- networking.firewall.extraCommands = ''
- iptables -I INPUT -t mangle -p esp -j MARK --set-mark 1/1
- iptables -I INPUT -t mangle -p udp --dport 4500 -j MARK --set-mark 1/1
- '';
-
- systemd.services.ovs-monitor-ipsec = {
- description = "Open_vSwitch Ipsec Daemon";
- wantedBy = [ "multi-user.target" ];
- requires = [ "ovsdb.service" ];
- before = [ "vswitchd.service" "racoon.service" ];
- environment.UNIXCTLPATH = "/tmp/ovsdb.ctl.sock";
- serviceConfig = {
- ExecStart = ''
- ${cfg.package}/bin/ovs-monitor-ipsec \
- --root-prefix ${runDir}/ipsec \
- --pidfile /run/openvswitch/ovs-monitor-ipsec.pid \
- --monitor --detach \
- unix:/run/openvswitch/db.sock
- '';
- PIDFile = "/run/openvswitch/ovs-monitor-ipsec.pid";
- # Use service type 'forking' to correctly determine when ovs-monitor-ipsec is ready.
- Type = "forking";
- };
-
- preStart = ''
- rm -r ${runDir}/ipsec/etc/racoon/certs || true
- mkdir -p ${runDir}/ipsec/{etc/racoon,etc/init.d/,usr/sbin/}
- ln -fs ${pkgs.ipsecTools}/bin/setkey ${runDir}/ipsec/usr/sbin/setkey
- ln -fs ${pkgs.writeScript "racoon-restart" ''
- #!${pkgs.runtimeShell}
- /run/current-system/sw/bin/systemctl $1 racoon
- ''} ${runDir}/ipsec/etc/init.d/racoon
- '';
- };
- })]));
+ imports = [
+ (mkRemovedOptionModule [ "virtualisation" "vswitch" "ipsec" ] ''
+ OpenVSwitch IPSec functionality has been removed, because it depended on racoon,
+ which was removed from nixpkgs, because it was abanoded upstream.
+ '')
+ ];
meta.maintainers = with maintainers; [ netixx ];
diff --git a/nixos/modules/virtualisation/proxmox-lxc.nix b/nixos/modules/virtualisation/proxmox-lxc.nix
new file mode 100644
index 000000000000..3913b474afbe
--- /dev/null
+++ b/nixos/modules/virtualisation/proxmox-lxc.nix
@@ -0,0 +1,64 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+{
+ options.proxmoxLXC = {
+ privileged = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable privileged mounts
+ '';
+ };
+ manageNetwork = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to manage network interfaces through nix options
+ When false, systemd-networkd is enabled to accept network
+ configuration from proxmox.
+ '';
+ };
+ };
+
+ config =
+ let
+ cfg = config.proxmoxLXC;
+ in
+ {
+ system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix {
+ storeContents = [{
+ object = config.system.build.toplevel;
+ symlink = "none";
+ }];
+
+ contents = [{
+ source = config.system.build.toplevel + "/init";
+ target = "/sbin/init";
+ }];
+
+ extraCommands = "mkdir -p root etc/systemd/network";
+ };
+
+ boot = {
+ isContainer = true;
+ loader.initScript.enable = true;
+ };
+
+ networking = mkIf (!cfg.manageNetwork) {
+ useDHCP = false;
+ useHostResolvConf = false;
+ useNetworkd = true;
+ };
+
+ services.openssh = {
+ enable = mkDefault true;
+ startWhenNeeded = mkDefault true;
+ };
+
+ systemd.mounts = mkIf (!cfg.privileged)
+ [{ where = "/sys/kernel/debug"; enable = false; }];
+
+ };
+}
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 29e3aa024dfa..dacbb64a2dac 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -632,6 +632,15 @@ in
Enable the Qemu guest agent.
'';
};
+
+ virtioKeyboard =
+ mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Enable the virtio-keyboard device.
+ '';
+ };
};
virtualisation.useNixStoreImage =
@@ -787,7 +796,7 @@ in
# allow `system.build.toplevel' to be included. (If we had a direct
# reference to ${regInfo} here, then we would get a cyclic
# dependency.)
- boot.postBootCommands =
+ boot.postBootCommands = lib.mkIf config.nix.enable
''
if [[ "$(cat /proc/cmdline)" =~ regInfo=([^ ]*) ]]; then
${config.nix.package.out}/bin/nix-store --load-db < ''${BASH_REMATCH[1]}
@@ -835,7 +844,9 @@ in
# FIXME: Consolidate this one day.
virtualisation.qemu.options = mkMerge [
- [ "-device virtio-keyboard" ]
+ (mkIf cfg.qemu.virtioKeyboard [
+ "-device virtio-keyboard"
+ ])
(mkIf pkgs.stdenv.hostPlatform.isx86 [
"-usb" "-device usb-tablet,bus=usb-bus.0"
])
diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix
index f702fb4e525c..7b55b3b9759e 100644
--- a/nixos/modules/virtualisation/virtualbox-guest.nix
+++ b/nixos/modules/virtualisation/virtualbox-guest.nix
@@ -68,7 +68,7 @@ in
SUBSYSTEM=="misc", KERNEL=="vboxguest", TAG+="systemd"
'';
} (mkIf cfg.x11 {
- services.xserver.videoDrivers = mkOverride 50 [ "vmware" "virtualbox" "modesetting" ];
+ services.xserver.videoDrivers = [ "vmware" "virtualbox" "modesetting" ];
services.xserver.config =
''
diff --git a/nixos/modules/virtualisation/waydroid.nix b/nixos/modules/virtualisation/waydroid.nix
index 4fc798ff39f8..2c0b658948dd 100644
--- a/nixos/modules/virtualisation/waydroid.nix
+++ b/nixos/modules/virtualisation/waydroid.nix
@@ -56,8 +56,6 @@ in
wantedBy = [ "multi-user.target" ];
- path = with pkgs; [ getent iptables iproute kmod nftables util-linux which ];
-
unitConfig = {
ConditionPathExists = "/var/lib/waydroid/lxc/waydroid";
};
@@ -68,6 +66,10 @@ in
ExecStopPost = "${pkgs.waydroid}/bin/waydroid session stop";
};
};
+
+ systemd.tmpfiles.rules = [
+ "d /var/lib/misc 0755 root root -" # for dnsmasq.leases
+ ];
};
}
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index ee3f3d19174e..fd8a39cfb92b 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -98,7 +98,6 @@ in rec {
(onFullSupported "nixos.tests.login")
(onFullSupported "nixos.tests.misc")
(onFullSupported "nixos.tests.mutableUsers")
- (onFullSupported "nixos.tests.nano")
(onFullSupported "nixos.tests.nat.firewall-conntrack")
(onFullSupported "nixos.tests.nat.firewall")
(onFullSupported "nixos.tests.nat.standalone")
@@ -130,7 +129,8 @@ in rec {
(onFullSupported "nixos.tests.networking.networkd.virtual")
(onFullSupported "nixos.tests.networking.networkd.vlan")
(onFullSupported "nixos.tests.systemd-networkd-ipv6-prefix-delegation")
- (onFullSupported "nixos.tests.nfs3.simple")
+ # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314
+ #(onFullSupported "nixos.tests.nfs3.simple")
(onFullSupported "nixos.tests.nfs4.simple")
(onFullSupported "nixos.tests.openssh")
(onFullSupported "nixos.tests.pantheon")
diff --git a/nixos/release-small.nix b/nixos/release-small.nix
index 996db54c9a40..1d51b4e7f28f 100644
--- a/nixos/release-small.nix
+++ b/nixos/release-small.nix
@@ -38,7 +38,8 @@ in rec {
login
misc
nat
- nfs3
+ # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314
+ #nfs3
openssh
php
predictable-interface-names
@@ -107,7 +108,8 @@ in rec {
"nixos.tests.nat.firewall-conntrack.x86_64-linux"
"nixos.tests.nat.firewall.x86_64-linux"
"nixos.tests.nat.standalone.x86_64-linux"
- "nixos.tests.nfs3.simple.x86_64-linux"
+ # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314
+ #"nixos.tests.nfs3.simple.x86_64-linux"
"nixos.tests.openssh.x86_64-linux"
"nixos.tests.php.fpm.x86_64-linux"
"nixos.tests.php.pcre.x86_64-linux"
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 62bc8acef606..ab6906cd24e2 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -32,9 +32,11 @@ in
acme = handleTest ./acme.nix {};
adguardhome = handleTest ./adguardhome.nix {};
aesmd = handleTest ./aesmd.nix {};
+ agate = handleTest ./web-servers/agate.nix {};
agda = handleTest ./agda.nix {};
airsonic = handleTest ./airsonic.nix {};
amazon-init-shell = handleTest ./amazon-init-shell.nix {};
+ apfs = handleTest ./apfs.nix {};
apparmor = handleTest ./apparmor.nix {};
atd = handleTest ./atd.nix {};
atop = handleTest ./atop.nix {};
@@ -50,11 +52,13 @@ in
bitcoind = handleTest ./bitcoind.nix {};
bittorrent = handleTest ./bittorrent.nix {};
blockbook-frontend = handleTest ./blockbook-frontend.nix {};
+ blocky = handleTest ./blocky.nix {};
boot = handleTestOn ["x86_64-linux" "aarch64-linux"] ./boot.nix {};
boot-stage1 = handleTest ./boot-stage1.nix {};
borgbackup = handleTest ./borgbackup.nix {};
botamusique = handleTest ./botamusique.nix {};
bpf = handleTestOn ["x86_64-linux" "aarch64-linux"] ./bpf.nix {};
+ breitbandmessung = handleTest ./breitbandmessung.nix {};
brscan5 = handleTest ./brscan5.nix {};
btrbk = handleTest ./btrbk.nix {};
buildbot = handleTest ./buildbot.nix {};
@@ -128,6 +132,7 @@ in
domination = handleTest ./domination.nix {};
dovecot = handleTest ./dovecot.nix {};
drbd = handleTest ./drbd.nix {};
+ earlyoom = handleTestOn ["x86_64-linux"] ./earlyoom.nix {};
ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
ecryptfs = handleTest ./ecryptfs.nix {};
@@ -139,6 +144,7 @@ in
env = handleTest ./env.nix {};
ergo = handleTest ./ergo.nix {};
ergochat = handleTest ./ergochat.nix {};
+ etc = pkgs.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; };
etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {};
etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {};
etebase-server = handleTest ./etebase-server.nix {};
@@ -184,9 +190,9 @@ in
grocy = handleTest ./grocy.nix {};
grub = handleTest ./grub.nix {};
gvisor = handleTest ./gvisor.nix {};
- hadoop.all = handleTestOn [ "x86_64-linux" ] ./hadoop/hadoop.nix {};
- hadoop.hdfs = handleTestOn [ "x86_64-linux" ] ./hadoop/hdfs.nix {};
- hadoop.yarn = handleTestOn [ "x86_64-linux" ] ./hadoop/yarn.nix {};
+ hadoop = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop; };
+ hadoop_3_2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop_3_2; };
+ hadoop2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop2; };
haka = handleTest ./haka.nix {};
haproxy = handleTest ./haproxy.nix {};
hardened = handleTest ./hardened.nix {};
@@ -219,6 +225,7 @@ in
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrdNetwork = handleTest ./initrd-network.nix {};
initrd-secrets = handleTest ./initrd-secrets.nix {};
+ input-remapper = handleTest ./input-remapper.nix {};
inspircd = handleTest ./inspircd.nix {};
installer = handleTest ./installer.nix {};
invoiceplane = handleTest ./invoiceplane.nix {};
@@ -235,7 +242,6 @@ in
jibri = handleTest ./jibri.nix {};
jirafeau = handleTest ./jirafeau.nix {};
jitsi-meet = handleTest ./jitsi-meet.nix {};
- k3s = handleTest ./k3s.nix {};
k3s-single-node = handleTest ./k3s-single-node.nix {};
k3s-single-node-docker = handleTest ./k3s-single-node-docker.nix {};
kafka = handleTest ./kafka.nix {};
@@ -266,6 +272,7 @@ in
litestream = handleTest ./litestream.nix {};
locate = handleTest ./locate.nix {};
login = handleTest ./login.nix {};
+ logrotate = handleTest ./logrotate.nix {};
loki = handleTest ./loki.nix {};
lxd = handleTest ./lxd.nix {};
lxd-image = handleTest ./lxd-image.nix {};
@@ -280,6 +287,7 @@ in
mailhog = handleTest ./mailhog.nix {};
man = handleTest ./man.nix {};
mariadb-galera = handleTest ./mysql/mariadb-galera.nix {};
+ mastodon = handleTestOn ["x86_64-linux" "i686-linux" "aarch64-linux"] ./web-apps/mastodon.nix {};
matomo = handleTest ./matomo.nix {};
matrix-appservice-irc = handleTest ./matrix-appservice-irc.nix {};
matrix-conduit = handleTest ./matrix-conduit.nix {};
@@ -301,8 +309,10 @@ in
molly-brown = handleTest ./molly-brown.nix {};
mongodb = handleTest ./mongodb.nix {};
moodle = handleTest ./moodle.nix {};
+ moonraker = handleTest ./moonraker.nix {};
morty = handleTest ./morty.nix {};
mosquitto = handleTest ./mosquitto.nix {};
+ moosefs = handleTest ./moosefs.nix {};
mpd = handleTest ./mpd.nix {};
mpv = handleTest ./mpv.nix {};
mumble = handleTest ./mumble.nix {};
@@ -316,13 +326,13 @@ in
mysql-replication = handleTest ./mysql/mysql-replication.nix {};
n8n = handleTest ./n8n.nix {};
nagios = handleTest ./nagios.nix {};
- nano = handleTest ./nano.nix {};
nar-serve = handleTest ./nar-serve.nix {};
nat.firewall = handleTest ./nat.nix { withFirewall = true; };
nat.firewall-conntrack = handleTest ./nat.nix { withFirewall = true; withConntrackHelpers = true; };
nat.standalone = handleTest ./nat.nix { withFirewall = false; };
nats = handleTest ./nats.nix {};
navidrome = handleTest ./navidrome.nix {};
+ nbd = handleTest ./nbd.nix {};
ncdns = handleTest ./ncdns.nix {};
ndppd = handleTest ./ndppd.nix {};
nebula = handleTest ./nebula.nix {};
@@ -342,11 +352,13 @@ in
nginx = handleTest ./nginx.nix {};
nginx-auth = handleTest ./nginx-auth.nix {};
nginx-etag = handleTest ./nginx-etag.nix {};
+ nginx-modsecurity = handleTest ./nginx-modsecurity.nix {};
nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
nginx-sandbox = handleTestOn ["x86_64-linux"] ./nginx-sandbox.nix {};
nginx-sso = handleTest ./nginx-sso.nix {};
nginx-variants = handleTest ./nginx-variants.nix {};
nitter = handleTest ./nitter.nix {};
+ nix-ld = handleTest ./nix-ld {};
nix-serve = handleTest ./nix-serve.nix {};
nix-serve-ssh = handleTest ./nix-serve-ssh.nix {};
nixops = handleTest ./nixops/default.nix {};
@@ -354,6 +366,7 @@ in
nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; };
node-red = handleTest ./node-red.nix {};
nomad = handleTest ./nomad.nix {};
+ noto-fonts = handleTest ./noto-fonts.nix {};
novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {};
nsd = handleTest ./nsd.nix {};
nzbget = handleTest ./nzbget.nix {};
@@ -375,6 +388,7 @@ in
os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
osrm-backend = handleTest ./osrm-backend.nix {};
overlayfs = handleTest ./overlayfs.nix {};
+ pacemaker = handleTest ./pacemaker.nix {};
packagekit = handleTest ./packagekit.nix {};
pam-file-contents = handleTest ./pam/pam-file-contents.nix {};
pam-oath-login = handleTest ./pam/pam-oath-login.nix {};
@@ -386,6 +400,8 @@ in
pdns-recursor = handleTest ./pdns-recursor.nix {};
peerflix = handleTest ./peerflix.nix {};
peertube = handleTestOn ["x86_64-linux"] ./web-apps/peertube.nix {};
+ pgadmin4 = handleTest ./pgadmin4.nix {};
+ pgadmin4-standalone = handleTest ./pgadmin4-standalone.nix {};
pgjwt = handleTest ./pgjwt.nix {};
pgmanage = handleTest ./pgmanage.nix {};
php = handleTest ./php {};
@@ -422,6 +438,7 @@ in
prometheus = handleTest ./prometheus.nix {};
prometheus-exporters = handleTest ./prometheus-exporters.nix {};
prosody = handleTest ./xmpp/prosody.nix {};
+ prosody-mysql = handleTest ./xmpp/prosody-mysql.nix {};
proxy = handleTest ./proxy.nix {};
prowlarr = handleTest ./prowlarr.nix {};
pt2-clone = handleTest ./pt2-clone.nix {};
@@ -437,6 +454,7 @@ in
resolv = handleTest ./resolv.nix {};
restartByActivationScript = handleTest ./restart-by-activation-script.nix {};
restic = handleTest ./restic.nix {};
+ retroarch = handleTest ./retroarch.nix {};
riak = handleTest ./riak.nix {};
robustirc-bridge = handleTest ./robustirc-bridge.nix {};
roundcube = handleTest ./roundcube.nix {};
@@ -454,6 +472,7 @@ in
seafile = handleTest ./seafile.nix {};
searx = handleTest ./searx.nix {};
service-runner = handleTest ./service-runner.nix {};
+ sfxr-qt = handleTest ./sfxr-qt.nix {};
shadow = handleTest ./shadow.nix {};
shadowsocks = handleTest ./shadowsocks {};
shattered-pixel-dungeon = handleTest ./shattered-pixel-dungeon.nix {};
@@ -471,7 +490,7 @@ in
sonarr = handleTest ./sonarr.nix {};
sourcehut = handleTest ./sourcehut.nix {};
spacecookie = handleTest ./spacecookie.nix {};
- spark = handleTestOn ["x86_64-linux"] ./spark {};
+ spark = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./spark {};
sslh = handleTest ./sslh.nix {};
sssd = handleTestOn ["x86_64-linux"] ./sssd.nix {};
sssd-ldap = handleTestOn ["x86_64-linux"] ./sssd-ldap.nix {};
@@ -491,7 +510,9 @@ in
systemd-boot = handleTest ./systemd-boot.nix {};
systemd-confinement = handleTest ./systemd-confinement.nix {};
systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {};
+ systemd-escaping = handleTest ./systemd-escaping.nix {};
systemd-journal = handleTest ./systemd-journal.nix {};
+ systemd-machinectl = handleTest ./systemd-machinectl.nix {};
systemd-networkd = handleTest ./systemd-networkd.nix {};
systemd-networkd-dhcpserver = handleTest ./systemd-networkd-dhcpserver.nix {};
systemd-networkd-dhcpserver-static-leases = handleTest ./systemd-networkd-dhcpserver-static-leases.nix {};
@@ -499,18 +520,20 @@ in
systemd-networkd-vrf = handleTest ./systemd-networkd-vrf.nix {};
systemd-nspawn = handleTest ./systemd-nspawn.nix {};
systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
- systemd-unit-path = handleTest ./systemd-unit-path.nix {};
+ systemd-misc = handleTest ./systemd-misc.nix {};
taskserver = handleTest ./taskserver.nix {};
teeworlds = handleTest ./teeworlds.nix {};
telegraf = handleTest ./telegraf.nix {};
teleport = handleTest ./teleport.nix {};
thelounge = handleTest ./thelounge.nix {};
+ terminal-emulators = handleTest ./terminal-emulators.nix {};
tiddlywiki = handleTest ./tiddlywiki.nix {};
tigervnc = handleTest ./tigervnc.nix {};
timezone = handleTest ./timezone.nix {};
tinc = handleTest ./tinc {};
tinydns = handleTest ./tinydns.nix {};
tinywl = handleTest ./tinywl.nix {};
+ tomcat = handleTest ./tomcat.nix {};
tor = handleTest ./tor.nix {};
# traefik test relies on docker-containers
traefik = handleTestOn ["x86_64-linux"] ./traefik.nix {};
@@ -543,6 +566,7 @@ in
vikunja = handleTest ./vikunja.nix {};
virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
vscodium = discoverTests (import ./vscodium.nix);
+ vsftpd = handleTest ./vsftpd.nix {};
wasabibackend = handleTest ./wasabibackend.nix {};
wiki-js = handleTest ./wiki-js.nix {};
wine = handleTest ./wine.nix {};
@@ -558,8 +582,10 @@ in
xrdp = handleTest ./xrdp.nix {};
xss-lock = handleTest ./xss-lock.nix {};
xterm = handleTest ./xterm.nix {};
+ xxh = handleTest ./xxh.nix {};
yabar = handleTest ./yabar.nix {};
yggdrasil = handleTest ./yggdrasil.nix {};
+ zammad = handleTest ./zammad.nix {};
zfs = handleTest ./zfs.nix {};
zigbee2mqtt = handleTest ./zigbee2mqtt.nix {};
zoneminder = handleTest ./zoneminder.nix {};
diff --git a/nixos/tests/apfs.nix b/nixos/tests/apfs.nix
new file mode 100644
index 000000000000..a82886cbe731
--- /dev/null
+++ b/nixos/tests/apfs.nix
@@ -0,0 +1,54 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+ name = "apfs";
+ meta.maintainers = with pkgs.lib.maintainers; [ Luflosi ];
+
+ machine = { pkgs, ... }: {
+ virtualisation.emptyDiskImages = [ 1024 ];
+
+ boot.supportedFilesystems = [ "apfs" ];
+ };
+
+ testScript = ''
+ machine.wait_for_unit("basic.target")
+ machine.succeed("mkdir /tmp/mnt")
+
+ with subtest("mkapfs refuses to work with a label that is too long"):
+ machine.fail( "mkapfs -L '000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F' /dev/vdb")
+
+ with subtest("mkapfs works with the maximum label length"):
+ machine.succeed("mkapfs -L '000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7' /dev/vdb")
+
+ with subtest("Enable case sensitivity and normalization sensitivity"):
+ machine.succeed(
+ "mkapfs -s -z /dev/vdb",
+ # Triggers a bug, see https://github.com/linux-apfs/linux-apfs-rw/issues/15
+ # "mount -o cknodes,readwrite /dev/vdb /tmp/mnt",
+ "mount -o readwrite /dev/vdb /tmp/mnt",
+ "echo 'Hello World 1' > /tmp/mnt/test.txt",
+ "[ ! -f /tmp/mnt/TeSt.TxT ] || false", # Test case sensitivity
+ "echo 'Hello World 1' | diff - /tmp/mnt/test.txt",
+ "echo 'Hello World 2' > /tmp/mnt/\u0061\u0301.txt",
+ "echo 'Hello World 2' | diff - /tmp/mnt/\u0061\u0301.txt",
+ "[ ! -f /tmp/mnt/\u00e1.txt ] || false", # Test Unicode normalization sensitivity
+ "umount /tmp/mnt",
+ "apfsck /dev/vdb",
+ )
+ with subtest("Disable case sensitivity and normalization sensitivity"):
+ machine.succeed(
+ "mkapfs /dev/vdb",
+ "mount -o readwrite /dev/vdb /tmp/mnt",
+ "echo 'bla bla bla' > /tmp/mnt/Test.txt",
+ "echo -n 'Hello World' > /tmp/mnt/test.txt",
+ "echo ' 1' >> /tmp/mnt/TEST.TXT",
+ "umount /tmp/mnt",
+ "apfsck /dev/vdb",
+ "mount -o readwrite /dev/vdb /tmp/mnt",
+ "echo 'Hello World 1' | diff - /tmp/mnt/TeSt.TxT", # Test case insensitivity
+ "echo 'Hello World 2' > /tmp/mnt/\u0061\u0301.txt",
+ "echo 'Hello World 2' | diff - /tmp/mnt/\u0061\u0301.txt",
+ "echo 'Hello World 2' | diff - /tmp/mnt/\u00e1.txt", # Test Unicode normalization
+ "umount /tmp/mnt",
+ "apfsck /dev/vdb",
+ )
+ '';
+})
diff --git a/nixos/tests/avahi.nix b/nixos/tests/avahi.nix
index ebb46838325f..c53a95903291 100644
--- a/nixos/tests/avahi.nix
+++ b/nixos/tests/avahi.nix
@@ -59,7 +59,7 @@ import ./make-test-python.nix {
two.succeed("test `wc -l < out` -gt 0")
# More DNS-SD.
- one.execute('avahi-publish -s "This is a test" _test._tcp 123 one=1 &')
+ one.execute('avahi-publish -s "This is a test" _test._tcp 123 one=1 >&2 &')
one.sleep(5)
two.succeed("avahi-browse -r -t _test._tcp | tee out >&2")
two.succeed("test `wc -l < out` -gt 0")
diff --git a/nixos/tests/bcachefs.nix b/nixos/tests/bcachefs.nix
index 211195586ed9..44997a746879 100644
--- a/nixos/tests/bcachefs.nix
+++ b/nixos/tests/bcachefs.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
virtualisation.emptyDiskImages = [ 4096 ];
networking.hostId = "deadbeef";
boot.supportedFilesystems = [ "bcachefs" ];
- environment.systemPackages = with pkgs; [ parted ];
+ environment.systemPackages = with pkgs; [ parted keyutils ];
};
testScript = ''
@@ -20,10 +20,9 @@ import ./make-test-python.nix ({ pkgs, ... }: {
"parted --script /dev/vdb mklabel msdos",
"parted --script /dev/vdb -- mkpart primary 1024M 50% mkpart primary 50% -1s",
"udevadm settle",
- # Due to #32279, we cannot use encryption for this test yet
- # "echo password | bcachefs format --encrypted --metadata_replicas 2 --label vtest /dev/vdb1 /dev/vdb2",
- # "echo password | bcachefs unlock /dev/vdb1",
- "bcachefs format --metadata_replicas 2 --label vtest /dev/vdb1 /dev/vdb2",
+ "keyctl link @u @s",
+ "echo password | bcachefs format --encrypted --metadata_replicas 2 --label vtest /dev/vdb1 /dev/vdb2",
+ "echo password | bcachefs unlock /dev/vdb1",
"mount -t bcachefs /dev/vdb1:/dev/vdb2 /tmp/mnt",
"udevadm settle",
"bcachefs fs usage /tmp/mnt",
diff --git a/nixos/tests/bird.nix b/nixos/tests/bird.nix
index 50d397be14ee..822a7caea9ba 100644
--- a/nixos/tests/bird.nix
+++ b/nixos/tests/bird.nix
@@ -9,7 +9,7 @@ let
inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
inherit (pkgs.lib) optionalString;
- hostShared = hostId: { pkgs, ... }: {
+ makeBird2Host = hostId: { pkgs, ... }: {
virtualisation.vlans = [ 1 ];
environment.systemPackages = with pkgs; [ jq ];
@@ -24,105 +24,6 @@ let
name = "eth1";
networkConfig.Address = "10.0.0.${hostId}/24";
};
- };
-
- birdTest = v4:
- let variant = "bird${optionalString (!v4) "6"}"; in
- makeTest {
- name = variant;
-
- nodes.host1 = makeBirdHost variant "1";
- nodes.host2 = makeBirdHost variant "2";
-
- testScript = makeTestScript variant v4 (!v4);
- };
-
- bird2Test = makeTest {
- name = "bird2";
-
- nodes.host1 = makeBird2Host "1";
- nodes.host2 = makeBird2Host "2";
-
- testScript = makeTestScript "bird2" true true;
- };
-
- makeTestScript = variant: v4: v6: ''
- start_all()
-
- host1.wait_for_unit("${variant}.service")
- host2.wait_for_unit("${variant}.service")
-
- ${optionalString v4 ''
- with subtest("Waiting for advertised IPv4 routes"):
- host1.wait_until_succeeds("ip --json r | jq -e 'map(select(.dst == \"10.10.0.2\")) | any'")
- host2.wait_until_succeeds("ip --json r | jq -e 'map(select(.dst == \"10.10.0.1\")) | any'")
- ''}
- ${optionalString v6 ''
- with subtest("Waiting for advertised IPv6 routes"):
- host1.wait_until_succeeds("ip --json -6 r | jq -e 'map(select(.dst == \"fdff::2\")) | any'")
- host2.wait_until_succeeds("ip --json -6 r | jq -e 'map(select(.dst == \"fdff::1\")) | any'")
- ''}
-
- with subtest("Check fake routes in preCheckConfig do not exists"):
- ${optionalString v4 ''host1.fail("ip --json r | jq -e 'map(select(.dst == \"1.2.3.4\")) | any'")''}
- ${optionalString v4 ''host2.fail("ip --json r | jq -e 'map(select(.dst == \"1.2.3.4\")) | any'")''}
-
- ${optionalString v6 ''host1.fail("ip --json -6 r | jq -e 'map(select(.dst == \"fd00::\")) | any'")''}
- ${optionalString v6 ''host2.fail("ip --json -6 r | jq -e 'map(select(.dst == \"fd00::\")) | any'")''}
- '';
-
- makeBirdHost = variant: hostId: { pkgs, ... }: {
- imports = [ (hostShared hostId) ];
-
- services.${variant} = {
- enable = true;
-
- config = ''
- log syslog all;
-
- debug protocols all;
-
- router id 10.0.0.${hostId};
-
- protocol device {
- }
-
- protocol kernel {
- import none;
- export all;
- }
-
- protocol static {
- include "static.conf";
- }
-
- protocol ospf {
- export all;
- area 0 {
- interface "eth1" {
- hello 5;
- wait 5;
- };
- };
- }
- '';
-
- preCheckConfig =
- let
- route = { bird = "1.2.3.4/32"; bird6 = "fd00::/128"; }.${variant};
- in
- ''echo "route ${route} blackhole;" > static.conf'';
- };
-
- systemd.tmpfiles.rules =
- let
- route = { bird = "10.10.0.${hostId}/32"; bird6 = "fdff::${hostId}/128"; }.${variant};
- in
- [ "f /etc/bird/static.conf - - - - route ${route} blackhole;" ];
- };
-
- makeBird2Host = hostId: { pkgs, ... }: {
- imports = [ (hostShared hostId) ];
services.bird2 = {
enable = true;
@@ -198,8 +99,31 @@ let
];
};
in
-{
- bird = birdTest true;
- bird6 = birdTest false;
- bird2 = bird2Test;
+makeTest {
+ name = "bird2";
+
+ nodes.host1 = makeBird2Host "1";
+ nodes.host2 = makeBird2Host "2";
+
+ testScript = ''
+ start_all()
+
+ host1.wait_for_unit("bird2.service")
+ host2.wait_for_unit("bird2.service")
+ host1.succeed("systemctl reload bird2.service")
+
+ with subtest("Waiting for advertised IPv4 routes"):
+ host1.wait_until_succeeds("ip --json r | jq -e 'map(select(.dst == \"10.10.0.2\")) | any'")
+ host2.wait_until_succeeds("ip --json r | jq -e 'map(select(.dst == \"10.10.0.1\")) | any'")
+ with subtest("Waiting for advertised IPv6 routes"):
+ host1.wait_until_succeeds("ip --json -6 r | jq -e 'map(select(.dst == \"fdff::2\")) | any'")
+ host2.wait_until_succeeds("ip --json -6 r | jq -e 'map(select(.dst == \"fdff::1\")) | any'")
+
+ with subtest("Check fake routes in preCheckConfig do not exists"):
+ host1.fail("ip --json r | jq -e 'map(select(.dst == \"1.2.3.4\")) | any'")
+ host2.fail("ip --json r | jq -e 'map(select(.dst == \"1.2.3.4\")) | any'")
+
+ host1.fail("ip --json -6 r | jq -e 'map(select(.dst == \"fd00::\")) | any'")
+ host2.fail("ip --json -6 r | jq -e 'map(select(.dst == \"fd00::\")) | any'")
+ '';
}
diff --git a/nixos/tests/blocky.nix b/nixos/tests/blocky.nix
new file mode 100644
index 000000000000..18e7f45e1c73
--- /dev/null
+++ b/nixos/tests/blocky.nix
@@ -0,0 +1,34 @@
+import ./make-test-python.nix {
+ name = "blocky";
+
+ nodes = {
+ server = { pkgs, ... }: {
+ environment.systemPackages = [ pkgs.dnsutils ];
+ services.blocky = {
+ enable = true;
+
+ settings = {
+ customDNS = {
+ mapping = {
+ "printer.lan" = "192.168.178.3,2001:0db8:85a3:08d3:1319:8a2e:0370:7344";
+ };
+ };
+ upstream = {
+ default = [ "8.8.8.8" "1.1.1.1" ];
+ };
+ port = 53;
+ httpPort = 5000;
+ logLevel = "info";
+ };
+ };
+ };
+ };
+
+ testScript = ''
+ with subtest("Service test"):
+ server.wait_for_unit("blocky.service")
+ server.wait_for_open_port(53)
+ server.wait_for_open_port(5000)
+ server.succeed("dig @127.0.0.1 +short -x 192.168.178.3 | grep -qF printer.lan")
+ '';
+}
diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix
index cf5565667131..ec2a9f6527c9 100644
--- a/nixos/tests/boot.nix
+++ b/nixos/tests/boot.nix
@@ -38,7 +38,6 @@ let
} // extraConfig);
in
makeTest {
- inherit iso;
name = "boot-" + name;
nodes = { };
testScript =
diff --git a/nixos/tests/bpf.nix b/nixos/tests/bpf.nix
index 233c7dab1ee2..e479cd057921 100644
--- a/nixos/tests/bpf.nix
+++ b/nixos/tests/bpf.nix
@@ -18,8 +18,12 @@ import ./make-test-python.nix ({ pkgs, ... }: {
# simple BEGIN probe (user probe on bpftrace itself)
print(machine.succeed("bpftrace -e 'BEGIN { print(\"ok\"); exit(); }'"))
# tracepoint
- print(machine.succeed("bpftrace -e 'tracepoint:syscalls:sys_enter_* { print(probe); exit(); }'"))
+ print(machine.succeed("bpftrace -e 'tracepoint:syscalls:sys_enter_* { print(probe); exit() }'"))
# kprobe
print(machine.succeed("bpftrace -e 'kprobe:schedule { print(probe); exit() }'"))
+ # BTF
+ print(machine.succeed("bpftrace -e 'kprobe:schedule { "
+ " printf(\"tgid: %d\", ((struct task_struct*) curtask)->tgid); exit() "
+ "}'"))
'';
})
diff --git a/nixos/tests/breitbandmessung.nix b/nixos/tests/breitbandmessung.nix
new file mode 100644
index 000000000000..12b1a094839b
--- /dev/null
+++ b/nixos/tests/breitbandmessung.nix
@@ -0,0 +1,33 @@
+import ./make-test-python.nix ({ lib, ... }: {
+ name = "breitbandmessung";
+ meta.maintainers = with lib.maintainers; [ b4dm4n ];
+
+ machine = { pkgs, ... }: {
+ imports = [
+ ./common/user-account.nix
+ ./common/x11.nix
+ ];
+
+ # increase screen size to make the whole program visible
+ virtualisation.resolution = { x = 1280; y = 1024; };
+
+ test-support.displayManager.auto.user = "alice";
+
+ environment.systemPackages = with pkgs; [ breitbandmessung ];
+ environment.variables.XAUTHORITY = "/home/alice/.Xauthority";
+
+ # breitbandmessung is unfree
+ nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "breitbandmessung" ];
+ };
+
+ enableOCR = true;
+
+ testScript = ''
+ machine.wait_for_x()
+ machine.execute("su - alice -c breitbandmessung >&2 &")
+ machine.wait_for_window("Breitbandmessung")
+ machine.wait_for_text("Breitbandmessung")
+ machine.wait_for_text("Datenschutz")
+ machine.screenshot("breitbandmessung")
+ '';
+})
diff --git a/nixos/tests/caddy.nix b/nixos/tests/caddy.nix
index 0902904b2086..16436ab52800 100644
--- a/nixos/tests/caddy.nix
+++ b/nixos/tests/caddy.nix
@@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
nodes = {
webserver = { pkgs, lib, ... }: {
services.caddy.enable = true;
- services.caddy.config = ''
+ services.caddy.extraConfig = ''
http://localhost {
encode gzip
@@ -22,7 +22,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
'';
specialisation.etag.configuration = {
- services.caddy.config = lib.mkForce ''
+ services.caddy.extraConfig = lib.mkForce ''
http://localhost {
encode gzip
@@ -38,7 +38,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
};
specialisation.config-reload.configuration = {
- services.caddy.config = ''
+ services.caddy.extraConfig = ''
http://localhost:8080 {
}
'';
diff --git a/nixos/tests/ceph-multi-node.nix b/nixos/tests/ceph-multi-node.nix
index 29e7c279d69a..556546beee76 100644
--- a/nixos/tests/ceph-multi-node.nix
+++ b/nixos/tests/ceph-multi-node.nix
@@ -48,7 +48,7 @@ let
sudo
ceph
xfsprogs
- netcat-openbsd
+ libressl.nc
];
boot.kernelModules = [ "xfs" ];
diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix
index 8965646bc5dc..3815dca76220 100644
--- a/nixos/tests/chromium.nix
+++ b/nixos/tests/chromium.nix
@@ -15,26 +15,9 @@
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
-mapAttrs (channel: chromiumPkg: makeTest rec {
- name = "chromium-${channel}";
- meta = {
- maintainers = with maintainers; [ aszlig primeos ];
- # https://github.com/NixOS/hydra/issues/591#issuecomment-435125621
- inherit (chromiumPkg.meta) timeout;
- };
-
- enableOCR = true;
-
+let
user = "alice";
- machine.imports = [ ./common/user-account.nix ./common/x11.nix ];
- machine.virtualisation.memorySize = 2047;
- machine.test-support.displayManager.auto.user = user;
- machine.environment = {
- systemPackages = [ chromiumPkg ];
- variables."XAUTHORITY" = "/home/alice/.Xauthority";
- };
-
startupHTML = pkgs.writeText "chromium-startup.html" ''
@@ -50,6 +33,25 @@ mapAttrs (channel: chromiumPkg: makeTest rec {