solutious-rudy 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rudy/routines.rb CHANGED
@@ -8,8 +8,11 @@ module Rudy
8
8
 
9
9
  class Base
10
10
  include Rudy::Huxtable
11
-
12
- def initialize(*args)
11
+
12
+ # * +cmdname+ The name of the command specified on the command line
13
+ # * +option+ An OpenStruct of named command line options
14
+ # * +argv+ An Array of command line argument
15
+ def initialize(cmdname, option, argv, *args)
13
16
  a, s, r = @@global.accesskey, @@global.secretkey, @@global.region
14
17
  @sdb = Rudy::AWS::SDB.new(a, s, r)
15
18
  @rinst = Rudy::AWS::EC2::Instances.new(a, s, r)
@@ -17,11 +20,12 @@ module Rudy
17
20
  @rkey = Rudy::AWS::EC2::KeyPairs.new(a, s, r)
18
21
  @rvol = Rudy::AWS::EC2::Volumes.new(a, s, r)
19
22
  @rsnap = Rudy::AWS::EC2::Snapshots.new(a, s, r)
23
+ @cmdname, @option, @argv = cmdname, option, argv
24
+ @option ||= OpenStruct.new
20
25
  init(*args)
21
26
  end
22
27
 
23
- def init
24
- end
28
+ def init; raise "Must override init"; end
25
29
 
26
30
  def execute
27
31
  raise "Override execute method"
@@ -39,6 +43,8 @@ module Rudy
39
43
  # machine between the disk routine and after blocks. The block receives
40
44
  # two argument: an instance of Rudy::Machine and one of Rye::Box.
41
45
  def generic_machine_runner(machine_action, routine=nil, skip_check=false, skip_header=false, &routine_action)
46
+ is_available= false
47
+
42
48
  if @@global.offline
43
49
  rmach = Rudy::Machines::Offline.new
44
50
  skip_check = true
@@ -74,15 +80,15 @@ module Rudy
74
80
  }
75
81
 
76
82
 
77
- lbox = Rye::Box.new('localhost')
83
+ lbox = Rye::Box.new('localhost', :info => (@@global.verbose > 3), :debug => false)
78
84
  sconf = fetch_script_config
79
85
 
80
86
  enjoy_every_sandwich {
81
87
  if Rudy::Routines::ScriptHelper.before_local?(routine) # before_local
82
88
  # Runs "before_local" scripts of routines config.
83
- puts task_separator("LOCAL SHELL")
89
+ task_separator("LOCAL SHELL")
84
90
  lbox.cd Dir.pwd # Run local command block from current working directory
85
- Rudy::Routines::ScriptHelper.before_local(routine, sconf, lbox)
91
+ Rudy::Routines::ScriptHelper.before_local(routine, sconf, lbox, @option, @argv)
86
92
  end
87
93
  }
88
94
 
@@ -90,9 +96,9 @@ module Rudy
90
96
  if Rudy::Routines::ScriptHelper.script_local?(routine) # script_local
91
97
  # Runs "script_local" scripts of routines config.
92
98
  # NOTE: This is synonymous with before_local
93
- puts task_separator("LOCAL SHELL")
99
+ task_separator("LOCAL SHELL")
94
100
  lbox.cd Dir.pwd # Run local command block from current working directory
95
- Rudy::Routines::ScriptHelper.script_local(routine, sconf, lbox)
101
+ Rudy::Routines::ScriptHelper.script_local(routine, sconf, lbox, @option, @argv)
96
102
  end
97
103
  }
98
104
 
@@ -131,80 +137,86 @@ module Rudy
131
137
  next # The short circuit
132
138
  end
133
139
 
