inspec/docs/migration.md

294 lines
14 KiB
Markdown
Raw Normal View History

---
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:
Improve "Which Serverspec resources are available in InSpec?" doc - Switch serverspec and inspec resource compare to a table and fix the links - Add links for serverspec resources not in inspec Serverspec to InSpec markdown table generated with: ``` mapping = { bond: 'bond', bridge: 'bridge', command: 'command', cron: 'crontab', docker_container: 'docker_container', docker_image: 'docker_image', file: 'file', group: 'group', host: 'host', interface: 'interface', iis_website: 'iis_website', iis_app_pool: 'iis_website', iptables: 'iptables', kernel_module: 'kernel_module', linux_kernel_parameter: 'kernel_parameter', mysql_config: 'mysql_conf', package: 'package', port: 'port', ppa: 'apt', process: 'processes', service: 'service', user: 'user', windows_feature: 'windows_feature', windows_registry_key: 'registry_key', x509_certificate: 'x509_certificate', yumrepo: 'yum', zfs: 'zfs_pool' } serverspec_base = 'http://serverspec.org/resource_types.html#' inspec_base = "https://www.inspec.io/docs/reference/resources/" serverspec_max = serverspec_base.length + mapping.max_by{|k,v| k.length}[0].length * 2 + 4 inspec_max = inspec_base.length + mapping.max_by{|k,v| v.length}[1].length * 2 + 5 serverspec_header_half = ' ' * ((serverspec_max - 'Serverspec'.length) / 2) inspec_header_half = ' ' * ((inspec_max - 'InSpec'.length) / 2) puts "| #{serverspec_header_half}Serverspec#{serverspec_header_half} | #{inspec_header_half}InSpec#{inspec_header_half} |" puts "|:#{'-' * serverspec_max}:|:#{'-' * inspec_max}:|" mapping.each do |serverspec, inspec| serverspec_text = "[#{serverspec}](#{serverspec_base}#{serverspec})" padding = serverspec_max - serverspec_text.length serverspec_string = serverspec_text + ' ' * padding inspec_text = "[#{inspec}](#{inspec_base}#{inspec}/)" padding = inspec_max - inspec_text.length inspec_string = inspec_text + ' ' * padding puts "| #{serverspec_string} | #{inspec_string} |" end ``` Signed-off-by: Grant Ridder <shortdudey123@gmail.com>
2017-04-28 22:00:14 +00:00
| 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 <package-install-centos-72>...
Detected alternative framework tests for `inspec`
Improve "Which Serverspec resources are available in InSpec?" doc - Switch serverspec and inspec resource compare to a table and fix the links - Add links for serverspec resources not in inspec Serverspec to InSpec markdown table generated with: ``` mapping = { bond: 'bond', bridge: 'bridge', command: 'command', cron: 'crontab', docker_container: 'docker_container', docker_image: 'docker_image', file: 'file', group: 'group', host: 'host', interface: 'interface', iis_website: 'iis_website', iis_app_pool: 'iis_website', iptables: 'iptables', kernel_module: 'kernel_module', linux_kernel_parameter: 'kernel_parameter', mysql_config: 'mysql_conf', package: 'package', port: 'port', ppa: 'apt', process: 'processes', service: 'service', user: 'user', windows_feature: 'windows_feature', windows_registry_key: 'registry_key', x509_certificate: 'x509_certificate', yumrepo: 'yum', zfs: 'zfs_pool' } serverspec_base = 'http://serverspec.org/resource_types.html#' inspec_base = "https://www.inspec.io/docs/reference/resources/" serverspec_max = serverspec_base.length + mapping.max_by{|k,v| k.length}[0].length * 2 + 4 inspec_max = inspec_base.length + mapping.max_by{|k,v| v.length}[1].length * 2 + 5 serverspec_header_half = ' ' * ((serverspec_max - 'Serverspec'.length) / 2) inspec_header_half = ' ' * ((inspec_max - 'InSpec'.length) / 2) puts "| #{serverspec_header_half}Serverspec#{serverspec_header_half} | #{inspec_header_half}InSpec#{inspec_header_half} |" puts "|:#{'-' * serverspec_max}:|:#{'-' * inspec_max}:|" mapping.each do |serverspec, inspec| serverspec_text = "[#{serverspec}](#{serverspec_base}#{serverspec})" padding = serverspec_max - serverspec_text.length serverspec_string = serverspec_text + ' ' * padding inspec_text = "[#{inspec}](#{inspec_base}#{inspec}/)" padding = inspec_max - inspec_text.length inspec_string = inspec_text + ' ' * padding puts "| #{serverspec_string} | #{inspec_string} |" end ``` Signed-off-by: Grant Ridder <shortdudey123@gmail.com>
2017-04-28 22:00:14 +00:00
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 <package-install-centos-72> (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
```