Module: Rightscale::RightSlicehostInterface

Included in:
Slicehost
Defined in:
lib/slicehost_base.rb

Constant Summary collapse

DEFAULT_SLICEHOST_URL =
'https://api.slicehost.com'
SLICEHOST_PROBLEMS =

Text, if found in an error message returned by Slicehost, indicates that this may be a transient error. Transient errors are automatically retried with exponential back-off. TODO: gather Slicehost errors here

[ ]
@@slicehost_problems =
SLICEHOST_PROBLEMS
@@caching =
false
@@bench =
SlicehostBenchmarkingBlock.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#cacheObject (readonly)

Cache



85
86
87
# File 'lib/slicehost_base.rb', line 85

def cache
  @cache
end

#connectionObject (readonly)

RightHttpConnection instance



83
84
85
# File 'lib/slicehost_base.rb', line 83

def connection
  @connection
end

#last_errorsObject

Last Slicehost errors list (used by SlicehostErrorHandler)



77
78
79
# File 'lib/slicehost_base.rb', line 77

def last_errors
  @last_errors
end

#last_requestObject (readonly)

Last HTTP request object



73
74
75
# File 'lib/slicehost_base.rb', line 73

def last_request
  @last_request
end

#last_responseObject (readonly)

Last HTTP response object



75
76
77
# File 'lib/slicehost_base.rb', line 75

def last_response
  @last_response
end

#loggerObject

Logger object



79
80
81
# File 'lib/slicehost_base.rb', line 79

def logger
  @logger
end

#paramsObject

Initial params hash



81
82
83
# File 'lib/slicehost_base.rb', line 81

def params
  @params
end

#slicehost_paswordObject (readonly)

Current Slicehost API key



71
72
73
# File 'lib/slicehost_base.rb', line 71

def slicehost_pasword
  @slicehost_pasword
end

Class Method Details

.bench_parserObject



63
64
65
# File 'lib/slicehost_base.rb', line 63

def self.bench_parser
  @@bench.parser
end

.bench_slicehostObject



66
67
68
# File 'lib/slicehost_base.rb', line 66

def self.bench_slicehost
  @@bench.service
end

.cachingObject



55
56
57
# File 'lib/slicehost_base.rb', line 55

def self.caching
  @@caching
end

.caching=(caching) ⇒ Object



58
59
60
# File 'lib/slicehost_base.rb', line 58

def self.caching=(caching)
  @@caching = caching
end

.slicehost_problemsObject

Returns a list of Slicehost responses which are known to be transient problems. We have to re-request if we get any of them, because the problem will probably disappear. By default this method returns the same value as the SLICEHOST_PROBLEMS const.



50
51
52
# File 'lib/slicehost_base.rb', line 50

def self.slicehost_problems
  @@slicehost_problems
end

Instance Method Details

#cache_hits?(function, response, do_raise = :raise) ⇒ Boolean

Check if the slicehost function response hits the cache or not. If the cache hits:

  • raises an SlicehostNoChange exception if do_raise == :raise.

  • returnes parsed response from the cache if it exists or true otherwise.

If the cache miss or the caching is off then returns false.

Returns:

  • (Boolean)


228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/slicehost_base.rb', line 228

def cache_hits?(function, response, do_raise=:raise) # :nodoc:
  result = false
  if caching?
    function     = function.to_sym
    response_md5 = MD5.md5(response).to_s
    # well, the response is new, reset cache data
    unless @cache[function] && @cache[function][:response_md5] == response_md5
      update_cache(function, {:response_md5 => response_md5,
                              :timestamp    => Time.now,
                              :hits         => 0,
                              :parsed       => nil})
    else
      # aha, cache hits, update the data and throw an exception if needed
      @cache[function][:hits] += 1
      if do_raise == :raise
        raise(SlicehostNoChange, "Cache hit: #{function} response has not changed since "+
                              "#{@cache[function][:timestamp].strftime('%Y-%m-%d %H:%M:%S')}, "+
                              "hits: #{@cache[function][:hits]}.")
      else
        result = @cache[function][:parsed] || true
      end
    end
  end
  result
end

#caching?Boolean

Returns true if the describe_xxx responses are being cached

Returns:

  • (Boolean)


219
220
221
# File 'lib/slicehost_base.rb', line 219

def caching?
  @params.key?(:cache) ? @params[:cache] : @@caching
end

#cgi_escape_params(params) ⇒ Object

:nodoc:



129
130
131
# File 'lib/slicehost_base.rb', line 129

