Creating Custom Vagrant Boxes for Integration Testing

For some things, a docker container will not work. For example, I am working on a Python project to automate the deployment and configuration of VMs and bare-metal boxes. It involves installing packages and configuring the OS and to properly test it requires a full fledged VM and not just a container.

Use packer to define the box you want to build

Install packer. The description straight from apt show packer is “HashiCorp Packer – A tool for creating identical machine images for multiple platforms from a single source configuration” Then create your pkr.hcl file (I am using the newer HCL DSL). The following is for a box that extends Debian 11.

variable "version" {
  type    = string
  default = ""
}

locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }

source "vagrant" "xfce4_debian_11" {
  add_force    = true
  communicator = "ssh"
  provider     = "virtualbox"
  source_path  = "debian/bullseye64"
}

build {
  sources = ["source.vagrant.xfce4_debian_11"]

  provisioner "shell" {
    execute_command = "echo 'vagrant' | {{.Vars}} sudo -S -E bash '{{.Path}}'"
    script          = "provision.sh"
  }
}

Build the box

packer build xfce4_debian_11.hcl

This will create an output-xfce4_debian_11 directory and build the box writing it into that directory. The contents of which, when finished will be

output-xfce4_debian_11/
|-- package.box
`-- Vagrantfile

Create a Vagrant file that uses the pre-built box

For your integration testing you will be spinning up an “instance” of the box you just built.

  1. Create a directory for your instance and cd into it: mkdir test-instance && cd test-instance
  2. Initialize the vagrant instance and then add the box that you built; vagrant init test-instance && vagrant box add test-instance <path-to-dir>/output-xfce4_debian_11/package.box
  3. Update the Vagrant file with any additional configs that you require and then run vagrant up to start it.

Using Environment Variables in a Vagrant File

An easy way to parameterize a Vagrant file is to use environment variables. You simply need to export a variable and then refer to it in the Vagrant file with the following syntax.

Export the variable:

export SSH_PORT=22222

Sample Vagrant file that reads the exported variable

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

Vagrant.configure("2") do |config|
  config.vm.box = "debian/bullseye64"
  config.vm.box_version = "11.20221219.1"

  config.vm.network "forwarded_port", guest: 22, host: ENV['SSH_PORT']
end

Declaring, Exporting, and Reading Dynamic Variables in Bash

If you want to dynamically define and export variable names in Bash here is the TLDR;

# Define the name of the variable
key="my-dynamic-var-name"

# Declare it and export it
declare -gx "$key"="some-value"

To then access that value via a dynamically generated variable name

# Create a variable that contains the variable name
var_to_access="my-dynamic-var-name"

# Read the value
my_var_value=${!var_to_access}

Read the man page for declare for more details and read this article for a really good explanation and further examples.

To read the declare man page

help declare

Chickpea and Rice Stew

Ingredients

  • 1.5 cups basmati rice
  • 1 TB olive oil
  • 1/4 cup olive oil
  • 1 cup yellow onion, diced
  • 2 (14 oz) cans chickpeas, drained
  • Salt & black pepper, to taste
  • 3 garlic cloves, minced
  • 1 tsp ground turmeric
  • 1/2 tsp crushed red pepper flakes
  • 1 lemon, juiced and zested
  • 1 (32 oz) box low sodium vegetable broth
  • 4 oz fresh baby spinach
  • 1/2 cup cilantro, chopped
  • 1/2 cup parsley, chopped
  • 1/4 cup dill, chopped
  • 1 TB chives, chopped
  • 4 Naan flatbread—To heat the Naan, preheat the oven to 400 degrees and place Naan on a baking sheet in the middle of oven and warm for 3 minutes

Directions

  1. Rinse the basmati rice in cold water. Combine rice with 2 1/4 cups water, 1 TB olive
    oil and a pinch of salt in a medium pot. Stir once and bring to a boil over high heat. Cover, reduce heat to low and simmer for 10 minutes. Remove pan from heat and leave covered for 5 minutes. Remove lid and fluff with fork before serving.
  2. Heat 1/4 cup olive oil in a large pan over medium heat. Add the garlic and diced onions and cook until soft, about 5-8 minutes.
  3. Add the 2 drained cans of chickpeas, season with salt & pepper to taste. Cook stirring occasionally until the chickpeas begin to crisp, about 5-8 minutes. Add the turmeric, crushed red pepper flakes (based on desired spice preference), and lemon zest, stir to combine, and cook about 2 minutes.
  4. Add 3 cups vegetable broth, the juice of 1/2 lemon and bring the mixture to a boil, then reduce heat to low. Stir in the baby spinach, 1/2 cup chopped cilantro, 1/2 cup chopped parsley, 1/4 cup chopped dill, and 1 TB chopped chives, and simmer for 10 minutes until the spinach is wilted. Add salt and black pepper, to taste, as needed. Add as much of the remaining 1 cup vegetable broth to reach desired soup consistency.
  5. To serve, divide the cooked basmati rice among bowls and ladle stew over. Top with reserved chickpeas. Enjoy with warmed Naan flatbread.

Bean and Barley Leek Soup

Make 3 cups of cooked barley ahead of time and have it on hand when cooking the soup.

Ingredients

  • 2 Tablespoons olive oil
  • 3 cloves garlic, minced
  • 2 leeks, diced
  • 3 carrots, diced
  • 1 bulb fennel, sliced thin (1 cup)
  • 1 (15 ounce) can no-salt added diced tomatoes
  • 1 teaspoon Herbes de Provence
  • 4 cups low-sodium vegetable broth
  • 2 (15 ounce) cans white beans,rinsed and drained
  • 1/2 teaspoon kosher salt
  • 1/4 teaspoon black pepper
  • 1 teaspoon lemon zest
  • 4 ounces spinach, chopped (2 cups)
  • 3 cups cooked barley
  • 1/2 cup chopped parsley
  • 1/4 cup crumbled feta, optional
  • 1 teaspoon of lemon zest

Instructions

  1. Heat a large sauté pan over medium heat.
  2. Add oil, garlic, leeks, carrots, cabbage, and fennel; sauté for
    about 3-4 minutes.
  3. Add tomatoes, Herbes, broth, beans, salt, and pepper. Bring to
    simmer and cook for 2 minutes.
  4. Add lemon zest, spinach, and barley; cook until heated
    through.
  5. Garnish with parsley and feta.