martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 1 | ================== |
| 2 | reclass operations |
| 3 | ================== |
| 4 | |
martin f. krafft | f432053 | 2013-11-30 17:00:37 +0100 | [diff] [blame] | 5 | YAML FS storage |
| 6 | --------------- |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 7 | While |reclass| has been built to support different storage backends through |
| 8 | plugins, currently only the ``yaml_fs`` storage backend exists. This is a very |
| 9 | simple, yet powerful, YAML-based backend, using flat files on the filesystem |
| 10 | (as suggested by the ``_fs`` postfix). |
| 11 | |
| 12 | ``yaml_fs`` works with two directories, one for node definitions, and another |
martin f. krafft | 16c9380 | 2013-11-30 13:23:16 +0100 | [diff] [blame] | 13 | for class definitions. The two directories must not be the same, nor can one |
| 14 | be a parent of the other. |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 15 | |
| 16 | Files in those directories are YAML-files, specifying key-value pairs. The |
| 17 | following three keys are read by |reclass|: |
| 18 | |
| 19 | ============ ================================================================ |
| 20 | Key Description |
| 21 | ============ ================================================================ |
| 22 | classes a list of parent classes |
| 23 | appliations a list of applications to append to the applications defined by |
| 24 | ancestors. If an application name starts with ``~``, it would |
| 25 | remove this application from the list, if it had already been |
| 26 | added — but it does not prevent a future addition. |
| 27 | E.g. ``~firewalled`` |
| 28 | parameters key-value pairs to set defaults in class definitions, override |
| 29 | existing data, or provide node-specific information in node |
| 30 | specifications. |
| 31 | \ |
| 32 | By convention, parameters corresponding to an application |
| 33 | should be provided as subkey-value pairs, keyed by the name of |
| 34 | the application, e.g.:: |
| 35 | |
| 36 | applications: |
| 37 | - ssh.server |
| 38 | parameters: |
| 39 | ssh.server: |
| 40 | permit_root_login: no |
martin f. krafft | d48a46e | 2014-01-03 14:32:49 +1300 | [diff] [blame] | 41 | environment only relevant for nodes, this allows to specify an "environment" |
| 42 | into which the node definition is supposed to be place. |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 43 | ============ ================================================================ |
| 44 | |
martin f. krafft | 14c81f5 | 2014-02-28 17:10:49 +0100 | [diff] [blame] | 45 | Classes files may reside in subdirectories, which act as namespaces. For |
| 46 | instance, a class ``ssh.server`` will result in the class definition to be |
| 47 | read from ``ssh/server.yml``. Specifying just ``ssh`` will cause the class |
| 48 | data to be read from ``ssh/init.yml`` or ``ssh.yml``. Note, however, that only |
| 49 | one of those two may be present. |
| 50 | |
| 51 | Nodes may also be defined in subdirectories. However, node names (filename) |
| 52 | must be unique across all subdirectories, and |reclass| will exit with an |
| 53 | error if a node is defined multiple times. Subdirectories therefore really |
| 54 | only exist for the administrator's local data structuring. They may be used in |
| 55 | mappings (see below) to tag additional classes onto nodes. |
martin f. krafft | 1f11ede | 2013-11-30 16:48:00 +0100 | [diff] [blame] | 56 | |
martin f. krafft | f432053 | 2013-11-30 17:00:37 +0100 | [diff] [blame] | 57 | Data merging |
| 58 | ------------ |
| 59 | |reclass| has two modes of operation: node information retrieval and inventory |
| 60 | listing. The second is really just a loop of the first across all defined |
| 61 | nodes, and needs not be further described. |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 62 | |
martin f. krafft | f432053 | 2013-11-30 17:00:37 +0100 | [diff] [blame] | 63 | When retrieving information about a node, |reclass| first obtains the node |
| 64 | definition from the storage backend. Then, it iterates the list of classes |
| 65 | defined for the node and recursively asks the storage backend for each class |
| 66 | definition (unless already cached). |
| 67 | |
| 68 | Next, |reclass| recursively descends each class, looking at the classes it |
| 69 | defines, and so on, until a leaf node is reached, i.e. a class that references |
| 70 | no other classes. |
| 71 | |
| 72 | Now, the merging starts. At every step, the list of applications and the set |
| 73 | of parameters at each level is merged into what has been accumulated so far. |
| 74 | |
| 75 | Merging of parameters is done "deeply", meaning that lists and dictionaries |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 76 | are extended (recursively), rather than replaced. However, a scalar value |
| 77 | *does* overwrite a dictionary or list value. While the scalar could be |
martin f. krafft | 6e0040d | 2014-06-04 12:24:18 +0200 | [diff] [blame^] | 78 | appended to an existing list, there is no sane default assumption in the |
| 79 | context of a dictionary, so this behaviour seems the most logical. Plus, it |
| 80 | allows for a dictionary to be erased by overwriting it with the null value. |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 81 | |
martin f. krafft | f432053 | 2013-11-30 17:00:37 +0100 | [diff] [blame] | 82 | After all classes (and the classes they reference) have been visited, |
| 83 | |reclass| finally merges the applications list and parameters defined for the |
| 84 | node into what has been accumulated during the processing of the classes, and |
| 85 | returns the final result. |
| 86 | |
martin f. krafft | 3b10e80 | 2013-11-26 23:30:10 +0100 | [diff] [blame] | 87 | Wildcard/Regexp mappings |
| 88 | ------------------------ |
| 89 | Using the :doc:`configuration file <configfile>`, it is also possible to |
| 90 | provide a list mappings between node names and classes. For instance:: |
| 91 | |
| 92 | class_mappings: |
| 93 | - \* default |
| 94 | - /^www\d+/ webserver |
| 95 | - \*.ch hosted@switzerland another_class_to_show_that_it_can_take_lists |
| 96 | |
| 97 | This will assign the ``default`` class to all nodes (make sure to escape |
| 98 | a leading asterisk (\*) to keep YAML happy), ``webserver`` to all nodes named |
| 99 | ``www1`` or ``www999``, and ``hosted-in-switzerland`` to all nodes whose names |
| 100 | end with ``.ch`` (again, note the escaped leading asterisk). Multiple classes |
| 101 | can be assigned to each mapping by providing a space-separated list (class |
| 102 | names cannot contain spaces anyway). |
| 103 | |
martin f. krafft | 010ea27 | 2013-11-27 14:08:28 +0100 | [diff] [blame] | 104 | .. warning:: |
| 105 | |
| 106 | The class mappings do not really belong in the configuration file, as they |
| 107 | are data, not configuration inmformation. Therefore, they are likely going |
| 108 | to move elsewhere, but I have not quite figured out to where. Most likely, |
| 109 | there will be an additional file, specified in the configuration file, which |
| 110 | then lists the mappings. |
| 111 | |
martin f. krafft | 2e233ed | 2013-11-27 13:50:56 +0100 | [diff] [blame] | 112 | Note that mappings are not designed to replace node definitions. Mappings can |
| 113 | be used to pre-populate the classes of existing nodes, but you still need to |
| 114 | define all nodes (and if only to allow them to be enumerated for the |
| 115 | inventory). |
| 116 | |
martin f. krafft | 41521eb | 2013-11-27 14:06:37 +0100 | [diff] [blame] | 117 | The mapped classes can also contain backreferences when regular expressions |
| 118 | are used, although they need to be escaped, e.g.:: |
| 119 | |
| 120 | class_mappings: |
| 121 | - /\.(\S+)$/ tld-\\1 |
| 122 | |
martin f. krafft | 05cbf6b | 2013-11-28 13:36:29 +0100 | [diff] [blame] | 123 | Furthermore, since the outer slashes ('/') are used to "quote" the regular |
martin f. krafft | 37b56b6 | 2013-12-10 16:04:52 +0100 | [diff] [blame] | 124 | expression, *any* slashes within the regular expression must be escaped. For |
| 125 | instance, the following class mapping assigns a ``subdir-X`` class to all |
Daniel Dehennin | 02550e4 | 2013-12-27 09:38:14 +1300 | [diff] [blame] | 126 | nodes that are defined in a subdirectory (using yaml_fs):: |
martin f. krafft | 05cbf6b | 2013-11-28 13:36:29 +0100 | [diff] [blame] | 127 | |
| 128 | class_mappings: |
martin f. krafft | 37b56b6 | 2013-12-10 16:04:52 +0100 | [diff] [blame] | 129 | - /^([^\/]+)\// subdir-\\1 |
martin f. krafft | 05cbf6b | 2013-11-28 13:36:29 +0100 | [diff] [blame] | 130 | |
martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 131 | Parameter interpolation |
| 132 | ------------------------ |
| 133 | Parameters may reference each other, including deep references, e.g.:: |
| 134 | |
| 135 | parameters: |
| 136 | location: Munich, Germany |
| 137 | motd: |
| 138 | header: This node sits in ${location} |
| 139 | for_demonstration: ${motd:header} |
| 140 | dict_reference: ${motd} |
| 141 | |
| 142 | After merging and interpolation, which happens automatically inside the |
| 143 | storage modules, the ``for_demonstration`` parameter will have a value of |
| 144 | "This node sits in Munich, Germany". |
| 145 | |
| 146 | Types are preserved if the value contains nothing but a reference. Hence, the |
| 147 | value of ``dict_reference`` will actually be a dictionary. |
| 148 | |
| 149 | You should now be ready to :doc:`use reclass <usage>`! |
| 150 | |
| 151 | .. include:: substs.inc |