Garcon

A collection of methods helpful in writing complex cookbooks that are impossible to comprehend.

Hipster, hoodie ninja cool awesome.

Requirements

Before trying to use the cookbook make sure you have a supported system. If you are attempting to use the cookbook in a standalone manner to do testing and development you will need a functioning Chef/Ruby environment, with the following:

Chef

Chef Server version 11+ and Chef Client version 11.16.2+ and Ohai 7+ are required. Clients older that 11.16.2 do not work.

Platforms

This cookbook uses Test Kitchen to do cross-platform convergence and post- convergence tests. The tested platforms are considered supported. This cookbook may work on other platforms or platform versions with or without modification.

Cookbooks

The following cookbooks are required as noted (check the metadata.rb file for the specific version numbers):

Development Requirements

In order to develop and test this Cookbook, you will need a handful of gems installed.

It is recommended for you to use the Chef Developer Kit (ChefDK). You can get the latest release of ChefDK from the downloads page.

On Mac OS X, you can also use homebrew-cask to install ChefDK.

Once you install the package, the chef-client suite, berks, kitchen, and this application (chef) will be symlinked into your system bin directory, ready to use.

You should then set your Ruby/Chef development environment to use ChefDK. You can do so by initializing your shell with ChefDK’s environment.

eval "$(chef shell-init SHELL_NAME)"

where SHELL_NAME is the name of your shell, (bash or zsh). This modifies your PATH and GEM_* environment variables to include ChefDK’s paths (run without the eval to see the generated code). Now your default ruby and associated tools will be the ones from ChefDK:

which ruby
# => /opt/chefdk/embedded/bin/ruby

You will also need Vagrant 1.6+ installed and a Virtualization provider such as VirtualBox or VMware.

Usage

Include the garcon recipe in your run list:

include_recipe 'garcon::default'

Attributes

Attributes are under the garcon namespace, the following attributes affect the behavior of how the cookbook performs an installation, or are used in the recipes for various settings that require flexibility.

General attributes:

General attributes can be found in the default.rb file.

Providers

This cookbook includes HWRPs for managing:

download

Use the download resource to transfer files from a remote location, similar to remote_file but provides multithreaded torrent and http downloader utilizing Aria2. This can be up to four times faster than the standard remote_file resource, useful for large file transfers.

Syntax

The syntax for using the download resource in a recipe is as follows:

download 'name' do
  attribute 'value' # see attributes section below
  ...
  action :action # see actions section below
end

Where:

For example:

download ::File.join(Chef::Config[:file_cache_path], 'file.tar.gz') do
  source 'http://www.example.org/file.tar.gz'
end

Actions

Attribute Parameters

Examples

The following examples demonstrate various approaches for using resources in recipes. If you want to see examples of how Chef uses resources in recipes, take a closer look at the cookbooks that Chef authors and maintains: https:// github.com/opscode-cookbooks.

Transfer a file from a URL
download '/tmp/testfile' do
  source 'http://www.example.com/tempfiles/testfile'
  mode 00644
  checksum '3a7dac00b1' # A SHA256 (or portion thereof) of the file.
end
Transfer a file only when the source has changed
download '/tmp/file.png' do
  source 'http://example.com/file.png'
  action :nothing
end

http_request 'HEAD //example.com/file.png' do
  message ''
  url '//example.com/file.png'
  action :head
  if ::File.exists?('/tmp/file.png')
    header "If-Modified-Since" => ::File.mtime("/tmp/file.png").httpdate
  end
  notifies :create, 'download[http://example.com/file.png]', :immediately
end
Install a file from a remote location using bash

The following is an example of how to install the foo123 module for Nginx. This module adds shell-style functionality to an Nginx configuration file and does the following:

The following code sample is similar to the upload_progress_module recipe in the nginx cookbook.

src_file = "foo123-nginx-module-v#{node[:nginx][:foo123][:version]}.tar.gz"
src_path = ::File.join(Chef::Config[:file_cache_path], src_file)
extract_path = ::File.join(Chef::Config[:file_cache_path],
  'nginx_foo123_module', node[:nginx][:foo123][:checksum]
)

download src_path do
  source node[:nginx][:foo123][:url]
  checksum node[:nginx][:foo123][:checksum]
  owner 'root'
  group 'root'
  mode 00644
end

bash 'extract module' do
  cwm ::File.dirname(src_path)
  code <<-CODE
    mkdir -p #{extract_path}
    tar xzf #{src_file} -C #{extract_path}
    mv #{extract_path}/*/* #{extract_path}/
  CODE
  not_if { ::File.exist?(extract_path) }
end

zip_file

This resource provides a pure-ruby implementation for managing zip files. Be sure to use the not_if or only_if meta parameters to guard the resource for idempotence or action will be taken every Chef run.

Syntax

The syntax for using the zip_file resource in a recipe is as follows:

zip_file 'name' do
  attribute 'value' # see attributes section below
  ...
  action :action # see actions section below
end

Where:

For example:

zip_file '/tmp/path' do
  source 'http://www.example.org/file.tar.gz'
end

Actions

Attribute Parameters

Examples

The following examples demonstrate various approaches for using resources in recipes. If you want to see examples of how Chef uses resources in recipes, take a closer look at the cookbooks that Chef authors and maintains: https:// github.com/opscode-cookbooks.

