Created
October 7, 2011 18:27
-
-
Save stuartrexking/1271016 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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