right_cloud_api_base 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/HISTORY +5 -1
- data/lib/base/api_manager.rb +4 -0
- data/lib/base/helpers/http_request.rb +15 -20
- data/lib/base/helpers/utils.rb +10 -9
- data/lib/base/routines/connection_proxies/net_http_persistent_proxy.rb +89 -35
- data/lib/base/routines/connection_proxies/right_http_connection_proxy.rb +4 -1
- data/lib/base/routines/connection_proxy.rb +3 -3
- data/lib/right_cloud_api_base_version.rb +2 -2
- metadata +9 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 93876f7645c63a599b1cdde9e5752490efcb6b9e
|
|
4
|
+
data.tar.gz: cf0a599994e10d1c17c2cf014e03ab303a18deed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 76b486fbb4c8392dff74a77e953c051b7eabeb8a2e723f795d0efb1bf66c3cebbcb6c543bc36e4674e41adee214e8bac4955fda97cd69b8a79e11ad7a4752e9c
|
|
7
|
+
data.tar.gz: ba3b90502877bbe162ceae9bfba958bb4682cc5ee2083fc1cd71c36b435c1ca8bb078cd522861683fb91fa30d3bf82855758936e803c2b04275e654a06e8b44a
|
data/HISTORY
CHANGED
data/lib/base/api_manager.rb
CHANGED
|
@@ -179,6 +179,10 @@ module RightScale
|
|
|
179
179
|
# @option options [Integer] :connection_retry_delay
|
|
180
180
|
# Defines how long we wait on a low level connection error (in seconds)
|
|
181
181
|
#
|
|
182
|
+
# @option options [Integer] :connection_verify_mode
|
|
183
|
+
# SSL connection cert check: either OpenSSL::SSL::VERIFY_PEER (default) or
|
|
184
|
+
# OpenSSL::SSL::VERIFY_NONE
|
|
185
|
+
#
|
|
182
186
|
# @option options [Hash] :creds
|
|
183
187
|
# A set of optional extra creds a cloud may require
|
|
184
188
|
# (see right_cloud_stack_api gem which supports :tenant_name and :tenant_id)
|
|
@@ -116,26 +116,21 @@ module RightScale
|
|
|
116
116
|
#
|
|
117
117
|
def body=(new_body)
|
|
118
118
|
# Set a request body
|
|
119
|
-
if new_body.
|
|
120
|
-
@body =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
file_size = file.respond_to?(:lstat) ? file.lstat.size : file.size
|
|
131
|
-
bytes_to_read = [ file_size - file.pos, self['content-length'].first ].compact.map{|v| v.to_i }.sort.first # remove nils then make values Integers
|
|
132
|
-
if self['content-length'].first._blank? || self['content-length'].first.to_i > bytes_to_read
|
|
133
|
-
self['content-length'] = bytes_to_read
|
|
134
|
-
end
|
|
135
|
-
else
|
|
136
|
-
@body = new_body
|
|
137
|
-
self['content-length'] = body.size if self['content-length'].first.to_i > body.size
|
|
119
|
+
if new_body.is_a?(IO)
|
|
120
|
+
@body = file = new_body
|
|
121
|
+
# Make sure the file is openned in binmode
|
|
122
|
+
file.binmode if file.respond_to?(:binmode)
|
|
123
|
+
# Fix 'content-length': it must not be bigger than a piece of a File left to be read or a String body size.
|
|
124
|
+
# Otherwise the connection may behave like crazy causing 4xx or 5xx responses
|
|
125
|
+
# KD: Make sure this code is used with the patched RightHttpConnection gem (see net_fix.rb)
|
|
126
|
+
file_size = file.respond_to?(:lstat) ? file.lstat.size : file.size
|
|
127
|
+
bytes_to_read = [ file_size - file.pos, self['content-length'].first ].compact.map{|v| v.to_i }.sort.first # remove nils then make values Integers
|
|
128
|
+
if self['content-length'].first._blank? || self['content-length'].first.to_i > bytes_to_read
|
|
129
|
+
self['content-length'] = bytes_to_read
|
|
138
130
|
end
|
|
131
|
+
else
|
|
132
|
+
@body = new_body.to_s
|
|
133
|
+
self['content-length'] = @body.bytesize if self['content-length'].first.to_i > @body.bytesize
|
|
139
134
|
end
|
|
140
135
|
end
|
|
141
136
|
|
|
@@ -164,7 +159,7 @@ module RightScale
|
|
|
164
159
|
if is_io?
|
|
165
160
|
"#{body.class.name}, size: #{body.respond_to?(:lstat) ? body.lstat.size : body.size}, pos: #{body.pos}"
|
|
166
161
|
else
|
|
167
|
-
"size: #{body.to_s.
|
|
162
|
+
"size: #{body.to_s.bytesize}, first #{BODY_BYTES_TO_LOG} bytes:\n#{body.to_s[0...BODY_BYTES_TO_LOG]}"
|
|
168
163
|
end
|
|
169
164
|
end
|
|
170
165
|
end
|
data/lib/base/helpers/utils.rb
CHANGED
|
@@ -49,7 +49,7 @@ module RightScale
|
|
|
49
49
|
def self.base64en(string)
|
|
50
50
|
Base64::encode64(string.to_s).strip
|
|
51
51
|
end
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
# Makes a URL params string from a given hash. If block is given the it invokes the block on
|
|
54
54
|
# every value so that one could escape it in his own way. If there is no block it url_encode
|
|
55
55
|
# values automatically.
|
|
@@ -169,9 +169,9 @@ module RightScale
|
|
|
169
169
|
# :code! => Condition, # Response code must not match Condition
|
|
170
170
|
# :response! => Condition, # Response body must not match Condition
|
|
171
171
|
# :if => Proc::new{ |opts| do something } # Extra condition: should return true | false
|
|
172
|
-
#
|
|
172
|
+
#
|
|
173
173
|
# (Condition above is /RegExp/ or String or Symbol)
|
|
174
|
-
#
|
|
174
|
+
#
|
|
175
175
|
# Opts is a Hash:
|
|
176
176
|
# :request => Object, # HTTP request instance
|
|
177
177
|
# :response => Object, # HTTP response instance
|
|
@@ -210,7 +210,7 @@ module RightScale
|
|
|
210
210
|
return nil if pattern[:if] && !pattern[:if].call(opts)
|
|
211
211
|
true
|
|
212
212
|
end
|
|
213
|
-
|
|
213
|
+
|
|
214
214
|
# Returns an Array with the current Thread and Fiber (if exists) instances.
|
|
215
215
|
#
|
|
216
216
|
# @return [Array] The first item is the current Thread instance and the second item
|
|
@@ -233,7 +233,7 @@ module RightScale
|
|
|
233
233
|
end
|
|
234
234
|
end
|
|
235
235
|
end
|
|
236
|
-
|
|
236
|
+
|
|
237
237
|
# Transforms body (when it is a Hash) into String
|
|
238
238
|
#
|
|
239
239
|
# @param [Hash] body The request body as a Hash instance.
|
|
@@ -254,13 +254,14 @@ module RightScale
|
|
|
254
254
|
def self.contentify_body(body, content_type)
|
|
255
255
|
return body unless body.is_a?(Hash)
|
|
256
256
|
# Transform
|
|
257
|
+
ct = dearrayify(content_type).to_s
|
|
257
258
|
case dearrayify(content_type).to_s
|
|
258
259
|
when /json/ then body.to_json
|
|
259
260
|
when /xml/ then body._to_xml!
|
|
260
|
-
else fail Error::new("
|
|
261
|
+
else fail Error::new("Cannot transform Hash body into #{ct.inspect} content type")
|
|
261
262
|
end
|
|
262
263
|
end
|
|
263
|
-
|
|
264
|
+
|
|
264
265
|
# Generates a unique token (Uses UUID when possible)
|
|
265
266
|
#
|
|
266
267
|
# @return [String] A random 28-symbols string.
|
|
@@ -275,7 +276,7 @@ module RightScale
|
|
|
275
276
|
# Use UUID gem if it is
|
|
276
277
|
if defined?(UUID) && UUID::respond_to?(:new)
|
|
277
278
|
uuid = UUID::new
|
|
278
|
-
return uuid.generate if uuid.respond_to?(:generate)
|
|
279
|
+
return uuid.generate if uuid.respond_to?(:generate)
|
|
279
280
|
end
|
|
280
281
|
# Otherwise generate a random token
|
|
281
282
|
time = Time::now.utc
|
|
@@ -374,7 +375,7 @@ module RightScale
|
|
|
374
375
|
end
|
|
375
376
|
chain
|
|
376
377
|
end
|
|
377
|
-
|
|
378
|
+
|
|
378
379
|
end
|
|
379
380
|
end
|
|
380
381
|
end
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
module RightScale
|
|
25
25
|
module CloudApi
|
|
26
26
|
class ConnectionProxy
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
class NetHttpPersistentProxy
|
|
29
29
|
class Error < CloudApi::Error
|
|
30
30
|
end
|
|
@@ -40,7 +40,8 @@ module RightScale
|
|
|
40
40
|
def log(message)
|
|
41
41
|
@data[:options][:cloud_api_logger].log(message, :connection_proxy, :warn)
|
|
42
42
|
end
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
|
|
44
45
|
# Performs an HTTP request.
|
|
45
46
|
#
|
|
46
47
|
# @param [Hash] data The API request +data+ storage.
|
|
@@ -51,48 +52,101 @@ module RightScale
|
|
|
51
52
|
#
|
|
52
53
|
def request(data)
|
|
53
54
|
require "net/http/persistent"
|
|
54
|
-
|
|
55
|
-
@data
|
|
55
|
+
# Initialize things:
|
|
56
|
+
@data = data
|
|
56
57
|
@data[:response] = {}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# Create
|
|
60
|
-
connection
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
http_request.body = fake.body
|
|
58
|
+
# Create a new HTTP request instance
|
|
59
|
+
http_request = create_new_http_request
|
|
60
|
+
# Create and tweak Net::HTTP::Persistent instance
|
|
61
|
+
connection = create_new_persistent_connection
|
|
62
|
+
# Make a request
|
|
63
|
+
begin
|
|
64
|
+
make_request_with_retries(connection, @data[:connection][:uri], http_request)
|
|
65
|
+
rescue => e
|
|
66
|
+
fail(ConnectionError, e.message)
|
|
67
|
+
ensure
|
|
68
|
+
connection.shutdown
|
|
69
69
|
end
|
|
70
|
-
|
|
71
|
-
fake.raw = http_request
|
|
70
|
+
end
|
|
72
71
|
|
|
72
|
+
|
|
73
|
+
# Creates a new connection.
|
|
74
|
+
#
|
|
75
|
+
# There is a bug in Net::HTTP::Persistent where it allows you to reuse an SSL connection
|
|
76
|
+
# created by another instance of Net::HTTP::Persistent, if they share the same app name.
|
|
77
|
+
# To avoid this, every instance of Net::HTTP::Persistent should have its own 'name'.
|
|
78
|
+
#
|
|
79
|
+
# If your app does not care about SSL certs and keys (like AWS does) then it is safe to
|
|
80
|
+
# reuse connections.
|
|
81
|
+
#
|
|
82
|
+
# see https://github.com/drbrain/net-http-persistent/issues/45
|
|
83
|
+
#
|
|
84
|
+
def create_new_persistent_connection
|
|
85
|
+
app_name = if @data[:options][:connection_ca_file] ||
|
|
86
|
+
@data[:credentials][:cert] ||
|
|
87
|
+
@data[:credentials][:key]
|
|
88
|
+
'right_cloud_api_gem_%s' % Utils::generate_token
|
|
89
|
+
else
|
|
90
|
+
'right_cloud_api_gem'
|
|
91
|
+
end
|
|
92
|
+
connection = Net::HTTP::Persistent.new(app_name)
|
|
93
|
+
set_persistent_connection_options!(connection)
|
|
73
94
|
# Register a callback to close current connection
|
|
74
95
|
@data[:callbacks][:close_current_connection] = Proc::new do |reason|
|
|
75
96
|
connection.shutdown
|
|
76
97
|
log "Current connection closed: #{reason}"
|
|
77
98
|
end
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
# P.S. :connection_retry_count, :http_connection_retry_delay are not supported by this proxy
|
|
81
|
-
#
|
|
82
|
-
http_request['user-agent'] ||= @data[:options][:connection_user_agent] if @data[:options].has_key?(:connection_user_agent)
|
|
83
|
-
connection.ca_file = @data[:options][:connection_ca_file] if @data[:options].has_key?(:connection_ca_file)
|
|
84
|
-
connection.read_timeout = @data[:options][:connection_read_timeout] if @data[:options].has_key?(:connection_read_timeout)
|
|
85
|
-
connection.open_timeout = @data[:options][:connection_open_timeout] if @data[:options].has_key?(:connection_open_timeout)
|
|
86
|
-
connection.cert = OpenSSL::X509::Certificate.new(@data[:credentials][:cert]) if @data[:credentials].has_key?(:cert)
|
|
87
|
-
connection.key = OpenSSL::PKey::RSA.new(@data[:credentials][:key]) if @data[:credentials].has_key?(:key)
|
|
99
|
+
connection
|
|
100
|
+
end
|
|
88
101
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
|
|
103
|
+
# Sets connection_ca_file, connection_read_timeout, connection_open_timeout,
|
|
104
|
+
# connection_verify_mode and SSL cert and key
|
|
105
|
+
#
|
|
106
|
+
# @param [Net::HTTP::Persistent] connection
|
|
107
|
+
#
|
|
108
|
+
# @return [Net::HTTP::Persistent]
|
|
109
|
+
#
|
|
110
|
+
def set_persistent_connection_options!(connection)
|
|
111
|
+
[:ca_file, :read_timeout, :open_timeout, :verify_mode].each do |connection_method|
|
|
112
|
+
connection_option_name = "connection_#{connection_method}".to_sym
|
|
113
|
+
next unless @data[:options].has_key?(connection_option_name)
|
|
114
|
+
connection.__send__("#{connection_method}=", @data[:options][connection_option_name])
|
|
115
|
+
end
|
|
116
|
+
if @data[:credentials].has_key?(:cert)
|
|
117
|
+
connection.cert = OpenSSL::X509::Certificate.new(@data[:credentials][:cert])
|
|
118
|
+
end
|
|
119
|
+
if @data[:credentials].has_key?(:key)
|
|
120
|
+
connection.key = OpenSSL::PKey::RSA.new(@data[:credentials][:key])
|
|
121
|
+
end
|
|
122
|
+
connection
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# Creates and configures a new HTTP request object
|
|
127
|
+
#
|
|
128
|
+
# @return [Net::HTTPRequest]
|
|
129
|
+
#
|
|
130
|
+
def create_new_http_request
|
|
131
|
+
# Create a new HTTP request instance
|
|
132
|
+
request_spec = @data[:request][:instance]
|
|
133
|
+
http_class = "Net::HTTP::#{request_spec.verb._camelize}"
|
|
134
|
+
http_request = http_class._constantize::new(request_spec.path)
|
|
135
|
+
# Set the request body
|
|
136
|
+
if request_spec.is_io?
|
|
137
|
+
http_request.body_stream = request_spec.body
|
|
138
|
+
else
|
|
139
|
+
http_request.body = request_spec.body
|
|
140
|
+
end
|
|
141
|
+
# Copy headers
|
|
142
|
+
request_spec.headers.each { |header, value| http_request[header] = value }
|
|
143
|
+
# Save the new request
|
|
144
|
+
request_spec.raw = http_request
|
|
145
|
+
# Set user-agent
|
|
146
|
+
if @data[:options].has_key?(:connection_user_agent)
|
|
147
|
+
http_request['user-agent'] ||= @data[:options][:connection_user_agent]
|
|
95
148
|
end
|
|
149
|
+
http_request
|
|
96
150
|
end
|
|
97
151
|
|
|
98
152
|
|
|
@@ -188,7 +242,7 @@ module RightScale
|
|
|
188
242
|
nil
|
|
189
243
|
end
|
|
190
244
|
|
|
191
|
-
end
|
|
245
|
+
end
|
|
192
246
|
end
|
|
193
247
|
end
|
|
194
248
|
end
|
|
@@ -91,7 +91,10 @@ module RightScale
|
|
|
91
91
|
http_connection_data[:raise_on_timeout] = @data[:options][:abort_on_timeout] if @data[:options][:abort_on_timeout]
|
|
92
92
|
http_connection_data[:cert] = @data[:credentials][:cert] if @data[:credentials].has_key?(:cert)
|
|
93
93
|
http_connection_data[:key] = @data[:credentials][:key] if @data[:credentials].has_key?(:key)
|
|
94
|
-
|
|
94
|
+
if @data[:options].has_key?(:connection_verify_mode)
|
|
95
|
+
http_connection_data[:use_server_auth] = (@data[:options][:connection_verify_mode] != OpenSSL::SSL::VERIFY_NONE)
|
|
96
|
+
end
|
|
97
|
+
|
|
95
98
|
#log "HttpConnection request: #{http_connection_data.inspect}"
|
|
96
99
|
|
|
97
100
|
# Make a request:
|
|
@@ -47,8 +47,8 @@ module RightScale
|
|
|
47
47
|
connection_proxy_class = RightScale::CloudApi::ConnectionProxy::NetHttpPersistentProxy
|
|
48
48
|
end
|
|
49
49
|
@connection_proxy = connection_proxy_class.new
|
|
50
|
-
end
|
|
51
|
-
|
|
50
|
+
end
|
|
51
|
+
|
|
52
52
|
# Register a call back to close current connection
|
|
53
53
|
data[:callbacks][:close_current_connection] = Proc::new do |reason|
|
|
54
54
|
@connection_proxy.close_connection(nil, reason)
|
|
@@ -60,7 +60,7 @@ module RightScale
|
|
|
60
60
|
@connection_proxy.request(data)
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: right_cloud_api_base
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- RightScale, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2015-01-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|
|
@@ -193,23 +193,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
193
193
|
version: '0'
|
|
194
194
|
requirements: []
|
|
195
195
|
rubyforge_project:
|
|
196
|
-
rubygems_version: 2.
|
|
196
|
+
rubygems_version: 2.4.3
|
|
197
197
|
signing_key:
|
|
198
198
|
specification_version: 4
|
|
199
199
|
summary: The gem provides base Query and REST API management functionalities for Amazon,
|
|
200
200
|
OpenStack, Rackspace, CloudStack, etc cloud services
|
|
201
201
|
test_files:
|
|
202
|
+
- spec/spec_helper.rb
|
|
202
203
|
- spec/routines/test_connection_proxy_spec.rb
|
|
203
|
-
- spec/routines/
|
|
204
|
-
- spec/routines/
|
|
204
|
+
- spec/routines/test_retry_manager_spec.rb
|
|
205
|
+
- spec/routines/test_response_parser_spec.rb
|
|
205
206
|
- spec/routines/connection_proxies/test_net_http_persistent_proxy_spec.rb
|
|
207
|
+
- spec/routines/test_cache_validator_spec.rb
|
|
206
208
|
- spec/routines/test_response_analyzer_spec.rb
|
|
207
209
|
- spec/routines/test_request_analyzer_spec.rb
|
|
208
|
-
- spec/routines/
|
|
209
|
-
- spec/routines/test_retry_manager_spec.rb
|
|
210
|
-
- spec/spec_helper.rb
|
|
211
|
-
- spec/helpers/query_api_pattern_spec.rb
|
|
210
|
+
- spec/routines/test_result_wrapper_spec.rb
|
|
212
211
|
- spec/helpers/support_xml_spec.rb
|
|
213
212
|
- spec/helpers/support_spec.rb
|
|
214
213
|
- spec/helpers/utils_spec.rb
|
|
214
|
+
- spec/helpers/query_api_pattern_spec.rb
|
|
215
215
|
has_rdoc:
|