lib/beaker/host/unix/exec.rb
def reboot(wait_time=10, max_connection_tries=9, uptime_retries=18)
    require 'time'

    attempts = 0

    # Some systems don't support 'last -F reboot' but it has second granularity
    boot_time_cmd = 'last -F reboot || who -b'

    # Try to match all of the common formats for 'last' and 'who'
    current_year = Time.now.strftime("%Y")
    boot_time_regex = Regexp.new(%{((?:#{(Date::ABBR_DAYNAMES + Date::ABBR_MONTHNAMES).compact.join('|')}|#{current_year}).+?(\\d+:\\d+)+?(?::(\\d+).+?#{current_year})?)})

    original_boot_time_str = nil
    original_boot_time_line = nil
    begin
      attempts += 1
      # Number of seconds to sleep before rebooting.
      reboot_sleep = 1

      original_boot_time_str = exec(Beaker::Command.new(boot_time_cmd), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
      original_boot_time_line = original_boot_time_str.lines.grep(/boot/).first

      raise Beaker::Host::RebootWarning, "Could not find system boot time using '#{boot_time_cmd}': '#{original_boot_time_str}'" unless original_boot_time_line

      original_boot_time_matches = original_boot_time_line.scan(boot_time_regex).last

      raise Beaker::Host::RebootWarning, "Found no valid times in '#{original_boot_time_line}'" unless original_boot_time_matches

      original_boot_time = Time.parse(original_boot_time_matches.first)

      unless original_boot_time_matches.last
        reboot_sleep = (61 - Time.now.strftime("%S").to_i)
      end

      @logger.notify("Sleeping #{reboot_sleep} seconds before rebooting")

      sleep(reboot_sleep)

      exec(Beaker::Command.new('/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now'), :expect_connection_failure => true)
    rescue ArgumentError => e
      raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
    rescue Beaker::Host::RebootWarning => e
      raise if attempts > uptime_retries
      @logger.warn(e.message)
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      retry
    rescue StandardError => e
      raise if attempts > uptime_retries
      @logger.warn("Unexpected Exception: #{e.message}")
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      @logger.warn(e.backtrace[0,3].join("\n"))
      @logger.debug(e.backtrace.join("\n"))
      retry
    end

    attempts = 0
    begin
      attempts += 1

      # give the host a little time to shutdown
      @logger.debug("Waiting #{wait_time} for host to shut down.")
      sleep wait_time

      # Accept all exit codes because this may fail due to the parallel nature of systemd
      current_boot_time_str = exec(Beaker::Command.new(boot_time_cmd), {:max_connection_tries => max_connection_tries, :silent => true, :accept_all_exit_codes => true}).stdout
      current_boot_time_line = current_boot_time_str.lines.grep(/boot/).first

      raise Beaker::Host::RebootWarning, "Could not find system boot time using '#{boot_time_cmd}': '#{current_boot_time_str}'" unless current_boot_time_line

      current_boot_time_matches = current_boot_time_line.scan(boot_time_regex).last

      raise Beaker::Host::RebootWarning, "Found no valid times in '#{current_boot_time_line}'" unless current_boot_time_matches

      current_boot_time = Time.parse(current_boot_time_matches.first)

      @logger.debug("Original Boot Time: #{original_boot_time}")
      @logger.debug("Current Boot Time: #{current_boot_time}")

      # If this is *exactly* the same then there is really no good way to detect a reboot
      if current_boot_time == original_boot_time
        raise Beaker::Host::RebootFailure, "Boot time did not reset. Reboot appears to have failed."
      end
    rescue ArgumentError => e
      raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
    rescue Beaker::Host::RebootFailure => e
      raise
    rescue Beaker::Host::RebootWarning => e
      raise if attempts > uptime_retries
      @logger.warn(e.message)
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      retry
    rescue StandardError => e
      raise if attempts > uptime_retries
      @logger.warn("Unexpected Exception: #{e.message}")
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      @logger.warn(e.backtrace[0,3].join("\n"))
      @logger.debug(e.backtrace.join("\n"))
      retry
    end
  end
# Reboots the host, comparing uptime values to verify success
# @param [Integer] wait_time How long to wait after sending the reboot
#                            command before attempting to check in on the host
# @param [Integer] max_connection_tries How many times to retry connecting to
#                            host after reboot. Note that there is an fibbonacci
#                            backoff when attempting retries so the time spent
#                            waiting on this can grow quickly.
# @param [Integer] uptime_retries How many times to check to see if the value of the uptime has reset.
#
# Will throw an exception RebootFailure if it fails
Reboots the host, comparing uptime values to verify success
Reboots the host comparing uptime values to verify success
def reboot(wait_time=10, max_connection_tries=9, uptime_retries=18)
    require 'time'
    attempts = 0
    boot_time_cmd = 'last -F reboot || who -b'
    current_year = Time.now.strftime("%Y")
    boot_time_regex = Regexp.new(%{((?:#{(Date::ABBR_DAYNAMES + Date::ABBR_MONTHNAMES).compact.join('|')}|#{current_year}).+?(\\d+:\\d+)+?(?::(\\d+).+?#{current_year})?)})
    original_boot_time_str = nil
    original_boot_time_line = nil
    begin
      attempts += 1
      reboot_sleep = 1
      original_boot_time_str = exec(Beaker::Command.new(boot_time_cmd), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
      original_boot_time_line = original_boot_time_str.lines.grep(/boot/).first
      raise Beaker::Host::RebootWarning, "Could not find system boot time using '#{boot_time_cmd}': '#{original_boot_time_str}'" unless original_boot_time_line
      original_boot_time_matches = original_boot_time_line.scan(boot_time_regex).last
      raise Beaker::Host::RebootWarning, "Found no valid times in '#{original_boot_time_line}'" unless original_boot_time_matches
      original_boot_time = Time.parse(original_boot_time_matches.first)
      unless original_boot_time_matches.last
        reboot_sleep = (61 - Time.now.strftime("%S").to_i)
      end
      @logger.notify("Sleeping #{reboot_sleep} seconds before rebooting")
      sleep(reboot_sleep)
      exec(Beaker::Command.new('/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now'), :expect_connection_failure => true)
    rescue ArgumentError => e
      raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
    rescue Beaker::Host::RebootWarning => e
      raise if attempts > uptime_retries
      @logger.warn(e.message)
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      retry
    rescue StandardError => e
      raise if attempts > uptime_retries
      @logger.warn("Unexpected Exception: #{e.message}")
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      @logger.warn(e.backtrace[0,3].join("\n"))
      @logger.debug(e.backtrace.join("\n"))
      retry
    end
    attempts = 0
    begin
      attempts += 1
      @logger.debug("Waiting #{wait_time} for host to shut down.")
      sleep wait_time
      current_boot_time_str = exec(Beaker::Command.new(boot_time_cmd), {:max_connection_tries => max_connection_tries, :silent => true, :accept_all_exit_codes => true}).stdout
      current_boot_time_line = current_boot_time_str.lines.grep(/boot/).first
      raise Beaker::Host::RebootWarning, "Could not find system boot time using '#{boot_time_cmd}': '#{current_boot_time_str}'" unless current_boot_time_line
      current_boot_time_matches = current_boot_time_line.scan(boot_time_regex).last
      raise Beaker::Host::RebootWarning, "Found no valid times in '#{current_boot_time_line}'" unless current_boot_time_matches
      current_boot_time = Time.parse(current_boot_time_matches.first)
      @logger.debug("Original Boot Time: #{original_boot_time}")
      @logger.debug("Current Boot Time: #{current_boot_time}")
      if current_boot_time == original_boot_time
        raise Beaker::Host::RebootFailure, "Boot time did not reset. Reboot appears to have failed."
      end
    rescue ArgumentError => e
      raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
    rescue Beaker::Host::RebootFailure => e
      raise
    rescue Beaker::Host::RebootWarning => e
      raise if attempts > uptime_retries
      @logger.warn(e.message)
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      retry
    rescue StandardError => e
      raise if attempts > uptime_retries
      @logger.warn("Unexpected Exception: #{e.message}")
      @logger.warn("Retrying #{uptime_retries - attempts} more times.")
      @logger.warn(e.backtrace[0,3].join("\n"))
      @logger.debug(e.backtrace.join("\n"))
      retry
    end
  end
def reboot ( wait_time = 10 , max_connection_tries = 9 , uptime_retries = 18 ) require 'time' attempts = 0 boot_time_cmd = 'last -F reboot || who -b' current_year = Time . now . strftime ( "%Y" ) boot_time_regex = Regexp . new ( %{((?:#{(Date::ABBR_DAYNAMES + Date::ABBR_MONTHNAMES).compact.join('|')}|#{current_year}).+?(\\d+:\\d+)+?(?::(\\d+).+?#{current_year})?)} ) original_boot_time_str = nil original_boot_time_line = nil begin attempts += 1 reboot_sleep = 1 original_boot_time_str = exec ( Beaker :: Command . new ( boot_time_cmd ) , { :max_connection_tries => max_connection_tries , :silent => true } ) . stdout original_boot_time_line = original_boot_time_str . lines . grep ( / boot / ) . first raise Beaker :: Host :: RebootWarning , "Could not find system boot time using '#{boot_time_cmd}': '#{original_boot_time_str}'" unless original_boot_time_line original_boot_time_matches = original_boot_time_line . scan ( boot_time_regex ) . last raise Beaker :: Host :: RebootWarning , "Found no valid times in '#{original_boot_time_line}'" unless original_boot_time_matches original_boot_time = Time . parse ( original_boot_time_matches . first ) unless original_boot_time_matches . last reboot_sleep = ( 61 - Time . now . strftime ( "%S" ) . to_i ) end @logger . notify ( "Sleeping #{reboot_sleep} seconds before rebooting" ) sleep ( reboot_sleep ) exec ( Beaker :: Command . new ( '/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now' ) , :expect_connection_failure => true ) rescue ArgumentError => e raise Beaker :: Host :: RebootFailure , "Unable to parse time: #{e.message}" rescue Beaker :: Host :: RebootWarning => e raise if attempts > uptime_retries @logger . warn ( e . message ) @logger . warn ( "Retrying #{uptime_retries - attempts} more times." ) retry rescue StandardError => e raise if attempts > uptime_retries @logger . warn ( "Unexpected Exception: #{e.message}" ) @logger . warn ( "Retrying #{uptime_retries - attempts} more times." ) @logger . warn ( e . backtrace [ 0 , 3 ] . join ( "\n" ) ) @logger . debug ( e . backtrace . join ( "\n" ) ) retry end attempts = 0 begin attempts += 1 @logger . debug ( "Waiting #{wait_time} for host to shut down." ) sleep wait_time current_boot_time_str = exec ( Beaker :: Command . new ( boot_time_cmd ) , { :max_connection_tries => max_connection_tries , :silent => true , :accept_all_exit_codes => true } ) . stdout current_boot_time_line = current_boot_time_str . lines . grep ( / boot / ) . first raise Beaker :: Host :: RebootWarning , "Could not find system boot time using '#{boot_time_cmd}': '#{current_boot_time_str}'" unless current_boot_time_line current_boot_time_matches = current_boot_time_line . scan ( boot_time_regex ) . last raise Beaker :: Host :: RebootWarning , "Found no valid times in '#{current_boot_time_line}'" unless current_boot_time_matches current_boot_time = Time . parse ( current_boot_time_matches . first ) @logger . debug ( "Original Boot Time: #{original_boot_time}" ) @logger . debug ( "Current Boot Time: #{current_boot_time}" ) if current_boot_time == original_boot_time raise Beaker :: Host :: RebootFailure , "Boot time did not reset. Reboot appears to have failed." end rescue ArgumentError => e raise Beaker :: Host :: RebootFailure , "Unable to parse time: #{e.message}" rescue Beaker :: Host :: RebootFailure => e raise rescue Beaker :: Host :: RebootWarning => e raise if attempts > uptime_retries @logger . warn ( e . message ) @logger . warn ( "Retrying #{uptime_retries - attempts} more times." ) retry rescue StandardError => e raise if attempts > uptime_retries @logger . warn ( "Unexpected Exception: #{e.message}" ) @logger . warn ( "Retrying #{uptime_retries - attempts} more times." ) @logger . warn ( e . backtrace [ 0 , 3 ] . join ( "\n" ) ) @logger . debug ( e . backtrace . join ( "\n" ) ) retry end end
Reboots the host, comparing uptime values to verify success
Reboots the host comparing uptime values to verify success
# Some systems don't support 'last -F reboot' but it has second granularity # Try to match all of the common formats for 'last' and 'who' # Number of seconds to sleep before rebooting. # give the host a little time to shutdown # Accept all exit codes because this may fail due to the parallel nature of systemd # If this is *exactly* the same then there is really no good way to detect a reboot
wait_time
max_connection_tries
uptime_retries
uptime_retries How many times to check to see if the value of the uptime has reset. Will throw an exception RebootFailure if it fails
uptime_retries How many times to check to see if the value of the uptime has reset . Will throw an exception RebootFailure if it fails