Test Kitchen with Hyper-V on Windows 10

I have recently moved from using a Apple MacBook Pro to a Microsoft Surface Book running Windows 10 and I wanted to play around with Docker for Windows. This meant that I had to install Hyper-V which posed the problem of having to remove Virtual Box which I had been using for my Test Kitchen runs of my cookbooks.

This post shows how to configure Hyper-V to work with Test Kitchen. It took a little while to get all the configuration set correctly and there are some gotchas, but on the whole it works very well.

Astute readers will be asking why I did not just start working with Docker now that I had it installed. I have done that as well, but that is for another post.

A surprising side effect of using Hyper-V was that machines are created much more quickly than in Virtual Box. The reason for this is that the final machine uses a differencing disk from the original so the virtual hard disk is not copied leading to faster spin up times.

Preparing Hyper-V

Create the base virtual machine

Unlike Virtual Box, Hyper-V does not have a central registry from which virtual machines can be downloaded to create the Test Kitchen (TK) environment. This means that a parent machine needs to be created. In this example a parent Ubuntu machine will be created.

Download the Ubuntu ISO file from here. The following examples assume this was saved into the users Downloads directory.

As this article is about setting up Hyper-V all the commands that are shown should be run in PowerShell

  • Open a PowerShell console with elevated privileges.
  • If Hyper-V is not installed run the following command:
PS > Enable-WindowsOptionalFeature -Online -FeatureName:Microsoft-Hyper-V -All
  • Create a new network switch. This will be designated Internal
PS > New-VMSwitch -Name InternalSwitch -SwitchType Internal
  • Allow the switch internet access. Built into Windows is a feature called Internet Connection Sharing (ICS) that allows internal networks to connect to the internet.

    • Press + R to bring up the Run box
    • Type ncpa.cpl
    • Select the network connection, e.g. LAN or WiFi, right click and select ‘Properties’
    • Select the ‘Sharing’ tab

    Remember to change this if the network connection is changed

  • Create directory to store all the virtual hard disks and the machine definitions

PS > mkdir "C:\Virtual Machines\Hyper-V"
  • Create an empty virtual machine attached to the network switch and the downloaded Ubuntu image loaded as a CD.
PS > $vm = New-VM -Name Ubuntu-16.04 -MemoryStartUpBytes 2GB -NewVHDPath "C:\Virtual Machines\Hyper-V\Ubuntu-16.04.vhdx" -NewVHDSizBytes 10GB -Path "C:\Virtual Machines\Hyper-V" -SwitchName InternalSwitch
PS > $vm | Add-VMDvdDrive -Path "~\Downloads\ubuntu-16.04.2-server.iso"
PS > $vm | Set-VM -AutomaticStartAction StartIfRunning -AutomaticStopAction ShutDOwn
PS > $vm | Start-VM
  • Use the Hyper-V console to attach to the virtual machine and complete the setup of Ubuntu. (The installation of Ubuntu is beyond the scope of this post)

Configure the base virtual machine

After the machine has been created it needs to be configured so that PowerShell is able to interrogate it to get the IP address so that TK can connect to the machine. This is called “Linux Integration Services” or LTS. It is similar to the Virtual Box extensions.

It is easy to download and install if using a RedHat based distribution, but as this is Ubuntu things need to be installed on the command line.

  • Log into the Ubuntu machine using the console and the password configured during setup
  • At the command prompt type the following:
$> sudo apt-get install linux-virtual-lts-xenial linux-tools-virtual-lts-xenial linux-cloud-tools-virtual-lts-xenial 
  • Create a new user called kitchen and set the password to kitchen
$> sudo useradd -d /home/kitchen -m kitchen
$> sudo passwd kitchen
  • Allow the new kitchen user to run commands as root, without a password. Create a new file in /etc/sudoers.d/kitchen with the following contents
kitchen ALL=(root) NOPASSWD:ALL
  • Shut the machine down
$> sudo shutdown now

Configure Test Kitchen

Now that the base machine has been created Test Kitchen can be configured to use the machine to run tests. The first thing to do is install the Test Kitchen Hyper-V driver.

Either install the driver using the gem command:

PS > gem install kitchen-hyperv

Or add it as a dependency to the cookbook GemFile, this is the recommended option:

gem "kitchen-hyperv"

and then run the following command

PS > bundle install

Now that the driver has been installed configure TK to use it. The following shows an example .kitchen.yml file.

---
driver:
  name: hyperv
  parent_vhd_folder: C:\VirtualMachines\Hyper-V
  parent_vhd_name: ubuntu-16.04.vhdx
  vm_switch: InternalSwitch
  memory_startup_bytes: 2GB

provisioner:
  name: chef_zero
  require_chef_omnibus: 13.0.118

transport:
  name: ssh

verifier:
  name: inspec
  format: doc

platforms:
  - name: ubuntu-16.04

suites:
  - name: default
    run_list:

In the above example the Chef-Client version has been set so that there are no nasty surprises from cookbooks if the latest version is installed

This tells TK to use the hyperv driver and where the base machine is. This is the location of the machine that was created in the previous section. As can be seen the vm_switch is set to “InternalSwitch” that has been configured to use ICS on the attached network adapter.

Now all the standard kitchen commands will work as expected, for example:

  • chef exec kitchen list

Gotchas

As mentioned at the beginning of the post there are a few gotchas when working with Hyper-V, these are highlighted below:

  • When running kitchen converge it must be done in an elevated Command or PowerShell prompt.
    • This is due to the way in which Windows handles the networking for the virtual machine. If you see message stating ‘Failed to find a default VM Switch’ (as shown below) make sure your are running in an elevated prompt.
  • Sometimes everything will be setup correctly and you will experience a timeout after the machine has been created. This seems to be an issue with ICS. The workaround is to disable sharing on the network connection and re-enable it again.

  • If things were working before and now they are not, check if you have moved network connections from wired to wireless for example. If this is the case the ICS needs to be setup on the new connection.

  • You have to share the Hyper-V switch with the network connection you are using. If you use wired at work and wireless elsewhere you have to make this change otherwise your TK machine will not be able to connect to the Internet.

Share Comments