Tuesday 3 January 2017

Chapter 5. Manage Sandbox Environments with Test Kitchen

For the rest of this book, we’re going to want to deploy to sandbox environments that closely simulate a production environment. Running Chef on your local development workstation, like we did in Chapter 4, is not the best approach. Your development workstation probably doesn’t match your production operating environment. Even if your development workstation does match your production environment, you probably don’t want to take the risk of running untested Chef code locally. Untested Chef code might make unintended configuration changes to your local development environment. Neither is it a good idea to run your experimental Chef code in your production environment before it is validated, for similar reasons.
We’ll use Test Kitchen to create a sandbox environment that simulates a production environment. Test Kitchen works in concert with two other tools, Vagrant and VirtualBox, to produce a sandbox locally in a virtual machine. This sandbox environment is a safe, isolated place in which to experiment with Chef.
The CentOS 6 operating system will be used in our sandbox environment. CentOS is a free operating system compatible with RedHat Enterprise Linux. RedHat Enterprise Linux is a popular choice for a production environment. CentOS is a compatible variant of RedHat intended for open source projects. CentOS does not require the purchase of a commercial license for use. The skills you will learn in this book aren’t specific to RedHat Enterprise Linux, however. You should be able to translate what you learn to your operating system of choice.
If you would like to easily follow along with the examples in this book, use the Vagrant and VirtualBox setup as outlined in this chapter. If you would prefer to use an alternative method, you can still follow the exercises in the book—all you really need is a separate machine, cloud instance, or virtual machine that is not your main development workstation. Refer to the website for this book for more information on alternative setups in which you can create sandbox environments with Test Kitchen.
Before we can get started using Test Kitchen with the setup we use as default for the exercises in this book, first you need to install the necessary virtualization software: Vagrant and VirtualBox.
As shown in Figure 5-1, Test Kitchen uses Vagrant to create sandbox environments as virtual machines. Vagrant provides a single abstraction layer for Test Kitchen so it can work with many different kinds of virtualization software on a host OS. Vagrant currently supports VirtualBox, VMware Workstation, VMware Fusion, and Hyper-V virtualization software. We chose to use VirtualBox for the examples in this book because it is a free, open source virtualization solution that works on all the supported Chef platforms—Linux, Mac OS X, and Windows.

Installing Vagrant and VirtualBox

In order to use the most straightforward Test Kitchen setup based on open source software, you’ll need to install Vagrant and VirtualBox. The machine requirements for this setup are:
  • At least 6 GB of memory total
  • At least 2 GB of free memory before running the sandbox environments
  • Roughly 10 GB of free disk space to hold the extracted sandbox environments
If your machine does not meet these requirements, take a look at http://learningchef.com for alternatives where you can configure your sandbox environments on another machine besides your development workstation.
Vagrant provides an API for virtualization software
Figure 5-1. Vagrant provides an API for virtualization software
Both Vagrant and VirtualBox are available as free downloads on the Internet. Visit the following web pages to download the Vagrant and VirtualBox installers, running each in turn:
  • Vagrant—http://www.vagrantup.com/downloads.html
  • VirtualBox—https://www.virtualbox.org/wiki/Downloads

NOTE

You might need to restart your computer after installing VirtualBox. Make sure you run VirtualBox at least once to make sure it is working properly.
To verify that Vagrant is installed properly, run vagrant --version on a command line. As we will be using images distributed via VagrantCloud, you must be using Vagrant 1.5.0 or higher. VagrantCloud is a directory of Vagrant images on the Internet. Further, we recommend that you use Vagrant 1.6.3 or higher, especially if you are using Windows. The Vagrant 1.6.x series is the first to officially add support for Windows guests:
$ vagrant --version
Vagrant 1.6.3
To verify that VirtualBox is installed properly, check the version with VBoxManage. Vagrant is compatible with VirtualBox versions 4.0.x, 4.1.x, 4.2.x, and 4.3.x, as you can read about in the documentation. We recommend that you use VirtualBox 4.3.12 or higher because the sandbox environments created for this book were prepared using VirtualBox 4.3.12.
Linux/Mac OS X:
$ VBoxManage --version
4.3.12r93733
Windows Command Prompt:
> "C:\Program Files\Oracle\VirtualBox\VBoxManage" --version
4.3.12r93733
Windows PowerShell:
PS> & "C:\Program Files\Oracle\VirtualBox\VBoxManage" --version
4.3.8r92456