def cgi_escape_params(params) # :nodoc:
  params.map {|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
end

#generate_request(method, path, params = {}) ⇒ Object

Generate a handy request hash.



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
# File 'lib/slicehost_base.rb', line 138

def generate_request(method, path, params={}) # :nodoc:
  # default request params
  params = cgi_escape_params(params)

  request_url = "#{@params[:service]}/#{path}"
  request_url << "?#{params}" unless params.blank?

  request = method.new(request_url)
  case method.name[/([^:]*)$/] && $1
  when 'Post'
    request['Accept']       = '*/*'
    request['Content-Type'] = 'application/xml'
  when 'Put'
    request['Accept']       = '*/*'
    request['Content-Type'] = 'application/xml'
  else
    request['Accept']  = 'application/xml'
  end

  request.basic_auth(@slicehost_pasword,'')

  { :request  => request,
    :server   => @params[:server],
    :port     => @params[:port],
    :protocol => @params[:protocol] }
end

#init(slicehost_pasword, params = {}) ⇒ Object

Params:

:slicehost_url
:logger
:multi_thread


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/slicehost_base.rb', line 94

def init(slicehost_pasword, params={}) #:nodoc:
  @params = params
  @cache  = {}
  @error_handler = nil
  # deny working without credentials
  if slicehost_pasword.blank?
    raise SlicehostError.new("Slicehost password is required to operate on Slicehost API service")
  end
  @slicehost_pasword = slicehost_pasword
  # parse Slicehost URL
  @params[:slicehost_url] ||= ENV['SLICEHOST_URL'] || DEFAULT_SLICEHOST_URL
  @params[:server]       = URI.parse(@params[:slicehost_url]).host
  @params[:port]         = URI.parse(@params[:slicehost_url]).port
  @params[:service]      = URI.parse(@params[:slicehost_url]).path
  @params[:protocol]     = URI.parse(@params[:slicehost_url]).scheme
  # other params
  @params[:multi_thread] ||= defined?(SLICEHOST_DAEMON)
  @logger = @params[:logger] || (defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER) || Logger.new(STDOUT)
  @logger.info "New #{self.class.name} using #{@params[:multi_thread] ? 'multi' : 'single'}-threaded mode"
end

#multi_threadObject

Return true if this instance works in multi_thread mode and false otherwise.



125
126
127
# File 'lib/slicehost_base.rb', line 125

def multi_thread
  @params[:multi_thread]
end

#on_exception(options = {:raise=>true, :log=>true}) ⇒ Object

:nodoc:



115
116
117
118
# File 'lib/slicehost_base.rb', line 115

def on_exception(options={:raise=>true, :log=>true}) # :nodoc:
  raise if $!.is_a?(SlicehostNoChange)
  SlicehostError::on_slicehost_exception(self, options)
end

#request_cache_or_info(method, request_hash, parser_class, use_cache = true) ⇒ Object

Perform a request. Skips a response parsing if caching is used.



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/slicehost_base.rb', line 202

def request_cache_or_info(method, request_hash, parser_class, use_cache=true) #:nodoc:
  # We do not want to break the logic of parsing hence will use a dummy parser to process all the standard
  # steps (errors checking etc). The dummy parser does nothig - just returns back the params it received.
  # If the caching is enabled and hit then throw  SlicehostNoChange.
  # P.S. caching works for the whole images list only! (when the list param is blank)
  response = request_info(request_hash, SlicehostDummyParser.new)
  # check cache
  cache_hits?(method.to_sym, response.body) if use_cache
  parser = parser_class.new(:logger => @logger)
  @@bench.parser.add!{ parser.parse(response) }
  result = block_given? ? yield(parser) : parser.result
  # update parsed data
  update_cache(method.to_sym, :parsed => result) if use_cache
  result
end

#request_info(request, parser) ⇒ Object

Perform a request. (4xx and 5xx error handling is being made through SlicehostErrorHandler)



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
# File 'lib/slicehost_base.rb', line 167

def request_info(request, parser)  #:nodoc:
  # check single/multi threading mode
  thread = @params[:multi_thread] ? Thread.current : Thread.main
  # create a connection if needed
  thread[:connection] ||= Rightscale::HttpConnection.new(:exception => SlicehostError, :logger => @logger)
  @connection    = thread[:connection]
  @last_request  = request[:request]
  @last_response = nil
  # perform a request
  @@bench.service.add!{ @last_response = @connection.request(request) }
  # check response for success...
  if @last_response.is_a?(Net::HTTPSuccess)
    @error_handler = nil
    @@bench.parser.add! { parser.parse(@last_response) }
    return parser.result
  else
    @error_handler ||= SlicehostErrorHandler.new(self, parser, :errors_list => @@slicehost_problems)
    check_result     = @error_handler.check(request)
    if check_result
      @error_handler = nil
      return check_result
    end
    raise SlicehostError.new(@last_errors, @last_response.code)
  end
rescue
  @error_handler = nil
  raise
end

#update_cache(function, hash) ⇒ Object

:nodoc:



254
255
256
# File 'lib/slicehost_base.rb', line 254

def update_cache(function, hash) # :nodoc:
  (@cache[function.to_sym] ||= {}).merge!(hash) if caching?
end