134
- unless skip_check
135
- msg = preliminary_separator("Waiting for SSH daemon...")
136
- Rudy::Utils.waiter(2, 60, STDOUT, msg, 0) {
137
- Rudy::Utils.service_available?(machine.dns_public, 22)
140
+ if !skip_check && has_remote_task?(routine)
141
+ enjoy_every_sandwich {
142
+ msg = preliminary_separator("Waiting for SSH daemon...")
143
+ ret = Rudy::Utils.waiter(2, 1, STDOUT, msg, 0) {
144
+ Rudy::Utils.service_available?(machine.dns_public, 22)
145
+ }
146
+ is_available = ret
138
147
  }
139
148
  end
140
149
 
141
- # TODO: trap rbox errors. We could get an authentication error.
142
- opts = { :keys => root_keypairpath, :user => remote_user, :info => @@global.verbose > 0 }
143
- begin
144
- rbox = Rye::Box.new(machine.dns_public, opts)
145
- rbox.connect
146
- rescue Rye::NoHost => ex
147
- STDERR.puts "No host: #{ex.message}"
148
- exit 65
149
- end
150
+ if is_available
151
+ # TODO: trap rbox errors. We could get an authentication error.
152
+ opts = { :keys => root_keypairpath, :user => remote_user, :info => @@global.verbose > 0 }
153
+ begin
154
+ rbox = Rye::Box.new(machine.dns_public, opts)
155
+ Rudy::Utils.waiter(2, 10, STDOUT, nil, 0) { rbox.connect }
156
+ rescue Rye::NoHost => ex
157
+ STDERR.puts "No host: #{ex.message}"
158
+ exit 65
159
+ end
150
160
 
151
- unless skip_check
152
- # Set the hostname if specified in the machines config.
153
- # :rudy -> change to Rudy's machine name
154
- # :default -> leave the hostname as it is
155
- # Anything else other than nil -> change to that value
156
- # NOTE: This will set hostname every time a routine is
157
- # run so we may want to make this an explicit action.
161
+ unless skip_check
162
+ # Set the hostname if specified in the machines config.
163
+ # :rudy -> change to Rudy's machine name
164
+ # :default -> leave the hostname as it is
165
+ # Anything else other than nil -> change to that value
166
+ # NOTE: This will set hostname every time a routine is
167
+ # run so we may want to make this an explicit action.
168
+ enjoy_every_sandwich {
169
+ hn = current_machine_hostname || :rudy
170
+ if hn != :default
171
+ hn = machine.name if hn == :rudy
172
+ print preliminary_separator("Setting hostname to #{hn}... ")
173
+ rbox.hostname(hn)
174
+ puts "done"
175
+ end
176
+ }
177
+ end
178
+
179
+
180
+ ## NOTE: This prevents shutdown from doing its thing and prob
181
+ ## isn't necessary.
182
+ ##unless has_remote_task?(routine)
183
+ ## puts "[no remote tasks]"
184
+ ## next
185
+ ##end
186
+
158
187
  enjoy_every_sandwich {
159
- hn = current_machine_hostname || :rudy
160
- if hn != :default
161
- hn = machine.name if hn == :rudy
162
- print preliminary_separator("Setting hostame to #{hn}... ")
163
- rbox.hostname(hn)
164
- puts "done"
188
+ if Rudy::Routines::UserHelper.adduser?(routine) # adduser
189
+ task_separator("ADD USER")
190
+ Rudy::Routines::UserHelper.adduser(routine, machine, rbox)
165
191
  end
166
192
  }
167
- end
168
193
 
169
- ## NOTE: This prevents shutdown from doing its thing and prob
170
- ## isn't necessary.
171
- ##unless has_remote_task?(routine)
172
- ## puts "[no remote tasks]"
173
- ## next
174
- ##end
175
-
176
- enjoy_every_sandwich {
177
- if Rudy::Routines::UserHelper.adduser?(routine) # adduser
178
- puts task_separator("ADD USER")
179
- Rudy::Routines::UserHelper.adduser(routine, machine, rbox)
180
- end
181
- }
182
-
183
- enjoy_every_sandwich {
184
- if Rudy::Routines::UserHelper.authorize?(routine) # authorize
185
- puts task_separator("AUTHORIZE USER")
186
- Rudy::Routines::UserHelper.authorize(routine, machine, rbox)
187
- end
188
- }
194
+ enjoy_every_sandwich {
195
+ if Rudy::Routines::UserHelper.authorize?(routine) # authorize
196
+ task_separator("AUTHORIZE USER")
197
+ Rudy::Routines::UserHelper.authorize(routine, machine, rbox)
198
+ end
199
+ }
189
200
 
190
- enjoy_every_sandwich {
191
- if Rudy::Routines::ScriptHelper.before?(routine) # before
192
- puts task_separator("REMOTE SHELL")
193
- Rudy::Routines::ScriptHelper.before(routine, sconf, machine, rbox)
194
- end
195
- }
201
+ enjoy_every_sandwich {
202
+ if Rudy::Routines::ScriptHelper.before?(routine) # before
203
+ task_separator("REMOTE SHELL")
204
+ Rudy::Routines::ScriptHelper.before(routine, sconf, machine, rbox, @option, @argv)
205
+ end
206
+ }
196
207
 
197
- enjoy_every_sandwich {
198
- if Rudy::Routines::DiskHelper.disks?(routine) # disk
199
- puts task_separator("DISKS")
200
- if rbox.ostype == "sunos"
201
- puts "Sorry, Solaris disks are not supported yet!"
202
- else
203
- Rudy::Routines::DiskHelper.execute(routine, machine, rbox)
204
- end
205
- end
206
- }
208
+ enjoy_every_sandwich {
209
+ if Rudy::Routines::DiskHelper.disks?(routine) # disk
210
+ task_separator("DISKS")
211
+ if rbox.ostype == "sunos"
212
+ puts "Sorry, Solaris disks are not supported yet!"
213
+ else
214
+ Rudy::Routines::DiskHelper.execute(routine, machine, rbox)
215
+ end
216
+ end
217
+ }
207
218
 
219
+ end
208
220
 
209
221
  enjoy_every_sandwich {
210
222
  # Startup, shutdown, release, deploy, etc...
@@ -212,38 +224,40 @@ module Rudy
212
224
  }
213
225
 
214
226
 
215
- # The "after" blocks are synonymous with "script" blocks.
216
- # For some routines, like startup, it makes sense to an
217
- # "after" block b/c "script" is ambiguous. In generic
218
- # routines, there is no concept of before or after. The
219
- # definition is the entire routine so we use "script".
220
- # NOTE: If both after and script are supplied they will
221
- # both be executed.
222
- enjoy_every_sandwich {
223
- if Rudy::Routines::ScriptHelper.script?(routine) # script
224
- puts task_separator("REMOTE SHELL")
225
- # Runs "after" scripts of routines config
226
- Rudy::Routines::ScriptHelper.script(routine, sconf, machine, rbox)
227
- end
228
- }
227
+ if is_available
228
+ # The "after" blocks are synonymous with "script" blocks.
229
+ # For some routines, like startup, it makes sense to an
230
+ # "after" block b/c "script" is ambiguous. In generic
231
+ # routines, there is no concept of before or after. The
232
+ # definition is the entire routine so we use "script".
233
+ # NOTE: If both after and script are supplied they will
234
+ # both be executed.
235
+ enjoy_every_sandwich {
236
+ if Rudy::Routines::ScriptHelper.script?(routine) # script
237
+ task_separator("REMOTE SHELL")
238
+ # Runs "after" scripts of routines config
239
+ Rudy::Routines::ScriptHelper.script(routine, sconf, machine, rbox, @option, @argv)
240
+ end
241
+ }
229
242
 
230
- enjoy_every_sandwich {
231
- if Rudy::Routines::ScriptHelper.after?(routine) # after
232
- puts task_separator("REMOTE SHELL")
233
- # Runs "after" scripts of routines config
234
- Rudy::Routines::ScriptHelper.after(routine, sconf, machine, rbox)
235
- end
236
- }
243
+ enjoy_every_sandwich {
244
+ if Rudy::Routines::ScriptHelper.after?(routine) # after
245
+ task_separator("REMOTE SHELL")
246
+ # Runs "after" scripts of routines config
247
+ Rudy::Routines::ScriptHelper.after(routine, sconf, machine, rbox, @option, @argv)
248
+ end
249
+ }
237
250
 
238
- rbox.disconnect
251
+ rbox.disconnect
252
+ end
239
253
  end
240
-
254
+
241
255
  enjoy_every_sandwich {
242
256
  if Rudy::Routines::ScriptHelper.after_local?(routine) # after_local
243
- puts task_separator("LOCAL SHELL")
257
+ task_separator("LOCAL SHELL")
244
258
  lbox.cd Dir.pwd # Run local command block from current working directory
245
259
  # Runs "after_local" scripts of routines config
246
- Rudy::Routines::ScriptHelper.after_local(routine, sconf, lbox)
260
+ Rudy::Routines::ScriptHelper.after_local(routine, sconf, lbox, @option, @argv)
247
261
  end
248
262
  }
249
263
 
@@ -259,7 +273,7 @@ module Rudy
259
273
  return unless depends
260
274
  unless depends.empty?
261
275
  depends.each_with_index do |d, index|
262
- puts task_separator("DEPENDENCY: #{d}")
276
+ task_separator("DEPENDENCY: #{d}")
263
277
  routine_dependency = fetch_routine_config(d)
264
278
  unless routine_dependency
265
279
  STDERR.puts " Unknown routine: #{d}".color(:red)
@@ -302,7 +316,7 @@ module Rudy
302
316
  def task_separator(title)
303
317
  dashes = 59 - title.size
304
318
  dashes = 0 if dashes < 1
305
- ("%s--- %s %s" % [$/, title, '-'*dashes])
319
+ puts ("%s--- %s %s" % [$/, title, '-'*dashes]) if @@global.verbose > 2
306
320
  end
307
321
 
308
322
  def machine_separator(name, awsid)
@@ -323,7 +337,14 @@ module Rudy
323
337
  rescue => ex
324
338
  STDERR.puts " Error: #{ex.message}".color(:red)
325
339
  STDERR.puts ex.backtrace if Rudy.debug?
326
- exit 12 unless keep_going?
340
+ choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
341
+ if choice.match(/\AS/i)
342
+ return
343
+ elsif choice.match(/\AR/i)
344
+ retry
345
+ else
346
+ exit 12
347
+ end
327
348
  rescue Interrupt
328
349
  puts "Aborting..."
329
350
  exit 12
@@ -331,10 +352,6 @@ module Rudy
331
352
  ret
332
353
  end
333
354
 
334
- def keep_going?
335
- Annoy.pose_question(" Keep going?\a ", /yes|y|ya|sure|you bet!/i, STDERR)
336
- end
337
-
338
355
  end
339
356
  end
340
357
  end
@@ -13,14 +13,35 @@ module Rudy
13
13
  print_response(ret)
14
14
  rescue IOError => ex
15
15
  STDERR.puts " Connection Error (#{ex.message})".color(:red)
16
- exit 12 unless keep_going?
16
+ choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
17
+ if choice.match(/\AS/i)
18
+ return
19
+ elsif choice.match(/\AR/i)
20
+ retry
21
+ else
22
+ exit 12
23
+ end
17
24
  rescue Rye::CommandError => ex
18
25
  print_response(ex)
19
- exit 12 unless keep_going?
26
+ choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
27
+ if choice.match(/\AS/i)
28
+ return
29
+ elsif choice.match(/\AR/i)
30
+ retry
31
+ else
32
+ exit 12
33
+ end
20
34
  rescue Rye::CommandNotFound => ex
21
35
  STDERR.puts " CommandNotFound: #{ex.message}".color(:red)
22
36
  STDERR.puts ex.backtrace if Rudy.debug?
23
- exit 12 unless keep_going?
37
+ choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
38
+ if choice.match(/\AS/i)
39
+ return
40
+ elsif choice.match(/\AR/i)
41
+ retry
42
+ else
43
+ exit 12
44
+ end
24
45
  end
25
46
 
26
47
  ret
@@ -31,11 +52,11 @@ module Rudy
31
52
  end
32
53
 
33
54
  # Returns a formatted string for printing command info
34
- def command_separator(cmd, user)
55
+ def command_separator(cmd, user, host)
35
56
  cmd ||= ""
36
57
  cmd, user = cmd.to_s, user.to_s
37
58
  prompt = user == "root" ? "#" : "$"
38
- ("%s%s%s %s" % [$/, user, prompt, cmd.bright])
59
+ ("%s@%s%s %s" % [user, host, prompt, cmd.bright])
39
60
  end
40
61
 
41
62
  private
@@ -13,8 +13,8 @@ module Rudy; module Routines;
13
13
 
14
14
  # TODO: refactor using this_method
15
15
 
16
- def before_local(routine, sconf, rbox)
17
- execute_command(:before_local, routine, sconf, 'localhost', rbox)
16
+ def before_local(routine, sconf, rbox, option=nil, argv=nil)
17
+ execute_command(:before_local, routine, sconf, 'localhost', rbox, option, argv)
18
18
  end
19
19
  def before_local?(routine)
20
20
  # before_local generally doesn't take a user name like the remote
@@ -24,8 +24,8 @@ module Rudy; module Routines;
24
24
  } if routine[:before_local].is_a?(Proc)
