I’ve been working with vagrant boxes for quite awhile now. I usually use them for development environments or creating lab environments for testing various network functions (i.e. BGP EVPN). Often times when I’m using a vagrant box I need to get it in a certain state before it’s ready for me to begin using. In the situation of creating lab environments I may need to install FRRouting on the vagrant box and then apply a configuration. A handy feature that vagrant provides to make this possible is the ability to use provisioners that can execute a script prior to the vagrant box being ready for use. The ones I find myself using most are the shell provisioner and ansible local provisioner. In this post I’ll go over how I use the ansible local provisioner to install FRRouting on a Ubuntu 20.04 vagrant box. If you would like to follow along I have created an example located in github here.
Prerequisites
Before you begin you need to do the following:
- Install Vagrant on your workstation
- Install a Vagrant Provider on your workstation
Review the Vagrantfile
Whenever you are working with vagrant boxes you are going to have a Vagrantfile defined. Check out the documentation provided in the previous statement to learn more about Vagrantfiles and everything you can do within one. In this post I won’t go into much detail on the Vagrantfile aside from the provisioner section. The basic gist of a Vagrantfile is it essentially defines your vagrant environment - the virtual boxes, their network connectivity, resources, etc.
Looking at the Vagrantfile in our example github repo you’ll see that it’s pretty simple.
Vagrant.configure("2") do |config|
config.vm.box = "bento/ubuntu-20.04"
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
ansible.install_mode = "pip"
ansible.pip_install_cmd = "sudo apt install -y python3-distutils && curl https://bootstrap.pypa.io/get-pip.py | sudo python3"
ansible.galaxy_command = "sudo ansible-galaxy install -r /vagrant/collections/requirements.yml"
end
end
The config.vm.box
statement defines the vagrant box that we’re going to use (bento/ubuntu-20.04). The next statement goes into our ansible local provisioner. When you perform a vagrant up
vagrant will first bring the vagrant box online. Once the vagrant box is online it will run the provisioner. The ansible local provisioner will first install ansible on the vagrant box. There’s a couple methods you can use for the installation. The default method is installing via the operating system package manager. On Ubuntu 20.04 I had issues using that method as focal was not recognized as a valid option. This is the error that I received when attempting that install method:
E: The repository 'http://ppa.launchpad.net/ansible/ansible/ubuntu focal Release' does not have a Release file.
Another approach that vagrant allows is installation via pip. Prior to installing ansible via pip I must first install pip. The vagrant box that I selected comes bare bones and pip is not available. Ubuntu 20.04 does not come with disutils and the pip installation will fail if it’s not present. So I also needed to make sure that is installed prior to the pip installation. Within the Vagrantfile you define how pip should be installed via the pip_install_command
statement. In the above example you can see I’m installing python3-disutils
first and then installing pip.
Once pip is installed vagrant will proceed with installing ansible. If you prefer a specific version of ansible you can define the version
otherwise pip will install the latest available. If you have any ansible roles or collections that need to be installed prior to your playbook executing you can define those in the galaxy_command
statement. In my example I have a requirements.yml file defined within my collections folder that needs to be installed prior to my playbook executing.
After ansible is installed vagrant will then run the playbook that is defined. In my example my playbook is called playbook.yml
. My playbook basically follows the steps outlined here for installing FRRouting. After the installation I also edit the sysctl.conf
file to enable routing on the vagrant box. Here are the contents of my playbook:
---
- name: provision vagrant box with frrouting
hosts: all
gather_facts: no
tasks:
- name: add frr apt-key
ansible.builtin.apt_key:
url: https://deb.frrouting.org/frr/keys.asc
state: present
become: yes
- name: get host distribution
ansible.builtin.command: lsb_release -sc
register: release
- name: add frr repository into source list
ansible.builtin.apt_repository:
repo: "deb https://deb.frrouting.org/frr {{ release.stdout }} {{ frr_version }}"
state: present
filename: /etc/apt/sources.list.d/frr
vars:
frr_version: frr-stable
become: yes
- name: install frr
ansible.builtin.apt:
name:
- frr
- frr-pythontools
update_cache: yes
register: apt_status
retries: 100
until: apt_status is success or ('Failed to lock apt for exclusive operation' not in apt_status.msg and '/var/lib/dpkg/lock' not in apt_status.msg)
become: yes
- name: edit sysctl.conf for ipv4 forward
ansible.posix.sysctl:
name: net.ipv4.ip_forward
value: '1'
state: present
reload: yes
become: yes
- name: edit sysctl.conf for ipv6 forward
ansible.posix.sysctl:
name: net.ipv6.conf.all.forwarding
value: '1'
state: present
reload: yes
become: yes
Vagrant Up
Go ahead and issue a vagrant up
within the example repo. You should see output similar to the following.
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'bento/ubuntu-20.04'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'bento/ubuntu-20.04' version '202010.24.0' is up to date...
==> default: Setting the name of the VM: vagrant-box-ansible-provisioner-example_default_1612559846779_78606
==> default: Fixed port collision for 22 => 2222. Now on port 2201.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2201 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2201
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection reset. Retrying...
default:
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair for better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest if it's present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
default: The guest additions on this VM do not match the installed version of
default: VirtualBox! In most cases this is fine, but in rare cases it can
default: prevent things such as shared folders from working properly. If you see
default: shared folder errors, please make sure the guest additions within the
default: virtual machine match the version of VirtualBox you have installed on
default: your host and reload your VM.
default:
default: Guest Additions Version: 6.1.16
default: VirtualBox Version: 6.0
==> default: Mounting shared folders...
default: /vagrant => /Users/username/directory/vagrant-box-ansible-provisioner-example
==> default: Running provisioner: ansible_local...
default: Installing Ansible...
default: Installing pip... (for Ansible installation)
default: Running ansible-playbook...
PLAY [provision vagrant box with frrouting] ************************************
TASK [add frr apt-key] *********************************************************
[DEPRECATION WARNING]: Distribution Ubuntu 20.04 on host default should use
/usr/bin/python3, but is using /usr/bin/python for backward compatibility with
prior Ansible releases. A future Ansible release will default to using the
discovered platform python for this host. See https://docs.ansible.com/ansible/
2.10/reference_appendices/interpreter_discovery.html for more information. This
feature will be removed in version 2.12. Deprecation warnings can be disabled
by setting deprecation_warnings=False in ansible.cfg.
changed: [default]
TASK [get host distribution] ***************************************************
changed: [default]
TASK [add frr repository into source list] *************************************
changed: [default]
TASK [install frr] *************************************************************
changed: [default]
TASK [edit sysctl.conf for ipv4 forward] ***************************************
changed: [default]
TASK [edit sysctl.conf for ipv6 forward] ***************************************
changed: [default]
PLAY RECAP *********************************************************************
default : ok=6 changed=6 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You now have a vagrant box that has FRRouting installed!