right_cloud_api_base 0.1.0
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 +7 -0
- data/HISTORY +2 -0
- data/LICENSE +19 -0
- data/README.md +14 -0
- data/Rakefile +37 -0
- data/lib/base/api_manager.rb +707 -0
- data/lib/base/helpers/cloud_api_logger.rb +214 -0
- data/lib/base/helpers/http_headers.rb +239 -0
- data/lib/base/helpers/http_parent.rb +103 -0
- data/lib/base/helpers/http_request.rb +173 -0
- data/lib/base/helpers/http_response.rb +122 -0
- data/lib/base/helpers/net_http_patch.rb +31 -0
- data/lib/base/helpers/query_api_patterns.rb +862 -0
- data/lib/base/helpers/support.rb +270 -0
- data/lib/base/helpers/support.xml.rb +306 -0
- data/lib/base/helpers/utils.rb +380 -0
- data/lib/base/manager.rb +122 -0
- data/lib/base/parsers/json.rb +38 -0
- data/lib/base/parsers/plain.rb +36 -0
- data/lib/base/parsers/rexml.rb +83 -0
- data/lib/base/parsers/sax.rb +200 -0
- data/lib/base/routines/cache_validator.rb +184 -0
- data/lib/base/routines/connection_proxies/net_http_persistent_proxy.rb +194 -0
- data/lib/base/routines/connection_proxies/right_http_connection_proxy.rb +224 -0
- data/lib/base/routines/connection_proxy.rb +66 -0
- data/lib/base/routines/request_analyzer.rb +122 -0
- data/lib/base/routines/request_generator.rb +48 -0
- data/lib/base/routines/request_initializer.rb +52 -0
- data/lib/base/routines/response_analyzer.rb +152 -0
- data/lib/base/routines/response_parser.rb +79 -0
- data/lib/base/routines/result_wrapper.rb +75 -0
- data/lib/base/routines/retry_manager.rb +106 -0
- data/lib/base/routines/routine.rb +98 -0
- data/lib/right_cloud_api_base.rb +72 -0
- data/lib/right_cloud_api_base_version.rb +37 -0
- data/right_cloud_api_base.gemspec +63 -0
- data/spec/helpers/query_api_pattern_spec.rb +312 -0
- data/spec/helpers/support_spec.rb +211 -0
- data/spec/helpers/support_xml_spec.rb +207 -0
- data/spec/helpers/utils_spec.rb +179 -0
- data/spec/routines/connection_proxies/test_net_http_persistent_proxy_spec.rb +143 -0
- data/spec/routines/test_cache_validator_spec.rb +152 -0
- data/spec/routines/test_connection_proxy_spec.rb +44 -0
- data/spec/routines/test_request_analyzer_spec.rb +106 -0
- data/spec/routines/test_response_analyzer_spec.rb +132 -0
- data/spec/routines/test_response_parser_spec.rb +228 -0
- data/spec/routines/test_result_wrapper_spec.rb +63 -0
- data/spec/routines/test_retry_manager_spec.rb +84 -0
- data/spec/spec_helper.rb +15 -0
- metadata +215 -0
@@ -0,0 +1,173 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2013 RightScale, Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
module RightScale
|
25
|
+
module CloudApi
|
26
|
+
|
27
|
+
# A Wrapper around standard Net::HTTPRequest class.
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
#
|
31
|
+
# The class supports some handy methods for managing the verb, the body, the path and the headers.
|
32
|
+
# And everythig else can be accessed through *raw* attribute that points to the original
|
33
|
+
# Net::HTTPRequest instance.
|
34
|
+
#
|
35
|
+
class HTTPRequest < HTTPParent
|
36
|
+
|
37
|
+
|
38
|
+
# Request HTTP verb
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
# @example
|
42
|
+
# response.verb #=> 'get'
|
43
|
+
#
|
44
|
+
attr_accessor :verb
|
45
|
+
|
46
|
+
|
47
|
+
# Request path
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
# @example
|
51
|
+
# response.path #=> 'xxx/yyy/zzz'
|
52
|
+
#
|
53
|
+
attr_accessor :path
|
54
|
+
|
55
|
+
|
56
|
+
# Request HTTP params
|
57
|
+
#
|
58
|
+
# @return [Hash]
|
59
|
+
# @example
|
60
|
+
# response.params #=> { 'a' => 'b', 'c' => 'd' }
|
61
|
+
#
|
62
|
+
attr_accessor :params
|
63
|
+
|
64
|
+
|
65
|
+
# Max byte to log
|
66
|
+
BODY_BYTES_TO_LOG = 6000
|
67
|
+
|
68
|
+
|
69
|
+
# Constructor
|
70
|
+
#
|
71
|
+
# @param [String,Symbol] verb The current verb ('get', 'post', 'put', etc).
|
72
|
+
# @param [String,IO,Nil] body The request body.
|
73
|
+
# @param [String] path The URL path.
|
74
|
+
# @param [Hash] headers The request headers.
|
75
|
+
# @param [Net::HTTPRequest] raw The original request (optional).
|
76
|
+
#
|
77
|
+
# @return [Rightscale::CloudApi::HTTPRequest] A new instance.
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# new('get', 'xxx/yyy/zzz', nil, {})
|
81
|
+
#
|
82
|
+
def initialize(verb, path, body, headers, raw=nil)
|
83
|
+
# Create a request
|
84
|
+
@verb = verb.to_s.downcase
|
85
|
+
@path = path
|
86
|
+
@raws = raw
|
87
|
+
@headers = HTTPHeaders::new(headers)
|
88
|
+
self.body = body
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Sets a new headers value(s)
|
93
|
+
#
|
94
|
+
# @param [String] header The header name.
|
95
|
+
# @param [String, Array] value The value for the header.
|
96
|
+
# @return [void]
|
97
|
+
# @example
|
98
|
+
# # no example
|
99
|
+
#
|
100
|
+
def []=(header, value)
|
101
|
+
@headers[header] = value
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Sets the body and the 'content-length' header
|
106
|
+
#
|
107
|
+
# If the body is blank it sets the header to 0.
|
108
|
+
# If the body is a String it sets the header to the string size.
|
109
|
+
# If the body is an IO object it tries to open it in *binmode* mode and sets the header to
|
110
|
+
# the filesize (if the header is not set or points outside of the range of (0..filesize-1)).
|
111
|
+
#
|
112
|
+
# @param [Object] new_body
|
113
|
+
# @return [void]
|
114
|
+
# @example
|
115
|
+
# # no example
|
116
|
+
#
|
117
|
+
def body=(new_body)
|
118
|
+
# Set a request body
|
119
|
+
if new_body._blank?
|
120
|
+
@body = nil
|
121
|
+
self['content-length'] = 0
|
122
|
+
else
|
123
|
+
if new_body.is_a?(IO)
|
124
|
+
@body = file = new_body
|
125
|
+
# Make sure the file is openned in binmode
|
126
|
+
file.binmode if file.respond_to?(:binmode)
|
127
|
+
# Fix 'content-length': it must not be bigger than a piece of a File left to be read or a String body size.
|
128
|
+
# Otherwise the connection may behave like crazy causing 4xx or 5xx responses
|
129
|
+
# KD: Make sure this code is used with the patched RightHttpConnection gem (see net_fix.rb)
|
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
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
# Displays the request as a String with the verb and the path
|
144
|
+
#
|
145
|
+
# @return [String] The request verb and path info.
|
146
|
+
# @example
|
147
|
+
# ec2.request.to_s #=>
|
148
|
+
# "GET /?AWSAccessKeyId=000..000A&Action=DescribeSecurityGroups&SignatureMethod=HmacSHA256&
|
149
|
+
# SignatureVersion=2&Timestamp=2013-02-22T23%3A54%3A30.000Z&Version=2012-10-15&
|
150
|
+
# Signature=Gd...N4yQStO5aKXfYnrM4%3D"
|
151
|
+
#
|
152
|
+
def to_s
|
153
|
+
"#{verb.upcase} #{path}"
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# Displays the body information
|
158
|
+
#
|
159
|
+
# @return [String] The body info.
|
160
|
+
# @example
|
161
|
+
# request.body_info #=> "something"
|
162
|
+
#
|
163
|
+
def body_info
|
164
|
+
if is_io?
|
165
|
+
"#{body.class.name}, size: #{body.respond_to?(:lstat) ? body.lstat.size : body.size}, pos: #{body.pos}"
|
166
|
+
else
|
167
|
+
"size: #{body.to_s.size}, first #{BODY_BYTES_TO_LOG} bytes:\n#{body.to_s[0...BODY_BYTES_TO_LOG]}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2013 RightScale, Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
module RightScale
|
25
|
+
module CloudApi
|
26
|
+
|
27
|
+
# A Wrapper around standard Net::HTTPRsponse class
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
#
|
31
|
+
# The class supports some handy methods for managing the code, the body and the headers.
|
32
|
+
# And everythig else can be accessed through *raw* attribute that points to the original
|
33
|
+
# Net::HTTPResponse instance.
|
34
|
+
#
|
35
|
+
class HTTPResponse < HTTPParent
|
36
|
+
|
37
|
+
# The response code
|
38
|
+
#
|
39
|
+
# @return [String]
|
40
|
+
# @example
|
41
|
+
# response.code #=> '404'
|
42
|
+
#
|
43
|
+
attr_reader :code
|
44
|
+
|
45
|
+
# Body bytes to log
|
46
|
+
BODY_BYTES_TO_LOG = 2000
|
47
|
+
|
48
|
+
# Body bytes to log in case of error
|
49
|
+
BODY_BYTES_TO_LOG_ERROR = 6000
|
50
|
+
|
51
|
+
|
52
|
+
# Constructor
|
53
|
+
#
|
54
|
+
# @param [String] code The http response code.
|
55
|
+
# @param [String,IO,Nil] body The response body.
|
56
|
+
# @param [Hash] headers The response headers.
|
57
|
+
# @param [Net::HTTPRequest] raw The original response (optional).
|
58
|
+
#
|
59
|
+
# @return [Rightscale::CloudApi::HTTPResponse] A new response instance.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# new('200', 'body', {}, object)
|
63
|
+
#
|
64
|
+
def initialize(code, body, headers, raw)
|
65
|
+
@code = code.to_s
|
66
|
+
@body = body
|
67
|
+
@raw = raw
|
68
|
+
@headers = HTTPHeaders::new(headers)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Returns true if the response code is in the range of 4xx or 5xx
|
73
|
+
#
|
74
|
+
# @return [Boolean]
|
75
|
+
# @example
|
76
|
+
# response.is_error? #=> false
|
77
|
+
#
|
78
|
+
def is_error?
|
79
|
+
!!(code.is_a?(String) && code.match(/^(5..|4..)/))
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Returns true if the response code is in the range of 3xx
|
84
|
+
#
|
85
|
+
# @return [Boolean]
|
86
|
+
# @example
|
87
|
+
# response.is_redirect? #=> false
|
88
|
+
#
|
89
|
+
def is_redirect?
|
90
|
+
!!(code.is_a?(String) && code.match(/^3..$/))
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Returns the response code and code name
|
95
|
+
#
|
96
|
+
# @return [String]
|
97
|
+
# @example
|
98
|
+
# ec2.response.to_s #=> '200 OK'
|
99
|
+
#
|
100
|
+
def to_s
|
101
|
+
result = code.dup
|
102
|
+
result << " #{raw.class.name[/Net::HTTP(.*)/] && $1}" if raw.is_a?(Net::HTTPResponse)
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Displays the body information
|
108
|
+
#
|
109
|
+
# @return [String] The body info.
|
110
|
+
# @example
|
111
|
+
# ec2.response.body_info #=> 'response boby'
|
112
|
+
#
|
113
|
+
def body_info
|
114
|
+
if is_io? then "#{body.class.name}"
|
115
|
+
elsif is_error? then "size: #{body.to_s.size}, first #{BODY_BYTES_TO_LOG_ERROR} bytes:\n#{body.to_s[0...BODY_BYTES_TO_LOG_ERROR]}"
|
116
|
+
else "size: #{body.to_s.size}, first #{BODY_BYTES_TO_LOG} bytes:\n#{body.to_s[0...BODY_BYTES_TO_LOG]}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2013 RightScale, Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# TBD: Remove once we use ruby 1.9.3 which introduces this class
|
25
|
+
unless defined?(Net::HTTP::Patch)
|
26
|
+
class Net::HTTP::Patch < Net::HTTPRequest
|
27
|
+
METHOD = 'PATCH'
|
28
|
+
REQUEST_HAS_BODY = true
|
29
|
+
RESPONSE_HAS_BODY = true
|
30
|
+
end
|
31
|
+
end
|