25
25
  execute_command?(:before_local, routine)
26
26
  end
27
- def script_local(routine, sconf, rbox)
28
- execute_command(:script_local, routine, sconf, 'localhost', rbox)
27
+ def script_local(routine, sconf, rbox, option=nil, argv=nil)
28
+ execute_command(:script_local, routine, sconf, 'localhost', rbox, option, argv)
29
29
  end
30
30
  def script_local?(routine)
31
31
  # before_local generally doesn't take a user name like the remote
@@ -36,8 +36,8 @@ module Rudy; module Routines;
36
36
  execute_command?(:script_local, routine)
37
37
  end
38
38
 
39
- def after_local(routine, sconf, rbox)
40
- execute_command(:after_local, routine, sconf, 'localhost', rbox)
39
+ def after_local(routine, sconf, rbox, option=nil, argv=nil)
40
+ execute_command(:after_local, routine, sconf, 'localhost', rbox, option, argv)
41
41
  end
42
42
  def after_local?(routine)
43
43
  routine[:after_local] = { # See before_local note
@@ -46,21 +46,21 @@ module Rudy; module Routines;
46
46
  execute_command?(:after_local, routine)
47
47
  end
48
48
 
49
- def before(routine, sconf, machine, rbox)
49
+ def before(routine, sconf, machine, rbox, option=nil, argv=nil)
50
50
  raise "ScriptHelper: Not a Rudy::Machine" unless machine.is_a?(Rudy::Machine)
51
- execute_command(:before, routine, sconf, machine.name, rbox)
51
+ execute_command(:before, routine, sconf, machine.name, rbox, option, argv)
52
52
  end
53
53
  def before?(routine); execute_command?(:before, routine); end
54
54
 
55
- def after(routine, sconf, machine, rbox)
55
+ def after(routine, sconf, machine, rbox, option=nil, argv=nil)
56
56
  raise "ScriptHelper: Not a Rudy::Machine" unless machine.is_a?(Rudy::Machine)
57
- execute_command(:after, routine, sconf, machine.name, rbox)
57
+ execute_command(:after, routine, sconf, machine.name, rbox, option, argv)
58
58
  end
59
59
  def after?(routine); execute_command?(:after, routine); end
60
60
 
61
- def script(routine, sconf, machine, rbox)
61
+ def script(routine, sconf, machine, rbox, option=nil, argv=nil)
62
62
  raise "ScriptHelper: Not a Rudy::Machine" unless machine.is_a?(Rudy::Machine)
63
- execute_command(:script, routine, sconf, machine.name, rbox)
63
+ execute_command(:script, routine, sconf, machine.name, rbox, option, argv)
64
64
  end
65
65
  def script?(routine); execute_command?(:script, routine); end
66
66
 
@@ -76,7 +76,12 @@ module Rudy; module Routines;
76
76
  return false unless hasconf
77
77
  unless routine[timing].kind_of?(Hash)
78
78
  STDERR.puts "No user supplied for #{timing} block".color(:red)
79
- exit 12 unless keep_going?
79
+ choice = Annoy.get_user_input('(S)kip (A)bort: ')
80
+ if choice.match(/\AS/i)
81
+ return
82
+ else
83
+ exit 12
84
+ end
80
85
  return false
81
86
  end
82
87
  routine[timing].each_pair do |user,proc|
@@ -95,13 +100,13 @@ module Rudy; module Routines;
95
100
  # * +sconf+ is a config hash from machines config (ignored if nil)
96
101
  # * +hostname+ machine hostname that we're working on
97
102
  # * +rbox+ a Rye::Box instance for the machine we're working on
98
- def execute_command(timing, routine, sconf, hostname, rbox)
103
+ def execute_command(timing, routine, sconf, hostname, rbox, option=nil, argv=nil)
99
104
  raise "ScriptHelper: Not a Rye::Box" unless rbox.is_a?(Rye::Box)
100
105
  raise "ScriptHelper: #{timing}?" unless @@script_types.member?(timing)
101
106
 
102
107
  # The config file that gets created on each remote machine
103
108
  # will be created in the user's home directory.
104
- script_config_remote_path = File.join(rbox.getenv['HOME'], @@script_config_file_name)
109
+ script_config_remote_path = File.join(rbox.getenv['HOME'] || '', @@script_config_file_name)
105
110
 
106
111
  if sconf && !sconf.empty?
107
112
  tf = Tempfile.new(@@script_config_file_name)
@@ -148,32 +153,52 @@ module Rudy; module Routines;
148
153
  }
