How to create a vagrant base-box for VirtualBox

Introduction

What is vagrant?

Vagrant is a tool to run and maintain lightweight and flexible development environments. It is often used in software companies to enable all of their developer to work with the same standardized virtual machines that fit to their production environments. If it is configured right, you can simply type vagrant up and you have a running dev environment.

Why do we need a base-box

To be able to work with vagrant as the management system of your development environment there are two parts necessary. One is the environment configuration based on chef or puppet recipes. These recipes will provide a list of packages and set-ups to configure the virtual machine according to their current needs. For example you can install a web-server and MySQL, set up the user accounts and get it up running.

The base-box itself contains only the very rudimentary system. In our example it is a nearly plain Ubuntu Server 14.04. This image will be used to ground all of our development systems. Vagrant boots it up and runs the recipes from chef or puppet to install the needed software.

Create the base-box

Software requirements

To set up a base-box for using with vagrant we at least need vagrant itself and VirtualBox. You can grab all of them by following the next links. As you might see there is also a link to download the actual Ubuntu Server image. This will be needed to install the operating system of your base-box.

I will not write about the installation and configuration of VirtualBox but it should be self-explanatory.

Another way to install vagrant and VirtualBox on Mac OSX is to use homebrew in addition with cask. Brew should be known by every advanced user of OSX and cask is a simple addition to not only install command-line tools but also to handle full GUI software packages. With it you can install software like VirtualBox or IntelliJ Idea for example.

The following command will install our necessary software.

Hardware settings of the virtual machine

My specifications.

Harddisk
  • VDI self growing image (43Gb)
Chipset
  •  PIIX3
RAM
  • 512Mb
 Network
  •  eth0: NAT
  • eth1: Host-only
 Hardware virtualization
  •  VT-x / AMD-V
  • Nested Paging
 Video
  •  12Mb
  • no 2D / 3D acceleration
 Audio
  • none

The following screens will guide you through the set up of the virtual machine.

Installation of the base system

With the Ubuntu Server image mounted to your virtual disc drive, boot up the machine using the start button and press F12 followed by pressing to select the CD as your boot device. The Ubuntu installation wizard will pop up and asks you for your preferred language and keyboard settings. This part can be configured the way you like it. At the point where you will be asked for the partition layout, select use the whole disk  but without the logical volume manager (LVM). This is convenient and fits to all of our needs.

The next step is setting up the primary user account. For vagrant to be able to run, this user has to be vagrant set up with the same as password.

  • username: vagrant
  • password:  vagrant

We will leave the next step with no automatic updates and proceed onto the software selection. The only prerequisite vagrant has for a base-box is the presence of a ssh-server. After selecting the openssh-server press return to continue. It will take a few minutes to complete the package installation and setting up the system.

That’s it. After ejecting the disk image from the virtual cd-drive we can continue with our last step.

Configure the base-system

We already installed the openssh-server during the ubuntu installation wizard but it is not yet configured to be used by vagrant.

Log in into your newly created machine with the credentials we set up earlier.

Ubuntu first login

Ubuntu first login

Vagrant uses an insecure keypair to be able to log in to your machine. To set up this key we have to copy its public part to the virtual machine. First we need to determine the ip-address of the system by running ifconfig.

ifconfig

ifconfig

With this address in mind we can user the following command to add the key to the server.

If this does not work, simply paste the content of the vagrant.pub file into the VMs vagrant users home folder under .ssh/authorized_keys with the following commands.

Paste the content and press ctrl + o  followed by ctrl + x. For openssh to be able to user this key it needs to have a specific combination of access right. Run the following commands to fix them.

The next step is very important because vagrant uses the sudo command to do all its stuff as a privileged user but does not want to type a password every time it uses it. To configure sudo passwordless type sudo visudo and add the following line right behind the privileges of the root user.

And also edit the line about the sudo user group to be able to user it without a password.

Install the guest additions

To get the best out of your virtual machine experience it is recommended to install to VirtualBox guest additions.

Before you can do this, there are a few packages needed to be able to compile the kernel packages.

The next step is to mount the guest additions image to your machine by going to the main menu, select the devices tab and click on Insert Guest Additions CD Image followed by typing into your machines console the next command.

Finally run the script that matches to your selected system architecture. In my case it is a 64bit system so i had to use the following command.

Install puppet or chef

Last but not least we need to install one of the environment configuration management clients. If you prefer chef or puppet is completely up to you. I will use puppet because of some company dependencies.

If everything succeeds we are ready to go.

Packaging the box

This step sounds like one of the hardest but it is very simple because vagrant provides us with all of the needed tools. We only have to type one command and vagrant will provide you with a base-box in the current working directory. The base-box-14.04 is the name of your virtual machine.

Final result.

Download my base-box

If your are interested in using my newly created base-box image, simply download it from the following link.

Sources

 

Golang and reflections

Introduction

Reflection is the ability of a program to examine its own structure. In go we can use it for example to build dynamically accessable structs.

How-to use reflect

I will give you with two examples and a hopefully easy-to-understand explanation of them.

Simple usage

At hikewith.me we use a simple way of reflection to map dynamically specified keys to a set-up value. With this we can map database-columns to a given key and generate SQL queries according to the given input instead of predefining everything. In our database, field are named another way then in our backend code (go). For example the first-name of a user will be saved in the column first_name but the field in our User-struct is named FirstName. We need a way to map these connection dynamically for updating the user data and keeping our code simple.

Field-map struct

These struct type defines the connection between our used struct field and the columns found in our database table. FirstName, LastName etc. are the field names used in our User struct. The assigned value will be the table column. It will be loaded from a json-file (see JSON configuration).

User struct

This type stores the information about a user. If he changes some of his data we use this struct to update the dataset in our database.

JSON configuration

As already noted, we store the mapping between columns and keys in a JSON-file that will be loaded during the initial start of our backend.

Configuration loader

To load the JSON represented field configuration we use the gotamer-cfg-loader. You can get it using the following line.

The usage is really simple. Initialize the var to save the loaded configuration as type of your FieldMapping struct and afterwards simply load the file content into this struct.

Field-mapper

This is where the magic happens. The method will be called with the field name as param and returns the value of the field. First it reflects the list of all fields of the FieldMapping struct after this we can do an indirect reflect to get value of the field.

A more generic version

The following code is a more generic version of my code from above. It is not bound to a specific type but can be used with any kind of type to get a fields value. I will show how to use this function within the more advanced example.

Advanced usage

In this second example, i will show how to compare two structs of the same type with each other and get a diff. With this diff-struct we update our user data-set.

Compare struct

It is a simple key-value-store that will be used in a slice to collect all diffs.

Compare two structs of the same type

This function will be called from within a new-user-struct like this newuserdata.compareUpdate(olduserdata). The reflection will be used in the first place to get the number of fields in this struct. With this we can iterate over all fields and use the above defined getFieldByIndex function to get the value of each field and compare them to the corresponding value of the old-user-struct. The last step is to add the compare struct to our returned slice if there was a difference.