vmware-vra 1.5.4 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -1
- data/lib/vra/catalog_item.rb +1 -1
- data/lib/vra/catalog_request.rb +1 -1
- data/lib/vra/client.rb +26 -29
- data/lib/vra/http.rb +142 -0
- data/lib/vra/request.rb +1 -1
- data/lib/vra/resource.rb +2 -2
- data/lib/vra/version.rb +1 -1
- data/spec/catalog_request_spec.rb +1 -1
- data/spec/client_spec.rb +65 -85
- data/spec/http_spec.rb +146 -0
- data/spec/request_spec.rb +2 -2
- data/spec/resource_spec.rb +4 -4
- data/vmware-vra.gemspec +0 -1
- metadata +6 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32967b6a528fdaea4b4c969fcc58ea9f1e84bd1a
|
4
|
+
data.tar.gz: 023a8634851534b756d4651373665802fb96c75b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b54eb12f4e39519bb79fba806443064e019a34a917d9b1710186fa55ce99ecd9571e681b638df8bfadcc5d26398f7235e5476522d4984c293b456b39fdde91a
|
7
|
+
data.tar.gz: e59668d3a5130eb86d671d57bd5ecc83b1b31fb3c7d4b052faf75ce8fd1da241e51440bc2ccf38bd52519c8d70ab70e235d231849457c055b8b58ea795417af6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# vmware-vra-gem CHANGELOG
|
2
2
|
|
3
|
+
## v1.6.0 (2016-05-10)
|
4
|
+
* [pr#28](https://github.com/chef-partners/vmware-vra-gem/pull/28) Remove rest-client dependency
|
5
|
+
|
3
6
|
## v1.5.4 (2016-04-27)
|
4
7
|
* [pr#29](https://github.com/chef-partners/vmware-vra-gem/pull/29) Bug fix: handle more gracefully the situations where a resource or catalog item is missing data in the API response
|
5
8
|
|
@@ -25,7 +28,7 @@
|
|
25
28
|
* [pr#11](https://github.com/chef-partners/vmware-vra-gem/pull/11) Ability to set paginated results page size, which is a workaround for issue reported in #10 regarding duplicate items returned in paginated results.
|
26
29
|
|
27
30
|
## v1.1.0
|
28
|
-
* [pr#9](https://github.com/chef-partners/vmware-vra-gem/pull/9) Mask password and bearer token in console/debug/log output.
|
31
|
+
* [pr#9](https://github.com/chef-partners/vmware-vra-gem/pull/9) Mask password and bearer token in console/debug/log output.
|
29
32
|
Thanks to [@rubytester](https://github.com/rubytester) for the idea and initial proposal to address in [pr#7](https://github.com/chef-partners/vmware-vra-gem/pull/7)
|
30
33
|
|
31
34
|
## v1.0.0
|
data/lib/vra/catalog_item.rb
CHANGED
@@ -42,7 +42,7 @@ module Vra
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def fetch_catalog_item
|
45
|
-
@catalog_item_data =
|
45
|
+
@catalog_item_data = client.get_parsed("/catalog-service/api/consumer/catalogItems/#{id}")
|
46
46
|
rescue Vra::Exception::HTTPNotFound
|
47
47
|
raise Vra::Exception::NotFound, "catalog ID #{id} does not exist"
|
48
48
|
end
|
data/lib/vra/catalog_request.rb
CHANGED
data/lib/vra/client.rb
CHANGED
@@ -17,8 +17,8 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'ffi_yajl'
|
20
|
-
require 'rest-client'
|
21
20
|
require 'passwordmasker'
|
21
|
+
require 'vra/http'
|
22
22
|
|
23
23
|
module Vra
|
24
24
|
# rubocop:disable ClassLength
|
@@ -93,19 +93,17 @@ module Vra
|
|
93
93
|
return false if @bearer_token.value.nil?
|
94
94
|
|
95
95
|
response = http_head("/identity/api/tokens/#{@bearer_token.value}", :skip_auth)
|
96
|
-
|
97
|
-
true
|
98
|
-
else
|
99
|
-
false
|
100
|
-
end
|
96
|
+
response.success_no_content?
|
101
97
|
end
|
102
98
|
|
103
99
|
def generate_bearer_token
|
104
100
|
@bearer_token.value = nil
|
105
101
|
validate_client_options!
|
106
102
|
|
107
|
-
response = http_post('/identity/api/tokens',
|
108
|
-
|
103
|
+
response = http_post('/identity/api/tokens',
|
104
|
+
FFI_Yajl::Encoder.encode(bearer_token_request_body),
|
105
|
+
:skip_auth)
|
106
|
+
unless response.success_ok?
|
109
107
|
raise Vra::Exception::Unauthorized, "Unable to get bearer token: #{response.body}"
|
110
108
|
end
|
111
109
|
|
@@ -116,30 +114,25 @@ module Vra
|
|
116
114
|
"#{@base_url}#{path}"
|
117
115
|
end
|
118
116
|
|
119
|
-
def
|
117
|
+
def http_fetch(method, path, skip_auth=nil)
|
120
118
|
authorize! unless skip_auth
|
121
119
|
|
122
|
-
response =
|
123
|
-
|
124
|
-
|
125
|
-
|
120
|
+
response = Vra::Http.execute(method: method,
|
121
|
+
url: full_url(path),
|
122
|
+
headers: request_headers,
|
123
|
+
verify_ssl: @verify_ssl)
|
126
124
|
rescue => e
|
127
125
|
raise_http_exception(e, path)
|
128
126
|
else
|
129
127
|
response
|
130
128
|
end
|
131
129
|
|
132
|
-
def
|
133
|
-
|
130
|
+
def http_head(path, skip_auth=nil)
|
131
|
+
http_fetch(:head, path, skip_auth)
|
132
|
+
end
|
134
133
|
|
135
|
-
|
136
|
-
|
137
|
-
headers: request_headers,
|
138
|
-
verify_ssl: @verify_ssl)
|
139
|
-
rescue => e
|
140
|
-
raise_http_exception(e, path)
|
141
|
-
else
|
142
|
-
response
|
134
|
+
def http_get(path, skip_auth=nil)
|
135
|
+
http_fetch(:get, path, skip_auth)
|
143
136
|
end
|
144
137
|
|
145
138
|
def http_get!(path)
|
@@ -147,13 +140,17 @@ module Vra
|
|
147
140
|
response.body
|
148
141
|
end
|
149
142
|
|
143
|
+
def get_parsed(path)
|
144
|
+
FFI_Yajl::Parser.parse(http_get!(path))
|
145
|
+
end
|
146
|
+
|
150
147
|
def http_get_paginated_array!(path)
|
151
148
|
items = []
|
152
149
|
page = 1
|
153
150
|
base_path = path + "?limit=#{page_size}"
|
154
151
|
|
155
152
|
loop do
|
156
|
-
response =
|
153
|
+
response = get_parsed("#{base_path}&page=#{page}")
|
157
154
|
items += response['content']
|
158
155
|
|
159
156
|
break if page >= response['metadata']['totalPages']
|
@@ -172,11 +169,11 @@ module Vra
|
|
172
169
|
def http_post(path, payload, skip_auth=nil)
|
173
170
|
authorize! unless skip_auth
|
174
171
|
|
175
|
-
response =
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
172
|
+
response = Vra::Http.execute(method: :post,
|
173
|
+
url: full_url(path),
|
174
|
+
headers: request_headers,
|
175
|
+
payload: payload,
|
176
|
+
verify_ssl: @verify_ssl)
|
180
177
|
rescue => e
|
181
178
|
raise_http_exception(e, path)
|
182
179
|
else
|
data/lib/vra/http.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Vra
|
4
|
+
module Http
|
5
|
+
def self.execute(params)
|
6
|
+
request = Request.new(params)
|
7
|
+
response = request.call
|
8
|
+
response = response.forward(request).call until response.final?
|
9
|
+
fail error(response) unless response.success?
|
10
|
+
response
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.error(response)
|
14
|
+
Error.from_response(response)
|
15
|
+
end
|
16
|
+
|
17
|
+
class Request
|
18
|
+
attr_reader :params
|
19
|
+
|
20
|
+
def initialize(params)
|
21
|
+
@params = params
|
22
|
+
end
|
23
|
+
|
24
|
+
def redirectable?
|
25
|
+
[:get, :head].include?(params[:method])
|
26
|
+
end
|
27
|
+
|
28
|
+
def redirect_to(location)
|
29
|
+
new(url: location)
|
30
|
+
end
|
31
|
+
|
32
|
+
def see_other(location)
|
33
|
+
redirect_to(location).new(method: :get)
|
34
|
+
end
|
35
|
+
|
36
|
+
def call
|
37
|
+
uri = URI(params[:url]) || fail(':url required')
|
38
|
+
|
39
|
+
Net::HTTP.start(uri.host, uri.port,
|
40
|
+
use_ssl: uri.scheme == 'https') do |http|
|
41
|
+
request = http_request(params[:method], uri)
|
42
|
+
request.initialize_http_header(params[:headers] || {})
|
43
|
+
request.body = params[:payload] || ''
|
44
|
+
|
45
|
+
Response.new(http.request(request))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def http_request(method, uri)
|
50
|
+
type = {
|
51
|
+
get: Net::HTTP::Get,
|
52
|
+
head: Net::HTTP::Head,
|
53
|
+
post: Net::HTTP::Post
|
54
|
+
}.fetch(method, nil)
|
55
|
+
|
56
|
+
fail "Unknown HTTP method #{method}!" unless type
|
57
|
+
|
58
|
+
type.new(uri)
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def new(new_params)
|
64
|
+
self.class.new(params.dup.merge(new_params))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Response
|
69
|
+
# For hiding the details of the HTTP response class
|
70
|
+
# so it can be swapped out easily
|
71
|
+
def initialize(response)
|
72
|
+
@response = response
|
73
|
+
end
|
74
|
+
|
75
|
+
def forward(request)
|
76
|
+
if redirect?
|
77
|
+
fail Http.error(self) unless request.redirectable?
|
78
|
+
request.redirect_to(location)
|
79
|
+
elsif see_other?
|
80
|
+
request.see_other(location)
|
81
|
+
else
|
82
|
+
request
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def location
|
87
|
+
@response['location']
|
88
|
+
end
|
89
|
+
|
90
|
+
def body
|
91
|
+
@response.body
|
92
|
+
end
|
93
|
+
|
94
|
+
def code
|
95
|
+
@response.code.to_i
|
96
|
+
end
|
97
|
+
|
98
|
+
def message
|
99
|
+
@response.message
|
100
|
+
end
|
101
|
+
|
102
|
+
def success_ok?
|
103
|
+
code == 200
|
104
|
+
end
|
105
|
+
|
106
|
+
def success_no_content?
|
107
|
+
code == 204
|
108
|
+
end
|
109
|
+
|
110
|
+
def success?
|
111
|
+
(200..207).cover?(code)
|
112
|
+
end
|
113
|
+
|
114
|
+
def redirect?
|
115
|
+
[301, 302, 307].include?(code)
|
116
|
+
end
|
117
|
+
|
118
|
+
def see_other?
|
119
|
+
code == 303
|
120
|
+
end
|
121
|
+
|
122
|
+
def final?
|
123
|
+
!(redirect? || see_other?)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Error < StandardError
|
128
|
+
def self.from_response(http_response)
|
129
|
+
new(http_response.message, http_response.code, http_response.body)
|
130
|
+
end
|
131
|
+
|
132
|
+
attr_reader :http_code
|
133
|
+
attr_reader :response
|
134
|
+
|
135
|
+
def initialize(message, http_code, response)
|
136
|
+
super(message)
|
137
|
+
@http_code = http_code
|
138
|
+
@response = response
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/vra/request.rb
CHANGED
@@ -32,7 +32,7 @@ module Vra
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def refresh
|
35
|
-
@request_data =
|
35
|
+
@request_data = client.get_parsed("/catalog-service/api/consumer/requests/#{@id}")
|
36
36
|
rescue Vra::Exception::HTTPNotFound
|
37
37
|
raise Vra::Exception::NotFound, "request ID #{@id} is not found"
|
38
38
|
end
|
data/lib/vra/resource.rb
CHANGED
@@ -45,7 +45,7 @@ module Vra
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def fetch_resource_data
|
48
|
-
@resource_data =
|
48
|
+
@resource_data = client.get_parsed("/catalog-service/api/consumer/resources/#{@id}")
|
49
49
|
rescue Vra::Exception::HTTPNotFound
|
50
50
|
raise Vra::Exception::NotFound, "resource ID #{@id} does not exist"
|
51
51
|
end
|
@@ -239,7 +239,7 @@ module Vra
|
|
239
239
|
def submit_action_request(action_id)
|
240
240
|
payload = action_request_payload(action_id).to_json
|
241
241
|
response = client.http_post('/catalog-service/api/consumer/requests', payload)
|
242
|
-
request_id = response.
|
242
|
+
request_id = response.location.split('/')[-1]
|
243
243
|
Vra::Request.new(client, request_id)
|
244
244
|
end
|
245
245
|
end
|
data/lib/vra/version.rb
CHANGED
@@ -106,7 +106,7 @@ describe Vra::CatalogRequest do
|
|
106
106
|
describe '#submit' do
|
107
107
|
before do
|
108
108
|
allow(request).to receive(:request_payload).and_return({})
|
109
|
-
response = double('response',
|
109
|
+
response = double('response', location: '/requests/request-12345')
|
110
110
|
allow(client).to receive(:http_post).with('/catalog-service/api/consumer/requests', '{}').and_return(response)
|
111
111
|
end
|
112
112
|
|
data/spec/client_spec.rb
CHANGED
@@ -104,20 +104,16 @@ describe Vra::Client do
|
|
104
104
|
client.bearer_token = '12345'
|
105
105
|
end
|
106
106
|
|
107
|
-
url = '/identity/api/tokens/12345'
|
108
|
-
|
109
107
|
it 'returns true if the token validates successfully' do
|
110
|
-
response = double('response')
|
111
|
-
allow(
|
112
|
-
allow(client).to receive(:http_head).with(url, :skip_auth).and_return(response)
|
108
|
+
response = double('response', success_no_content?: true, code: 204)
|
109
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
113
110
|
|
114
111
|
expect(client.authorized?).to be true
|
115
112
|
end
|
116
113
|
|
117
114
|
it 'returns false if the token validates unsuccessfully' do
|
118
|
-
response = double('response')
|
119
|
-
allow(
|
120
|
-
allow(client).to receive(:http_head).with(url, :skip_auth).and_return(response)
|
115
|
+
response = double('response', success_no_content?: false, code: 500)
|
116
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
121
117
|
|
122
118
|
expect(client.authorized?).to be false
|
123
119
|
end
|
@@ -132,24 +128,22 @@ describe Vra::Client do
|
|
132
128
|
}.to_json
|
133
129
|
|
134
130
|
it 'posts to the tokens API endpoint' do
|
135
|
-
response = double('response')
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
131
|
+
response = double('response', code: 200, body: '{"id":"12345"}', success_ok?: true)
|
132
|
+
expect(Vra::Http).to receive(:execute)
|
133
|
+
.with(method: :post,
|
134
|
+
url: client.full_url('/identity/api/tokens'),
|
135
|
+
payload: payload,
|
136
|
+
headers: anything,
|
137
|
+
verify_ssl: true)
|
138
|
+
.and_return(response)
|
141
139
|
|
142
140
|
client.generate_bearer_token
|
143
141
|
end
|
144
142
|
|
145
143
|
context 'when token is generated successfully' do
|
146
144
|
it 'sets the token' do
|
147
|
-
response = double('response')
|
148
|
-
allow(
|
149
|
-
allow(response).to receive(:body).and_return('{"id":"12345"}')
|
150
|
-
allow(client).to receive(:http_post).with('/identity/api/tokens',
|
151
|
-
payload,
|
152
|
-
:skip_auth).and_return(response)
|
145
|
+
response = double('response', code: 200, body: '{"id":"12345"}', success_ok?: true)
|
146
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
153
147
|
|
154
148
|
client.generate_bearer_token
|
155
149
|
|
@@ -159,13 +153,8 @@ describe Vra::Client do
|
|
159
153
|
|
160
154
|
context 'when token is not generated successfully' do
|
161
155
|
it 'raises an exception' do
|
162
|
-
response = double('response')
|
163
|
-
allow(
|
164
|
-
allow(response).to receive(:body).and_return('error string')
|
165
|
-
allow(client).to receive(:http_post).with('/identity/api/tokens',
|
166
|
-
payload,
|
167
|
-
:skip_auth)
|
168
|
-
.and_return(response)
|
156
|
+
response = double('response', code: 500, body: 'error string', success_ok?: false)
|
157
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
169
158
|
|
170
159
|
expect { client.generate_bearer_token }.to raise_error(Vra::Exception::Unauthorized)
|
171
160
|
end
|
@@ -182,7 +171,7 @@ describe Vra::Client do
|
|
182
171
|
context 'when skip_auth is nil' do
|
183
172
|
it 'authorizes before proceeding' do
|
184
173
|
response = double('response')
|
185
|
-
allow(
|
174
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
186
175
|
expect(client).to receive(:authorize!)
|
187
176
|
|
188
177
|
client.http_head('/test')
|
@@ -192,14 +181,14 @@ describe Vra::Client do
|
|
192
181
|
context 'when skip_auth is not nil' do
|
193
182
|
it 'does not authorize before proceeding' do
|
194
183
|
response = double('response')
|
195
|
-
allow(
|
184
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
196
185
|
expect(client).to_not receive(:authorize!)
|
197
186
|
|
198
187
|
client.http_head('/test', :skip_auth)
|
199
188
|
end
|
200
189
|
end
|
201
190
|
|
202
|
-
it 'calls
|
191
|
+
it 'calls Vra::Http.execute' do
|
203
192
|
response = double('response')
|
204
193
|
path = '/test'
|
205
194
|
full_url = 'https://vra.corp.local/test'
|
@@ -207,21 +196,21 @@ describe Vra::Client do
|
|
207
196
|
verify_ssl = true
|
208
197
|
|
209
198
|
allow(client).to receive(:authorize!)
|
210
|
-
expect(
|
211
|
-
|
212
|
-
|
213
|
-
|
199
|
+
expect(Vra::Http).to receive(:execute).with(method: :head,
|
200
|
+
url: full_url,
|
201
|
+
headers: headers,
|
202
|
+
verify_ssl: verify_ssl)
|
214
203
|
.and_return(response)
|
215
204
|
|
216
205
|
client.http_head(path)
|
217
206
|
end
|
218
207
|
|
219
|
-
it '
|
208
|
+
it 'raises an HTTPNotFound on a 404 error' do
|
220
209
|
allow(client).to receive(:authorize!)
|
221
|
-
allow(
|
222
|
-
|
210
|
+
allow(Vra::Http).to receive(:execute)
|
211
|
+
.and_raise(Vra::Http::Error.new('message', 404, 'Not Found'))
|
223
212
|
|
224
|
-
client.http_head('/404')
|
213
|
+
expect { client.http_head('/404') }.to raise_error(Vra::Exception::HTTPNotFound)
|
225
214
|
end
|
226
215
|
end
|
227
216
|
|
@@ -229,7 +218,7 @@ describe Vra::Client do
|
|
229
218
|
context 'when skip_auth is nil' do
|
230
219
|
it 'authorizes before proceeding' do
|
231
220
|
response = double('response')
|
232
|
-
allow(
|
221
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
233
222
|
expect(client).to receive(:authorize!)
|
234
223
|
|
235
224
|
client.http_get('/test')
|
@@ -239,14 +228,14 @@ describe Vra::Client do
|
|
239
228
|
context 'when skip_auth is not nil' do
|
240
229
|
it 'does not authorize before proceeding' do
|
241
230
|
response = double('response')
|
242
|
-
allow(
|
231
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
243
232
|
expect(client).to_not receive(:authorize!)
|
244
233
|
|
245
234
|
client.http_get('/test', :skip_auth)
|
246
235
|
end
|
247
236
|
end
|
248
237
|
|
249
|
-
it 'calls
|
238
|
+
it 'calls Vra::Http.execute' do
|
250
239
|
response = double('response')
|
251
240
|
path = '/test'
|
252
241
|
full_url = 'https://vra.corp.local/test'
|
@@ -254,79 +243,70 @@ describe Vra::Client do
|
|
254
243
|
verify_ssl = true
|
255
244
|
|
256
245
|
allow(client).to receive(:authorize!)
|
257
|
-
expect(
|
258
|
-
|
259
|
-
|
260
|
-
|
246
|
+
expect(Vra::Http).to receive(:execute).with(method: :get,
|
247
|
+
url: full_url,
|
248
|
+
headers: headers,
|
249
|
+
verify_ssl: verify_ssl)
|
261
250
|
.and_return(response)
|
262
251
|
|
263
252
|
client.http_get(path)
|
264
253
|
end
|
265
254
|
|
266
|
-
it '
|
255
|
+
it 'raises an HTTPNotFound on a 404 error' do
|
267
256
|
allow(client).to receive(:authorize!)
|
268
|
-
allow(
|
269
|
-
|
270
|
-
|
271
|
-
client.http_get('/404')
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
describe '#http_get!' do
|
276
|
-
it 'returns the response body' do
|
277
|
-
response = double('response', body: 'body text')
|
278
|
-
allow(client).to receive(:http_get).with('/test').and_return(response)
|
257
|
+
allow(Vra::Http).to receive(:execute)
|
258
|
+
.and_raise(Vra::Http::Error.new('message', 404, 'Not Found'))
|
279
259
|
|
280
|
-
expect
|
260
|
+
expect { client.http_get('/404') }.to raise_error(Vra::Exception::HTTPNotFound)
|
281
261
|
end
|
282
262
|
end
|
283
263
|
|
284
264
|
describe '#http_get_paginated_array!' do
|
285
265
|
it 'allows a limit override' do
|
286
266
|
client.page_size = 10
|
287
|
-
expect(client).to receive(:
|
267
|
+
expect(client).to receive(:get_parsed)
|
288
268
|
.with('/test?limit=10&page=1')
|
289
|
-
.and_return(
|
269
|
+
.and_return('content' => [], 'metadata' => { 'totalPages' => 1 })
|
290
270
|
|
291
271
|
client.http_get_paginated_array!('/test')
|
292
272
|
end
|
293
273
|
|
294
|
-
it 'only calls
|
295
|
-
expect(client).to receive(:
|
274
|
+
it 'only calls get_parsed once when total pages is 0 (no items)' do
|
275
|
+
expect(client).to receive(:get_parsed)
|
296
276
|
.once
|
297
277
|
.with('/test?limit=20&page=1')
|
298
|
-
.and_return(
|
278
|
+
.and_return('content' => [], 'metadata' => { 'totalPages' => 0 })
|
299
279
|
|
300
280
|
client.http_get_paginated_array!('/test')
|
301
281
|
end
|
302
282
|
|
303
|
-
it 'only calls
|
304
|
-
expect(client).to receive(:
|
283
|
+
it 'only calls get_parsed once when total pages is 1' do
|
284
|
+
expect(client).to receive(:get_parsed)
|
305
285
|
.once
|
306
286
|
.with('/test?limit=20&page=1')
|
307
|
-
.and_return(
|
287
|
+
.and_return('content' => [], 'metadata' => { 'totalPages' => 1 })
|
308
288
|
|
309
289
|
client.http_get_paginated_array!('/test')
|
310
290
|
end
|
311
291
|
|
312
|
-
it 'calls
|
313
|
-
expect(client).to receive(:
|
292
|
+
it 'calls get_parsed 3 times if there are 3 pages of response' do
|
293
|
+
expect(client).to receive(:get_parsed)
|
314
294
|
.with('/test?limit=20&page=1')
|
315
|
-
.and_return(
|
316
|
-
expect(client).to receive(:
|
295
|
+
.and_return('content' => [], 'metadata' => { 'totalPages' => 3 })
|
296
|
+
expect(client).to receive(:get_parsed)
|
317
297
|
.with('/test?limit=20&page=2')
|
318
|
-
.and_return(
|
319
|
-
expect(client).to receive(:
|
298
|
+
.and_return('content' => [], 'metadata' => { 'totalPages' => 3 })
|
299
|
+
expect(client).to receive(:get_parsed)
|
320
300
|
.with('/test?limit=20&page=3')
|
321
|
-
.and_return(
|
301
|
+
.and_return('content' => [], 'metadata' => { 'totalPages' => 3 })
|
322
302
|
|
323
303
|
client.http_get_paginated_array!('/test')
|
324
304
|
end
|
325
305
|
|
326
306
|
it 'raises an exception if duplicate items are returned by the API' do
|
327
|
-
allow(client).to receive(:
|
307
|
+
allow(client).to receive(:get_parsed)
|
328
308
|
.with('/test?limit=20&page=1')
|
329
|
-
.and_return(
|
309
|
+
.and_return('content' => [ 1, 2, 3, 1 ], 'metadata' => { 'totalPages' => 1 })
|
330
310
|
|
331
311
|
expect { client.http_get_paginated_array!('/test') }.to raise_error(Vra::Exception::DuplicateItemsDetected)
|
332
312
|
end
|
@@ -336,7 +316,7 @@ describe Vra::Client do
|
|
336
316
|
context 'when skip_auth is nil' do
|
337
317
|
it 'authorizes before proceeding' do
|
338
318
|
response = double('response')
|
339
|
-
allow(
|
319
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
340
320
|
expect(client).to receive(:authorize!)
|
341
321
|
|
342
322
|
client.http_post('/test', 'some payload')
|
@@ -346,14 +326,14 @@ describe Vra::Client do
|
|
346
326
|
context 'when skip_auth is not nil' do
|
347
327
|
it 'does not authorize before proceeding' do
|
348
328
|
response = double('response')
|
349
|
-
allow(
|
329
|
+
allow(Vra::Http).to receive(:execute).and_return(response)
|
350
330
|
expect(client).to_not receive(:authorize!)
|
351
331
|
|
352
332
|
client.http_post('/test', 'some payload', :skip_auth)
|
353
333
|
end
|
354
334
|
end
|
355
335
|
|
356
|
-
it 'calls
|
336
|
+
it 'calls Vra::Http.execute' do
|
357
337
|
response = double('response')
|
358
338
|
path = '/test'
|
359
339
|
full_url = 'https://vra.corp.local/test'
|
@@ -362,19 +342,19 @@ describe Vra::Client do
|
|
362
342
|
verify_ssl = true
|
363
343
|
|
364
344
|
allow(client).to receive(:authorize!)
|
365
|
-
expect(
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
345
|
+
expect(Vra::Http).to receive(:execute).with(method: :post,
|
346
|
+
url: full_url,
|
347
|
+
headers: headers,
|
348
|
+
payload: payload,
|
349
|
+
verify_ssl: verify_ssl)
|
370
350
|
.and_return(response)
|
371
351
|
|
372
352
|
client.http_post(path, payload)
|
373
353
|
end
|
374
354
|
|
375
|
-
it 'calls raise_http_exception upon
|
355
|
+
it 'calls raise_http_exception upon error' do
|
376
356
|
allow(client).to receive(:authorize!)
|
377
|
-
allow(
|
357
|
+
allow(Vra::Http).to receive(:execute).and_raise(StandardError)
|
378
358
|
expect(client).to receive(:raise_http_exception)
|
379
359
|
|
380
360
|
client.http_post('/404', 'test payload')
|
data/spec/http_spec.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'webmock'
|
3
|
+
|
4
|
+
describe Vra::Http do
|
5
|
+
def expecting_request(method, url, with=nil)
|
6
|
+
stub = stub_request(method, url)
|
7
|
+
stub.with(with) if with
|
8
|
+
yield if block_given?
|
9
|
+
expect(stub).to have_been_requested
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute(method, params)
|
13
|
+
Vra::Http.execute(params.merge(method: method))
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(params)
|
17
|
+
execute :get, params
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(params)
|
21
|
+
execute :post, params
|
22
|
+
end
|
23
|
+
|
24
|
+
def head(params)
|
25
|
+
execute :head, params
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#execute' do
|
29
|
+
it 'makes a HEAD request' do
|
30
|
+
headers = { 'X-Made-Up-Header' => 'Foo AND bar? Are you sure?' }
|
31
|
+
|
32
|
+
expecting_request(:head, 'http://test.local', headers: headers) do
|
33
|
+
head url: 'http://test.local', headers: headers
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'makes a GET request' do
|
38
|
+
headers = { 'X-Made-Up-Header' => 'Foo AND bar? Are you sure?' }
|
39
|
+
|
40
|
+
expecting_request(:get, 'http://test.local', headers: headers) do
|
41
|
+
get url: 'http://test.local', headers: headers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'makes a POST request' do
|
46
|
+
headers = { 'X-Made-Up-Header' => 'Foo AND bar? Are you sure?' }
|
47
|
+
payload = 'withabodylikethis'
|
48
|
+
|
49
|
+
expecting_request(:post, 'http://test.local', headers: headers, body: payload) do
|
50
|
+
post url: 'http://test.local', headers: headers, payload: payload
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'preserves Location' do
|
55
|
+
stub_request(:head, 'http://test.local')
|
56
|
+
.to_return(headers: { 'Location' => 'http://test-location.local' })
|
57
|
+
|
58
|
+
response = head(url: 'http://test.local')
|
59
|
+
|
60
|
+
expect(response.location).to eq 'http://test-location.local'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'preserves status code' do
|
64
|
+
stub_request(:head, 'http://test.local')
|
65
|
+
.to_return(status: [204, 'No content'])
|
66
|
+
|
67
|
+
response = head(url: 'http://test.local')
|
68
|
+
|
69
|
+
expect(response.code).to eq 204
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when successful' do
|
73
|
+
it 'returns a successful response given a status 200' do
|
74
|
+
stub_request(:head, 'http://test.local')
|
75
|
+
.to_return(status: [200, 'Whatevs'])
|
76
|
+
|
77
|
+
response = head(url: 'http://test.local')
|
78
|
+
|
79
|
+
expect(response.success_ok?).to be_truthy
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns a successful response given a status 204' do
|
83
|
+
stub_request(:head, 'http://test.local')
|
84
|
+
.to_return(status: [204, 'Whatevs'])
|
85
|
+
|
86
|
+
response = head(url: 'http://test.local')
|
87
|
+
|
88
|
+
expect(response.success_no_content?).to be_truthy
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when unsuccessful' do
|
93
|
+
(400..418).each do |status|
|
94
|
+
it 'raises an exception given a status #{status}' do
|
95
|
+
stub_request(:get, 'http://test.local')
|
96
|
+
.to_return(status: [status, 'Whatevs'],
|
97
|
+
body: 'Error body')
|
98
|
+
|
99
|
+
expect { get(url: 'http://test.local') }.to raise_error do |error|
|
100
|
+
expect(error).to be_a(StandardError)
|
101
|
+
expect(error.http_code).to eq status
|
102
|
+
expect(error.response).to eq 'Error body'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when redirected' do
|
109
|
+
[301, 302, 307].each do |status|
|
110
|
+
[:get, :head].each do |method|
|
111
|
+
it "follows #{status} redirected #{method.to_s.upcase} requests" do
|
112
|
+
stub_request(method, 'http://test.local')
|
113
|
+
.to_return(status: [status, 'redirect'],
|
114
|
+
headers: { 'Location' => 'http://test.local/redirect' })
|
115
|
+
expecting_request(method, 'http://test.local/redirect') do
|
116
|
+
execute(method, url: 'http://test.local')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "does not follow #{status} redirected POST requests" do
|
122
|
+
stub_request(:post, 'http://test.local')
|
123
|
+
.to_return(status: [status, 'redirect'],
|
124
|
+
headers: { 'Location' => 'http://test.local/redirect' })
|
125
|
+
|
126
|
+
expect { post(url: 'http://test.local') }.to raise_error do |error|
|
127
|
+
expect(error).to be_a(StandardError)
|
128
|
+
expect(error.http_code).to eq status
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
[:head, :post].each do |method|
|
134
|
+
it "converts #{method.to_s.upcase} to GET on 303 redirect" do
|
135
|
+
stub_request(method, 'http://test.local')
|
136
|
+
.to_return(status: [303, 'See Other'],
|
137
|
+
headers: { 'Location' => 'http://test.local/redirect' })
|
138
|
+
|
139
|
+
expecting_request(:get, 'http://test.local/redirect') do
|
140
|
+
execute method, url: 'http://test.local'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/spec/request_spec.rb
CHANGED
@@ -71,9 +71,9 @@ describe Vra::Request do
|
|
71
71
|
|
72
72
|
describe '#refresh' do
|
73
73
|
it 'calls the request API endpoint' do
|
74
|
-
expect(client).to receive(:
|
74
|
+
expect(client).to receive(:get_parsed)
|
75
75
|
.with("/catalog-service/api/consumer/requests/#{request_id}")
|
76
|
-
.and_return(in_progress_payload
|
76
|
+
.and_return(in_progress_payload)
|
77
77
|
|
78
78
|
request.refresh
|
79
79
|
end
|
data/spec/resource_spec.rb
CHANGED
@@ -92,10 +92,10 @@ describe Vra::Resource do
|
|
92
92
|
end
|
93
93
|
|
94
94
|
describe '#fetch_resource_data' do
|
95
|
-
it 'calls
|
96
|
-
expect(client).to receive(:
|
95
|
+
it 'calls get_parsed against the resources API endpoint' do
|
96
|
+
expect(client).to receive(:get_parsed)
|
97
97
|
.with("/catalog-service/api/consumer/resources/#{resource_id}")
|
98
|
-
.and_return(
|
98
|
+
.and_return({})
|
99
99
|
|
100
100
|
Vra::Resource.new(client, id: resource_id)
|
101
101
|
end
|
@@ -356,7 +356,7 @@ describe Vra::Resource do
|
|
356
356
|
describe '#submit_action_request' do
|
357
357
|
before do
|
358
358
|
allow(resource).to receive(:action_request_payload).and_return({})
|
359
|
-
response = double('response',
|
359
|
+
response = double('response', location: '/requests/request-12345')
|
360
360
|
allow(client).to receive(:http_post).with('/catalog-service/api/consumer/requests', '{}').and_return(response)
|
361
361
|
end
|
362
362
|
|
data/vmware-vra.gemspec
CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency 'rest-client', '~> 1.8'
|
22
21
|
spec.add_dependency 'ffi-yajl', '~> 2.2'
|
23
22
|
spec.add_dependency 'passwordmasker', '~> 1.2'
|
24
23
|
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vmware-vra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Leff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: rest-client
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.8'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.8'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: ffi-yajl
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,6 +143,7 @@ files:
|
|
157
143
|
- lib/vra/catalog_request.rb
|
158
144
|
- lib/vra/client.rb
|
159
145
|
- lib/vra/exceptions.rb
|
146
|
+
- lib/vra/http.rb
|
160
147
|
- lib/vra/request.rb
|
161
148
|
- lib/vra/request_parameters.rb
|
162
149
|
- lib/vra/requests.rb
|
@@ -170,6 +157,7 @@ files:
|
|
170
157
|
- spec/fixtures/resource/non_vm_resource.json
|
171
158
|
- spec/fixtures/resource/vm_resource.json
|
172
159
|
- spec/fixtures/resource/vm_resource_no_operations.json
|
160
|
+
- spec/http_spec.rb
|
173
161
|
- spec/request_spec.rb
|
174
162
|
- spec/requests_spec.rb
|
175
163
|
- spec/resource_spec.rb
|
@@ -196,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
184
|
version: '0'
|
197
185
|
requirements: []
|
198
186
|
rubyforge_project:
|
199
|
-
rubygems_version: 2.
|
187
|
+
rubygems_version: 2.2.2
|
200
188
|
signing_key:
|
201
189
|
specification_version: 4
|
202
190
|
summary: Client gem for interacting with VMware vRealize Automation.
|
@@ -208,6 +196,7 @@ test_files:
|
|
208
196
|
- spec/fixtures/resource/non_vm_resource.json
|
209
197
|
- spec/fixtures/resource/vm_resource.json
|
210
198
|
- spec/fixtures/resource/vm_resource_no_operations.json
|
199
|
+
- spec/http_spec.rb
|
211
200
|
- spec/request_spec.rb
|
212
201
|
- spec/requests_spec.rb
|
213
202
|
- spec/resource_spec.rb
|