Unzip a remote zip file locally
zip_file '/opt/app' do
  source 'http://example.com/app.zip'
  owner 'app_user'
  group 'app_group'
  action :unzip
  not_if { ::File.exist?('/opt/app/bin/startup.sh') }
end
Unzip a local zipfile
zip_file '/home/foo' do
  source '/tmp/something.zip'
  action :unzip
end
Create a local zipfile
zip_file '/tmp/foo.zip' do
  source '/home/foo'
  action :zip
end

Testing

Ensure you have all the required prerequisite listed in the Development Requirements section. You should have a working Vagrant installation with either VirtualBox or VMware installed. From the parent directory of this cookbook begin by running bundler to ensure you have all the required Gems:

bundle install

A ruby environment with Bundler installed is a prerequisite for using the testing harness shipped with this cookbook. At the time of this writing, it works with Ruby 2.1.2 and Bundler 1.6.2. All programs involved, with the exception of Vagrant and VirtualBox, can be installed by cd’ing into the parent directory of this cookbook and running ‘bundle install’.

Vagrant and VirtualBox

The installation of Vagrant and VirtualBox is extremely complex and involved. Please be prepared to spend some time at your computer:

If you have not yet installed Homebrew do so now:

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

Next install Homebrew Cask:

brew tap phinze/homebrew-cask && brew install brew-cask

Then, to get Vagrant installed run this command:

brew cask install vagrant

Finally install VirtualBox:

brew cask install virtualbox

You will also need to get the Berkshelf and Omnibus plugins for Vagrant:

vagrant plugin install vagrant-berkshelf
vagrant plugin install vagrant-omnibus

Try doing that on Windows.

Rakefile

The Rakefile ships with a number of tasks, each of which can be ran individually, or in groups. Typing rake by itself will perform style checks with Rubocop and Foodcritic, Chefspec with rspec, and integration with Test Kitchen using the Vagrant driver by default. Alternatively, integration tests can be ran with Test Kitchen cloud drivers for EC2 are provided.

$ rake -T
rake all                         # Run all tasks
rake chefspec                    # Run RSpec code examples
rake doc                         # Build documentation
rake foodcritic                  # Lint Chef cookbooks
rake kitchen:all                 # Run all test instances
rake kitchen:apps-dir-centos-65  # Run apps-dir-centos-65 test instance
rake kitchen:default-centos-65   # Run default-centos-65 test instance
rake kitchen:ihs-centos-65       # Run ihs-centos-65 test instance
rake kitchen:was-centos-65       # Run was-centos-65 test instance
rake kitchen:wps-centos-65       # Run wps-centos-65 test instance
rake readme                      # Generate README.md from _README.md.erb
rake rubocop                     # Run RuboCop
rake rubocop:auto_correct        # Auto-correct RuboCop offenses
rake test                        # Run all tests except `kitchen` / Run
                                 # kitchen integration tests
rake yard                        # Generate YARD Documentation

Style Testing

Ruby style tests can be performed by Rubocop by issuing either the bundled binary or with the Rake task:

$ bundle exec rubocop
    or
$ rake style:ruby

Chef style tests can be performed with Foodcritic by issuing either:

$ bundle exec foodcritic
    or
$ rake style:chef

Testing

This cookbook uses Test Kitchen to verify functionality.

  1. Install ChefDK

  2. Activate ChefDK’s copy of ruby: eval "$(chef shell-init bash)"

  3. bundle install

  4. bundle exec kitchen test kitchen:default-centos-65

Spec Testing

Unit testing is done by running Rspec examples. Rspec will test any libraries, then test recipes using ChefSpec. This works by compiling a recipe (but not converging it), and allowing the user to make assertions about the resource_collection.

Integration Testing

Integration testing is performed by Test Kitchen. Test Kitchen will use either the Vagrant driver or EC2 cloud driver to instantiate machines and apply cookbooks. After a successful converge, tests are uploaded and ran out of band of Chef. Tests are be designed to ensure that a recipe has accomplished its goal.

Integration Testing using Vagrant

Integration tests can be performed on a local workstation using Virtualbox or VMWare. Detailed instructions for setting this up can be found at the Bento project web site. Integration tests using Vagrant can be performed with either:

$ bundle exec kitchen test
    or
$ rake integration:vagrant

Integration Testing using EC2 Cloud provider

Integration tests can be performed on an EC2 providers using Test Kitchen plugins. This cookbook references environmental variables present in the shell that kitchen test is ran from. These must contain authentication tokens for driving APIs, as well as the paths to ssh private keys needed for Test Kitchen log into them after they’ve been created.

Examples of environment variables being set in ~/.bash_profile:

# aws
export AWS_ACCESS_KEY_ID='your_bits_here'
export AWS_SECRET_ACCESS_KEY='your_bits_here'
export AWS_KEYPAIR_NAME='your_bits_here'

Integration tests using cloud drivers can be performed with either

$ bundle exec kitchen test
    or
$ rake integration:cloud

Guard

Guard tasks have been separated into the following groups:

By default, Guard will generate documentation, lint, and run unit tests. The integration group must be selected manually with guard -g integration.

Contributing

Please see the CONTRIBUTING.md.

License and Authors

Author:: Stefano Harding riddopic@gmail.com

Copyright:: 2014-2015, Stefano Harding

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.