MONITOR-DRIVEN
INFRASTRUCTURE
DEVELOPMENT USING
ANSIBLE
Itamar Hassin
THE PREMISE
• Ansible scripts should be treated with the
same rigour with which we treat application
code
• In the way they’re tested
• In the way they’re written
JAMES WHITE MANIFESTO
•There is one system, not a collection of systems.
• The desired state of the system should be a known
quantity.
• The "known quantity" must be machine parseable.
• The actual state of the system must self-correct to the
desired state.
• The entire system must be deployable using source
media and text files.
• The only authoritative source for the actual state of the
system is the system.
UNTESTED CODE
WHY ANSIBLE?
•Assures scalability
•Repeatable and measurable
•Assures environments for consistent
development testing
Do not improve manual processes
if you can automate them instead.
•Fail fast (offline!) and cycle quickly
•Time To Rebuild System < Time To Fix It
THE REVOLUTION
Specify infrastructure configuration using
Ansible
You are writing
code!
INFRASTRUCTURE AS
CODE
•Employ TDD
•Version in SCM
•Part of the deliverable
•Submit to CI
•Have a story on the board
•Deploy to prod
XDD
• An activity whereby a feature is described
from its user’s perspective prior to its
implementation
SOFTWARE DELIVERY
User Story &
Acceptance
criteria
Code with unit
tests
Automated
tests
Specification Implementation Verification
UNIFIED DELIVERY
From this To this
BDD
Configuration
Instructions
Acceptance tests
(code)
•Instructions can be the acceptance tests
•Environments emerge in a running state
•Coded tests are living
documentation
MDD
• ServerSpec will serve as the testing
framework for the Anisible code
• Not in production if it’s not monitored
SERVERSPEC
describe service('sshd') do
it { should be_running }
end
describe service('ntpd') do
it { should be_running }
end
WHAT WE’RE GOING TO
DO
Controller
Watcher
TargetMonitor
Configure
{
WRITE A TEST
GET A TARGET
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.define "webserver"
config.vm.hostname = "webserver"
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "private_network", ip: "33.33.33.33"
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
ansible.inventory_path = "inventory.ini"
ansible.sudo = true
end
end
GET A TARGET
RUN THE TEST
GET APACHE PLAYBOOK
CONFIGURE TARGET
RUN THE TEST
CUCUMBER
Feature: App deploys to a VM
Background:
Given I have a vm with ip "33.33.33.33"
When I provision users on it
Scenario: Adding users
Then I can log on to it as the "deploy" user
And I can log on to it as the "root" user
Scenario: Adding Linux dependencies
When I run the "webserver" ansible playbook
And I log on as "deploy", there is no "ruby"
But "gcc" is present
CUCUMBER
IMPLEMENTATION
Then(/^I can log on to it as the "(.*?)" user$/) do |user|
result = system "ssh #{user}@#{@ip} exit"
result.should be_true
end
When(/^I run the "(.*?)" ansible playbook$/) do |playbook|
command = %W(../devops/#{playbook}.yml -i webhosts)
result = system 'ansible-playbook', *command
result.should be_true
end
WHY BOTHER?
• ServerSpec is to Ansible as rSpec is to Ruby
• You do not want your Ansible code to be
used untested
SOURCE CONTROL
SCaaCC
• Ansible code is part of the delivered code
• Developers and SysAdmins share code
using git for modifications.
• HugOps can use master
• Others can use branching or forking
SOURCE CONTROL
• Run ServerSpec prior to committing code
• Commit
• CI will take care of the rest
• Integration tests
• Environment Promotion
CI
Commit CI
ServerSpe
c
Cucumber VMTest
VMStaging
VMProd
XP PRACTICES
• SysAdmins are part of the development
team
• Participate in standups, part of a
story/task cards
• Participate in pairing sessions
• Empathise
devopsdays.org
REFERENCES
The Visible Ops Handbook
blog.websages.com/2010/12/10/jameswhite-manifesto/
rspec.info serverspec.comcukes.info
ansible.com galaxy.ansible.com
QUESTIONS & THANK YOU!
@itababy
www.in-context.com

Monitor-Driven Development Using Ansible