Key Benefits

  • OS and CM agnostic
  • InSpec runtime is faster than ServerSpec
  • DRY – Componentization of test suites using shared InSpec Profiles
  • Removes downloading of Gem files on every test execution
  • Quick to Change from ServerSpec to InSpec
  • CLI binary available to run tests from CI/CD
  • Allows usage of community test suites
  • Allows usage of InSpec Profiles from a Chef Compliance server
  • Allows compliance reporting to Chef Automate Visibility server

ServerSpec has been a great automated integration test framework for years, but it has always had some limitations. Such as, when running with Test Kitchen it downloads several gems every time tests are run and the inability to easily have shared test suites that could be used by multiple cookbooks or delivery solutions. Chef took on the challenge of extending ServerSpec to solve many of these inadequacies. Chef created a project named InSpec. It supports the same fundamental syntax of ServerSpec and adds extended capabilities.

InSpec does not require downloading gems during testing. ChefDK comes with all you need which the minimum is the inspec Rubygem. It also has the Test Kitchen extension gem named kitchen-inspec. Just this along makes for faster testing. Also, it helps for environments that may not have internet access.

InSpec also brings shared capabilities by way of what they’ve called InSpec Profiles. InSpec Profiles can be simple or as complex as you would like to make. With Profiles, you can also pass arguments. For example, you can have a shared InSpec Profile hosted in its own Git repo that tests for the version of Chef Client installed. You can set a default Chef Client version to check for, but allow an argument to override the default. So, you can pass in an argument string to the test profile with the version you expect and want it to check for. I have a simple example of that here.

When using InSpec with Test Kitchen it is possible to call multiple InSpec Profiles remote and/or local. For example, it’s possible to have said a set of standard security/compliance profiles, other cookbooks that are wrapped, baseline profile (bootstrapping) and then have a local profile that checks the specific cookbook configurations.

Here’s an example Kitchen config from bonusbits_mediawiki_nginx cookbook. This is at root level of a test suite.

    verifier:
      inspec_tests:
        - name: bootstrap
          git: https://github.com/bonusbits/inspec_bootstrap.git
        - name: bonusbits_base
          git: https://github.com/bonusbits/inspec_bonusbits_base.git
        - path: test/inspec/profiles/bonusbits_web/
      attributes:
        chef_version: '12.19.36'

It’s fairly easy and quick to migrate ServerSpec tests to InSpec tests. In all actuality, you could migrate some local ServerSpec tests to InSpec in a matter of minutes.

To demonstrate how quickly we can convert ServerSpec to InSpec I have created a short series of videos that walk through this process. Companions to the videos are Github reference branches for each part and wiki articles that I have linked below:

ServerSpec to InSpec – Part 1
Creating a ServerSpec Tested Chef Cookbook


Github Branch – Part 1
Wiki Article – Part 1

ServerSpec to InSpec – Part 2
Converting Local ServerSpec to Local InSpec Tests


Github Branch – Part 2
Wiki Article – Part 2

ServerSpec to InSpec – Part 3
Converting Local InSpec to Shared Remote Tests


Github Branch – Part 3
Github Example Shared InSpec Profile
Wiki Article

Complete Walkthrough Video Playlist

Spoiler!

Ok, so if you don’t have time to watch videos or read the wiki articles. Here’s the basic conversion for local ServerSpec to local InSpec tests. This is from Part 2. Part 3 goes into the best part about InSpec which is remote/shared tests.

Before

test
└── integration
 ├── default
 │   └── serverspec
 │      ├── nginx_spec.rb
 │      └── phpfpm_spec.rb
 └── helpers
    └── serverspec
       └── spec_helper.rb
test/integration/default/serverspec/nginx_spec.rb
require 'spec_helper'

describe 'Nginx' do
  it 'nginx installed' do
    expect(package('nginx')).to be_installed
  end

  it 'nginx service' do
    expect(service('nginx')).to be_enabled
    expect(service('nginx')).to be_running
  end
end
test/integration/default/serverspec/phpfpm_spec.rb
require 'spec_helper'

describe 'Php FPM' do
  it 'php-fpm installed' do
    expect(package('php70-fpm')).to be_installed
  end

  it 'php-fpm service' do
    expect(service('php-fpm-7.0')).to be_enabled
    expect(service('php-fpm-7.0')).to be_running
  end

  it 'nginx owns /var/log/php-fpm' do
    expect(file('/var/log/php-fpm')).to be_owned_by('nginx')
    expect(file('/var/log/php-fpm/7.0')).to be_owned_by('nginx')
  end

  it 'nginx owns /var/lib/php/7.0' do
    expect(file('/var/lib/php/7.0')).to be_grouped_into('nginx')
  end
end
test/integration/helpers/serverspec/spec_helper.rb
# Encoding: utf-8
require 'serverspec'

if (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM).nil?
  set :backend, :exec
  set :path, '/sbin:/usr/local/sbin:/bin:/usr/bin:$PATH'
else
  set :backend, :cmd
  set :os, family: 'windows'
end

After

test
└── integration
    └── default
        └── inspec
            ├── nginx_spec.rb
            └── phpfpm_spec.rb
test/integration/default/serverspec/nginx_spec.rb
describe 'Nginx' do
  it 'nginx installed' do
    expect(package('nginx')).to be_installed
  end

  it 'nginx service' do
    expect(service('nginx')).to be_enabled
    expect(service('nginx')).to be_running
  end
end
test/integration/default/serverspec/phpfpm_spec.rb
describe 'Php FPM' do
  it 'php-fpm installed' do
    expect(package('php70-fpm')).to be_installed
  end

  it 'php-fpm service' do
    expect(service('php-fpm-7.0')).to be_enabled
    expect(service('php-fpm-7.0')).to be_running
  end

  it 'nginx owns /var/log/php-fpm' do
    expect(file('/var/log/php-fpm')).to be_owned_by('nginx')
    expect(file('/var/log/php-fpm/7.0')).to be_owned_by('nginx')
  end

  it 'nginx owns /var/lib/php/7.0' do
    expect(file('/var/lib/php/7.0')).to be_grouped_into('nginx')
  end
end
.kitchen.yml
verifier:
  name: inspec

Resources

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s