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:

  • 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.

Also popular now: