Class: Rudy::Routines::Base

Inherits:
Object
  • Object
show all
Includes:
Huxtable
Defined in:
lib/rudy/routines.rb

Direct Known Subclasses

Passthrough, Reboot, Release, Shutdown, Startup

Instance Method Summary collapse

Methods included from Huxtable

change_environment, change_position, change_region, change_role, change_zone, #check_keys, #config_dirname, create_domain, #current_group_name, #current_machine_address, #current_machine_count, #current_machine_group, #current_machine_hostname, #current_machine_image, #current_machine_name, #current_machine_size, #current_user, #current_user_keypairpath, debug?, #debug?, domain, domain_exists?, #group_metadata, #has_keypair?, #has_keys?, #has_pem_keys?, #has_root_keypair?, keypair_path_to_name, #known_machine_group?, #root_keypairname, #root_keypairpath, #switch_user, update_config, update_global, update_logger, #user_keypairname, #user_keypairpath

Constructor Details

#initialize(*args) ⇒ Base

Returns a new instance of Base.



12
13
14
15
16
17
18
19
20
21
# File 'lib/rudy/routines.rb', line 12

def initialize(*args)
  a, s, r = @@global.accesskey, @@global.secretkey, @@global.region
  @sdb = Rudy::AWS::SDB.new(a, s, r)
  @rinst = Rudy::AWS::EC2::Instances.new(a, s, r)
  @rgrp = Rudy::AWS::EC2::Groups.new(a, s, r)
  @rkey = Rudy::AWS::EC2::KeyPairs.new(a, s, r)
  @rvol = Rudy::AWS::EC2::Volumes.new(a, s, r)
  @rsnap = Rudy::AWS::EC2::Snapshots.new(a, s, r)
  init(*args)
end

Instance Method Details

#enjoy_every_sandwich(&bloc_party) ⇒ Object



297
298
299
300
301
302
303
304
305
# File 'lib/rudy/routines.rb', line 297

def enjoy_every_sandwich(&bloc_party)
  begin
    bloc_party.call
  rescue => ex
    STDERR.puts "  Error: #{ex.message}".color(:red)
    STDERR.puts ex.backtrace if Rudy.debug?
    exit 12 unless keep_going?
  end
end

#executeObject



26
27
28
# File 'lib/rudy/routines.rb', line 26

def execute
  raise "Override execute method"
end

#execute_dependency(depends, skip_check, skip_header) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rudy/routines.rb', line 235

def execute_dependency(depends, skip_check, skip_header)
  return unless depends
  unless depends.empty?
    depends.each_with_index do |d, index|
      puts task_separator("DEPENDENCY: #{d}")  
      routine_dependency = fetch_routine_config(d)
      unless routine_dependency
        STDERR.puts "  Unknown routine: #{d}".color(:red)
        next
      end
      # NOTE: running routines here means they do not have their own
      # payload and they must use the list action. I think this is ok
      # though b/c there should only be a few routines with payloads
      # (startup, shutdown, reboot)
      generic_machine_runner(:list, routine_dependency, skip_check, skip_header)
    end
  end
end

#generic_machine_runner(machine_action, routine = nil, skip_check = false, skip_header = false, &routine_action) ⇒ Object

  • machine_action a method on Rudy::Machines, one of: create, destroy, list

  • routine Override routine with another routine (default: nil)

  • skip_check Don’t check that the machine is up and SSH is available (default: false)

  • skip_header Don’t print machine header (default: false)

  • routine_action is an optional block which will be executed for each machine between the disk routine and after blocks. The block receives two argument: an instance of Rudy::Machine and one of Rye::Box.



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
160
161
162
163
164
165
166
167
168
169
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/rudy/routines.rb', line 41

