| 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 | 
 | 78 | appended to an existing list, there is sane default assumption in the context | 
 | 79 | of a dictionary, so this behaviour seems the most logical. | 
 | 80 |  | 
| martin f. krafft | f432053 | 2013-11-30 17:00:37 +0100 | [diff] [blame] | 81 | After all classes (and the classes they reference) have been visited, | 
 | 82 | |reclass| finally merges the applications list and parameters defined for the | 
 | 83 | node into what has been accumulated during the processing of the classes, and | 
 | 84 | returns the final result. | 
 | 85 |  | 
| martin f. krafft | 3b10e80 | 2013-11-26 23:30:10 +0100 | [diff] [blame] | 86 | Wildcard/Regexp mappings | 
 | 87 | ------------------------ | 
 | 88 | Using the :doc:`configuration file <configfile>`, it is also possible to | 
 | 89 | provide a list mappings between node names and classes. For instance:: | 
 | 90 |  | 
 | 91 |   class_mappings: | 
 | 92 |     - \* default | 
 | 93 |     - /^www\d+/ webserver | 
 | 94 |     - \*.ch hosted@switzerland another_class_to_show_that_it_can_take_lists | 
 | 95 |  | 
 | 96 | This will assign the ``default`` class to all nodes (make sure to escape | 
 | 97 | a leading asterisk (\*) to keep YAML happy), ``webserver`` to all nodes named | 
 | 98 | ``www1`` or ``www999``, and ``hosted-in-switzerland`` to all nodes whose names | 
 | 99 | end with ``.ch`` (again, note the escaped leading asterisk). Multiple classes | 
 | 100 | can be assigned to each mapping by providing a space-separated list (class | 
 | 101 | names cannot contain spaces anyway). | 
 | 102 |  | 
| martin f. krafft | 010ea27 | 2013-11-27 14:08:28 +0100 | [diff] [blame] | 103 | .. warning:: | 
 | 104 |  | 
 | 105 |   The class mappings do not really belong in the configuration file, as they | 
 | 106 |   are data, not configuration inmformation. Therefore, they are likely going | 
 | 107 |   to move elsewhere, but I have not quite figured out to where. Most likely, | 
 | 108 |   there will be an additional file, specified in the configuration file, which | 
 | 109 |   then lists the mappings. | 
 | 110 |  | 
| martin f. krafft | 2e233ed | 2013-11-27 13:50:56 +0100 | [diff] [blame] | 111 | Note that mappings are not designed to replace node definitions. Mappings can | 
 | 112 | be used to pre-populate the classes of existing nodes, but you still need to | 
 | 113 | define all nodes (and if only to allow them to be enumerated for the | 
 | 114 | inventory). | 
 | 115 |  | 
| martin f. krafft | 41521eb | 2013-11-27 14:06:37 +0100 | [diff] [blame] | 116 | The mapped classes can also contain backreferences when regular expressions | 
 | 117 | are used, although they need to be escaped, e.g.:: | 
 | 118 |  | 
 | 119 |   class_mappings: | 
 | 120 |     - /\.(\S+)$/ tld-\\1 | 
 | 121 |  | 
| martin f. krafft | 05cbf6b | 2013-11-28 13:36:29 +0100 | [diff] [blame] | 122 | Furthermore, since the outer slashes ('/') are used to "quote" the regular | 
| martin f. krafft | 37b56b6 | 2013-12-10 16:04:52 +0100 | [diff] [blame] | 123 | expression, *any* slashes within the regular expression must be escaped. For | 
 | 124 | instance, the following class mapping assigns a ``subdir-X`` class to all | 
| Daniel Dehennin | 02550e4 | 2013-12-27 09:38:14 +1300 | [diff] [blame] | 125 | nodes that are defined in a subdirectory (using yaml_fs):: | 
| martin f. krafft | 05cbf6b | 2013-11-28 13:36:29 +0100 | [diff] [blame] | 126 |  | 
 | 127 |   class_mappings: | 
| martin f. krafft | 37b56b6 | 2013-12-10 16:04:52 +0100 | [diff] [blame] | 128 |     - /^([^\/]+)\// subdir-\\1 | 
| martin f. krafft | 05cbf6b | 2013-11-28 13:36:29 +0100 | [diff] [blame] | 129 |  | 
| martin f. krafft | 8acd49d | 2013-08-26 21:22:25 +0200 | [diff] [blame] | 130 | Parameter interpolation | 
 | 131 | ------------------------ | 
 | 132 | Parameters may reference each other, including deep references, e.g.:: | 
 | 133 |  | 
 | 134 |   parameters: | 
 | 135 |     location: Munich, Germany | 
 | 136 |     motd: | 
 | 137 |       header: This node sits in ${location} | 
 | 138 |     for_demonstration: ${motd:header} | 
 | 139 |     dict_reference: ${motd} | 
 | 140 |  | 
 | 141 | After merging and interpolation, which happens automatically inside the | 
 | 142 | storage modules, the ``for_demonstration`` parameter will have a value of | 
 | 143 | "This node sits in Munich, Germany". | 
 | 144 |  | 
 | 145 | Types are preserved if the value contains nothing but a reference. Hence, the | 
 | 146 | value of ``dict_reference`` will actually be a dictionary. | 
 | 147 |  | 
 | 148 | You should now be ready to :doc:`use reclass <usage>`! | 
 | 149 |  | 
 | 150 | .. include:: substs.inc |