Class: ClusterBomb::BombShell
Constant Summary
collapse
- WELCOME =
"Welcome to the BombShell v 0.2.1, Cowboy\n:help -- quick help"
Constants included
from Shawties
Shawties::SHAWTIES_FILE_NAME
Constants included
from Dispatcher
Dispatcher::COMMANDS, Dispatcher::COMMAND_AUTOCOMPLETE
Constants included
from History
History::HISTORY_FILE
Instance Method Summary
collapse
Methods included from Shawties
#define_shawtie, #get_shawtie, #load_shawties!, #save_shawties, #shawtie_names, #shawties_list
Methods included from Dispatcher
#dir_completion_proc, #dir_list, #dispatcher_completion_proc, #init_autocomplete, #process_cmd, #secondary_completion_proc
Methods included from History
#libedit?, #load_history, #save_history
Constructor Details
#initialize(bomb) ⇒ BombShell
Returns a new instance of BombShell.
14
15
16
17
18
19
20
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 14
def initialize(bomb)
@bomb=bomb
@bomb.interactive=true
@stty_save = `stty -g`.chomp
@roles=[]
end
|
Instance Method Details
#disconnect(p) ⇒ Object
125
126
127
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 125
def disconnect(p)
@bomb.disconnect!
end
|
#exec(p) ⇒ Object
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 170
def exec(p)
return if p=='shell'
task_name = p.split(' ').first unless p.nil?
if task_name.nil? || !@bomb.valid_task?(task_name.to_sym)
puts "Task missing or not found"
self.list(nil)
return
end
roles=@roles
opts = @bomb.get_task(task_name.to_sym).options || {}
roles = opts[:roles] if opts[:roles] && opts[:sticky_roles]
self.process_task_args(p)
puts "NOTE Using sticky roles defined on task: #{roles.inspect}" if opts[:sticky_roles]
@bomb.clear
begin
unless roles.empty?
@bomb.exec(task_name.to_sym, {:roles=>roles})
else
@bomb.exec(task_name.to_sym)
end
rescue Exception=>e
puts "ERROR: #{e.message}"
end
@bomb.clear_env!
end
|
#help(p = nil) ⇒ Object
278
279
280
281
282
283
284
285
286
287
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 278
def help(p=nil)
puts "Anything entered at the shell prompt will be executed on the current set of remote servers. "
puts "Anything preceded by a : will be interpreted as a cluster_bomb command"
puts "Available cluster_bomb commands:"
Dispatcher::COMMANDS.each do |cr|
puts " #{cr[:name]} - #{cr[:description]}"
end
puts ":<nnn> will re-execute a command from the history"
puts "Use the bang (!) to execute something in the local shell. ex !ls -la"
end
|
#history(p) ⇒ Object
129
130
131
132
133
134
135
136
137
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 129
def history(p)
Readline::HISTORY.to_a.each_with_index do |h,i|
if p.nil?
puts " #{i}: #{h}"
else
puts " #{i}: #{h}" if h.match(p)
end
end
end
|
#host_list(p) ⇒ Object
289
290
291
292
293
294
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 289
def host_list(p)
Logging.puts "Roles in use: #{@roles.join(',')}"
hl = @bomb.hosts.collect {|h| h.name}
Logging.puts "#{hl.length} active hosts"
Logging.puts "#{hl.join(',')}"
end
|
#list(p) ⇒ Object
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 155
def list(p)
tg = {}
@bomb.task_list.each do |t|
tg[t.group] ||=[]
tg[t.group] << t
end
puts "Available tasks (usually autocompletable):"
tg.to_a.sort{|a,b|a[0]<=>b[0] }.each do |ta|
puts " #{ta[0]}"
t_sorted = ta[1].sort {|a,b| a.name.to_s <=> b.name.to_s}
t_sorted.each do |t|
puts " [#{t.name}] - #{t.description}"
end
end
end
|
#loop ⇒ Object
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 22
def loop
puts WELCOME
load_history @bomb.configuration.max_history
init_autocomplete
load_shawties!
while true
cmd = read_line
break if cmd.nil?
next if cmd.empty?
if m = cmd.match(/^:(\d+)$/)
cmd = Readline::HISTORY[m[1].to_i]
next if cmd.nil?
puts cmd
Readline::HISTORY.pop
Readline::HISTORY.push(cmd)
end
Logging.log(cmd)
break if !process_input(cmd)
end
save_history
puts "Exiting..."
Logging.log_disable
end
|
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 47
def process_input(buf, reprocess=false)
if buf.index(':')==0
return false if !process_cmd(buf[1..-1])
elsif buf.index('!')==0
self.shell(buf)
elsif buf.index('\\')==0 && !reprocess
self.shawtie(buf)
else
begin
run(buf)
rescue Exception => e
puts "Exception on run command: #{e.message}"
puts e.backtrace
end
end
return true
end
|
#process_task_args(p) ⇒ Object
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 199
def process_task_args(p)
arg_keys=[]
args=p.split(' ')
return [] if args.length <=1
args[1..-1].each do |kv|
pair = kv.split('=')
if pair.length == 2
k = pair[0].strip.to_sym
arg_keys << k
@bomb.set(k,pair[1].strip)
end
end
arg_keys end
|
#read_line ⇒ Object
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 101
def read_line
total_hosts = @bomb.hosts.length
total_connected_hosts = 0
@bomb.hosts.each {|h| total_connected_hosts +=1 if h.connected}
begin
sm = @bomb.sudo_mode ? '[SUDO] ' : ''
line = Readline.readline("#{sm}(#{@bomb.username}) #{total_connected_hosts}/#{total_hosts}> ", true)
if line =~ /^\s*$/ || Readline::HISTORY.to_a[-2] == line
Readline::HISTORY.pop
end
rescue Interrupt => e
system('stty', @stty_save)
return nil
end
return line if line.nil? line.strip!
return line
end
|
#run(cmd, host_list = nil) ⇒ Object
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 303
def run(cmd, host_list=nil)
@bomb.clear
opts={}
opts[:hosts]=host_list if host_list
opts[:sudo] = true if @sudo_mode
@bomb.run(cmd, opts) do |r|
if r.exception
puts "#{r.name} => EXCEPTION: #{r.exception.message}"
else
output = r.console
ll = output.length + r.name.length + 3
if ll > @bomb.configuration.screen_width.to_i || output.index('\n')
Logging.puts "=== #{r.name} ==="
Logging.puts output
else
Logging.puts "#{r.name} => #{output}"
end
end
end
end
|
#set(p) ⇒ Object
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 138
def set(p)
return if p.nil? || p=='shell'
parts = p.split('=')
if parts.length > 2
puts "syntax: set <name>=<value"
end
k = parts[0].strip.to_sym
unless @bomb.configuration.valid_key? k
puts "Unknown configuration setting #{k}"
return
end
if parts.length == 2
@bomb.configuration.set(k,parts[1].strip)
else
@bomb.configuration.set(k,nil)
end
end
|
#shawtie(cmd) ⇒ Object
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
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 65
def shawtie(cmd)
if cmd.index(/^\\d /) == 0
m = cmd.match(/^\\d +(\w+) +(\d+)/)
if m
sdef = Readline::HISTORY[m[2].to_i]
if sdef
puts "Defined short #{m[1]} :: #{sdef}"
define_shawtie(m[1],sdef)
end
else
m = cmd.match(/^\\d +(\w+) +(.+)$/)
if m.nil?
m = cmd.match(/^\\d +(\w+)/)
define_shawtie(m[1],nil)
puts "Undefed short #{m[1]}"
else
define_shawtie(m[1],m[2])
puts "Defined short #{m[1]} - [#{m[2]}]"
end
end
elsif cmd.index(/^\\l$/) == 0
shawties_list
else
m=cmd.match(/\\(\w+)/)
if !m
shawties_list
else
sdef = get_shawtie(m[1])
if sdef
puts "Run short: #{m[1]} :: #{sdef}"
self.process_input(sdef)
end
end
end
end
|
#shell(cmd) ⇒ Object
120
121
122
123
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 120
def shell(cmd)
cmdline=cmd[1..-1].strip
puts `#{cmdline}`
end
|
#sudo(p) ⇒ Object
300
301
302
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 300
def sudo(p)
@bomb.sudo_mode = !@bomb.sudo_mode
end
|
#switch(p) ⇒ Object
296
297
298
299
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 296
def switch(p)
return if p.empty?
@bomb.switch_user(p)
end
|
#upload(p) ⇒ Object
265
266
267
268
269
270
271
272
273
274
275
276
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 265
def upload(p)
source, dest = p.split(' ') unless p.nil?
if source.nil? || dest.nil? || p.nil?
puts "syntax: upload sourcepath destpath (no wildcards)"
return true
end
begin
@bomb.upload(source, dest)
rescue Exception => e
puts "ERROR: #{e.message}"
end
end
|
#use(p) ⇒ Object
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 214
def use(p)
unless p.nil?
match = p.strip.match(/(.*?) +(.*)/)
if match
host_list = match[1]
cmd=match[2].strip
else
host_list = p
end
hosts=host_list.split(',').collect{|r|r.strip}
else
puts("Host list argument required")
return
end
@roles=[] begin
self.run(cmd, hosts)
rescue Exception => e
puts "ERROR: #{e.message}"
end
end
|
#with(p) ⇒ Object
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
|
# File 'lib/cluster_bomb/bomb_shell.rb', line 236
def with(p)
unless p.nil?
match = p.strip.match(/(.*?) +(.*)/)
if match
role_list = match[1]
cmd=match[2].strip
else
role_list = p
end
roles=role_list.split(',').collect{|r|r.strip.to_sym}
bad_role=roles.detect{|r| !@bomb.valid_role? r }
end
if p.nil? || bad_role
p.nil? ? puts("Role argument required") : puts("Unknown role: #{bad_role}")
puts "Available roles:"
@bomb.role_list.each do |r|
puts " #{r[:name]} (#{r[:hostnames].length} hosts)"
end
return
end
@roles=roles
begin
@bomb.reconnect!(@roles)
run cmd if cmd
rescue Exception => e
puts "ERROR: #{e.message}"
end
end
|