Using Test Driven Development to write Chef cookbooks and recipes and adopting the "Infrastructure as Code" way. Including an introduction of what infrastructure is about, what is using testing, etc...
Burgess to get his work done by automating the management of a small group of workstations in the Department of Theoretical Physics. Scripting took too much time, the flavours of Unix were significantly different, and scripts had to be maintained for multiple platforms, drowning in exception logic.”
install and maintain computers the way the automotive industry built cars in the early 1900s. An individual craftsman manually manipulates a machine into being, and manually maintains it afterwards. The automotive industry discovered first mass production, then mass customisation using standard tooling. The systems administration industry has a long way to go, but is getting there.” — 1997, infrastructures.org
themselves unable to log back in. … The root cause of this outage was human error.” blogs.msdn.com/b/xblops/archive/2011/10/03/issues-with-xbox-live-earlier-today.aspx
can bind a single interface, if the bind option is not # specified all the interfaces will listen for incoming connections. bind <%= @bind %> ... template "/etc/redis/redis.conf" do ... variables({ bind: node[:redis][:bind] }) end redis cookbook
version 11.4.0 Compiling Cookbooks... Converging 3 resources Recipe: redis::default * package[redis-server] action upgrade (up to date) * service[redis-server] action nothing (up to date) * template[/etc/redis/redis.conf] action create - update template[/etc/redis/redis.conf] from 81b4f1 to 8a6cec --- /etc/redis/redis.conf 2011-07-27 17:26:50.000000000 +0000 +++ /tmp/chef-rendered-template20130406-2537-f8vlv6 2013-04-06 ... @@ -27,7 +27,7 @@ # If you want you can bind a single interface, if the bind option is not # specified all the interfaces will listen for incoming connections. # -bind 127.0.0.1 +bind 0.0.0.0 # Specify the path for the unix socket that will be used to listen for # incoming connections. There is no default, so Redis will not listen * service[redis-server] action restart - restart service service[redis-server] Chef Client finished, 2 resources updated install package run service configuration + restart
'http://sethvargo.com') @webpage = URI.parse(webpage) write Net::HTTP.get(@webpage) end def write(contents) File.open("#{@webpage.host}.html", 'w') do |file| file.write(contents) end end end Scraper.new
be_a URI subject.webpage.host.should == 'sethvargo.com' end it 'writes the file' do File.read('sethvargo.com.html').should match "Unit Testing Chef Cookbooks" end end
It's not idempotent This is NOT a Unit Test! sethvargo.com/unit-testing-correctly/ describe Scraper do it 'parses the uri' do subject.webpage.should be_a URI subject.webpage.host.should == 'sethvargo.com' end it 'writes the file' do File.read('sethvargo.com.html').should match "Unit Testing Chef Cookbooks" end end
◦ control data ◦ fit for use In computer programming, unit testing is a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures are tested to determine if they are fit for use. wikipedia.org/wiki/Unit_testing
'includes the nginx cookbook' do expect(chef_run).to include_recipe(nginx::default') end it 'installs nginx' do expect(chef_run).to install_package('nginx') end end chefspec
that we are more efficient with our time As a technical team We can connect to a shared server to collaborate on client work Scenario: Users can connect to server via ssh key Given a newly bootstrapped server When the technical users recipe is applied Then a user should be able to ssh to the server Scenario: Default shell is bash Given a newly bootstrapped server When the technical users recipe is applied And a user connects to the server via ssh Then their login shell should be "bash" 2 scenarios (2 undefined) 12 steps (7 undefined) 0m0.013s Given /^a newly bootstrapped server$/ do ... When /^the technical users recipe is applied$/ do ... Then /^a user should be able to ssh to the server$/ do When /^a user connects to the server via ssh$/ do ... Then /^their login shell should be "([^"]*)"$/ do |arg1| Given /^with a user's default shell changed to "([^"]*)"$/ do |arg1| ... When /^the user connects to the server via ssh$/ do ... Cucumber Chef
File.exist?('/etc/nginx.conf') end def test_succeed assert run_status.success? end end chef-minitest # Spec Cases describe_recipe 'nginx:configuration' do it 'creates nginx.conf' it 'installs version 1.0.15' do node[:nginx][:version].should == '1.4.4' end end