Getting Started With Vagrant

The Vagrant driver is a new, experimental driver for spinning up a VagrantBox virtual machine, and installing Salt on it.

Dependencies

The Vagrant driver itself has no external dependencies.

The machine which will host the VagrantBox must be an already existing minion of the cloud server's Salt master. It must have Vagrant installed, and a Vagrant-compatible virtual machine engine, such as VirtualBox. (Note: The Vagrant driver does not depend on the salt-cloud VirtualBox driver in any way.)

[Caution: The version of Vagrant packaged for apt install in Ubuntu 16.04 will not connect a bridged network adapter correctly. Use a version downloaded directly from the web site.]

Include the Vagrant guest editions plugin: vagrant plugin install vagrant-vbguest.

Configuration

Configuration of the client virtual machine (using VirtualBox, VMware, etc) will be done by Vagrant as specified in the Vagrantfile on the host machine.

Salt-cloud will push the commands to install and provision a salt minion on the virtual machine, so you need not (perhaps should not) provision salt in your Vagrantfile, in most cases.

If, however, your cloud master cannot open an SSH connection to the child VM, you may need to let Vagrant provision the VM with Salt, and use some other method (such as passing a pillar dictionary to the VM) to pass the master's IP address to the VM. The VM can then attempt to reach the salt master in the usual way for non-cloud minions. Specify the profile configuration argument as deploy: False to prevent the cloud master from trying.

# Note: This example is for /etc/salt/cloud.providers file or any file in
# the /etc/salt/cloud.providers.d/ directory.

my-vagrant-config:
  minion:
    master: 111.222.333.444
  provider: vagrant

Because the Vagrant driver needs a place to store the mapping between the node name you use for Salt commands and the Vagrantfile which controls the VM, you must configure your salt minion as a Salt smb server. (See host provisioning example below.)

Profiles

Vagrant requires a profile to be configured for each machine that needs Salt installed. The initial profile can be set up at /etc/salt/cloud.profiles or in the /etc/salt/cloud.profiles.d/ directory.

Each profile requires a vagrantfile parameter. If the Vagrantfile has definitions for multiple machines then you need a machine parameter,

Salt-cloud uses SSH to provision the minion. There must be a routable path from the cloud master to the VM. Usually, you will want to use a bridged network adapter for SSH. The address may not be known until DHCP assigns it. If ssh_host is not defined, and target_network is defined, the driver will attempt to read the address from the output of an ifconfig command. Lacking either setting, the driver will try to use the value Vagrant returns as its ssh_host, which will work only if the cloud master is running somewhere on the same host.

The target_network setting should be used to identify the IP network your bridged adapter is expected to appear on. Use CIDR notation, like target_network: '2001:DB8::/32' or target_network: '192.0.2.0/24'.

Profile configuration example:

# /etc/salt/cloud.profiles.d/vagrant.conf

vagrant-machine:
  host: my-vhost  # the Salt id of the virtual machine's host computer.
  provider: my-vagrant-config
  cwd: /srv/machines  # the path to your Vagrantfile.
  vagrant_runas: my-username  # the username who defined the Vagrantbox on the host
  # vagrant_up_timeout: 300 # (seconds) timeout for cmd.run of the "vagrant up" command
  # vagrant_provider: '' # option for "vagrant up" like: "--provider vmware_fusion"
  # ssh_host: None  # "None" means try to find the routable IP address from "ifconfig"
  # ssh_username: '' # also required when ssh_host is used.
  # target_network: None  # Expected CIDR address range of your bridged network
  # force_minion_config: false  # Set "true" to re-purpose an existing VM

The machine can now be created and configured with the following command:

salt-cloud -p vagrant-machine my-id

This will create the machine specified by the cloud profile vagrant-machine, and will give the machine the minion id of my-id. If the cloud master is also the salt-master, its Salt key will automatically be accepted on the master.

Once a salt-minion has been successfully installed on the instance, connectivity to it can be verified with Salt:

salt my-id test.version

Provisioning a Vagrant cloud host (example)

In order to query or control minions it created, each host minion needs to track the Salt node names associated with any guest virtual machines on it. It does that using a Salt sdb database.

The Salt sdb is not configured by default. The following example shows a simple installation.

