blob: 61364a426986683d67e86bfce89ba6ba6431013e [file] [log] [blame]
Petr Michalecad441172017-09-18 17:18:10 +02001Escaping of References and Inventory Queries
2--------------------------------------------
3
4Reference and inventory queries can be escaped to produce literal strings, for example:
5
6.. code-block:: yaml
7
8 parameters:
9 colour: Blue
10 unescaped: The colour is ${colour}
11 escaped: The colour is \${colour}
12 double_escaped: The colour is \\${colour}
13
14
15This would produce:
16
17.. code-block:: yaml
18
19 parameters:
20 colour: Blue
21 unescaped: The colour is Blue
22 escaped: The colour is ${colour}
23 double_escaped: The colour is \Blue
24
25
26
27Ignore class not found
28----------------------
29
30At some cases (bootstrapping, development) it can be convenient to ignore some missing classes.
31To control the feature there are two options available:
32
33.. code-block:: yaml
34
35 ignore_class_notfound: False
Petr Michalec19324742017-09-18 17:32:24 +020036 ignore_class_regexp: ['.*']
Petr Michalecad441172017-09-18 17:18:10 +020037
38If you set regexp pattern to ``service.*`` all missing classes starting 'service.' will be logged with warning, but will not
39fail to return rendered reclass. Assuming all parameter interpolation passes.
40
41
42
43Merging Referenced Lists and Dictionaries
44-----------------------------------------
45
46Referenced lists or dicts can now be merged:
47
48.. code-block:: yaml
49
50 # nodes/test.yml
51 classes:
52 - test1
53 - test2
54 parameters:
55 one:
56 a: 1
57 b: 2
58 two:
59 c: 3
60 d: 4
61 three:
62 e: 5
63
64 # classes/test1.yml
65 parameters:
66 three: ${one}
67
68 # classes/test2.yml
69 parameters:
70 three: ${two}
71
72``running reclass.py --nodeinfo node1`` then gives:
73
74.. code-block:: yaml
75
76 parameters:
77 one:
78 a: 1
79 b: 2
80 three:
81 a: 1
82 b: 2
83 c: 3
84 d: 4
85 e: 5
86 two:
87 c: 3
88 d: 4
89
90This first sets the parameter three to the value of parameter one (class test1) then merges parameter two into
91parameter three (class test2) and finally merges the parameter three definition given in the node definition into
92the final value.
93
94
Petr Michalec0a3a3682018-03-28 15:30:15 +020095Allow override list and dicts by empty entity,None instead of merge
96-------------------------------------------------------------------
97
98With settings:
99
100.. code-block:: yaml
101
102 allow_none_override: True # default True
103
104 # note dict,list over None is allowed and not configurable
105
106Referenced lists or dicts can now be overriden by None or empty type of dict, list:
107
108.. code-block:: yaml
109
110 # nodes/test.yml
111 parameters:
112 one:
113 a: 1
114 b: 2
115 two: {}
116 three: None
117
118 # classes/test1.yml
119 parameters:
120 one: ${two}
121
122 # classes/test2.yml
123 parameters:
124 three: ${one}
125
Petr Michalecad441172017-09-18 17:18:10 +0200126
127Nested References
128-----------------
129
130References can now be nested, for example:
131
132.. code-block:: yaml
133
134 # nodes/node1.yml
135 parameters:
136 alpha:
137 one: ${beta:${alpha:two}}
138 two: a
139 beta:
140 a: 99
141
142``reclass.py --nodeinfo node1`` then gives:
143
144.. code-block:: yaml
145
146 parameters:
147 alpha:
148 one: 99
149 two: a
150 beta:
151 a: 99
152
153The ``${beta:${alpha:two}}`` construct first resolves the ``${alpha:two}`` reference to the value 'a', then resolves
154the reference ``${beta:a}`` to the value 99.
155
156
Andrew Pickforde0eb7b62018-03-16 08:45:42 +0100157Ignore overwritten missing references
158-------------------------
159
160Given the following classes:
161
162.. code-block:: yaml
163 # node1.yml
164 classes:
165 - class1
166 - class2
167 - class3
168
169 # class1.yml
170 parameters:
171 a: ${x}
172
173 # class2.yml
174 parameters:
175 a: ${y}
176
177 # class3.yml
178 parameters:
179 y: 1
180
181
182The parameter ``a`` only depends on the parameter ``y`` through the reference set in class2. The fact that the parameter ``x`` referenced
183in class1 is not defined does not affect the final value of the parameter ``a``. For such overwritten missing references by default a warning is
184printed but no error is raised, providing the final value of the parameter being evaluated is a scalar. If the final value is a dictionary or list
185an error will always be raised in the case of a missing reference.
186
187Default value is True to keep backward compatible behavior.
188
189.. code-block:: yaml
190
191 ignore_overwritten_missing_reference: True
192
Petr Michalecad441172017-09-18 17:18:10 +0200193
Andrew Pickfordffd77b42018-03-16 14:37:03 +0100194Print summary of missed references
195----------------------------------
196
197Instead of failing on the first undefinded reference error all missing reference errors are printed at once.
198
199.. code-block:: yaml
200 reclass --nodeinfo mynode
201 -> dontpanic
202 Cannot resolve ${_param:kkk}, at mkkek3:tree:to:fail, in yaml_fs:///test/classes/third.yml
203 Cannot resolve ${_param:kkk}, at mkkek3:tree:another:xxxx, in yaml_fs:///test/classes/third.yml
204 Cannot resolve ${_param:kkk}, at mykey2:tree:to:fail, in yaml_fs:///test/classes/third.yml
205
206.. code-block:: yaml
207
208 group_errors: True
209
210
Andrew Pickford04cb20a2018-04-24 14:27:50 +0200211Use references in class names
212-----------------------------
213
214Allows to use references in the class names.
215
216References pointed to in class names cannot themselves reference another key, they should be simple strings.
217
218To avoid pitfalls do not over-engineer your class references. They should be used only for core conditions and only for them.
219A short example: `- system.wrodpress.db.${_class:database_backend}`.
220
221Best practices:
222- use references in class names always load your global class specification prior the reference is used.
223- structure your class references under parameters under one key (for example `_class`).
224- use class references as a kind of "context" or "global" available options you always know what they are set.
225
226Class referencing for existing reclass users. Frequently when constructing your models you had to load or not load some
227classes based on your setup. In most cases this lead to fork of a model or introducing kind of template generator (like cookiecutter) to
228create a model based on the base "context" or "global" variables. Class referencing is a simple way how to avoid
229"pre-processors" like this and if/else conditions around class section.
230
231
232Assuming following class setup:
233
234* node is loading `third.yml` class only
235
236
237Classes:
238
239.. code-block:: yaml
240 #/etc/reclass/classes/global.yml
241 parameters:
242 _class:
243 env:
244 override: 'env.dev'
245 lab:
246 name: default
247
248 #/etc/reclass/classes/lab/env/dev.yml
249 parameters:
250 lab:
251 name: dev
252
253 #/etc/reclass/classes/second.yml
254 classes:
255 - global
256 - lab.${_class:env:override}
257
258 #/etc/reclass/classes/third.yml
259 classes:
260 - global
261 - second
262
263
264Reclass --nodeinfo then returns:
265
266.. code-block:: yaml
267
268 ...
269 ...
270 applications: []
271 environment: base
272 exports: {}
273 classes:
Petr Michalec67e737c2018-04-25 09:44:02 +0200274 - global
Andrew Pickford04cb20a2018-04-24 14:27:50 +0200275 - lab.${_class:env:override}
276 - second
277 parameters:
278 _class:
279 env:
280 override: env.dev
281 lab:
282 name: dev
283 ...
284 ...
285
286
Petr Michalecad441172017-09-18 17:18:10 +0200287Inventory Queries
288-----------------
289
290Inventory querying works using a new key type - exports to hold values which other node definitions can read using a $[] query, for example with:
291
292.. code-block:: yaml
293
294 # nodes/node1.yml
295 exports:
296 test_zero: 0
297 test_one:
298 name: ${name}
299 value: 6
300 test_two: ${dict}
301
302 parameters:
303 name: node1
304 dict:
305 a: 1
306 b: 2
307 exp_value_test: $[ exports:test_two ]
308 exp_if_test0: $[ if exports:test_zero == 0 ]
309 exp_if_test1: $[ exports:test_one if exports:test_one:value == 7 ]
310 exp_if_test2: $[ exports:test_one if exports:test_one:name == self:name ]
311
312 # nodes/node2.yml
313 exports:
314 test_zero: 0
315 test_one:
316 name: ${name}
317 value: 7
318 test_two: ${dict}
319
320 parameters:
321 name: node2
322 dict:
323 a: 11
324 b: 22
325
326
327``running reclass.py --nodeinfo node1`` gives (listing only the exports and parameters):
328
329.. code-block:: yaml
330
331 exports:
332 test_one:
333 name: node1
334 value: 6
335 test_two:
336 a: 1
337 b: 2
338 parameters:
339 dict:
340 a: 1
341 b: 2
342 exp_if_test0:
343 - node1
344 - node2
345 exp_if_test1:
346 node2:
347 name: node2
348 value: 7
349 exp_if_test2:
350 node1:
351 name: node1
352 value: 6
353 exp_value_test:
354 node1:
355 a: 1
356 b: 2
357 node2:
358 a: 11
359 b: 22
360 name: node1
361
362
363Exports defined for a node can be a simple value or a reference to a parameter in the node definition.
Petr Michalecab9cac32017-09-18 17:35:54 +0200364The ``$[]`` inventory queries are calculated for simple value expressions, ``$[ exports:key ]``, by returning
365a dictionary with an element (``{ node_name: key value }``) for each node which defines 'key' in the exports
366section. For tests with a preceeding value, ``$[ exports:key if exports:test_key == test_value ]``, the
367element (``{ node_name: key value }``) is only added to the returned dictionary if the test_key defined in
Petr Michalecad441172017-09-18 17:18:10 +0200368the node exports section equals the test value. For tests without a preceeding value,
Petr Michalecab9cac32017-09-18 17:35:54 +0200369``$[ if exports:test_key == test_value ]``, a list of nodes which pass the test is returned. For either test
Petr Michalecad441172017-09-18 17:18:10 +0200370form the test value can either be a simple value or a node parameter. And as well as an equality test
Petr Michalecab9cac32017-09-18 17:35:54 +0200371a not equals test (``!=``) can also be used.
Petr Michalecad441172017-09-18 17:18:10 +0200372
373
374**Inventory query options**
375
376By default inventory queries only look at nodes in the same environment as the querying node. This can be
377overriden using the +AllEnvs option:
378
Petr Michalecab9cac32017-09-18 17:35:54 +0200379.. code-block:: yaml
380
Petr Michalecad441172017-09-18 17:18:10 +0200381 $[ +AllEnvs exports:test ]
382
383Any errors in rendering the export parameters for a node will give an error for the inventory query as a whole.
Petr Michalecab9cac32017-09-18 17:35:54 +0200384This can be overriden using the ``+IgnoreErrors`` option:
385
386.. code-block:: yaml
Petr Michalecad441172017-09-18 17:18:10 +0200387
388 $[ +IgnoreErrors exports:test ]
389
Petr Michalecab9cac32017-09-18 17:35:54 +0200390With the ``+IgnoreErrors`` option nodes which generate an error evaluating ``exports:test`` will be ignored.
Petr Michalecad441172017-09-18 17:18:10 +0200391
392Inventory query options can be combined:
393
Petr Michalecab9cac32017-09-18 17:35:54 +0200394.. code-block:: yaml
395
Petr Michalecad441172017-09-18 17:18:10 +0200396 $[ +AllEnvs +IgnoreErrors exports:test ]
397
398**Logical operators and/or**
399
400The logical operators and/or can be used in inventory queries:
401
Petr Michalecab9cac32017-09-18 17:35:54 +0200402.. code-block:: yaml
403
Petr Michalecad441172017-09-18 17:18:10 +0200404 $[ exports:test_value if exports:test_zero == 0 and exports:test_one == self:value ]
405
406The individual elements of the if statement are evaluated and combined with the logical operators starting from the
407left and working to the right.
408
409
410**Inventory query example**
411
412Defining a cluster of machines using an inventory query, for example to open access to a database server to a
413group of nodes. Given exports/parameters for nodes of the form:
414
415.. code-block:: yaml
416
Petr Michalecab9cac32017-09-18 17:35:54 +0200417 # for all nodes requiring access to the database server
418 exports:
419 host:
420 ip_address: aaa.bbb.ccc.ddd
421 cluster: _some_cluster_name_
Petr Michalecad441172017-09-18 17:18:10 +0200422
423.. code-block:: yaml
424
Petr Michalecab9cac32017-09-18 17:35:54 +0200425 # for the database server
426 parameters:
427 cluster_name: production-cluster
428 postgresql:
429 server:
430 clients: $[ exports:host:ip_address if exports:cluster == self:cluster_name ]
Petr Michalecad441172017-09-18 17:18:10 +0200431
Petr Michalecab9cac32017-09-18 17:35:54 +0200432This will generate a dictionary with an entry for node where the ``export:cluster`` key for a node is equal to the
433``parameter:cluster_name`` key of the node on which the inventory query is run on. Each entry in the generated dictionary
434will contain the value of the ``exports:host:ip_address`` key. The output dictionary (depending on node definitions)
Petr Michalecad441172017-09-18 17:18:10 +0200435would look like:
436
437.. code-block:: yaml
438
Petr Michalecab9cac32017-09-18 17:35:54 +0200439 node1:
440 ip_address: aaa.bbb.ccc.ddd
441 node2:
442 ip_address: www.xxx.yyy.zzz
Petr Michalecad441172017-09-18 17:18:10 +0200443
444For nodes where exports:cluster key is not defined or where the key is not equal to self:cluster_name no entry is made
445in the output dictionary.
446
447In practise the exports:cluster key can be set using a parameter reference:
448
449.. code-block:: yaml
450
Petr Michalecab9cac32017-09-18 17:35:54 +0200451 exports:
452 cluster: ${cluster_name}
453 parameters:
454 cluster_name: production-cluster
Petr Michalecad441172017-09-18 17:18:10 +0200455
456The above exports and parameter definitions could be put into a separate class and then included by nodes which require
457access to the database and included by the database server as well.