Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

nixos/doc: Add modular services section

Changed files
+139 -1
nixos
pkgs
by-name
ni
nixos-render-docs
src
nixos_render_docs
+28
nixos/doc/manual/default.nix
··· 14 14 inherit (pkgs) buildPackages runCommand docbook_xsl_ns; 15 15 16 16 inherit (pkgs.lib) 17 + evalModules 17 18 hasPrefix 18 19 removePrefix 19 20 flip ··· 116 117 ${testOptionsDoc.optionsJSON}/${common.outputPath}/options.json 117 118 sed -e '/@PYTHON_MACHINE_METHODS@/ {' -e 'r ${testDriverMachineDocstrings}/machine-methods.md' -e 'd' -e '}' \ 118 119 -i ./development/writing-nixos-tests.section.md 120 + substituteInPlace ./development/modular-services.md \ 121 + --replace-fail \ 122 + '@PORTABLE_SERVICE_OPTIONS@' \ 123 + ${portableServiceOptions.optionsJSON}/${common.outputPath}/options.json 124 + substituteInPlace ./development/modular-services.md \ 125 + --replace-fail \ 126 + '@SYSTEMD_SERVICE_OPTIONS@' \ 127 + ${systemdServiceOptions.optionsJSON}/${common.outputPath}/options.json 119 128 ''; 129 + 130 + portableServiceOptions = buildPackages.nixosOptionsDoc { 131 + inherit (evalModules { modules = [ ../../modules/system/service/portable/service.nix ]; }) options; 132 + inherit revision warningsAreErrors; 133 + transformOptions = opt: opt // { 134 + # Clean up declaration sites to not refer to the NixOS source tree. 135 + declarations = map stripAnyPrefixes opt.declarations; 136 + }; 137 + }; 138 + 139 + systemdServiceOptions = buildPackages.nixosOptionsDoc { 140 + inherit (evalModules { modules = [ ../../modules/system/service/systemd/service.nix ]; }) options; 141 + # TODO: filter out options that are not systemd-specific, maybe also change option prefix to just `service-opt-`? 142 + inherit revision warningsAreErrors; 143 + transformOptions = opt: opt // { 144 + # Clean up declaration sites to not refer to the NixOS source tree. 145 + declarations = map stripAnyPrefixes opt.declarations; 146 + }; 147 + }; 120 148 121 149 in 122 150 rec {
+1
nixos/doc/manual/development/development.md
··· 12 12 nixos-tests.chapter.md 13 13 developing-the-test-driver.chapter.md 14 14 testing-installer.chapter.md 15 + modular-services.md 15 16 ```
+91
nixos/doc/manual/development/modular-services.md
··· 1 + 2 + # Modular Services {#modular-services} 3 + 4 + Status: in development. This functionality is new in NixOS 25.05, and significant changes should be expected. We'd love to hear your feedback in <https://github.com/NixOS/nixpkgs/pull/372170> 5 + 6 + Traditionally, NixOS services were defined using sets of options *in* modules, not *as* modules. This made them non-modular, resulting in problems with composability, reuse, and portability. 7 + 8 + A *modular service* is a [module] that defines values for a core set of options, including which program to run. 9 + 10 + NixOS provides two options into which such modules can be plugged: 11 + 12 + - `system.services.<name>` 13 + - an option for user services (TBD) 14 + 15 + Crucially, these options have the type [`attrsOf`] [`submodule`]. 16 + The name of the service is the attribute name corresponding to `attrsOf`. 17 + <!-- ^ This is how composition is *always* provided, instead of a difficult thing (but this is reference docs, not a changelog) --> 18 + The `submodule` is pre-loaded with two modules: 19 + - a generic module that is intended to be portable 20 + - a module with systemd-specific options, whose values or defaults derive from the generic module's option values. 21 + 22 + So note that the default value of `system.services.<name>` is not a complete service. It requires that the user provide a value, and this is typically done by importing a module. For example: 23 + 24 + <!-- Not using typical example syntax, because reading this is *not* optional, and should it should not be folded closed. --> 25 + ```nix 26 + { 27 + system.services.httpd = { 28 + imports = [ nixpkgs.modules.services.foo ]; 29 + foo.settings = { 30 + # ... 31 + }; 32 + }; 33 + } 34 + ``` 35 + 36 + ## Portability {#modular-service-portability} 37 + 38 + It is possible to write service modules that are portable. This is done by either avoiding the `systemd` option tree, or by defining process-manager-specific definitions in an optional way: 39 + 40 + ```nix 41 + { config, options, lib, ... }: { 42 + _class = "service"; 43 + config = { 44 + process.executable = "${lib.getExe config.foo.program}"; 45 + } // lib.optionalAttrs (options?systemd) { 46 + # ... systemd-specific definitions ... 47 + }; 48 + } 49 + ``` 50 + 51 + This way, the module can be loaded into a configuration manager that does not use systemd, and the `systemd` definitions will be ignored. 52 + Similarly, other configuration managers can declare their own options for services to customize. 53 + 54 + ## Composition and Ownership {#modular-service-composition} 55 + 56 + Compared to traditional services, modular services are inherently more composable, by virtue of being modules and receiving a user-provided name when imported. 57 + However, composition can not end there, because services need to be able to interact with each other. 58 + This can be achieved in two ways: 59 + 1. Users can link services together by providing the necessary NixOS configuration. 60 + 2. Services can be compositions of other services. 61 + 62 + These aren't mutually exclusive. In fact, it is a good practice when developing services to first write them as individual services, and then compose them into a higher-level composition. Each of these services is a valid modular service, including their composition. 63 + 64 + ## Migration {#modular-service-migration} 65 + 66 + Many services could be migrated to the modular service system, but even when the modular service system is mature, it is not necessary to migrate all services. 67 + For instance, many system-wide services are a mandatory part of a desktop system, and it doesn't make sense to have multiple instances of them. 68 + Moving their logic into separate Nix files may still be beneficial for the efficient evaluation of configurations that don't use those services, but that is a rather minor benefit, unless modular services potentially become the standard way to define services. 69 + 70 + <!-- TODO example of a single-instance service --> 71 + 72 + ## Portable Service Options {#modular-service-options-portable} 73 + 74 + ```{=include=} options 75 + id-prefix: service-opt- 76 + list-id: service-options 77 + source: @PORTABLE_SERVICE_OPTIONS@ 78 + ``` 79 + 80 + ## Systemd-specific Service Options {#modular-service-options-systemd} 81 + 82 + ```{=include=} options 83 + id-prefix: systemd-service-opt- 84 + list-id: systemd-service-options 85 + source: @SYSTEMD_SERVICE_OPTIONS@ 86 + ``` 87 + 88 + [module]: https://nixos.org/manual/nixpkgs/stable/index.html#module-system 89 + <!-- TODO: more anchors --> 90 + [`attrsOf`]: #sec-option-types-composed 91 + [`submodule`]: #sec-option-types-submodule
+18
nixos/doc/manual/redirects.json
··· 2 2 "book-nixos-manual": [ 3 3 "index.html#book-nixos-manual" 4 4 ], 5 + "modular-service-composition": [ 6 + "index.html#modular-service-composition" 7 + ], 8 + "modular-service-migration": [ 9 + "index.html#modular-service-migration" 10 + ], 11 + "modular-service-options-portable": [ 12 + "index.html#modular-service-options-portable" 13 + ], 14 + "modular-service-options-systemd": [ 15 + "index.html#modular-service-options-systemd" 16 + ], 17 + "modular-service-portability": [ 18 + "index.html#modular-service-portability" 19 + ], 20 + "modular-services": [ 21 + "index.html#modular-services" 22 + ], 5 23 "module-services-anubis": [ 6 24 "index.html#module-services-anubis" 7 25 ],
+1 -1
pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/redirects.py
··· 114 114 - The first element of an identifier's redirects list must denote its current location. 115 115 """ 116 116 xref_targets = {} 117 - ignored_identifier_patterns = ("opt-", "auto-generated-", "function-library-") 117 + ignored_identifier_patterns = ("opt-", "auto-generated-", "function-library-", "service-opt-", "systemd-service-opt") 118 118 for id, target in initial_xref_targets.items(): 119 119 # filter out automatically generated identifiers from module options and library documentation 120 120 if id.startswith(ignored_identifier_patterns):