--- title: InSpec Migration Guide --- # Migrate from Serverspec to InSpec ## How is InSpec different from Serverspec We've written a complete blog post about that topic: [The Road to InSpec](https://blog.chef.io/2015/11/04/the-road-to-inspec/) ## Is InSpec suitable for infrastructure testing? InSpec is a framework that allows you to run infrastructure testing as well as compliance testing. The compliance features are always optional and provide customers a way to use InSpec for both use-cases. To ensure we build the best infrastructure testing, we migrate our cookbooks [chef-cookbooks](https://github.com/chef-cookbooks) to InSpec. ## Which Serverspec resources are available in InSpec? The following resources are available in InSpec: | Serverspec | InSpec | |:------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------:| | [`bond`](http://serverspec.org/resource_types.html#bond) | [`bond`](https://www.inspec.io/docs/reference/resources/bond/) | | [`bridge`](http://serverspec.org/resource_types.html#bridge) | [`bridge`](https://www.inspec.io/docs/reference/resources/bridge/) | | [`command`](http://serverspec.org/resource_types.html#command) | [`command`](https://www.inspec.io/docs/reference/resources/command/) | | [`cron`](http://serverspec.org/resource_types.html#cron) | [`crontab`](https://www.inspec.io/docs/reference/resources/crontab/) | | [`docker_container`](http://serverspec.org/resource_types.html#docker_container) | [`docker_container`](https://www.inspec.io/docs/reference/resources/docker_container/) | | [`docker_image`](http://serverspec.org/resource_types.html#docker_image) | [`docker_image`](https://www.inspec.io/docs/reference/resources/docker_image/) | | [`file`](http://serverspec.org/resource_types.html#file) | [`file`](https://www.inspec.io/docs/reference/resources/file/) | | [`group`](http://serverspec.org/resource_types.html#group) | [`group`](https://www.inspec.io/docs/reference/resources/group/) | | [`host`](http://serverspec.org/resource_types.html#host) | [`host`](https://www.inspec.io/docs/reference/resources/host/) | | [`interface`](http://serverspec.org/resource_types.html#interface) | [`interface`](https://www.inspec.io/docs/reference/resources/interface/) | | [`iis_website`](http://serverspec.org/resource_types.html#iis_website) | [`iis_website`](https://www.inspec.io/docs/reference/resources/iis_website/) | | [`iis_app_pool`](http://serverspec.org/resource_types.html#iis_app_pool) | [`iis_website`](https://www.inspec.io/docs/reference/resources/iis_website/) | | [`iptables`](http://serverspec.org/resource_types.html#iptables) | [`iptables`](https://www.inspec.io/docs/reference/resources/iptables/) | | [`kernel_module`](http://serverspec.org/resource_types.html#kernel_module) | [`kernel_module`](https://www.inspec.io/docs/reference/resources/kernel_module/) | | [`linux_kernel_parameter`](http://serverspec.org/resource_types.html#linux_kernel_parameter) | [`kernel_parameter`](https://www.inspec.io/docs/reference/resources/kernel_parameter/) | | [`mysql_config`](http://serverspec.org/resource_types.html#mysql_config) | [`mysql_conf`](https://www.inspec.io/docs/reference/resources/mysql_conf/) | | [`package`](http://serverspec.org/resource_types.html#package) | [`package`](https://www.inspec.io/docs/reference/resources/package/) | | [`port`](http://serverspec.org/resource_types.html#port) | [`port`](https://www.inspec.io/docs/reference/resources/port/) | | [`ppa`](http://serverspec.org/resource_types.html#ppa) | [`apt`](https://www.inspec.io/docs/reference/resources/apt/) | | [`process`](http://serverspec.org/resource_types.html#process) | [`processes`](https://www.inspec.io/docs/reference/resources/processes/) | | [`service`](http://serverspec.org/resource_types.html#service) | [`service`](https://www.inspec.io/docs/reference/resources/service/) | | [`user`](http://serverspec.org/resource_types.html#user) | [`user`](https://www.inspec.io/docs/reference/resources/user/) | | [`windows_feature`](http://serverspec.org/resource_types.html#windows_feature) | [`windows_feature`](https://www.inspec.io/docs/reference/resources/windows_feature/) | | [`windows_registry_key`](http://serverspec.org/resource_types.html#windows_registry_key) | [`registry_key`](https://www.inspec.io/docs/reference/resources/registry_key/) | | [`x509_certificate`](http://serverspec.org/resource_types.html#x509_certificate) | [`x509_certificate`](https://www.inspec.io/docs/reference/resources/x509_certificate/) | | [`yumrepo`](http://serverspec.org/resource_types.html#yumrepo) | [`yum`](https://www.inspec.io/docs/reference/resources/yum/) | | [`zfs`](http://serverspec.org/resource_types.html#zfs) | [`zfs_pool`](https://www.inspec.io/docs/reference/resources/zfs_pool/) | Some Serverspec resources are not available yet. We will implement those resources based on user feedback. If you need a resource that is not available in InSpec, please open an [Github issue](https://github.com/chef/inspec/issues). The list of resources that are not available in InSpec: * [`cgroup`](http://serverspec.org/resource_types.html#cgroup) * [`default_gateway`](http://serverspec.org/resource_types.html#default_gateway) * [`ip6tables`](http://serverspec.org/resource_types.html#ip6tables) * [`ipfilter`](http://serverspec.org/resource_types.html#ipfilter) * [`ipnat`](http://serverspec.org/resource_types.html#ipnat) * [`linux_audit_system`](http://serverspec.org/resource_types.html#linux_audit_system) * [`lxc`](http://serverspec.org/resource_types.html#lxc) * [`mail_alias`](http://serverspec.org/resource_types.html#mail_alias) * [`php_config`](http://serverspec.org/resource_types.html#php_config) * [`routing_table`](http://serverspec.org/resource_types.html#routing_table) * [`selinux`](http://serverspec.org/resource_types.html#selinux) * [`selinux_module`](http://serverspec.org/resource_types.html#selinux_module) * [`x509_private_key`](http://serverspec.org/resource_types.html#x509_private_key) In addition InSpec provides additional [resources](https://www.inspec.io/docs/reference/resources/) that are not available in Serverspec: * [`apache_conf`](https://www.inspec.io/docs/reference/resources/apache_conf/) * [`apt`](https://www.inspec.io/docs/reference/resources/apt/) * [`audit_policy`](https://www.inspec.io/docs/reference/resources/audit_policy/) * [`auditd_conf`](https://www.inspec.io/docs/reference/resources/auditd_conf/) * [`bash`](https://www.inspec.io/docs/reference/resources/bash/) * [`csv`](https://www.inspec.io/docs/reference/resources/csv/) * [`etc_shadow`](https://www.inspec.io/docs/reference/resources/etc_shadow/) * [`gem`](https://www.inspec.io/docs/reference/resources/gem/) * [`grub_conf`](https://www.inspec.io/docs/reference/resources/grub_conf/) * [`inetd_conf`](https://www.inspec.io/docs/reference/resources/inetd_conf/) * [`ini`](https://www.inspec.io/docs/reference/resources/ini/) * [`json`](https://www.inspec.io/docs/reference/resources/json/) * [`npm`](https://www.inspec.io/docs/reference/resources/npm/) * [`ntp_conf`](https://www.inspec.io/docs/reference/resources/ntp_conf/) * [`oneget`](https://www.inspec.io/docs/reference/resources/oneget/) * [`pip`](https://www.inspec.io/docs/reference/resources/pip/) * [`powershell`](https://www.inspec.io/docs/reference/resources/powershell/) * [`security_policy`](https://www.inspec.io/docs/reference/resources/security_policy/) * [`ssh_config`](https://www.inspec.io/docs/reference/resources/ssh_config/) * [`sshd_config`](https://www.inspec.io/docs/reference/resources/sshd_config/) * [`sys_info`](https://www.inspec.io/docs/reference/resources/sys_info/) ## How do I migrate my Serverspec tests to InSpec For most cases, the migration to InSpec is pretty straight forward. First, replace the current verifier in `kitchen.yml` configuration with: ``` verifier: name: inspec ``` Second, rename the directory `test/integration/default/serverspec` to `test/integration/default/inspec` Third, remove the Serverspec-specific code from the test files. ``` require 'serverspec' # Required by serverspec set :backend, :exec ``` InSpec is now configured with Test-Kitchen: ``` kitchen verify package-install-centos-72 -----> Starting Kitchen (v1.14.2) -----> Verifying ... Detected alternative framework tests for `inspec` Loaded Target: ssh://vagrant@127.0.0.1:2200 PHP has ✔ php ✔ the pear.php.net channel ✔ the pecl.php.net channel Test Summary: 3 successful, 0 failures, 0 skipped Finished verifying (0m0.40s). -----> Kitchen is finished. (0m3.31s) ``` Some real-world migrations are available: * [docker](https://github.com/chef-cookbooks/docker) * [nginx](https://github.com/chef-cookbooks/chef_nginx/pull/5/files) * [mysql](https://github.com/chef-cookbooks/mysql/pull/430/files) * [php](https://github.com/chef-cookbooks/php/pull/189/files) Some general recommendations: * use test-kitchen 1.14+ * in case of errors, increase the log level `kitchen verify package-install-centos-72 -l debug` ## Do I still need the backend configuration? InSpec does not attach backend information to test files. All tests are defined independently of any backend. Therefore a Serverspec test file: ``` require 'serverspec' # Required by serverspec set :backend, :exec describe 'PHP' do it 'has php' do expect(command('php -v').exit_status).to eq(0) end it 'has the pear.php.net channel' do expect(command('pear list-channels').stdout).to include('pear.php.net') end it 'has the pecl.php.net channel' do expect(command('pear list-channels').stdout).to include('pecl.php.net') end end ``` will become the following InSpec test file: ``` describe 'PHP' do it 'has php' do expect(command('php -v').exit_status).to eq(0) end it 'has the pear.php.net channel' do expect(command('pear list-channels').stdout).to include('pear.php.net') end it 'has the pecl.php.net channel' do expect(command('pear list-channels').stdout).to include('pecl.php.net') end end ``` As you can see, the InSpec test files just focuses on tests and tries to avoid all clutter. ## Nested describe blocks Serverspec and RSpec allow you to define nested describe blocks. We did a survey and found out that most users use nested describe blocks only to improve their output report. We believe the code structure should not change to improve the output of a report. Nevertheless we understand that nested describe blocks help you to structure test code. A sample code block looks like: ``` describe 'chef-server-directories' do describe file('/etc/opscode') do it { should be_directory } it { should be_owned_by 'root' } end describe file('/etc/opscode-analytics') do it { should be_directory } it { should be_owned_by 'opscode' } it { should be_grouped_into 'opscode' } end describe file('/var/log/opscode') do it { should be_directory } it { should be_owned_by 'opscode' } it { should be_grouped_into 'opscode' } end describe file('/var/opt/opscode') do it { should be_directory } it { should be_owned_by 'root' } end end ``` In InSpec you would split up groups into files. ``` tests ├── server-directories.rb ├── other-tests.rb └── further-tests.rb ``` Each file can have a top-level description of its content: ``` title "Chef Server Directories" describe file('/etc/opscode') do it { should be_directory } it { should be_owned_by 'root' } end describe file('/etc/opscode-analytics') do it { should be_directory } it { should be_owned_by 'opscode' } it { should be_grouped_into 'opscode' } end describe file('/var/log/opscode') do it { should be_directory } it { should be_owned_by 'opscode' } it { should be_grouped_into 'opscode' } end describe file('/var/opt/opscode') do it { should be_directory } it { should be_owned_by 'root' } end ``` ## Are you supporting the `expect` syntax? Of course. We still prefer the `should` syntax for UX reasons. We did surveys with various types of customers like devops engineers, auditors, managers. All participants who preferred the `expect` syntax have been Ruby experts. All non-Ruby developers found it easier to understand the `should` syntax. ### `should` syntax with InSpec ``` describe command('php -v') do its('exit_status') { should eq 0 } end describe command('pear list-channels') do its('stdout') { should include('pear.php.net')} end describe command('pear list-channels') do its('stdout') { should include('pecl.php.net')} end ``` ### `expect` syntax with InSpec ``` describe 'PHP' do it 'has php' do expect(command('php -v').exit_status).to eq(0) end it 'has the pear.php.net channel' do expect(command('pear list-channels').stdout).to include('pear.php.net') end it 'has the pecl.php.net channel' do expect(command('pear list-channels').stdout).to include('pecl.php.net') end end ```