Test Driven Infrastructure with Chef

Test Driven Infrastructure with Chef

These are the slides from my 2013 Velocity talk on Chef Driven Infrastructure with Chef using ChefSpec, Test Kitchen, GitHub, Jenkins, and more!

502828deee7e3b38ca1e527dded8a1a9?s=128

Seth Vargo

June 18, 2013
Tweet

Transcript

  1. 5.
  2. 17.
  3. 18.
  4. 22.

    Gemfile source 'https://rubygems.org' group :test do gem 'chefspec', '~> 1.3'

    gem 'foodcritic', '~> 2.1' gem 'strainer', '~> 3.0' gem 'test-kitchen', '~> 1.0.0.alpha' gem 'kitchen-lxc', '~> 0.0.1.beta1' gem 'knife-spork', '~> 1.0.17' gem 'hipchat', '~> 0.10.0' gem 'guard', '~> 1.8' gem 'guard-foodcritic', '~> 1.0' gem 'guard-rspec', '~> 3.0' end
  5. 27.

    spec/default_spec.rb require 'spec_helper' describe 'sethvargo-myface::default' do let(:chef_run) do run =

    ChefSpec::ChefRunner.new(platfrom: 'ubuntu', version: '12.04') run.converge('sethvargo-myface::default') end it 'installs apache2' do expect(chef_run).to install_package('apache2') end # ... end
  6. 32.

    Guardfile guard :rspec, all_on_start: false do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^(recipes)/(.+)\.rb$}) { |m|

    "spec/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { 'spec' } end guard :foodcritic, cookbook_paths: '.', all_on_start: false do watch(%r{attributes/.+\.rb$}) watch(%r{providers/.+\.rb$}) watch(%r{recipes/.+\.rb$}) watch(%r{resources/.+\.rb$}) end
  7. 34.
  8. 35.
  9. 36.
  10. 37.
  11. 38.
  12. 40.

    Strainerfile knife: bundle exec knife cookbook test $COOKBOOK foodcritic: bundle

    exec foodcritic $SANDBOX/$COOKBOOK -f any rspec: (cd $COOKBOOK && bundle exec rspec --color)
  13. 44.
  14. 50.
  15. 51.
  16. 52.
  17. 53.
  18. 54.
  19. 60.

    1

  20. 61.

    1

  21. 63.

    1

  22. 65.

    S

  23. 66.

    I, _________, solemnly swear under penalty of my GPU catching

    fire, that I will not touch anyone's build but my own.  NO ASSHOLE PLEDGE
  24. 69.

    2

  25. 72.
  26. 73.

    2

  27. 75.
  28. 84.
  29. 85.

    2

  30. 90.

    3

  31. 99.

    spec/default_spec.rb describe 'sethvargo-myface::default' do # pre-existing tests # ... it

    'creates the default template' do expect(chef_run).to create_file('/var/www/index.html') end it 'creates the site with the correct content' do template = chef_run.template('/var/www/index.html') expect(template.owner).to eq('root') expect(template.group).to eq('root') end end
  32. 100.
  33. 102.

    recipes/default.rb package 'apache2' service 'apache2' do action [:enable, :start] end

    template '/var/www/index.html' do owner 'root' group 'root' mode '0755' source 'index.html.erb' end
  34. 104.

    templates/default/index.html.erb <html> <head> <title>Welcome to <%= node['fqdn'] %></title> </head> <body>

    <p>Here's everything you need to know about <%= node['fqdn'] %>:</p> <pre><%= JSON.pretty_generate(node.to_hash) %></pre> </body> </html>
  35. 107.

  36. 109.

  37. 111.

  38. 112.

    c

  39. 114.

    J

  40. 117.

    J

  41. 118.

    J

  42. 119.

    J

  43. 122.

    metadata.rb name 'myface' maintainer 'YOUR_COMPANY_NAME' maintainer_email 'YOUR_EMAIL' license 'All rights

    reserved' description 'Installs/Configures myface' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '0.1.0'
  44. 123.

    metadata.rb name 'myface' maintainer 'Seth Vargo' maintainer_email 'sethvargo@opscode.com' license 'All

    rights reserved' description 'Installs/Configures myface' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '0.1.0'
  45. 126.
  46. 128.

    S

  47. 129.
  48. 132.
  49. 137.

    J

  50. 138.

    J

  51. 141.

    J

  52. 144.
  53. 145.

    J

  54. 147.

    J

  55. 150.

    J

  56. 152.
  57. 153.

    R

  58. 161.

    J

  59. 162.

    J

  60. 163.

    J

  61. 166.
  62. 170.

    q

  63. 172.

    q

  64. 177.

    .kitchen.yml driver_plugin: lxc driver_config: use_sudo: true platforms: - name: ubuntu-12.04

    driver_config: base_container: ubuntu_12.04 username: ubuntu password: ubuntu suites: - name: default run_list: ["recipe[myface]"] attributes: {}
  65. 178.

    Strainerfile knife: bundle exec knife cookbook test $COOKBOOK foodcritic: bundle

    exec foodcritic $SANDBOX/$COOKBOOK -f any rspec: (cd $COOKBOOK && bundle exec rspec --color) kitchen: (cd $COOKBOOK && bundle exec kitchen test)
  66. 179.

    metadata.rb name 'myface' maintainer 'Seth Vargo' maintainer_email 'sethvargo@opscode.com' license 'All

    rights reserved' description 'Installs/Configures myface' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '0.1.0'
  67. 180.

    metadata.rb name 'myface' maintainer 'Seth Vargo' maintainer_email 'sethvargo@opscode.com' license 'All

    rights reserved' description 'Installs/Configures myface' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) version '0.1.1'
  68. 183.

    q

  69. 184.
  70. 185.
  71. 194.
  72. 196.
  73. 197.
  74. 198.
  75. 199.
  76. 200.

    environments/production.json { "name" : "production", "description" : "Production cluster in

    EC2", "override_attributes" : { ... }, "default_attributes" : { ... } }
  77. 201.

    environments/production.json { "name" : "production", "description" : "Production cluster in

    EC2", "override_attributes" : { ... }, "default_attributes" : { ... }, "cookbook_versions" : { "myface": "0.1.0" }, }
  78. 202.

    CD

  79. 203.
  80. 204.