at 23.05-pre 15 kB view raw
1<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-settings-options"> 2 <title>Options for Program Settings</title> 3 <para> 4 Many programs have configuration files where program-specific 5 settings can be declared. File formats can be separated into two 6 categories: 7 </para> 8 <itemizedlist> 9 <listitem> 10 <para> 11 Nix-representable ones: These can trivially be mapped to a 12 subset of Nix syntax. E.g. JSON is an example, since its values 13 like <literal>{&quot;foo&quot;:{&quot;bar&quot;:10}}</literal> 14 can be mapped directly to Nix: 15 <literal>{ foo = { bar = 10; }; }</literal>. Other examples are 16 INI, YAML and TOML. The following section explains the 17 convention for these settings. 18 </para> 19 </listitem> 20 <listitem> 21 <para> 22 Non-nix-representable ones: These can't be trivially mapped to a 23 subset of Nix syntax. Most generic programming languages are in 24 this group, e.g. bash, since the statement 25 <literal>if true; then echo hi; fi</literal> doesn't have a 26 trivial representation in Nix. 27 </para> 28 <para> 29 Currently there are no fixed conventions for these, but it is 30 common to have a <literal>configFile</literal> option for 31 setting the configuration file path directly. The default value 32 of <literal>configFile</literal> can be an auto-generated file, 33 with convenient options for controlling the contents. For 34 example an option of type <literal>attrsOf str</literal> can be 35 used for representing environment variables which generates a 36 section like <literal>export FOO=&quot;foo&quot;</literal>. 37 Often it can also be useful to also include an 38 <literal>extraConfig</literal> option of type 39 <literal>lines</literal> to allow arbitrary text after the 40 autogenerated part of the file. 41 </para> 42 </listitem> 43 </itemizedlist> 44 <section xml:id="sec-settings-nix-representable"> 45 <title>Nix-representable Formats (JSON, YAML, TOML, INI, 46 ...)</title> 47 <para> 48 By convention, formats like this are handled with a generic 49 <literal>settings</literal> option, representing the full program 50 configuration as a Nix value. The type of this option should 51 represent the format. The most common formats have a predefined 52 type and string generator already declared under 53 <literal>pkgs.formats</literal>: 54 </para> 55 <variablelist> 56 <varlistentry> 57 <term> 58 <literal>pkgs.formats.javaProperties</literal> { 59 <emphasis><literal>comment</literal></emphasis> ? 60 <literal>&quot;Generated with Nix&quot;</literal> } 61 </term> 62 <listitem> 63 <para> 64 A function taking an attribute set with values 65 </para> 66 <variablelist> 67 <varlistentry> 68 <term> 69 <literal>comment</literal> 70 </term> 71 <listitem> 72 <para> 73 A string to put at the start of the file in a comment. 74 It can have multiple lines. 75 </para> 76 </listitem> 77 </varlistentry> 78 </variablelist> 79 <para> 80 It returns the <literal>type</literal>: 81 <literal>attrsOf str</literal> and a function 82 <literal>generate</literal> to build a Java 83 <literal>.properties</literal> file, taking care of the 84 correct escaping, etc. 85 </para> 86 </listitem> 87 </varlistentry> 88 <varlistentry> 89 <term> 90 <literal>pkgs.formats.json</literal> { } 91 </term> 92 <listitem> 93 <para> 94 A function taking an empty attribute set (for future 95 extensibility) and returning a set with JSON-specific 96 attributes <literal>type</literal> and 97 <literal>generate</literal> as specified 98 <link linkend="pkgs-formats-result">below</link>. 99 </para> 100 </listitem> 101 </varlistentry> 102 <varlistentry> 103 <term> 104 <literal>pkgs.formats.yaml</literal> { } 105 </term> 106 <listitem> 107 <para> 108 A function taking an empty attribute set (for future 109 extensibility) and returning a set with YAML-specific 110 attributes <literal>type</literal> and 111 <literal>generate</literal> as specified 112 <link linkend="pkgs-formats-result">below</link>. 113 </para> 114 </listitem> 115 </varlistentry> 116 <varlistentry> 117 <term> 118 <literal>pkgs.formats.ini</literal> { 119 <emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ? 120 false, <emphasis><literal>listToValue</literal></emphasis> ? 121 null, ... } 122 </term> 123 <listitem> 124 <para> 125 A function taking an attribute set with values 126 </para> 127 <variablelist> 128 <varlistentry> 129 <term> 130 <literal>listsAsDuplicateKeys</literal> 131 </term> 132 <listitem> 133 <para> 134 A boolean for controlling whether list values can be 135 used to represent duplicate INI keys 136 </para> 137 </listitem> 138 </varlistentry> 139 <varlistentry> 140 <term> 141 <literal>listToValue</literal> 142 </term> 143 <listitem> 144 <para> 145 A function for turning a list of values into a single 146 value. 147 </para> 148 </listitem> 149 </varlistentry> 150 </variablelist> 151 <para> 152 It returns a set with INI-specific attributes 153 <literal>type</literal> and <literal>generate</literal> as 154 specified <link linkend="pkgs-formats-result">below</link>. 155 </para> 156 </listitem> 157 </varlistentry> 158 <varlistentry> 159 <term> 160 <literal>pkgs.formats.toml</literal> { } 161 </term> 162 <listitem> 163 <para> 164 A function taking an empty attribute set (for future 165 extensibility) and returning a set with TOML-specific 166 attributes <literal>type</literal> and 167 <literal>generate</literal> as specified 168 <link linkend="pkgs-formats-result">below</link>. 169 </para> 170 </listitem> 171 </varlistentry> 172 <varlistentry> 173 <term> 174 <literal>pkgs.formats.elixirConf { elixir ? pkgs.elixir }</literal> 175 </term> 176 <listitem> 177 <para> 178 A function taking an attribute set with values 179 </para> 180 <variablelist> 181 <varlistentry> 182 <term> 183 <literal>elixir</literal> 184 </term> 185 <listitem> 186 <para> 187 The Elixir package which will be used to format the 188 generated output 189 </para> 190 </listitem> 191 </varlistentry> 192 </variablelist> 193 <para> 194 It returns a set with Elixir-Config-specific attributes 195 <literal>type</literal>, <literal>lib</literal>, and 196 <literal>generate</literal> as specified 197 <link linkend="pkgs-formats-result">below</link>. 198 </para> 199 <para> 200 The <literal>lib</literal> attribute contains functions to 201 be used in settings, for generating special Elixir values: 202 </para> 203 <variablelist> 204 <varlistentry> 205 <term> 206 <literal>mkRaw elixirCode</literal> 207 </term> 208 <listitem> 209 <para> 210 Outputs the given string as raw Elixir code 211 </para> 212 </listitem> 213 </varlistentry> 214 <varlistentry> 215 <term> 216 <literal>mkGetEnv { envVariable, fallback ? null }</literal> 217 </term> 218 <listitem> 219 <para> 220 Makes the configuration fetch an environment variable 221 at runtime 222 </para> 223 </listitem> 224 </varlistentry> 225 <varlistentry> 226 <term> 227 <literal>mkAtom atom</literal> 228 </term> 229 <listitem> 230 <para> 231 Outputs the given string as an Elixir atom, instead of 232 the default Elixir binary string. Note: lowercase 233 atoms still needs to be prefixed with 234 <literal>:</literal> 235 </para> 236 </listitem> 237 </varlistentry> 238 <varlistentry> 239 <term> 240 <literal>mkTuple array</literal> 241 </term> 242 <listitem> 243 <para> 244 Outputs the given array as an Elixir tuple, instead of 245 the default Elixir list 246 </para> 247 </listitem> 248 </varlistentry> 249 <varlistentry> 250 <term> 251 <literal>mkMap attrset</literal> 252 </term> 253 <listitem> 254 <para> 255 Outputs the given attribute set as an Elixir map, 256 instead of the default Elixir keyword list 257 </para> 258 </listitem> 259 </varlistentry> 260 </variablelist> 261 </listitem> 262 </varlistentry> 263 </variablelist> 264 <para xml:id="pkgs-formats-result"> 265 These functions all return an attribute set with these values: 266 </para> 267 <variablelist> 268 <varlistentry> 269 <term> 270 <literal>type</literal> 271 </term> 272 <listitem> 273 <para> 274 A module system type representing a value of the format 275 </para> 276 </listitem> 277 </varlistentry> 278 <varlistentry> 279 <term> 280 <literal>lib</literal> 281 </term> 282 <listitem> 283 <para> 284 Utility functions for convenience, or special interactions 285 with the format. This attribute is optional. It may contain 286 inside a <literal>types</literal> attribute containing types 287 specific to this format. 288 </para> 289 </listitem> 290 </varlistentry> 291 <varlistentry> 292 <term> 293 <literal>generate</literal> 294 <emphasis><literal>filename jsonValue</literal></emphasis> 295 </term> 296 <listitem> 297 <para> 298 A function that can render a value of the format to a file. 299 Returns a file path. 300 </para> 301 <note> 302 <para> 303 This function puts the value contents in the Nix store. So 304 this should be avoided for secrets. 305 </para> 306 </note> 307 </listitem> 308 </varlistentry> 309 </variablelist> 310 <anchor xml:id="ex-settings-nix-representable" /> 311 <para> 312 <emphasis role="strong">Example: Module with conventional 313 <literal>settings</literal> option</emphasis> 314 </para> 315 <para> 316 The following shows a module for an example program that uses a 317 JSON configuration file. It demonstrates how above values can be 318 used, along with some other related best practices. See the 319 comments for explanations. 320 </para> 321 <programlisting language="bash"> 322{ options, config, lib, pkgs, ... }: 323let 324 cfg = config.services.foo; 325 # Define the settings format used for this program 326 settingsFormat = pkgs.formats.json {}; 327in { 328 329 options.services.foo = { 330 enable = lib.mkEnableOption &quot;foo service&quot;; 331 332 settings = lib.mkOption { 333 # Setting this type allows for correct merging behavior 334 type = settingsFormat.type; 335 default = {}; 336 description = '' 337 Configuration for foo, see 338 &lt;link xlink:href=&quot;https://example.com/docs/foo&quot;/&gt; 339 for supported settings. 340 ''; 341 }; 342 }; 343 344 config = lib.mkIf cfg.enable { 345 # We can assign some default settings here to make the service work by just 346 # enabling it. We use `mkDefault` for values that can be changed without 347 # problems 348 services.foo.settings = { 349 # Fails at runtime without any value set 350 log_level = lib.mkDefault &quot;WARN&quot;; 351 352 # We assume systemd's `StateDirectory` is used, so we require this value, 353 # therefore no mkDefault 354 data_path = &quot;/var/lib/foo&quot;; 355 356 # Since we use this to create a user we need to know the default value at 357 # eval time 358 user = lib.mkDefault &quot;foo&quot;; 359 }; 360 361 environment.etc.&quot;foo.json&quot;.source = 362 # The formats generator function takes a filename and the Nix value 363 # representing the format value and produces a filepath with that value 364 # rendered in the format 365 settingsFormat.generate &quot;foo-config.json&quot; cfg.settings; 366 367 # We know that the `user` attribute exists because we set a default value 368 # for it above, allowing us to use it without worries here 369 users.users.${cfg.settings.user} = { isSystemUser = true; }; 370 371 # ... 372 }; 373} 374</programlisting> 375 <section xml:id="sec-settings-attrs-options"> 376 <title>Option declarations for attributes</title> 377 <para> 378 Some <literal>settings</literal> attributes may deserve some 379 extra care. They may need a different type, default or merging 380 behavior, or they are essential options that should show their 381 documentation in the manual. This can be done using 382 <xref linkend="sec-freeform-modules" />. 383 </para> 384 <para> 385 We extend above example using freeform modules to declare an 386 option for the port, which will enforce it to be a valid integer 387 and make it show up in the manual. 388 </para> 389 <anchor xml:id="ex-settings-typed-attrs" /> 390 <para> 391 <emphasis role="strong">Example: Declaring a type-checked 392 <literal>settings</literal> attribute</emphasis> 393 </para> 394 <programlisting language="bash"> 395settings = lib.mkOption { 396 type = lib.types.submodule { 397 398 freeformType = settingsFormat.type; 399 400 # Declare an option for the port such that the type is checked and this option 401 # is shown in the manual. 402 options.port = lib.mkOption { 403 type = lib.types.port; 404 default = 8080; 405 description = '' 406 Which port this service should listen on. 407 ''; 408 }; 409 410 }; 411 default = {}; 412 description = '' 413 Configuration for Foo, see 414 &lt;link xlink:href=&quot;https://example.com/docs/foo&quot;/&gt; 415 for supported values. 416 ''; 417}; 418</programlisting> 419 </section> 420 </section> 421</section>