Slide 1

Slide 1 text

Infrataster ~ Infra Behavior Testing Framework ~ Ryota Arai

Slide 2

Slide 2 text

Self Introduction

Slide 3

Slide 3 text

Ryota Arai ߥҪ ྑଠ Infrastructure Engineer ! 2013.04~ GREE, Inc 2014.03~ COOKPAD, Inc ! https://twitter.com/ryot_a_rai https://github.com/ryotarai

Slide 4

Slide 4 text

Infrataster tast‧er [countable] 1. someone whose job is to test the quality of foods, teas, wines etc by tasting them (Longman Dictionary)

Slide 5

Slide 5 text

Infrastructure as Code Automate building infra by code ! with Chef, Puppet, Ansible and also shell scripts # Example: Chef # install apache package 'apache2' do action :install end ! # start apache service 'apache2' do action :start end

Slide 6

Slide 6 text

What is Infrataster? Infrastructure Behavior Testing Framework ! It tests infrastructure's behavior from outside of servers.

Slide 7

Slide 7 text

What is Infrataster? describe server(:proxy) do describe http('http://app.example.com') do it "returns content including 'app'" do expect(response.body).to include('app') end end ! describe http('http://static.example.com') do it "returns content including 'static'" do expect(response.body).to include('static') end end end

Slide 8

Slide 8 text

What is Infrataster? $ rspec ! server 'proxy' http 'http://app.example.com' returns content including 'app' http 'http://static.example.com' returns content including 'static' ! Finished in 8.87 seconds 2 examples, 0 failures

Slide 9

Slide 9 text

Behavior Testing Framework? Apache MySQL Browser (User) Application server

Slide 10

Slide 10 text

Behavior Testing Framework? Apache MySQL Browser (User) ☓ Application ☓ server

Slide 11

Slide 11 text

Behavior Testing Framework? Apache MySQL Browser (User) Application iptables GRANT server

Slide 12

Slide 12 text

Behavior Testing Framework? ? Infrataster Check MySQL query response Check HTTP response target server

Slide 13

Slide 13 text

Behavior Testing Framework? Apache MySQL Config Check file content Is Apache running? Is port 80 opened? Is MySQL running? ? whitebox blackbox Infrataster Check MySQL query response Check HTTP response target server Serverspec

Slide 14

Slide 14 text

Test Driven Infrastructure RED GREEN RED GREEN Infrataster

Slide 15

Slide 15 text

Getting Started $ bundle install $ rspec --init # spec/spec_helper.rb require 'infrataster/rspec' # Gemfile source 'https://rubygems.org' gem 'infrataster'

Slide 16

Slide 16 text

Create VM with Vagrant # Vagrantfile Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise64" ! config.vm.define :proxy do |c| c.vm.network "private_network", ip: "192.168.33.10" c.vm.network "private_network", ip: "171.16.33.10", virtualbox__intnet: "infrataster-example" end ! config.vm.define :app do |c| c.vm.network "private_network", ip: "171.16.33.11", virtualbox__intnet: "infrataster-example" end end

Slide 17

Slide 17 text

Define Servers VM Host Proxy 192.168.33.10 (172.16.33.10) Infrataster::Server.define( :proxy, # name '192.168.0.0/16', # ip address vagrant: true # for vagrant VM )

Slide 18

Slide 18 text

Define Servers VM Host Proxy 192.168.33.10 (172.16.33.10) Infrataster::Server.define( :proxy, # name '192.168.0.0/16', # ip address vagrant: true # for vagrant VM ) Auto detect Auto SSH config

Slide 19

Slide 19 text

Define Servers VM Host Proxy 192.168.33.10 (172.16.33.10) App 172.16.33.11 SSH Port Forwarding Infrataster::Server.define( :proxy, # name '192.168.0.0/16', # ip address vagrant: true # for vagrant VM ) ! Infrataster::Server.define( :app, # name '172.16.0.0/16', # ip address vagrant: true, # for vagrant VM from: :proxy # test from proxy )

Slide 20

Slide 20 text

Define Servers VM Host Proxy 192.168.33.10 (172.16.33.10) App 172.16.33.11 SSH Port Forwarding Infrataster::Server.define( :proxy, # name '192.168.0.0/16', # ip address vagrant: true # for vagrant VM ) ! Infrataster::Server.define( :app, # name '172.16.0.0/16', # ip address vagrant: true, # for vagrant VM from: :proxy # test from proxy ) Access from proxy by SSH port forwarding

Slide 21

Slide 21 text

'http' resource describe server(:proxy) do # 192.168.33.10 describe http('http://app') do it "responds content including 'Hello Sinatra'" do expect(response.body).to include('Hello Sinatra') end end describe http('http://static') do it "responds content including 'Welcome to nginx!'" do expect(response.body).to include('Welcome to nginx!') end end end

Slide 22

Slide 22 text

'http'resource describe server(:proxy) do # 192.168.33.10 describe http('http://app') do it "responds content including 'Hello Sinatra'" do expect(response.body).to include('Hello Sinatra') end end describe http('http://static') do it "responds content including 'Welcome to nginx!'" do expect(response.body).to include('Welcome to nginx!') end end end Access from proxy by SSH port forwarding VirtualHost support (Host header manipulation) response is a Faraday::Response (You can check status, header too)

Slide 23

Slide 23 text

‘capybara' resource describe server(:app) do # Test from proxy server describe capybara('http://app') do it "responds content including 'Hello Sinatra'" do visit '/' expect(page).to have_content('Hello Sinatra') end end end

Slide 24

Slide 24 text

'capybara' resource PhantomJS (Poltergeist) SSH SSH (proxy) app Visit http://127.0.0.1:XXXX (with Host:app header) Forward from 127.0.0.1:XXXX to app:80 Listen 80 describe server(:app) do # Test from proxy server describe capybara('http://app') do it "responds content including 'Hello Sinatra'" do visit '/' expect(page).to have_content('Hello Sinatra') end end end

Slide 25

Slide 25 text

'capybara' resource (#2) describe server(:app) do describe capybara('http://app') do before { page.driver.clear_network_traffic } specify "all resources is loaded with success" do visit '/' page.driver.network_traffic.each do |req| req.response_parts.each do |res| expect(res.status).to be_between(200, 299) end end end end end

Slide 26

Slide 26 text

'mysql_query' resource describe server(:db) do describe mysql_query('SHOW STATUS') do it 'responds uptime' do row = results.find do |r| r['Variable_name'] == 'Uptime' end expect(row['Value'].to_i).to be > 0 end end end https://github.com/ryotarai/infrataster-plugin-mysql

Slide 27

Slide 27 text

Run Specs $ bundle exec rspec Run options: include {:focus=>true} ! All examples were filtered out; ignoring {:focus=>true} ! server 'app' from 'proxy' capybara 'http://app' responds content including 'Hello Sinatra' http 'http://app' responds content including 'Hello Sinatra' responds OK 200 responds as 'text/html' server 'proxy' http 'http://static' responds as 'text/html' responds content including 'Welcome to nginx!' … ! Finished in 17.92 seconds 11 examples, 0 failures ! Randomized with seed 12750

Slide 28

Slide 28 text

After Infrataster Test Passed $ curl http://server_tested_with_infrataster It always works!

Slide 29

Slide 29 text

infrataster.net