KitchenCI + Ansible for Windows and Linux
My colleague wrote a great blog about locally testing Ansible roles using KitchenCI . A very fast and simple tool consisting of ruby gems available on every OS, which also works with different testing tools (for example, Serverspec and Pester). A colleague developed this solution for the needs of his projects (provision and deploy exclusively for Windows), which at first glance became a problem, because:
Who cares what happened next, please, under the cat.
After a short discussion, we agreed that I would adapt his tool to both environments, and the end user of the tool (whether an engineer or a developer) will be able to use all its components or only part. But first, a brief description of what works now.
And now we have the standard Ansible role, in a separate directory there is the kitchen, in which the Pester tests are located to test WinServer's configuration and configure, in fact, the kitchen itself. in the .kitchen file there are 2 configurations for Vagrant boxes (Ansible + Winserver), deployment scripts and test paths. Who cares, the source is here .
For 4 teams in the kitchen directory, our testing will pass from start to finish.
The first time will be incredibly long (the Windows box is very heavy), so be patient.
An important point that I forgot to mention: this configuration is a skeleton of a role that a developer can learn in order to understand how he can develop and test his role. I can’t imagine a case when a developer develops one role that should work on both ecosystems.
Nevertheless, corporate GitHub is not rubber, so you need to save a little.
To begin with, we’ll configure the playbook’s role to be universal for both operating systems. Ansible trivial facts will help us here.
As you can see, in the first case we install the IIS role in Windows, in the second - install and run Nginx.
Now for the tests. We create a new directory in kitchen / tests / integration / default (default is the name of our test suit'a) called serverspec. In it, we will have only one defailt_spec.rb file.
I am not very strong in ruby, so I did it dirty without spec-helper.
Here we have only three checks: the package is installed, the service is launched both on the auto start and on port 80, someone is listening.
A little advice to those who, like me, do not know how in Ruby - according to the documentation serverspec-init will generate a default test for you, as in the example above.
So, the role is, the tests are. Now you need to configure the kitchen itself. A colleague is forced to lift two machines, since deploying a small ansible server is much easier than installing it on Windows. In my case, the kitchen itself will install the ansible role, so one machine is enough for me. My kitchen script will be smaller.
I have a separate ansible_playbook, because in it the role is performed only for the linux machine in the inventory file.
In general, the development is over. And explaining to the kitchen what configuration to use is pretty easy. Before executing the kitchen command, you need to pass it the environment variable KITCHEN_YAML = "our_ configuration_name".
For instance:
Thank you for attention.
- I love Ansible too
- I need Ansible to manage Linux
- I don’t want to create another repository on GitHub for separate testing of Linux roles, because I don’t want to produce entities (Occam's razor is everything)
Who cares what happened next, please, under the cat.
After a short discussion, we agreed that I would adapt his tool to both environments, and the end user of the tool (whether an engineer or a developer) will be able to use all its components or only part. But first, a brief description of what works now.
And now we have the standard Ansible role, in a separate directory there is the kitchen, in which the Pester tests are located to test WinServer's configuration and configure, in fact, the kitchen itself. in the .kitchen file there are 2 configurations for Vagrant boxes (Ansible + Winserver), deployment scripts and test paths. Who cares, the source is here .
For 4 teams in the kitchen directory, our testing will pass from start to finish.
- kitchen create - create our local virtual infrastructure
- kitchen converge - apply ansible roles
- kitchen verifiy - apply test suite from verifier
- kitchen destroy - will clean up after itself.
The first time will be incredibly long (the Windows box is very heavy), so be patient.
An important point that I forgot to mention: this configuration is a skeleton of a role that a developer can learn in order to understand how he can develop and test his role. I can’t imagine a case when a developer develops one role that should work on both ecosystems.
Nevertheless, corporate GitHub is not rubber, so you need to save a little.
To begin with, we’ll configure the playbook’s role to be universal for both operating systems. Ansible trivial facts will help us here.
---
# This play installs IIS, if you run it on windows box
- name: install web-server feature
win_feature:
name: Web-Server
state: present
when: ansible_os_family == "Windows"
- name: deploy iis start page template
template:
src: iisstart.j2
dest: C:\inetpub\wwwroot\iisstart.htm
when: ansible_os_family == "Windows"
# This play installs Nginx, if you run it on linux box
- name: install nginx
yum: name=nginx state=latest
when: ansible_os_family == "RedHat"
- name: start nginx
service: name=nginx state=started enabled=True
when: ansible_os_family == "RedHat"
As you can see, in the first case we install the IIS role in Windows, in the second - install and run Nginx.
Now for the tests. We create a new directory in kitchen / tests / integration / default (default is the name of our test suit'a) called serverspec. In it, we will have only one defailt_spec.rb file.
I am not very strong in ruby, so I did it dirty without spec-helper.
require 'rubygems'
require 'bundler/setup'
require 'serverspec'
require 'pathname'
require 'net/ssh'
RSpec.configure do |config|
set :host, ENV['KITCHEN_HOSTNAME']
# ssh options at http://net-ssh.github.io/net-ssh/Net/SSH.html#method-c-start
# ssh via ssh key (only)
set :ssh_options,
:user => ENV['KITCHEN_USERNAME'],
:port => ENV['KITCHEN_PORT'],
:auth_methods => [ 'publickey' ],
:keys => [ ENV['KITCHEN_SSH_KEY'] ],
:keys_only => true,
:paranoid => false,
:verbose => :error
set :backend, :ssh
set :request_pty, true
end
describe package('nginx'), :if => os[:family] == 'redhat' do
it { should be_installed }
end
describe service('nginx'), :if => os[:family] == 'redhat' do
it { should be_enabled }
it { should be_running }
end
describe port(80) do
it { should be_listening }
end
Here we have only three checks: the package is installed, the service is launched both on the auto start and on port 80, someone is listening.
A little advice to those who, like me, do not know how in Ruby - according to the documentation serverspec-init will generate a default test for you, as in the example above.
So, the role is, the tests are. Now you need to configure the kitchen itself. A colleague is forced to lift two machines, since deploying a small ansible server is much easier than installing it on Windows. In my case, the kitchen itself will install the ansible role, so one machine is enough for me. My kitchen script will be smaller.
---
driver:
name: vagrant
gui: true
linked_clone: true
platforms:
- name: centos_box
driver_plugin: vagrant
driver_config:
box: centos/7
network:
- [ 'private_network', { ip: '172.28.128.13' } ]
transport:
max_ssh_sessions: 1
provisioner:
name: ansible_playbook
roles_path: ../
role_name: kitchen_test_role
ansible_inventory: inventory/hosts
require_windows_support: true
require_chef_for_busser: false
ansible_host_key_checking: false
ansible_verbose: true
ansible_verbosity: 4
playbook: default_linux.yml
verifier:
name: serverspec
remote_exec: false
suites:
- name: default
verifier:
patterns:
- tests/integration/default/serverspec/default_spec.rb
I have a separate ansible_playbook, because in it the role is performed only for the linux machine in the inventory file.
In general, the development is over. And explaining to the kitchen what configuration to use is pretty easy. Before executing the kitchen command, you need to pass it the environment variable KITCHEN_YAML = "our_ configuration_name".
For instance:
KITCHEN_YAML=".kitchen_linux.yml" kitchen create/converge/verify/destroy.
Thank you for attention.