149
154
 
150
155
  begin
151
- # We define hooks so we can call the script block as a batch.
152
- # We intentionally set and unset the hooks so the other commands
153
- # (config file copy) don't get printed.
154
- #
155
- # This block gets called for every command method call.
156
- rbox.pre_command_hook do |cmd, args, user|
157
- puts command_separator(rbox.preview_command(cmd, args), user)
156
+ # We define hooks so we can still print each command and its output
157
+ # when running the command blocks. NOTE: We only print this in
158
+ # verbosity mode. We intentionally set and unset the hooks
159
+ # so the other commands (config file copy) don't get printed.
160
+ if @@global.verbose > 0
161
+ # This block gets called for every command method call.
162
+ rbox.pre_command_hook do |cmd, args, user, host|
163
+ puts command_separator(rbox.preview_command(cmd, args), user, host)
164
+ end
158
165
  end
159
- # And this one gets called after each command method call.
160
- rbox.post_command_hook do |ret|
161
- puts ' ' << ret.stdout.join("#{$/} ") if !ret.stdout.empty?
162
- print_response(ret)
166
+ if @@global.verbose > 1
167
+ # And this one gets called after each command method call.
168
+ rbox.post_command_hook do |ret|
169
+ puts ' ' << ret.stdout.join("#{$/} ") if !ret.stdout.empty?
170
+ print_response(ret)
171
+ end
163
172
  end
