maws 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/maws +10 -0
- data/lib/maws/chunk_source.rb +41 -0
- data/lib/maws/command.rb +62 -0
- data/lib/maws/command_loader.rb +28 -0
- data/lib/maws/command_options_parser.rb +37 -0
- data/lib/maws/commands/configure.rb +287 -0
- data/lib/maws/commands/console.rb +38 -0
- data/lib/maws/commands/create.rb +25 -0
- data/lib/maws/commands/describe.rb +15 -0
- data/lib/maws/commands/destroy.rb +11 -0
- data/lib/maws/commands/elb-add.rb +17 -0
- data/lib/maws/commands/elb-describe.rb +23 -0
- data/lib/maws/commands/elb-disable-zones.rb +17 -0
- data/lib/maws/commands/elb-enable-zones.rb +18 -0
- data/lib/maws/commands/elb-remove.rb +16 -0
- data/lib/maws/commands/set-prefix.rb +24 -0
- data/lib/maws/commands/set-security-groups.rb +442 -0
- data/lib/maws/commands/start.rb +11 -0
- data/lib/maws/commands/status.rb +25 -0
- data/lib/maws/commands/stop.rb +11 -0
- data/lib/maws/commands/teardown.rb +11 -0
- data/lib/maws/commands/volumes-cleanup.rb +22 -0
- data/lib/maws/commands/volumes-status.rb +43 -0
- data/lib/maws/commands/wait.rb +61 -0
- data/lib/maws/connection.rb +121 -0
- data/lib/maws/core_ext/object.rb +5 -0
- data/lib/maws/description/ebs.rb +40 -0
- data/lib/maws/description/ec2.rb +72 -0
- data/lib/maws/description/elb.rb +52 -0
- data/lib/maws/description/rds.rb +47 -0
- data/lib/maws/description.rb +78 -0
- data/lib/maws/instance/ebs.rb +45 -0
- data/lib/maws/instance/ec2.rb +144 -0
- data/lib/maws/instance/elb.rb +92 -0
- data/lib/maws/instance/rds.rb +84 -0
- data/lib/maws/instance.rb +167 -0
- data/lib/maws/instance_collection.rb +98 -0
- data/lib/maws/instance_display.rb +84 -0
- data/lib/maws/instance_matcher.rb +27 -0
- data/lib/maws/loader.rb +173 -0
- data/lib/maws/logger.rb +66 -0
- data/lib/maws/mash.rb +9 -0
- data/lib/maws/maws.rb +102 -0
- data/lib/maws/profile_loader.rb +92 -0
- data/lib/maws/specification.rb +127 -0
- data/lib/maws/ssh.rb +7 -0
- data/lib/maws/trollop.rb +782 -0
- data/lib/maws/volumes_command.rb +29 -0
- data/lib/maws.rb +25 -0
- metadata +115 -0
data/bin/maws
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
class ChunkSource
|
2
|
+
def initialize(config, instances)
|
3
|
+
@config = config
|
4
|
+
@instances = instances
|
5
|
+
end
|
6
|
+
|
7
|
+
# what is :first, :all, :chunk
|
8
|
+
# options are:
|
9
|
+
# :chunk_size - how big the chunks are
|
10
|
+
# :chunk_key - unique name of the context for looping over all instances in chunks. every time calling this method with same key will return next chunk
|
11
|
+
# :from - nil to pick default scope for role_name, otherwise :zone or :region
|
12
|
+
def select(what, role_name, zone, options = {})
|
13
|
+
# :zone or :region
|
14
|
+
from_zone = (options[:from] || @config.combined[role_name].scope).to_sym == :zone
|
15
|
+
|
16
|
+
source_instances = from_zone ? @instances.with_zone(zone) : @instances
|
17
|
+
source_instances = source_instances.with_role(role_name)
|
18
|
+
|
19
|
+
what = :all if what == :chunk && options[:chunk_size].nil?
|
20
|
+
|
21
|
+
case what
|
22
|
+
when :all : source_instances
|
23
|
+
when :first : source_instances.first
|
24
|
+
when :chunk : pick_next_chunk(source_instances, options[:chunk_size], options[:chunk_key])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def pick_next_chunk(all, size = 1, key = "")
|
29
|
+
# this is the starting index of the current chunk
|
30
|
+
# this index doesn't wrap around, it needs to be wrapped by the lookup methiod
|
31
|
+
@chunk_indexes ||= {}
|
32
|
+
@chunk_indexes[key] ||= 0
|
33
|
+
|
34
|
+
index = @chunk_indexes[key] % all.count # real index
|
35
|
+
@chunk_indexes[key] += size # update for next time this is called
|
36
|
+
|
37
|
+
# so we don't have to do any math to wrap it
|
38
|
+
big_all = all * size
|
39
|
+
big_all[index,size]
|
40
|
+
end
|
41
|
+
end
|
data/lib/maws/command.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'maws/instance'
|
2
|
+
|
3
|
+
class Command
|
4
|
+
attr_accessor :maws, :connection
|
5
|
+
|
6
|
+
def description
|
7
|
+
"command - does nothing"
|
8
|
+
end
|
9
|
+
|
10
|
+
def instances
|
11
|
+
maws.instances
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(config)
|
16
|
+
@config = config
|
17
|
+
@maws = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def connection
|
21
|
+
@maws.connection
|
22
|
+
end
|
23
|
+
|
24
|
+
def run!
|
25
|
+
puts "generic command does nothing"
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def add_generic_options(parser)
|
30
|
+
available_roles = @config.available_roles.join(', ')
|
31
|
+
parser.opt :selection, "Selection of instances
|
32
|
+
any of the following:
|
33
|
+
zones (a, b, c, etc.)
|
34
|
+
indexes (2, 1-10, 5-, -10, *) where * is all existing indexes and blank means all defined in profile
|
35
|
+
role names (available: #{available_roles})
|
36
|
+
in any order and separated by spaces", :type => :string, :default => nil
|
37
|
+
parser.opt :prefix, "Prefix", :short => '-p', :type => :string, :default => ""
|
38
|
+
parser.opt :region, "Region", :short => '-R', :type => :string, :default => @config.config.default_region
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_specific_options(parser)
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_options
|
45
|
+
@config.region = @config.command_line.region
|
46
|
+
@config.prefix = @config.command_line.prefix
|
47
|
+
end
|
48
|
+
|
49
|
+
def verify_options
|
50
|
+
if @config.command_line.region.blank?
|
51
|
+
Trollop::die "Region must be specified in command line options OR as 'default_region' in #{@config.config.paths.config}"
|
52
|
+
end
|
53
|
+
|
54
|
+
if @config.command_line.selection.nil?
|
55
|
+
Trollop::die "Must specify a selection of some instances"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def verify_configs
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CommandLoader
|
2
|
+
def initialize(config)
|
3
|
+
@config = config
|
4
|
+
end
|
5
|
+
|
6
|
+
def load
|
7
|
+
# assumes command file is known to exist already
|
8
|
+
@config.command_name = @config.command_line.command_name
|
9
|
+
command_path = @config.config.available_commands[@config.command_name]
|
10
|
+
class_constant_name = constantize_file_name(@config.command_name)
|
11
|
+
|
12
|
+
require command_path
|
13
|
+
|
14
|
+
begin
|
15
|
+
@config.command_class = Object.const_get(class_constant_name)
|
16
|
+
rescue NameError
|
17
|
+
error "Could not load class #{class_constant_name} from the file #{command_path}"
|
18
|
+
exit(1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def constantize_file_name(dashed)
|
25
|
+
dashed.split('-').map {|w| w.capitalize}.join
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'maws/trollop'
|
2
|
+
|
3
|
+
class CommandOptionsParser
|
4
|
+
def initialize(config)
|
5
|
+
@config = config
|
6
|
+
end
|
7
|
+
|
8
|
+
def process_command_options(command)
|
9
|
+
banner_text = usage(@config.profile.name, @config.command_name)
|
10
|
+
banner_text << "\n#{command.description}\n\n"
|
11
|
+
banner_text << "options:\n"
|
12
|
+
command_opts = Trollop::options do
|
13
|
+
banner banner_text
|
14
|
+
command.add_generic_options(self)
|
15
|
+
command.add_specific_options(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
@config.command_line.merge!(command_opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
def usage(profile = nil, command = nil)
|
22
|
+
profile ||= 'profile'
|
23
|
+
command ||= 'command'
|
24
|
+
<<-EOS
|
25
|
+
|
26
|
+
MAWS - Toolset for provisioning and managing AWS
|
27
|
+
|
28
|
+
Usage:
|
29
|
+
maws.rb #{profile} #{command} [options]
|
30
|
+
|
31
|
+
profiles: #{@config.config.available_profiles.keys.join(', ')}
|
32
|
+
commands: #{@config.config.available_commands.keys.join(', ')}
|
33
|
+
|
34
|
+
EOS
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/chunk_source'
|
3
|
+
require 'erubis'
|
4
|
+
require 'maws/ssh'
|
5
|
+
require 'net/scp'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
class Configure < Command
|
11
|
+
attr_reader :options
|
12
|
+
def description
|
13
|
+
"configure - create and upload templated configurations and run commands on specified servers with SSH"
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_specific_options(parser)
|
17
|
+
parser.opt :dump, "Dump config files before uploading them", :type => :flag, :default => false
|
18
|
+
parser.opt :command, "Command to run remotely (either name or a string)", :type => :string, :default => ""
|
19
|
+
parser.opt :login_name, "The SSH login name", :short => '-l', :type => :string, :default => "root"
|
20
|
+
parser.opt :hostname, "The SSH hostname", :short => '-h', :type => :string, :default => nil
|
21
|
+
parser.opt :identity_file, "The SSH identity file", :short => '-i', :type => :string
|
22
|
+
parser.opt :copy_to_local, "Copy template output to local folders", :short => '-L', :type => :flag, :default => false
|
23
|
+
end
|
24
|
+
|
25
|
+
def run!
|
26
|
+
@chunk_source = ChunkSource.new(@config, instances)
|
27
|
+
@template_output_dir = @config.config.paths.template_output
|
28
|
+
|
29
|
+
@ssh_actions = {}
|
30
|
+
@options = @config.command_line
|
31
|
+
|
32
|
+
configurable_instances = instances.specified.find_all do |instance|
|
33
|
+
(instance.status == 'running' || instance.configure_without_running) &&
|
34
|
+
(instance.configurations || !options.command.empty?)
|
35
|
+
end
|
36
|
+
|
37
|
+
prepare_ssh_actions(configurable_instances)
|
38
|
+
execute_ssh_actions(configurable_instances)
|
39
|
+
end
|
40
|
+
|
41
|
+
def prepare_ssh_actions(instances)
|
42
|
+
instances.each do |instance|
|
43
|
+
@ssh_actions[instance] = []
|
44
|
+
build_ssh_actions_for_instance(instance)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute_ssh_actions(instances)
|
49
|
+
# create threads that execute ssh commands
|
50
|
+
threads = []
|
51
|
+
ssh_connections = {}
|
52
|
+
instances.each do |instance|
|
53
|
+
ssh_actions = @ssh_actions[instance]
|
54
|
+
next if ssh_actions.empty?
|
55
|
+
|
56
|
+
threads << Thread.new do
|
57
|
+
Thread.current[:title] = "#{instance.name} (#{instance.dns_name})"
|
58
|
+
Thread.current[:ensured_output] = []
|
59
|
+
|
60
|
+
ssh = ssh_connect_to(instance)
|
61
|
+
ssh_connections[instance] = ssh
|
62
|
+
|
63
|
+
ssh_actions.each {|action| action.call(ssh)}
|
64
|
+
|
65
|
+
ssh_disconnect(ssh, instance)
|
66
|
+
ssh_connections[instance] = nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
begin
|
71
|
+
threads.each do |t|
|
72
|
+
Kernel.sleep 0.03
|
73
|
+
t.join
|
74
|
+
end
|
75
|
+
ensure
|
76
|
+
ssh_connections.each do |instance, ssh|
|
77
|
+
ssh_disconnect(ssh, instance) if ssh
|
78
|
+
end
|
79
|
+
print_ensured_output(threads)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_ssh_actions_for_instance(instance)
|
84
|
+
if instance.configurations && instance.configurations.collect{|c| c.name}.include?(options.command)
|
85
|
+
# command specified as name of a config
|
86
|
+
configuration = instance.configurations.find{|c| c.name == options.command}
|
87
|
+
execute_configuration(instance, configuration)
|
88
|
+
elsif options.command && !options.command.empty?
|
89
|
+
queue_remote_command(instance, nil, options.command)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def ssh_connect_to(instance)
|
94
|
+
host = options.hostname || instance.dns_name
|
95
|
+
user = options.login_name
|
96
|
+
|
97
|
+
identity_file = options.identity_file || File.join(KEYPAIRS_PATH, "#{instance.keypair}.pem")
|
98
|
+
raise ArgumentError.new("Missing identity file: #{identity_file}") if !File.exists?(identity_file)
|
99
|
+
|
100
|
+
info "connecting to '#{user}@#{host}'..."
|
101
|
+
|
102
|
+
3.times { # retry on host unreachable errors
|
103
|
+
begin
|
104
|
+
return Net::SSH.start(host, user, { :keys => [identity_file], :verbose => :warn, :auth_methods => ["publickey"], :keys_only => true })
|
105
|
+
rescue Errno::EHOSTUNREACH
|
106
|
+
sleep 2
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
def ssh_disconnect(ssh, instance)
|
112
|
+
host = options.hostname || instance.dns_name
|
113
|
+
user = options.login_name
|
114
|
+
|
115
|
+
info "...done (disconnected from '#{user}@#{host}')"
|
116
|
+
ssh.close
|
117
|
+
end
|
118
|
+
|
119
|
+
def execute_configuration(instance, configuration)
|
120
|
+
if configuration.template
|
121
|
+
generate_and_queue_upload_template(instance, configuration)
|
122
|
+
elsif configuration.command
|
123
|
+
queue_remote_command(instance, configuration.name, configuration.command)
|
124
|
+
elsif configuration.command_set
|
125
|
+
configuration.command_set.to_a.each do |command_name|
|
126
|
+
specified_configuration = instance.configurations.find{|c| c.name == command_name}
|
127
|
+
execute_configuration(instance, specified_configuration) if specified_configuration
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def queue_remote_command(instance, name, command)
|
133
|
+
queue_ssh_action(instance) {|ssh| do_remote_command(ssh, instance, name, command)}
|
134
|
+
end
|
135
|
+
|
136
|
+
def do_remote_command(ssh, instance, name, command)
|
137
|
+
if name
|
138
|
+
ensure_output :info, " executing #{name} command: " + command
|
139
|
+
else
|
140
|
+
ensure_output :info, " executing #{command}"
|
141
|
+
end
|
142
|
+
|
143
|
+
result = ssh.exec!(command)
|
144
|
+
ensure_output :info, result if result
|
145
|
+
end
|
146
|
+
|
147
|
+
def generate_and_queue_upload_template(instance, configuration)
|
148
|
+
locations = [configuration.location].flatten
|
149
|
+
locations.each do |location|
|
150
|
+
# prepare params for config file interpolation
|
151
|
+
resolved_params = {}
|
152
|
+
configuration.template_params ||= {}
|
153
|
+
|
154
|
+
configuration.template_params.each do |param_name, param_config|
|
155
|
+
resolved_params[param_name] = resolve_template_param(instance, configuration.template, param_name, param_config)
|
156
|
+
end
|
157
|
+
resolved_params['instance'] = instance
|
158
|
+
resolved_params['instances'] = instances
|
159
|
+
resolved_params['settings'] = @profile.settings
|
160
|
+
|
161
|
+
# generate config file
|
162
|
+
template_path = File.join(TEMPLATES_PATH, configuration.template + ".erb")
|
163
|
+
template = File.read(template_path)
|
164
|
+
generated_config = Erubis::Eruby.new(template).result(resolved_params)
|
165
|
+
|
166
|
+
Dir.mkdir(TEMPLATE_OUTPUT_DIR) if !File.directory?(TEMPLATE_OUTPUT_DIR)
|
167
|
+
config_output_path = File.join(TEMPLATE_OUTPUT_DIR, "#{instance.name}--#{instance.aws_id}." + configuration.template)
|
168
|
+
File.open(config_output_path, "w") {|f| f.write(generated_config)}
|
169
|
+
info "generated '#{config_output_path}'"
|
170
|
+
|
171
|
+
if options.copy_to_local
|
172
|
+
info "copying to local path: #{location}"
|
173
|
+
FileUtils.cp(config_output_path, location)
|
174
|
+
end
|
175
|
+
|
176
|
+
queue_ssh_action(instance) do |ssh|
|
177
|
+
ensure_output :info, "configuring #{configuration.template} for #{instance.name}"
|
178
|
+
|
179
|
+
if options.dump
|
180
|
+
ensure_output :info, "\n\n------- BEGIN #{config_output_path} -------"
|
181
|
+
ensure_output :info, generated_config
|
182
|
+
ensure_output :info, "-------- END #{config_output_path} --------\n\n"
|
183
|
+
end
|
184
|
+
|
185
|
+
if configuration.copy_as_user
|
186
|
+
remote_tmp_path = File.join("/tmp/", "#{instance.name}--#{instance.aws_id}." + configuration.template)
|
187
|
+
ssh.scp.upload!(config_output_path, remote_tmp_path)
|
188
|
+
cp_command = "sudo su - #{configuration.copy_as_user} -c 'cp -f #{remote_tmp_path} #{location}' && sudo rm #{remote_tmp_path}"
|
189
|
+
do_remote_command(ssh, instance, 'copy_as_user', cp_command)
|
190
|
+
else
|
191
|
+
ssh.scp.upload!(config_output_path, location)
|
192
|
+
end
|
193
|
+
|
194
|
+
if configuration.owner
|
195
|
+
chown_command = "sudo su - -c 'chown -R #{configuration.owner} #{location}'"
|
196
|
+
do_remote_command(ssh, instance, 'permissions', chown_command)
|
197
|
+
end
|
198
|
+
|
199
|
+
if configuration.permissions
|
200
|
+
chmod_command = "sudo su - -c 'chmod -R #{configuration.permissions} #{location}'"
|
201
|
+
do_remote_command(ssh, instance, 'permissions', chmod_command)
|
202
|
+
end
|
203
|
+
|
204
|
+
timestamp = ssh.exec!("sudo stat -c %y #{location}")
|
205
|
+
ensure_output :info, " new timestamp for #{location}: " + timestamp
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def resolve_template_param(instance, template_name, param_name, param_config)
|
211
|
+
if param_config == 'self'
|
212
|
+
return instance
|
213
|
+
|
214
|
+
elsif param_config == 'config'
|
215
|
+
return @config
|
216
|
+
|
217
|
+
elsif param_config.is_a? String
|
218
|
+
return param_config
|
219
|
+
|
220
|
+
elsif param_config.select_one.is_a? String
|
221
|
+
context = "#{instance.role_name}-#{template_name}-#{param_name}"
|
222
|
+
@chunk_source.select(:chunk, param_config.select_one, instance.zone,
|
223
|
+
:chunk_size => 1, :chunk_key => context).first
|
224
|
+
|
225
|
+
elsif param_config.select_many.is_a? String
|
226
|
+
@chunk_source.select(:all, param_config.select_many, instance.zone)
|
227
|
+
|
228
|
+
elsif param_config.select_one
|
229
|
+
context = "#{instance.role_name}-#{template_name}-#{param_name}"
|
230
|
+
from = param_config.select_one.from # nil means default
|
231
|
+
@chunk_source.select(:chunk, param_config.select_one.role, instance.zone,
|
232
|
+
:chunk_size => 1, :chunk_key => context, :from => from).first
|
233
|
+
|
234
|
+
elsif param_config.select_many
|
235
|
+
context = "#{instance.role_name}-#{template_name}-#{param_name}"
|
236
|
+
from = param_config.select_many.from # nil means default
|
237
|
+
@chunk_source.select(:chunk, param_config.select_many.role, instance.zone,
|
238
|
+
:chunk_size => param_config.select_many.chunk_size, :chunk_key => context, :from => from)
|
239
|
+
|
240
|
+
else
|
241
|
+
param_config
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def verify_configs
|
246
|
+
@config.roles.each do |name, config|
|
247
|
+
verify_config(name, config, "role definition")
|
248
|
+
end
|
249
|
+
|
250
|
+
@config.profile.each do |name, config|
|
251
|
+
verify_config(name, config, "profile role")
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def verify_config(name, config, scope = '')
|
258
|
+
return unless config.respond_to? :configurations
|
259
|
+
|
260
|
+
Trollop::die "empty or non-array configurations for #{scope} '#{name}'" unless config.configurations.respond_to? :each
|
261
|
+
|
262
|
+
config.configurations.each do |configuration|
|
263
|
+
Trollop::die "nil configuration for #{scope} '#{name}'" unless configuration
|
264
|
+
Trollop::die "nameless configuration [#{configuration.to_hash.inspect}] for #{scope} '#{name}'" if configuration.name.to_s.empty?
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def queue_ssh_action(instance, &block)
|
269
|
+
@ssh_actions[instance] << block
|
270
|
+
end
|
271
|
+
|
272
|
+
def print_ensured_output(threads)
|
273
|
+
info "\n"
|
274
|
+
threads.each do |t|
|
275
|
+
InstanceDisplay.pretty_describe_heading(t[:title])
|
276
|
+
t[:ensured_output].each do |method, message|
|
277
|
+
send(method, message)
|
278
|
+
end
|
279
|
+
|
280
|
+
InstanceDisplay.pretty_describe_footer
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def ensure_output method, message
|
285
|
+
Thread.current[:ensured_output] << [method.to_sym, message]
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
|
3
|
+
class Console < Command
|
4
|
+
def description
|
5
|
+
"console - interactive console for direct access to MAWS internal objects"
|
6
|
+
end
|
7
|
+
|
8
|
+
def run!
|
9
|
+
IRB.start_session(binding)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
require 'irb'
|
16
|
+
|
17
|
+
module IRB # :nodoc:
|
18
|
+
def self.start_session(binding)
|
19
|
+
unless @__initialized
|
20
|
+
args = ARGV
|
21
|
+
ARGV.replace(ARGV.dup)
|
22
|
+
IRB.setup(nil)
|
23
|
+
ARGV.replace(args)
|
24
|
+
@__initialized = true
|
25
|
+
end
|
26
|
+
|
27
|
+
workspace = WorkSpace.new(binding)
|
28
|
+
|
29
|
+
irb = Irb.new(workspace)
|
30
|
+
|
31
|
+
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
32
|
+
@CONF[:MAIN_CONTEXT] = irb.context
|
33
|
+
|
34
|
+
catch(:IRB_EXIT) do
|
35
|
+
irb.eval_input
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
|
3
|
+
class Create < Command
|
4
|
+
def description
|
5
|
+
"create - creates all specified instances if they don't exist"
|
6
|
+
end
|
7
|
+
|
8
|
+
def run!
|
9
|
+
instances_to_create = instances.specified.not_alive
|
10
|
+
if instances_to_create.empty?
|
11
|
+
info "nothing to create"
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
instances_to_create.each {|i| i.create}
|
16
|
+
|
17
|
+
# create tags
|
18
|
+
instances_to_be_tagged = instances_to_create.alive.with_service(:ec2)
|
19
|
+
unless instances_to_be_tagged.empty?
|
20
|
+
sleep 2
|
21
|
+
# connection.silent = true
|
22
|
+
instances_to_be_tagged.each {|i| i.create_tags}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'terminal-table/import'
|
3
|
+
|
4
|
+
class Describe < Command
|
5
|
+
def description
|
6
|
+
"describe - prints all available AWS information for specified instances"
|
7
|
+
end
|
8
|
+
|
9
|
+
def run!
|
10
|
+
instances.specified.each do |i|
|
11
|
+
i.display.pretty_details
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/elb_command'
|
3
|
+
require 'maws/trollop'
|
4
|
+
|
5
|
+
class ElbAdd < ElbCommand
|
6
|
+
def description
|
7
|
+
"elb-add - adds all specified EC2 instances to all specified ELBs"
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
ec2s = instances.specified.with_service(:ec2)
|
12
|
+
elbs = instances.specified.with_service(:elb)
|
13
|
+
|
14
|
+
elbs.each {|elb| elb.add_instances(ec2s)}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/elb_command'
|
3
|
+
require 'maws/trollop'
|
4
|
+
|
5
|
+
class ElbDescribe < ElbCommand
|
6
|
+
def description
|
7
|
+
"elb-describe - prints detailed information about all specified ELBs"
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
elbs = instances.specified.with_service(:elb)
|
12
|
+
|
13
|
+
elbs.each do |elb|
|
14
|
+
title = elb.name.to_s.upcase
|
15
|
+
instances = elb.attached_instances
|
16
|
+
text = "ENABLED ZONES: #{elb.enabled_availability_zones.join(', ')}\n" +
|
17
|
+
"ATTACHED INSTANCES:\n\n" +
|
18
|
+
instances.collect {|i| "#{i.name} (#{i.aws_id})"}.join("\n")
|
19
|
+
|
20
|
+
InstanceDisplay.pretty_describe(title, text)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/elb_command'
|
3
|
+
require 'maws/trollop'
|
4
|
+
|
5
|
+
class ElbDisableZones < ElbCommand
|
6
|
+
def description
|
7
|
+
"elb-disable-zones - remove entire zones from specified ELBs (ELBs will not allow removing the last zone)"
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_specific_options(parser)
|
11
|
+
parser.opt :zones, "Zones to disable", :short => '-z', :type => :strings
|
12
|
+
end
|
13
|
+
|
14
|
+
def run!
|
15
|
+
instances.specified.with_service(:elb).each {|elb| elb.disable_zones(options.zones)}
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/elb_command'
|
3
|
+
require 'maws/trollop'
|
4
|
+
|
5
|
+
class ElbEnableZones < ElbCommand
|
6
|
+
def description
|
7
|
+
"elb-enable-zones - add entire zones to specified ELBs (zones must exist)"
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def add_specific_options(parser)
|
12
|
+
parser.opt :zones, "Zones to enable", :short => '-z', :type => :strings
|
13
|
+
end
|
14
|
+
|
15
|
+
def run!
|
16
|
+
instances.specified.with_service(:elb).each {|elb| elb.enable_zones(options.zones)}
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
require 'maws/elb_command'
|
3
|
+
require 'maws/trollop'
|
4
|
+
|
5
|
+
class ElbRemove < ElbCommand
|
6
|
+
def description
|
7
|
+
"elb-remove - remove specified EC2 instances from specified ELBs"
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
ec2s = instances.specified.with_service(:ec2)
|
12
|
+
elbs = instances.specified.with_service(:elb)
|
13
|
+
|
14
|
+
elbs.each {|elb| elb.remove_instances(ec2s)}
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'maws/command'
|
2
|
+
|
3
|
+
class SetPrefix < Command
|
4
|
+
def description
|
5
|
+
"set-prefix - sets prefix for specified EC2 instances"
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_specific_options(parser)
|
9
|
+
parser.opt :prefix_to_set, "Prefix to set", :short => "-P", :type => :string, :default => ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def verify_options
|
13
|
+
super
|
14
|
+
prefix = @config.command_line.prefix_to_set
|
15
|
+
|
16
|
+
Trollop::die "Can't set the prefix to be the same as the prefix currently in scope: '#{@config.prefix}'" if prefix == @config.prefix
|
17
|
+
end
|
18
|
+
|
19
|
+
def run!
|
20
|
+
prefix = @config.command_line.prefix_to_set
|
21
|
+
|
22
|
+
instances.specified.alive.each {|i| i.set_prefix(prefix) if i.respond_to?(:set_prefix)}
|
23
|
+
end
|
24
|
+
end
|