Overview
In my previous articles I looked at what SaltStack Config is, how it relates to Salt and how you define a configuration to be applied to workloads (Salt Minions). In this latest article I’m going to build on that, looking at building roles that describe a Target and the configurations that should be applied based on a role.
There are several approaches to applying configurations to Minions so I’ll start off with the most basic method and go from there.
SaltStack Config Targets & Jobs
SaltStack Config has the capability to define multiple types of configuration items but in this context I’m going to cover Targets and Jobs which are part of the product foundation.
A Target is a group of one or more Minions. How you choose which Minions make up the Target is up to you. It could be based on Minion ID, Grain values, static lists of Minions or a compound of lots of different criteria put together. In addition criteria logic operators can also be leveraged allowing AND, OR and NOT operators to be used.
The Target definition is a SaltStack Config only item. In other words you can use open source Salt to supply all the same criteria that describe your targets at Salt execution time but the actual definition of a Target (which is stored and can be repeatedly re-used without having to re-type it) is specific to SaltStack Config.
Here’s an example Target definition within SaltStack Config. I’m looking for all the Minions that have a Grain called “dc” that’s value is “london” AND the Minion ID must start with an “s”. The “Glob” function allows us to perform pattern matching on the Minion ID itself using a selection of restricted characters.

If you were to transfer this target criteria to applying a state using open source Salt then the command would look like this (you can find a list of command line matching options here https://docs.saltproject.io/en/latest/topics/targeting/compound.html).
salt -C 'G@dc:london and s*' nameofstate.sls
The SaltStack Config Target will then be displayed as a new grouping under “Minions”. The configuration of the Target can be amended at any time in order to change the matching criteria.

Once there’s a Target defined you can link a Job to it. I briefly touched on Jobs when I was talking about States in my last article so lets do a quick re-cap.
A Job definition is specific to SaltStack Config. It takes a Target and maps it to a Function which may be to apply a State or execute one of many specific tasks along with any required arguments. Open source Salt jobs are all defined at runtime (see example command line above) and not stored for re-execution. Once a Job has been defined that includes a Target then that Job can only be used for that Target (unless the Job definition is edited). A Job with no defined Target can be run against any Target by choosing the Target at runtime.
If you imagine that a Target could represent a type of workload, maybe a web server or database platform for example then linking a Job to that Target allows all Minions that become a member of that Target to receive the same configuration as they would apply the same States. The limitation with this method is that the Job only allows for a single State to be added. What if you have multiple State files built up for lots of different types of configuration and your application servers need all of those states applying? Well in that case you have several options:
- Copy the contents of all your State files into a single state file
- Leveraging the “include” requisite in the State file you would add to your Job definition which allows the other needed State files to be linked to without duplicating their content
- Build a Top File to define role to state mappings
It is this last option that we will look at next.
Top Files
A Top File is just that, the top file in an Environment State directory tree and usually named “top.sls”. It defines States which should be run against Targets however as this is not a SaltStack Config specific option it cannot use the Targets that are stored within SaltStack Config. Top files are one of the core component of Salt.
Multiple Top files can exist when using different Environments (one file defined at the root of each Environment tree) however there are rules about how they are processed and merged and which files have precedence. I’ll go more into this as we go but first lets see what a Top File looks like.
This is an example Top file in its simplest form, written in YAML.
Example: #Environment name '*client*': #Target criteria - directory #State to apply - directory.file #State to apply
The Environment name maps to the Environment name on a fileserver. If you’re using the SaltStack Config fileserver then this would constitute a first level directory. The Target criteria relates to a range of pattern matching or matching done via Grains or other available data. In the above example we’re looking for all Minions that have ‘client’ in their Minion ID. Lastly we have the States that should be applied to the Targets in the order they should be applied.
Several sets of Target criteria and associated States can reside in the same Top file such as the following:
Example: #Environment name '*client*': #Target criteria - directory #State to apply - directory.file #State to apply 'G@dc:london': #Grain match - directory.file 'S@192.168.1.0/24':#Subnet match -directory.directory2.file 'os:CentOS': #Criteria - match: grain #Match method - directory.file
The last of the above examples is an alternative method of doing a match by specifying the criteria and matching method as 2 different parts of the YAML structure.
Once the Top File is created and stored in the root of the environment state tree then a Minion needs to be told to process it. This is done by applying a “Highstate” on the Minion. Applying a Highstate tells the Minion to fetch the Top file from the environment specified and then apply its contents for those parts that are relevant to it (i.e. the bits where the Target criteria match). This is done by either performing a “state.apply” function with no State specified or by using the “state.highstate” function. “state.apply” is the newest way and wraps “state.highstate” but either method will work.
In this example I am defining a Job in SaltStack Config to apply my Highstate. When the Job is run it will cause all Minions to process and apply the contents of the Top file in the “Example” environment. Notice there is no State file specified as it is implied that the Top File in the specified Environment will be used.

I can also apply the same Highstate in open source Salt via the Salt command as shown here. In this example I am specifying my Target for the Highstate as a single Minion with the “test=True”. This shows me what the configuration changes would look like without actually applying them (you can do the same via the SaltStack Config GUI as well).

The Top file I have used in the above example will apply the “Example/directory/file.sls” State which in turn will create a managed file called /tmp/exampleHighState.conf. The other green states shown are for states from other environments and Jobs that have already been applied to this Minion.
Hopefully this has given you an insight into some of the options available when matching States to Targets. In the next article I’ll be looking at Beacons and Reactors.