Skip to content

Instantly share code, notes, and snippets.

@moqada
Created June 24, 2014 01:59
Show Gist options
  • Save moqada/ac9560e07dfaa852bdd7 to your computer and use it in GitHub Desktop.
Save moqada/ac9560e07dfaa852bdd7 to your computer and use it in GitHub Desktop.
serverspec で Elastic Beanstalk をテストする ref: http://qiita.com/moqada/items/c62b5852c7654bb972c8
source 'https://rubygems.org'
gem 'serverspec'
gem 'rake'
mkdir -p vendor/bundle
bundle install --path vendor/bundle
require 'rake'
require 'rspec/core/rake_task'
require 'json'
servers = JSON.parse(File.read('spec/env/servers.json'))
desc "Run serverspec to all servers"
task :spec => 'serverspec:all'
class ServerspecTask < RSpec::Core::RakeTask
attr_accessor :target_host, :target_hostname
def spec_command
cmd = super
"env TARGET_HOST=#{target_host} TARGET_HOSTNAME=#{target_hostname} #{cmd}"
end
end
namespace :serverspec do
task :all => servers.map {|s| 'serverspec:' + s['name'] }
servers.each do |server|
desc "Run serverspec to #{server['name']} (#{server['hostname']})"
ServerspecTask.new(server['name'].to_sym) do |t|
t.target_host = server['host']
t.target_hostname = server['hostname']
t.pattern = 'spec/{' + server['roles'].join(',') + '}/*_spec.rb'
end
end
end
[
{
"host": "foo-staging",
"hostname": "10.0.2.206",
"name": "foo-staging-10.0.2.206",
"roles": [
"base"
]
},
{
"host": "foo-production",
"hostname": "10.0.3.225",
"name": "foo-production-10.0.3.225",
"roles": [
"base"
]
},
{
"host": "foo-production",
"hostname": "10.0.1.205",
"name": "foo-production-10.0.1.205",
"roles": [
"base"
]
}
]
bundle exec rake spec
bundle exec rake spec -t
# -*- coding: utf-8 -*-
import json
import boto
import boto.beanstalk
import boto.ec2
from fabric.api import task, puts
# Elastic Beanstalk の Applicaton 名
EB_APP_NAME = 'example-app'
# Elastic Beanstalk の リージョン名
EB_REGION = 'ap-northeast-1'
def _get_eb_conn():
""" Beanstalk の conn オブジェクトを取得する
"""
region = [r for r in boto.beanstalk.regions() if r.name == EB_REGION][0]
return boto.connect_beanstalk(region=region)
def _get_ec2_conn():
""" EC2 の conn オブジェクトを取得する
"""
region = [r for r in boto.ec2.regions() if r.name == EB_REGION][0]
return boto.connect_ec2(region=region)
def _get_eb_environments():
""" Application 内の Environment 一覧を返す
"""
conn = _get_eb_conn()
res = conn.describe_environments(application_name=EB_APP_NAME)
return res['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments']
@task
def generate_spec_servers():
""" Application 内の EC2 で severs.json を生成する
"""
puts('Start generate spec/env/servers.json for serverspec')
envs = _get_eb_environments()
eb_conn = _get_eb_conn()
ec2_conn = _get_ec2_conn()
servers = []
for e in envs:
env_name = e['EnvironmentName']
if 'production' in env_name:
host = 'foo-production'
elif 'staging' in env_name:
host = 'foo-staging'
res = eb_conn.describe_environment_resources(environment_id=e['EnvironmentId'])
instances = res['DescribeEnvironmentResourcesResponse']['DescribeEnvironmentResourcesResult']['EnvironmentResources']['Instances']
for ins in ec2_conn.get_only_instances(instance_ids=[i['Id'] for i in instances]):
servers.append({
'name': '{}-{}'.format(env_name, ins.private_ip_address),
'host': host,
'hostname': ins.private_ip_address,
'roles': ['base']
})
with open('spec/env/hosts2.json', 'w') as f:
f.write(json.dumps(servers, indent=2))
puts('Completed')
fab generate_spec_servers
bundle exec serverspec-init
Select OS type:
1) UN*X
2) Windows
Select number: 1
Select a backend type:
1) SSH
2) Exec (local)
Select number: 1
Vagrant instance y/n: n
Input target host name: example.com
+ spec/
+ spec/example.com/httpd_spec.rb
+ spec/spec_helper.rb
+ Rakefile
require 'spec_helper'
describe package('nginx') do
it { should be_installed }
end
describe service('nginx') do
it { should be_running }
end
describe port(80) do
it { should be_listening }
end
describe file('/etc/nginx/conf.d/webserver.conf') do
it { should be_file }
end
describe file('/var/log/nginx') do
it { should be_mode 755 }
end
describe process("nrsysmond") do
its(:args) { should match /-c \/etc\/newrelic\/nrsysmond.cfg -p / }
end
Host foo-staging-bastion
HostName 54.xxx.yyy.zzz
IdentityFile ~/.ssh/foo-staging.pem
User foouser
Host foo-staging
IdentityFile ~/.ssh/foo-staging.pem
User ec2-user
ProxyCommand ssh foo_step -W %h:%p
Host foo-staging-bastion
HostName 54.zzz.yyy.xxxx
IdentityFile ~/.ssh/foo-production.pem
User foouser
Host foo-production
IdentityFile ~/.ssh/foo-production.pem
User ec2-user
ProxyCommand ssh foo_step -W %h:%p
.
├── Rakefile
└── spec
   ├── base
   │   ├── fluentd_spec.rb
   │   ├── newrelic_spec.rb
   │   ├── nginx_spec.rb
   │   └── uwsgi_spec.rb
    ├── env
    │   └── servers.json
   └── spec_helper.rb
require 'serverspec'
require 'pathname'
require 'net/ssh'
include SpecInfra::Helper::Ssh
include SpecInfra::Helper::DetectOS
RSpec.configure do |c|
c.request_pty = true
if ENV['ASK_SUDO_PASSWORD']
require 'highline/import'
c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
else
c.sudo_password = ENV['SUDO_PASSWORD']
end
c.before :all do
block = self.class.metadata[:example_group_block]
if RUBY_VERSION.start_with?('1.8')
file = block.to_s.match(/.*@(.*):[0-9]+>/)[1]
else
file = block.source_location.first
end
c.ssh.close if c.ssh
c.host = ENV['TARGET_HOST']
hostname = ENV['TARGET_HOSTNAME']
options = Net::SSH::Config.for(c.host)
user = options[:user] || Etc.getlogin
c.ssh = Net::SSH.start(hostname, user, options)
c.os = backend.check_os
end
end
c.request_ppy = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment