Stub Chef guard_interpreter for ChefSpec test

2016/12/20

If you have a Chef cookbook with a resource containing a “guardian”, like, let’s say a PowerShell guard interpreter, you must stub the content of the Chef guard.
Here is an example of the resource using the guardian:

file “some_log_path” do
  guard_interpreter :powershell_script
  action :delete
  not_if “(ls -Dir ‘C:\temp’).Name.Contains(‘build’)”
end

Here’s how you have to construct your ChefSpec file:

describe ‘my_cookbook::my_recipe’ do
  let(:chef_run) do
    ChefSpec::ServerRunner.new do |node, server|
      stub_chef_server(node, server)
    end.converge(described_recipe)
  end

  before do
    stub_command(“(ls -Dir ‘C:\temp’).Name.Contains(‘build’)”).and_return(false)
  end

  it ‘does not raise an exception’ do
    expect { chef_run }.to_not raise_error
  end

  it ‘deletes the existing log file’ do
    expect(chef_run).to delete_file(‘C:\temp\releases\some_build\log.txt’)
  end
end


LWRP for deleting old builds

2016/12/07

In your cookbook, in libraries folder, create the following:

provider_cache_cleaner.rb

class BuildCacheCleaner
  # Provider for build_cache_cleaner
  class BuildCacheCleanerProvider < Chef::Provider::LWRPBase
    provides :build_cache_cleaner
    use_inline_resources
    action :delete do
      delete_count = 0
      if ::File.directory?(new_resource.cache_path)
        search_path = ::File.join(new_resource.cache_path.to_path, “#{new_resource.suffix}*\.#{new_resource.extension}”)
        cached_files = ::Dir.glob(search_path).sort_by { |f| ::File.ctime(f) }
        if cached_files.count > new_resource.keep_count
          delete_count = cached_files.count – new_resource.keep_count
        end
        files_to_delete = cached_files.first(delete_count)
        unless files_to_delete.empty?
          Chef::Log.info(“#{delete_count} cached builds will be deleted !”)
          files_to_delete.each do |file_name|
            Chef::Log.info(“Deleting file #{::File.basename(file_name)} …”)
            ::File.delete(file_name)
          end
        end
      end
      new_resource.updated_by_last_action(true) if delete_count > 0
    end
  end
end

resource_cache_cleaner.rb

class BuildCacheCleaner
  # Resource for build_cache_cleaner
  class BuildCacheCleanerResource < Chef::Resource::LWRPBase
    resource_name :build_cache_cleaner
    provides :build_cache_cleaner

    actions(:delete)
    default_action(:delete)

    attribute :keep_count, :kind_of => Integer, :required => false, :default => 5
    attribute :suffix, :kind_of => String, :required => false, :default => ‘Build’
    attribute :extension, :kind_of => String, :required => false, :default => ‘zip’
    attribute :cache_path, :kind_of => String, :required => false, :default => Chef::Config[:file_cache_path]
  end
end

string_util.rb

# String utility extension methods
class String
  def to_path(end_slash = false)
    “#{‘/’ if self[0] == ‘\\’}#{split(‘\\’).join(‘/’)}#{‘/’ if end_slash}”
  end
end

matchers.rb

# ChefSpec is a tool to unit test cookbooks in conjunction with rspec
# Learn more on the README or at https://github.com/sethvargo/chefspec.
if defined?(ChefSpec)
  def delete_build_cache_cleaner(resource_name)
    ChefSpec::Matchers::ResourceMatcher.new(:build_cache_cleaner, :delete, resource_name)
  end
end

In your recipe, use the resource as follow:

build_cache_cleaner ‘delete cached builds’ do
  keep_count 7
end

In your ChefSpec test, add the following:

it ‘deletes unused cached builds’ do
  expect(chef_run).to delete_build_cache_cleaner(‘delete cached builds’)
end

Note 1: Credits go to StackOverflow, IT blogs and alike, sites that helped me with the code when searching for solutions.
Note 2: Be aware that when copy-pasting, the quotes and possibly other characters get messed up by WordPress, you’ll have to replace them.
Note 3: While I may have tested myself most of the bits of code posted here, please be aware that you’re trying the code/scripts at your own risk, and I take no responsibility for any damage that may occur on your system(s).


Add Chef cookbook dependency in Berksfile group for testing

2016/11/24
source `https://supermarket.chef.io`

metadata

group :integration do
cookbook ‘some_cookbook’, path: ‘./test/fixtures/cookbooks/some_cookbook’

# not a strict dependency, but necessary for testing
cookbook ‘java’
end

Note 1: Credits go to StackOverflow, IT blogs and alike, sites that helped me with the code when searching for solutions.
Note 2: Be aware that when copy-pasting, the quotes and possibly other characters get messed up by WordPress, you’ll have to replace them.


Useful Chef development prerequisites

2016/03/02

The PowerShell commands below are some main steps needed to configure Chef on a development machine; still, they are not the only needed steps, there are others, like adding the SSH key to GitLab, downloading PEM key from Chef server, maybe Azure configuration, etc.

# Installing packages with Chocolatey
choco install atom -y
choco install git -y
choco install poshgit -y
choco install chefdk -y
choco install virtualbox -y
choco install virtualbox.extensionpack -y
choco install vagrant -y
choco install vagrant-winrm-config -y

# Restart required after packages installation
Restart-Computer

# Install gems for Pester and chef-vault, if used for tests
chef gem install kitchen-pester
chef gem install chef-vault-testfixtures

# Environment variables configuration
$home_folder = “d:\home”
$chef_user = “”
$chef_repo = “d:\repos”
$chef_module = “your-chef-module”
if (!(Test-Path $home_folder)) {
  mkdir $home_folder
}
[Environment]::SetEnvironmentVariable(“Path”, $env:Path + “;C:\Program Files\Git\usr\bin”, “Machine”)
[Environment]::SetEnvironmentVariable(“HOME”, “$home_folder”, “User”)
[Environment]::SetEnvironmentVariable(“CHEF_ORG”, “your-organization”, “User”)
[Environment]::SetEnvironmentVariable(“CHEF_USER”, $chef_user, “User”)
[Environment]::SetEnvironmentVariable(“Path”, $env:Path + “;C:\HashiCorp\Vagrant\bin”, “Machine”)
[Environment]::SetEnvironmentVariable(“VAGRANT_HOME”, “$env:HOME\vagrant.d”, “User”)

# Git configuration
git config –global user.name “”
git config –global user.email “”
git config –global push.default simple

# SSH key generation
ssh-keygen -t rsa -b 4096 -C “”

# Handle Git repository locally
cd $chef_repo
git clone git@gitlab.com:cookbooks-parent-folder/$chef_module.git
cd $chef_module
git submodule update –init –remote

# Handle knife settings
Copy-Item “$chef_repo\$chef_module\chef\.chef\knife.rb” “$env:HOME\.chef\knife.rb”

# Install vagrant plugin for WinRM
vagrant plugin install vagrant-winrm


Chef converge error “No such file or directory”

2015/11/04

If you get the following error when you are converging a kitchen

>>>>>> Message: Failed to complete #converge action: [No such file or directory @ some_name_here (…)

then most probably you forgot to exclude the .kitchen from .gitignore :

.kitchen/
.kitchen.local.yml

and from chefignore files :

# Kitchen #
###########
.kitchen

%d bloggers like this: