4. Devops Is A Two-Way Street
⢠Itâs great when
developers care
about
⢠uptime!
⢠scaling!
⢠deployment!
⢠Put them on call!
etc. etc. etc.
Friday, June 14, 13
5. Devops Is A Two-Way Street
⢠Systems Administrators
also have as much or more to
learn from developers as well!
Friday, June 14, 13
9. Source
Code
Compiler
Artifact
Test
Typical Development Workflow
⢠Artifact
⢠Artifacts are executable programs
created by compilers.
⢠Compiled artifacts cannot be edited
directly. Source code must be changed
and re-compiled to produce a new build
artifact.
Friday, June 14, 13
11. Source
Code
Compiler
Artifact
Test
Typical Development Workflow
⢠When developing software, most time
isnât actually spent coding
⢠10-second changes to source code can
take minutes to vet
⢠Compiling code
⢠Deploying code
⢠Writing & Running tests
Friday, June 14, 13
17. Source'Code'
Compiler'
Ar/fact'
Test'
Boooooooring
⢠Too much time doing
âpaperworkâ
⢠vi recipes/something.rb
⢠knife cookbook upload
⢠sudo pkill -USR1 chef-
client
⢠#%$#%$ something
broke, let me do that all
again
⢠Not enough time doing fun
stuff!
⢠Writing recipes
Less Fun!
More Boring!
X
Friday, June 14, 13
18. Source'Code'
Compiler'
Ar/fact'
Test'
Boooooooring
⢠Too much time doing
âpaperworkâ
⢠vi recipes/something.rb
⢠knife cookbook upload
⢠sudo pkill -USR1 chef-
client
⢠#%$#%$ something
broke, let me do that all
again
⢠Not enough time doing fun
stuff!
⢠Writing recipes
Less Fun!
More Boring!
XTH
IS
SUCKS!
Friday, June 14, 13
19. Chefs on a Plane
What if...
Friday, June 14, 13
20. Chefs on a Plane
What if...Worksta(on:+
Knife+cookbook+
create+
Worksta(on:+
Edit+cookbook+
Worksta(on:+
Knife+cookbook+
upload+
Provision+target+
Bootstrap+
target+
Worksta(on:+
Edit+target+run+
list+
ssh+target+
Target:+Run+
chef>client+
Target:(Run(
chef/client(
Worksta6on:(
edit(cookbook(
Worksta6on:(
knife(cookbook(
upload(
...we could
automate all
of this...
Friday, June 14, 13
21. Chefs on a Plane
What if...Worksta(on:+
Knife+cookbook+
create+
Worksta(on:+
Edit+cookbook+
Worksta(on:+
Knife+cookbook+
upload+
Provision+target+
Bootstrap+
target+
Worksta(on:+
Edit+target+run+
list+
ssh+target+
Target:+Run+
chef>client+
Target:(Run(
chef/client(
Worksta6on:(
edit(cookbook(
Worksta6on:(
knife(cookbook(
upload(
...we could
automate all
of this...
...to run entirely on this...
Friday, June 14, 13
22. Chefs on a Plane
What if...
...even while
aboard this?
Worksta(on:+
Knife+cookbook+
create+
Worksta(on:+
Edit+cookbook+
Worksta(on:+
Knife+cookbook+
upload+
Provision+target+
Bootstrap+
target+
Worksta(on:+
Edit+target+run+
list+
ssh+target+
Target:+Run+
chef>client+
Target:(Run(
chef/client(
Worksta6on:(
edit(cookbook(
Worksta6on:(
knife(cookbook(
upload(
...we could
automate all
of this...
...to run entirely on this...
Friday, June 14, 13
23. Source'Code'
Compiler'
Ar/fact'
Test'
Developing for Chef: Rapid Iteration
⢠Less time waiting around
for cookbook deploys and
Chef runs
⢠More frequent testing
⢠Better code
⢠Business needs met
more quickly
More Fun!
Less Boring!
X
Friday, June 14, 13
26. The Toolchain
⢠Youâre becoming a developer!
⢠Reasonably powerful computer
⢠Good editor
Friday, June 14, 13
27. Have a Good Computer
⢠Virtualization is used to run
acceptance tests
⢠Running on a real virtualized
ânodeâ
⢠Lots of memory (4GB+, 8GB
recommended)
⢠Fast disk (SSD)
⢠Good processor (Intel i5+)
⢠Modern OS
X
Friday, June 14, 13
28. Tools
⢠Chef (obviously)
⢠Virtualization provider
⢠Virtualization automation
(Vagrant)
⢠Cookbook dependency
manager (Berkshelf,
Librarian)
⢠Unit and acceptance testing
frameworks
Friday, June 14, 13
30. Different Types of Testing
⢠There are formal
Software Engineering
definitions for testing
Friday, June 14, 13
31. Different Types of Testing
⢠There are formal
Software Engineering
definitions for testing
⢠Unit test
Friday, June 14, 13
32. Different Types of Testing
⢠There are formal
Software Engineering
definitions for testing
⢠Unit test
⢠Integration test
Friday, June 14, 13
33. Different Types of Testing
⢠There are formal
Software Engineering
definitions for testing
⢠Unit test
⢠Integration test
⢠Acceptance test
Friday, June 14, 13
34. Different Types of Testing
⢠There are formal
Software Engineering
definitions for testing
⢠Unit test
⢠Integration test
⢠Acceptance test
⢠An easy explanation for
SAs is ...
Friday, June 14, 13
35. ⢠Unit Test: Signal Input
What and When To Test
Flickr user: Rain Rabbit
Friday, June 14, 13
36. ⢠Unit Test: Signal Input
⢠Did I send Chef the correct
command?
What and When To Test
Flickr user: Rain Rabbit
Friday, June 14, 13
37. ⢠Unit Test: Signal Input
⢠Did I send Chef the correct
command?
⢠Signal Processing
What and When To Test
Flickr user: Rain Rabbit
Friday, June 14, 13
38. ⢠Unit Test: Signal Input
⢠Did I send Chef the correct
command?
⢠Signal Processing
⢠Did Chef interpret my command
correctly?
What and When To Test
Flickr user: Rain Rabbit
Friday, June 14, 13
39. ⢠Unit Test: Signal Input
⢠Did I send Chef the correct
command?
⢠Signal Processing
⢠Did Chef interpret my command
correctly?
⢠Acceptance Test: Signal Output
What and When To Test
Flickr user: Rain Rabbit
Friday, June 14, 13
40. ⢠Unit Test: Signal Input
⢠Did I send Chef the correct
command?
⢠Signal Processing
⢠Did Chef interpret my command
correctly?
⢠Acceptance Test: Signal Output
⢠Did my expressed intent, executed
by Chef, achieve the desired
result?
What and When To Test
Flickr user: Rain Rabbit
Friday, June 14, 13
43. Chef Testing Tools
⢠Signal Input
⢠ChefSpec
⢠Signal out
⢠Chef Minitests & Minitest Handler
Friday, June 14, 13
44. Chef Testing Tools
⢠Signal Input
⢠ChefSpec
⢠Signal out
⢠Chef Minitests & Minitest Handler
⢠Signal processing
⢠Who cares; thatâs what Opscodeâs own tests for
Chef are for!
Friday, June 14, 13
46. General Philosophy for Chef Testing
⢠Unit tests
⢠ChefSpec assertion for every resource of interest
⢠Each recipe should get its own test file
Friday, June 14, 13
47. General Philosophy for Chef Testing
⢠Unit tests
⢠ChefSpec assertion for every resource of interest
⢠Each recipe should get its own test file
⢠Acceptance tests
⢠Anything that you couldnât test in a unit test
Friday, June 14, 13
48. General Philosophy for Chef Testing
⢠Unit tests
⢠ChefSpec assertion for every resource of interest
⢠Each recipe should get its own test file
⢠Acceptance tests
⢠Anything that you couldnât test in a unit test
⢠Donât repeat yourself!
Friday, June 14, 13
50. ChefSpec Overview
⢠Built on top of RSpec
⢠Converge a Chef run in memory
⢠Overrides all providers to take no action
⢠Make assertions about the in-memory Chef run
⢠Mock Ohai data (automatic attributes) with Fauxhai
Friday, June 14, 13
51. Example Recipe Part One
include_recipe âjavaâ
user node['sauceproxy']['server']['user'] do
  comment "SauceLabs Proxy User"
  system true
  action :create
end
directory node['sauceproxy']['server']['install_dir'] do
  owner node['sauceproxy']['server']['user']
  mode 00755
  action :create
end
# Can't assume we have unzip
package "unzip" do
  action :install
end
execute "unzip-saucelabs-proxy" do
  cwd node['sauceproxy']['server']['install_dir']
  command "unzip -o #{Chef::Config[:file_cache_path]}/#{node['sauceproxy']['server']['zipfile']}"
  action :nothing
  notifies :restart, "service[sauceproxy]"
end
https://github.com/juliandunn/sauceproxy/blob/master/recipes/server.rb
Friday, June 14, 13
52. Example Recipe Part Two
remote_file "#{Chef::Config[:file_cache_path]}/#{node['sauceproxy']['server']['zipfile']}" do
source "#{node['sauceproxy']['server']['download_url']}/#{node['sauceproxy']['server']['zipfile']}"
  action :create_if_missing
  notifies :run, "execute[unzip-saucelabs-proxy]", :immediately
end
template "/etc/init.d/sauceproxy" do
  source "sauceproxy.init.erb"
  mode 00755
  owner "root"
  group "root"
  action :create
end
template "/etc/sysconfig/sauceproxy" do
  source "sauceproxy.sysconfig.erb"
  mode 00644
  owner "root"
  group "root"
  action :create
end
service "sauceproxy" do
  supports :restart => true
  action [:enable, :start]
end
Friday, June 14, 13
53. Example ChefSpec Test: Setup
describe 'sauceproxy::server' do
let (:chef_run) do
runner = ChefSpec::ChefRunner.new(
platform: 'centos',
version: '6.3'
)
runner.node.set['sauceproxy']['server']['user'] = 'fake'
runner.node.set['sauceproxy']['server']['install_dir'] =
'/tmp/fake'
runner.node.set['sauceproxy']['server']['version'] = '3.14159'
runner.converge('sauceproxy::server')
end
Friday, June 14, 13
54. Example ChefSpec Test: Expectations
it 'should create a sauceproxy directory with the right
ownership' do
expect(chef_run).to create_directory('/tmp/fake')
expect(chef_run.directory('/tmp/fake')).to
be_owned_by('fake')
end
it 'should start a service called sauceproxy' do
expect(chef_run).to start_service('sauceproxy')
expect(chef_run).to
set_service_to_start_on_boot('sauceproxy')
end
end
Friday, June 14, 13
56. ChefSpec: Expectations
⢠Many expectations (assertions) possible
⢠https://github.com/acrmp/chefspec#making-
assertions
⢠Donât (just) restate static resources
⢠Mock out data
⢠Static resource assertions: good for regressions
⢠Whoops, I deleted the service resource
Friday, June 14, 13
60. Acceptance Tests as Report Handler
⢠Acceptance testing as a Chef Report Handler
⢠Many tools (serverspec, bats, minitest)
⢠Iâll demo Chef-MiniTest-Handler; most widely used
Friday, June 14, 13
61. MiniTest Handler Cookbook
⢠http://community.opscode.com/cookbooks/minitest-
handler
⢠Installs Minitest Gems
⢠Installs Chef Minitest Gems
⢠Installs the Chef-Minitest-Handler Notification
Handler for Chef-Client
⢠Places test files from cookbooks on the target node
as part of a Chef-client run
Friday, June 14, 13
62. MiniTest Files
⢠Each recipe gets an individual test file.
⢠recipes/server.rb
⢠files/default/test/server_test.rb
⢠Tests for each recipe are automatically loaded by the
handler
Friday, June 14, 13
63. Example MiniTest
require 'minitest/spec'
describe_recipe 'sauceproxy::server' do
it 'runs as a daemon' do
service('sauceproxy').must_be_running
end
end
http://tinyurl.com/minitest-examples
for many more example tests
Friday, June 14, 13
64. Make this go on a
with virtualization!
Friday, June 14, 13
65. Using Vagrant & Berkshelf to Iterate
⢠Vagrant is virtualization middleware
⢠Driven from Vagrantfile
⢠Defines VM images, customization parameters,
provisioners (Chef in our case)
⢠Berkshelf is a cookbook dependency manager
⢠Get dependent cookbooks from community API
⢠Feed them to Vagrant Chef provisioner
Friday, June 14, 13
66. Example Vagrantfile
Vagrant.configure("2") do |config|
config.vm.hostname = "sauceproxy-berkshelf"
config.vm.box = "opscode-centos-6.4"
config.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/
opscode_centos-6.4_chef-11.4.4.box"
config.ssh.max_tries = 40
config.ssh.timeout = 120
config.vm.provision :chef_solo do |chef|
chef.json = {}
chef.run_list = [
"recipe[minitest-handler]",
"recipe[sauceproxy::server]"
]
end
end
Friday, June 14, 13
67. % vagrant up
Bringing Up Vagrant
borkbork:~/Dropbox/devel/github/juliandunn/sauceproxy (master)$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'centos-6.4'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[Berkshelf] Updating Vagrant's berkshelf: '/Users/juliandunn/.berkshelf/vagrant/
berkshelf-20130611-20810-rt7k01'
[Berkshelf] Using sauceproxy (0.1.8) at path: '/Users/juliandunn/Dropbox/devel/github/juliandunn/
sauceproxy'
[Berkshelf] Using minitest-handler (0.2.1)
[Berkshelf] Using java (1.11.4)
[Berkshelf] Using windows (1.8.10)
[Berkshelf] Using chef_handler (1.1.4)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
Friday, June 14, 13
68. % vagrant up
Bringing Up Vagrant
borkbork:~/Dropbox/devel/github/juliandunn/sauceproxy (master)$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'centos-6.4'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[Berkshelf] Updating Vagrant's berkshelf: '/Users/juliandunn/.berkshelf/vagrant/
berkshelf-20130611-20810-rt7k01'
[Berkshelf] Using sauceproxy (0.1.8) at path: '/Users/juliandunn/Dropbox/devel/github/juliandunn/
sauceproxy'
[Berkshelf] Using minitest-handler (0.2.1)
[Berkshelf] Using java (1.11.4)
[Berkshelf] Using windows (1.8.10)
[Berkshelf] Using chef_handler (1.1.4)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
Friday, June 14, 13
69. Vagrant Run Continued
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
GuestAdditions 4.2.12 running --- OK.
[default] Setting hostname...
[default] Configuring and enabling network interfaces...
[default] Mounting shared folders...
[default] -- /vagrant
[default] -- /tmp/vagrant-chef-1/chef-solo-1/cookbooks
[default] Running provisioner: chef_solo...
Generating chef JSON and uploading...
Running chef-solo...
[2013-06-12T02:52:26+00:00] INFO: *** Chef 11.4.4 ***
[2013-06-12T02:52:26+00:00] INFO: Setting the run_list to ["recipe[minitest-
handler]", "recipe[sauceproxy::server]"] from JSON
[2013-06-12T02:52:26+00:00] INFO: Run List is [recipe[minitest-handler],
recipe[sauceproxy::server]]
[2013-06-12T02:52:26+00:00] INFO: Run List expands to [minitest-handler,
sauceproxy::server]
[2013-06-12T02:52:26+00:00] INFO: Starting Chef Run for sauceproxy-berkshelf
Friday, June 14, 13
70. Vagrant Run Continued
[2013-06-12T02:55:22+00:00] INFO: Chef Run complete in 175.788656866 seconds
[2013-06-12T02:55:22+00:00] INFO: Running report handlers
Run options: -v --seed 31883
# Running tests:
recipe::java::openjdk#test_0001_installs the correct version of the jdk =
0.11 s = .
recipe::java::openjdk#test_0002_properly sets JAVA_HOME environment variable =
0.04 s = .
recipe::sauceproxy::server#test_0001_runs as a daemon =
0.09 s = .
Finished tests in 0.244690s, 12.2604 tests/s, 12.2604 assertions/s.
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
[2013-06-12T02:55:22+00:00] INFO: Report handlers complete
Friday, June 14, 13
71. Vagrant Run Continued
[2013-06-12T02:55:22+00:00] INFO: Chef Run complete in 175.788656866 seconds
[2013-06-12T02:55:22+00:00] INFO: Running report handlers
Run options: -v --seed 31883
# Running tests:
recipe::java::openjdk#test_0001_installs the correct version of the jdk =
0.11 s = .
recipe::java::openjdk#test_0002_properly sets JAVA_HOME environment variable =
0.04 s = .
recipe::sauceproxy::server#test_0001_runs as a daemon =
0.09 s = .
Finished tests in 0.244690s, 12.2604 tests/s, 12.2604 assertions/s.
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
[2013-06-12T02:55:22+00:00] INFO: Report handlers complete
Friday, June 14, 13
72. Minitests from Java cookbook ran too!
[2013-06-12T02:55:22+00:00] INFO: Chef Run complete in 175.788656866 seconds
[2013-06-12T02:55:22+00:00] INFO: Running report handlers
Run options: -v --seed 31883
# Running tests:
recipe::java::openjdk#test_0001_installs the correct version of the jdk =
0.11 s = .
recipe::java::openjdk#test_0002_properly sets JAVA_HOME environment variable =
0.04 s = .
recipe::sauceproxy::server#test_0001_runs as a daemon =
0.09 s = .
Finished tests in 0.244690s, 12.2604 tests/s, 12.2604 assertions/s.
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
[2013-06-12T02:55:22+00:00] INFO: Report handlers complete
Friday, June 14, 13
73. Minitests from Java cookbook ran too!
[2013-06-12T02:55:22+00:00] INFO: Chef Run complete in 175.788656866 seconds
[2013-06-12T02:55:22+00:00] INFO: Running report handlers
Run options: -v --seed 31883
# Running tests:
recipe::java::openjdk#test_0001_installs the correct version of the jdk =
0.11 s = .
recipe::java::openjdk#test_0002_properly sets JAVA_HOME environment variable =
0.04 s = .
recipe::sauceproxy::server#test_0001_runs as a daemon =
0.09 s = .
Finished tests in 0.244690s, 12.2604 tests/s, 12.2604 assertions/s.
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
[2013-06-12T02:55:22+00:00] INFO: Report handlers complete
Friday, June 14, 13
74. New Test/Dev Cycle
Write Unit Tests
Worked?
Run ChefSpec
No
Write Recipe
Code
Write Acceptance
Tests
Yes
Worked?
Run Vagrant + Minitest Handler
No
vagrant destroy
Yes Commit/Tag Code,
etc.
Friday, June 14, 13
76. Continuous Integration Pipeline
⢠Run unit tests in your pipeline
⢠Run acceptance tests in your
pipeline
⢠Drive cookbook uploads as the
output!
Friday, June 14, 13
77. Travis-CI Example for SauceProxy
language: ruby
gemfile:
  - gemfiles/travis.gemfile
rvm:
  - "1.9.2"
  - "1.9.3"
script: bundle exec rake test:syntax test:lint test:spec
notifications:
  email:
    - jdunn@opscode.com
Friday, June 14, 13
78. Rakefile Example
⢠Too long to post here
⢠Rake tasks for Foodcritic
and ChefSpec
⢠https://github.com/
juliandunn/sauceproxy/
blob/master/Rakefile
Friday, June 14, 13
81. Test Kitchen (alpha)
⢠Run acceptance test suite on
multiple OSes
⢠Different fixtures for each, if desired
⢠Different drivers (vagrant, ec2, lxc,
etc.)
⢠Hook up to Jenkins or other CI
system if desired
Friday, June 14, 13
86. More on Testing
⢠Chef-NYC: The Hows and Whys
of Cookbook Testing
⢠Seth Vargo (Author of ChefSpec,
Fauxhai, many others)
⢠http://www.meetup.com/Chef-
NYC/events/122219772/
⢠June 25th in Manhattan
Friday, June 14, 13
87. Chef Fundamentals Training
⢠Boston, July 11-12
(CompuWorks, 263
Summer St.)
⢠eventbrite.com/event/
6652057483
⢠Use code BOSTON-
MEETUP to save 25%!
Friday, June 14, 13
88. Questions and Prizes
Also, weâre hiring! Automate all the things for fun and profit!
http://www.opscode.com/blog/careers/
(and/or see me after)
Friday, June 14, 13