EasyConfig Vagrant Plugin

This plugin is a collection of Ruby-files that can be placed inside a Vagrant directory. When used it helps with configuring plugins, defining the VMs and provisioning with Ansible by providing a simple to configure YAML-file.

Installation

vagrant plugin install vagrant-easyconfig

YAML-File

The configuration file is hard-coded on purpose and when it is non-existent it will be created an can then be adapted therefrom. The file looks as follows

---
default:
  vm:
    gui: false
    memory: 4096
    cpus: 4
    storage: 10GB
    # list of boxes that may be used for this project
    boxes:
      ubuntu1804: ubuntu/bionic64
      ubuntu: ubuntu/focal64
    # key for the box that is used for this project
    box: ubuntu
  hosts:
    # name of the host
    example-host:
      # if no ip is given it will be generated from net.ip
      ip:
      # groups used for ansible
      groups:
      # aliases are added to the /etc/hosts on the host and guest
      aliases:
      # override vm options per host
      # vm:
      #   memory: 8192
  plugins:
    # automatically installs vbguest, hostmanager and disksize
    auto_install: true
    vbguest:
      # turn off auto_update of vbguest
      auto_update: true
  linked_clones: true
  net:
    # ip to auto generate IPs from
    # incrementing by 1 for every host
    ip: 192.168.100.100
    private_nic_type: 82540EM
    network_type: private_network
  ansible:
    # whether to use ansible_local or ansible provisioner
    local: true
    # whether to install ansible with guest OS or pip
    pip: false
    # where the ansible project is located
    playbook_path:
    # where the playbook is located inside the ansible project
    playbook:
    # when used passes the extra_vars to ansible
    extra_vars:
    # when used only tasks with these tags are run
    tags:
    # when used all tasks except for one with these tags are run
    skip_tags:
    # toggle verbose logging for ansible
    verbose: false
  # will be disable on unix systems
  windows:
    ssh:
      # specify ssh-key location
      key:
# override for current host
# by specifying the hostname of the current machine
# all settings under this key are overriding the default section
# example-host:
#   vm:
#     memory: 8192
#   hosts:
#     example-host:
#       vm:
#         memory: 16384

Overriding

There are two sections that can be utilized for overriding default values.

Overriding per Host

Supposing a project is used on different hosts which in turn have a different set of resources available (which is expected and does not impair the functionality of the project for the intended purposes). Then it would be helpful to dedicate a specific amount of resources to the project (VM) depending on that host. For this reason and others it is possible to override all of the settings inside the default block by custom values depending on the host it is used in.

Therefore one has to specify another block below the default block, the key being the hostname of the host. When the host's hostname is example-host the key should be example-host. An example is given in the code above from line 61-68.


This may also benefit if for example the Vagrant version is different and in one it is not possible to use the pip-installation of Ansible. Or some provisioning should be skipped, then it can be set in the host-specific section with Ansible-tags.

Overriding per Guest

Sometimes one expects all the Guest-VMs to have the same specifications, e.g. when creating a Kubernetes-Cluster. However, if the setup requires different Hosts, i.e. database-hosts, master- and slaves, control- and production-machines, then the Guest-machines may need different specs. Therefore it is possible to define a vm-section inside the host-section. This then overrides the default values of the vm-section. An example is given in the code above in line 23-25.

Boxes

It is possible to specify a list of boxes in the boxes-section. The box-section then is set with the key from the boxes-section. That makes sense, when the project should support multiple platforms and those should be persisted.

IPs

The section net.ip specifies the base IP-address. When no IPs are specified inside the host-sections this one is used and incremented by one for every guest, and then assigning it.

This can be overridden by specifying an IP-address directly in the host-section as can be seen in line 36.

Groups

Groups refer to Ansible-groups. This is a simple way to group Guests together. Only single strings or a simple list of strings is allowed, so no complex nested groups can be created like this.

Aliases

A host may need aliases that should be specified to make it reachable through different hostnames. Rancher's UI (Website of the Kubernetes-Product Rancher), can only be access through a root path of a URL, as otherwise assets are not reachable. Therefore this product requires the host to be reachable via two hostnames. One for the UI and one for reaching the Kubernetes-services themselves.

the hosts.*.aliases-section is a string-list and those will be added to the host's and guest's /etc/hosts-files.

Plugins

The plugins.auto_install-section allows toggling on and off the auto installation of the plugins vagrant-vbguest, vagrant-hostmanager and vagrant-disksize.

The plugins.vbguest.auto_update-section allows toggling on and off the auto installation of the most recent version of the VirtualBox Guest Extensions.

Ansible

section default description
local true Use the ansible_local provisioner. Meaning the Ansible project is directly invoked on the Guest-machine by specifying the target to be localhost and the connection being local.
Otherwise use the ansible provisioner, invoking Ansible from the host against the Guest-machine.
pip false Use the pip to install Ansible on the Guest-machine, when not available and using local=true.
Otherwise use the systems package manager to install Ansible, i.e. aptitude, yum, dnf...
playbook_path ansible The location of the Ansible-project. If nothing is specified the directory <vagrant-directory>/ansible is assumed.
playbook playbook.yml The location of the Playbook-file. If nothing is specified playbook.yml is assumed.
extra_vars nil If used passes the extra_vars to Ansible.
tags nil If specified only tasks/roles with these tags are run.
skip_tags nil If specified tasks/roles with these tags are skipped.
verbose false Make output more verbose.

Usage

A classic usage of the plugin looks as follows:

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

EasyConfig::Config.load("config.yaml")
EasyConfig::Config.print()

Vagrant.configure("2") do |config|
  EasyConfig::Plugins.configure(config)
  EasyConfig::VM.each(config) do |host|
    # do something except defining
  end
end

Load the config.yaml

EasyConfig::Config.load("config.yaml")

In the previous major section, the config.yaml was described. This one has to be loaded. If the file does not exist, a config.yaml.template is automatically created at the specified location, which can then be moved or copied and adapted.

Always see the configuration

EasyConfig::Config.print()

This will just print out the configuration. By putting this directly after loading it is shown with every vagrant command executed. It could also be put in the trigger sections if needed.

Plugin-Configuration

EasyConfig::Plugins.configure(config)

Plugins mostly need the config to be configured. Thus the config has to be passed to the EasyConfig::Plugins module, for it to be able to configure the plugins on the host-level, i.e. for each guest the same configuration.

Define the VMs

EasyConfig::VM.each(config) do |host|
  # do something except defining
end

This is enough to define all the VMs specified inside the config.yaml with the Ansible-provisioner. It is still possible to add further configuration code inside the block of the each-function which gets the host-configuration passed.