This example assumes:

  • you are on a large network using the 10.x.x.x IP address space

  • your Salt master's Salt id is "bevymaster"

  • it will also be your salt-cloud controller

  • it is at hardware address 10.124.30.7

  • it is running a recent Debian family Linux (raspbian)

  • your workstation is a Salt minion of bevymaster

  • your workstation's minion id is "my_laptop"

  • VirtualBox has been installed on "my_laptop" (apt install is okay)

  • Vagrant was installed from vagrantup.com. (not the 16.04 Ubuntu apt)

  • "my_laptop" has done "vagrant plugin install vagrant-vbguest"

  • the VM you want to start is on "my_laptop" at "/home/my_username/Vagrantfile"

# file /etc/salt/minion.d/vagrant_sdb.conf on host computer "my_laptop"
#  -- this sdb database is required by the Vagrant module --
vagrant_sdb_data:  # The sdb database must have this name.
  driver: sqlite3  # Let's use SQLite to store the data ...
  database: /var/cache/salt/vagrant.sqlite  # ... in this file ...
  table: sdb  # ... using this table name.
  create_table: True  # if not present

Remember to re-start your minion after changing its configuration files...

sudo systemctl restart salt-minion

# -*- mode: ruby -*-
# file /home/my_username/Vagrantfile on host computer "my_laptop"
BEVY = "bevy1"
DOMAIN = BEVY + ".test"  # .test is an ICANN reserved non-public TLD

# must supply a list of names to avoid Vagrant asking for interactive input
def get_good_ifc()   # try to find a working Ubuntu network adapter name
  addr_infos = Socket.getifaddrs
  addr_infos.each do |info|
    a = info.addr
    if a and a.ip? and not a.ip_address.start_with?("127.")
     return info.name
     end
  end
  return "eth0"  # fall back to an old reliable name
end

Vagrant.configure(2) do |config|
  config.ssh.forward_agent = true  # so you can use git ssh://...

  # add a bridged network interface. (try to detect name, then guess MacOS names, too)
  interface_guesses = [get_good_ifc(), 'en0: Ethernet', 'en1: Wi-Fi (AirPort)']
  config.vm.network "public_network", bridge: interface_guesses
  if ARGV[0] == "up"
    puts "Trying bridge network using interfaces: #{interface_guesses}"
  end
  config.vm.provision "shell", inline: "ip address", run: "always"  # make user feel good

  # . . . . . . . . . . . . Define machine QUAIL1 . . . . . . . . . . . . . .
  config.vm.define "quail1", primary: true do |quail_config|
    quail_config.vm.box = "boxesio/xenial64-standard"  # a public VMware & Virtualbox box
    quail_config.vm.hostname = "quail1." + DOMAIN  # supply a name in our bevy
    quail_config.vm.provider "virtualbox" do |v|
        v.memory = 1024       # limit memory for the virtual box
        v.cpus = 1
        v.linked_clone = true # make a soft copy of the base Vagrant box
        v.customize ["modifyvm", :id, "--natnet1", "192.168.128.0/24"]  # do not use 10.x network for NAT
    end
  end
end
# file /etc/salt/cloud.profiles.d/my_vagrant_profiles.conf on bevymaster
q1:
  host: my_laptop  # the Salt id of your virtual machine host
  machine: quail1   # a machine name in the Vagrantfile (if not primary)
  vagrant_runas: my_username  # owner of Vagrant box files on "my_laptop"
  cwd: '/home/my_username' # the path (on "my_laptop") of the Vagrantfile
  provider: my_vagrant_provider  # name of entry in provider.conf file
  target_network: '10.0.0.0/8'  # VM external address will be somewhere here
# file /etc/salt/cloud.providers.d/vagrant_provider.conf on bevymaster
my_vagrant_provider:
  driver: vagrant
  minion:
    master: 10.124.30.7  # the hard address of the master

Create and use your new Salt minion

  • Typing on the Salt master computer bevymaster, tell it to create a new minion named v1 using profile q1...

sudo salt-cloud -p q1 v1
sudo salt v1 network.ip_addrs
  [ you get a list of IP addresses, including the bridged one ]
  • logged in to your laptop (or some other computer known to GitHub)...

    [NOTE:] if you are using MacOS, you need to type ssh-add -K after each boot, unless you use one of the methods in this gist.

ssh -A vagrant@< the bridged network address >
  # [ or, if you are at /home/my_username/ on my_laptop ]
vagrant ssh quail1
  • then typing on your new node "v1" (a.k.a. quail1.bevy1.test)...

password: vagrant
  # [ stuff types out ... ]

ls -al /vagrant
  # [ should be shared /home/my_username from my_laptop ]

# you can access other network facilities using the ssh authorization
# as recorded in your ~.ssh/ directory on my_laptop ...

sudo apt update
sudo apt install git
git clone ssh://git@github.com/yourID/your_project
# etc...