def generic_machine_runner(machine_action, routine=nil, skip_check=false, skip_header=false, &routine_action)
  if @@global.offline
    rmach = Rudy::Machines::Offline.new
    skip_check = true
    remote_user = Rudy.sysinfo.user
  else
    rmach = Rudy::Machines.new
    remote_user = 'root'
  end
  
  routine ||= @routine
  raise "No routine supplied" unless routine
  raise "No machine action supplied" unless machine_action
  unless rmach.respond_to?(machine_action)
    raise "Unknown machine action #{machine_action}" 
  end
  
  # Declare a couple vars so they're available outide the block
  before_dependencies = after_dependencies = nil  
  enjoy_every_sandwich {
    # This gets and removes the dependencies from the routines hash. 
    if Rudy::Routines::DependsHelper.has_depends?(:before, routine)
      before_dependencies = Rudy::Routines::DependsHelper.get(:before, routine)
    end
    
    # We grab the after ones now too, so we don't fool the ScriptHelper 
    # later on in this routine (after keyword is used for scripts too)
    if Rudy::Routines::DependsHelper.has_depends?(:after, routine)
      after_dependencies = Rudy::Routines::DependsHelper.get(:after, routine)
    end
    
    # This calls generic_machine_runner for every dependent before routine. 
    execute_dependency(before_dependencies, skip_check, skip_header)
  }
  
  lbox = Rye::Box.new( @@global.localhost )
  sconf = fetch_script_config
  
  enjoy_every_sandwich {
    if Rudy::Routines::ScriptHelper.before_local?(routine)  # before_local
      # Runs "before_local" scripts of routines config. 
      puts task_separator("LOCAL SHELL")
      Rudy::Routines::ScriptHelper.before_local(routine, sconf, lbox)
    end
  }
  
  enjoy_every_sandwich {
    if Rudy::Routines::ScriptHelper.script_local?(routine)  # script_local
      # Runs "script_local" scripts of routines config. 
      # NOTE: This is synonymous with before_local
      puts task_separator("LOCAL SHELL")
      Rudy::Routines::ScriptHelper.script_local(routine, sconf, lbox)
    end
  }
  
  # Execute the action (create, list, destroy, restart) & apply the block to each
  machines = []
  rmach.send(machine_action) do |machine|
    machines << machine
    
    puts machine_separator(machine.name, machine.awsid) unless skip_header
    
    unless skip_check
      msg = preliminary_separator("Checking if instance is running...")
      Rudy::Utils.waiter(3, 120, STDOUT, msg, 0) {
        inst = machine.get_instance
        inst && inst.running?
      } 
    
      # Add instance info to machine and save it. This is really important
      # for the initial startup so the metadata is updated right away. But
      # it's also important to call here because if a routine was executed
      # and an unexpected exception occurs before this update is executed
      # the machine metadata won't contain the DNS information. Calling it
      # here ensure that the metadata is always up-to-date. 
      machine.update 
    
      msg = preliminary_separator("Waiting for SSH daemon...")
      Rudy::Utils.waiter(2, 60, STDOUT, msg, 0) {
        Rudy::Utils.service_available?(machine.dns_public, 22)
      }
    end
    
    # TODO: trap rbox errors. We could get an authentication error. 
    opts = { :keys =>  root_keypairpath, :user => remote_user, :info => @@global.verbose > 0 }
    begin
      rbox = Rye::Box.new(machine.dns_public, opts)
      rbox.connect
    rescue Rye::NoHost => ex
      STDERR.puts "No host: #{ex.message}"
      exit 65
    end
    
    unless skip_check
      # Set the hostname if specified in the machines config. 
      # :rudy -> change to Rudy's machine name
      # :default -> leave the hostname as it is
      # Anything else other than nil -> change to that value
      # NOTE: This will set hostname every time a routine is
      # run so we may want to make this an explicit action. 
      enjoy_every_sandwich {
        hn = current_machine_hostname || :rudy
        if hn != :default
          hn = machine.name if hn == :rudy
          print preliminary_separator("Setting hostame to #{hn}... ")
          rbox.hostname(hn) 
          puts "done"
        end
      }
    end
    
    unless has_remote_task?(routine)
      puts "[no remote tasks]"
      next
    end
    
    enjoy_every_sandwich {
      if Rudy::Routines::UserHelper.adduser?(routine)       # adduser
        puts task_separator("ADD USER")
        Rudy::Routines::UserHelper.adduser(routine, machine, rbox)
      end
    }
    
    enjoy_every_sandwich {
      if Rudy::Routines::UserHelper.authorize?(routine)     # authorize
        puts task_separator("AUTHORIZE USER")
        Rudy::Routines::UserHelper.authorize(routine, machine, rbox)
      end
    }
    
    enjoy_every_sandwich {
      if Rudy::Routines::ScriptHelper.before?(routine)      # before
        puts task_separator("REMOTE SHELL")
        Rudy::Routines::ScriptHelper.before(routine, sconf, machine, rbox)
      end
    }
    
    enjoy_every_sandwich {
      if Rudy::Routines::DiskHelper.disks?(routine)         # disk
        puts task_separator("DISKS")
        if rbox.ostype == "sunos"
          puts "Sorry, Solaris disks are not supported yet!"
        else
          Rudy::Routines::DiskHelper.execute(routine, machine, rbox)
        end    
      end
    }
    
    enjoy_every_sandwich {
      # Startup, shutdown, release, deploy, etc...
      routine_action.call(machine, rbox) if routine_action
    }
    
    # The "after" blocks are synonymous with "script" blocks. 
    # For some routines, like startup, it makes sense to an 
    # "after" block b/c "script" is ambiguous. In generic
    # routines, there is no concept of before or after. The
    # definition is the entire routine so we use "script".
    # NOTE: If both after and script are supplied they will 
    # both be executed. 
    enjoy_every_sandwich {
      if Rudy::Routines::ScriptHelper.script?(routine)      # script
        puts task_separator("REMOTE SHELL")
        # Runs "after" scripts of routines config
        Rudy::Routines::ScriptHelper.script(routine, sconf, machine, rbox)
      end
    }
    
    enjoy_every_sandwich {
      if Rudy::Routines::ScriptHelper.after?(routine)       # after
        puts task_separator("REMOTE SHELL")
        # Runs "after" scripts of routines config
        Rudy::Routines::ScriptHelper.after(routine, sconf, machine, rbox)
      end
    }
    
    rbox.disconnect
  end
  
  enjoy_every_sandwich {
    if Rudy::Routines::ScriptHelper.after_local?(routine)   # after_local
      puts task_separator("LOCAL SHELL")
      # Runs "after_local" scripts of routines config
      Rudy::Routines::ScriptHelper.after_local(routine, sconf, lbox)
    end
  }
  
  # This calls generic_machine_runner for every dependent after routine 
  enjoy_every_sandwich {
    execute_dependency(after_dependencies, skip_check, skip_header)
  }
  
