Setup for a SaltStack Vagrant Environment

Often when writing Salt related code, I need an environment in which ideas can quicly be tested and interated upon. I have found that Vagrant is usually suited perfectly for filling this need. If you want to use Vagrant as well, first you’ll need to install it from the VagrantUp Hashicorp website.

The idea here is to create an environment with a single master and minion from which changes to Salt formulas, modules, pillars, orchs, beacons, engines, etc. can quickly and easily be tested.

Setting Up Vagrant

Because I like to break out my Vagrant environments based on the project or environment for which I need to work on, I create the directory ~/Documents/vagrant/salt and then change to it and run vagrant init.

Inside this directory, I need a few files:


Vagrant is Ruby based, and the Vagrantfile is also Ruby based. Meaning it can be glommed onto for things we want or need. In my case, I used a Vagrantfile derived from

# -*- mode: ruby -*-
# vi: set ft=ruby :

require 'yaml'
hosts = YAML.load_file('vagrant_hosts.yml')

# Set options for the network interface configuration. All values are
# optional, and can include:
# - ip (default = DHCP)
# - netmask (default value =
# - mac
# - auto_config (if false, Vagrant will not configure this network interface
# - intnet (if true, an internal network adapter will be created instead of a
# host-only adapter)
def network_options(host)
options = {}
if host.has_key?('ip')
options[:ip] = host['ip']
options[:netmask] = host['netmask'] ||= ''
options[:type] = 'dhcp'

if host.has_key?('mac')
options[:mac] = host['mac'].gsub(/[-:]/, '')
if host.has_key?('auto_config')
options[:auto_config] = host['auto_config']
if host.has_key?('intnet') && host['intnet']
options[:virtualbox__intnet] = true

def box_choice(host)
choice = ''
if host.has_key?('box')
choice = host['box']
choice = 'centos/7'

$script = <<-SCRIPT
sudo yum -y install python3
sudo ln -s /srv/salt /etc/salt

Vagrant.configure("2") do |config|
hosts.each do | host |
if host.has_key?('sync_folder')
config.vm.synced_folder host['sync_folder']['host'], host['sync_folder']['guest'], type: 'nfs'
config.vm.define host['name'] do | node | = box_choice(host)
node.vm.hostname = host['name'] :private_network, network_options(host)
node.vm.provider :virtualbox do | vb | = host['name']
vb.cpus = host['cpus'] ||= 1
vb.memory = host['memory'] ||= 512

if host.has_key?('sync_folder')
node.vm.provision 'shell',
inline: $script

node.vm.provision :salt do | salt |
if host.has_key?('sync_folder')
salt.master_config = 'salt_master_config'
salt.bootstrap_script = ''
salt.bootstrap_options = '-M'
salt.python_version = '3'
salt.minion_config = 'salt_minion_config'
salt.run_highstate = false
salt.bootstrap_script = ''
salt.install_type = 'stable'
salt.install_args = '2019.2'

Salt-Bootstrap Script

The salt-bootstrap script should be retrieved directly from the SaltStack project with:

curl -o -L

Salt-Master Config

The salt master config I use is usually exactly the same as the one I use in production just stripped of comments to make for easier deciphering.

grep -v '^$\|^#' master > salt_master_config

Salt-Minion Config

The minion config is about a simple as I can make it.

file_client: remote
hash_type: sha512

Vagrant Hosts YAML

This is just a YAML file that describes the instances I want built for this environment.

- name: minion1
cpu: 1
memory: 1024
box: centos/7
- name: master1
cpu: 1
memory: 1024
box: centos/7
host: "~/Documents/salt-master-configuration"
guest: "/srv/salt"

The magic in this setup is:


For this particular setup, the entirety of the Salt configuration is contained in the salt-master-configuration directory. This is forumlas, pillars, everything.

Using Vagrant

If all the pieces are in place, just run vagrant up and the machines will be created. Once they are running, you can access them with vagrant ssh master1 or vagrant ssh minion1.

Typically, while I’m using this set up, I have an editor with the Salt related code I’m working on open as well as a terminal window with an SSH connection to minion1 running in Vagrant. Because Vagrant has setup an NFS mount between the salt-master-configuration directory on my laptop and the master1 instance, as I make changes in the file in the editor, I can use salt-call on the minion to check the effect.

Originally published at on September 8, 2020.

Climber, surfer, yogi, dad who does some IT on the side to get by.

Love podcasts or audiobooks? Learn on the go with our new app.