Dear Loyal Readers,
The basic scenario for a VPC is a public facing subnet, and a private subnet only accessible via the first subnet (this is the web server w/ data backend scenario, aka Scenario 2). Unlike spawning an instance like I did in my previous post, the challenge to this script is that many of the objects depend on each other, and they don’t get created instantaneously. So, I am going to have to create the object, but then wait for it to exist before creating something else that depends on it. And, when I detect an error, I’ll have tear it all down in reverse order.
# First load what I need require 'aws-sdk' require 'net/http' require 'net/ssh' require File.expand_path('./ruby_config.rb')
# Then name everything vpc_idx=4 vpc_name="jpm_vpc#{vpc_idx}" ig_name ="jpm_ig#{vpc_idx}" rt_name ="jpm_rt_public#{vpc_idx}" sn_public_name = "jpm_sn_public#{vpc_idx}" sn_private_name= "jpm_sn_private#{vpc_idx}" vpc_ip_base="10.10" vpc_cidr="#{vpc_ip_base}.0.0/16" sn_public_cidr="#{vpc_ip_base}.#{vpc_idx}.0/24" sn_private_cidr="#{vpc_ip_base}.#{vpc_idx+1}.0/24"
# Initialize some variables vpc_id=nil ig_id=nil sn_ids=[] rt_id=nil ec2=nil ec2client=nil
begin ec2 = AWS::EC2.new ec2client = ec2.client rescue raise "Failed to get EC2 client" end
begin # Wrap the whole thing for cleanup rescuing
## Create VPC puts "\nCreating vpc(#{vpc_name})" vpc_res = ec2client.create_vpc :cidr_block=>vpc_cidr vpc_id = vpc_res[:vpc][:vpc_id] # Wait until done print "Waiting for vpc(#{vpc_id}) to exist" until ec2client.describe_vpcs[:vpc_set].select { |v| v[:vpc_id]== vpc_id }.size == 1 do print "." sleep 1 end puts " Done" print "Found vpc(#{vpc_id}), waiting for 'available'" until ec2client.describe_vpcs[:vpc_set].select { |v| v[:vpc_id]== vpc_id }.first[:state] == "available" do print "." sleep 1 end puts " Done" # name vpc puts "Naming vpc: #{vpc_name}" ec2client.create_tags( :resources=>[ vpc_id ], :tags=>[:key=>"Name",:value=>vpc_name] )
## Create internet gateway puts "\nCreating Internet Gateway(#{ig_name})" ig_res = ec2client.create_internet_gateway ig_id = ig_res[:internet_gateway][:internet_gateway_id] print "Wating for Internet(#{ig_id}) to exist" until ec2client.describe_internet_gateways[:internet_gateway_set].select { |ig| ig[:internet_gateway_id]==ig_id }.size == 1 do print "." sleep 1 end puts " Done" # name ig puts "Naming internet gateway(#{ig_id}) #{ig_name}" ec2client.create_tags( :resources=>[ ig_id ], :tags=>[:key=>"Name",:value=>ig_name] )
## Attach IG to VPC puts "Attaching Internet Gateway(#{ig_id}) to vpc(#{vpc_id})" ec2client.attach_internet_gateway( :internet_gateway_id=>ig_id, :vpc_id=>vpc_id )
## create subnets [public/private] puts "\nCreating public subnet(#{sn_public_name}): #{sn_public_cidr}" sn1_res = ec2client.create_subnet( :vpc_id=>vpc_id, :cidr_block=>sn_public_cidr ) sn1_id = sn1_res[:subnet][:subnet_id] puts "Creating private subnet(#{sn_private_name}): #{sn_private_cidr}" sn2_res = ec2client.create_subnet( :vpc_id=>vpc_id, :cidr_block=>sn_private_cidr ) sn2_id = sn2_res[:subnet][:subnet_id] sn_ids = [sn1_id,sn2_id] puts "Waiting for subnets(#{sn_ids.join(",")}) to exist" sleep 1 until ec2client.describe_subnets[:subnet_set].select{ |s| s[:subnet_id] == sn1_id }.size == 1 sleep 1 until ec2client.describe_subnets[:subnet_set].select{ |s| s[:subnet_id] == sn2_id }.size == 1 puts "Found subnets, waiting for 'available'" sleep 1 until ec2client.describe_subnets( :subnet_ids=>sn_ids)[:subnet_set].select { |s| s[:state] == "available" }.size == 2 puts "Subnets are ready" # Name subnets puts "Naming subnet(#{sn1_id}): #{sn_public_name}" ec2client.create_tags( :resources=>[ sn1_id ], :tags=>[:key=>"Name",:value=>sn_public_name] ) puts "Naming subnet(#{sn2_id}): #{sn_private_name}" ec2client.create_tags( :resources=>[ sn2_id ], :tags=>[:key=>"Name",:value=>sn_private_name] )
## set up routing with net/16, 0.0.0.0/0 ig for public puts "\nCreating Routing table #{rt_name}" rt_res = ec2client.create_route_table( :vpc_id=>vpc_id ) rt_id = rt_res[:route_table][:route_table_id] my_route_table=nil; ec2.route_tables.each { |rt| my_route_table=rt if rt_id==rt.route_table_id } my_route_table.create_route( "0.0.0.0/0", { :internet_gateway=>ig_id } )
## Get current rt associations for that subnet and disassociate ec2client.describe_route_tables[:route_table_set].select { |rt| !rt[:association_set].empty?}.map { |as_list| as_list[:association_set] }.flatten.select{ |as| as[:subnet_id]==sn1_id }.map { |as| as[:route_table_association_id]}.each { |as_id| puts " Dissocciating routingtable/subnet using #{as_id}" ec2client.disassociate_route_table( :association_id=>as_id ) sleep 1 } puts "Associating RouteTable #{rt_name}(#{rt_id}) with Subnet #{sn_public_name}(#{sn1_id})" ec2client.associate_route_table( :subnet_id=>sn1_id, :route_table_id=>rt_id ) ec2client.create_tags( :resources=>[ rt_id ], :tags=>[:key=>"Name",:value=>rt_name] )
if FORCE_CLEANUP puts "Cleanup forced in 15 sec" sleep 15 raise "was just a test" end
rescue => error # clean up puts "\nGot error: #{error.message}\n#{error.backtrace}" if !sn_ids.empty? sn_ids.each { |sn_id| puts "Found Subnet(#{sn_id}), attempting to clean up" puts ec2client.delete_subnet( :subnet_id=>sn_id ) } end
if rt_id puts "Found RoutingTable(#{rt_id}), attempting to clean up" puts ec2client.delete_route_table( :route_table_id=>rt_id ) end
if ig_id puts "Found InternetGateway(#{ig_id}), attempting to clean up" puts ec2client.detach_internet_gateway( :internet_gateway_id=>ig_id, :vpc_id=>vpc_id ) puts ec2client.delete_internet_gateway( :internet_gateway_id=>ig_id ) end
if vpc_id puts "Found vpc(#{vpc_id}), attempting to cleanup" puts ec2client.delete_vpc( :vpc_id=>vpc_id ) end
end #begin
Until the robots take over,
Jonathan Malachowski