Automating VirtualBox Test Environments

Introduction

VirtualBox is awesome, and I use it a lot. Yes, I know I said I was transitioning over to AWS for most of my homelab work. And that is entirely true. But, sometimes, you just need something super simple. And for that, nothing beats a small locally hosted virtual machine environment. I find myself testing various linux configurations on a daily basis, both for work and for personal projects. Every time I spin up a new virtual machine or restore a template, I always grumble, mumbling something about how I should automate my standard testing process. Well friends, I have finally done just that; using the handy dandy VBoxManage terminal interface which comes pre-installed as part of VirtualBox.

Assumptions

In order for this to work, you will need a virtual machine running your preferred flavor of Linux. This virtual machine will need to be on a NAT network connection managed by VirtualBox. The NAT network will need to have port forwarding enabled. I have chosen port 2223 forwarded from the host to port 22 on the guest. I also assume that you have key based ssh enabled on the virtual machine with a key authorized connection back to your host device. Finally, I assume that you have a snapshot created which includes the ssh key (I named my snapshot ‘BASE’).

Commands

The first command we will execute provides the UUIDs of each virtual machine. This GUID will be our anchor point for most of the commands we will execute later.

$: vboxmanage list vms 

After running this command the names and UUIDs of each virtual machine will be displayed in the terminal window. An example of this command is shown below:

"CentOS Template" {e21e8bc2-2afc-44d0-91e4-bd116c61f817}
 "CentOS TestBench 1" {34e68873-a0b8-465d-9369-f438e7fe05a3}
 "RHEL7 Template" {fa402565-d211-41dd-86aa-4e8008a4e45c}

In this case, the UUID we need is for the “RHEL7 Template”. Take note of the code within the brackets for the next series of commands.

Once the UUID has been recorded, we can use that code as part of additional commands to create a few distinct functionalities.

Shutdown VM
$: vboxmanage controlvm fa402565-d211-41dd-86aa-4e8008a4e45c  poweroff soft

Restore VM
$: vboxmanage snapshot fa402565-d211-41dd-86aa-4e8008a4e45c restore BASE
 
Startup VM
$: vboxmanage startvm fa402565-d211-41dd-86aa-4e8008a4e45c

Each of these commands will perform a different action on the endpoint. As titled, the first command will shutdown the VM. Then, the second command restores the VM to its original snapshot. The final command starts up the virtual machine.

For simplicity, I have combined the Shutdown and Restore functions into a single action by joining them with a && statement. This command is shown below:

$: vboxmanage controlvm fa402565-d211-41dd-86aa-4e8008a4e45c  poweroff soft && vboxmanage snapshot fa402565-d211-41dd-86aa-4e8008a4e45c restore BASE

Once combined and actioned, the virtual machine will shutdown and then restore to the BASE snapshot as a single action.

I have taken this process a step further, by aliasing these commands (and a bonus SSH command) within my .bashrc/.zshrc configuration files. My aliases look like this:

alias box-kill="vboxmanage controlvm fa402565-d211-41dd-86aa-4e8008a4e45c  poweroff soft && vboxmanage snapshot fa402565-d211-41dd-86aa-4e8008a4e45c restore BASE"
alias box-init="vboxmanage startvm fa402565-d211-41dd-86aa-4e8008a4e45c"
alias box-enter=ssh -p 2223 root@localhost"

Therefore, rather than typing in that monstrosity of a command, I can now simply type in:

Shutdown & Restore VM Snapshot
$: box-kill

Start VM
$: box-init

SSH to VM
$: box-enter

with those two simplified commands, I can quickly and memorably start or reset my virtual machine environment.

From there, I have just two more tools I need for a fully functioning virtual machine test suite. First, I need to be able to review the status of my virtual environment. To do that, I will use the command shown below:

$: vboxmanage showvminfo fa402565-d211-41dd-86aa-4e8008a4e45c | grep -e "Name:" -e "State:" -e "Snapshots:"

This command returns the status of the virtual machine, as shown in the output below:

Name:                        RHEL7 Template
 State:                       powered off (since 2021-06-29T23:49:21.383000000)
 Snapshots:
    Name: BASE (UUID: 2f2677c2-dded-4cda-9854-b3fd2077fe8f) *

As with the previous commands, I am going to turn this command into an alias, as shown below:

alias box-status="vboxmanage showvminfo fa402565-d211-41dd-86aa-4e8008a4e45c | grep -e \"Name:\" -e \"State:\" -e \"Snapshots:\""

Once I have entered that alias into my .bashrc/.zshrc configuration files, I will then be able to gather status information from my endpoint with the command below:

Virtual Machine Status
$: box-status

Finally, I am going to create a simple script which will provide the ability to push files from my host machine to the virtual machine using scp. The contents of the script are shown below:

#!/bin/bash
 current_dir=$(pwd)
 scp -P 2223 ${current_dir}/$1 root@localhost:~/

This script will grab the current directory of the terminal, and then push a selected file to the home directory of the virtual machine. I have placed the contents of this script in /usr/local/bin/ under the file name box-push. Finally, I mark the /usr/local/bin/box-push file as executable with the command:

 "chmod +x /usr/local/bin/box-push"

Then, I can push files to the virtual machine with a single command, as shown here:

Pushing Files to Virtual Machine
$: box-push testscript.rb

In this case, I am prompting the box-push command to securely copy the testscript.rb file from the current directory over to the virtual machine.

TLDR

I created some commands that do things! Using the VBoxManage command line tool, I have created aliases and scrips which perform basic actions on my test lab environment hosted in VirtualBox on my local computer. The final end product is shown below:

Shutdown & Restore VM Snapshot
$: box-kill

Start VM
$: box-init

SSH to VM
$: box-enter

Virtual Machine Status
$: box-status

Pushing Files to Virtual Machine
$: box-push testscript.rb

Leave a Comment