mirror of
https://github.com/CHN-beta/nixpkgs.git
synced 2026-01-12 19:00:19 +08:00
Compare commits
4 Commits
python-tes
...
qemu-vm/tp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a3760926a | ||
|
|
c3e3968544 | ||
|
|
685da3c995 | ||
|
|
975b5d3152 |
@@ -101,7 +101,3 @@ end_of_line = unset
|
||||
insert_final_newline = unset
|
||||
trim_trailing_whitespace = unset
|
||||
charset = unset
|
||||
|
||||
[lib/tests/*.plist]
|
||||
indent_style = tab
|
||||
insert_final_newline = unset
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{ pkgs ? import ../../.. {} }:
|
||||
let
|
||||
inherit (pkgs) lib;
|
||||
manpageURLs = lib.importJSON (pkgs.path + "/doc/manpage-urls.json");
|
||||
manpageURLs = builtins.fromJSON (builtins.readFile (pkgs.path + "/doc/manpage-urls.json"));
|
||||
in pkgs.writeText "link-manpages.lua" ''
|
||||
--[[
|
||||
Adds links to known man pages that aren't already in a link.
|
||||
|
||||
@@ -45,10 +45,7 @@ let
|
||||
# NB: This file describes the Nixpkgs manual, which happens to use module
|
||||
# docs infra originally developed for NixOS.
|
||||
optionsDoc = pkgs.nixosOptionsDoc {
|
||||
inherit (pkgs.lib.evalModules {
|
||||
modules = [ ../../pkgs/top-level/config.nix ];
|
||||
class = "nixpkgsConfig";
|
||||
}) options;
|
||||
inherit (pkgs.lib.evalModules { modules = [ ../../pkgs/top-level/config.nix ]; }) options;
|
||||
documentType = "none";
|
||||
transformOptions = opt:
|
||||
opt // {
|
||||
|
||||
@@ -38,12 +38,12 @@ Here is a simple package example.
|
||||
|
||||
- It uses the `fetchFromGitHub` fetcher to get its source.
|
||||
|
||||
- It also accept `duneVersion` parameter (valid value are `"1"`, `"2"`, and
|
||||
`"3"`). The recommended practice it to set only if you don't want the default
|
||||
value and/or it depends on something else like package version. You might see
|
||||
a not-supported argument `useDune2`. The behavior was `useDune2 = true;` =>
|
||||
`duneVersion = "2";` and `useDune2 = false;` => `duneVersion = "1";`. It was
|
||||
used at the time when dune3 didn't existed.
|
||||
- `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
|
||||
@@ -71,6 +71,7 @@ Here is a simple package example.
|
||||
buildDunePackage rec {
|
||||
pname = "angstrom";
|
||||
version = "0.15.0";
|
||||
duneVersion = "2";
|
||||
|
||||
minimalOCamlVersion = "4.04";
|
||||
|
||||
@@ -103,6 +104,8 @@ buildDunePackage rec {
|
||||
pname = "wtf8";
|
||||
version = "1.0.2";
|
||||
|
||||
useDune2 = true;
|
||||
|
||||
minimalOCamlVersion = "4.02";
|
||||
|
||||
src = fetchurl {
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
<xi:include href="using/configuration.chapter.xml" />
|
||||
<xi:include href="using/overlays.chapter.xml" />
|
||||
<xi:include href="using/overrides.chapter.xml" />
|
||||
</part>
|
||||
<part>
|
||||
<title>Nixpkgs <code>lib</code></title>
|
||||
<xi:include href="functions.xml" />
|
||||
<xi:include href="module-system/module-system.chapter.xml" />
|
||||
</part>
|
||||
<part xml:id="part-stdenv">
|
||||
<title>Standard environment</title>
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
# Module System {#module-system}
|
||||
|
||||
## Introduction {#module-system-introduction}
|
||||
|
||||
The module system is a language for handling configuration, implemented as a Nix library.
|
||||
|
||||
Compared to plain Nix, it adds documentation, type checking and composition or extensibility.
|
||||
|
||||
::: {.note}
|
||||
This chapter is new and not complete yet. For a gentle introduction to the module system, in the context of NixOS, see [Writing NixOS Modules](https://nixos.org/manual/nixos/unstable/index.html#sec-writing-modules) in the NixOS manual.
|
||||
:::
|
||||
|
||||
|
||||
## `lib.evalModules` {#module-system-lib-evalModules}
|
||||
|
||||
Evaluate a set of modules. This function is typically only used once per application (e.g. once in NixOS, once in Home Manager, ...).
|
||||
|
||||
### Parameters {#module-system-lib-evalModules-parameters}
|
||||
|
||||
#### `modules` {#module-system-lib-evalModules-param-modules}
|
||||
|
||||
A list of modules. These are merged together to form the final configuration.
|
||||
<!-- TODO link to section about merging, TBD -->
|
||||
|
||||
#### `specialArgs` {#module-system-lib-evalModules-param-specialArgs}
|
||||
|
||||
An attribute set of module arguments that can be used in `imports`.
|
||||
|
||||
This is in contrast to `config._module.args`, which is only available after all `imports` have been resolved.
|
||||
|
||||
#### `class` {#module-system-lib-evalModules-param-class}
|
||||
|
||||
If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `_class` declaration.
|
||||
|
||||
The `class` value should be a string in lower [camel case](https://en.wikipedia.org/wiki/Camel_case).
|
||||
|
||||
If applicable, the `class` should match the "prefix" of the attributes used in (experimental) [flakes](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#description). Some examples are:
|
||||
|
||||
- `nixos` as in `flake.nixosModules`
|
||||
- `nixosTest`: modules that constitute a [NixOS VM test](https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests)
|
||||
<!-- We've only just started with `class`. You're invited to add a few more. -->
|
||||
|
||||
#### `prefix` {#module-system-lib-evalModules-param-prefix}
|
||||
|
||||
A list of strings representing the location at or below which all options are evaluated. This is used by `types.submodule` to improve error reporting and find the implicit `name` module argument.
|
||||
|
||||
### Return value {#module-system-lib-evalModules-return-value}
|
||||
|
||||
The result is an attribute set with the following attributes:
|
||||
|
||||
#### `options` {#module-system-lib-evalModules-return-value-options}
|
||||
|
||||
The nested attribute set of all option declarations.
|
||||
|
||||
#### `config` {#module-system-lib-evalModules-return-value-config}
|
||||
|
||||
The nested attribute set of all option values.
|
||||
|
||||
#### `type` {#module-system-lib-evalModules-return-value-type}
|
||||
|
||||
A module system type. This type is an instance of `types.submoduleWith` containing the current [`modules`](#module-system-lib-evalModules-param-modules).
|
||||
|
||||
The option definitions that are typed with this type will extend the current set of modules, like [`extendModules`](#module-system-lib-evalModules-return-value-extendModules).
|
||||
|
||||
However, the value returned from the type is just the [`config`](#module-system-lib-evalModules-return-value-config), like any submodule.
|
||||
|
||||
If you're familiar with prototype inheritance, you can think of this `evalModules` invocation as the prototype, and usages of this type as the instances.
|
||||
|
||||
This type is also available to the [`modules`](#module-system-lib-evalModules-param-modules) as the module argument `moduleType`.
|
||||
<!-- TODO: document the module arguments. Using moduleType is like saying: suppose this configuration was extended. -->
|
||||
|
||||
#### `extendModules` {#module-system-lib-evalModules-return-value-extendModules}
|
||||
|
||||
A function similar to `evalModules` but building on top of the already passed [`modules`](#module-system-lib-evalModules-param-modules). Its arguments, `modules` and `specialArgs` are added to the existing values.
|
||||
|
||||
If you're familiar with prototype inheritance, you can think of the current, actual `evalModules` invocation as the prototype, and the return value of `extendModules` as the instance.
|
||||
|
||||
This functionality is also available to modules as the `extendModules` module argument.
|
||||
|
||||
::: {.note}
|
||||
|
||||
**Evaluation Performance**
|
||||
|
||||
`extendModules` returns a configuration that shares very little with the original `evalModules` invocation, because the module arguments may be different.
|
||||
|
||||
So if you have a configuration that has been (or will be) largely evaluated, almost none of the computation is shared with the configuration returned by `extendModules`.
|
||||
|
||||
The real work of module evaluation happens while computing the values in `config` and `options`, so multiple invocations of `extendModules` have a particularly small cost, as long as only the final `config` and `options` are evaluated.
|
||||
|
||||
If you do reference multiple `config` (or `options`) from before and after `extendModules`, evaluation performance is the same as with multiple `evalModules` invocations, because the new modules' ability to override existing configuration fundamentally requires constructing a new `config` and `options` fixpoint.
|
||||
:::
|
||||
|
||||
#### `_module` {#module-system-lib-evalModules-return-value-_module}
|
||||
|
||||
A portion of the configuration tree which is elided from `config`.
|
||||
|
||||
<!-- TODO: when markdown migration is complete, make _module docs visible again and reference _module docs. Maybe move those docs into this chapter? -->
|
||||
|
||||
#### `_type` {#module-system-lib-evalModules-return-value-_type}
|
||||
|
||||
A nominal type marker, always `"configuration"`.
|
||||
|
||||
#### `class` {#module-system-lib-evalModules-return-value-_configurationClass}
|
||||
|
||||
The [`class` argument](#module-system-lib-evalModules-param-class).
|
||||
13
flake.nix
13
flake.nix
@@ -57,19 +57,6 @@
|
||||
|
||||
nixosModules = {
|
||||
notDetected = ./nixos/modules/installer/scan/not-detected.nix;
|
||||
|
||||
/*
|
||||
Make the `nixpkgs.*` configuration read-only. Guarantees that `pkgs`
|
||||
is the way you initialize it.
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
imports = [ nixpkgs.nixosModules.readOnlyPkgs ];
|
||||
nixpkgs.pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||
}
|
||||
*/
|
||||
readOnlyPkgs = ./nixos/modules/misc/nixpkgs/read-only.nix;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -355,7 +355,6 @@ rec {
|
||||
# PLIST handling
|
||||
toPlist = {}: v: let
|
||||
isFloat = builtins.isFloat or (x: false);
|
||||
isPath = x: builtins.typeOf x == "path";
|
||||
expr = ind: x: with builtins;
|
||||
if x == null then "" else
|
||||
if isBool x then bool ind x else
|
||||
@@ -363,7 +362,6 @@ rec {
|
||||
if isString x then str ind x else
|
||||
if isList x then list ind x else
|
||||
if isAttrs x then attrs ind x else
|
||||
if isPath x then str ind (toString x) else
|
||||
if isFloat x then float ind x else
|
||||
abort "generators.toPlist: should never happen (v = ${v})";
|
||||
|
||||
@@ -436,7 +434,6 @@ ${expr "" v}
|
||||
Configuration:
|
||||
* multiline - by default is true which results in indented block-like view.
|
||||
* indent - initial indent.
|
||||
* asBindings - by default generate single value, but with this use attrset to set global vars.
|
||||
|
||||
Attention:
|
||||
Regardless of multiline parameter there is no trailing newline.
|
||||
@@ -467,35 +464,18 @@ ${expr "" v}
|
||||
/* If this option is true, the output is indented with newlines for attribute sets and lists */
|
||||
multiline ? true,
|
||||
/* Initial indentation level */
|
||||
indent ? "",
|
||||
/* Interpret as variable bindings */
|
||||
asBindings ? false,
|
||||
indent ? ""
|
||||
}@args: v:
|
||||
with builtins;
|
||||
let
|
||||
innerIndent = "${indent} ";
|
||||
introSpace = if multiline then "\n${innerIndent}" else " ";
|
||||
outroSpace = if multiline then "\n${indent}" else " ";
|
||||
innerArgs = args // {
|
||||
indent = if asBindings then indent else innerIndent;
|
||||
asBindings = false;
|
||||
};
|
||||
innerArgs = args // { indent = innerIndent; };
|
||||
concatItems = concatStringsSep ",${introSpace}";
|
||||
isLuaInline = { _type ? null, ... }: _type == "lua-inline";
|
||||
|
||||
generatedBindings =
|
||||
assert lib.assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}";
|
||||
libStr.concatStrings (
|
||||
lib.attrsets.mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v
|
||||
);
|
||||
|
||||
# https://en.wikibooks.org/wiki/Lua_Programming/variable#Variable_names
|
||||
matchVarName = match "[[:alpha:]_][[:alnum:]_]*(\\.[[:alpha:]_][[:alnum:]_]*)*";
|
||||
badVarNames = filter (name: matchVarName name == null) (attrNames v);
|
||||
in
|
||||
if asBindings then
|
||||
generatedBindings
|
||||
else if v == null then
|
||||
if v == null then
|
||||
"nil"
|
||||
else if isInt v || isFloat v || isString v || isBool v then
|
||||
builtins.toJSON v
|
||||
|
||||
@@ -8,10 +8,9 @@ with lib;
|
||||
option = x:
|
||||
x // { optional = true; };
|
||||
|
||||
yes = { tristate = "y"; optional = false; };
|
||||
no = { tristate = "n"; optional = false; };
|
||||
module = { tristate = "m"; optional = false; };
|
||||
unset = { tristate = null; optional = false; };
|
||||
yes = { tristate = "y"; optional = false; };
|
||||
no = { tristate = "n"; optional = false; };
|
||||
module = { tristate = "m"; optional = false; };
|
||||
freeform = x: { freeform = x; optional = false; };
|
||||
|
||||
/*
|
||||
|
||||
160
lib/modules.nix
160
lib/modules.nix
@@ -63,8 +63,39 @@ let
|
||||
decls
|
||||
));
|
||||
|
||||
/* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
|
||||
or file://./../doc/module-system/module-system.chapter.md
|
||||
in
|
||||
|
||||
rec {
|
||||
|
||||
/*
|
||||
Evaluate a set of modules. The result is a set with the attributes:
|
||||
|
||||
‘options’: The nested set of all option declarations,
|
||||
|
||||
‘config’: The nested set of all option values.
|
||||
|
||||
‘type’: A module system type representing the module set as a submodule,
|
||||
to be extended by configuration from the containing module set.
|
||||
|
||||
This is also available as the module argument ‘moduleType’.
|
||||
|
||||
‘extendModules’: A function similar to ‘evalModules’ but building on top
|
||||
of the module set. Its arguments, ‘modules’ and ‘specialArgs’ are
|
||||
added to the existing values.
|
||||
|
||||
Using ‘extendModules’ a few times has no performance impact as long
|
||||
as you only reference the final ‘options’ and ‘config’.
|
||||
If you do reference multiple ‘config’ (or ‘options’) from before and
|
||||
after ‘extendModules’, performance is the same as with multiple
|
||||
‘evalModules’ invocations, because the new modules' ability to
|
||||
override existing configuration fundamentally requires a new
|
||||
fixpoint to be constructed.
|
||||
|
||||
This is also available as a module argument.
|
||||
|
||||
‘_module’: A portion of the configuration tree which is elided from
|
||||
‘config’. It contains some values that are mostly internal to the
|
||||
module system implementation.
|
||||
|
||||
!!! Please think twice before adding to this argument list! The more
|
||||
that is specified here instead of in the modules themselves the harder
|
||||
@@ -79,12 +110,8 @@ let
|
||||
# there's _module.args. If specialArgs.modulesPath is defined it will be
|
||||
# used as the base path for disabledModules.
|
||||
specialArgs ? {}
|
||||
, # `class`:
|
||||
# A nominal type for modules. When set and non-null, this adds a check to
|
||||
# make sure that only compatible modules are imported.
|
||||
# This would be remove in the future, Prefer _module.args option instead.
|
||||
class ? null
|
||||
, args ? {}
|
||||
, # This would be remove in the future, Prefer _module.args option instead.
|
||||
args ? {}
|
||||
, # This would be remove in the future, Prefer _module.check option instead.
|
||||
check ? true
|
||||
}:
|
||||
@@ -233,7 +260,6 @@ let
|
||||
|
||||
merged =
|
||||
let collected = collectModules
|
||||
class
|
||||
(specialArgs.modulesPath or "")
|
||||
(regularModules ++ [ internalModule ])
|
||||
({ inherit lib options config specialArgs; } // specialArgs);
|
||||
@@ -310,64 +336,38 @@ let
|
||||
prefix ? [],
|
||||
}:
|
||||
evalModules (evalModulesArgs // {
|
||||
inherit class;
|
||||
modules = regularModules ++ modules;
|
||||
specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
|
||||
prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
|
||||
});
|
||||
|
||||
type = lib.types.submoduleWith {
|
||||
inherit modules specialArgs class;
|
||||
inherit modules specialArgs;
|
||||
};
|
||||
|
||||
result = withWarnings {
|
||||
_type = "configuration";
|
||||
options = checked options;
|
||||
config = checked (removeAttrs config [ "_module" ]);
|
||||
_module = checked (config._module);
|
||||
inherit extendModules type;
|
||||
class = class;
|
||||
};
|
||||
in result;
|
||||
|
||||
# collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
|
||||
# collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
|
||||
#
|
||||
# Collects all modules recursively through `import` statements, filtering out
|
||||
# all modules in disabledModules.
|
||||
collectModules = class: let
|
||||
collectModules = let
|
||||
|
||||
# Like unifyModuleSyntax, but also imports paths and calls functions if necessary
|
||||
loadModule = args: fallbackFile: fallbackKey: m:
|
||||
if isFunction m then
|
||||
unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgs fallbackKey m args)
|
||||
else if isAttrs m then
|
||||
if m._type or "module" == "module" then
|
||||
unifyModuleSyntax fallbackFile fallbackKey m
|
||||
else if m._type == "if" || m._type == "override" then
|
||||
loadModule args fallbackFile fallbackKey { config = m; }
|
||||
else
|
||||
throw (
|
||||
"Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}"
|
||||
+ lib.optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}."
|
||||
+ lib.optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice."
|
||||
# Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line.
|
||||
)
|
||||
if isFunction m || isAttrs m then
|
||||
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) (applyModuleArgsIfFunction (toString m) (import m) args);
|
||||
|
||||
checkModule =
|
||||
if class != null
|
||||
then
|
||||
m:
|
||||
if m._class != null -> m._class == class
|
||||
then m
|
||||
else
|
||||
throw "The module ${m._file or m.key} was imported into ${class} instead of ${m._class}."
|
||||
else
|
||||
m: m;
|
||||
|
||||
/*
|
||||
Collects all modules recursively into the form
|
||||
|
||||
@@ -401,7 +401,7 @@ let
|
||||
};
|
||||
in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
|
||||
let
|
||||
module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
|
||||
module = loadModule args parentFile "${parentKey}:anon-${toString n}" x;
|
||||
collectedImports = collectStructuredModules module._file module.key module.imports args;
|
||||
in {
|
||||
key = module.key;
|
||||
@@ -465,12 +465,11 @@ let
|
||||
else config;
|
||||
in
|
||||
if m ? config || m ? options then
|
||||
let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
|
||||
let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
|
||||
if badAttrs != {} then
|
||||
throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute."
|
||||
else
|
||||
{ _file = toString m._file or file;
|
||||
_class = m._class or null;
|
||||
key = toString m.key or key;
|
||||
disabledModules = m.disabledModules or [];
|
||||
imports = m.imports or [];
|
||||
@@ -481,18 +480,14 @@ let
|
||||
# shorthand syntax
|
||||
lib.throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
|
||||
{ _file = toString m._file or file;
|
||||
_class = m._class or null;
|
||||
key = toString m.key or key;
|
||||
disabledModules = m.disabledModules or [];
|
||||
imports = m.require or [] ++ m.imports or [];
|
||||
options = {};
|
||||
config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);
|
||||
config = addFreeformType (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]);
|
||||
};
|
||||
|
||||
applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }:
|
||||
if isFunction f then applyModuleArgs key f args else f;
|
||||
|
||||
applyModuleArgs = key: f: args@{ config, options, lib, ... }:
|
||||
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
|
||||
@@ -516,7 +511,9 @@ let
|
||||
# context on the explicit arguments of "args" too. This update
|
||||
# operator is used to make the "args@{ ... }: with args.lib;" notation
|
||||
# works.
|
||||
in f (args // extraArgs);
|
||||
in f (args // extraArgs)
|
||||
else
|
||||
f;
|
||||
|
||||
/* Merge a list of modules. This will recurse over the option
|
||||
declarations in all modules, combining them into a single set.
|
||||
@@ -1221,67 +1218,4 @@ let
|
||||
_file = file;
|
||||
config = lib.importTOML file;
|
||||
};
|
||||
|
||||
private = lib.mapAttrs
|
||||
(k: lib.warn "External use of `lib.modules.${k}` is deprecated. If your use case isn't covered by non-deprecated functions, we'd like to know more and perhaps support your use case well, instead of providing access to these low level functions. In this case please open an issue in https://github.com/nixos/nixpkgs/issues/.")
|
||||
{
|
||||
inherit
|
||||
applyModuleArgsIfFunction
|
||||
dischargeProperties
|
||||
evalOptionValue
|
||||
mergeModules
|
||||
mergeModules'
|
||||
pushDownProperties
|
||||
unifyModuleSyntax
|
||||
;
|
||||
collectModules = collectModules null;
|
||||
};
|
||||
|
||||
in
|
||||
private //
|
||||
{
|
||||
# NOTE: not all of these functions are necessarily public interfaces; some
|
||||
# are just needed by types.nix, but are not meant to be consumed
|
||||
# externally.
|
||||
inherit
|
||||
defaultOrderPriority
|
||||
defaultOverridePriority
|
||||
defaultPriority
|
||||
doRename
|
||||
evalModules
|
||||
filterOverrides
|
||||
filterOverrides'
|
||||
fixMergeModules
|
||||
fixupOptionType # should be private?
|
||||
importJSON
|
||||
importTOML
|
||||
mergeDefinitions
|
||||
mergeOptionDecls # should be private?
|
||||
mkAfter
|
||||
mkAliasAndWrapDefinitions
|
||||
mkAliasAndWrapDefsWithPriority
|
||||
mkAliasDefinitions
|
||||
mkAliasIfDef
|
||||
mkAliasOptionModule
|
||||
mkAliasOptionModuleMD
|
||||
mkAssert
|
||||
mkBefore
|
||||
mkChangedOptionModule
|
||||
mkDefault
|
||||
mkDerivedConfig
|
||||
mkFixStrictness
|
||||
mkForce
|
||||
mkIf
|
||||
mkImageMediaOverride
|
||||
mkMerge
|
||||
mkMergedOptionModule
|
||||
mkOptionDefault
|
||||
mkOrder
|
||||
mkOverride
|
||||
mkRemovedOptionModule
|
||||
mkRenamedOptionModule
|
||||
mkRenamedOptionModuleWith
|
||||
mkVMOverride
|
||||
setDefaultModuleLocation
|
||||
sortProperties;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ rec {
|
||||
config = "mipsel-unknown-linux-gnu";
|
||||
} // platforms.fuloong2f_n32;
|
||||
|
||||
loongarch64-linux = {
|
||||
config = "loongarch64-unknown-linux-gnu";
|
||||
};
|
||||
|
||||
# can execute on 32bit chip
|
||||
mips-linux-gnu = { config = "mips-unknown-linux-gnu"; } // platforms.gcc_mips32r2_o32;
|
||||
mipsel-linux-gnu = { config = "mipsel-unknown-linux-gnu"; } // platforms.gcc_mips32r2_o32;
|
||||
@@ -135,10 +139,6 @@ rec {
|
||||
libc = "newlib";
|
||||
};
|
||||
|
||||
loongarch64-linux = {
|
||||
config = "loongarch64-unknown-linux-gnu";
|
||||
};
|
||||
|
||||
mmix = {
|
||||
config = "mmix-unknown-mmixware";
|
||||
libc = "newlib";
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
with import ../default.nix;
|
||||
|
||||
let
|
||||
testingThrow = expr: {
|
||||
expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
|
||||
expected = { success = false; value = false; };
|
||||
};
|
||||
testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
|
||||
|
||||
testSanitizeDerivationName = { name, expected }:
|
||||
let
|
||||
@@ -919,30 +914,6 @@ runTests {
|
||||
expected = "«foo»";
|
||||
};
|
||||
|
||||
testToPlist =
|
||||
let
|
||||
deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
|
||||
in {
|
||||
expr = mapAttrs (const (generators.toPlist { })) {
|
||||
value = {
|
||||
nested.values = rec {
|
||||
int = 42;
|
||||
float = 0.1337;
|
||||
bool = true;
|
||||
emptystring = "";
|
||||
string = "fn\${o}\"r\\d";
|
||||
newlinestring = "\n";
|
||||
path = /. + "/foo";
|
||||
null_ = null;
|
||||
list = [ 3 4 "test" ];
|
||||
emptylist = [];
|
||||
attrs = { foo = null; "foo b/ar" = "baz"; };
|
||||
emptyattrs = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
|
||||
};
|
||||
|
||||
testToLuaEmptyAttrSet = {
|
||||
expr = generators.toLua {} {};
|
||||
@@ -991,41 +962,6 @@ runTests {
|
||||
expected = ''{ 41, 43 }'';
|
||||
};
|
||||
|
||||
testToLuaEmptyBindings = {
|
||||
expr = generators.toLua { asBindings = true; } {};
|
||||
expected = "";
|
||||
};
|
||||
|
||||
testToLuaBindings = {
|
||||
expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
|
||||
expected = ''
|
||||
_y = {
|
||||
["a"] = 43
|
||||
}
|
||||
x1 = 41
|
||||
'';
|
||||
};
|
||||
|
||||
testToLuaPartialTableBindings = {
|
||||
expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
|
||||
expected = ''
|
||||
x.y = 42
|
||||
'';
|
||||
};
|
||||
|
||||
testToLuaIndentedBindings = {
|
||||
expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
|
||||
expected = " x = {\n [\"y\"] = 42\n }\n";
|
||||
};
|
||||
|
||||
testToLuaBindingsWithSpace = testingThrow (
|
||||
generators.toLua { asBindings = true; } { "with space" = 42; }
|
||||
);
|
||||
|
||||
testToLuaBindingsWithLeadingDigit = testingThrow (
|
||||
generators.toLua { asBindings = true; } { "11eleven" = 42; }
|
||||
);
|
||||
|
||||
testToLuaBasicExample = {
|
||||
expr = generators.toLua {} {
|
||||
cmd = [ "typescript-language-server" "--stdio" ];
|
||||
|
||||
@@ -166,7 +166,6 @@ checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*'
|
||||
checkConfigOutput '^true$' "$@" ./define-module-check.nix
|
||||
|
||||
# Check coerced value.
|
||||
set --
|
||||
checkConfigOutput '^"42"$' config.value ./declare-coerced-value.nix
|
||||
checkConfigOutput '^"24"$' config.value ./declare-coerced-value.nix ./define-value-string.nix
|
||||
checkConfigError 'A definition for option .* is not.*string or signed integer convertible to it.*. Definition values:\n\s*- In .*: \[ \]' config.value ./declare-coerced-value.nix ./define-value-list.nix
|
||||
@@ -255,8 +254,6 @@ checkConfigError 'A definition for option .* is not of type .*' \
|
||||
## Freeform modules
|
||||
# Assigning without a declared option should work
|
||||
checkConfigOutput '^"24"$' config.value ./freeform-attrsOf.nix ./define-value-string.nix
|
||||
# Shorthand modules interpret `meta` and `class` as config items
|
||||
checkConfigOutput '^true$' options._module.args.value.result ./freeform-attrsOf.nix ./define-freeform-keywords-shorthand.nix
|
||||
# No freeform assignments shouldn't make it error
|
||||
checkConfigOutput '^{ }$' config ./freeform-attrsOf.nix
|
||||
# but only if the type matches
|
||||
@@ -362,24 +359,6 @@ checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survive
|
||||
# because of an `extendModules` bug, issue 168767.
|
||||
checkConfigOutput '^1$' config.sub.specialisation.value ./extendModules-168767-imports.nix
|
||||
|
||||
# Class checks, evalModules
|
||||
checkConfigOutput '^{ }$' config.ok.config ./class-check.nix
|
||||
checkConfigOutput '"nixos"' config.ok.class ./class-check.nix
|
||||
checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nixos instead of darwin.' config.fail.config ./class-check.nix
|
||||
checkConfigError 'The module foo.nix#darwinModules.default was imported into nixos instead of darwin.' config.fail-anon.config ./class-check.nix
|
||||
|
||||
# Class checks, submoduleWith
|
||||
checkConfigOutput '^{ }$' config.sub.nixosOk ./class-check.nix
|
||||
checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nixos instead of darwin.' config.sub.nixosFail.config ./class-check.nix
|
||||
|
||||
# submoduleWith type merge with different class
|
||||
checkConfigError 'error: A submoduleWith option is declared multiple times with conflicting class values "darwin" and "nixos".' config.sub.mergeFail.config ./class-check.nix
|
||||
|
||||
# _type check
|
||||
checkConfigError 'Could not load a value as a module, because it is of type "flake", in file .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix
|
||||
checkConfigOutput '^true$' "$@" config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix
|
||||
checkConfigError 'Could not load a value as a module, because it is of type "configuration", in file .*/import-configuration.nix.*please only import the modules that make up the configuration.*' config ./import-configuration.nix
|
||||
|
||||
# doRename works when `warnings` does not exist.
|
||||
checkConfigOutput '^1234$' config.c.d.e ./doRename-basic.nix
|
||||
# doRename adds a warning.
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
{ lib, ... }: {
|
||||
options = {
|
||||
sub = {
|
||||
nixosOk = lib.mkOption {
|
||||
type = lib.types.submoduleWith {
|
||||
class = "nixos";
|
||||
modules = [ ];
|
||||
};
|
||||
};
|
||||
# Same but will have bad definition
|
||||
nixosFail = lib.mkOption {
|
||||
type = lib.types.submoduleWith {
|
||||
class = "nixos";
|
||||
modules = [ ];
|
||||
};
|
||||
};
|
||||
|
||||
mergeFail = lib.mkOption {
|
||||
type = lib.types.submoduleWith {
|
||||
class = "nixos";
|
||||
modules = [ ];
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
imports = [
|
||||
{
|
||||
options = {
|
||||
sub = {
|
||||
mergeFail = lib.mkOption {
|
||||
type = lib.types.submoduleWith {
|
||||
class = "darwin";
|
||||
modules = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
config = {
|
||||
_module.freeformType = lib.types.anything;
|
||||
ok =
|
||||
lib.evalModules {
|
||||
class = "nixos";
|
||||
modules = [
|
||||
./module-class-is-nixos.nix
|
||||
];
|
||||
};
|
||||
|
||||
fail =
|
||||
lib.evalModules {
|
||||
class = "nixos";
|
||||
modules = [
|
||||
./module-class-is-nixos.nix
|
||||
./module-class-is-darwin.nix
|
||||
];
|
||||
};
|
||||
|
||||
fail-anon =
|
||||
lib.evalModules {
|
||||
class = "nixos";
|
||||
modules = [
|
||||
./module-class-is-nixos.nix
|
||||
{ _file = "foo.nix#darwinModules.default";
|
||||
_class = "darwin";
|
||||
config = {};
|
||||
imports = [];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
sub.nixosOk = { _class = "nixos"; };
|
||||
sub.nixosFail = { imports = [ ./module-class-is-darwin.nix ]; };
|
||||
};
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{ lib, ... }:
|
||||
# I think this might occur more realistically in a submodule
|
||||
{
|
||||
imports = [ (lib.mkIf true { enable = true; }) ];
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{ config, ... }: {
|
||||
class = { "just" = "data"; };
|
||||
a = "one";
|
||||
b = "two";
|
||||
meta = "meta";
|
||||
|
||||
_module.args.result =
|
||||
let r = builtins.removeAttrs config [ "_module" ];
|
||||
in builtins.trace (builtins.deepSeq r r) (r == {
|
||||
a = "one";
|
||||
b = "two";
|
||||
class = { "just" = "data"; };
|
||||
meta = "meta";
|
||||
});
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
myconf = lib.evalModules { modules = [ { } ]; };
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
# We can't do this. A configuration is not equal to its set of a modules.
|
||||
# Equating those would lead to a mess, as specialArgs, anonymous modules
|
||||
# that can't be deduplicated, and possibly more come into play.
|
||||
myconf
|
||||
];
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
_class = "darwin";
|
||||
config = {};
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
_class = "nixos";
|
||||
config = {};
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
imports = [ { _type = "flake"; } ];
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>nested</key>
|
||||
<dict>
|
||||
<key>values</key>
|
||||
<dict>
|
||||
<key>attrs</key>
|
||||
<dict>
|
||||
<key>foo b/ar</key>
|
||||
<string>baz</string>
|
||||
</dict>
|
||||
<key>bool</key>
|
||||
<true/>
|
||||
<key>emptyattrs</key>
|
||||
<dict>
|
||||
|
||||
</dict>
|
||||
<key>emptylist</key>
|
||||
<array>
|
||||
|
||||
</array>
|
||||
<key>emptystring</key>
|
||||
<string></string>
|
||||
<key>float</key>
|
||||
<real>0.133700</real>
|
||||
<key>int</key>
|
||||
<integer>42</integer>
|
||||
<key>list</key>
|
||||
<array>
|
||||
<integer>3</integer>
|
||||
<integer>4</integer>
|
||||
<string>test</string>
|
||||
</array>
|
||||
<key>newlinestring</key>
|
||||
<string>
|
||||
</string>
|
||||
<key>path</key>
|
||||
<string>/foo</string>
|
||||
<key>string</key>
|
||||
<string>fn${o}"r\d</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -476,14 +476,6 @@ rec {
|
||||
check = x: isDerivation x && hasAttr "shellPath" x;
|
||||
};
|
||||
|
||||
pkgs = addCheck
|
||||
(unique { message = "A Nixpkgs pkgs set can not be merged with another pkgs set."; } attrs // {
|
||||
name = "pkgs";
|
||||
descriptionClass = "noun";
|
||||
description = "Nixpkgs package set";
|
||||
})
|
||||
(x: (x._type or null) == "pkgs");
|
||||
|
||||
path = mkOptionType {
|
||||
name = "path";
|
||||
descriptionClass = "noun";
|
||||
@@ -704,7 +696,6 @@ rec {
|
||||
, specialArgs ? {}
|
||||
, shorthandOnlyDefinesConfig ? false
|
||||
, description ? null
|
||||
, class ? null
|
||||
}@attrs:
|
||||
let
|
||||
inherit (lib.modules) evalModules;
|
||||
@@ -716,7 +707,7 @@ rec {
|
||||
) defs;
|
||||
|
||||
base = evalModules {
|
||||
inherit class specialArgs;
|
||||
inherit specialArgs;
|
||||
modules = [{
|
||||
# This is a work-around for the fact that some sub-modules,
|
||||
# such as the one included in an attribute set, expects an "args"
|
||||
@@ -771,14 +762,9 @@ rec {
|
||||
functor = defaultFunctor name // {
|
||||
type = types.submoduleWith;
|
||||
payload = {
|
||||
inherit modules class specialArgs shorthandOnlyDefinesConfig description;
|
||||
inherit modules specialArgs shorthandOnlyDefinesConfig description;
|
||||
};
|
||||
binOp = lhs: rhs: {
|
||||
class =
|
||||
if lhs.class == null then rhs.class
|
||||
else if rhs.class == null then lhs.class
|
||||
else if lhs.class == rhs.class then lhs.class
|
||||
else throw "A submoduleWith option is declared multiple times with conflicting class values \"${toString lhs.class}\" and \"${toString rhs.class}\".";
|
||||
modules = lhs.modules ++ rhs.modules;
|
||||
specialArgs =
|
||||
let intersecting = builtins.intersectAttrs lhs.specialArgs rhs.specialArgs;
|
||||
|
||||
@@ -1654,16 +1654,6 @@
|
||||
githubId = 1017537;
|
||||
name = "Bruno Bieth";
|
||||
};
|
||||
badele = {
|
||||
name = "Bruno Adelé";
|
||||
email = "brunoadele@gmail.com";
|
||||
matrix = "@badele:matrix.org";
|
||||
github = "badele";
|
||||
githubId = 2806307;
|
||||
keys = [{
|
||||
fingerprint = "00F4 21C4 C537 7BA3 9820 E13F 6B95 E13D E469 CC5D";
|
||||
}];
|
||||
};
|
||||
badmutex = {
|
||||
email = "github@badi.sh";
|
||||
github = "badmutex";
|
||||
@@ -5705,12 +5695,6 @@
|
||||
githubId = 1713676;
|
||||
name = "Luis G. Torres";
|
||||
};
|
||||
giorgiga = {
|
||||
email = "giorgio.gallo@bitnic.it";
|
||||
github = "giorgiga";
|
||||
githubId = 471835;
|
||||
name = "Giorgio Gallo";
|
||||
};
|
||||
GKasparov = {
|
||||
email = "mizozahr@gmail.com";
|
||||
github = "GKasparov";
|
||||
@@ -5882,12 +5866,6 @@
|
||||
fingerprint = "7FC7 98AB 390E 1646 ED4D 8F1F 797F 6238 68CD 00C2";
|
||||
}];
|
||||
};
|
||||
greg = {
|
||||
email = "greg.hellings@gmail.com";
|
||||
github = "greg-hellings";
|
||||
githubId = 273582;
|
||||
name = "greg";
|
||||
};
|
||||
greizgh = {
|
||||
email = "greizgh@ephax.org";
|
||||
github = "greizgh";
|
||||
@@ -8682,12 +8660,6 @@
|
||||
githubId = 621759;
|
||||
name = "Lassulus";
|
||||
};
|
||||
laurent-f1z1 = {
|
||||
email = "laurent.nixpkgs@fainsin.bzh";
|
||||
github = "Laurent2916";
|
||||
githubId = 21087104;
|
||||
name = "Laurent Fainsin";
|
||||
};
|
||||
layus = {
|
||||
email = "layus.on@gmail.com";
|
||||
github = "layus";
|
||||
@@ -8792,12 +8764,6 @@
|
||||
githubId = 567634;
|
||||
name = "Daniel Kuehn";
|
||||
};
|
||||
lelgenio = {
|
||||
email = "lelgenio@disroot.org";
|
||||
github = "lelgenio";
|
||||
githubId = 31388299;
|
||||
name = "Leonardo Eugênio";
|
||||
};
|
||||
leo60228 = {
|
||||
email = "leo@60228.dev";
|
||||
matrix = "@leo60228:matrix.org";
|
||||
@@ -12208,16 +12174,6 @@
|
||||
githubId = 581269;
|
||||
name = "Philip Potter";
|
||||
};
|
||||
philclifford = {
|
||||
email = "philip.clifford@gmail.com";
|
||||
matrix = "@phil8o:matrix.org";
|
||||
github = "philclifford";
|
||||
githubId = 8797027;
|
||||
keys = [{
|
||||
fingerprint = "FC15 E59F 0CFA 9329 101B 71D9 92F7 A790 E9BA F1F7";
|
||||
}];
|
||||
name = "Phil Clifford";
|
||||
};
|
||||
phile314 = {
|
||||
email = "nix@314.ch";
|
||||
github = "phile314";
|
||||
@@ -13455,12 +13411,6 @@
|
||||
githubId = 710906;
|
||||
name = "Roel van Dijk";
|
||||
};
|
||||
rogarb = {
|
||||
email = "rogarb@rgarbage.fr";
|
||||
github = "rogarb";
|
||||
githubId = 69053978;
|
||||
name = "rogarb";
|
||||
};
|
||||
roman = {
|
||||
email = "open-source@roman-gonzalez.info";
|
||||
github = "roman";
|
||||
@@ -14484,15 +14434,6 @@
|
||||
githubId = 12828415;
|
||||
name = "Michel Weitbrecht";
|
||||
};
|
||||
slwst = {
|
||||
email = "email@slw.st";
|
||||
github = "slwst";
|
||||
githubId = 11047377;
|
||||
name = "slwst";
|
||||
keys = [{
|
||||
fingerprint = "6CEB 4A2F E6DC C345 1B2B 4733 AD52 C5FB 3EFE CC7A";
|
||||
}];
|
||||
};
|
||||
smakarov = {
|
||||
email = "setser200018@gmail.com";
|
||||
github = "SeTSeR";
|
||||
@@ -14689,6 +14630,12 @@
|
||||
githubId = 6391601;
|
||||
name = "Roger Mason";
|
||||
};
|
||||
spwhitt = {
|
||||
email = "sw@swhitt.me";
|
||||
github = "spwhitt";
|
||||
githubId = 1414088;
|
||||
name = "Spencer Whitt";
|
||||
};
|
||||
squalus = {
|
||||
email = "squalus@squalus.net";
|
||||
github = "squalus";
|
||||
@@ -15298,12 +15245,6 @@
|
||||
}];
|
||||
name = "David Tchekachev";
|
||||
};
|
||||
tcheronneau = {
|
||||
email = "nix@mcth.fr";
|
||||
github = "tcheronneau";
|
||||
githubId = 7914437;
|
||||
name = "Thomas Cheronneau";
|
||||
};
|
||||
tckmn = {
|
||||
email = "andy@tck.mn";
|
||||
github = "tckmn";
|
||||
@@ -15691,11 +15632,10 @@
|
||||
githubId = 18621411;
|
||||
};
|
||||
tilpner = {
|
||||
name = "Till Höppner";
|
||||
email = "nixpkgs@tilpner.com";
|
||||
matrix = "@tilpner:tx0.co";
|
||||
email = "till@hoeppner.ws";
|
||||
github = "tilpner";
|
||||
githubId = 4322055;
|
||||
name = "Till Höppner";
|
||||
};
|
||||
timbertson = {
|
||||
email = "tim@gfxmonk.net";
|
||||
@@ -17532,12 +17472,6 @@
|
||||
githubId = 393108;
|
||||
name = "Damien Diederen";
|
||||
};
|
||||
zumorica = {
|
||||
name = "Vera Aguilera Puerto";
|
||||
email = "gradientvera+nix@outlook.com";
|
||||
github = "Zumorica";
|
||||
githubId = 6766154;
|
||||
};
|
||||
zupo = {
|
||||
name = "Nejc Zupan";
|
||||
email = "nejczupan+nix@gmail.com";
|
||||
|
||||
@@ -100,12 +100,11 @@ def convert_to_throw(date_older_list: list[str]) -> list[tuple[str, str]]:
|
||||
date_older_list.remove(line)
|
||||
continue
|
||||
|
||||
alias = before_equal
|
||||
alias_unquoted = before_equal.strip('"')
|
||||
alias = before_equal.strip()
|
||||
after_equal_list = [x.strip(";:") for x in after_equal.split()]
|
||||
|
||||
converted = (
|
||||
f"{indent}{alias} = throw \"'{alias_unquoted}' has been renamed to/replaced by"
|
||||
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")}'
|
||||
)
|
||||
|
||||
@@ -149,15 +149,6 @@ with lib.maintainers; {
|
||||
enableFeatureFreezePing = true;
|
||||
};
|
||||
|
||||
cuda = {
|
||||
members = [
|
||||
SomeoneSerge
|
||||
];
|
||||
scope = "Maintain CUDA-enabled packages";
|
||||
shortName = "Cuda";
|
||||
githubTeams = [ "cuda-maintainers" ];
|
||||
};
|
||||
|
||||
darwin = {
|
||||
members = [
|
||||
toonn
|
||||
|
||||
@@ -25,8 +25,6 @@ These include `pkgs.nixosTest`, `testing-python.nix` and `make-test-python.nix`.
|
||||
|
||||
## Testing changes to the test framework {#sec-test-the-test-framework}
|
||||
|
||||
We currently have limited unit tests for the framework itself. You may run these with `nix-build -A nixosTests.nixos-test-driver`.
|
||||
|
||||
When making significant changes to the test framework, we run the tests on Hydra, to avoid disrupting the larger NixOS project.
|
||||
|
||||
For this, we use the `python-test-refactoring` branch in the `NixOS/nixpkgs` repository, and its [corresponding Hydra jobset](https://hydra.nixos.org/jobset/nixos/python-test-refactoring).
|
||||
|
||||
@@ -13,7 +13,7 @@ checking for entire option trees, it is only recommended for use in
|
||||
submodules.
|
||||
|
||||
::: {#ex-freeform-module .example}
|
||||
### Freeform submodule
|
||||
**Example: Freeform submodule**
|
||||
|
||||
The following shows a submodule assigning a freeform type that allows
|
||||
arbitrary attributes with `str` values below `settings`, but also
|
||||
|
||||
@@ -77,7 +77,6 @@ The option's description is "Whether to enable \<name\>.".
|
||||
For example:
|
||||
|
||||
::: {#ex-options-declarations-util-mkEnableOption-magic .example}
|
||||
### `mkEnableOption` usage
|
||||
```nix
|
||||
lib.mkEnableOption (lib.mdDoc "magic")
|
||||
# is like
|
||||
@@ -127,7 +126,6 @@ During the transition to CommonMark documentation `mkPackageOption` creates an o
|
||||
Examples:
|
||||
|
||||
::: {#ex-options-declarations-util-mkPackageOption-hello .example}
|
||||
### Simple `mkPackageOption` usage
|
||||
```nix
|
||||
lib.mkPackageOptionMD pkgs "hello" { }
|
||||
# is like
|
||||
@@ -141,7 +139,6 @@ lib.mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-options-declarations-util-mkPackageOption-ghc .example}
|
||||
### `mkPackageOption` with explicit default and example
|
||||
```nix
|
||||
lib.mkPackageOptionMD pkgs "GHC" {
|
||||
default = [ "ghc" ];
|
||||
@@ -159,7 +156,6 @@ lib.mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-options-declarations-util-mkPackageOption-extraDescription .example}
|
||||
### `mkPackageOption` with additional description text
|
||||
```nix
|
||||
mkPackageOption pkgs [ "python39Packages" "pytorch" ] {
|
||||
extraDescription = "This is an example and doesn't actually do anything.";
|
||||
@@ -221,7 +217,7 @@ changing the main service module file and the type system automatically
|
||||
enforces that there can only be a single display manager enabled.
|
||||
|
||||
::: {#ex-option-declaration-eot-service .example}
|
||||
### Extensible type placeholder in the service module
|
||||
**Example: Extensible type placeholder in the service module**
|
||||
```nix
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
description = "Display manager to use";
|
||||
@@ -231,7 +227,7 @@ services.xserver.displayManager.enable = mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-option-declaration-eot-backend-gdm .example}
|
||||
### Extending `services.xserver.displayManager.enable` in the `gdm` module
|
||||
**Example: Extending `services.xserver.displayManager.enable` in the `gdm` module**
|
||||
```nix
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
type = with types; nullOr (enum [ "gdm" ]);
|
||||
@@ -240,7 +236,7 @@ services.xserver.displayManager.enable = mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-option-declaration-eot-backend-sddm .example}
|
||||
### Extending `services.xserver.displayManager.enable` in the `sddm` module
|
||||
**Example: Extending `services.xserver.displayManager.enable` in the `sddm` module**
|
||||
```nix
|
||||
services.xserver.displayManager.enable = mkOption {
|
||||
type = with types; nullOr (enum [ "sddm" ]);
|
||||
|
||||
@@ -36,7 +36,7 @@ merging is handled.
|
||||
together. This type is recommended when the option type is unknown.
|
||||
|
||||
::: {#ex-types-anything .example}
|
||||
### `types.anything`
|
||||
**Example: `types.anything` Example**
|
||||
|
||||
Two definitions of this type like
|
||||
|
||||
@@ -99,10 +99,6 @@ merging is handled.
|
||||
problems.
|
||||
:::
|
||||
|
||||
`types.pkgs`
|
||||
|
||||
: A type for the top level Nixpkgs package set.
|
||||
|
||||
### Numeric types {#sec-option-types-numeric}
|
||||
|
||||
`types.int`
|
||||
@@ -360,7 +356,7 @@ you will still need to provide a default value (e.g. an empty attribute set)
|
||||
if you want to allow users to leave it undefined.
|
||||
|
||||
::: {#ex-submodule-direct .example}
|
||||
### Directly defined submodule
|
||||
**Example: Directly defined submodule**
|
||||
```nix
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
@@ -379,7 +375,7 @@ options.mod = mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-submodule-reference .example}
|
||||
### Submodule defined as a reference
|
||||
**Example: Submodule defined as a reference**
|
||||
```nix
|
||||
let
|
||||
modOptions = {
|
||||
@@ -407,7 +403,7 @@ multiple definitions of the submodule option set
|
||||
([Example: Definition of a list of submodules](#ex-submodule-listof-definition)).
|
||||
|
||||
::: {#ex-submodule-listof-declaration .example}
|
||||
### Declaration of a list of submodules
|
||||
**Example: Declaration of a list of submodules**
|
||||
```nix
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
@@ -426,7 +422,7 @@ options.mod = mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-submodule-listof-definition .example}
|
||||
### Definition of a list of submodules
|
||||
**Example: Definition of a list of submodules**
|
||||
```nix
|
||||
config.mod = [
|
||||
{ foo = 1; bar = "one"; }
|
||||
@@ -441,7 +437,7 @@ multiple named definitions of the submodule option set
|
||||
([Example: Definition of attribute sets of submodules](#ex-submodule-attrsof-definition)).
|
||||
|
||||
::: {#ex-submodule-attrsof-declaration .example}
|
||||
### Declaration of attribute sets of submodules
|
||||
**Example: Declaration of attribute sets of submodules**
|
||||
```nix
|
||||
options.mod = mkOption {
|
||||
description = "submodule example";
|
||||
@@ -460,7 +456,7 @@ options.mod = mkOption {
|
||||
:::
|
||||
|
||||
::: {#ex-submodule-attrsof-definition .example}
|
||||
### Definition of attribute sets of submodules
|
||||
**Example: Definition of attribute sets of submodules**
|
||||
```nix
|
||||
config.mod.one = { foo = 1; bar = "one"; };
|
||||
config.mod.two = { foo = 2; bar = "two"; };
|
||||
@@ -480,7 +476,7 @@ Types are mainly characterized by their `check` and `merge` functions.
|
||||
([Example: Overriding a type check](#ex-extending-type-check-2)).
|
||||
|
||||
::: {#ex-extending-type-check-1 .example}
|
||||
### Adding a type check
|
||||
**Example: Adding a type check**
|
||||
|
||||
```nix
|
||||
byte = mkOption {
|
||||
@@ -491,7 +487,7 @@ Types are mainly characterized by their `check` and `merge` functions.
|
||||
:::
|
||||
|
||||
::: {#ex-extending-type-check-2 .example}
|
||||
### Overriding a type check
|
||||
**Example: Overriding a type check**
|
||||
|
||||
```nix
|
||||
nixThings = mkOption {
|
||||
|
||||
@@ -143,7 +143,7 @@ These functions all return an attribute set with these values:
|
||||
:::
|
||||
|
||||
::: {#ex-settings-nix-representable .example}
|
||||
### Module with conventional `settings` option
|
||||
**Example: Module with conventional `settings` option**
|
||||
|
||||
The following shows a module for an example program that uses a JSON
|
||||
configuration file. It demonstrates how above values can be used, along
|
||||
@@ -218,7 +218,7 @@ the port, which will enforce it to be a valid integer and make it show
|
||||
up in the manual.
|
||||
|
||||
::: {#ex-settings-typed-attrs .example}
|
||||
### Declaring a type-checked `settings` attribute
|
||||
**Example: Declaring a type-checked `settings` attribute**
|
||||
```nix
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
|
||||
@@ -37,7 +37,7 @@ options, but does not declare any. The structure of full NixOS modules
|
||||
is shown in [Example: Structure of NixOS Modules](#ex-module-syntax).
|
||||
|
||||
::: {#ex-module-syntax .example}
|
||||
### Structure of NixOS Modules
|
||||
**Example: Structure of NixOS Modules**
|
||||
```nix
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
@@ -100,7 +100,7 @@ Exec directives](#exec-escaping-example) for an example. When using these
|
||||
functions system environment substitution should *not* be disabled explicitly.
|
||||
|
||||
::: {#locate-example .example}
|
||||
### NixOS Module for the "locate" Service
|
||||
**Example: NixOS Module for the "locate" Service**
|
||||
```nix
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
@@ -161,7 +161,7 @@ in {
|
||||
:::
|
||||
|
||||
::: {#exec-escaping-example .example}
|
||||
### Escaping in Exec directives
|
||||
**Example: Escaping in Exec directives**
|
||||
```nix
|
||||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
|
||||
@@ -130,11 +130,6 @@ starting them in parallel:
|
||||
start_all()
|
||||
```
|
||||
|
||||
If the hostname of a node contains characters that can't be used in a
|
||||
Python variable name, those characters will be replaced with
|
||||
underscores in the variable name, so `nodes.machine-a` will be exposed
|
||||
to Python as `machine_a`.
|
||||
|
||||
## Machine objects {#ssec-machine-objects}
|
||||
|
||||
The following methods are available on machine objects:
|
||||
|
||||
@@ -538,7 +538,7 @@ drive (here `/dev/sda`). [Example: NixOS Configuration](#ex-config) shows a
|
||||
corresponding configuration Nix expression.
|
||||
|
||||
::: {#ex-partition-scheme-MBR .example}
|
||||
### Example partition schemes for NixOS on `/dev/sda` (MBR)
|
||||
**Example: Example partition schemes for NixOS on `/dev/sda` (MBR)**
|
||||
```ShellSession
|
||||
# parted /dev/sda -- mklabel msdos
|
||||
# parted /dev/sda -- mkpart primary 1MB -8GB
|
||||
@@ -547,7 +547,7 @@ corresponding configuration Nix expression.
|
||||
:::
|
||||
|
||||
::: {#ex-partition-scheme-UEFI .example}
|
||||
### Example partition schemes for NixOS on `/dev/sda` (UEFI)
|
||||
**Example: Example partition schemes for NixOS on `/dev/sda` (UEFI)**
|
||||
```ShellSession
|
||||
# parted /dev/sda -- mklabel gpt
|
||||
# parted /dev/sda -- mkpart primary 512MB -8GB
|
||||
@@ -558,7 +558,7 @@ corresponding configuration Nix expression.
|
||||
:::
|
||||
|
||||
::: {#ex-install-sequence .example}
|
||||
### Commands for Installing NixOS on `/dev/sda`
|
||||
**Example: Commands for Installing NixOS on `/dev/sda`**
|
||||
|
||||
With a partitioned disk.
|
||||
|
||||
@@ -578,7 +578,7 @@ With a partitioned disk.
|
||||
:::
|
||||
|
||||
::: {#ex-config .example}
|
||||
### Example: NixOS Configuration
|
||||
**Example: NixOS Configuration**
|
||||
```ShellSession
|
||||
{ config, pkgs, ... }: {
|
||||
imports = [
|
||||
|
||||
@@ -46,12 +46,7 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- [Cloudlog](https://www.magicbug.co.uk/cloudlog/), a web-based Amateur Radio logging application. Available as [services.cloudlog](#opt-services.cloudlog.enable).
|
||||
|
||||
- [Deepin Desktop Environment](https://github.com/linuxdeepin/dde), an elegant, easy to use and reliable desktop environment. Available as [services.xserver.desktopManager.deepin](options.html#opt-services.xserver.desktopManager.deepin).
|
||||
|
||||
- [system-repart](https://www.freedesktop.org/software/systemd/man/systemd-repart.service.html), grow and add partitions to a partition table. Available as [systemd.repart](options.html#opt-systemd.repart) and [boot.initrd.systemd.repart](options.html#opt-boot.initrd.systemd.repart)
|
||||
|
||||
- [fzf](https://github.com/junegunn/fzf), a command line fuzzyfinder. Available as [programs.fzf](#opt-programs.fzf.fuzzyCompletion).
|
||||
|
||||
- [readarr](https://github.com/Readarr/Readarr), Book Manager and Automation (Sonarr for Ebooks). Available as [services.readarr](options.html#opt-services.readarr.enable).
|
||||
|
||||
- [gemstash](https://github.com/rubygems/gemstash), a RubyGems.org cache and private gem server. Available as [services.gemstash](#opt-services.gemstash.enable).
|
||||
@@ -70,8 +65,6 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- [opensearch](https://opensearch.org), a search server alternative to Elasticsearch. Available as [services.opensearch](options.html#opt-services.opensearch.enable).
|
||||
|
||||
- [kavita](https://kavitareader.com), a self-hosted digital library. Available as [services.kavita](options.html#opt-services.kavita.enable).
|
||||
|
||||
- [monica](https://www.monicahq.com), an open source personal CRM. Available as [services.monica](options.html#opt-services.monica.enable).
|
||||
|
||||
- [authelia](https://www.authelia.com/), is an open-source authentication and authorization server. Available under [services.authelia](options.html#opt-services.authelia.enable).
|
||||
@@ -94,10 +87,6 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- [keyd](https://github.com/rvaiya/keyd), a key remapping daemon for linux. Available as [services.keyd](#opt-services.keyd.enable).
|
||||
|
||||
- [consul-template](https://github.com/hashicorp/consul-template/), a template rendering, notifier, and supervisor for HashiCorp Consul and Vault data. Available as [services.consul-template](#opt-services.consul-template.instances).
|
||||
|
||||
- [vault-agent](https://developer.hashicorp.com/vault/docs/agent), a template rendering and API auth proxy for HashiCorp Vault, similar to `consul-template`. Available as [services.vault-agent](#opt-services.vault-agent.instances).
|
||||
|
||||
- [v2rayA](https://v2raya.org), a Linux web GUI client of Project V which supports V2Ray, Xray, SS, SSR, Trojan and Pingtunnel. Available as [services.v2raya](options.html#opt-services.v2raya.enable).
|
||||
|
||||
- [wstunnel](https://github.com/erebe/wstunnel), a proxy tunnelling arbitrary TCP or UDP traffic through a WebSocket connection. Instances may be configured via [services.wstunnel](options.html#opt-services.wstunnel.enable).
|
||||
@@ -144,8 +133,6 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- `carnix` and `cratesIO` has been removed due to being unmaintained, use alternatives such as [naersk](https://github.com/nix-community/naersk) and [crate2nix](https://github.com/kolloch/crate2nix) instead.
|
||||
|
||||
- `services.asusd` configuration now uses strings instead of structured configuration, as upstream switched to the [RON](https://github.com/ron-rs/ron) configuration format. Support for structured configuration may return when [RON](https://github.com/ron-rs/ron) generation is implemented in nixpkgs.
|
||||
|
||||
- `checkInputs` have been renamed to `nativeCheckInputs`, because they behave the same as `nativeBuildInputs` when `doCheck` is set. `checkInputs` now denote a new type of dependencies, added to `buildInputs` when `doCheck` is set. As a rule of thumb, `nativeCheckInputs` are tools on `$PATH` used during the tests, and `checkInputs` are libraries which are linked to executables built as part of the tests. Similarly, `installCheckInputs` are renamed to `nativeInstallCheckInputs`, corresponding to `nativeBuildInputs`, and `installCheckInputs` are a new type of dependencies added to `buildInputs` when `doInstallCheck` is set. (Note that this change will not cause breakage to derivations with `strictDeps` unset, which are most packages except python, rust, ocaml and go packages).
|
||||
|
||||
- `buildDunePackage` now defaults to `strictDeps = true` which means that any library should go into `buildInputs` or `checkInputs`. Any executable that is run on the building machine should go into `nativeBuildInputs` or `nativeCheckInputs` respectively. Example of executables are `ocaml`, `findlib` and `menhir`. PPXs are libraries which are built by dune and should therefore not go into `nativeBuildInputs`.
|
||||
@@ -185,8 +172,6 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- The option `i18n.inputMethod.fcitx5.enableRimeData` has been removed. Default RIME data is now included in `fcitx5-rime` by default, and can be customized using `fcitx5-rime.override { rimeDataPkgs = [ pkgs.rime-data, package2, ... ]; }`
|
||||
|
||||
- The udev hwdb.bin file is now built with systemd-hwdb rather than the [deprecated "udevadm hwdb"](https://github.com/systemd/systemd/pull/25714). This may impact mappings where the same key is defined in multiple matching entries. The updated behavior will select the latest definition in case of conflict. In general, this should be a positive change, as the hwdb source files are designed with this ordering in mind. As an example, the mapping of the HP Dev One keyboard scan code for "mute mic" is corrected by this update. This change may impact users who have worked-around previously incorrect mappings.
|
||||
|
||||
- Kime has been updated from 2.5.6 to 3.0.2 and the `i18n.inputMethod.kime.config` option has been removed. Users should use `daemonModules`, `iconColor`, and `extraConfig` options under `i18n.inputMethod.kime` instead.
|
||||
|
||||
- `tut` has been updated from 1.0.34 to 2.0.0, and now uses the TOML format for the configuration file instead of INI. Additional information can be found [here](https://github.com/RasmusLindroth/tut/releases/tag/2.0.0).
|
||||
@@ -223,11 +208,6 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- The [services.wordpress.sites.<name>.plugins](#opt-services.wordpress.sites._name_.plugins) and [services.wordpress.sites.<name>.themes](#opt-services.wordpress.sites._name_.themes) options have been converted from sets to attribute sets to allow for consumers to specify explicit install paths via attribute name.
|
||||
|
||||
- [`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally) now uses socket authentication and is no longer compatible with password authentication.
|
||||
- If you want the module to manage the database for you, unset [`services.nextcloud.config.dbpassFile`](#opt-services.nextcloud.config.dbpassFile) (and [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost), if it's set).
|
||||
- If your database is external, simply set [`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally) to `false`.
|
||||
- If you want to use password authentication **and** create the database locally, you will have to use [`services.mysql`](#opt-services.mysql.enable) to set it up.
|
||||
|
||||
- `protonmail-bridge` package has been updated to major version 3.
|
||||
|
||||
- Nebula now runs as a system user and group created for each nebula network, using the `CAP_NET_ADMIN` ambient capability on launch rather than starting as root. Ensure that any files each Nebula instance needs to access are owned by the correct user and group, by default `nebula-${networkName}`.
|
||||
@@ -255,14 +235,10 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
[upstream's release notes](https://github.com/iputils/iputils/releases/tag/20221126)
|
||||
for more details and available replacements.
|
||||
|
||||
- The ppp plugin `rp-pppoe.so` has been renamed to `pppoe.so` in ppp 2.4.9. Starting from ppp 2.5.0, there is no longer a alias for backwards compatiblity. Configurations that use this plugin must be updated accordingly from `plugin rp-pppoe.so` to `plugin pppoe.so`. See [upstream change](https://github.com/ppp-project/ppp/commit/610a7bd76eb1f99f22317541b35001b1e24877ed).
|
||||
|
||||
- [services.xserver.videoDrivers](options.html#opt-services.xserver.videoDrivers) now defaults to the `modesetting` driver over device-specific ones. The `radeon`, `amdgpu` and `nouveau` drivers are still available, but effectively unmaintained and not recommended for use.
|
||||
|
||||
- To enable the HTTP3 (QUIC) protocol for a nginx virtual host, set the `quic` attribute on it to true, e.g. `services.nginx.virtualHosts.<name>.quic = true;`.
|
||||
|
||||
- In `services.fail2ban`, `bantime-increment.<name>` options now default to `null` (except `bantime-increment.enable`) and are used to set the corresponding option in `jail.local` only if not `null`. Also, enforce that `bantime-increment.formula` and `bantime-increment.multipliers` are not both specified.
|
||||
|
||||
- The default Asterisk package was changed to v20 from v19. Asterisk versions 16 and 19 have been dropped due to being EOL. You may need to update /var/lib/asterisk to match the template files in `${asterisk-20}/var/lib/asterisk`.
|
||||
|
||||
- conntrack helper autodetection has been removed from kernels 6.0 and up upstream, and an assertion was added to ensure things don't silently stop working. Migrate your configuration to assign helpers explicitly or use an older LTS kernel branch as a temporary workaround.
|
||||
@@ -279,8 +255,6 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- The `baget` package and module was removed due to being unmaintained.
|
||||
|
||||
- The `qlandkartegt` and `garmindev` packages were removed due to being unmaintained and insecure.
|
||||
|
||||
- `go-ethereum` package has been updated to v1.11.5 and the `puppeth` command is no longer available as of v1.11.0.
|
||||
|
||||
- The `pnpm` package has be updated to from version 7.29.1 to version 8.1.1 and Node.js 14 support has been discontinued (though, there are workarounds if Node.js 14 is still required)
|
||||
@@ -332,9 +306,7 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
replacement. It stores backups as volume dump files and thus better integrates
|
||||
into contemporary backup solutions.
|
||||
|
||||
- `services.maddy` got several updates:
|
||||
- Configuration of users and their credentials using `services.maddy.ensureCredentials`.
|
||||
- Configuration of TLS key and certificate files using `services.maddy.tls`.
|
||||
- `services.maddy` now allows to configure users and their credentials using `services.maddy.ensureCredentials`.
|
||||
|
||||
- The `dnsmasq` service now takes configuration via the
|
||||
`services.dnsmasq.settings` attribute set. The option
|
||||
|
||||
@@ -33,7 +33,6 @@ let
|
||||
];
|
||||
specialArgs = {
|
||||
inherit config pkgs utils;
|
||||
class = "nixos";
|
||||
};
|
||||
};
|
||||
docs = import "${nixosPath}/doc/manual" {
|
||||
|
||||
@@ -38,7 +38,6 @@ let
|
||||
# is experimental.
|
||||
lib.evalModules {
|
||||
inherit prefix modules;
|
||||
class = "nixos";
|
||||
specialArgs = {
|
||||
modulesPath = builtins.toString ../modules;
|
||||
} // specialArgs;
|
||||
|
||||
@@ -38,8 +38,6 @@ let pkgs_ = pkgs;
|
||||
in
|
||||
|
||||
let
|
||||
inherit (lib) optional;
|
||||
|
||||
evalModulesMinimal = (import ./default.nix {
|
||||
inherit lib;
|
||||
# Implicit use of feature is noted in implementation.
|
||||
@@ -49,19 +47,15 @@ let
|
||||
pkgsModule = rec {
|
||||
_file = ./eval-config.nix;
|
||||
key = _file;
|
||||
config = lib.mkMerge (
|
||||
(optional (system != null) {
|
||||
# Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
|
||||
# this. Since the latter defaults to the former, the former should
|
||||
# default to the argument. That way this new default could propagate all
|
||||
# they way through, but has the last priority behind everything else.
|
||||
nixpkgs.system = lib.mkDefault system;
|
||||
})
|
||||
++
|
||||
(optional (pkgs_ != null) {
|
||||
_module.args.pkgs = lib.mkForce pkgs_;
|
||||
})
|
||||
);
|
||||
config = {
|
||||
# Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
|
||||
# this. Since the latter defaults to the former, the former should
|
||||
# default to the argument. That way this new default could propagate all
|
||||
# they way through, but has the last priority behind everything else.
|
||||
nixpkgs.system = lib.mkIf (system != null) (lib.mkDefault system);
|
||||
|
||||
_module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
|
||||
};
|
||||
};
|
||||
|
||||
withWarnings = x:
|
||||
|
||||
@@ -3,6 +3,7 @@ import argparse
|
||||
import ptpython.repl
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
|
||||
from test_driver.logger import rootlog
|
||||
from test_driver.driver import Driver
|
||||
@@ -77,6 +78,13 @@ def main() -> None:
|
||||
nargs="*",
|
||||
help="vlans to span by the driver",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"--tpms",
|
||||
metavar="TPMs",
|
||||
action=EnvDefault,
|
||||
envvar="tpms",
|
||||
help="tpms blob to initialize by the driver (in JSON)",
|
||||
)
|
||||
arg_parser.add_argument(
|
||||
"-o",
|
||||
"--output_directory",
|
||||
@@ -101,6 +109,7 @@ def main() -> None:
|
||||
with Driver(
|
||||
args.start_scripts,
|
||||
args.vlans,
|
||||
json.loads(args.tpms),
|
||||
args.testscript.read_text(),
|
||||
args.output_directory.resolve(),
|
||||
args.keep_vm_state,
|
||||
@@ -120,7 +129,7 @@ def generate_driver_symbols() -> None:
|
||||
in user's test scripts. That list is then used by pyflakes to lint those
|
||||
scripts.
|
||||
"""
|
||||
d = Driver([], [], "", Path())
|
||||
d = Driver([], [], [], "", Path())
|
||||
test_symbols = d.test_symbols()
|
||||
with open("driver-symbols", "w") as fp:
|
||||
fp.write(",".join(test_symbols.keys()))
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterator, List, Union, Optional, Callable, ContextManager
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Iterator,
|
||||
List,
|
||||
Union,
|
||||
Optional,
|
||||
Callable,
|
||||
ContextManager,
|
||||
Tuple,
|
||||
)
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
from test_driver.logger import rootlog
|
||||
from test_driver.machine import Machine, NixStartScript, retry
|
||||
from test_driver.vlan import VLan
|
||||
from test_driver.tpm import Tpm
|
||||
from test_driver.polling_condition import PollingCondition
|
||||
|
||||
|
||||
@@ -29,10 +39,6 @@ def get_tmp_dir() -> Path:
|
||||
return tmp_dir
|
||||
|
||||
|
||||
def pythonize_name(name: str) -> str:
|
||||
return re.sub(r"^[^A-z_]|[^A-z0-9_]", "_", name)
|
||||
|
||||
|
||||
class Driver:
|
||||
"""A handle to the driver that sets up the environment
|
||||
and runs the tests"""
|
||||
@@ -40,18 +46,21 @@ class Driver:
|
||||
tests: str
|
||||
vlans: List[VLan]
|
||||
machines: List[Machine]
|
||||
tpms: Dict[str, Tpm]
|
||||
polling_conditions: List[PollingCondition]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
start_scripts: List[str],
|
||||
vlans: List[int],
|
||||
tpms: List[Dict[str, str]],
|
||||
tests: str,
|
||||
out_dir: Path,
|
||||
keep_vm_state: bool = False,
|
||||
):
|
||||
self.tests = tests
|
||||
self.out_dir = out_dir
|
||||
self.polling_conditions = []
|
||||
|
||||
tmp_dir = get_tmp_dir()
|
||||
|
||||
@@ -59,12 +68,22 @@ class Driver:
|
||||
vlans = list(set(vlans))
|
||||
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
|
||||
|
||||
with rootlog.nested("start all TPMs"):
|
||||
self.tpms = {
|
||||
tpm_data["machine_name"]: Tpm(
|
||||
tpm_data["swtpm_binary_path"], tpm_data["socket_path"]
|
||||
)
|
||||
for tpm_data in tpms
|
||||
}
|
||||
for tpm in self.tpms.values():
|
||||
tpm.start()
|
||||
# Monitor TPMs for unexpected crashes.
|
||||
self.polling_conditions.append(PollingCondition(tpm.check))
|
||||
|
||||
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
|
||||
for s in scripts:
|
||||
yield NixStartScript(s)
|
||||
|
||||
self.polling_conditions = []
|
||||
|
||||
self.machines = [
|
||||
Machine(
|
||||
start_command=cmd,
|
||||
@@ -73,6 +92,7 @@ class Driver:
|
||||
tmp_dir=tmp_dir,
|
||||
callbacks=[self.check_polling_conditions],
|
||||
out_dir=self.out_dir,
|
||||
tpm=self.tpms.get(cmd.machine_name),
|
||||
)
|
||||
for cmd in cmd(start_scripts)
|
||||
]
|
||||
@@ -116,13 +136,17 @@ class Driver:
|
||||
serial_stdout_off=self.serial_stdout_off,
|
||||
serial_stdout_on=self.serial_stdout_on,
|
||||
polling_condition=self.polling_condition,
|
||||
Machine=Machine, # for typing
|
||||
# for typing
|
||||
Machine=Machine,
|
||||
Tpm=Tpm,
|
||||
)
|
||||
machine_symbols = {pythonize_name(m.name): m for m in self.machines}
|
||||
machine_symbols = {m.name: m for m in self.machines}
|
||||
tpm_symbols = {f"tpm_{m.name}": m.tpm for m in self.machines}
|
||||
# If there's exactly one machine, make it available under the name
|
||||
# "machine", even if it's not called that.
|
||||
if len(self.machines) == 1:
|
||||
(machine_symbols["machine"],) = self.machines
|
||||
(tpm_symbols["tpm_machine"],) = self.tpms.values()
|
||||
vlan_symbols = {
|
||||
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
|
||||
}
|
||||
@@ -130,11 +154,13 @@ class Driver:
|
||||
"additionally exposed symbols:\n "
|
||||
+ ", ".join(map(lambda m: m.name, self.machines))
|
||||
+ ",\n "
|
||||
+ ", ".join(self.tpms.keys())
|
||||
+ ",\n "
|
||||
+ ", ".join(map(lambda v: f"vlan{v.nr}", self.vlans))
|
||||
+ ",\n "
|
||||
+ ", ".join(list(general_symbols.keys()))
|
||||
)
|
||||
return {**general_symbols, **machine_symbols, **vlan_symbols}
|
||||
return {**general_symbols, **machine_symbols, **vlan_symbols, **tpm_symbols}
|
||||
|
||||
def test_script(self) -> None:
|
||||
"""Run the test script"""
|
||||
|
||||
@@ -17,6 +17,7 @@ import threading
|
||||
import time
|
||||
|
||||
from test_driver.logger import rootlog
|
||||
from test_driver.tpm import Tpm
|
||||
|
||||
CHAR_TO_KEY = {
|
||||
"A": "shift-a",
|
||||
@@ -318,6 +319,8 @@ class Machine:
|
||||
shell: Optional[socket.socket]
|
||||
serial_thread: Optional[threading.Thread]
|
||||
|
||||
tpm: Tpm | None
|
||||
|
||||
booted: bool
|
||||
connected: bool
|
||||
# Store last serial console lines for use
|
||||
@@ -336,6 +339,7 @@ class Machine:
|
||||
name: str = "machine",
|
||||
keep_vm_state: bool = False,
|
||||
callbacks: Optional[List[Callable]] = None,
|
||||
tpm: Optional[Tpm] = None,
|
||||
) -> None:
|
||||
self.out_dir = out_dir
|
||||
self.tmp_dir = tmp_dir
|
||||
@@ -343,6 +347,7 @@ class Machine:
|
||||
self.name = name
|
||||
self.start_command = start_command
|
||||
self.callbacks = callbacks if callbacks is not None else []
|
||||
self.tpm = tpm
|
||||
|
||||
# set up directories
|
||||
self.shared_dir = self.tmp_dir / "shared-xchg"
|
||||
|
||||
54
nixos/lib/test-driver/test_driver/tpm.py
Normal file
54
nixos/lib/test-driver/test_driver/tpm.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import subprocess
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
|
||||
class Tpm:
|
||||
"""
|
||||
This is a TPM driver for QEMU tests.
|
||||
It gives you access to a TPM socket path on the host
|
||||
you can access at `tpm_socket_path`.
|
||||
"""
|
||||
|
||||
state_dir: TemporaryDirectory
|
||||
swtpm_binary_path: str
|
||||
tpm_socket_path: str
|
||||
|
||||
def __init__(self, swtpm_binary_path: str, tpm_socket_path: str):
|
||||
self.state_dir = TemporaryDirectory()
|
||||
self.swtpm_binary_path = swtpm_binary_path
|
||||
self.tpm_socket_path = tpm_socket_path
|
||||
self.start()
|
||||
|
||||
def start(self) -> None:
|
||||
"""
|
||||
Start swtpm binary and wait for its proper startup.
|
||||
In case of failure, this will raise a runtime error.
|
||||
"""
|
||||
self.proc = subprocess.Popen(
|
||||
[
|
||||
self.swtpm_binary_path,
|
||||
"socket",
|
||||
"--tpmstate",
|
||||
f"dir={self.state_dir.name}",
|
||||
"--ctrl",
|
||||
f"type=unixio,path={self.tpm_socket_path}",
|
||||
"--tpm2",
|
||||
]
|
||||
)
|
||||
|
||||
# Check whether starting swtpm failed
|
||||
try:
|
||||
exit_code = self.proc.wait(timeout=0.2)
|
||||
if exit_code is not None and exit_code != 0:
|
||||
raise RuntimeError(f"failed to start swtpm, exit code: {exit_code}")
|
||||
except subprocess.TimeoutExpired:
|
||||
pass
|
||||
|
||||
def check(self) -> None:
|
||||
"""
|
||||
Check whether the swtpm process exited due to an error
|
||||
Useful as a @polling_condition.
|
||||
"""
|
||||
exit_code = self.proc.poll()
|
||||
if exit_code is not None and exit_code != 0:
|
||||
raise RuntimeError("swtpm process died")
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
from test_driver.driver import Driver
|
||||
from test_driver.vlan import VLan
|
||||
from test_driver.tpm import Tpm
|
||||
from test_driver.machine import Machine
|
||||
from test_driver.logger import Logger
|
||||
from typing import Callable, Iterator, ContextManager, Optional, List, Dict, Any, Union
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
{ lib }:
|
||||
let
|
||||
|
||||
evalTest = module: lib.evalModules {
|
||||
modules = testModules ++ [ module ];
|
||||
class = "nixosTest";
|
||||
};
|
||||
evalTest = module: lib.evalModules { modules = testModules ++ [ module ]; };
|
||||
runTest = module: (evalTest ({ config, ... }: { imports = [ module ]; result = config.test; })).config.result;
|
||||
|
||||
testModules = [
|
||||
|
||||
@@ -14,6 +14,14 @@ let
|
||||
|
||||
vlans = map (m: m.virtualisation.vlans) (lib.attrValues config.nodes);
|
||||
vms = map (m: m.system.build.vm) (lib.attrValues config.nodes);
|
||||
tpms = map (n:
|
||||
let m = config.nodes.${n};
|
||||
in
|
||||
{
|
||||
swtpm_binary_path = "${lib.getExe m.virtualisation.tpm.package}";
|
||||
socket_path = "${m.virtualisation.tpm.socketPath}";
|
||||
machine_name = n;
|
||||
}) (lib.attrNames config.nodes);
|
||||
|
||||
nodeHostNames =
|
||||
let
|
||||
@@ -21,20 +29,36 @@ let
|
||||
in
|
||||
nodesList ++ lib.optional (lib.length nodesList == 1 && !lib.elem "machine" nodesList) "machine";
|
||||
|
||||
pythonizeName = name:
|
||||
let
|
||||
head = lib.substring 0 1 name;
|
||||
tail = lib.substring 1 (-1) name;
|
||||
in
|
||||
(if builtins.match "[A-z_]" head == null then "_" else head) +
|
||||
lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
|
||||
# TODO: This is an implementation error and needs fixing
|
||||
# the testing famework cannot legitimately restrict hostnames further
|
||||
# beyond RFC1035
|
||||
invalidNodeNames = lib.filter
|
||||
(node: builtins.match "^[A-z_]([A-z0-9_]+)?$" node == null)
|
||||
nodeHostNames;
|
||||
|
||||
uniqueVlans = lib.unique (builtins.concatLists vlans);
|
||||
vlanNames = map (i: "vlan${toString i}: VLan;") uniqueVlans;
|
||||
pythonizedNames = map pythonizeName nodeHostNames;
|
||||
machineNames = map (name: "${name}: Machine;") pythonizedNames;
|
||||
machineNames = map (name: "${name}: Machine;") nodeHostNames;
|
||||
tpmNames = map (name:
|
||||
let
|
||||
tpmConfig = config.nodes.${name}.virtualisation.tpm;
|
||||
in
|
||||
''tpm_${name}: Tpm = Tpm(\"${lib.getExe tpmConfig.package}\", \"${tpmConfig.socketPath}\")''
|
||||
) (lib.attrNames config.nodes);
|
||||
|
||||
withChecks = lib.warnIf config.skipLint "Linting is disabled";
|
||||
|
||||
withChecks =
|
||||
if lib.length invalidNodeNames > 0 then
|
||||
throw ''
|
||||
Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
|
||||
All machines are referenced as python variables in the testing framework which will break the
|
||||
script when special characters are used.
|
||||
|
||||
This is an IMPLEMENTATION ERROR and needs to be fixed. Meanwhile,
|
||||
please stick to alphanumeric chars and underscores as separation.
|
||||
''
|
||||
else
|
||||
lib.warnIf config.skipLint "Linting is disabled";
|
||||
|
||||
driver =
|
||||
hostPkgs.runCommand "nixos-test-driver-${config.name}"
|
||||
@@ -61,6 +85,7 @@ let
|
||||
cat "${../test-script-prepend.py}" >> testScriptWithTypes
|
||||
echo "${builtins.toString machineNames}" >> testScriptWithTypes
|
||||
echo "${builtins.toString vlanNames}" >> testScriptWithTypes
|
||||
echo "${builtins.toString tpmNames}" >> testScriptWithTypes
|
||||
echo -n "$testScript" >> testScriptWithTypes
|
||||
|
||||
cat -n testScriptWithTypes
|
||||
@@ -78,7 +103,7 @@ let
|
||||
${testDriver}/bin/generate-driver-symbols
|
||||
${lib.optionalString (!config.skipLint) ''
|
||||
PYFLAKES_BUILTINS="$(
|
||||
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," pythonizedNames)},
|
||||
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
|
||||
< ${lib.escapeShellArg "driver-symbols"}
|
||||
)" ${hostPkgs.python3Packages.pyflakes}/bin/pyflakes $out/test-script
|
||||
''}
|
||||
@@ -89,6 +114,7 @@ let
|
||||
--set startScripts "''${vmStartScripts[*]}" \
|
||||
--set testScript "$out/test-script" \
|
||||
--set vlans '${toString vlans}' \
|
||||
--set tpms '${builtins.toJSON tpms}' \
|
||||
${lib.escapeShellArgs (lib.concatMap (arg: ["--add-flags" arg]) config.extraDriverArgs)}
|
||||
'';
|
||||
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
testModuleArgs@{ config, lib, hostPkgs, nodes, ... }:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
literalExpression
|
||||
literalMD
|
||||
mapAttrs
|
||||
mdDoc
|
||||
mkDefault
|
||||
mkIf
|
||||
mkOption mkForce
|
||||
optional
|
||||
optionalAttrs
|
||||
types
|
||||
;
|
||||
inherit (lib) mkOption mkForce optional types mapAttrs mkDefault mdDoc;
|
||||
|
||||
system = hostPkgs.stdenv.hostPlatform.system;
|
||||
|
||||
baseOS =
|
||||
import ../eval-config.nix {
|
||||
system = null; # use modularly defined system
|
||||
inherit system;
|
||||
inherit (config.node) specialArgs;
|
||||
modules = [ config.defaults ];
|
||||
baseModules = (import ../../modules/module-list.nix) ++
|
||||
@@ -26,17 +17,11 @@ let
|
||||
({ config, ... }:
|
||||
{
|
||||
virtualisation.qemu.package = testModuleArgs.config.qemu.package;
|
||||
})
|
||||
(optionalAttrs (!config.node.pkgsReadOnly) {
|
||||
key = "nodes.nix-pkgs";
|
||||
config = {
|
||||
|
||||
# Ensure we do not use aliases. Ideally this is only set
|
||||
# when the test framework is used by Nixpkgs NixOS tests.
|
||||
nixpkgs.config.allowAliases = false;
|
||||
# TODO: switch to nixpkgs.hostPlatform and make sure containers-imperative test still evaluates.
|
||||
nixpkgs.system = hostPkgs.stdenv.hostPlatform.system;
|
||||
};
|
||||
})
|
||||
})
|
||||
testModuleArgs.config.extraBaseModules
|
||||
];
|
||||
};
|
||||
@@ -83,30 +68,6 @@ in
|
||||
default = { };
|
||||
};
|
||||
|
||||
node.pkgs = mkOption {
|
||||
description = mdDoc ''
|
||||
The Nixpkgs to use for the nodes.
|
||||
|
||||
Setting this will make the `nixpkgs.*` options read-only, to avoid mistakenly testing with a Nixpkgs configuration that diverges from regular use.
|
||||
'';
|
||||
type = types.nullOr types.pkgs;
|
||||
default = null;
|
||||
defaultText = literalMD ''
|
||||
`null`, so construct `pkgs` according to the `nixpkgs.*` options as usual.
|
||||
'';
|
||||
};
|
||||
|
||||
node.pkgsReadOnly = mkOption {
|
||||
description = mdDoc ''
|
||||
Whether to make the `nixpkgs.*` options read-only. This is only relevant when [`node.pkgs`](#test-opt-node.pkgs) is set.
|
||||
|
||||
Set this to `false` when any of the [`nodes`](#test-opt-nodes) needs to configure any of the `nixpkgs.*` options. This will slow down evaluation of your test a bit.
|
||||
'';
|
||||
type = types.bool;
|
||||
default = config.node.pkgs != null;
|
||||
defaultText = literalExpression ''node.pkgs != null'';
|
||||
};
|
||||
|
||||
node.specialArgs = mkOption {
|
||||
type = types.lazyAttrsOf types.raw;
|
||||
default = { };
|
||||
@@ -139,11 +100,5 @@ in
|
||||
config.nodes;
|
||||
|
||||
passthru.nodes = config.nodesCompat;
|
||||
|
||||
defaults = mkIf config.node.pkgsReadOnly {
|
||||
nixpkgs.pkgs = config.node.pkgs;
|
||||
imports = [ ../../modules/misc/nixpkgs/read-only.nix ];
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ let
|
||||
path = makeBinPath [
|
||||
pkgs.jq
|
||||
nixos-enter
|
||||
pkgs.util-linuxMinimal
|
||||
];
|
||||
};
|
||||
|
||||
@@ -66,9 +65,6 @@ let
|
||||
name = "nixos-enter";
|
||||
src = ./nixos-enter.sh;
|
||||
inherit (pkgs) runtimeShell;
|
||||
path = makeBinPath [
|
||||
pkgs.util-linuxMinimal
|
||||
];
|
||||
};
|
||||
|
||||
in
|
||||
@@ -127,7 +123,7 @@ in
|
||||
system.nixos-generate-config.configuration = mkDefault ''
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page
|
||||
# and in the NixOS manual (accessible by running `nixos-help`).
|
||||
# and in the NixOS manual (accessible by running ‘nixos-help’).
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
@@ -218,7 +214,7 @@ in
|
||||
|
||||
# This value determines the NixOS release from which the default
|
||||
# settings for stateful data, like file locations and database versions
|
||||
# on your system were taken. It's perfectly fine and recommended to leave
|
||||
# on your system were taken. It’s perfectly fine and recommended to leave
|
||||
# this value at the release version of the first install of this system.
|
||||
# Before changing this value read the documentation for this option
|
||||
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||
|
||||
@@ -38,7 +38,6 @@ let
|
||||
modules = [ {
|
||||
_module.check = false;
|
||||
} ] ++ docModules.eager;
|
||||
class = "nixos";
|
||||
specialArgs = specialArgs // {
|
||||
pkgs = scrubDerivations "pkgs" pkgs;
|
||||
# allow access to arbitrary options for eager modules, eg for getting
|
||||
|
||||
@@ -49,10 +49,10 @@ let
|
||||
merge = lib.mergeOneOption;
|
||||
};
|
||||
|
||||
pkgsType = types.pkgs // {
|
||||
# This type is only used by itself, so let's elaborate the description a bit
|
||||
# for the purpose of documentation.
|
||||
pkgsType = mkOptionType {
|
||||
name = "nixpkgs";
|
||||
description = "An evaluation of Nixpkgs; the top level attribute set of packages";
|
||||
check = builtins.isAttrs;
|
||||
};
|
||||
|
||||
# Whether `pkgs` was constructed by this module - not if nixpkgs.pkgs or
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# A replacement for the traditional nixpkgs module, such that none of the modules
|
||||
# can add their own configuration. This ensures that the Nixpkgs configuration is
|
||||
# exactly as the user intends.
|
||||
# This may also be used as a performance optimization when evaluating multiple
|
||||
# configurations at once, with a shared `pkgs`.
|
||||
|
||||
# This is a separate module, because merging this logic into the nixpkgs module
|
||||
# is too burdensome, considering that it is already burdened with legacy.
|
||||
# Moving this logic into a module does not lose any composition benefits, because
|
||||
# its purpose is not something that composes anyway.
|
||||
|
||||
{ lib, config, ... }:
|
||||
|
||||
let
|
||||
cfg = config.nixpkgs;
|
||||
inherit (lib) mkOption types;
|
||||
|
||||
in
|
||||
{
|
||||
disabledModules = [
|
||||
../nixpkgs.nix
|
||||
];
|
||||
options = {
|
||||
nixpkgs = {
|
||||
pkgs = mkOption {
|
||||
type = lib.types.pkgs;
|
||||
description = lib.mdDoc ''The pkgs module argument.'';
|
||||
};
|
||||
config = mkOption {
|
||||
internal = true;
|
||||
type = types.unique { message = "nixpkgs.config is set to read-only"; } types.anything;
|
||||
description = lib.mdDoc ''
|
||||
The Nixpkgs `config` that `pkgs` was initialized with.
|
||||
'';
|
||||
};
|
||||
overlays = mkOption {
|
||||
internal = true;
|
||||
type = types.unique { message = "nixpkgs.overlays is set to read-only"; } types.anything;
|
||||
description = lib.mdDoc ''
|
||||
The Nixpkgs overlays that `pkgs` was initialized with.
|
||||
'';
|
||||
};
|
||||
hostPlatform = mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = lib.mdDoc ''
|
||||
The platform of the machine that is running the NixOS configuration.
|
||||
'';
|
||||
};
|
||||
buildPlatform = mkOption {
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = lib.mdDoc ''
|
||||
The platform of the machine that built the NixOS configuration.
|
||||
'';
|
||||
};
|
||||
# NOTE: do not add the legacy options such as localSystem here. Let's keep
|
||||
# this module simple and let module authors upgrade their code instead.
|
||||
};
|
||||
};
|
||||
config = {
|
||||
_module.args.pkgs =
|
||||
# find mistaken definitions
|
||||
builtins.seq cfg.config
|
||||
builtins.seq cfg.overlays
|
||||
builtins.seq cfg.hostPlatform
|
||||
builtins.seq cfg.buildPlatform
|
||||
cfg.pkgs;
|
||||
nixpkgs.config = cfg.pkgs.config;
|
||||
nixpkgs.overlays = cfg.pkgs.overlays;
|
||||
nixpkgs.hostPlatform = cfg.pkgs.stdenv.hostPlatform;
|
||||
nixpkgs.buildPlatform = cfg.pkgs.stdenv.buildPlatform;
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
# [nixpkgs]$ nix-build -A nixosTests.nixpkgs --show-trace
|
||||
|
||||
{ evalMinimalConfig, pkgs, lib, stdenv }:
|
||||
let
|
||||
eval = mod: evalMinimalConfig {
|
||||
@@ -29,47 +27,6 @@ let
|
||||
let
|
||||
uncheckedEval = lib.evalModules { modules = [ ../nixpkgs.nix module ]; };
|
||||
in map (ass: ass.message) (lib.filter (ass: !ass.assertion) uncheckedEval.config.assertions);
|
||||
|
||||
readOnlyUndefined = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
};
|
||||
|
||||
readOnlyBad = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
nixpkgs.pkgs = { };
|
||||
};
|
||||
|
||||
readOnly = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
nixpkgs.pkgs = pkgs;
|
||||
};
|
||||
|
||||
readOnlyBadConfig = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
nixpkgs.pkgs = pkgs;
|
||||
nixpkgs.config.allowUnfree = true; # do in pkgs instead!
|
||||
};
|
||||
|
||||
readOnlyBadOverlays = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
nixpkgs.pkgs = pkgs;
|
||||
nixpkgs.overlays = [ (_: _: {}) ]; # do in pkgs instead!
|
||||
};
|
||||
|
||||
readOnlyBadHostPlatform = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
nixpkgs.pkgs = pkgs;
|
||||
nixpkgs.hostPlatform = "foo-linux"; # do in pkgs instead!
|
||||
};
|
||||
|
||||
readOnlyBadBuildPlatform = evalMinimalConfig {
|
||||
imports = [ ./read-only.nix ];
|
||||
nixpkgs.pkgs = pkgs;
|
||||
nixpkgs.buildPlatform = "foo-linux"; # do in pkgs instead!
|
||||
};
|
||||
|
||||
throws = x: ! (builtins.tryEval x).success;
|
||||
|
||||
in
|
||||
lib.recurseIntoAttrs {
|
||||
invokeNixpkgsSimple =
|
||||
@@ -108,21 +65,5 @@ lib.recurseIntoAttrs {
|
||||
nixpkgs.pkgs = pkgs;
|
||||
} == [];
|
||||
|
||||
|
||||
# Tests for the read-only.nix module
|
||||
assert readOnly._module.args.pkgs.stdenv.hostPlatform.system == pkgs.stdenv.hostPlatform.system;
|
||||
assert throws readOnlyBad._module.args.pkgs.stdenv;
|
||||
assert throws readOnlyUndefined._module.args.pkgs.stdenv;
|
||||
assert throws readOnlyBadConfig._module.args.pkgs.stdenv;
|
||||
assert throws readOnlyBadOverlays._module.args.pkgs.stdenv;
|
||||
assert throws readOnlyBadHostPlatform._module.args.pkgs.stdenv;
|
||||
assert throws readOnlyBadBuildPlatform._module.args.pkgs.stdenv;
|
||||
# read-only.nix does not provide legacy options, for the sake of simplicity
|
||||
# If you're bothered by this, upgrade your configs to use the new *Platform
|
||||
# options.
|
||||
assert !readOnly.options.nixpkgs?system;
|
||||
assert !readOnly.options.nixpkgs?localSystem;
|
||||
assert !readOnly.options.nixpkgs?crossSystem;
|
||||
|
||||
pkgs.emptyFile;
|
||||
}
|
||||
|
||||
@@ -413,9 +413,6 @@
|
||||
./services/desktops/bamf.nix
|
||||
./services/desktops/blueman.nix
|
||||
./services/desktops/cpupower-gui.nix
|
||||
./services/desktops/deepin/dde-api.nix
|
||||
./services/desktops/deepin/app-services.nix
|
||||
./services/desktops/deepin/dde-daemon.nix
|
||||
./services/desktops/dleyna-renderer.nix
|
||||
./services/desktops/dleyna-server.nix
|
||||
./services/desktops/espanso.nix
|
||||
@@ -444,7 +441,6 @@
|
||||
./services/desktops/pipewire/wireplumber.nix
|
||||
./services/desktops/profile-sync-daemon.nix
|
||||
./services/desktops/system-config-printer.nix
|
||||
./services/desktops/system76-scheduler.nix
|
||||
./services/desktops/telepathy.nix
|
||||
./services/desktops/tumbler.nix
|
||||
./services/desktops/zeitgeist.nix
|
||||
@@ -1113,7 +1109,6 @@
|
||||
./services/security/torsocks.nix
|
||||
./services/security/usbguard.nix
|
||||
./services/security/vault.nix
|
||||
./services/security/vault-agent.nix
|
||||
./services/security/vaultwarden/default.nix
|
||||
./services/security/yubikey-agent.nix
|
||||
./services/system/automatic-timezoned.nix
|
||||
@@ -1184,7 +1179,6 @@
|
||||
./services/web-apps/jirafeau.nix
|
||||
./services/web-apps/jitsi-meet.nix
|
||||
./services/web-apps/kasmweb/default.nix
|
||||
./services/web-apps/kavita.nix
|
||||
./services/web-apps/keycloak.nix
|
||||
./services/web-apps/komga.nix
|
||||
./services/web-apps/lemmy.nix
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
{ pkgs, config, lib, ... }:
|
||||
{pkgs, config, lib, ...}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.programs.fzf;
|
||||
in
|
||||
{
|
||||
in {
|
||||
options = {
|
||||
programs.fzf = {
|
||||
fuzzyCompletion = mkEnableOption (mdDoc "fuzzy completion with fzf");
|
||||
@@ -12,21 +11,17 @@ in
|
||||
};
|
||||
config = {
|
||||
environment.systemPackages = optional (cfg.keybindings || cfg.fuzzyCompletion) pkgs.fzf;
|
||||
|
||||
programs.bash.interactiveShellInit = optionalString cfg.fuzzyCompletion ''
|
||||
source ${pkgs.fzf}/share/fzf/completion.bash
|
||||
'' + optionalString cfg.keybindings ''
|
||||
source ${pkgs.fzf}/share/fzf/key-bindings.bash
|
||||
'';
|
||||
|
||||
programs.zsh.interactiveShellInit = optionalString (!config.programs.zsh.ohMyZsh.enable)
|
||||
(optionalString cfg.fuzzyCompletion ''
|
||||
source ${pkgs.fzf}/share/fzf/completion.zsh
|
||||
'' + optionalString cfg.keybindings ''
|
||||
source ${pkgs.fzf}/share/fzf/key-bindings.zsh
|
||||
'');
|
||||
|
||||
programs.zsh.ohMyZsh.plugins = optional (cfg.keybindings || cfg.fuzzyCompletion) [ "fzf" ];
|
||||
programs.zsh.interactiveShellInit = optionalString cfg.fuzzyCompletion ''
|
||||
source ${pkgs.fzf}/share/fzf/completion.zsh
|
||||
'' + optionalString cfg.keybindings ''
|
||||
source ${pkgs.fzf}/share/fzf/key-bindings.zsh
|
||||
'';
|
||||
};
|
||||
meta.maintainers = with maintainers; [ laalsaas ];
|
||||
}
|
||||
|
||||
@@ -57,14 +57,17 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
environment = {
|
||||
systemPackages = [ cfg.package ];
|
||||
|
||||
};
|
||||
|
||||
fonts.enableDefaultFonts = mkDefault true;
|
||||
hardware.opengl.enable = mkDefault true;
|
||||
|
||||
programs = {
|
||||
dconf.enable = mkDefault true;
|
||||
xwayland.enable = mkDefault cfg.xwayland.enable;
|
||||
xwayland.enable = mkDefault true;
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
|
||||
@@ -11,8 +11,6 @@ in {
|
||||
|
||||
enable = mkEnableOption (lib.mdDoc "Navidrome music server");
|
||||
|
||||
package = mkPackageOptionMD pkgs "navidrome" { };
|
||||
|
||||
settings = mkOption rec {
|
||||
type = settingsFormat.type;
|
||||
apply = recursiveUpdate default;
|
||||
@@ -38,7 +36,7 @@ in {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = ''
|
||||
${cfg.package}/bin/navidrome --configfile ${settingsFormat.generate "navidrome.json" cfg.settings}
|
||||
${pkgs.navidrome}/bin/navidrome --configfile ${settingsFormat.generate "navidrome.json" cfg.settings}
|
||||
'';
|
||||
DynamicUser = true;
|
||||
StateDirectory = "navidrome";
|
||||
|
||||
@@ -339,7 +339,6 @@ in
|
||||
RuntimeDirectory = "restic-backups-${name}";
|
||||
CacheDirectory = "restic-backups-${name}";
|
||||
CacheDirectoryMode = "0700";
|
||||
PrivateTmp = true;
|
||||
} // optionalAttrs (backup.environmentFile != null) {
|
||||
EnvironmentFile = backup.environmentFile;
|
||||
};
|
||||
|
||||
@@ -35,9 +35,6 @@ in
|
||||
ExecStartPre = testCommand;
|
||||
Restart = "on-failure";
|
||||
RestartSec = 120;
|
||||
|
||||
LimitSTACK = 256 * 1024 * 1024;
|
||||
OOMPolicy = "continue";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = teams.deepin.members;
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.deepin.app-services = {
|
||||
|
||||
enable = mkEnableOption (lib.mdDoc "Service collection of DDE applications, including dconfig-center");
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.services.deepin.app-services.enable {
|
||||
|
||||
environment.systemPackages = [ pkgs.deepin.dde-app-services ];
|
||||
|
||||
services.dbus.packages = [ pkgs.deepin.dde-app-services ];
|
||||
|
||||
environment.pathsToLink = [ "/share/dsg" ];
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = teams.deepin.members;
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.deepin.dde-api = {
|
||||
|
||||
enable = mkEnableOption (lib.mdDoc ''
|
||||
Provides some dbus interfaces that is used for screen zone detecting,
|
||||
thumbnail generating, and sound playing in Deepin Desktop Enviroment.
|
||||
'');
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.services.deepin.dde-api.enable {
|
||||
|
||||
environment.systemPackages = [ pkgs.deepin.dde-api ];
|
||||
|
||||
services.dbus.packages = [ pkgs.deepin.dde-api ];
|
||||
|
||||
systemd.packages = [ pkgs.deepin.dde-api ];
|
||||
|
||||
environment.pathsToLink = [ "/lib/deepin-api" ];
|
||||
|
||||
users.groups.deepin-sound-player = { };
|
||||
users.users.deepin-sound-player = {
|
||||
description = "Deepin sound player";
|
||||
home = "/var/lib/deepin-sound-player";
|
||||
createHome = true;
|
||||
group = "deepin-sound-player";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = teams.deepin.members;
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
services.deepin.dde-daemon = {
|
||||
|
||||
enable = mkEnableOption (lib.mdDoc "Daemon for handling the deepin session settings");
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.services.deepin.dde-daemon.enable {
|
||||
|
||||
environment.systemPackages = [ pkgs.deepin.dde-daemon ];
|
||||
|
||||
services.dbus.packages = [ pkgs.deepin.dde-daemon ];
|
||||
|
||||
services.udev.packages = [ pkgs.deepin.dde-daemon ];
|
||||
|
||||
systemd.packages = [ pkgs.deepin.dde-daemon ];
|
||||
|
||||
environment.pathsToLink = [ "/lib/deepin-daemon" ];
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.system76-scheduler;
|
||||
|
||||
inherit (builtins) concatStringsSep map toString attrNames;
|
||||
inherit (lib) boolToString types mkOption literalExpression mdDoc optional mkIf mkMerge;
|
||||
inherit (types) nullOr listOf bool int ints float str enum;
|
||||
|
||||
withDefaults = optionSpecs: defaults:
|
||||
lib.genAttrs (attrNames optionSpecs) (name:
|
||||
mkOption (optionSpecs.${name} // {
|
||||
default = optionSpecs.${name}.default or defaults.${name} or null;
|
||||
}));
|
||||
|
||||
latencyProfile = withDefaults {
|
||||
latency = {
|
||||
type = int;
|
||||
description = mdDoc "`sched_latency_ns`.";
|
||||
};
|
||||
nr-latency = {
|
||||
type = int;
|
||||
description = mdDoc "`sched_nr_latency`.";
|
||||
};
|
||||
wakeup-granularity = {
|
||||
type = float;
|
||||
description = mdDoc "`sched_wakeup_granularity_ns`.";
|
||||
};
|
||||
bandwidth-size = {
|
||||
type = int;
|
||||
description = mdDoc "`sched_cfs_bandwidth_slice_us`.";
|
||||
};
|
||||
preempt = {
|
||||
type = enum [ "none" "voluntary" "full" ];
|
||||
description = mdDoc "Preemption mode.";
|
||||
};
|
||||
};
|
||||
schedulerProfile = withDefaults {
|
||||
nice = {
|
||||
type = nullOr (ints.between (-20) 19);
|
||||
description = mdDoc "Niceness.";
|
||||
};
|
||||
class = {
|
||||
type = nullOr (enum [ "idle" "batch" "other" "rr" "fifo" ]);
|
||||
example = literalExpression "\"batch\"";
|
||||
description = mdDoc "CPU scheduler class.";
|
||||
};
|
||||
prio = {
|
||||
type = nullOr (ints.between 1 99);
|
||||
example = literalExpression "49";
|
||||
description = mdDoc "CPU scheduler priority.";
|
||||
};
|
||||
ioClass = {
|
||||
type = nullOr (enum [ "idle" "best-effort" "realtime" ]);
|
||||
example = literalExpression "\"best-effort\"";
|
||||
description = mdDoc "IO scheduler class.";
|
||||
};
|
||||
ioPrio = {
|
||||
type = nullOr (ints.between 0 7);
|
||||
example = literalExpression "4";
|
||||
description = mdDoc "IO scheduler priority.";
|
||||
};
|
||||
matchers = {
|
||||
type = nullOr (listOf str);
|
||||
default = [];
|
||||
example = literalExpression ''
|
||||
[
|
||||
"include cgroup=\"/user.slice/*.service\" parent=\"systemd\""
|
||||
"emacs"
|
||||
]
|
||||
'';
|
||||
description = mdDoc "Process matchers.";
|
||||
};
|
||||
};
|
||||
|
||||
cfsProfileToString = name: let
|
||||
p = cfg.settings.cfsProfiles.${name};
|
||||
in
|
||||
"${name} latency=${toString p.latency} nr-latency=${toString p.nr-latency} wakeup-granularity=${toString p.wakeup-granularity} bandwidth-size=${toString p.bandwidth-size} preempt=\"${p.preempt}\"";
|
||||
|
||||
prioToString = class: prio: if prio == null then "\"${class}\"" else "(${class})${toString prio}";
|
||||
|
||||
schedulerProfileToString = name: a: indent:
|
||||
concatStringsSep " "
|
||||
(["${indent}${name}"]
|
||||
++ (optional (a.nice != null) "nice=${toString a.nice}")
|
||||
++ (optional (a.class != null) "sched=${prioToString a.class a.prio}")
|
||||
++ (optional (a.ioClass != null) "io=${prioToString a.ioClass a.ioPrio}")
|
||||
++ (optional ((builtins.length a.matchers) != 0) ("{\n${concatStringsSep "\n" (map (m: " ${indent}${m}") a.matchers)}\n${indent}}")));
|
||||
|
||||
in {
|
||||
options = {
|
||||
services.system76-scheduler = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "system76-scheduler");
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = config.boot.kernelPackages.system76-scheduler;
|
||||
defaultText = literalExpression "config.boot.kernelPackages.system76-scheduler";
|
||||
description = mdDoc "Which System76-Scheduler package to use.";
|
||||
};
|
||||
|
||||
useStockConfig = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = mdDoc ''
|
||||
Use the (reasonable and featureful) stock configuration.
|
||||
|
||||
When this option is `true`, `services.system76-scheduler.settings`
|
||||
are ignored.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = {
|
||||
cfsProfiles = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = mdDoc "Tweak CFS latency parameters when going on/off battery";
|
||||
};
|
||||
|
||||
default = latencyProfile {
|
||||
latency = 6;
|
||||
nr-latency = 8;
|
||||
wakeup-granularity = 1.0;
|
||||
bandwidth-size = 5;
|
||||
preempt = "voluntary";
|
||||
};
|
||||
responsive = latencyProfile {
|
||||
latency = 4;
|
||||
nr-latency = 10;
|
||||
wakeup-granularity = 0.5;
|
||||
bandwidth-size = 3;
|
||||
preempt = "full";
|
||||
};
|
||||
};
|
||||
|
||||
processScheduler = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = mdDoc "Tweak scheduling of individual processes in real time.";
|
||||
};
|
||||
|
||||
useExecsnoop = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = mdDoc "Use execsnoop (otherwise poll the precess list periodically).";
|
||||
};
|
||||
|
||||
refreshInterval = mkOption {
|
||||
type = int;
|
||||
default = 60;
|
||||
description = mdDoc "Process list poll interval, in seconds";
|
||||
};
|
||||
|
||||
foregroundBoost = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = mdDoc ''
|
||||
Boost foreground process priorities.
|
||||
|
||||
(And de-boost background ones). Note that this option needs cooperation
|
||||
from the desktop environment to work. On Gnome the client side is
|
||||
implemented by the "System76 Scheduler" shell extension.
|
||||
'';
|
||||
};
|
||||
foreground = schedulerProfile {
|
||||
nice = 0;
|
||||
ioClass = "best-effort";
|
||||
ioPrio = 0;
|
||||
};
|
||||
background = schedulerProfile {
|
||||
nice = 6;
|
||||
ioClass = "idle";
|
||||
};
|
||||
};
|
||||
|
||||
pipewireBoost = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
description = mdDoc "Boost Pipewire client priorities.";
|
||||
};
|
||||
profile = schedulerProfile {
|
||||
nice = -6;
|
||||
ioClass = "best-effort";
|
||||
ioPrio = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
assignments = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = schedulerProfile { };
|
||||
});
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
{
|
||||
nix-builds = {
|
||||
nice = 15;
|
||||
class = "batch";
|
||||
ioClass = "idle";
|
||||
matchers = [
|
||||
"nix-daemon"
|
||||
];
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = mdDoc "Process profile assignments.";
|
||||
};
|
||||
|
||||
exceptions = mkOption {
|
||||
type = types.listOf str;
|
||||
default = [];
|
||||
example = literalExpression ''
|
||||
[
|
||||
"include descends=\"schedtool\""
|
||||
"schedtool"
|
||||
]
|
||||
'';
|
||||
description = mdDoc "Processes that are left alone.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
services.dbus.packages = [ cfg.package ];
|
||||
|
||||
systemd.services.system76-scheduler = {
|
||||
description = "Manage process priorities and CFS scheduler latencies for improved responsiveness on the desktop";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [
|
||||
# execsnoop needs those to extract kernel headers:
|
||||
pkgs.kmod
|
||||
pkgs.gnutar
|
||||
pkgs.xz
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "dbus";
|
||||
BusName= "com.system76.Scheduler";
|
||||
ExecStart = "${cfg.package}/bin/system76-scheduler daemon";
|
||||
ExecReload = "${cfg.package}/bin/system76-scheduler daemon reload";
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc = mkMerge [
|
||||
(mkIf cfg.useStockConfig {
|
||||
# No custom settings: just use stock configuration with a fix for Pipewire
|
||||
"system76-scheduler/config.kdl".source = "${cfg.package}/data/config.kdl";
|
||||
"system76-scheduler/process-scheduler/00-dist.kdl".source = "${cfg.package}/data/pop_os.kdl";
|
||||
"system76-scheduler/process-scheduler/01-fix-pipewire-paths.kdl".source = ../../../../pkgs/os-specific/linux/system76-scheduler/01-fix-pipewire-paths.kdl;
|
||||
})
|
||||
|
||||
(let
|
||||
settings = cfg.settings;
|
||||
cfsp = settings.cfsProfiles;
|
||||
ps = settings.processScheduler;
|
||||
in mkIf (!cfg.useStockConfig) {
|
||||
"system76-scheduler/config.kdl".text = ''
|
||||
version "2.0"
|
||||
autogroup-enabled false
|
||||
cfs-profiles enable=${boolToString cfsp.enable} {
|
||||
${cfsProfileToString "default"}
|
||||
${cfsProfileToString "responsive"}
|
||||
}
|
||||
process-scheduler enable=${boolToString ps.enable} {
|
||||
execsnoop ${boolToString ps.useExecsnoop}
|
||||
refresh-rate ${toString ps.refreshInterval}
|
||||
assignments {
|
||||
${if ps.foregroundBoost.enable then (schedulerProfileToString "foreground" ps.foregroundBoost.foreground " ") else ""}
|
||||
${if ps.foregroundBoost.enable then (schedulerProfileToString "background" ps.foregroundBoost.background " ") else ""}
|
||||
${if ps.pipewireBoost.enable then (schedulerProfileToString "pipewire" ps.pipewireBoost.profile " ") else ""}
|
||||
}
|
||||
}
|
||||
'';
|
||||
})
|
||||
|
||||
{
|
||||
"system76-scheduler/process-scheduler/02-config.kdl".text =
|
||||
"exceptions {\n${concatStringsSep "\n" (map (e: " ${e}") cfg.exceptions)}\n}\n"
|
||||
+ "assignments {\n"
|
||||
+ (concatStringsSep "\n" (map (name: schedulerProfileToString name cfg.assignments.${name} " ")
|
||||
(attrNames cfg.assignments)))
|
||||
+ "\n}\n";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = [ lib.maintainers.cmm ];
|
||||
};
|
||||
}
|
||||
@@ -80,8 +80,7 @@ The first step to declare the list of packages you want in your Emacs
|
||||
installation is to create a dedicated derivation. This can be done in a
|
||||
dedicated {file}`emacs.nix` file such as:
|
||||
|
||||
::: {.example #ex-emacsNix}
|
||||
### Nix expression to build Emacs with packages (`emacs.nix`)
|
||||
[]{#ex-emacsNix}
|
||||
|
||||
```nix
|
||||
/*
|
||||
@@ -137,7 +136,6 @@ in
|
||||
pkgs.notmuch # From main packages set
|
||||
])
|
||||
```
|
||||
:::
|
||||
|
||||
The result of this configuration will be an {command}`emacs`
|
||||
command which launches Emacs with all of your chosen packages in the
|
||||
@@ -160,24 +158,19 @@ and yasnippet.
|
||||
|
||||
The list of available packages in the various ELPA repositories can be seen
|
||||
with the following commands:
|
||||
::: {.example #module-services-emacs-querying-packages}
|
||||
### Querying Emacs packages
|
||||
|
||||
[]{#module-services-emacs-querying-packages}
|
||||
```
|
||||
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.elpaPackages
|
||||
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.melpaPackages
|
||||
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.melpaStablePackages
|
||||
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.orgPackages
|
||||
```
|
||||
:::
|
||||
|
||||
If you are on NixOS, you can install this particular Emacs for all users by
|
||||
adding it to the list of system packages (see
|
||||
[](#sec-declarative-package-mgmt)). Simply modify your file
|
||||
{file}`configuration.nix` to make it contain:
|
||||
::: {.example #module-services-emacs-configuration-nix}
|
||||
### Custom Emacs in `configuration.nix`
|
||||
|
||||
[]{#module-services-emacs-configuration-nix}
|
||||
```
|
||||
{
|
||||
environment.systemPackages = [
|
||||
@@ -186,7 +179,6 @@ adding it to the list of system packages (see
|
||||
];
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
In this case, the next {command}`nixos-rebuild switch` will take
|
||||
care of adding your {command}`emacs` to the {var}`PATH`
|
||||
@@ -200,9 +192,7 @@ If you are not on NixOS or want to install this particular Emacs only for
|
||||
yourself, you can do so by adding it to your
|
||||
{file}`~/.config/nixpkgs/config.nix` (see
|
||||
[Nixpkgs manual](https://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides)):
|
||||
::: {.example #module-services-emacs-config-nix}
|
||||
### Custom Emacs in `~/.config/nixpkgs/config.nix`
|
||||
|
||||
[]{#module-services-emacs-config-nix}
|
||||
```
|
||||
{
|
||||
packageOverrides = super: let self = super.pkgs; in {
|
||||
@@ -210,7 +200,6 @@ yourself, you can do so by adding it to your
|
||||
};
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
In this case, the next `nix-env -f '<nixpkgs>' -iA
|
||||
myemacs` will take care of adding your emacs to the
|
||||
@@ -225,9 +214,7 @@ automatically generated {file}`emacs.desktop` (useful if you
|
||||
only use {command}`emacsclient`), you can change your file
|
||||
{file}`emacs.nix` in this way:
|
||||
|
||||
::: {.example #ex-emacsGtk3Nix}
|
||||
### Custom Emacs build
|
||||
|
||||
[]{#ex-emacsGtk3Nix}
|
||||
```
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
let
|
||||
@@ -244,9 +231,8 @@ let
|
||||
});
|
||||
in [...]
|
||||
```
|
||||
:::
|
||||
|
||||
After building this file as shown in [](#ex-emacsNix), you
|
||||
After building this file as shown in [the example above](#ex-emacsNix), you
|
||||
will get an GTK 3-based Emacs binary pre-loaded with your favorite packages.
|
||||
|
||||
## Running Emacs as a Service {#module-services-emacs-running}
|
||||
@@ -341,10 +327,7 @@ This will add the symlink
|
||||
|
||||
The Emacs init file should be changed to load the extension packages at
|
||||
startup:
|
||||
|
||||
::: {.example #module-services-emacs-package-initialisation}
|
||||
### Package initialization in `.emacs`
|
||||
|
||||
[]{#module-services-emacs-package-initialisation}
|
||||
```
|
||||
(require 'package)
|
||||
|
||||
@@ -354,7 +337,6 @@ startup:
|
||||
(setq package-enable-at-startup nil)
|
||||
(package-initialize)
|
||||
```
|
||||
:::
|
||||
|
||||
After the declarative emacs package configuration has been tested,
|
||||
previously downloaded packages can be cleaned up by removing
|
||||
@@ -395,9 +377,7 @@ To install the DocBook 5.0 schemas, either add
|
||||
Then customize the variable {var}`rng-schema-locating-files` to
|
||||
include {file}`~/.emacs.d/schemas.xml` and put the following
|
||||
text into that file:
|
||||
::: {.example #ex-emacs-docbook-xml}
|
||||
### nXML Schema Configuration (`~/.emacs.d/schemas.xml`)
|
||||
|
||||
[]{#ex-emacs-docbook-xml}
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
@@ -417,4 +397,3 @@ text into that file:
|
||||
-->
|
||||
</locatingRules>
|
||||
```
|
||||
:::
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
let
|
||||
cfg = config.services.asusd;
|
||||
json = pkgs.formats.json { };
|
||||
toml = pkgs.formats.toml { };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -17,55 +19,55 @@ in
|
||||
};
|
||||
|
||||
animeConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
type = json.type;
|
||||
default = { };
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/anime.ron.
|
||||
The content of /etc/asusd/anime.conf.
|
||||
See https://asus-linux.org/asusctl/#anime-control.
|
||||
'';
|
||||
};
|
||||
|
||||
asusdConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
type = json.type;
|
||||
default = { };
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/asusd.ron.
|
||||
The content of /etc/asusd/asusd.conf.
|
||||
See https://asus-linux.org/asusctl/.
|
||||
'';
|
||||
};
|
||||
|
||||
auraConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
type = json.type;
|
||||
default = { };
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/aura.ron.
|
||||
The content of /etc/asusd/aura.conf.
|
||||
See https://asus-linux.org/asusctl/#led-keyboard-control.
|
||||
'';
|
||||
};
|
||||
|
||||
profileConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
default = "";
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/profile.ron.
|
||||
The content of /etc/asusd/profile.conf.
|
||||
See https://asus-linux.org/asusctl/#profiles.
|
||||
'';
|
||||
};
|
||||
|
||||
fanCurvesConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/fan_curves.ron.
|
||||
See https://asus-linux.org/asusctl/#fan-curves.
|
||||
ledModesConfig = lib.mkOption {
|
||||
type = lib.types.nullOr toml.type;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/asusd-ledmodes.toml. Leave `null` to use default settings.
|
||||
See https://asus-linux.org/asusctl/#led-keyboard-control.
|
||||
'';
|
||||
};
|
||||
|
||||
userLedModesConfig = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
type = lib.types.nullOr toml.type;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
The content of /etc/asusd/asusd-user-ledmodes.ron.
|
||||
The content of /etc/asusd/asusd-user-ledmodes.toml.
|
||||
See https://asus-linux.org/asusctl/#led-keyboard-control.
|
||||
'';
|
||||
};
|
||||
@@ -77,18 +79,26 @@ in
|
||||
|
||||
environment.etc =
|
||||
let
|
||||
maybeConfig = name: cfg: lib.mkIf (cfg != null) {
|
||||
source = pkgs.writeText name cfg;
|
||||
maybeConfig = name: cfg: lib.mkIf (cfg != { }) {
|
||||
source = json.generate name cfg;
|
||||
mode = "0644";
|
||||
};
|
||||
in
|
||||
{
|
||||
"asusd/anime.ron" = maybeConfig "anime.ron" cfg.animeConfig;
|
||||
"asusd/asusd.ron" = maybeConfig "asusd.ron" cfg.asusdConfig;
|
||||
"asusd/aura.ron" = maybeConfig "aura.ron" cfg.auraConfig;
|
||||
"asusd/profile.conf" = maybeConfig "profile.ron" cfg.profileConfig;
|
||||
"asusd/fan_curves.ron" = maybeConfig "fan_curves.ron" cfg.fanCurvesConfig;
|
||||
"asusd/asusd_user_ledmodes.ron" = maybeConfig "asusd_user_ledmodes.ron" cfg.userLedModesConfig;
|
||||
"asusd/anime.conf" = maybeConfig "anime.conf" cfg.animeConfig;
|
||||
"asusd/asusd.conf" = maybeConfig "asusd.conf" cfg.asusdConfig;
|
||||
"asusd/aura.conf" = maybeConfig "aura.conf" cfg.auraConfig;
|
||||
"asusd/profile.conf" = lib.mkIf (cfg.profileConfig != null) {
|
||||
source = pkgs.writeText "profile.conf" cfg.profileConfig;
|
||||
mode = "0644";
|
||||
};
|
||||
"asusd/asusd-ledmodes.toml" = {
|
||||
source =
|
||||
if cfg.ledModesConfig == null
|
||||
then "${pkgs.asusctl}/share/asusd/data/asusd-ledmodes.toml"
|
||||
else toml.generate "asusd-ledmodes.toml" cfg.ledModesConfig;
|
||||
mode = "0644";
|
||||
};
|
||||
};
|
||||
|
||||
services.dbus.enable = true;
|
||||
|
||||
@@ -160,7 +160,7 @@ let
|
||||
|
||||
echo "Generating hwdb database..."
|
||||
# hwdb --update doesn't return error code even on errors!
|
||||
res="$(${pkgs.buildPackages.systemd}/bin/systemd-hwdb --root=$(pwd) update 2>&1)"
|
||||
res="$(${pkgs.buildPackages.udev}/bin/udevadm hwdb --update --root=$(pwd) 2>&1)"
|
||||
echo "$res"
|
||||
[ -z "$(echo "$res" | egrep '^Error')" ]
|
||||
mv etc/udev/hwdb.bin $out
|
||||
|
||||
@@ -461,7 +461,6 @@ in {
|
||||
"mopeka"
|
||||
"oralb"
|
||||
"qingping"
|
||||
"rapt_ble"
|
||||
"ruuvi_gateway"
|
||||
"ruuvitag_ble"
|
||||
"sensirion_ble"
|
||||
|
||||
@@ -13,6 +13,8 @@ let
|
||||
# configuration here https://github.com/foxcpp/maddy/blob/master/maddy.conf
|
||||
# Do not use this in production!
|
||||
|
||||
tls off
|
||||
|
||||
auth.pass_table local_authdb {
|
||||
table sql_table {
|
||||
driver sqlite3
|
||||
@@ -33,7 +35,6 @@ let
|
||||
}
|
||||
optional_step file /etc/maddy/aliases
|
||||
}
|
||||
|
||||
msgpipeline local_routing {
|
||||
destination postmaster $(local_domains) {
|
||||
modify {
|
||||
@@ -214,63 +215,6 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
tls = {
|
||||
loader = mkOption {
|
||||
type = with types; nullOr (enum [ "file" "off" ]);
|
||||
default = "off";
|
||||
description = lib.mdDoc ''
|
||||
TLS certificates are obtained by modules called "certificate
|
||||
loaders". Currently only the file loader is supported which reads
|
||||
certificates from files specifying the options `keyPaths` and
|
||||
`certPaths`.
|
||||
'';
|
||||
};
|
||||
|
||||
certificates = mkOption {
|
||||
type = with types; listOf (submodule {
|
||||
options = {
|
||||
keyPath = mkOption {
|
||||
type = types.path;
|
||||
example = "/etc/ssl/mx1.example.org.key";
|
||||
description = lib.mdDoc ''
|
||||
Path to the private key used for TLS.
|
||||
'';
|
||||
};
|
||||
certPath = mkOption {
|
||||
type = types.path;
|
||||
example = "/etc/ssl/mx1.example.org.crt";
|
||||
description = lib.mdDoc ''
|
||||
Path to the certificate used for TLS.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
default = [];
|
||||
example = lib.literalExpression ''
|
||||
[{
|
||||
keyPath = "/etc/ssl/mx1.example.org.key";
|
||||
certPath = "/etc/ssl/mx1.example.org.crt";
|
||||
}]
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
A list of attribute sets containing paths to TLS certificates and
|
||||
keys. Maddy will use SNI if multiple pairs are selected.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = with types; nullOr lines;
|
||||
description = lib.mdDoc ''
|
||||
Arguments for the specific certificate loader. Note that Maddy uses
|
||||
secure defaults for the TLS configuration so there is no need to
|
||||
change anything in most cases.
|
||||
See [upstream manual](https://maddy.email/reference/tls/) for
|
||||
available options.
|
||||
'';
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -280,7 +224,7 @@ in {
|
||||
};
|
||||
|
||||
ensureAccounts = mkOption {
|
||||
type = with types; listOf str;
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = lib.mdDoc ''
|
||||
List of IMAP accounts which get automatically created. Note that for
|
||||
@@ -326,16 +270,6 @@ in {
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
assertions = [{
|
||||
assertion = cfg.tls.loader == "file" -> cfg.tls.certificates != [];
|
||||
message = ''
|
||||
If maddy is configured to use TLS, tls.certificates with attribute sets
|
||||
of certPath and keyPath must be provided.
|
||||
Read more about obtaining TLS certificates here:
|
||||
https://maddy.email/tutorials/setting-up/#tls-certificates
|
||||
'';
|
||||
}];
|
||||
|
||||
systemd = {
|
||||
|
||||
packages = [ pkgs.maddy ];
|
||||
@@ -384,17 +318,6 @@ in {
|
||||
$(primary_domain) = ${cfg.primaryDomain}
|
||||
$(local_domains) = ${toString cfg.localDomains}
|
||||
hostname ${cfg.hostname}
|
||||
|
||||
${if (cfg.tls.loader == "file") then ''
|
||||
tls file ${concatStringsSep " " (
|
||||
map (x: x.certPath + " " + x.keyPath
|
||||
) cfg.tls.certificates)} ${optionalString (cfg.tls.extraConfig != "") ''
|
||||
{ ${cfg.tls.extraConfig} }
|
||||
''}
|
||||
'' else if (cfg.tls.loader == "off") then ''
|
||||
tls off
|
||||
'' else ""}
|
||||
|
||||
${cfg.config}
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ in {
|
||||
|
||||
systemd.timers.fstrim = {
|
||||
timerConfig = {
|
||||
OnCalendar = [ "" cfg.interval ];
|
||||
OnCalendar = cfg.interval;
|
||||
};
|
||||
wantedBy = [ "timers.target" ];
|
||||
};
|
||||
|
||||
@@ -9,7 +9,6 @@ let
|
||||
env = {
|
||||
GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}";
|
||||
DEBUG = "0";
|
||||
DEBUG_TOOLBAR = "0";
|
||||
MEDIA_ROOT = "/var/lib/tandoor-recipes";
|
||||
} // optionalAttrs (config.time.timeZone != null) {
|
||||
TIMEZONE = config.time.timeZone;
|
||||
|
||||
@@ -235,7 +235,7 @@ in {
|
||||
|
||||
systemd.services = let
|
||||
makeService = attrs: recursiveUpdate {
|
||||
path = [ datadogPkg pkgs.sysstat pkgs.procps pkgs.iproute2 ];
|
||||
path = [ datadogPkg pkgs.python pkgs.sysstat pkgs.procps pkgs.iproute2 ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
User = "datadog";
|
||||
|
||||
@@ -13,7 +13,12 @@ in
|
||||
options.services.grafana-agent = {
|
||||
enable = mkEnableOption (lib.mdDoc "grafana-agent");
|
||||
|
||||
package = mkPackageOptionMD pkgs "grafana-agent" { };
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.grafana-agent;
|
||||
defaultText = lib.literalExpression "pkgs.grafana-agent";
|
||||
description = lib.mdDoc "The grafana-agent package to use.";
|
||||
};
|
||||
|
||||
credentials = mkOption {
|
||||
description = lib.mdDoc ''
|
||||
@@ -32,22 +37,11 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
extraFlags = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
example = [ "-enable-features=integrations-next" "-disable-reporting" ];
|
||||
description = lib.mdDoc ''
|
||||
Extra command-line flags passed to {command}`grafana-agent`.
|
||||
|
||||
See <https://grafana.com/docs/agent/latest/static/configuration/flags/>
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
description = lib.mdDoc ''
|
||||
Configuration for {command}`grafana-agent`.
|
||||
Configuration for `grafana-agent`.
|
||||
|
||||
See <https://grafana.com/docs/agent/latest/configuration/>
|
||||
See https://grafana.com/docs/agent/latest/configuration/
|
||||
'';
|
||||
|
||||
type = types.submodule {
|
||||
@@ -146,7 +140,7 @@ in
|
||||
# We can't use Environment=HOSTNAME=%H, as it doesn't include the domain part.
|
||||
export HOSTNAME=$(< /proc/sys/kernel/hostname)
|
||||
|
||||
exec ${lib.getExe cfg.package} -config.expand-env -config.file ${configFile} ${escapeShellArgs cfg.extraFlags}
|
||||
exec ${lib.getExe cfg.package} -config.expand-env -config.file ${configFile}
|
||||
'';
|
||||
serviceConfig = {
|
||||
Restart = "always";
|
||||
|
||||
@@ -92,6 +92,17 @@ let
|
||||
grafanaTypes.datasourceConfig = types.submodule {
|
||||
freeformType = provisioningSettingsFormat.type;
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "password" ] ''
|
||||
`services.grafana.provision.datasources.settings.datasources.<name>.password` has been removed
|
||||
in Grafana 9. Use `secureJsonData` instead.
|
||||
'')
|
||||
(mkRemovedOptionModule [ "basicAuthPassword" ] ''
|
||||
`services.grafana.provision.datasources.settings.datasources.<name>.basicAuthPassword` has been removed
|
||||
in Grafana 9. Use `secureJsonData` instead.
|
||||
'')
|
||||
];
|
||||
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
@@ -592,6 +603,7 @@ in {
|
||||
description = lib.mdDoc "List of datasources to insert/update.";
|
||||
default = [];
|
||||
type = types.listOf grafanaTypes.datasourceConfig;
|
||||
apply = map (flip builtins.removeAttrs [ "password" "basicAuthPassword" ]);
|
||||
};
|
||||
|
||||
deleteDatasources = mkOption {
|
||||
|
||||
@@ -118,56 +118,56 @@ in
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = lib.mdDoc ''
|
||||
"bantime.increment" allows to use database for searching of previously banned ip's to increase
|
||||
a default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32 ...
|
||||
Allows to use database for searching of previously banned ip's to increase
|
||||
a default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
|
||||
'';
|
||||
};
|
||||
|
||||
bantime-increment.rndtime = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
default = "4m";
|
||||
type = types.str;
|
||||
example = "8m";
|
||||
description = lib.mdDoc ''
|
||||
"bantime.rndtime" is the max number of seconds using for mixing with random time
|
||||
"bantime-increment.rndtime" is the max number of seconds using for mixing with random time
|
||||
to prevent "clever" botnets calculate exact time IP can be unbanned again
|
||||
'';
|
||||
};
|
||||
|
||||
bantime-increment.maxtime = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
default = "10h";
|
||||
type = types.str;
|
||||
example = "48h";
|
||||
description = lib.mdDoc ''
|
||||
"bantime.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
|
||||
"bantime-increment.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
|
||||
'';
|
||||
};
|
||||
|
||||
bantime-increment.factor = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
default = "1";
|
||||
type = types.str;
|
||||
example = "4";
|
||||
description = lib.mdDoc ''
|
||||
"bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
|
||||
"bantime-increment.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
|
||||
default value of factor is 1 and with default value of formula, the ban time grows by 1, 2, 4, 8, 16 ...
|
||||
'';
|
||||
};
|
||||
|
||||
bantime-increment.formula = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
default = "ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor";
|
||||
type = types.str;
|
||||
example = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)";
|
||||
description = lib.mdDoc ''
|
||||
"bantime.formula" used by default to calculate next value of ban time, default value bellow,
|
||||
the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32 ...
|
||||
"bantime-increment.formula" used by default to calculate next value of ban time, default value bellow,
|
||||
the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
|
||||
'';
|
||||
};
|
||||
|
||||
bantime-increment.multipliers = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
example = "1 2 4 8 16 32 64";
|
||||
default = "1 2 4 8 16 32 64";
|
||||
type = types.str;
|
||||
example = "2 4 16 128";
|
||||
description = lib.mdDoc ''
|
||||
"bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding
|
||||
"bantime-increment.multipliers" used to calculate next value of ban time instead of formula, corresponding
|
||||
previously ban count and given "bantime.factor" (for multipliers default is 1);
|
||||
following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
|
||||
always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
|
||||
@@ -175,11 +175,11 @@ in
|
||||
};
|
||||
|
||||
bantime-increment.overalljails = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
default = false;
|
||||
type = types.bool;
|
||||
example = true;
|
||||
description = lib.mdDoc ''
|
||||
"bantime.overalljails" (if true) specifies the search of IP in the database will be executed
|
||||
"bantime-increment.overalljails" (if true) specifies the search of IP in the database will be executed
|
||||
cross over all jails, if false (default), only current jail of the ban IP will be searched
|
||||
'';
|
||||
};
|
||||
@@ -276,16 +276,8 @@ in
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = (cfg.bantime-increment.formula == null || cfg.bantime-increment.multipliers == null);
|
||||
message = ''
|
||||
Options `services.fail2ban.bantime-increment.formula` and `services.fail2ban.bantime-increment.multipliers` cannot be both specified.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
warnings = mkIf (!config.networking.firewall.enable && !config.networking.nftables.enable) [
|
||||
warnings = mkIf (config.networking.firewall.enable == false && config.networking.nftables.enable == false) [
|
||||
"fail2ban can not be used without a firewall"
|
||||
];
|
||||
|
||||
@@ -338,14 +330,15 @@ in
|
||||
# Add some reasonable default jails. The special "DEFAULT" jail
|
||||
# sets default values for all other jails.
|
||||
services.fail2ban.jails.DEFAULT = ''
|
||||
# Bantime increment options
|
||||
bantime.increment = ${boolToString cfg.bantime-increment.enable}
|
||||
${optionalString (cfg.bantime-increment.rndtime != null) "bantime.rndtime = ${cfg.bantime-increment.rndtime}"}
|
||||
${optionalString (cfg.bantime-increment.maxtime != null) "bantime.maxtime = ${cfg.bantime-increment.maxtime}"}
|
||||
${optionalString (cfg.bantime-increment.factor != null) "bantime.factor = ${cfg.bantime-increment.factor}"}
|
||||
${optionalString (cfg.bantime-increment.formula != null) "bantime.formula = ${cfg.bantime-increment.formula}"}
|
||||
${optionalString (cfg.bantime-increment.multipliers != null) "bantime.multipliers = ${cfg.bantime-increment.multipliers}"}
|
||||
${optionalString (cfg.bantime-increment.overalljails != null) "bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}"}
|
||||
${optionalString cfg.bantime-increment.enable ''
|
||||
# Bantime incremental
|
||||
bantime.increment = ${boolToString cfg.bantime-increment.enable}
|
||||
bantime.maxtime = ${cfg.bantime-increment.maxtime}
|
||||
bantime.factor = ${cfg.bantime-increment.factor}
|
||||
bantime.formula = ${cfg.bantime-increment.formula}
|
||||
bantime.multipliers = ${cfg.bantime-increment.multipliers}
|
||||
bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}
|
||||
''}
|
||||
# Miscellaneous options
|
||||
ignoreip = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}
|
||||
${optionalString (cfg.bantime != null) ''
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
format = pkgs.formats.json { };
|
||||
commonOptions = { pkgName, flavour ? pkgName }: mkOption {
|
||||
default = { };
|
||||
description = mdDoc ''
|
||||
Attribute set of ${flavour} instances.
|
||||
Creates independent `${flavour}-''${name}.service` systemd units for each instance defined here.
|
||||
'';
|
||||
type = with types; attrsOf (submodule ({ name, ... }: {
|
||||
options = {
|
||||
enable = mkEnableOption (mdDoc "this ${flavour} instance") // { default = true; };
|
||||
|
||||
package = mkPackageOptionMD pkgs pkgName { };
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
description = mdDoc ''
|
||||
User under which this instance runs.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "root";
|
||||
description = mdDoc ''
|
||||
Group under which this instance runs.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = format.type;
|
||||
|
||||
options = {
|
||||
pid_file = mkOption {
|
||||
default = "/run/${flavour}/${name}.pid";
|
||||
type = types.str;
|
||||
description = mdDoc ''
|
||||
Path to use for the pid file.
|
||||
'';
|
||||
};
|
||||
|
||||
template = mkOption {
|
||||
default = [ ];
|
||||
type = with types; listOf (attrsOf anything);
|
||||
description =
|
||||
let upstreamDocs =
|
||||
if flavour == "vault-agent"
|
||||
then "https://developer.hashicorp.com/vault/docs/agent/template"
|
||||
else "https://github.com/hashicorp/consul-template/blob/main/docs/configuration.md#templates";
|
||||
in
|
||||
mdDoc ''
|
||||
Template section of ${flavour}.
|
||||
Refer to <${upstreamDocs}> for supported values.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
default = { };
|
||||
|
||||
description =
|
||||
let upstreamDocs =
|
||||
if flavour == "vault-agent"
|
||||
then "https://developer.hashicorp.com/vault/docs/agent#configuration-file-options"
|
||||
else "https://github.com/hashicorp/consul-template/blob/main/docs/configuration.md#configuration-file";
|
||||
in
|
||||
mdDoc ''
|
||||
Free-form settings written directly to the `config.json` file.
|
||||
Refer to <${upstreamDocs}> for supported values.
|
||||
|
||||
::: {.note}
|
||||
Resulting format is JSON not HCL.
|
||||
Refer to <https://www.hcl2json.com/> if you are unsure how to convert HCL options to JSON.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
createAgentInstance = { instance, name, flavour }:
|
||||
let
|
||||
configFile = format.generate "${name}.json" instance.settings;
|
||||
in
|
||||
mkIf (instance.enable) {
|
||||
description = "${flavour} daemon - ${name}";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
path = [ pkgs.getent ];
|
||||
startLimitIntervalSec = 60;
|
||||
startLimitBurst = 3;
|
||||
serviceConfig = {
|
||||
User = instance.user;
|
||||
Group = instance.group;
|
||||
RuntimeDirectory = flavour;
|
||||
ExecStart = "${getExe instance.package} ${optionalString ((getName instance.package) == "vault") "agent"} -config ${configFile}";
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
|
||||
KillSignal = "SIGINT";
|
||||
TimeoutStopSec = "30s";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.consul-template.instances = commonOptions { pkgName = "consul-template"; };
|
||||
services.vault-agent.instances = commonOptions { pkgName = "vault"; flavour = "vault-agent"; };
|
||||
};
|
||||
|
||||
config = mkMerge (map
|
||||
(flavour:
|
||||
let cfg = config.services.${flavour}; in
|
||||
mkIf (cfg.instances != { }) {
|
||||
systemd.services = mapAttrs'
|
||||
(name: instance: nameValuePair "${flavour}-${name}" (createAgentInstance { inherit name instance flavour; }))
|
||||
cfg.instances;
|
||||
})
|
||||
[ "consul-template" "vault-agent" ]);
|
||||
|
||||
meta.maintainers = with maintainers; [ indeednotjames tcheronneau ];
|
||||
}
|
||||
|
||||
@@ -2,22 +2,18 @@
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.cloud-init;
|
||||
path = with pkgs; [
|
||||
cloud-init
|
||||
iproute2
|
||||
nettools
|
||||
openssh
|
||||
shadow
|
||||
util-linux
|
||||
busybox
|
||||
]
|
||||
++ optional cfg.btrfs.enable btrfs-progs
|
||||
++ optional cfg.ext4.enable e2fsprogs
|
||||
;
|
||||
settingsFormat = pkgs.formats.yaml { };
|
||||
cfgfile = settingsFormat.generate "cloud.cfg" cfg.settings;
|
||||
let cfg = config.services.cloud-init;
|
||||
path = with pkgs; [
|
||||
cloud-init
|
||||
iproute2
|
||||
nettools
|
||||
openssh
|
||||
shadow
|
||||
util-linux
|
||||
busybox
|
||||
] ++ optional cfg.btrfs.enable btrfs-progs
|
||||
++ optional cfg.ext4.enable e2fsprogs
|
||||
;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
@@ -25,7 +21,7 @@ in
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
description = lib.mdDoc ''
|
||||
Enable the cloud-init service. This services reads
|
||||
configuration metadata in a cloud environment and configures
|
||||
the machine according to this metadata.
|
||||
@@ -44,7 +40,7 @@ in
|
||||
btrfs.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
description = lib.mdDoc ''
|
||||
Allow the cloud-init service to operate `btrfs` filesystem.
|
||||
'';
|
||||
};
|
||||
@@ -52,7 +48,7 @@ in
|
||||
ext4.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = mdDoc ''
|
||||
description = lib.mdDoc ''
|
||||
Allow the cloud-init service to operate `ext4` filesystem.
|
||||
'';
|
||||
};
|
||||
@@ -60,170 +56,141 @@ in
|
||||
network.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = mdDoc ''
|
||||
description = lib.mdDoc ''
|
||||
Allow the cloud-init service to configure network interfaces
|
||||
through systemd-networkd.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
description = mdDoc ''
|
||||
Structured cloud-init configuration.
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = settingsFormat.type;
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = mdDoc ''
|
||||
raw cloud-init configuration.
|
||||
default = ''
|
||||
system_info:
|
||||
distro: nixos
|
||||
network:
|
||||
renderers: [ 'networkd' ]
|
||||
users:
|
||||
- root
|
||||
|
||||
Takes precedence over the `settings` option if set.
|
||||
'';
|
||||
disable_root: false
|
||||
preserve_hostname: false
|
||||
|
||||
cloud_init_modules:
|
||||
- migrator
|
||||
- seed_random
|
||||
- bootcmd
|
||||
- write-files
|
||||
- growpart
|
||||
- resizefs
|
||||
- update_hostname
|
||||
- resolv_conf
|
||||
- ca-certs
|
||||
- rsyslog
|
||||
- users-groups
|
||||
|
||||
cloud_config_modules:
|
||||
- disk_setup
|
||||
- mounts
|
||||
- ssh-import-id
|
||||
- set-passwords
|
||||
- timezone
|
||||
- disable-ec2-metadata
|
||||
- runcmd
|
||||
- ssh
|
||||
|
||||
cloud_final_modules:
|
||||
- rightscale_userdata
|
||||
- scripts-vendor
|
||||
- scripts-per-once
|
||||
- scripts-per-boot
|
||||
- scripts-per-instance
|
||||
- scripts-user
|
||||
- ssh-authkey-fingerprints
|
||||
- keys-to-console
|
||||
- phone-home
|
||||
- final-message
|
||||
- power-state-change
|
||||
'';
|
||||
description = lib.mdDoc "cloud-init configuration.";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
services.cloud-init.settings = {
|
||||
system_info = mkDefault {
|
||||
distro = "nixos";
|
||||
network = {
|
||||
renderers = [ "networkd" ];
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
users = mkDefault [ "root" ];
|
||||
disable_root = mkDefault false;
|
||||
preserve_hostname = mkDefault false;
|
||||
|
||||
cloud_init_modules = mkDefault [
|
||||
"migrator"
|
||||
"seed_random"
|
||||
"bootcmd"
|
||||
"write-files"
|
||||
"growpart"
|
||||
"resizefs"
|
||||
"update_hostname"
|
||||
"resolv_conf"
|
||||
"ca-certs"
|
||||
"rsyslog"
|
||||
"users-groups"
|
||||
];
|
||||
|
||||
cloud_config_modules = mkDefault [
|
||||
"disk_setup"
|
||||
"mounts"
|
||||
"ssh-import-id"
|
||||
"set-passwords"
|
||||
"timezone"
|
||||
"disable-ec2-metadata"
|
||||
"runcmd"
|
||||
"ssh"
|
||||
];
|
||||
|
||||
cloud_final_modules = mkDefault [
|
||||
"rightscale_userdata"
|
||||
"scripts-vendor"
|
||||
"scripts-per-once"
|
||||
"scripts-per-boot"
|
||||
"scripts-per-instance"
|
||||
"scripts-user"
|
||||
"ssh-authkey-fingerprints"
|
||||
"keys-to-console"
|
||||
"phone-home"
|
||||
"final-message"
|
||||
"power-state-change"
|
||||
];
|
||||
};
|
||||
} // (mkIf cfg.enable {
|
||||
|
||||
environment.etc."cloud/cloud.cfg" =
|
||||
if cfg.config == "" then
|
||||
{ source = cfgfile; }
|
||||
else
|
||||
{ text = cfg.config; }
|
||||
;
|
||||
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";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
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";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.cloud-init = {
|
||||
description = "Initial cloud-init job (metadata service crawler)";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [
|
||||
"network-online.target"
|
||||
"cloud-init-local.service"
|
||||
"sshd.service"
|
||||
"sshd-keygen.service"
|
||||
];
|
||||
after = [ "network-online.target" "cloud-init-local.service" ];
|
||||
before = [ "sshd.service" "sshd-keygen.service" ];
|
||||
requires = [ "network.target" ];
|
||||
path = path;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
systemd.services.cloud-init =
|
||||
{ description = "Initial cloud-init job (metadata service crawler)";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" "cloud-init-local.service"
|
||||
"sshd.service" "sshd-keygen.service" ];
|
||||
after = [ "network-online.target" "cloud-init-local.service" ];
|
||||
before = [ "sshd.service" "sshd-keygen.service" ];
|
||||
requires = [ "network.target"];
|
||||
path = path;
|
||||
serviceConfig =
|
||||
{ Type = "oneshot";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.cloud-config = {
|
||||
description = "Apply the settings specified in cloud-config";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
|
||||
systemd.services.cloud-config =
|
||||
{ description = "Apply the settings specified in cloud-config";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
|
||||
|
||||
path = path;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
path = path;
|
||||
serviceConfig =
|
||||
{ Type = "oneshot";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.cloud-final = {
|
||||
description = "Execute cloud user/final scripts";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
|
||||
requires = [ "cloud-config.target" ];
|
||||
path = path;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
systemd.services.cloud-final =
|
||||
{ description = "Execute cloud user/final scripts";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
|
||||
requires = [ "cloud-config.target" ];
|
||||
path = path;
|
||||
serviceConfig =
|
||||
{ Type = "oneshot";
|
||||
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final";
|
||||
RemainAfterExit = "yes";
|
||||
TimeoutSec = "infinity";
|
||||
StandardOutput = "journal+console";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.targets.cloud-config = {
|
||||
description = "Cloud-config availability";
|
||||
requires = [ "cloud-init-local.service" "cloud-init.service" ];
|
||||
};
|
||||
});
|
||||
systemd.targets.cloud-config =
|
||||
{ description = "Cloud-config availability";
|
||||
requires = [ "cloud-init-local.service" "cloud-init.service" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.kavita;
|
||||
in {
|
||||
options.services.kavita = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "Kavita reading server");
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "kavita";
|
||||
description = lib.mdDoc "User account under which Kavita runs.";
|
||||
};
|
||||
|
||||
package = lib.mkPackageOptionMD pkgs "kavita" { };
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
default = "/var/lib/kavita";
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc "The directory where Kavita stores its state.";
|
||||
};
|
||||
|
||||
tokenKeyFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = lib.mdDoc ''
|
||||
A file containing the TokenKey, a secret with at 128+ bits.
|
||||
It can be generated with `head -c 32 /dev/urandom | base64`.
|
||||
'';
|
||||
};
|
||||
port = lib.mkOption {
|
||||
default = 5000;
|
||||
type = lib.types.port;
|
||||
description = lib.mdDoc "Port to bind to.";
|
||||
};
|
||||
ipAdresses = lib.mkOption {
|
||||
default = ["0.0.0.0" "::"];
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = lib.mdDoc "IP Adresses to bind to. The default is to bind
|
||||
to all IPv4 and IPv6 addresses.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.kavita = {
|
||||
description = "Kavita";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
preStart = ''
|
||||
umask u=rwx,g=rx,o=
|
||||
cat > "${cfg.dataDir}/config/appsettings.json" <<EOF
|
||||
{
|
||||
"TokenKey": "$(cat ${cfg.tokenKeyFile})",
|
||||
"Port": ${toString cfg.port},
|
||||
"IpAddresses": "${lib.concatStringsSep "," cfg.ipAdresses}"
|
||||
}
|
||||
EOF
|
||||
'';
|
||||
serviceConfig = {
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
ExecStart = "${lib.getExe cfg.package}";
|
||||
Restart = "always";
|
||||
User = cfg.user;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.user} - -"
|
||||
"d '${cfg.dataDir}/config' 0750 ${cfg.user} ${cfg.user} - -"
|
||||
];
|
||||
|
||||
users = {
|
||||
users.${cfg.user} = {
|
||||
description = "kavita service user";
|
||||
isSystemUser = true;
|
||||
group = cfg.user;
|
||||
home = cfg.dataDir;
|
||||
};
|
||||
groups.${cfg.user} = { };
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ misterio77 ];
|
||||
}
|
||||
@@ -8,8 +8,7 @@ let
|
||||
cfg = config.services.mediawiki;
|
||||
fpm = config.services.phpfpm.pools.mediawiki;
|
||||
user = "mediawiki";
|
||||
group = if cfg.webserver == "apache" then "apache" else "mediawiki";
|
||||
|
||||
group = config.services.httpd.group;
|
||||
cacheDir = "/var/cache/mediawiki";
|
||||
stateDir = "/var/lib/mediawiki";
|
||||
|
||||
@@ -74,7 +73,7 @@ let
|
||||
$wgScriptPath = "";
|
||||
|
||||
## The protocol and server name to use in fully-qualified URLs
|
||||
$wgServer = "${cfg.url}";
|
||||
$wgServer = "${if cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL then "https" else "http"}://${cfg.virtualHost.hostName}";
|
||||
|
||||
## The URL path to static resources (images, scripts, etc.)
|
||||
$wgResourceBasePath = $wgScriptPath;
|
||||
@@ -88,7 +87,8 @@ let
|
||||
$wgEnableEmail = true;
|
||||
$wgEnableUserEmail = true; # UPO
|
||||
|
||||
$wgPasswordSender = "${cfg.passwordSender}";
|
||||
$wgEmergencyContact = "${if cfg.virtualHost.adminAddr != null then cfg.virtualHost.adminAddr else config.services.httpd.adminAddr}";
|
||||
$wgPasswordSender = $wgEmergencyContact;
|
||||
|
||||
$wgEnotifUserTalk = false; # UPO
|
||||
$wgEnotifWatchlist = false; # UPO
|
||||
@@ -190,16 +190,6 @@ in
|
||||
description = lib.mdDoc "Which MediaWiki package to use.";
|
||||
};
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
default = pkg;
|
||||
defaultText = literalExpression "pkg";
|
||||
description = lib.mdDoc ''
|
||||
The final package used by the module. This is the package that will have extensions and skins installed.
|
||||
'';
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
default = "MediaWiki";
|
||||
@@ -207,22 +197,6 @@ in
|
||||
description = lib.mdDoc "Name of the wiki.";
|
||||
};
|
||||
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
default = if cfg.webserver == "apache" then
|
||||
"${if cfg.httpd.virtualHost.addSSL || cfg.httpd.virtualHost.forceSSL || cfg.httpd.virtualHost.onlySSL then "https" else "http"}://${cfg.httpd.virtualHost.hostName}"
|
||||
else
|
||||
"http://localhost";
|
||||
defaultText = literalExpression ''
|
||||
if cfg.webserver == "apache" then
|
||||
"''${if cfg.httpd.virtualHost.addSSL || cfg.httpd.virtualHost.forceSSL || cfg.httpd.virtualHost.onlySSL then "https" else "http"}://''${cfg.httpd.virtualHost.hostName}"
|
||||
else
|
||||
"http://localhost";
|
||||
'';
|
||||
example = "https://wiki.example.org";
|
||||
description = lib.mdDoc "URL of the wiki.";
|
||||
};
|
||||
|
||||
uploadsDir = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = "${stateDir}/uploads";
|
||||
@@ -238,24 +212,6 @@ in
|
||||
example = "/run/keys/mediawiki-password";
|
||||
};
|
||||
|
||||
passwordSender = mkOption {
|
||||
type = types.str;
|
||||
default =
|
||||
if cfg.webserver == "apache" then
|
||||
if cfg.httpd.virtualHost.adminAddr != null then
|
||||
cfg.httpd.virtualHost.adminAddr
|
||||
else
|
||||
config.services.httpd.adminAddr else "root@localhost";
|
||||
defaultText = literalExpression ''
|
||||
if cfg.webserver == "apache" then
|
||||
if cfg.httpd.virtualHost.adminAddr != null then
|
||||
cfg.httpd.virtualHost.adminAddr
|
||||
else
|
||||
config.services.httpd.adminAddr else "root@localhost"
|
||||
'';
|
||||
description = lib.mdDoc "Contact address for password reset.";
|
||||
};
|
||||
|
||||
skins = mkOption {
|
||||
default = {};
|
||||
type = types.attrsOf types.path;
|
||||
@@ -285,12 +241,6 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
webserver = mkOption {
|
||||
type = types.enum [ "apache" "none" ];
|
||||
default = "apache";
|
||||
description = lib.mdDoc "Webserver to use.";
|
||||
};
|
||||
|
||||
database = {
|
||||
type = mkOption {
|
||||
type = types.enum [ "mysql" "postgres" "sqlite" "mssql" "oracle" ];
|
||||
@@ -368,7 +318,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
httpd.virtualHost = mkOption {
|
||||
virtualHost = mkOption {
|
||||
type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
|
||||
example = literalExpression ''
|
||||
{
|
||||
@@ -416,10 +366,6 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(lib.mkRenamedOptionModule [ "services" "mediawiki" "virtualHost" ] [ "services" "mediawiki" "httpd" "virtualHost" ])
|
||||
];
|
||||
|
||||
# implementation
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
@@ -466,42 +412,36 @@ in
|
||||
services.phpfpm.pools.mediawiki = {
|
||||
inherit user group;
|
||||
phpEnv.MEDIAWIKI_CONFIG = "${mediawikiConfig}";
|
||||
settings = (if (cfg.webserver == "apache") then {
|
||||
settings = {
|
||||
"listen.owner" = config.services.httpd.user;
|
||||
"listen.group" = config.services.httpd.group;
|
||||
} else {
|
||||
"listen.owner" = user;
|
||||
"listen.group" = group;
|
||||
}) // cfg.poolConfig;
|
||||
} // cfg.poolConfig;
|
||||
};
|
||||
|
||||
services.httpd = lib.mkIf (cfg.webserver == "apache") {
|
||||
services.httpd = {
|
||||
enable = true;
|
||||
extraModules = [ "proxy_fcgi" ];
|
||||
virtualHosts.${cfg.httpd.virtualHost.hostName} = mkMerge [
|
||||
cfg.httpd.virtualHost
|
||||
{
|
||||
documentRoot = mkForce "${pkg}/share/mediawiki";
|
||||
extraConfig = ''
|
||||
<Directory "${pkg}/share/mediawiki">
|
||||
<FilesMatch "\.php$">
|
||||
<If "-f %{REQUEST_FILENAME}">
|
||||
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
|
||||
</If>
|
||||
</FilesMatch>
|
||||
virtualHosts.${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost {
|
||||
documentRoot = mkForce "${pkg}/share/mediawiki";
|
||||
extraConfig = ''
|
||||
<Directory "${pkg}/share/mediawiki">
|
||||
<FilesMatch "\.php$">
|
||||
<If "-f %{REQUEST_FILENAME}">
|
||||
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
|
||||
</If>
|
||||
</FilesMatch>
|
||||
|
||||
Require all granted
|
||||
DirectoryIndex index.php
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
'' + optionalString (cfg.uploadsDir != null) ''
|
||||
Alias "/images" "${cfg.uploadsDir}"
|
||||
<Directory "${cfg.uploadsDir}">
|
||||
Require all granted
|
||||
</Directory>
|
||||
'';
|
||||
}
|
||||
];
|
||||
Require all granted
|
||||
DirectoryIndex index.php
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
'' + optionalString (cfg.uploadsDir != null) ''
|
||||
Alias "/images" "${cfg.uploadsDir}"
|
||||
<Directory "${cfg.uploadsDir}">
|
||||
Require all granted
|
||||
</Directory>
|
||||
'';
|
||||
} ];
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
@@ -549,14 +489,13 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.httpd.after = optional (cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "mysql") "mysql.service"
|
||||
++ optional (cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "postgres") "postgresql.service";
|
||||
systemd.services.httpd.after = optional (cfg.database.createLocally && cfg.database.type == "mysql") "mysql.service"
|
||||
++ optional (cfg.database.createLocally && cfg.database.type == "postgres") "postgresql.service";
|
||||
|
||||
users.users.${user} = {
|
||||
group = group;
|
||||
isSystemUser = true;
|
||||
};
|
||||
users.groups.${group} = {};
|
||||
|
||||
environment.systemPackages = [ mediawikiScripts ];
|
||||
};
|
||||
|
||||
@@ -76,7 +76,7 @@ in
|
||||
export DATABASE_PASSWORD="$(<"${cfg.dbpassFile}")"
|
||||
'' + ''
|
||||
export DATABASE_URL="${dbUrl}"
|
||||
${cfg.package}/bin/notify_push '${config.services.nextcloud.datadir}/config/config.php'
|
||||
${cfg.package}/bin/notify_push --glob-config '${config.services.nextcloud.datadir}/config/config.php'
|
||||
'';
|
||||
serviceConfig = {
|
||||
User = "nextcloud";
|
||||
|
||||
@@ -12,16 +12,10 @@ major version available.
|
||||
|
||||
Nextcloud is a PHP-based application which requires an HTTP server
|
||||
([`services.nextcloud`](#opt-services.nextcloud.enable)
|
||||
and optionally supports
|
||||
[`services.nginx`](#opt-services.nginx.enable)).
|
||||
|
||||
For the database, you can set
|
||||
[`services.nextcloud.config.dbtype`](#opt-services.nextcloud.config.dbtype) to
|
||||
either `sqlite` (the default), `mysql`, or `pgsql`. For the last two, by
|
||||
default, a local database will be created and nextcloud will connect to it via
|
||||
socket; this can be disabled by setting
|
||||
[`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally)
|
||||
to `false`.
|
||||
optionally supports
|
||||
[`services.nginx`](#opt-services.nginx.enable))
|
||||
and a database (it's recommended to use
|
||||
[`services.postgresql`](#opt-services.postgresql.enable)).
|
||||
|
||||
A very basic configuration may look like this:
|
||||
```
|
||||
@@ -32,10 +26,30 @@ A very basic configuration may look like this:
|
||||
hostName = "nextcloud.tld";
|
||||
config = {
|
||||
dbtype = "pgsql";
|
||||
dbuser = "nextcloud";
|
||||
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
|
||||
dbname = "nextcloud";
|
||||
adminpassFile = "/path/to/admin-pass-file";
|
||||
adminuser = "root";
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "nextcloud" ];
|
||||
ensureUsers = [
|
||||
{ name = "nextcloud";
|
||||
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# ensure that postgres is running *before* running the setup
|
||||
systemd.services."nextcloud-setup" = {
|
||||
requires = ["postgresql.service"];
|
||||
after = ["postgresql.service"];
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
}
|
||||
```
|
||||
|
||||
@@ -57,9 +57,6 @@ let
|
||||
|
||||
inherit (config.system) stateVersion;
|
||||
|
||||
mysqlLocal = cfg.database.createLocally && cfg.config.dbtype == "mysql";
|
||||
pgsqlLocal = cfg.database.createLocally && cfg.config.dbtype == "pgsql";
|
||||
|
||||
in {
|
||||
|
||||
imports = [
|
||||
@@ -317,9 +314,13 @@ in {
|
||||
|
||||
createLocally = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
default = false;
|
||||
description = lib.mdDoc ''
|
||||
Create the database and database user locally.
|
||||
Create the database and database user locally. Only available for
|
||||
mysql database.
|
||||
Note that this option will use the latest version of MariaDB which
|
||||
is not officially supported by Nextcloud. As for now a workaround
|
||||
is used to also support MariaDB version >= 10.6.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -351,15 +352,12 @@ in {
|
||||
};
|
||||
dbhost = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default =
|
||||
if pgsqlLocal then "/run/postgresql"
|
||||
else if mysqlLocal then "localhost:/run/mysqld/mysqld.sock"
|
||||
else "localhost";
|
||||
defaultText = "localhost";
|
||||
default = "localhost";
|
||||
description = lib.mdDoc ''
|
||||
Database host or socket path. Defaults to the correct unix socket
|
||||
instead if `services.nextcloud.database.createLocally` is true and
|
||||
`services.nextcloud.config.dbtype` is either `pgsql` or `mysql`.
|
||||
Database host.
|
||||
|
||||
Note: for using Unix authentication with PostgreSQL, this should be
|
||||
set to `/run/postgresql`.
|
||||
'';
|
||||
};
|
||||
dbport = mkOption {
|
||||
@@ -739,22 +737,8 @@ in {
|
||||
}
|
||||
|
||||
{ assertions = [
|
||||
{ assertion = cfg.database.createLocally -> cfg.config.dbpassFile == null;
|
||||
message = ''
|
||||
Using `services.nextcloud.database.createLocally` (that now defaults
|
||||
to true) with database password authentication is no longer
|
||||
supported.
|
||||
|
||||
If you use an external database (or want to use password auth for any
|
||||
other reason), set `services.nextcloud.database.createLocally` to
|
||||
`false`. The database won't be managed for you (use `services.mysql`
|
||||
if you want to set it up).
|
||||
|
||||
If you want this module to manage your nextcloud database for you,
|
||||
unset `services.nextcloud.config.dbpassFile` and
|
||||
`services.nextcloud.config.dbhost` to use socket authentication
|
||||
instead of password.
|
||||
'';
|
||||
{ assertion = cfg.database.createLocally -> cfg.config.dbtype == "mysql";
|
||||
message = ''services.nextcloud.config.dbtype must be set to mysql if services.nextcloud.database.createLocally is set to true.'';
|
||||
}
|
||||
]; }
|
||||
|
||||
@@ -918,8 +902,6 @@ in {
|
||||
in {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "phpfpm-nextcloud.service" ];
|
||||
after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
|
||||
requires = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
|
||||
path = [ occ ];
|
||||
script = ''
|
||||
${optionalString (c.dbpassFile != null) ''
|
||||
@@ -1025,7 +1007,7 @@ in {
|
||||
|
||||
environment.systemPackages = [ occ ];
|
||||
|
||||
services.mysql = lib.mkIf mysqlLocal {
|
||||
services.mysql = lib.mkIf cfg.database.createLocally {
|
||||
enable = true;
|
||||
package = lib.mkDefault pkgs.mariadb;
|
||||
ensureDatabases = [ cfg.config.dbname ];
|
||||
@@ -1033,15 +1015,14 @@ in {
|
||||
name = cfg.config.dbuser;
|
||||
ensurePermissions = { "${cfg.config.dbname}.*" = "ALL PRIVILEGES"; };
|
||||
}];
|
||||
};
|
||||
|
||||
services.postgresql = mkIf pgsqlLocal {
|
||||
enable = true;
|
||||
ensureDatabases = [ cfg.config.dbname ];
|
||||
ensureUsers = [{
|
||||
name = cfg.config.dbuser;
|
||||
ensurePermissions = { "DATABASE ${cfg.config.dbname}" = "ALL PRIVILEGES"; };
|
||||
}];
|
||||
initialScript = pkgs.writeText "mysql-init" ''
|
||||
CREATE USER '${cfg.config.dbname}'@'localhost' IDENTIFIED BY '${builtins.readFile( cfg.config.dbpassFile )}';
|
||||
CREATE DATABASE IF NOT EXISTS ${cfg.config.dbname};
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
|
||||
CREATE TEMPORARY TABLES ON ${cfg.config.dbname}.* TO '${cfg.config.dbuser}'@'localhost'
|
||||
IDENTIFIED BY '${builtins.readFile( cfg.config.dbpassFile )}';
|
||||
FLUSH privileges;
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx.enable = mkDefault true;
|
||||
|
||||
@@ -1,71 +1,65 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.stargazer;
|
||||
globalSection = ''
|
||||
listen = ${lib.concatStringsSep " " cfg.listen}
|
||||
connection-logging = ${lib.boolToString cfg.connectionLogging}
|
||||
log-ip = ${lib.boolToString cfg.ipLog}
|
||||
log-ip-partial = ${lib.boolToString cfg.ipLogPartial}
|
||||
routesFormat = pkgs.formats.ini { };
|
||||
globalFile = pkgs.writeText "global.ini" ''
|
||||
listen = ${concatStringsSep " " cfg.listen}
|
||||
connection-logging = ${boolToString cfg.connectionLogging}
|
||||
log-ip = ${boolToString cfg.ipLog}
|
||||
log-ip-partial = ${boolToString cfg.ipLogPartial}
|
||||
request-timeout = ${toString cfg.requestTimeout}
|
||||
response-timeout = ${toString cfg.responseTimeout}
|
||||
|
||||
[:tls]
|
||||
store = ${toString cfg.store}
|
||||
organization = ${cfg.certOrg}
|
||||
gen-certs = ${lib.boolToString cfg.genCerts}
|
||||
regen-certs = ${lib.boolToString cfg.regenCerts}
|
||||
${lib.optionalString (cfg.certLifetime != "") "cert-lifetime = ${cfg.certLifetime}"}
|
||||
gen-certs = ${boolToString cfg.genCerts}
|
||||
regen-certs = ${boolToString cfg.regenCerts}
|
||||
${optionalString (cfg.certLifetime != "") "cert-lifetime = ${cfg.certLifetime}"}
|
||||
|
||||
'';
|
||||
genINI = lib.generators.toINI { };
|
||||
configFile = pkgs.writeText "config.ini" (lib.strings.concatStrings (
|
||||
[ globalSection ] ++ (lib.lists.forEach cfg.routes (section:
|
||||
let
|
||||
name = section.route;
|
||||
params = builtins.removeAttrs section [ "route" ];
|
||||
in
|
||||
genINI
|
||||
{
|
||||
"${name}" = params;
|
||||
} + "\n"
|
||||
))
|
||||
));
|
||||
routesFile = routesFormat.generate "router.ini" cfg.routes;
|
||||
configFile = pkgs.runCommand "config.ini" { } ''
|
||||
cat ${globalFile} ${routesFile} > $out
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.services.stargazer = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "Stargazer Gemini server");
|
||||
enable = mkEnableOption (lib.mdDoc "Stargazer Gemini server");
|
||||
|
||||
listen = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]";
|
||||
defaultText = lib.literalExpression ''[ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]"'';
|
||||
example = lib.literalExpression ''[ "10.0.0.12" "[2002:a00:1::]" ]'';
|
||||
type = types.listOf types.str;
|
||||
default = [ "0.0.0.0" ] ++ optional config.networking.enableIPv6 "[::0]";
|
||||
defaultText = literalExpression ''[ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]"'';
|
||||
example = literalExpression ''[ "10.0.0.12" "[2002:a00:1::]" ]'';
|
||||
description = lib.mdDoc ''
|
||||
Address and port to listen on.
|
||||
'';
|
||||
};
|
||||
|
||||
connectionLogging = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc "Whether or not to log connections to stdout.";
|
||||
};
|
||||
|
||||
ipLog = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = lib.mdDoc "Log client IP addresses in the connection log.";
|
||||
};
|
||||
|
||||
ipLogPartial = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = lib.mdDoc "Log partial client IP addresses in the connection log.";
|
||||
};
|
||||
|
||||
requestTimeout = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
type = types.int;
|
||||
default = 5;
|
||||
description = lib.mdDoc ''
|
||||
Number of seconds to wait for the client to send a complete
|
||||
@@ -74,7 +68,7 @@ in
|
||||
};
|
||||
|
||||
responseTimeout = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = lib.mdDoc ''
|
||||
Number of seconds to wait for the client to send a complete
|
||||
@@ -84,7 +78,7 @@ in
|
||||
};
|
||||
|
||||
store = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
type = types.path;
|
||||
default = /var/lib/gemini/certs;
|
||||
description = lib.mdDoc ''
|
||||
Path to the certificate store on disk. This should be a
|
||||
@@ -93,7 +87,7 @@ in
|
||||
};
|
||||
|
||||
certOrg = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
type = types.str;
|
||||
default = "stargazer";
|
||||
description = lib.mdDoc ''
|
||||
The name of the organization responsible for the X.509
|
||||
@@ -102,7 +96,7 @@ in
|
||||
};
|
||||
|
||||
genCerts = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
Set to false to disable automatic certificate generation.
|
||||
@@ -111,7 +105,7 @@ in
|
||||
};
|
||||
|
||||
regenCerts = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = lib.mdDoc ''
|
||||
Set to false to turn off automatic regeneration of expired certificates.
|
||||
@@ -120,76 +114,54 @@ in
|
||||
};
|
||||
|
||||
certLifetime = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = lib.mdDoc ''
|
||||
How long certs generated by Stargazer should live for.
|
||||
Certs live forever by default.
|
||||
'';
|
||||
example = lib.literalExpression "\"1y\"";
|
||||
example = literalExpression "\"1y\"";
|
||||
};
|
||||
|
||||
routes = lib.mkOption {
|
||||
type = lib.types.listOf
|
||||
(lib.types.submodule {
|
||||
freeformType = with lib.types; attrsOf (nullOr
|
||||
(oneOf [
|
||||
bool
|
||||
int
|
||||
float
|
||||
str
|
||||
]) // {
|
||||
description = "INI atom (null, bool, int, float or string)";
|
||||
});
|
||||
options.route = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc "Route section name";
|
||||
};
|
||||
});
|
||||
default = [ ];
|
||||
type = routesFormat.type;
|
||||
default = { };
|
||||
description = lib.mdDoc ''
|
||||
Routes that Stargazer should server.
|
||||
|
||||
Expressed as a list of attribute sets. Each set must have a key `route`
|
||||
that becomes the section name for that route in the stargazer ini cofig.
|
||||
The remaining keys and vaules become the parameters for that route.
|
||||
|
||||
[Refer to upstream docs for other params](https://git.sr.ht/~zethra/stargazer/tree/main/item/doc/stargazer.ini.5.txt)
|
||||
[Refer to upstream docs](https://git.sr.ht/~zethra/stargazer/tree/main/item/doc/stargazer.ini.5.txt)
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
[
|
||||
{
|
||||
route = "example.com";
|
||||
root = "/srv/gemini/example.com"
|
||||
}
|
||||
{
|
||||
route = "example.com:/man";
|
||||
example = literalExpression ''
|
||||
{
|
||||
"example.com" = {
|
||||
root = "/srv/gemini/example.com";
|
||||
};
|
||||
"example.com:/man" = {
|
||||
root = "/cgi-bin";
|
||||
cgi = true;
|
||||
}
|
||||
{
|
||||
route = "other.org~(.*)";
|
||||
};
|
||||
"other.org~(.*)" = {
|
||||
redirect = "gemini://example.com";
|
||||
rewrite = "\1";
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "stargazer";
|
||||
description = lib.mdDoc "User account under which stargazer runs.";
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "stargazer";
|
||||
description = lib.mdDoc "Group account under which stargazer runs.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.stargazer = {
|
||||
description = "Stargazer gemini server";
|
||||
after = [ "network.target" ];
|
||||
@@ -205,19 +177,19 @@ in
|
||||
|
||||
# Create default cert store
|
||||
system.activationScripts.makeStargazerCertDir =
|
||||
lib.optionalAttrs (cfg.store == /var/lib/gemini/certs) ''
|
||||
optionalAttrs (cfg.store == /var/lib/gemini/certs) ''
|
||||
mkdir -p /var/lib/gemini/certs
|
||||
chown -R ${cfg.user}:${cfg.group} /var/lib/gemini/certs
|
||||
'';
|
||||
|
||||
users.users = lib.optionalAttrs (cfg.user == "stargazer") {
|
||||
users.users = optionalAttrs (cfg.user == "stargazer") {
|
||||
stargazer = {
|
||||
group = cfg.group;
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = lib.optionalAttrs (cfg.group == "stargazer") {
|
||||
users.groups = optionalAttrs (cfg.group == "stargazer") {
|
||||
stargazer = { };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
xcfg = config.services.xserver;
|
||||
cfg = xcfg.desktopManager.deepin;
|
||||
|
||||
nixos-gsettings-overrides = pkgs.deepin.dde-gsettings-schemas.override {
|
||||
extraGSettingsOverridePackages = cfg.extraGSettingsOverridePackages;
|
||||
extraGSettingsOverrides = cfg.extraGSettingsOverrides;
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
|
||||
services.xserver.desktopManager.deepin = {
|
||||
enable = mkEnableOption (lib.mdDoc "Enable Deepin desktop manager");
|
||||
extraGSettingsOverrides = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
description = lib.mdDoc "Additional gsettings overrides.";
|
||||
};
|
||||
extraGSettingsOverridePackages = mkOption {
|
||||
default = [ ];
|
||||
type = types.listOf types.path;
|
||||
description = lib.mdDoc "List of packages for which gsettings are overridden.";
|
||||
};
|
||||
};
|
||||
|
||||
environment.deepin.excludePackages = mkOption {
|
||||
default = [ ];
|
||||
type = types.listOf types.package;
|
||||
description = lib.mdDoc "List of default packages to exclude from the configuration";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable
|
||||
{
|
||||
services.xserver.displayManager.sessionPackages = [ pkgs.deepin.startdde ];
|
||||
services.xserver.displayManager.defaultSession = mkDefault "deepin";
|
||||
|
||||
# Update the DBus activation environment after launching the desktop manager.
|
||||
services.xserver.displayManager.sessionCommands = ''
|
||||
${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
|
||||
'';
|
||||
|
||||
hardware.bluetooth.enable = mkDefault true;
|
||||
hardware.pulseaudio.enable = mkDefault true;
|
||||
security.polkit.enable = true;
|
||||
|
||||
services.deepin.dde-daemon.enable = mkForce true;
|
||||
services.deepin.dde-api.enable = mkForce true;
|
||||
services.deepin.app-services.enable = mkForce true;
|
||||
|
||||
services.colord.enable = mkDefault true;
|
||||
services.accounts-daemon.enable = mkDefault true;
|
||||
services.gvfs.enable = mkDefault true;
|
||||
services.gnome.glib-networking.enable = mkDefault true;
|
||||
services.gnome.gnome-keyring.enable = mkDefault true;
|
||||
services.bamf.enable = mkDefault true;
|
||||
|
||||
services.xserver.libinput.enable = mkDefault true;
|
||||
services.udisks2.enable = true;
|
||||
services.upower.enable = mkDefault config.powerManagement.enable;
|
||||
networking.networkmanager.enable = mkDefault true;
|
||||
programs.dconf.enable = mkDefault true;
|
||||
|
||||
fonts.fonts = with pkgs; [ noto-fonts ];
|
||||
xdg.mime.enable = true;
|
||||
xdg.menus.enable = true;
|
||||
xdg.icons.enable = true;
|
||||
xdg.portal.enable = mkDefault true;
|
||||
xdg.portal.extraPortals = mkDefault [
|
||||
(pkgs.xdg-desktop-portal-gtk.override {
|
||||
buildPortalsInGnome = false;
|
||||
})
|
||||
];
|
||||
|
||||
environment.sessionVariables = {
|
||||
NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-overrides}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
|
||||
DDE_POLKIT_AGENT_PLUGINS_DIRS = [ "${pkgs.deepin.dpa-ext-gnomekeyring}/lib/polkit-1-dde/plugins" ];
|
||||
};
|
||||
|
||||
environment.pathsToLink = [
|
||||
"/lib/dde-dock/plugins"
|
||||
"/lib/dde-control-center"
|
||||
"/lib/dde-session-shell"
|
||||
"/lib/dde-file-manager"
|
||||
"/share/backgrounds"
|
||||
"/share/wallpapers"
|
||||
];
|
||||
|
||||
environment.etc = {
|
||||
"distribution.info".text = ''
|
||||
[Distribution]
|
||||
Name=NixOS
|
||||
WebsiteName=www.nixos.org
|
||||
Website=https://www.nixos.org
|
||||
Logo=${pkgs.nixos-icons}/share/icons/hicolor/96x96/apps/nix-snowflake.png
|
||||
LogoLight=${pkgs.nixos-icons}/share/icons/hicolor/32x32/apps/nix-snowflake.png
|
||||
LogoTransparent=${pkgs.deepin.deepin-desktop-base}/share/pixmaps/distribution_logo_transparent.svg
|
||||
'';
|
||||
"deepin-installer.conf".text = ''
|
||||
system_info_vendor_name="Copyright (c) 2003-2023 NixOS contributors"
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/AccountsService 0775 root root - -"
|
||||
"C /var/lib/AccountsService/icons 0775 root root - ${pkgs.deepin.dde-account-faces}/var/lib/AccountsService/icons"
|
||||
];
|
||||
|
||||
security.pam.services.dde-lock.text = ''
|
||||
# original at {dde-session-shell}/etc/pam.d/dde-lock
|
||||
auth substack login
|
||||
account include login
|
||||
password substack login
|
||||
session include login
|
||||
'';
|
||||
|
||||
environment.systemPackages = with pkgs; with deepin;
|
||||
let
|
||||
requiredPackages = [
|
||||
pciutils # for dtkcore/startdde
|
||||
xdotool # for dde-daemon
|
||||
glib # for gsettings program / gdbus
|
||||
gtk3 # for gtk-launch program
|
||||
xdg-user-dirs # Update user dirs
|
||||
util-linux # runuser
|
||||
polkit_gnome
|
||||
librsvg # dde-api use rsvg-convert
|
||||
lshw # for dtkcore
|
||||
libsForQt5.kde-gtk-config # deepin-api/gtk-thumbnailer need
|
||||
libsForQt5.kglobalaccel
|
||||
xsettingsd # lightdm-deepin-greeter
|
||||
qt5platform-plugins
|
||||
deepin-pw-check
|
||||
deepin-turbo
|
||||
|
||||
dde-account-faces
|
||||
deepin-icon-theme
|
||||
deepin-sound-theme
|
||||
deepin-gtk-theme
|
||||
deepin-wallpapers
|
||||
|
||||
startdde
|
||||
dde-dock
|
||||
dde-launcher
|
||||
dde-session-ui
|
||||
dde-session-shell
|
||||
dde-file-manager
|
||||
dde-control-center
|
||||
dde-network-core
|
||||
dde-clipboard
|
||||
dde-calendar
|
||||
dde-polkit-agent
|
||||
dpa-ext-gnomekeyring
|
||||
deepin-desktop-schemas
|
||||
deepin-terminal
|
||||
dde-kwin
|
||||
deepin-kwin
|
||||
];
|
||||
optionalPackages = [
|
||||
onboard # dde-dock plugin
|
||||
deepin-camera
|
||||
deepin-calculator
|
||||
deepin-compressor
|
||||
deepin-editor
|
||||
deepin-picker
|
||||
deepin-draw
|
||||
deepin-album
|
||||
deepin-image-viewer
|
||||
deepin-music
|
||||
deepin-movie-reborn
|
||||
deepin-system-monitor
|
||||
deepin-screen-recorder
|
||||
deepin-shortcut-viewer
|
||||
];
|
||||
in
|
||||
requiredPackages
|
||||
++ utils.removePackagesByName optionalPackages config.environment.deepin.excludePackages;
|
||||
|
||||
services.dbus.packages = with pkgs.deepin; [
|
||||
dde-dock
|
||||
dde-launcher
|
||||
dde-session-ui
|
||||
dde-session-shell
|
||||
dde-file-manager
|
||||
dde-control-center
|
||||
dde-calendar
|
||||
dde-clipboard
|
||||
dde-kwin
|
||||
deepin-kwin
|
||||
deepin-pw-check
|
||||
];
|
||||
|
||||
systemd.packages = with pkgs.deepin; [
|
||||
dde-launcher
|
||||
dde-file-manager
|
||||
dde-calendar
|
||||
dde-clipboard
|
||||
deepin-kwin
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ in
|
||||
./none.nix ./xterm.nix ./phosh.nix ./xfce.nix ./plasma5.nix ./lumina.nix
|
||||
./lxqt.nix ./enlightenment.nix ./gnome.nix ./retroarch.nix ./kodi.nix
|
||||
./mate.nix ./pantheon.nix ./surf-display.nix ./cde.nix
|
||||
./cinnamon.nix ./budgie.nix ./deepin.nix
|
||||
./cinnamon.nix ./budgie.nix
|
||||
];
|
||||
|
||||
options = {
|
||||
|
||||
@@ -121,7 +121,7 @@ let
|
||||
fi
|
||||
done
|
||||
|
||||
for i in $(find ${toString cfg.modules} -type d | sort); do
|
||||
for i in $(find ${toString cfg.modules} -type d); do
|
||||
if test $(echo $i/*.so* | wc -w) -ne 0; then
|
||||
echo " ModulePath \"$i\"" >> $out
|
||||
fi
|
||||
|
||||
@@ -40,7 +40,7 @@ let
|
||||
# This can only be done here because we *cannot* depend on $out
|
||||
# referring to the toplevel, except by living in the toplevel itself.
|
||||
toplevelInjector = lib.escapeShellArgs [
|
||||
"${pkgs.buildPackages.jq}/bin/jq"
|
||||
"${pkgs.jq}/bin/jq"
|
||||
''
|
||||
."org.nixos.bootspec.v1".toplevel = $toplevel |
|
||||
."org.nixos.bootspec.v1".init = $init
|
||||
@@ -60,7 +60,7 @@ let
|
||||
children);
|
||||
in
|
||||
lib.escapeShellArgs [
|
||||
"${pkgs.buildPackages.jq}/bin/jq"
|
||||
"${pkgs.jq}/bin/jq"
|
||||
"--sort-keys"
|
||||
''."org.nixos.specialisation.v1" = ($ARGS.named | map_values(. | first))''
|
||||
] + " ${lib.concatStringsSep " " specialisationLoader}";
|
||||
|
||||
@@ -34,29 +34,23 @@ sub getList {
|
||||
}
|
||||
|
||||
sub readFile {
|
||||
my ($fn) = @_;
|
||||
# enable slurp mode: read entire file in one go
|
||||
local $/ = undef;
|
||||
open my $fh, "<$fn" or return undef;
|
||||
my $s = <$fh>;
|
||||
close $fh;
|
||||
# disable slurp mode
|
||||
local $/ = "\n";
|
||||
chomp $s;
|
||||
return $s;
|
||||
my ($fn) = @_; local $/ = undef;
|
||||
open FILE, "<$fn" or return undef; my $s = <FILE>; close FILE;
|
||||
local $/ = "\n"; chomp $s; return $s;
|
||||
}
|
||||
|
||||
sub writeFile {
|
||||
my ($fn, $s) = @_;
|
||||
open my $fh, ">$fn" or die "cannot create $fn: $!\n";
|
||||
print $fh $s or die "cannot write to $fn: $!\n";
|
||||
close $fh or die "cannot close $fn: $!\n";
|
||||
open FILE, ">$fn" or die "cannot create $fn: $!\n";
|
||||
print FILE $s or die;
|
||||
close FILE or die;
|
||||
}
|
||||
|
||||
sub runCommand {
|
||||
open(my $fh, "-|", @_) or die "Failed to execute: $@_\n";
|
||||
my @ret = $fh->getlines();
|
||||
close $fh;
|
||||
my ($cmd) = @_;
|
||||
open FILE, "$cmd 2>/dev/null |" or die "Failed to execute: $cmd\n";
|
||||
my @ret = <FILE>;
|
||||
close FILE;
|
||||
return ($?, @ret);
|
||||
}
|
||||
|
||||
@@ -206,7 +200,7 @@ sub GrubFs {
|
||||
$search = $types{$fsIdentifier} . ' ';
|
||||
|
||||
# Based on the type pull in the identifier from the system
|
||||
my ($status, @devInfo) = runCommand("@utillinux@/bin/blkid", "-o", "export", @{[$fs->device]});
|
||||
my ($status, @devInfo) = runCommand("@utillinux@/bin/blkid -o export @{[$fs->device]}");
|
||||
if ($status != 0) {
|
||||
die "Failed to get blkid info (returned $status) for @{[$fs->mount]} on @{[$fs->device]}";
|
||||
}
|
||||
@@ -219,7 +213,7 @@ sub GrubFs {
|
||||
|
||||
# BTRFS is a special case in that we need to fix the referrenced path based on subvolumes
|
||||
if ($fs->type eq 'btrfs') {
|
||||
my ($status, @id_info) = runCommand("@btrfsprogs@/bin/btrfs", "subvol", "show", @{[$fs->mount]});
|
||||
my ($status, @id_info) = runCommand("@btrfsprogs@/bin/btrfs subvol show @{[$fs->mount]}");
|
||||
if ($status != 0) {
|
||||
die "Failed to retrieve subvolume info for @{[$fs->mount]}\n";
|
||||
}
|
||||
@@ -227,7 +221,7 @@ sub GrubFs {
|
||||
if ($#ids > 0) {
|
||||
die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
|
||||
} elsif ($#ids == 0) {
|
||||
my ($status, @path_info) = runCommand("@btrfsprogs@/bin/btrfs", "subvol", "list", @{[$fs->mount]});
|
||||
my ($status, @path_info) = runCommand("@btrfsprogs@/bin/btrfs subvol list @{[$fs->mount]}");
|
||||
if ($status != 0) {
|
||||
die "Failed to find @{[$fs->mount]} subvolume id from btrfs\n";
|
||||
}
|
||||
|
||||
@@ -2383,7 +2383,7 @@ let
|
||||
bridgeVLANConfig = mkOption {
|
||||
default = {};
|
||||
example = { VLAN = "10-20"; };
|
||||
type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeVLAN;
|
||||
type = types.addCheck (types.attrsOf unitOption) check.network.sectionbridgeVLAN;
|
||||
description = lib.mdDoc ''
|
||||
Each attribute in this set specifies an option in the
|
||||
`[BridgeVLAN]` section of the unit. See
|
||||
|
||||
@@ -410,11 +410,6 @@ mountFS() {
|
||||
n=$((n + 1))
|
||||
done
|
||||
|
||||
# For bind mounts, busybox has a tendency to ignore options, which can be a
|
||||
# security issue (e.g. "nosuid"). Remounting the partition seems to fix the
|
||||
# issue.
|
||||
mount "/mnt-root$mountPoint" -o "remount,$optionsPrefixed"
|
||||
|
||||
[ "$mountPoint" == "/" ] &&
|
||||
[ -f "/mnt-root/etc/NIXOS_LUSTRATE" ] &&
|
||||
lustrateRoot "/mnt-root"
|
||||
|
||||
@@ -130,7 +130,7 @@ let
|
||||
${concatStringsSep " \\\n" ([ "-f qcow2" ]
|
||||
++ optional (cfg.useBootLoader && cfg.useDefaultFilesystems) "-F qcow2 -b ${systemImage}/nixos.qcow2"
|
||||
++ optional (!(cfg.useBootLoader && cfg.useDefaultFilesystems)) "-o size=${toString config.virtualisation.diskSize}M"
|
||||
++ [ ''"$NIX_DISK_IMAGE"'' ])}
|
||||
++ [ "$NIX_DISK_IMAGE" ])}
|
||||
echo "Virtualisation disk image created."
|
||||
fi
|
||||
|
||||
@@ -169,26 +169,18 @@ let
|
||||
# Create a directory for exchanging data with the VM.
|
||||
mkdir -p "$TMPDIR/xchg"
|
||||
|
||||
${lib.optionalString cfg.useEFIBoot
|
||||
${lib.optionalString cfg.useBootLoader
|
||||
''
|
||||
# Expose EFI variables, it's useful even when we are not using a bootloader (!).
|
||||
# We might be interested in having EFI variable storage present even if we aren't booting via UEFI, hence
|
||||
# no guard against `useBootLoader`. Examples:
|
||||
# - testing PXE boot or other EFI applications
|
||||
# - directbooting LinuxBoot, which `kexec()s` into a UEFI environment that can boot e.g. Windows
|
||||
NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${config.system.name}-efi-vars.fd}")
|
||||
# VM needs writable EFI vars
|
||||
if ! test -e "$NIX_EFI_VARS"; then
|
||||
${if cfg.useBootLoader then
|
||||
# We still need the EFI var from the make-disk-image derivation
|
||||
# because our "switch-to-configuration" process might
|
||||
# write into it and we want to keep this data.
|
||||
''cp ${systemImage}/efi-vars.fd "$NIX_EFI_VARS"''
|
||||
else
|
||||
''cp ${cfg.efi.variables} "$NIX_EFI_VARS"''
|
||||
}
|
||||
chmod 0644 "$NIX_EFI_VARS"
|
||||
fi
|
||||
|
||||
${lib.optionalString cfg.useEFIBoot
|
||||
''
|
||||
# VM needs writable EFI vars
|
||||
if ! test -e "$NIX_EFI_VARS"; then
|
||||
cp ${systemImage}/efi-vars.fd "$NIX_EFI_VARS"
|
||||
chmod 0644 "$NIX_EFI_VARS"
|
||||
fi
|
||||
''}
|
||||
''}
|
||||
|
||||
cd "$TMPDIR"
|
||||
@@ -804,6 +796,42 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.tpm = {
|
||||
enable = mkEnableOption ''a TPM device in the virtual machine with a driver, using swtpm.
|
||||
|
||||
To use it in a `test_script`, you can use `machine.tpm` which is a TPM driver offering some basic
|
||||
facilities to manipulate the TPM socket on the host.
|
||||
'';
|
||||
|
||||
package = mkPackageOptionMD cfg.host.pkgs "swtpm" { };
|
||||
|
||||
socketPath = mkOption {
|
||||
type = types.str;
|
||||
default = "/tmp/swtpm-sock";
|
||||
description = lib.mdDoc "swtpm socket path on the host";
|
||||
};
|
||||
|
||||
deviceModel = mkOption {
|
||||
type = types.str;
|
||||
default = ({
|
||||
"i686-linux" = "tpm-tis";
|
||||
"x86_64-linux" = "tpm-tis";
|
||||
"ppc64-linux" = "tpm-spapr";
|
||||
"armv7-linux" = "tpm-tis-device";
|
||||
"aarch64-linux" = "tpm-tis-device";
|
||||
}.${pkgs.hostPlatform.system});
|
||||
defaultText = ''({
|
||||
"i686-linux" = "tpm-tis";
|
||||
"x86_64-linux" = "tpm-tis";
|
||||
"ppc64-linux" = "tpm-spapr";
|
||||
"armv7-linux" = "tpm-tis-device";
|
||||
"aarch64-linux" = "tpm-tis-device";
|
||||
}.''${pkgs.hostPlatform.system})'';
|
||||
example = "tpm-tis-device";
|
||||
description = lib.mdDoc "QEMU device model for the TPM, uses the appropriate default based on the system and the package passed.";
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.useDefaultFilesystems =
|
||||
mkOption {
|
||||
type = types.bool;
|
||||
@@ -954,7 +982,8 @@ in
|
||||
|
||||
boot.initrd.availableKernelModules =
|
||||
optional cfg.writableStore "overlay"
|
||||
++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx";
|
||||
++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
|
||||
++ optional (cfg.tpm.enable) "tpm_tis";
|
||||
|
||||
virtualisation.additionalPaths = [ config.system.build.toplevel ];
|
||||
|
||||
@@ -1020,6 +1049,11 @@ in
|
||||
(mkIf (!cfg.graphics) [
|
||||
"-nographic"
|
||||
])
|
||||
(mkIf (cfg.tpm.enable) [
|
||||
"-chardev socket,id=chrtpm,path=${cfg.tpm.socketPath}"
|
||||
"-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm"
|
||||
"-device ${cfg.tpm.deviceModel},tpmdev=tpm_dev_0"
|
||||
])
|
||||
];
|
||||
|
||||
virtualisation.qemu.drives = mkMerge [
|
||||
|
||||
@@ -46,7 +46,7 @@ let
|
||||
inherit
|
||||
(rec {
|
||||
doRunTest = arg: ((import ../lib/testing-python.nix { inherit system pkgs; }).evalTest {
|
||||
imports = [ arg readOnlyPkgs ];
|
||||
imports = [ arg ];
|
||||
}).config.result;
|
||||
findTests = tree:
|
||||
if tree?recurseForDerivations && tree.recurseForDerivations
|
||||
@@ -65,36 +65,10 @@ let
|
||||
runTestOn
|
||||
;
|
||||
|
||||
# Using a single instance of nixpkgs makes test evaluation faster.
|
||||
# To make sure we don't accidentally depend on a modified pkgs, we make the
|
||||
# related options read-only. We need to test the right configuration.
|
||||
#
|
||||
# If your service depends on a nixpkgs setting, first try to avoid that, but
|
||||
# otherwise, you can remove the readOnlyPkgs import and test your service as
|
||||
# usual.
|
||||
readOnlyPkgs =
|
||||
# TODO: We currently accept this for nixosTests, so that the `pkgs` argument
|
||||
# is consistent with `pkgs` in `pkgs.nixosTests`. Can we reinitialize
|
||||
# it with `allowAliases = false`?
|
||||
# warnIf pkgs.config.allowAliases "nixosTests: pkgs includes aliases."
|
||||
{
|
||||
_class = "nixosTest";
|
||||
node.pkgs = pkgs;
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
# Testing the test driver
|
||||
nixos-test-driver = {
|
||||
extra-python-packages = handleTest ./nixos-test-driver/extra-python-packages.nix {};
|
||||
node-name = runTest ./nixos-test-driver/node-name.nix;
|
||||
};
|
||||
|
||||
# NixOS vm tests and non-vm unit tests
|
||||
|
||||
_3proxy = runTest ./3proxy.nix;
|
||||
aaaaxy = runTest ./aaaaxy.nix;
|
||||
acme = runTest { imports = [ ./acme.nix ]; };
|
||||
acme = runTest ./acme.nix;
|
||||
adguardhome = runTest ./adguardhome.nix;
|
||||
aesmd = runTestOn ["x86_64-linux"] ./aesmd.nix;
|
||||
agate = runTest ./web-servers/agate.nix;
|
||||
@@ -172,7 +146,6 @@ in {
|
||||
collectd = handleTest ./collectd.nix {};
|
||||
connman = handleTest ./connman.nix {};
|
||||
consul = handleTest ./consul.nix {};
|
||||
consul-template = handleTest ./consul-template.nix {};
|
||||
containers-bridge = handleTest ./containers-bridge.nix {};
|
||||
containers-custom-pkgs.nix = handleTest ./containers-custom-pkgs.nix {};
|
||||
containers-ephemeral = handleTest ./containers-ephemeral.nix {};
|
||||
@@ -197,7 +170,6 @@ in {
|
||||
cups-pdf = handleTest ./cups-pdf.nix {};
|
||||
custom-ca = handleTest ./custom-ca.nix {};
|
||||
croc = handleTest ./croc.nix {};
|
||||
deepin = handleTest ./deepin.nix {};
|
||||
deluge = handleTest ./deluge.nix {};
|
||||
dendrite = handleTest ./matrix/dendrite.nix {};
|
||||
dex-oidc = handleTest ./dex-oidc.nix {};
|
||||
@@ -223,7 +195,6 @@ in {
|
||||
dovecot = handleTest ./dovecot.nix {};
|
||||
drbd = handleTest ./drbd.nix {};
|
||||
earlyoom = handleTestOn ["x86_64-linux"] ./earlyoom.nix {};
|
||||
early-mount-options = handleTest ./early-mount-options.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 {};
|
||||
@@ -247,6 +218,7 @@ in {
|
||||
etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {};
|
||||
etebase-server = handleTest ./etebase-server.nix {};
|
||||
etesync-dav = handleTest ./etesync-dav.nix {};
|
||||
extra-python-packages = handleTest ./extra-python-packages.nix {};
|
||||
evcc = handleTest ./evcc.nix {};
|
||||
fancontrol = handleTest ./fancontrol.nix {};
|
||||
fcitx5 = handleTest ./fcitx5 {};
|
||||
@@ -369,7 +341,6 @@ in {
|
||||
kafka = handleTest ./kafka.nix {};
|
||||
kanidm = handleTest ./kanidm.nix {};
|
||||
karma = handleTest ./karma.nix {};
|
||||
kavita = handleTest ./kavita.nix {};
|
||||
kbd-setfont-decompress = handleTest ./kbd-setfont-decompress.nix {};
|
||||
kbd-update-search-paths-patch = handleTest ./kbd-update-search-paths-patch.nix {};
|
||||
kea = handleTest ./kea.nix {};
|
||||
@@ -420,7 +391,7 @@ in {
|
||||
lxd-image-server = handleTest ./lxd-image-server.nix {};
|
||||
#logstash = handleTest ./logstash.nix {};
|
||||
lorri = handleTest ./lorri/default.nix {};
|
||||
maddy = discoverTests (import ./maddy { inherit handleTest; });
|
||||
maddy = handleTest ./maddy.nix {};
|
||||
maestral = handleTest ./maestral.nix {};
|
||||
magic-wormhole-mailbox-server = handleTest ./magic-wormhole-mailbox-server.nix {};
|
||||
magnetico = handleTest ./magnetico.nix {};
|
||||
@@ -782,7 +753,6 @@ in {
|
||||
varnish60 = handleTest ./varnish.nix { package = pkgs.varnish60; };
|
||||
varnish72 = handleTest ./varnish.nix { package = pkgs.varnish72; };
|
||||
vault = handleTest ./vault.nix {};
|
||||
vault-agent = handleTest ./vault-agent.nix {};
|
||||
vault-dev = handleTest ./vault-dev.nix {};
|
||||
vault-postgresql = handleTest ./vault-postgresql.nix {};
|
||||
vaultwarden = handleTest ./vaultwarden.nix {};
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import ./make-test-python.nix ({ ... }: {
|
||||
name = "consul-template";
|
||||
|
||||
nodes.machine = { ... }: {
|
||||
services.consul-template.instances.example.settings = {
|
||||
template = [{
|
||||
contents = ''
|
||||
{{ key "example" }}
|
||||
'';
|
||||
perms = "0600";
|
||||
destination = "/example";
|
||||
}];
|
||||
};
|
||||
|
||||
services.consul = {
|
||||
enable = true;
|
||||
extraConfig = {
|
||||
server = true;
|
||||
bootstrap_expect = 1;
|
||||
bind_addr = "127.0.0.1";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("consul.service")
|
||||
machine.wait_for_open_port(8500)
|
||||
|
||||
machine.wait_for_unit("consul-template-example.service")
|
||||
|
||||
machine.wait_until_succeeds('consul kv put example example')
|
||||
|
||||
machine.wait_for_file("/example")
|
||||
machine.succeed('grep "example" /example')
|
||||
'';
|
||||
})
|
||||
@@ -1,57 +0,0 @@
|
||||
import ./make-test-python.nix ({ pkgs, lib, ... }: {
|
||||
name = "deepin";
|
||||
|
||||
meta = with lib; {
|
||||
maintainers = teams.deepin.members;
|
||||
};
|
||||
|
||||
nodes.machine = { ... }: {
|
||||
imports = [
|
||||
./common/user-account.nix
|
||||
];
|
||||
|
||||
services.xserver.enable = true;
|
||||
|
||||
services.xserver.displayManager = {
|
||||
lightdm.enable = true;
|
||||
autoLogin = {
|
||||
enable = true;
|
||||
user = "alice";
|
||||
};
|
||||
};
|
||||
|
||||
services.xserver.desktopManager.deepin.enable = true;
|
||||
};
|
||||
|
||||
testScript = { nodes, ... }:
|
||||
let
|
||||
user = nodes.machine.users.users.alice;
|
||||
in
|
||||
''
|
||||
with subtest("Wait for login"):
|
||||
machine.wait_for_x()
|
||||
machine.wait_for_file("${user.home}/.Xauthority")
|
||||
machine.succeed("xauth merge ${user.home}/.Xauthority")
|
||||
|
||||
with subtest("Check that logging in has given the user ownership of devices"):
|
||||
machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}")
|
||||
|
||||
with subtest("Check if DDE wm chooser actually start"):
|
||||
machine.wait_until_succeeds("pgrep -f dde-wm-chooser")
|
||||
machine.wait_for_window("dde-wm-chooser")
|
||||
machine.execute("pkill dde-wm-chooser")
|
||||
|
||||
|
||||
with subtest("Check if Deepin session components actually start"):
|
||||
machine.wait_until_succeeds("pgrep -f dde-session-daemon")
|
||||
machine.wait_for_window("dde-session-daemon")
|
||||
machine.wait_until_succeeds("pgrep -f dde-desktop")
|
||||
machine.wait_for_window("dde-desktop")
|
||||
|
||||
with subtest("Open deepin-terminal"):
|
||||
machine.succeed("su - ${user.name} -c 'DISPLAY=:0 deepin-terminal >&2 &'")
|
||||
machine.wait_for_window("deepin-terminal")
|
||||
machine.sleep(20)
|
||||
machine.screenshot("screen")
|
||||
'';
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
# Test for https://github.com/NixOS/nixpkgs/pull/193469
|
||||
import ./make-test-python.nix {
|
||||
name = "early-mount-options";
|
||||
|
||||
nodes.machine = {
|
||||
virtualisation.fileSystems."/var" = {
|
||||
options = [ "bind" "nosuid" "nodev" "noexec" ];
|
||||
device = "/var";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
var_mount_info = machine.succeed("findmnt /var -n -o OPTIONS")
|
||||
options = var_mount_info.strip().split(",")
|
||||
assert "nosuid" in options and "nodev" in options and "noexec" in options
|
||||
'';
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import ../make-test-python.nix ({ ... }:
|
||||
import ./make-test-python.nix ({ ... }:
|
||||
{
|
||||
name = "extra-python-packages";
|
||||
|
||||
@@ -345,7 +345,6 @@ let
|
||||
(docbook-xsl-ns.override {
|
||||
withManOptDedupPatch = true;
|
||||
})
|
||||
kbd.dev
|
||||
kmod.dev
|
||||
libarchive.dev
|
||||
libxml2.bin
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import ./make-test-python.nix ({ pkgs, ...} : {
|
||||
name = "kavita";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ misterio77 ];
|
||||
};
|
||||
|
||||
nodes = {
|
||||
kavita = { config, pkgs, ... }: {
|
||||
services.kavita = {
|
||||
enable = true;
|
||||
port = 5000;
|
||||
tokenKeyFile = builtins.toFile "kavita.key" "QfpjFvjT83BLtZ74GE3U3Q==";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = let
|
||||
regUrl = "http://kavita:5000/api/Account/register";
|
||||
payload = builtins.toFile "payload.json" (builtins.toJSON {
|
||||
username = "foo";
|
||||
password = "correcthorsebatterystaple";
|
||||
email = "foo@bar";
|
||||
});
|
||||
in ''
|
||||
kavita.start
|
||||
kavita.wait_for_unit("kavita.service")
|
||||
|
||||
# Check that static assets are working
|
||||
kavita.wait_until_succeeds("curl http://kavita:5000/site.webmanifest | grep Kavita")
|
||||
|
||||
# Check that registration is working
|
||||
kavita.succeed("curl -fX POST ${regUrl} --json @${payload}")
|
||||
# But only for the first one
|
||||
kavita.fail("curl -fX POST ${regUrl} --json @${payload}")
|
||||
'';
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import ../make-test-python.nix ({ pkgs, ... }: {
|
||||
name = "maddy-unencrypted";
|
||||
import ./make-test-python.nix ({ pkgs, ... }: {
|
||||
name = "maddy";
|
||||
meta = with pkgs.lib.maintainers; { maintainers = [ onny ]; };
|
||||
|
||||
nodes = {
|
||||
@@ -1,6 +0,0 @@
|
||||
{ handleTest }:
|
||||
|
||||
{
|
||||
unencrypted = handleTest ./unencrypted.nix { };
|
||||
tls = handleTest ./tls.nix { };
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import ../make-test-python.nix ({ pkgs, ... }:
|
||||
let
|
||||
certs = import ../common/acme/server/snakeoil-certs.nix;
|
||||
domain = certs.domain;
|
||||
in {
|
||||
name = "maddy-tls";
|
||||
meta = with pkgs.lib.maintainers; { maintainers = [ onny ]; };
|
||||
|
||||
nodes = {
|
||||
server = { options, ... }: {
|
||||
services.maddy = {
|
||||
enable = true;
|
||||
hostname = domain;
|
||||
primaryDomain = domain;
|
||||
openFirewall = true;
|
||||
ensureAccounts = [ "postmaster@${domain}" ];
|
||||
ensureCredentials = {
|
||||
# Do not use this in production. This will make passwords world-readable
|
||||
# in the Nix store
|
||||
"postmaster@${domain}".passwordFile = "${pkgs.writeText "postmaster" "test"}";
|
||||
};
|
||||
tls = {
|
||||
loader = "file";
|
||||
certificates = [{
|
||||
certPath = "${certs.${domain}.cert}";
|
||||
keyPath = "${certs.${domain}.key}";
|
||||
}];
|
||||
};
|
||||
# Enable TLS listeners. Configuring this via the module is not yet
|
||||
# implemented.
|
||||
config = builtins.replaceStrings [
|
||||
"imap tcp://0.0.0.0:143"
|
||||
"submission tcp://0.0.0.0:587"
|
||||
] [
|
||||
"imap tls://0.0.0.0:993 tcp://0.0.0.0:143"
|
||||
"submission tls://0.0.0.0:465 tcp://0.0.0.0:587"
|
||||
] options.services.maddy.config.default;
|
||||
};
|
||||
# Not covered by openFirewall yet
|
||||
networking.firewall.allowedTCPPorts = [ 993 465 ];
|
||||
};
|
||||
|
||||
client = { nodes, ... }: {
|
||||
security.pki.certificateFiles = [
|
||||
certs.ca.cert
|
||||
];
|
||||
networking.extraHosts = ''
|
||||
${nodes.server.networking.primaryIPAddress} ${domain}
|
||||
'';
|
||||
environment.systemPackages = [
|
||||
(pkgs.writers.writePython3Bin "send-testmail" { } ''
|
||||
import smtplib
|
||||
import ssl
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
context = ssl.create_default_context()
|
||||
msg = MIMEText("Hello World")
|
||||
msg['Subject'] = 'Test'
|
||||
msg['From'] = "postmaster@${domain}"
|
||||
msg['To'] = "postmaster@${domain}"
|
||||
with smtplib.SMTP_SSL(host='${domain}', port=465, context=context) as smtp:
|
||||
smtp.login('postmaster@${domain}', 'test')
|
||||
smtp.sendmail(
|
||||
'postmaster@${domain}', 'postmaster@${domain}', msg.as_string()
|
||||
)
|
||||
'')
|
||||
(pkgs.writers.writePython3Bin "test-imap" { } ''
|
||||
import imaplib
|
||||
|
||||
with imaplib.IMAP4_SSL('${domain}') as imap:
|
||||
imap.login('postmaster@${domain}', 'test')
|
||||
imap.select()
|
||||
status, refs = imap.search(None, 'ALL')
|
||||
assert status == 'OK'
|
||||
assert len(refs) == 1
|
||||
status, msg = imap.fetch(refs[0], 'BODY[TEXT]')
|
||||
assert status == 'OK'
|
||||
assert msg[0][1].strip() == b"Hello World"
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
server.wait_for_unit("maddy.service")
|
||||
server.wait_for_open_port(143)
|
||||
server.wait_for_open_port(993)
|
||||
server.wait_for_open_port(587)
|
||||
server.wait_for_open_port(465)
|
||||
client.succeed("send-testmail")
|
||||
client.succeed("test-imap")
|
||||
'';
|
||||
})
|
||||
@@ -7,8 +7,8 @@
|
||||
let
|
||||
shared = {
|
||||
services.mediawiki.enable = true;
|
||||
services.mediawiki.httpd.virtualHost.hostName = "localhost";
|
||||
services.mediawiki.httpd.virtualHost.adminAddr = "root@example.com";
|
||||
services.mediawiki.virtualHost.hostName = "localhost";
|
||||
services.mediawiki.virtualHost.adminAddr = "root@example.com";
|
||||
services.mediawiki.passwordFile = pkgs.writeText "password" "correcthorsebatterystaple";
|
||||
services.mediawiki.extensions = {
|
||||
Matomo = pkgs.fetchzip {
|
||||
@@ -54,24 +54,4 @@ in
|
||||
assert "MediaWiki has been installed" in page
|
||||
'';
|
||||
};
|
||||
|
||||
nohttpd = testLib.makeTest {
|
||||
name = "mediawiki-nohttpd";
|
||||
nodes.machine = {
|
||||
services.mediawiki.webserver = "none";
|
||||
};
|
||||
testScript = { nodes, ... }: ''
|
||||
start_all()
|
||||
machine.wait_for_unit("phpfpm-mediawiki.service")
|
||||
env = (
|
||||
"SCRIPT_NAME=/index.php",
|
||||
"SCRIPT_FILENAME=${nodes.machine.services.mediawiki.finalPackage}/share/mediawiki/index.php",
|
||||
"REMOTE_ADDR=127.0.0.1",
|
||||
'QUERY_STRING=title=Main_Page',
|
||||
"REQUEST_METHOD=GET",
|
||||
);
|
||||
page = machine.succeed(f"{' '.join(env)} ${pkgs.fcgi}/bin/cgi-fcgi -bind -connect ${nodes.machine.services.phpfpm.pools.mediawiki.socket}")
|
||||
assert "MediaWiki has been installed" in page, f"no 'MediaWiki has been installed' in:\n{page}"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import ../make-test-python.nix ({ pkgs, ...}: let
|
||||
username = "custom_admin_username";
|
||||
# This will be used both for redis and postgresql
|
||||
pass = "hunter2";
|
||||
# Don't do this at home, use a file outside of the nix store instead
|
||||
passFile = toString (pkgs.writeText "pass-file" ''
|
||||
${pass}
|
||||
'');
|
||||
adminpass = "hunter2";
|
||||
adminuser = "custom-admin-username";
|
||||
in {
|
||||
name = "nextcloud-with-declarative-redis";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
@@ -27,15 +22,15 @@ in {
|
||||
redis = true;
|
||||
memcached = false;
|
||||
};
|
||||
# This test also validates that we can use an "external" database
|
||||
database.createLocally = false;
|
||||
config = {
|
||||
dbtype = "pgsql";
|
||||
dbname = "nextcloud";
|
||||
dbuser = username;
|
||||
dbpassFile = passFile;
|
||||
adminuser = username;
|
||||
adminpassFile = passFile;
|
||||
dbuser = "nextcloud";
|
||||
dbhost = "/run/postgresql";
|
||||
inherit adminuser;
|
||||
adminpassFile = toString (pkgs.writeText "admin-pass-file" ''
|
||||
${adminpass}
|
||||
'');
|
||||
};
|
||||
secretFile = "/etc/nextcloud-secrets.json";
|
||||
|
||||
@@ -57,20 +52,20 @@ in {
|
||||
|
||||
systemd.services.nextcloud-setup= {
|
||||
requires = ["postgresql.service"];
|
||||
after = [ "postgresql.service" ];
|
||||
after = [
|
||||
"postgresql.service"
|
||||
];
|
||||
};
|
||||
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
ensureDatabases = [ "nextcloud" ];
|
||||
ensureUsers = [
|
||||
{ name = "nextcloud";
|
||||
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
|
||||
}
|
||||
];
|
||||
};
|
||||
systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
|
||||
password=$(cat ${passFile})
|
||||
${config.services.postgresql.package}/bin/psql <<EOF
|
||||
CREATE ROLE ${username} WITH LOGIN PASSWORD '$password' CREATEDB;
|
||||
CREATE DATABASE nextcloud;
|
||||
GRANT ALL PRIVILEGES ON DATABASE nextcloud TO ${username};
|
||||
EOF
|
||||
'';
|
||||
|
||||
# This file is meant to contain secret options which should
|
||||
# not go into the nix store. Here it is just used to set the
|
||||
@@ -91,8 +86,8 @@ in {
|
||||
export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
|
||||
export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/"
|
||||
export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
|
||||
export RCLONE_CONFIG_NEXTCLOUD_USER="${username}"
|
||||
export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${pass})"
|
||||
export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
|
||||
export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
|
||||
"''${@}"
|
||||
'';
|
||||
copySharedFile = pkgs.writeScript "copy-shared-file" ''
|
||||
|
||||
@@ -26,13 +26,24 @@ in {
|
||||
redis = false;
|
||||
memcached = true;
|
||||
};
|
||||
database.createLocally = true;
|
||||
config = {
|
||||
dbtype = "mysql";
|
||||
dbname = "nextcloud";
|
||||
dbuser = "nextcloud";
|
||||
dbhost = "127.0.0.1";
|
||||
dbport = 3306;
|
||||
dbpassFile = "${pkgs.writeText "dbpass" "hunter2" }";
|
||||
# Don't inherit adminuser since "root" is supposed to be the default
|
||||
adminpassFile = "${pkgs.writeText "adminpass" adminpass}"; # Don't try this at home!
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.nextcloud-setup= {
|
||||
requires = ["mysql.service"];
|
||||
after = ["mysql.service"];
|
||||
};
|
||||
|
||||
services.memcached.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user