Host versus Guest

When talking about virtual machines and sandbox environments, it helps to explain two terms: host and guest.Figure 5-2 presents an overview of the logical architecture for a virtualization system like VirtualBox.
Guest OS overview
Figure 5-2. Guest OS overview
Virtualization software such as VirtualBox allows you to run practically any kind of operating system (OS) on your physical hardware. Virtualization software accomplishes this feat by running a target operating system in an isolated environment. Within this isolated environment, the virtualization system simulates the operating system running on separate, dedicated hardware, even though it is sharing resources with the main host. This isolated environment only consumes resources when needed and is easily replaced if something goes wrong. It’s the perfect place for experimenting with Chef.
VirtualBox allows your single workstation to behave as if it were multiple machines. You have your physical machine, running Linux, Mac OS X, or Windows (and the VirtualBox virtualization software). This is commonly referred to as the host environment. Each isolated environment that runs a separate copy of an operating system, behaving as if it were a separate machine, is referred to as a guest. On a single machine, there is only one host environment, but there can be many guest environments. There can be as many guest environments as the physical resources on the host allow.
For this book, you have installed the Chef Development Kit on your host environment. In Chapter 4, you wrote Chef code on the host, and deployed Chef code on the host. Going forward, you will continue to write Chef code on the host environment. But from now on, you will deploy your code to a guest running CentOS 6. The guest environment will simulate a production environment running CentOS 6.
It is a good idea to develop your Chef code in a separate environment from your production machines. To make it more convenient to do work on just one machine, you can use virtualization software to simulate having multiple machines. To follow the exercises in this book, you will need to enter commands on one machine or the other. The terms host and guest are a convenient way to be more specific about precisely which environment we expect you to be using.

Introducing Test Kitchen

You installed Test Kitchen in Chapter 2, either as part of the Chef Development Kit, or manually, if you chose the Chef Client option. Test Kitchen will create a number of supporting files in the current working directory while it is being used. You should create a project directory for each sandbox environment to organize these files. For your first sandbox environment, create a directory called kitchen and make it the current directory:
$ mkdir kitchen
$ cd kitchen
Run the kitchen init --create-gemfile command in your newly created kitchen directory. The kitchen init command generates all the config files needed to add Test Kitchen support to a project. We need to use the --create-gemfile option, because if we don’t, Test Kitchen will immediately try to run gem install as a user instead of as an admin. This fails on some platforms because the Chef Development Kit installation doesn’t always make its gem directory user-writeable:
$ kitchen init --create-gemfile
      create  .kitchen.yml
      create  test/integration/default
      create  Gemfile
      append  Gemfile
      append  Gemfile
