Skip to content

Instantly share code, notes, and snippets.

@stuartrexking
Created October 7, 2011 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stuartrexking/1271016 to your computer and use it in GitHub Desktop.
Save stuartrexking/1271016 to your computer and use it in GitHub Desktop.
#! /usr/bin/ruby
require 'rubygems'
require 'fog'
require 'json'
require 'optparse'
USAGE = "usage: bootstrap.rb build_number "
#defaults
region = 'us-west-1'
image = 'ami-596f3c1c'
instance_type = 'm1.small'
environ = 'test'
domain = 'a domain'
api_ip = '127.0.0.1'
build_ip = '127.0.0.1'
hornetq_ip = '127.0.0.1'
mongodb_ip = '127.0.0.1'
mongodb_replset = false
mongodb_master = false
mongodb_masterip = '127.0.0.1'
solr_ip = '127.0.0.1'
webapp_ip = '127.0.0.1'
run_list = 'role[base-system] role[mongodb] role[sync-api] role[solr] role[nginx]'
sec_group = nil
build_json = 'server.json'
ARGV.options do |opts|
opts.banner = USAGE
opts.separator " Options:"
opts.on("-a", "--api API_IP", %{api ip address (default "127.0.0.1")}) do |api|
api_ip = api
end
opts.on("-b", "--build BUILD_IP", %{build server ip address (default "127.0.0.1")}) do |bs|
build_ip = bs
end
opts.on("-d", "--domain DOMAIN", %{domain for nginx config (default "guid.ee")}) do |dom|
domain = dom
end
opts.on("-e", "--env ENVIRON", %{environment (default "test")}) do |env|
environ = env
end
opts.on("-g", "--groups GROUPS", %{aws security groups (default environment)}) do |grp|
sec_group = grp
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
opts.on("-i", "--image IMAGE", %{Amazon Machine Image (default "ami-596f3c1c")}) do |img|
image = img
end
opts.on("-j", "--json JSON", %{json for dependent build (default server.json)}) do |grp|
sec_group = grp
end
opts.on("-l", "--runlist RUNLIST", %{chef run_list (default "role[base-system] role[mongodb] role[sync-api] role[solr] role[nginx]")}) do |run|
run_list = run
end
opts.on("-m", "--mongodb MONGODB_IP", %{mongodb ip address (default "127.0.0.1")}) do |mdb|
mongodb_ip = mdb
end
opts.on( "--mongodb-replset MONGODB_REPLSET", %{mongodb replication set }) do |mrs|
mongodb_replset = mrs
end
opts.on( "--mongodb-master", %{mongodb replset master }) do
mongodb_master = true
end
opts.on("-q", "--hornetq HORNETQ_IP", %{hornetq ip address (default "127.0.0.1")}) do |hq|
hornetq_ip = hq
end
opts.on("-r", "--region REGION", %{aws region (default "us-west-1")}) do |reg|
region = reg
end
opts.on("-s", "--solr SOLR_IP", %{solr ip address (default "127.0.0.1")}) do |solr|
solr_ip = solr
end
opts.on("-t", "--type TYPE", %{aws instance type (default 'm1.small")}) do |type|
instance_type = type
end
opts.on("-w", "--webapp WEBAPP_IP", %{webapp ip address (default "127.0.0.1")}) do |wapp|
webapp_ip = wapp
end
opts.parse!
if ARGV.count != 1
puts opts
exit
elsif mongodb_master && ! mongodb_replset
puts "mongodb replset undefined. Use --mongodb-replset"
puts opts
exit
end
end
#build number and type
build_num = ARGV[0]
#automation user
access_key_id = 'key'
secret_access_key = 'secret'
#vm variables
sec_group ||= "#{environ}"
key_name = "#{environ}"
key_path = "chef/cookbooks/440/files/default/#{environ}_rsa"
ssh_username = 'ubuntu'
chef_json = "chef/bootstrap.json"
#chef variables
chef_version = '0.10.2'
gem_path = "/var/lib/gems/1.8/bin"
chef_cmd = "#{gem_path}/chef-solo"
#thieved from knife code
def tcp_test_ssh(hostname)
tcp_socket = TCPSocket.new(hostname, 22)
readable = IO.select([tcp_socket], nil, nil, 5)
if readable
yield
true
else
false
end
rescue Errno::ETIMEDOUT
false
rescue Errno::EPERM
false
rescue Errno::ECONNREFUSED
sleep 2
false
# This happens on EC2 quite often
rescue Errno::EHOSTUNREACH
sleep 2
false
ensure
tcp_socket && tcp_socket.close
end
connection = Fog::Compute.new(:provider => 'AWS', :aws_access_key_id => access_key_id, :aws_secret_access_key => secret_access_key, :region => region)
#mongodb replset checks
if mongodb_replset
mymaster = connection.servers.find_all { |s| s.tags["mongodb_master"] == mongodb_replset && s.state == 'running' }
if mongodb_master
if mymaster.count != 0
raise "master for replset #{mongodb_replset} already exists"
end
else
if mymaster.count == 0
raise "Could not find master for replset #{mongodb_replset}"
elsif mymaster.count > 1 && ! mongodb_master
raise "Found #{mymaster.count} masters for replset #{mongodb_replset}. I am confused"
else
mongodb_masterip = mymaster[0].private_ip_address
end
end
end
puts "creating new aws instance"
server = connection.servers.create(:image_id => image, :key_name => key_name, :flavor_id => instance_type, :groups => sec_group.split)
server.wait_for { ready? }
#tag server with build number
connection.tags.new(:resource_id => server.id, :resource_type => 'instance', :key => 'build', :value => build_num).save
#tag mongodb replset master
if mongodb_master
connection.tags.new(:resource_id => server.id, :resource_type => 'instance', :key => 'mongodb_master', :value => mongodb_replset).save
end
puts('.') until tcp_test_ssh(server.public_ip_address) {
sleep 30
puts "Configuring #{server.id}"
}
#server.reload
#ssh in and install
server.private_key_path = key_path
server.username = ssh_username
chef_commands = ["sudo apt-get update", "sudo apt-get -y install ruby rubygems", "sudo gem install chef -v #{chef_version}"]
chef_commands.each do |c|
rc = server.ssh("#{c}")
if rc[0].status != 0
raise "#{rc[0].command} failed. #{rc[0].stdout} #{rc[0].stderr}"
else
puts "#{rc[0].command} completed"
end
end
chef_details = {
"environ" => environ,
"nginx_domain" => domain,
"mongodb_ipaddress" => mongodb_ip,
"mongodb_replset" => mongodb_replset,
"mongodb_master" => mongodb_master,
"mongodb_masterip" => mongodb_masterip,
"hornetq_ipaddress" => hornetq_ip,
"solr_ipaddress" => solr_ip,
"api_ipaddress" => api_ip,
"build_ipaddress" => build_ip,
"webapp_ipaddress" => webapp_ip,
"run_list" => run_list.split
}
#generate bootstrap.json
File.open(chef_json, 'w') do |f|
f.puts JSON.generate(chef_details)
end
#run chef-solo
server.scp("chef/", ".", :recursive => true)
rc = server.ssh("/usr/bin/sudo #{chef_cmd} -c chef/solo.rb -j #{chef_json}")
if rc[0].status != 0
raise "#{rc[0].command} failed. #{rc[0].stdout} #{rc[0].stderr}"
else
puts "#{rc[0].command} completed"
end
#json for dependant builds
vmdetails = {:id => "#{server.id}", :private_ip => "#{server.private_ip_address}", :public_ip => "#{server.public_ip_address}", :build => "#{build_num}"}
File.open(build_json, 'w') do |f|
f.puts JSON.generate(vmdetails)
end
puts "New server #{server.id} public ip: #{server.public_ip_address} private ip: #{server.private_ip_address}"
puts "Details saved to #{build_json}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment