Module: OpsWalrus::HostDSL
- Included in:
- Host
- Defined in:
- lib/opswalrus/host.rb
Instance Method Summary collapse
- #autoretry(delay: 5, timeout: 300, limit: 3, &block) ⇒ Object
- #debug(msg) ⇒ Object
- #desc(msg) ⇒ Object
- #env(*args, **kwargs) ⇒ Object
- #host_prop(name) ⇒ Object
- #params(*args, **kwargs) ⇒ Object
- #parse_stdout_and_script_return_value(command_output) ⇒ Object
-
#reboot(delay: 1, sync: true, timeout: 300) ⇒ Object
delay: integer? # default: 1 - 1 second delay before reboot sync: boolean? # default: true - wait for the remote host to become available again before returning success/failure timeout: integer? # default: 300 - 300 seconds (5 minutes).
-
#reconnect(delay = 1, timeout = 300) ⇒ Object
returns an integer number of seconds if reconnected; nil otherwise.
-
#run_ops(ops_command, ops_command_options = nil, command_arguments, in_bundle_root_dir: true, ops_prompt_for_sudo_password: false) ⇒ Object
runs the specified ops command with the specified command arguments returns [stdout, stderr, exit_status].
-
#sh(desc_or_cmd = nil, cmd = nil, input: nil, &block) ⇒ Object
runs the given command returns the stdout from the command.
-
#sh?(desc_or_cmd = nil, cmd = nil, input: nil, &block) ⇒ Boolean
runs the given command returns true if the exit status was success; false otherwise.
-
#shell(desc_or_cmd = nil, cmd = nil, input: nil, &block) ⇒ Object
returns the tuple: [stdout, stderr, exit_status].
-
#shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil, ops_prompt_for_sudo_password: false) ⇒ Object
returns the tuple: [stdout, stderr, exit_status].
- #ssh_session ⇒ Object
- #warn(msg) ⇒ Object
Instance Method Details
#autoretry(delay: 5, timeout: 300, limit: 3, &block) ⇒ Object
163 164 165 166 167 168 169 170 171 172 |
# File 'lib/opswalrus/host.rb', line 163 def autoretry(delay: 5, timeout: 300, limit: 3, &block) attempts ||= 0 attempts += 1 block.call rescue RetriableRemoteInvocationError => e if attempts <= limit reconnected = reconnect(delay, timeout) retry if reconnected end end |
#debug(msg) ⇒ Object
382 383 384 |
# File 'lib/opswalrus/host.rb', line 382 def debug(msg) puts msg.mustache(2) if App.instance.debug? || App.instance.trace? # we use two here, because one stack frame accounts for the call from the ops script into HostProxy#desc end |
#desc(msg) ⇒ Object
374 375 376 |
# File 'lib/opswalrus/host.rb', line 374 def desc(msg) puts Style.green(msg.mustache(2)) # we use two here, because one stack frame accounts for the call from the ops script into HostProxy#desc end |
#env(*args, **kwargs) ⇒ Object
386 387 388 |
# File 'lib/opswalrus/host.rb', line 386 def env(*args, **kwargs) @ops_file_script.env(*args, **kwargs) end |
#host_prop(name) ⇒ Object
394 395 396 |
# File 'lib/opswalrus/host.rb', line 394 def host_prop(name) @props[name] || @default_props[name] end |
#params(*args, **kwargs) ⇒ Object
390 391 392 |
# File 'lib/opswalrus/host.rb', line 390 def params(*args, **kwargs) @ops_file_script.params(*args, **kwargs) end |
#parse_stdout_and_script_return_value(command_output) ⇒ Object
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/opswalrus/host.rb', line 330 def parse_stdout_and_script_return_value(command_output) output_sections = command_output.split(/#{::OpsWalrus::App::SCRIPT_RESULT_HEADER}/) case output_sections.count when 1 stdout, ops_script_retval = output_sections.first, nil # puts "found it1!: #{output_sections.inspect}" when 2 stdout, ops_script_retval = *output_sections # puts "found it2!: #{ops_script_retval}" else # this is unexpected ops_script_retval = output_sections.pop stdout = output_sections.join(::OpsWalrus::App::SCRIPT_RESULT_HEADER) # puts "found it3!: #{ops_script_retval}" end [stdout, ops_script_retval] end |
#reboot(delay: 1, sync: true, timeout: 300) ⇒ Object
delay: integer? # default: 1 - 1 second delay before reboot sync: boolean? # default: true - wait for the remote host to become available again before returning success/failure timeout: integer? # default: 300 - 300 seconds (5 minutes)
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/opswalrus/host.rb', line 145 def reboot(delay: 1, sync: true, timeout: 300) delay = 1 if delay < 1 desc "Rebooting #{to_s} (alias=#{self.alias})" reboot_success = sh? 'sudo /bin/sh -c "(sleep {{ delay }} && reboot) &"'.mustache puts reboot_success reconnect_time = reconnect(delay, timeout) if sync reconnect_success = !!reconnect_time { success: reboot_success && (sync == reconnect_success), rebooted: reboot_success, reconnected: reconnect_success, reboot_duration: reconnect_time } end |
#reconnect(delay = 1, timeout = 300) ⇒ Object
returns an integer number of seconds if reconnected; nil otherwise
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 |
# File 'lib/opswalrus/host.rb', line 175 def reconnect(delay = 1, timeout = 300) delay = 1 if delay < 1 desc "Waiting for #{to_s} (alias=#{self.alias}) to become available. Reconnecting." initial_reconnect_delay = delay + 10 sleep initial_reconnect_delay reconnected = false give_up = false t1 = Time.now until reconnected || give_up begin reconnected = sh?('true') # while trying to reconnect, we expect the following exceptions: # 1. Net::SSH::Disconnect < Net::SSH::Exception with message: "connection closed by remote host" # 2. Errno::ECONNRESET < SystemCallError with message: "Connection reset by peer" # 3. Errno::ECONNREFUSED < SystemCallError with message: "Connection refused - connect(2) for 192.168.56.10:22" rescue Net::SSH::Disconnect, Net::SSH::ConnectionTimeout, Errno::ECONNRESET, Errno::ECONNREFUSED => e # noop; we expect these while we're trying to reconnect rescue => e puts "#{e.class} < #{e.class.superclass}" puts e. puts e.backtrace.take(5).join("\n") end wait_time_elapsed_in_seconds = Time.now - t1 give_up = wait_time_elapsed_in_seconds > timeout sleep 5 end if reconnected initial_reconnect_delay + (Time.now - t1) # initialize session again _initialize_session end end |
#run_ops(ops_command, ops_command_options = nil, command_arguments, in_bundle_root_dir: true, ops_prompt_for_sudo_password: false) ⇒ Object
runs the specified ops command with the specified command arguments returns [stdout, stderr, exit_status]
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/opswalrus/host.rb', line 350 def run_ops(ops_command, = nil, command_arguments, in_bundle_root_dir: true, ops_prompt_for_sudo_password: false) local_hostname_for_remote_host = if self.alias "#{host} (#{self.alias})" else host end # cmd = "OPS_GEM=\"#{OPS_GEM}\" OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}'; $OPS_GEM exec --conservative -g opswalrus ops" cmd = "OPSWALRUS_LOCAL_HOSTNAME='#{local_hostname_for_remote_host}' eval #{OPS_CMD}" if App.instance.trace? cmd << " --loudest" elsif App.instance.debug? cmd << " --louder" elsif App.instance.info? cmd << " --loud" end cmd << " #{ops_command.to_s}" cmd << " #{.to_s}" if cmd << " #{@tmp_bundle_root_dir}" if in_bundle_root_dir cmd << " #{command_arguments}" unless command_arguments.empty? shell!(cmd, ops_prompt_for_sudo_password: ops_prompt_for_sudo_password) end |
#sh(desc_or_cmd = nil, cmd = nil, input: nil, &block) ⇒ Object
runs the given command returns the stdout from the command
215 216 217 218 |
# File 'lib/opswalrus/host.rb', line 215 def sh(desc_or_cmd = nil, cmd = nil, input: nil, &block) out, err, status = *shell!(desc_or_cmd, cmd, block, input: input) out end |
#sh?(desc_or_cmd = nil, cmd = nil, input: nil, &block) ⇒ Boolean
runs the given command returns true if the exit status was success; false otherwise
222 223 224 225 |
# File 'lib/opswalrus/host.rb', line 222 def sh?(desc_or_cmd = nil, cmd = nil, input: nil, &block) out, err, status = *shell!(desc_or_cmd, cmd, block, input: input) status == 0 end |
#shell(desc_or_cmd = nil, cmd = nil, input: nil, &block) ⇒ Object
returns the tuple: [stdout, stderr, exit_status]
228 229 230 |
# File 'lib/opswalrus/host.rb', line 228 def shell(desc_or_cmd = nil, cmd = nil, input: nil, &block) shell!(desc_or_cmd, cmd, block, input: input) end |
#shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil, ops_prompt_for_sudo_password: false) ⇒ Object
returns the tuple: [stdout, stderr, exit_status]
233 234 235 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 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/opswalrus/host.rb', line 233 def shell!(desc_or_cmd = nil, cmd = nil, block = nil, input: nil, ops_prompt_for_sudo_password: false) # description = nil return ["", "", 0] if !desc_or_cmd && !cmd && !block # we were told to do nothing; like hitting enter at the bash prompt; we can do nothing successfully description = desc_or_cmd if cmd || block description = WalrusLang.render(description, block.binding) if description && block cmd = block.call if block cmd ||= desc_or_cmd cmd = if cmd =~ /{{.*}}/ if block WalrusLang.render(cmd, block.binding) else offset = 3 # 3, because 1 references the stack frame corresponding to the caller of WalrusLang.eval, # 2 references the stack frame corresponding to the caller of shell!, # and 3 references the stack frame corresponding to the caller of either sh/sh?/shell WalrusLang.eval(cmd, offset) end else cmd end # cmd = WalrusLang.render(cmd, block.binding) if block && cmd =~ /{{.*}}/ #cmd = Shellwords.escape(cmd) cmd_id = Random.uuid.split('-').first output_block = StringIO.open do |io| if App.instance.info? # this is true if log_level is trace, debug, info io.print Style.blue(host) io.print " (#{Style.blue(self.alias)})" if self.alias io.print " | #{Style.green(description)}" if description io.puts io.print Style.yellow(cmd_id) io.print Style.green.bold(" > ") io.puts Style.yellow(cmd) elsif App.instance.warn? && description io.print Style.blue(host) io.print " (#{Style.blue(self.alias)})" if self.alias io.print " | #{Style.green(description)}" if description io.puts end io.string end puts output_block unless output_block.empty? return unless cmd && !cmd.strip.empty? t1 = Time.now output, stderr, exit_status = if App.instance.dry_run? ["", "", 0] else sshkit_cmd = execute_cmd(cmd, input_mapping: input, ops_prompt_for_sudo_password: ops_prompt_for_sudo_password) [sshkit_cmd.full_stdout, sshkit_cmd.full_stderr, sshkit_cmd.exit_status] end t2 = Time.now seconds = t2 - t1 stdout, remote_ops_script_retval = parse_stdout_and_script_return_value(output) output_block = StringIO.open do |io| if App.instance.info? # this is true if log_level is trace, debug, info if App.instance.trace? io.puts Style.cyan(stdout) io.puts Style.red(stderr) elsif App.instance.debug? io.puts Style.cyan(stdout) io.puts Style.red(stderr) elsif App.instance.info? io.puts Style.cyan(stdout) io.puts Style.red(stderr) end io.print Style.yellow(cmd_id) io.print Style.blue(" | Finished in #{seconds} seconds with exit status ") if exit_status == 0 io.puts Style.green("#{exit_status} (success)") else io.puts Style.red("#{exit_status} (failure)") end io.puts Style.green("*" * 80) elsif App.instance.warn? && description io.print Style.blue("Finished in #{seconds} seconds with exit status ") if exit_status == 0 io.puts Style.green("#{exit_status} (success)") else io.puts Style.red("#{exit_status} (failure)") end io.puts Style.green("*" * 80) end io.string end puts output_block unless output_block.empty? out = remote_ops_script_retval || stdout [out, stderr, exit_status] end |
#ssh_session ⇒ Object
398 399 400 |
# File 'lib/opswalrus/host.rb', line 398 def ssh_session @sshkit_backend end |
#warn(msg) ⇒ Object
378 379 380 |
# File 'lib/opswalrus/host.rb', line 378 def warn(msg) puts Style.yellow(msg.mustache(2)) # we use two here, because one stack frame accounts for the call from the ops script into HostProxy#desc end |