class CloudstackClient::Connection

Constants

DEF_ASYNC_TIMEOUT
DEF_POLL_INTERVAL
DEF_REQ_TIMEOUT

Attributes

api_key[RW]
api_url[RW]
async_poll_interval[RW]
async_timeout[RW]
debug[RW]
host[RW]
read_timeout[RW]
secret_key[RW]
symbolize_keys[RW]
verbose[RW]

Public Class Methods

new(api_url, api_key, secret_key, options = {}) click to toggle source
   # File lib/cloudstack_client/connection.rb
19 def initialize(api_url, api_key, secret_key, options = {})
20   @api_url = api_url
21   @api_key = api_key
22   @secret_key = secret_key
23   @verbose = options[:quiet] ? false : true
24   @debug = options[:debug] ? true : false
25   @symbolize_keys = options[:symbolize_keys] ? true : false
26   @host = options[:host]
27   @read_timeout = options[:read_timeout] || DEF_REQ_TIMEOUT
28   @async_poll_interval = options[:async_poll_interval] || DEF_POLL_INTERVAL
29   @async_timeout = options[:async_timeout] || DEF_ASYNC_TIMEOUT
30   @options = options
31   validate_input!
32 end

Public Instance Methods

send_async_request(params) click to toggle source

Sends an asynchronous request and waits for the response.

The contents of the ‘jobresult’ element are returned upon completion of the command.

    # File lib/cloudstack_client/connection.rb
 90 def send_async_request(params)
 91   data = send_request(params)
 92 
 93   params = {
 94     'command' => 'queryAsyncJobResult',
 95     'jobid' => data[k('jobid')]
 96   }
 97 
 98   max_tries.times do
 99     data = send_request(params)
100     print "." if @verbose
101 
102     case data[k('jobstatus')]
103     when 1
104       return data[k('jobresult')]
105     when 2
106       raise JobError, "Request failed (#{data[k('jobresultcode')]}): #{data[k('jobresult')][k('errortext')]}."
107     end
108 
109     STDOUT.flush if @verbose
110     sleep @async_poll_interval
111   end
112 
113   raise TimeoutError, "Asynchronous request timed out."
114 end
send_request(params) click to toggle source

Sends a synchronous request to the CloudStack API and returns the response as a Hash.

   # File lib/cloudstack_client/connection.rb
38 def send_request(params)
39   params['response'] = 'json'
40   params['apiKey'] = @api_key
41   print_debug_output JSON.pretty_generate(params) if @debug
42 
43   data = params_to_data(params)
44   uri = URI.parse "#{@api_url}?#{data}&signature=#{create_signature(data)}"
45 
46   http = Net::HTTP.new(uri.host, uri.port)
47   if uri.scheme == 'https'
48     http.use_ssl = true
49     http.verify_mode = OpenSSL::SSL::VERIFY_NONE
50   end
51   http.read_timeout = @read_timeout
52 
53   begin
54     req = Net::HTTP::Get.new(uri.request_uri)
55     req['Host'] = host if host.present?
56     response = http.request(req)
57   rescue
58     raise ConnectionError, "API URL \'#{@api_url}\' is not reachable."
59   end
60 
61   begin
62     body = JSON.parse(response.body, symbolize_names: @symbolize_keys).values.first
63   rescue JSON::ParserError
64     raise ParseError,
65           "Response from server is not readable. Check if the API endpoint (#{@api_url}) is valid and accessible."
66   end
67 
68   if response.is_a?(Net::HTTPOK)
69     return body unless body.respond_to?(:keys)
70     if body.size == 2 && body.key?(k('count'))
71       return body.reject { |key, _| key == k('count') }.values.first
72     elsif body.size == 1 && body.values.first.respond_to?(:keys)
73       item = body.values.first
74       return (item.is_a?(Array) || item.is_a?(Hash)) ? item : []
75     else
76       body.reject! { |key, _| key == k('count') } if body.key?(k('count'))
77       body.size == 0 ? [] : body
78     end
79   else
80     message = body[k('errortext')] rescue body
81     raise ApiError, "Status #{response.code}: #{message}."
82   end
83 end

Private Instance Methods

create_signature(data) click to toggle source
    # File lib/cloudstack_client/connection.rb
147 def create_signature(data)
148   signature = OpenSSL::HMAC.digest('sha1', @secret_key, data.downcase)
149   signature = Base64.encode64(signature).chomp
150   CGI.escape(signature)
151 end
escape(input) click to toggle source
    # File lib/cloudstack_client/connection.rb
157 def escape(input)
158   CGI.escape(input.to_s).gsub('+', '%20').gsub(' ', '%20')
159 end
k(name)
Alias for: symbolized_key
max_tries() click to toggle source
    # File lib/cloudstack_client/connection.rb
153 def max_tries
154   (@async_timeout / @async_poll_interval).round
155 end
params_to_data(params) click to toggle source
    # File lib/cloudstack_client/connection.rb
126 def params_to_data(params)
127   params_arr = params.sort.map do |key, value|
128     case value
129     when Array # support for maps (Arrays of Hashes)
130       map = []
131       value.each_with_index do |items, i|
132         items.each {|k, v| map << "#{key}[#{i}].#{k}=#{escape(v)}"}
133       end
134       map.sort.join("&")
135     when Hash # support for maps values of values (Hash values of Hashes)
136       value.each_with_index.map do |(k, v), i|
137         "#{key}[#{i}].key=#{escape(k)}&" +
138           "#{key}[#{i}].value=#{escape(v)}"
139       end.join("&")
140     else
141       "#{key}=#{escape(value)}"
142     end
143   end
144   params_arr.sort.join('&')
145 end
symbolized_key(name) click to toggle source
    # File lib/cloudstack_client/connection.rb
161 def symbolized_key(name)
162   @symbolize_keys ? name.to_sym : name
163 end
Also aliased as: k
validate_input!() click to toggle source
    # File lib/cloudstack_client/connection.rb
118 def validate_input!
119   raise InputError, "API URL not set." if @api_url == nil
120   raise InputError, "API KEY not set." if @api_key == nil
121   raise InputError, "API SECRET KEY not set." if @secret_key == nil
122   raise InputError, "ASYNC POLL INTERVAL must be at least 1." if @async_poll_interval < 1.0
123   raise InputError, "ASYNC TIMEOUT must be at least 60." if @async_timeout < 60
124 end