164
173
 
165
174
  ### EXECUTE THE COMMANDS BLOCK
166
- rbox.batch(&proc)
175
+ rbox.batch(option, argv, &proc)
167
176
 
168
- rbox.pre_command_hook = nil
169
- rbox.post_command_hook = nil
170
177
  rescue Rye::CommandError => ex
171
178
  print_response(ex)
172
- exit 12 unless keep_going?
179
+ choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
180
+ if choice.match(/\AS/i)
181
+ return
182
+ elsif choice.match(/\AR/i)
183
+ retry
184
+ else
185
+ exit 12
186
+ end
173
187
  rescue Rye::CommandNotFound => ex
174
188
  STDERR.puts " CommandNotFound: #{ex.message}".color(:red)
175
189
  STDERR.puts ex.backtrace if Rudy.debug?
176
- exit 12 unless keep_going?
190
+ choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ')
191
+ if choice.match(/\AS/i)
192
+ return
193
+ elsif choice.match(/\AR/i)
194
+ retry
195
+ else
196
+ exit 12
197
+ end
198
+ ensure
199
+ rbox.pre_command_hook = nil
200
+ rbox.post_command_hook = nil
201
+ rbox.enable_safe_mode # In case it was disabled
177
202
  end
178
203
 
179
204
  rbox.cd # reset to home dir