yet.org

Using Salt with reclass

Now that data center are software driven, it is crucial to have a single source of truth, a kind of know all inventory about your resources, your nodes, their functions and their associated parameters, which describe everything and store it in a single location. Welcome reclass which use Class inheritance to define nodes roles and avoid duplication by gathering all important datacenter parameters in a central location. All of this will then be used by your automation tools like Salt, Ansible or Puppet to bootstrap your infrastructure as a software. In other words, reclass can be classified as a hierarchical inventory management solution. Let see how we could use it with Salt.

reclass is an open source software released by Martin F. Krafft under the Artistic License 2.0. It can be categorized as an External Node Classifier and it provides information about your nodes, such as variables and the application they should be running. reclass has the ability to merge data sources hierarchically, it allow us to say, this node has this behaviour, or this node has a certain number of classes and these parameters.

Configuration Management System use the following Data:

  • What application should a role have ?
  • How does this node differ from all other nodes that have the same application (parameters) ?
  • Which nodes belong to a group (nodegroup, clusters) ?

reclass help to organize and store all of this without having to rely on any specific configuration management features but plug into them and provide the data they need to let them provision your infrastructure.

Installation

reclass is packaged for Debian/Ubuntu, so the installation is as simple as

apt-get install reclass reclass-doc

But it could also be installed from source on other operating systems.

Configuration

reclass configure is stored in ~/reclass-config.yml, the main thing you have to configure is the inventory directory

inventory_base_uri: /srv/salt/reclass

If not specified reclass will look for nodes and classes directories into /etc/reclass/ but when running reclass command line, you can also use the following argument instead -b inventory_base_uri.

Concepts

The main reclass concept are

  • node - usually a server in your infrastructure
  • class - A category, tag, feature, or role that applies to a node. Classes may be nested, form a class hierarchy
  • application - behaviour to apply to a node
  • parameter - Node-specific variables, with inheritance throughout the class hierarchy

When asked for information, reclass will parse the class or node definition and recurses to his parent before anything else and then merge everything. Because the merging happens late in the process, a node or any class may override any of the data defined by its ancestors.

data structure

By default, reclass store all the required information in YAML* files by leveraging its yaml_fs storage backend. But the storage backend is pluggable. Remote FS* is another example of a different backend contributed by Michael Kutý.

keywords

reclass YAML files contains the following keywords that implement the above concepts

  • classes - a list of parent class (e.g. web_server, debian_server).
  • applications - list of applications to append to applications defined in ancestors, ~remove this application from the list (e.g. nginx, ssh_client).
  • parameters - key-value pairs which set defaults in class definitions (e.g. ipaddr = 192.0.2.1, nginx_port = 8080).
  • environment - only relevant for nodes, this allows to specify an “environment” into which the node definition is supposed to be place (e.g. production, staging, devel).

directories structure

reclass store all of its files in two directories below the inventory root

  • /srv/salt/reclass/nodes - node definition
  • /srv/salt/reclass/classes - classes definition

inheritance

Nodes and classes files may specify classes to inherit. To give you an example, let me rewrite the etcd cluster example I used in my previous article about Salt formulas. Instead of relying on Pillar and Top files, lets create classes and nodes YAML file to describe our cluster.

A etcd node declaration looks like that

nodes/saltstack-m01.yml

environment: base
classes:
  - common
  - etcd-cluster
parameters:
  hostname: saltstack-m01
  ip_address: 172.16.52.101

Create the same for both saltstack-m02, saltstack-m03 nodes with updated IP and hostname.

classes/common.yml

applications:
  - hostfile
  - tools
parameters:
  linux:
    system:
      name: ${hostname}

In the classe above I declare that the nodes that inherit from it will have 2 applications and one parameters available to them.

classes/etcd-cluster.yml

applications:
  - etcd
parameters:
  etcd:
    server:
      enabled: true
      bind:
        host: ${ip_address}
      token: $(uuidgen)
      members:
      - host: 172.16.52.101
        name: saltstack-m01
        port: 4001
      - host: 172.16.52.102
        name: saltstack-m02
        port: 4001
      - host: 172.16.52.103
        name: saltstack-m03
        port: 4001

Parameters can also be overwritten, the last evaluated classe can redefine any previously defined ones.

namespaces

reclass files are stored in directories that can reflect namespaces for classes. For example, a class named ssh.server will be read from ssh/server.yaml, if you specify only ssh, the lookup will happen for ssh/init.yaml or ssh.yml, but only one of the two can exist.

parameter interpolation

In our class definition above, ${ip_address} will be interpolated at merging time from the information available in the node declaration.

Merging

Before running the above example, one more thing, keep in mind that:

  • List are append only
  • Dictionaries are merged deeply
  • Only scalars are replaced, the one which stay is the one which comes the last.

Lets now run our example with

$ reclass -n saltstack-m01
__reclass__:
  environment: base
  name: saltstack-m01
  node: ./saltstack-m01
  timestamp: Thu Oct  6 14:48:20 2016
  uri: yaml_fs:///srv/salt/reclass/nodes/./saltstack-m01.yml
applications:
- hostfile
- tools
- etcd
classes:
- common
- etcd-cluster
environment: base
parameters:
  etcd:
    server:
      bind:
        host: 172.16.52.101
      enabled: true
      members:
      - host: 172.16.52.101
        name: saltstack-m01
        port: 4001
      - host: 172.16.52.102
        name: saltstack-m02
        port: 4001
      - host: 172.16.52.103
        name: saltstack-m03
        port: 4001
      token: $(uuidgen)
  hostname: saltstack-m01
  ip_address: 172.16.52.101
  linux:
    system:
      name: saltstack-m01

