reclass assumes a node-centric perspective into your inventory. This is obvious when you query reclass for node-specific information, but it might not be clear when you ask reclass to provide you with a list of groups. In that case, reclass loops over all nodes it can find in its database, reads all information it can find about the nodes, and finally reorders the result to provide a list of groups with the nodes they contain.
Since the term “groups” is somewhat ambiguous, it helps to start off with a short glossary of reclass-specific terminology:
|node||A node, usually a computer in your infrastructure|
|class||A category, tag, feature, or role that applies to a node Classes may be nested, i.e. there can be a class hierarchy|
|application||A specific set of behaviour to apply|
|parameter||Node-specific variables, with inheritance throughout the class hierarchy.|
A class consists of zero or more parent classes, zero or more applications, and any number of parameters.
A class name must not contain spaces.
A node is almost equivalent to a class, except that it usually does not (but can) specify applications.
When reclass parses a node (or class) definition and encounters a parent class, it recurses to this parent class first before reading any data of the node (or class). When reclass returns from the recursive, depth first walk, it then merges all information of the current node (or class) into the information it obtained during the recursion.
Furthermore, a node (or class) may define a list of classes it derives from, in which case classes defined further down the list will be able to override classes further up the list.
Information in this context is essentially one of a list of applications or a list of parameters.
The interaction between the depth-first walk and the delayed merging of data means that the node (and any class) may override any of the data defined by any of the parent classes (ancestors). This is in line with the assumption that more specific definitions (“this specific host”) should have a higher precedence than more general definitions (“all webservers”, which includes all webservers in Munich, which includes “this specific host”, for example).
Here’s a quick example, showing how parameters accumulate and can get replaced.
All “unixnodes” (i.e. nodes who have the unixnode class in their ancestry) have /etc/motd centrally-managed (through the motd application), and the unixnode class definition provides a generic message-of-the-day to be put into this file.
All descendants of the class debiannode, a descendant of unixnode, should include the Debian codename in this message, so the message-of-the-day is overwritten in the debiannodes class.
The node quantum.example.org (a debiannode) will have a scheduled downtime this weekend, so until Monday, an appropriate message-of-the-day is added to the node definition.
When the motd application runs, it receives the appropriate message-of-the-day (from quantum.example.org when run on that node) and writes it into /etc/motd.
At this point it should be noted that parameters whose values are lists or key-value pairs don’t get overwritten by children classes or node definitions, but the information gets merged (recursively) instead.
Similarly to parameters, applications also accumulate during the recursive walk through the class ancestry. It is possible for a node or child class to remove an application added by a parent class, by prefixing the application with ~.
Finally, reclass happily lets you use multiple inheritance, and ensures that the resolution of parameters is still well-defined. Here’s another example building upon the one about /etc/motd above:
quantum.example.org (which is back up and therefore its node definition no longer contains a message-of-the-day) is at a site in Munich. Therefore, it is a child of the class hosted@munich. This class is independent of the unixnode hierarchy, quantum.example.org derives from both.
In this example infrastructure, hosted@munich is more specific than debiannode because there are plenty of Debian nodes at other sites (and some non-Debian nodes in Munich). Therefore, quantum.example.org derives from hosted@munich _after_ debiannodes.
When an electricity outage is expected over the weekend in Munich, the admin can change the message-of-the-day in the hosted@munich class, and it will apply to all hosts in Munich.
However, not all hosts in Munich have /etc/motd, because some of them are of class windowsnode. Since the windowsnode ancestry does not specify the motd application, those hosts have access to the message-of-the-day in the node variables, but the message won’t get used…
… unless, of course, windowsnode specified a Windows-specific application to bring such notices to the attention of the user.
It’s also trivial to ensure a certain order of class evaluation. Here’s another example:
The ssh.server class defines the permit_root_login parameter to no.
The backuppc.client class defines the parameter to without-password, because the BackupPC server might need to log in to the host as root.
Now, what happens if the admin accidentally provides the following two classes?
Theoretically, this would mean permit_root_login gets set to no.
However, since all backuppc.client nodes need ssh.server (at least in most setups), the class backuppc.client itself derives from ssh.server, ensuring that it gets parsed before backuppc.client.
When reclass returns to the node and encounters the ssh.server class defined there, it simply skips it, as it’s already been processed.
Now read about reclass operations!