vRA SaltStack Config – Top Files

So far we played with Salt State files to apply configurations to Minions and we learned that these are generic by design and describe only what configuration should be achieved. And we used the concept of Targeting to specify where one, or more, State should be applied.

In this post I’ll try to cover a different file, called the Top file, that brings together States and Targeting, that is what and where configurations should be applied. States and the Top file work together to create the core of SaltStack’s configuration management capability.

Top Files

A Top file is used to apply multiple State files to your Salt Minions, this action is also called a highstate. The States that are applied to each system are determined by the targets that are specified in the Top file.

A Top file has three elements:

  • Environment: that is the saltenv, a state tree directory containing a set of State files to configure Minions;
  • Target: a grouping of Minions which will have a set of states applied to them;
  • State files: a list of State files to be applied to a target. Each State file describes one or more configuration to be enforced on the targeted Minions.

The relationship between these three components is nested as follows:

  • Environments contain Targets
  • Targets contain States

Here below there is a very basic Top file to introduce the structure just described.

base:          # Apply SLS files for the 'base' environment
  'web*':      # All minions with a minion_id that begins with 'web'
    - apache   # Apply the state file apache

When Top file is applied, each Salt Minion is matched against the targets listed in the top.sls file. When a Salt Minion matches a target, it receives all of the State files defined in the list underneath that target.

Top File Example

In my opinion, Top file is one of those things that are best learned by example. Instead of further elaborating and digging into details, here after there is a simple Top file and further below we will go through each section.

    - /config/users
    - /config/scripts
    - /applications/nginx
    - match: grain
    - /applications/mongodb

All Minions get applied users and scripts States

    - /config/users
    - /config/scripts

Every Minion having the string web in the ID gets applied with the ngninx State file

    - /applications/nginx

Every Minion having grain application : mongodb get applied mongodb State file. In a Top file you can use all the advanced targeting capabilities made available by SaltStack as documented here.

    - match: grain
    - /applications/mongodb

Wait! I forgot the very first thing in our example! The base at the begin of the Top file identifies the applicable saltenv environment. You can have multiple environment sections in your Top file, of course all the states that you use within an environment section have to exists in that environment.

Get Started with Top Files

Before you get started with Top file you need to make sure file_roots property is defined for all your environments in the master configuration file, the following is what I have in my SaltStack deployment. Make sure to adjust root path as per your environment specifics as this is the place where you will store your Top file.

     - /srv/salt

Place your Top file in the specified path: /srv/salt/top.sls. Please, note that top.sls is a kind of special name. Top files are named top.sls by default and they are so-named because they always exist in the “top” of a directory hierarchy that contains state files. That directory hierarchy is called a state tree.

To apply a Top file you can simply use one of the the following commands:

salt '*' state.apply

In the example above we are using the state.apply command that we already know, calling state.apply with no arguments starts a highstate (the highstate is the action to apply Top file). Alternatively we can explicitly use the state.highstate command as reported below.

salt '*' state.highstate

If you are in a multiple environments Saltstack deployment you can use the saltenv argument to set the saltenv for the highstate.

salt '*' state.apply saltenv=dev
salt '*' state.highstate saltenv=test

Lab Time!

In my lab I have some minions, but for this activity I will restrict the scope to 3 minions having the string secops in their Minion IDs. One of them has a grain application:nginx.

My Top file is reported below. Please, note that specifying match: compound is redundant as Compound is the default matcher for Top files.

    - /config/users
  'G@os:CentOS and G@application:apache':
    - match: compound
    - /applications/apache
  'G@os:CentOS and G@application:nginx':
    - match: compound
    - /applications/nginx
  'G@os:CentOS and G@application:mysql':
    - match: compound
    - /applications/mysql
  'G@os:CentOS and G@application:mongodb':
    - match: compound
    - /applications/mongodb

Applying my Top file to the 3 Minions in scope of this activity enforces users to be present on any Minions and than install nginx on the centos-secops.iberia.local. User’s State file creates 3 local users by collecting data from a map file and using Jinja2 templating (I’ll cover templating and State files parameterization in a future post).

{% from 'config/users/map.jinja' import users with context %}

{% for user in users %}
add_user_{{ user.username }}:
    - name: {{ user.username }}
    - uid: {{ user.uid }}
    - password: {{ user.password }}

{% endfor %}

Here is the map.jinja file:

{% set users = [
    {'username': 'luca', 'uid': 2001, 'password': 'be3bed2f000aae03f8cf880d77507e028280fb692a1e3b16cd3afb053e5ff30c'},
    {'username': 'marco', 'uid': 2002, 'password': 'be3bed2f000aae03f8cf880d77507e028280fb692a1e3b16cd3afb053e5ff30c'},
    {'username': 'pietro', 'uid': 2003, 'password': 'be3bed2f000aae03f8cf880d77507e028280fb692a1e3b16cd3afb053e5ff30c'},

The Nginx’s State file includes 3 state IDs: install epel as it is a pre-requisites for Nginx, install Nginx and start Nginx.

# Install NGINX on CentOS/RHEL

    - name: epel-release

    - name: nginx
    - requres:
      - install_epel_release

    - name: nginx
    - enable: True
    - requires:
      - install_nginx

Here is the CLI command and some section of the return:

The ubuntu-secops.iberia.local has 3 succeeded states as it get applied to User’s State file only (a state for each user).

Also the windows-secops.iberia.local has 3 succeeded states as it get applied to User’s state file only (a state for each user).

The centos-secops.iberia.local has 6 succeeded states as it get applied to User’s State file (a state for each user) and the Nginx’s State file (that is made up of 3 state IDs).

This is post just provides the very basic to get started with Top files, you can use the snippets included in this post to replicate this in your lab and surely you can improve it! I hope this can help you in your Salt exploration journey.