right_cloud_api_base 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY +2 -0
  3. data/LICENSE +19 -0
  4. data/README.md +14 -0
  5. data/Rakefile +37 -0
  6. data/lib/base/api_manager.rb +707 -0
  7. data/lib/base/helpers/cloud_api_logger.rb +214 -0
  8. data/lib/base/helpers/http_headers.rb +239 -0
  9. data/lib/base/helpers/http_parent.rb +103 -0
  10. data/lib/base/helpers/http_request.rb +173 -0
  11. data/lib/base/helpers/http_response.rb +122 -0
  12. data/lib/base/helpers/net_http_patch.rb +31 -0
  13. data/lib/base/helpers/query_api_patterns.rb +862 -0
  14. data/lib/base/helpers/support.rb +270 -0
  15. data/lib/base/helpers/support.xml.rb +306 -0
  16. data/lib/base/helpers/utils.rb +380 -0
  17. data/lib/base/manager.rb +122 -0
  18. data/lib/base/parsers/json.rb +38 -0
  19. data/lib/base/parsers/plain.rb +36 -0
  20. data/lib/base/parsers/rexml.rb +83 -0
  21. data/lib/base/parsers/sax.rb +200 -0
  22. data/lib/base/routines/cache_validator.rb +184 -0
  23. data/lib/base/routines/connection_proxies/net_http_persistent_proxy.rb +194 -0
  24. data/lib/base/routines/connection_proxies/right_http_connection_proxy.rb +224 -0
  25. data/lib/base/routines/connection_proxy.rb +66 -0
  26. data/lib/base/routines/request_analyzer.rb +122 -0
  27. data/lib/base/routines/request_generator.rb +48 -0
  28. data/lib/base/routines/request_initializer.rb +52 -0
  29. data/lib/base/routines/response_analyzer.rb +152 -0
  30. data/lib/base/routines/response_parser.rb +79 -0
  31. data/lib/base/routines/result_wrapper.rb +75 -0
  32. data/lib/base/routines/retry_manager.rb +106 -0
  33. data/lib/base/routines/routine.rb +98 -0
  34. data/lib/right_cloud_api_base.rb +72 -0
  35. data/lib/right_cloud_api_base_version.rb +37 -0
  36. data/right_cloud_api_base.gemspec +63 -0
  37. data/spec/helpers/query_api_pattern_spec.rb +312 -0
  38. data/spec/helpers/support_spec.rb +211 -0
  39. data/spec/helpers/support_xml_spec.rb +207 -0
  40. data/spec/helpers/utils_spec.rb +179 -0
  41. data/spec/routines/connection_proxies/test_net_http_persistent_proxy_spec.rb +143 -0
  42. data/spec/routines/test_cache_validator_spec.rb +152 -0
  43. data/spec/routines/test_connection_proxy_spec.rb +44 -0
  44. data/spec/routines/test_request_analyzer_spec.rb +106 -0
  45. data/spec/routines/test_response_analyzer_spec.rb +132 -0
  46. data/spec/routines/test_response_parser_spec.rb +228 -0
  47. data/spec/routines/test_result_wrapper_spec.rb +63 -0
  48. data/spec/routines/test_retry_manager_spec.rb +84 -0
  49. data/spec/spec_helper.rb +15 -0
  50. 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