module Bosh::Common

Module for common methods used throughout the BOSH code.

Constants

VERSION

Public Class Methods

retryable(options = {}, &block) click to toggle source

Retries execution of given block until block returns true

The block is called with two parameters: the number of tries and the most recent exception. If the block returns true retrying is stopped. Examples:

Bosh::Common.retryable do |retries, exception|
  puts "try #{retries} failed with exception: #{exception}" if retries > 0
  pick_up_soap
end

# Wait for EC2 instance to be terminated
Bosh::Common.retryable(on: AWS::EC2::Errors::RequestLimitExceeded) do |retries, exception|
  @ec2.instance['i-a3x5g5'].status == :terminated
end

@param [Hash] options @options opts [Proc] :ensure

 Default: `Proc.new {}`
 Ensure that a block of code is executed, regardless of whether an exception
 was raised. It doesn't matter if the block exits normally, if it retries
 to execute block of code, or if it is terminated by an uncaught exception
 -- the ensure block will get run.
 Example:
 f = File.open("testfile")

 ensure_cb = Proc.new do |retries|
   puts "total retry attempts: #{retries}"

   f.close
end

Bosh::Common.retryable(ensure: ensure_cb) do
  # process file
end

@options opts [Regexp] :matching

Default: `/.*/`
Retry based on the exception message
Example:
Bosh::Common.retryable(matching: /IO timeout/) do |retries, exception|
  raise "yo, IO timeout!" if retries == 0
end

@options opts [Array<ExceptionClass>] :on

Default: `[]`
The array of exception classes to retry on.
Example:
Bosh::Common.retryable(on: [StandardError, ArgumentError]) do
  # do something and retry if StandardError or ArgumentError is raised
end

@options opts [Proc, Fixnum] :sleep

Defaults: `lambda { |tries, _| [2**(tries-1), 10].min }`,  1, 2, 4, 8, 10, 10..10 seconds
If a Fixnum is given, sleep that many seconds between retries.
If a Proc is given, call it with the expectation that a Fixnum is returned
and sleep that many seconds. The Proc will be called with the number of tries
and the raised exception (or nil)
Example:
Bosh::Common.retryable(sleep: lambda { |n,e| logger.info(e.message) if e; 4**n }) { }

@options opts [Fixnum] :tries

Default: 2
Number of times to try
Example:
Bosh::Common.retryable(tries: 3, on: OpenURI::HTTPError) do
  xml = open("http://example.com/test.xml").read
end
# File lib/common/common.rb, line 118
def retryable(options = {}, &block)
  Bosh::Retryable.new(options).retryer(&block)
end
symbolize_keys(hash) click to toggle source

Converts all keys of a [Hash] to symbols. Performs deep conversion.

@param [Hash] hash to convert @return [Hash] a copy of the original hash

# File lib/common/common.rb, line 14
def symbolize_keys(hash)
  hash.inject({}) do |h, (key, value)|
    h[key.to_sym] = value.is_a?(Hash) ? symbolize_keys(value) : value
    h
  end
end
which(programs, path=ENV["PATH"]) click to toggle source

@overload which(program, path)

Looks for program in the executables search path (PATH).
The file must be executable to be found.
@param [String] program
@param [String] path search path
@return [String] full path of the executable,
  or nil if not found

@overload which(programs, path)

Looks for one of the programs in the executables search path (PATH).
The file must be executable to be found.
@param [Array] programs
@param [String] path search path
@return [String] full path of the executable,
  or nil if not found
# File lib/common/common.rb, line 37
def which(programs, path=ENV["PATH"])
  path.split(File::PATH_SEPARATOR).each do |dir|
    Array(programs).each do |bin|
      exe = File.join(dir, bin)
      return exe if File.executable?(exe)
    end
  end
  nil
end

Private Instance Methods

retryable(options = {}, &block) click to toggle source

Retries execution of given block until block returns true

The block is called with two parameters: the number of tries and the most recent exception. If the block returns true retrying is stopped. Examples:

Bosh::Common.retryable do |retries, exception|
  puts "try #{retries} failed with exception: #{exception}" if retries > 0
  pick_up_soap
end

# Wait for EC2 instance to be terminated
Bosh::Common.retryable(on: AWS::EC2::Errors::RequestLimitExceeded) do |retries, exception|
  @ec2.instance['i-a3x5g5'].status == :terminated
end

@param [Hash] options @options opts [Proc] :ensure

 Default: `Proc.new {}`
 Ensure that a block of code is executed, regardless of whether an exception
 was raised. It doesn't matter if the block exits normally, if it retries
 to execute block of code, or if it is terminated by an uncaught exception
 -- the ensure block will get run.
 Example:
 f = File.open("testfile")

 ensure_cb = Proc.new do |retries|
   puts "total retry attempts: #{retries}"

   f.close
end

Bosh::Common.retryable(ensure: ensure_cb) do
  # process file
end

@options opts [Regexp] :matching

Default: `/.*/`
Retry based on the exception message
Example:
Bosh::Common.retryable(matching: /IO timeout/) do |retries, exception|
  raise "yo, IO timeout!" if retries == 0
end

@options opts [Array<ExceptionClass>] :on

Default: `[]`
The array of exception classes to retry on.
Example:
Bosh::Common.retryable(on: [StandardError, ArgumentError]) do
  # do something and retry if StandardError or ArgumentError is raised
end

@options opts [Proc, Fixnum] :sleep

Defaults: `lambda { |tries, _| [2**(tries-1), 10].min }`,  1, 2, 4, 8, 10, 10..10 seconds
If a Fixnum is given, sleep that many seconds between retries.
If a Proc is given, call it with the expectation that a Fixnum is returned
and sleep that many seconds. The Proc will be called with the number of tries
and the raised exception (or nil)
Example:
Bosh::Common.retryable(sleep: lambda { |n,e| logger.info(e.message) if e; 4**n }) { }

@options opts [Fixnum] :tries

Default: 2
Number of times to try
Example:
Bosh::Common.retryable(tries: 3, on: OpenURI::HTTPError) do
  xml = open("http://example.com/test.xml").read
end
# File lib/common/common.rb, line 118
def retryable(options = {}, &block)
  Bosh::Retryable.new(options).retryer(&block)
end
symbolize_keys(hash) click to toggle source

Converts all keys of a [Hash] to symbols. Performs deep conversion.

@param [Hash] hash to convert @return [Hash] a copy of the original hash

# File lib/common/common.rb, line 14
def symbolize_keys(hash)
  hash.inject({}) do |h, (key, value)|
    h[key.to_sym] = value.is_a?(Hash) ? symbolize_keys(value) : value
    h
  end
end
which(programs, path=ENV["PATH"]) click to toggle source

@overload which(program, path)

Looks for program in the executables search path (PATH).
The file must be executable to be found.
@param [String] program
@param [String] path search path
@return [String] full path of the executable,
  or nil if not found

@overload which(programs, path)

Looks for one of the programs in the executables search path (PATH).
The file must be executable to be found.
@param [Array] programs
@param [String] path search path
@return [String] full path of the executable,
  or nil if not found
# File lib/common/common.rb, line 37
def which(programs, path=ENV["PATH"])
  path.split(File::PATH_SEPARATOR).each do |dir|
    Array(programs).each do |bin|
      exe = File.join(dir, bin)
      return exe if File.executable?(exe)
    end
  end
  nil
end