-
Notifications
You must be signed in to change notification settings - Fork 7
/
launch_instances
executable file
·159 lines (134 loc) · 4.89 KB
/
launch_instances
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env ruby
#
#launch_instances 2.0.2 (c) 2010 Josh Lindsey
#Took Josh's script. Prolly has some changes. Thanks Josh.
#
# Require gems with versions
begin
require 'logger'
require 'rubygems'
# gem 'fog', '~> 0.4.1'
# gem 'trollop', '~> 1.16.2'
require 'fog'
require 'trollop'
rescue LoadError
$stderr.puts "Error: Requires rubygems ~> 1.3.7, fog ~> 0.4.1, trollop ~> 1.16.2"
exit 1
end
# Setup Trollop options
opts = Trollop::options do
version "launch_instances 2.0.2 (c) 2010 Josh Lindsey"
banner <<-EOS
Launch one or several EC2 instances based on the set of [options].
Usage:
launch_instances AMI [options]
where [options] are:
EOS
opt :type, "instance type (size)", :default => 'm1.small'
opt :num, "number of instances like this to launch", :default => 1
opt :groups, "security groups to assign", :default => ['default']
opt :key, "name of the keypair to use", :type => String
opt :tags, "list of tag key/value pairs to apply", :type => :strings
opt :file, "file to read in and assign to user_data", :type => :io
opt :wait, "wait to return until instance is booted"
opt :connect, "connect to instance after boot (implies -w)"
opt :logfile, "file to log to", :type => :io, :default => $stdout
opt :loglevel, "level to set the logger at (0-4; 0 == DEBUG)", :default => 1
end
ami = ARGV.pop
# Grab access keys from system vars
AccessKeyID = ENV['AWS_ACCESS_KEY_ID']
SecretAccessKey = ENV['AWS_SECRET_ACCESS_KEY']
if AccessKeyID.nil? or SecretAccessKey.nil?
$stderr.puts "Error: must set the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.( Add them to your .bashrc)"
exit 1
end
# Input validation
AllowedInstanceTypes = %w(m1.small m1.large m1.xlarge t1.micro m2.xlarge m2.2xlarge
x2.4xlarge c1.medium c1.xlarge cc1.4xlarge)
Trollop::die "AMI is required" if ami.nil?
Trollop::die :key, 'is required' if opts[:key].nil?
Trollop::die :type, 'must be a recognized AWS instance type
(See: http://aws.amazon.com/ec2/instance-types/)' unless AllowedInstanceTypes.include? opts[:type]
Trollop::die :tags, 'must be an even number (for key => val encoding into a hash)' if !opts[:tags].nil? and
opts[:tags].length % 2 == 1
Trollop::die 'Cannot connect to more than one instance' if opts[:connect] and opts[:num] > 1
Trollop::die :loglevel, "must be between 0 and 4" unless (0..4).to_a.include? opts[:loglevel]
if opts[:connect] and !File.exists?(File.join(ENV['HOME'], '.ssh', "#{opts[:key]}.pem"))
logger.warn "Key file #{opts[:key]}.pem not found in ENV['HOME']/.ssh"
end
# Setup logger object
logger = Logger.new opts[:logfile]
logger.level = opts[:loglevel]
# Parse tags
tags = nil
unless opts[:tags].nil?
tags = Hash[*opts[:tags]]
logger.debug "Parsed tags: #{tags.inspect}"
end
# Init Fog instance
fog = Fog::Compute.new :provider => 'AWS',
:aws_access_key_id => AccessKeyID,
:aws_secret_access_key => SecretAccessKey
# Debug info
logger.debug "Options: #{opts.inspect}"
logger.debug "AMI: #{ami.inspect}"
logger.debug "Fog instance: #{fog.inspect}"
# Create the node
begin
nodes = []
logger.info "Launching #{opts[:num]} #{opts[:type]} node(s) from AMI '#{ami}'"
opts[:num].times do
node = fog.servers.create(:image_id => ami,
:flavor_id => opts[:type],
:groups => opts[:groups],
:key_name => opts[:key],
:user_data => (!opts[:file].nil? && opts[:file].read) || nil)
unless tags.nil?
logger.debug "Tagging node #{node.id}"
tags.each_pair do |k, v|
fog.tags.create :key => k, :value => v, :resource_id => node.id
end
end
logger.debug "Node: #{node.reload.inspect}"
nodes.push node
end
rescue Fog::Service::NotFound => e
if e.to_s =~ /AMI ID .* does not exist/
logger.fatal "Provided AMI ID not found"
else
# Just re-emit the exception
raise e
end
exit 1
rescue Fog::Service::Error => e
if e.to_s =~ /AuthFailure/
logger.fatal "Invalid AWS access credentials. Check your shell variables"
elsif e.to_s =~ /requested instance type's architecture/
logger.fatal "Provided instance size and AMI are incompatible"
else
# Just re-emit the exception
raise e
end
exit 1
end
# Wait on the instance to boot
if opts[:wait] or opts[:connect]
logger.info "Waiting for instance(s) to boot"
loop do
logger.debug "Sleeping"
sleep 1
break unless nodes.map { |node| node.reload.ready? }.include? false
end
# Connect to it if we're supposed to
if opts[:connect]
logger.info "Connecting to instance"
exec %Q(ssh -o StrictHostKeyChecking=no -i #{File.join(ENV['HOME'], '.ssh', "#{opts[:key]}.pem")}\
ubuntu@#{nodes.pop.reload.dns_name})
end
logger.info "DNS Names: "
nodes.each { |node| logger.info node.dns_name }
else
logger.info "Instance data: #{nodes.inspect}"
end
logger.info "Done"