end

#has_remote_task?(routine) ⇒ Boolean

Does the given routine define any remote tasks?

Returns:

  • (Boolean)


256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/rudy/routines.rb', line 256

def has_remote_task?(routine)
  any = [Rudy::Routines::DiskHelper.disks?(routine),
         Rudy::Routines::ScriptHelper.before?(routine),
         Rudy::Routines::ScriptHelper.after?(routine),
         Rudy::Routines::ScriptHelper.script?(routine),
         Rudy::Routines::UserHelper.authorize?(routine),
         Rudy::Routines::UserHelper.adduser?(routine), 
         !@after_dependencies.nil?,
         !@before_dependencies.nil?]
  # Throw away all false answers (and nil answers)
  any = any.compact.select { |success| success }
  !any.empty?   # Returns true if any element contains true
end

#initObject



23
24
# File 'lib/rudy/routines.rb', line 23

def init
end

#keep_going?Boolean

Returns:

  • (Boolean)


307
308
309
# File 'lib/rudy/routines.rb', line 307

def keep_going?
  Annoy.pose_question("  Keep going?\a ", /yes|y|ya|sure|you bet!/i, STDERR)
end

#machine_separator(name, awsid) ⇒ Object



285
286
287
# File 'lib/rudy/routines.rb', line 285

def machine_separator(name, awsid)
  ('%s %-63s awsid: %s ' % [$/, name, awsid]).att(:reverse)
end

#preliminary_separator(msg) ⇒ Object



270
271
272
273
274
275
276
277
# File 'lib/rudy/routines.rb', line 270

def preliminary_separator(msg)
  # TODO: Count number messages printed 1/3. ie:
  # m-us-east-1b-stage-app-01                   
  #   (1/3) Checking if instance is running... done
  #   (2/3) Waiting for SSH daemon... done
  #   (3/3) Setting hostame to m-us-east-1b-stage-app-01... done
  ("  -> #{msg}")
end

#raise_early_exceptionsObject



30
31
32
# File 'lib/rudy/routines.rb', line 30

def raise_early_exceptions
  raise "Must override raise_early_exceptions"
end

#routine_separator(name) ⇒ Object



289
290
291
292
293
294
295
# File 'lib/rudy/routines.rb', line 289

def routine_separator(name)
  # Not used (for now)
  name = name.to_s
  dashes = 59 - name.size # 
  dashes = 0 if dashes < 1
  #puts '%-40s' % [name.bright]
end

#task_separator(title) ⇒ Object



279
280
281
282
283
# File 'lib/rudy/routines.rb', line 279

def task_separator(title)
  dashes = 59 - title.size 
  dashes = 0 if dashes < 1
  ("%s---  %s  %s" % [$/, title, '-'*dashes])
end