at 22.05-pre 10 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.json</literal> { } 59 </term> 60 <listitem> 61 <para> 62 A function taking an empty attribute set (for future 63 extensibility) and returning a set with JSON-specific 64 attributes <literal>type</literal> and 65 <literal>generate</literal> as specified 66 <link linkend="pkgs-formats-result">below</link>. 67 </para> 68 </listitem> 69 </varlistentry> 70 <varlistentry> 71 <term> 72 <literal>pkgs.formats.yaml</literal> { } 73 </term> 74 <listitem> 75 <para> 76 A function taking an empty attribute set (for future 77 extensibility) and returning a set with YAML-specific 78 attributes <literal>type</literal> and 79 <literal>generate</literal> as specified 80 <link linkend="pkgs-formats-result">below</link>. 81 </para> 82 </listitem> 83 </varlistentry> 84 <varlistentry> 85 <term> 86 <literal>pkgs.formats.ini</literal> { 87 <emphasis><literal>listsAsDuplicateKeys</literal></emphasis> ? 88 false, <emphasis><literal>listToValue</literal></emphasis> ? 89 null, ... } 90 </term> 91 <listitem> 92 <para> 93 A function taking an attribute set with values 94 </para> 95 <variablelist> 96 <varlistentry> 97 <term> 98 <literal>listsAsDuplicateKeys</literal> 99 </term> 100 <listitem> 101 <para> 102 A boolean for controlling whether list values can be 103 used to represent duplicate INI keys 104 </para> 105 </listitem> 106 </varlistentry> 107 <varlistentry> 108 <term> 109 <literal>listToValue</literal> 110 </term> 111 <listitem> 112 <para> 113 A function for turning a list of values into a single 114 value. 115 </para> 116 </listitem> 117 </varlistentry> 118 </variablelist> 119 <para> 120 It returns a set with INI-specific attributes 121 <literal>type</literal> and <literal>generate</literal> as 122 specified <link linkend="pkgs-formats-result">below</link>. 123 </para> 124 </listitem> 125 </varlistentry> 126 <varlistentry> 127 <term> 128 <literal>pkgs.formats.toml</literal> { } 129 </term> 130 <listitem> 131 <para> 132 A function taking an empty attribute set (for future 133 extensibility) and returning a set with TOML-specific 134 attributes <literal>type</literal> and 135 <literal>generate</literal> as specified 136 <link linkend="pkgs-formats-result">below</link>. 137 </para> 138 </listitem> 139 </varlistentry> 140 </variablelist> 141 <para xml:id="pkgs-formats-result"> 142 These functions all return an attribute set with these values: 143 </para> 144 <variablelist> 145 <varlistentry> 146 <term> 147 <literal>type</literal> 148 </term> 149 <listitem> 150 <para> 151 A module system type representing a value of the format 152 </para> 153 </listitem> 154 </varlistentry> 155 <varlistentry> 156 <term> 157 <literal>generate</literal> 158 <emphasis><literal>filename jsonValue</literal></emphasis> 159 </term> 160 <listitem> 161 <para> 162 A function that can render a value of the format to a file. 163 Returns a file path. 164 </para> 165 <note> 166 <para> 167 This function puts the value contents in the Nix store. So 168 this should be avoided for secrets. 169 </para> 170 </note> 171 </listitem> 172 </varlistentry> 173 </variablelist> 174 <anchor xml:id="ex-settings-nix-representable" /> 175 <para> 176 <emphasis role="strong">Example: Module with conventional 177 <literal>settings</literal> option</emphasis> 178 </para> 179 <para> 180 The following shows a module for an example program that uses a 181 JSON configuration file. It demonstrates how above values can be 182 used, along with some other related best practices. See the 183 comments for explanations. 184 </para> 185 <programlisting language="bash"> 186{ options, config, lib, pkgs, ... }: 187let 188 cfg = config.services.foo; 189 # Define the settings format used for this program 190 settingsFormat = pkgs.formats.json {}; 191in { 192 193 options.services.foo = { 194 enable = lib.mkEnableOption &quot;foo service&quot;; 195 196 settings = lib.mkOption { 197 # Setting this type allows for correct merging behavior 198 type = settingsFormat.type; 199 default = {}; 200 description = '' 201 Configuration for foo, see 202 &lt;link xlink:href=&quot;https://example.com/docs/foo&quot;/&gt; 203 for supported settings. 204 ''; 205 }; 206 }; 207 208 config = lib.mkIf cfg.enable { 209 # We can assign some default settings here to make the service work by just 210 # enabling it. We use `mkDefault` for values that can be changed without 211 # problems 212 services.foo.settings = { 213 # Fails at runtime without any value set 214 log_level = lib.mkDefault &quot;WARN&quot;; 215 216 # We assume systemd's `StateDirectory` is used, so we require this value, 217 # therefore no mkDefault 218 data_path = &quot;/var/lib/foo&quot;; 219 220 # Since we use this to create a user we need to know the default value at 221 # eval time 222 user = lib.mkDefault &quot;foo&quot;; 223 }; 224 225 environment.etc.&quot;foo.json&quot;.source = 226 # The formats generator function takes a filename and the Nix value 227 # representing the format value and produces a filepath with that value 228 # rendered in the format 229 settingsFormat.generate &quot;foo-config.json&quot; cfg.settings; 230 231 # We know that the `user` attribute exists because we set a default value 232 # for it above, allowing us to use it without worries here 233 users.users.${cfg.settings.user} = { isSystemUser = true; }; 234 235 # ... 236 }; 237} 238</programlisting> 239 <section xml:id="sec-settings-attrs-options"> 240 <title>Option declarations for attributes</title> 241 <para> 242 Some <literal>settings</literal> attributes may deserve some 243 extra care. They may need a different type, default or merging 244 behavior, or they are essential options that should show their 245 documentation in the manual. This can be done using 246 <xref linkend="sec-freeform-modules" />. 247 </para> 248 <para> 249 We extend above example using freeform modules to declare an 250 option for the port, which will enforce it to be a valid integer 251 and make it show up in the manual. 252 </para> 253 <anchor xml:id="ex-settings-typed-attrs" /> 254 <para> 255 <emphasis role="strong">Example: Declaring a type-checked 256 <literal>settings</literal> attribute</emphasis> 257 </para> 258 <programlisting language="bash"> 259settings = lib.mkOption { 260 type = lib.types.submodule { 261 262 freeformType = settingsFormat.type; 263 264 # Declare an option for the port such that the type is checked and this option 265 # is shown in the manual. 266 options.port = lib.mkOption { 267 type = lib.types.port; 268 default = 8080; 269 description = '' 270 Which port this service should listen on. 271 ''; 272 }; 273 274 }; 275 default = {}; 276 description = '' 277 Configuration for Foo, see 278 &lt;link xlink:href=&quot;https://example.com/docs/foo&quot;/&gt; 279 for supported values. 280 ''; 281}; 282</programlisting> 283 </section> 284 </section> 285</section>