You must run `bundle install' to fetch any new gems.
The bundle install command referenced in the preceding command line output refers to the Bundler tool. Bundler is a tool that downloads and manages Ruby gems. Test Kitchen needs you to run bundle install to download and install the kitchen-vagrant driver and some supporting gems.

NOTE

You might be prompted for your administrator/root password when running bundle install.
kitchen-vagrant is a driver for Test Kitchen that adds support for managing VirtualBox and VMware virtual machines using Vagrant. Nearly all Test Kitchen functionality is implemented via these drivers, as Test Kitchen is itself is nothing more than a generic framework for managing environments and running tests. Add-on drivers actually implement functionality. Run bundle install, like kitchen init, suggests installing those extra dependencies:
$ bundle install
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
Using mixlib-shellout (1.4.0)
Using net-ssh (2.9.1)
Using net-scp (1.2.1)
Using safe_yaml (1.0.3)
Using thor (0.19.1)
Using test-kitchen (1.2.1)
Using kitchen-vagrant (0.15.0)
Using bundler (1.5.2)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
Let’s go over the directory structure and files kitchen init just created:
.
├── .kitchen
│   └── logs
│       └── kitchen.log
├── .kitchen.yml
├── Gemfile
├── Gemfile.lock
└── test
    └── integration
        └── default
.kitchen.yml
Used to configure virtual environments for Test Kitchen.
Gemfile
Bundler uses this file to configure the gem repository and the list of gems to download. Bundler will automatically determine a gem’s dependencies by its references to other gems, so you need only list the top level gems you require.
Gemfile.lock
Records all the versions of the gems Bundler downloaded for the current project, plus the versions of all dependencies. This file can be used by another Chef developer to reproduce your current gem environment using bundle install.
.kitchen/
Hidden directory that Test Kitchen uses to store persistent data it needs to function properly.
.kitchen/logs/kitchen.log
Text file that contains the output from the last run of Test Kitchen.
test/
Directory structure that contains tests (initially just a skeleton structure with the subdirectory tree test/integration/default/).

Spinning Up Your First Virtual Machine

Before spinning up the virtual machine, you’ll need to modify the kitchen.yml configuration file created by kitchen init. You’ll need to change the .kitchen.yml configuration file so it loads the environment prepared exclusively for this book. Open .kitchen.yml with your programmer’s editor and edit the platforms: section to make sure .kitchen.yml resembles what you see in Example 5-1.
Example 5-1. kitchen/.kitchen.yml
---
driver:
  name: vagrant

provisioner:
  name: chef_solo

platforms:
  - name: centos65
    driver:
      box: learningchef/centos65
      box_url: learningchef/centos65

suites:
  - name: default
    run_list:
    attributes:

NOTE

Spacing matters in the .kitchen.yml file. Make sure you use the space character and not the tab character for white space. The .kitchen.yml should be tab free! Vertical alignment of the statements in this file also matters, so make sure the spacing lines up exactly as shown in Example 5-1.
This change will tell Test Kitchen to download the CentOS 6.5 image from VagrantCloud prepared for this book. The box: field must match the VagrantCloud box name listed on https://vagrantcloud.com/learningchef/centos65. The box name is learningchef/centos65. Because we will be typing in the name: field in Test Kitchen command prompts as an alias string for this box, we shorten it to centos65.
In Test Kitchen lingo, an instance is an environment that includes a way to create a virtual machine with an operating system and a way to deploy automation code. Run the kitchen list command to print out the available instance names:
$ kitchen list
Instance          Driver   Provisioner  Last Action
default-centos65  Vagrant  ChefSolo     <Not Created>
Notice that the default-centos65 instance is set up to use the Vagrant driver (kitchen-vagrant) and to use theChefSolo provisioner. We’ll cover the ChefSolo provisioner more in Chapter 9.

NOTE

If you are using a Windows PC, make sure you have hardware virtualization support enabled in your BIOS. For more information, see the VirtualBox User Manual.
To create a virtual environment on your Chef Development Workstation running CentOS, use the kitchen create command, passing it a Test Kitchen instance name. Depending on the speed of your Internet connection, this download might take anywhere from 5 to 15 minutes the first time:
$ kitchen create default-centos65
-----> Starting Kitchen (v1.2.2.dev)
-----> Creating <default-centos65>...
       Bringing machine 'default' up with 'virtualbox' provider...
       ==> default: Box 'learningchef/centos65' could not be found.
           default: Box Provider: virtualbox
           default: Box Version: >= 0
       ==> default: Loading metadata for box 'learningchef/centos65'
           default: URL: https://vagrantcloud.com/learningchef/centos65
       ==> default: Adding box 'learningchef/centos65' (v0.2.0) for provider:
           virtualbox
           default: Downloading: https://vagrantcloud.com/learningchef/centos65
       ==> default: Successfully added box 'learningchef/centos65' (v0.2.0) for
           'virtualbox'!
       ==> default: Importing base box 'learningchef/centos65'...
       ==> default: Matching MAC address for NAT networking...
       ==> default: Checking if box 'learningchef/centos65' is up to date...
       ==> default: Setting the name of the VM: default-centos65_default_
           1407741726274_31370
       ==> default: Clearing any previously set network interfaces...
       ==> default: Preparing network interfaces based on configuration...
           default: Adapter 1: nat
       ==> default: Forwarding ports...
           default: 22 => 2222 (adapter 1)
       ==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
           default: Warning: Connection timeout. Retrying...
       ==> default: Machine booted and ready!
       ==> default: Checking for guest additions in VM...
       ==> default: Setting hostname...
       ==> default: Machine not provisioning because `--no-provision`
       is specified.
       Vagrant instance <default-centos65> created.
       Finished creating <default-centos65> (1m43.54s).
-----> Kitchen is finished. (1m43.79s)

NOTE

When there is only one instance name in a .kitchen.yml file, there is no need to specify an instance name. The command line kitchen create would have been sufficient in the previous example. We’ll continue to specify the instance name on all kitchen command lines in this book for clarity. But feel free to omit them if you want to save typing a few extra characters.
The flowchart in Figure 5-3 presents an overview of the logic kitchen create uses to create a virtual environment.
kitchen create logic
Figure 5-3. kitchen create logic
The kitchen-vagrant driver uses prepackaged basebox templates to accelerate the virtual machine creation process. A basebox contains a bare-bones OS installation, just enough to enable Chef to run. Test Kitchen comes preconfigured to use baseboxes that Chef Software makes available on the Internet via VagrantCloud. The baseboxes vary in size, depending on the operating system, and are roughly the size of a CD—a 400-MB to 600-MB download. Test Kitchen downloads a basebox only once, if it is not already present on your system. Vagrant maintains the catalog of baseboxes, which you can view with the command vagrant box list.

NOTE

Do you want to create your own custom baseboxes? Packer can be used to create baseboxes from small configuration scripts. The Packer tool is available for download. Chef Software makes the configuration scripts for the Test Kitchen baseboxes freely available on the Internet; you can use these as a starting point.
Chef sponsors two projects: Bento and Box-Cutter. The Bento project contains Packer definitions that Chef uses internally to build software. Box-Cutter offers configuration management tool-agnostic Packer templates that go beyond the platforms Chef uses for its internal builds, offering more cutting-edge, experimental features.
Once a basebox has been downloaded, the box is imported to your virtualization software. Test Kitchen then works with the virtualization provider to configure a virtual machine instance according to the parameters set in the .kitchen.yml file. Finally, it boots up the virtual machine so that it is ready to use, creating an instance.
You can verify that Test Kitchen performed all these steps by running the kitchen list command, noting that its Last Action changed to Created:
$ kitchen list
Instance          Driver   Provisioner  Last Action
default-centos65  Vagrant  ChefSolo     Created
You can also verify that a virtual machine got created in the VirtualBox Manager as shown in Figure 5-4 and that VBoxManage list runningvms shows that a VM is running.
On Linux/Mac OS X:
$ VBoxManage list runningvms
"default-centos65_default_1407741726274_31370"
{70b5e95a-d5f5-4956-b8b6-86dbf00e7218}
On Windows Command Prompt:
> "C:\Program Files\Oracle\VirtualBox\VBoxManage" list runningvms
"default-centos65_default_1404514741641_54313"
{2db0fb6c-ab8e-4c65-99aa-2d4d4a4d27ff}
On Windows PowerShell:
PS> & "C:\Program Files\Oracle\VirtualBox\VBoxManage" list runningvms
"default-centos65_default_1404514741641_54313"
{2db0fb6c-ab8e-4c65-99aa-2d4d4a4d27ff}
CentOS 6.5 virtual machine running in VirtualBox
Figure 5-4. CentOS 6.5 virtual machine running in VirtualBox

NOTE

You might be tempted to manage these virtual machines directly in the VirtualBox Manager GUI. Be careful, because you might confuse Test Kitchen. It is intended that you use the Test Kitchen command line interface to manage the lifecycle of these virtual environments.
Now that the virtual machine has been created and started, you can log in to the instance via the kitchen login command, using the same instance name we used for kitchen create:
$ kitchen login default-centos65
Last login: Fri Jul  4 14:48:27 2014 from 10.0.2.2
Welcome to your Packer-built virtual machine.
You should notice that you are now logged into the CentOS 6.5 guest virtual machine running on your Chef Development Workstation host via Oracle VM VirtualBox. To verify that the operating system is indeed CentOS Enterprise Linux, run cat /etc/redhat-release to print out the operating system release information:
[vagrant@default-centos65 ~]$ cat /etc/redhat-release
CentOS release 6.5 (Final)

NOTE

If you get an error message that includes “No such file or directory - ssh,” make sure that you have the ssh program in your $PATH. On Windows, make sure you install the Unix tools for Windows, which includes the required ssh command (see Install Unix Tools for Windows).
In this book, you will see that all the virtual machine command lines will have the Test Kitchen instance name in them before the $ prompt. For example, note that the command lines you just ran in the virtual machine were all prefaced by [ ~]. This should make it less confusing as to whether commands should be run in the Chef Workstation host environment or the virtual machine guest environment.
To exit back out to your host command prompt, run the exit command. You should notice that the command prompt changes from [ ~] to the default prompt for your host platform:
[vagrant@default-centos65 ~]$ exit
logout
Connection to 127.0.0.1 closed.
Atwood:kitchen misheska$
We’re done with this sandbox environment. Run the kitchen destroy command to shut down the virtual machine and release all the associated system resources:
$ kitchen destroy default-centos65
-----> Starting Kitchen (v1.2.2.dev)
-----> Destroying <default-centos65>...
       ==> default: Forcing shutdown of VM...
       ==> default: Destroying VM and associated drives...
       Vagrant instance <default-centos65> destroyed.
       Finished destroying <default-centos65> (0m2.83s).
-----> Kitchen is finished. (0m3.07s)

YAML Overview

The .kitchen.yml configuration file used to configure Test Kitchen is in the YAML file format. YAML is a recursive acronym that stands for YAML Ain’t Markup Language. A sequence of three hyphens (---) denote the beginning of a YAML document, so you’ll see this at the beginning of every .kitchen.yml file. Comments are indicated by the hash symbol (#), just like in Ruby. Space and indentation matter in a YAML file. Tab characters should never be used in a YAML file, only spaces.
YAML files work with two fundamental kinds of a data:
  • Key-value pair
  • List
A key-value pair has the form <key>: <value> like:
name: vagrant
The space after the colon is required. The value for name is vagrant. The value vagrant can be looked up by the name key.
Key-value pairs can be nested, so that the value for a key is another key-value pair. When a key-value pair is nested, the value portion for the parent is written on separate lines, indented by at least one space. For example:
driver:
  name: vagrant
  aws_access_key_id: 12345
Having more spaces is perfectly fine, as long as the values belonging to the same nested key-value pair are all aligned vertically, with the same number of spaces:
driver:
             name: vagrant
             aws_access_key_id: 12345
You can also include as many spaces as you like before the colon, like so:
driver:
  name              : vagrant
  aws_access_key_id : 12345
If there were no spaces before each line, the nested values would not be interpreted correctly, however:
driver:
name: vagrant
aws_access_key_id: 12345
There is an alternate format for nested key-value pairs. They can also be in the form of {<key>: <value>, <key>: <value>, …}, also known as JavaScript Object Notation format, or JSON. For example:
mysql: {server_root_password: "rootpass", server_debian_password: "debpass"}
It is interpreted the same as:
mysql:
  server_root_password: "rootpass"
  server_debian_password: "debpass"
Lists are the other kind of data that can be stored in a YAML file. Lists contain ordered data. Each value is not associated with a key, like in a key-value pair. Lists are used when having a key for each value does not make sense. The items in a list are on separate lines, similar to nested key-value pairs. The items start with a dash followed by a space. Here’s an example from a .kitchen.yml for a list of supported platforms, as key-value pairs with the name key, name:
platforms:
- name: ubuntu-10.04
- name: ubuntu-12.04
- name: ubuntu-12.10
- name: ubuntu-13.04
- name: centos-5.9
- name: centos-6.4
- name: debian-7.1.0
The previous example also shows how you can put key-value pairs inside of a list. (You can also put lists inside of a key-value pair as well.) Similar to key-value pairs, the items in a list can have any number of spaces before, as long as all the items have the same number of spaces. The following would be equivalent to the last example:
platforms:
    - name: ubuntu-10.04
    - name: ubuntu-12.04
    - name: ubuntu-12.10
    - name: ubuntu-13.04
    - name: centos-5.9
    - name: centos-6.4
    - name: debian-7.1.0
Values can also have a type. kitchen.yml files mostly deal with integers, strings, or arrays. Values that start with a digit are interpreted as integers. Values that start with an alphabetical character, enclosed by single quotes ('') or double quotes (“”), are interpreted as strings. Arrays are enclosed by square brackets ([ ]), with values separated by commas. Here’s an example that puts all these concepts together:
network:
- ["forwarded_port", {guest: 80, host: 8080}]
- ["private_network", {ip: "192.168.33.33"}]

Test Kitchen Configuration with .kitchen.yml

Now that you understand the basics of YAML, let’s go over the .kitchen.yml file that Test Kitchen generated:
---
driver:
  name: vagrant

provisioner:
  name: chef_solo

platforms:
  - name: ubuntu-12.04
  - name: centos-6.4

suites:
  - name: default
    run_list:
    attributes:
The three hyphens at the beginning denote that kitchen.yml is a YAML file.
The .kitchen.yml contains four main sections:
driver:
Specifies the driver plugin to use, plus configuration parameters to manage Test Kitchen environments. You can get a list of drivers running the command kitchen driver discover. We’re using the default driver kitchen-vagrant. By convention, the kitchen- part of the driver name is dropped when specified in kitchen.yml.
provisioner:
Determines which configuration management tool will be used to provision the driver’s environment(s). We’re using the chef_solo provisioner. When you run kitchen setup it will install Chef Client on the node, if it is not already installed.
platforms:
A list of operating systems for which Test Kitchen will create instances.
suites:
In the case of the Chef configuration management tool, specifies a configuration to be run on each instance. Among other things, a suite contains a list of recipes to run on each instance.
The platform names in your .kitchen.yml file are aliases that point to baseboxes managed by Chef Software. When you see values such as:
---
platforms:
  - name: ubuntu-12.04
  - name: centos-6.4
Test Kitchen expands the values to the following internally:
platforms:
- name: ubuntu-12.04
  driver:
    box: opscode-ubuntu-12.04
    box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/\
             opscode_ubuntu-12.04_provisionerless.box
- name: centos-6.4
  driver:
    box: opscode-centos-6.4
    box_url: https://opscode-vm-bento.s3.amazonaws.com/vagrant/\
             opscode_centos-6.4_provisionerless.box
Each platform item can have a driver key-value pair that specifies a box and a box_url, denoting the name of the box in the vagrant box list catalog and the URL from which the basebox file can be downloaded, respectively. When they are not specified, the kitchen-vagrant driver assumes you want to download baseboxes from the standard Chef Software site on the Internet.

Summary

In this chapter, we introduced the following commands that Test Kitchen uses to manage sandbox environments:
kitchen init
Add Test Kitchen support to a project
kitchen list
Display information about Test Kitchen instances
kitchen create
Start a Test Kitchen instance, if it is not already running
kitchen login
Log into a Test Kitchen instance
kitchen destroy
Shut down an instance and destroy the virtual machine
We introduced the following configuration files that control the behavior of Test Kitchen:
.kitchen.yml
Configures Test Kitchen environment settings
Gemfile
List of gems needed and the repository from which Bundler should download gems via bundle install
Gemfile.lock
List of gem dependencies determined by Bundler when bundle install runs. Used to reproduce an identical setup on another developer’s machine
We explained the YAML file format used by .kitchen.yml files in great detail, including how to configure synced folders to synchronize source between your host and guest environments.
Also, we pointed you at http://learningchef.com should you wish to use an alternative to the Vagrant + VirtualBox setup around which we’ve tailored the hands-on exercises in this book. You can find some great .kitchen.yml file examples there as well.
In the next chapter, we’ll learn more about nodesNode is the generic term Chef uses to refer to any system managed by Chef.

No comments:

Post a Comment