Continuous Integration for Infrastructure

Continuous Integration for Infrastructure

Lots of examples of emerging infrastructure testing patterns. Test Kitchen, Puppet, Docker, Serverspec, Packer, Bats and more. Presented at #craftconf in Budapest

98234c645fe8c935edc0fec0186d28b8?s=128

Gareth Rushgrove

April 25, 2014
Tweet

Transcript

  1. 5.
  2. 6.
  3. 28.

    - install-packages: packages: ruby1.9.1-dev - script: name: install bundler code:

    sudo gem install bundler - bundle-install - script: name: print ruby version code: ruby —version wercker.yaml Gareth Rushgrove
  4. 29.

    - install-packages: packages: ruby1.9.1-dev - script: name: install bundler code:

    sudo gem install bundler - bundle-install - script: name: print ruby version code: ruby —version wercker.yaml Gareth Rushgrove 1 2 3 4
  5. 32.

    - install-packages: packages: ruby1.9.1-dev - script: name: install bundler code:

    sudo gem install bundler - bundle-install - script: name: print ruby version code: ruby —version wercker.yaml Gareth Rushgrove
  6. 48.
  7. 49.

    Run code against short lived virtual machines and make assertions

    against the resulting state Gareth Rushgrove
  8. 54.

    --- driver: name: digitalocean ! provisioner: name: shell ! platforms:

    - name: ubuntu-12.04 ! suites: - name: default provisioner: script: scripts/bootstrap.sh .kitchen.yml Gareth Rushgrove
  9. 59.

    platforms: - name: ubuntu-14.04 - name: ubuntu-13.10 - name: centos-6.5

    - name: centos-6.4 - name: ubuntu-12.04 - name: centos-6.4 - name: centos-6.4 - name: archlinux-2013.05 .kitchen.yml Gareth Rushgrove
  10. 62.
  11. 64.

    describe service('ntp') do it { should be_enabled } it {

    should be_running } end serverspec/sample_spec.rb Gareth Rushgrove
  12. 66.

    Package "ntp" should be installed ! Service "ntp" should be

    enabled should be running ! Finished in 0.11191 seconds 3 examples, 0 failures Finished verifying <default-ubuntu-1310> (0m7.39s). -----> Destroying <default-ubuntu-1310>... Digital Ocean instance <1493500> destroyed. Finished destroying <default-ubuntu-1310> (0m4.47s). Finished testing <default-ubuntu-1310> (3m59.40s). -----> Kitchen is finished. (3m59.95s) Gareth Rushgrove
  13. 74.

    Packer is a tool for creating identical machine images for

    multiple platforms from a single source configuration Gareth Rushgrove
  14. 76.

    { "variables": { "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}", "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}" },

    "builders": [{ "type": "amazon-ebs", "access_key": "{{user `aws_access_key`}}", "secret_key": "{{user `aws_secret_key`}}", "region": "eu-west-1", "source_ami": "ami-480bea3f", "instance_type": "t1.micro", "ssh_username": "ubuntu", "ami_name": "packer-serverspec-example-{{timestamp}}" }], "provisioners": [{ "type": "shell", "script": "scripts/puppet.sh" }, { "type": "file", template.json Gareth Rushgrove
  15. 79.

    ! "provisioners": [{ "type": "shell", "script": "scripts/puppet.sh" }, { "type":

    "puppet-masterless", "manifest_file": "manifests/site.pp", "hiera_config_path": "hiera.yaml", "module_paths": ["modules"] } template.json Gareth Rushgrove
  16. 81.

    ! "provisioners": [{ "type": "shell", "script": "scripts/puppet.sh" }, { "type":

    "puppet-masterless", "manifest_file": "manifests/site.pp", "hiera_config_path": "hiera.yaml", "module_paths": ["modules"] } template.json Gareth Rushgrove
  17. 82.

    #!/bin/bash ! # Install language locale as without can #

    interfere with package installation sudo apt-get install language-pack-en -y ! # Install Ruby sudo apt-get update sudo apt-get install ruby1.9.1 -y ! # Install puppet/facter sudo gem install puppet facter --no-ri --no-rdoc scripts/puppet.sh Gareth Rushgrove
  18. 84.

    ! "provisioners": [{ "type": "shell", "script": "scripts/puppet.sh" }, { "type":

    "puppet-masterless", "manifest_file": "manifests/site.pp", "hiera_config_path": "hiera.yaml", "module_paths": ["modules"] } template.json Gareth Rushgrove
  19. 103.

    class ExampleSimulation extends Simulation { val httpConf = http.baseURL("http://www.example.com") !

    val sample = scenario("Simple example").exec( http("Homepage").get("/").check(status.is(200))) ! setUp(sample.inject(ramp(3 users) over (10 seconds))) .protocols(httpConf) } ExampleSimulation.scala Gareth Rushgrove
  20. 117.

    --- droplets: - name: production.web.1 - name: production.web.2 - name:

    production.app.1 size: 64 - name: production.app.2 size: 64 - name: production.db.1 size: 69 vars/droplets.yml Gareth Rushgrove
  21. 121.

    #!/usr/bin/env bats ! @test "addition using bc" { result="$(echo 2+2

    | bc)" [ "$result" -eq 4 ] } ! @test "addition using dc" { result="$(echo 2 2+p | dc)" [ "$result" -eq 4 ] } example.bats Gareth Rushgrove
  22. 123.

    @test "no droplets exist" { run tugboat droplets [ "$status"

    -eq 0 ] [ "${lines[0]}" = "You don't appear to have any droplets." ] } ! @test "provisioner runs successfully" { run ansible-playbook -i hosts provision_digital_ocean.yml [ "$status" -eq 0 ] } acceptance.bats Gareth Rushgrove
  23. 125.

    @test “we can count the correct number of machines" {

    run bash -c "ansible -i hosts all --list-hosts | wc - l | tr -d ' '" [ "$status" -eq 0 ] [ "$output" -eq 5 ] } acceptance.bats Gareth Rushgrove
  24. 127.

    @test "per host serverspec tests pass" { run rake spec

    [ "$status" -eq 0 ] } acceptance.bats Gareth Rushgrove
  25. 129.

    ✓ no droplets exist ✓ provisioner runs successfully ✓ we

    can count the correct number of hosts ✓ we can list the new hosts ✓ all host serverspec tests pass ✓ clean up all droplets ✓ droplets have been cleaned up ! 7 tests, 0 failures Gareth Rushgrove