As you can confirm above, ip_address and hostname parameters have been interpolated.

To get the overall inventory use

$ reclass -i

You can also look at a provided inventory exemple

$ reclass -b /usr/share/doc/reclass/examples/ --inventory

salt adapters

reclass Adapters interface between configuration management system and reclass. Such an adapter exist for Salt, this adapter has been integrated to Salt as a module since release 0.16.0. The module provides top and Pillar data. On a Debian system installed from packages, you’ll find both adapters at the following location

  • /usr/lib/python2.7/dist-packages/salt/tops/reclass_adapter.py
  • /usr/lib/python2.7/dist-packages/salt/pillar/reclass_adapter.py.

You can check the exact location on your debian master with

dpkg -S reclass_adapter.py

By using these two bundled reclass adapters, Salt can retrieve Salt States for each host by querying Reclass applications instead of a top.sls file. Salt can also retrieve Pillar data from reclass parameters.

So here is a corresponding map between reclass concepts and Salt ones

  • reclass nodes -> salt minion
  • reclass applications -> Salt States
  • reclass parameters -> Salt Pillars
  • environment -> environment

Installation

To ease the troubleshooting you can create a symlink to use a python module in charge of converting reclass data to salt data structure

ln -s /usr/lib/python2.7/dist-packages/reclass/adapters/salt.py /usr/local/sbin/salt-reclass
chmod +x /usr/lib/python2.7/dist-packages/reclass/adapters/salt.py

Let’s try it

$ salt-reclass --top
base:
  saltstack-m01:
  - hostfile
  - tools
  - etcd
  saltstack-m02:
  - hostfile
  - tools
  - etcd
  saltstack-m03:
  - hostfile
  - tools
  - etcd

And to get Pillar data

$ salt-reclass --pillar saltstack-m01
__reclass__:
  applications:
  - hostfile
  - tools
  - etcd
  classes:
  - common
  - etcd-cluster
  environment: base
  nodename: saltstack-m01
etcd:
  server:
    bind:
      host: 172.16.52.101
    enabled: true
    members:
    - host: 172.16.52.101
      name: saltstack-m01
      port: 4001
    - host: 172.16.52.102
      name: saltstack-m02
      port: 4001
    - host: 172.16.52.103
      name: saltstack-m03
      port: 4001
    token: $(uuidgen)
hostname: saltstack-m01
ip_address: 172.16.52.101
linux:
  system:
    name: saltstack-m01

The output looks pretty much the same as the one obtained from reclass cli but the parameters are in the beginning now, this is what expect Salt and the adapter makes sure everything looks good to salt by massaging data.

Configure your Salt Master to use reclass

To tell your Salt Master to use reclass as its external inventory, add the following line in its configuration file

$ vi /etc/salt/master
reclass: &reclass
  storage_type: yaml_fs
  inventory_base_uri: /srv/salt/reclass

ext_pillar:
  - reclass: *reclass

master_tops:
  reclass: *reclass

Restart your salt-master

service salt-master restart

You also need to make sure that you don’t have any more top.sls file in your Salt root directory. Also make sure you comment out the pillar_roots section in the master configuration file.

You should be able to see reclass information from salt

$ salt \*m01 state.show_top
saltstack-m01:
    ----------
    base:
        - hostfile
        - tools
        - etcd

$ salt \*m01 pillar.items
saltstack-m01:
   [...]
   etcd:
       ----------
       server:
           ----------
           bind:
               ----------
               host:
                   172.16.52.101
           enabled:
               True
           members:
               |_
                 ----------
                 host:
                     172.16.52.101
                 name:
                     saltstack-m01
                 port:
                     4001
               |_
                 ----------
                 host:
                     172.16.52.102
                 name:
                     saltstack-m02
                 port:
                     4001
               |_
                 ----------
                 host:
                     172.16.52.103
                 name:
                     saltstack-m03
                 port:
                     4001
           token:
               $(uuidgen)
   hostname:
       saltstack-m01
   ip_address:
       172.16.52.101
   linux:
       ----------
       system:
           ----------
           name:
               saltstack-m01

Congrat, you’ve connected reclass and Salt !!!

Apply the state

The last step is now to apply the states inherited from reclass applications to our minion, it’s just a standard salt state.apply command

salt \*m0* state.apply
[...]
------------
Succeeded: 6
Failed:    0
------------
Total states run:     6
Total run time:  30.248 s

You should now have a working etcd cluster.

Conclusion

Parametrisation of your infrastructure is key, if you can extract the difference between your nodes and store it within reclass, it will help when you’ll have to change servers, reinstall your application on a new infrastructure, etc…

reclass just assemble and provide the data, it doesn’t do any modification on your hosts which aren’t even aware of its existence. It is actually just on abstraction layer on top of other configuration management systems. It is a single data source that can be used with multiple systems. So you can easily switch from one technology to another, from Puppet to Salt, all your data stays within reclass. You can also use the same data with multiple systems at the same time.

reclass was originally written for Puppet and is pretty much similar to Hiera a key/value lookup tool for configuration data. But it was rewritten from scratch in 2013, so now there isn’t any adapter for it but you can easily use it with Salt (adapter module) or Ansible (script).

  • reclass on github
  • Infrastructure management using Salt and Reclass article

Video

  • Recursive inventory management presentation from Martin F. Krafft the creator of reclass.
  • Hierarchical infrastructure description for your system management needs presentation - pretty similar to the previous one.

Documentation