vra-restapi 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,59 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'spec_helper'
20
+
21
+ describe Vra::Requests do
22
+ let(:client) do
23
+ Vra::Client.new(username: 'user@corp.local',
24
+ password: 'password',
25
+ tenant: 'tenant',
26
+ base_url: 'https://vra.corp.local')
27
+ end
28
+
29
+ let(:requests) { Vra::Requests.new(client) }
30
+
31
+ describe '#all_resources' do
32
+ it 'calls the requests API endpoint' do
33
+ expect(client).to receive(:http_get_paginated_array!)
34
+ .with('/catalog-service/api/consumer/requests')
35
+ .and_return([])
36
+
37
+ requests.all_requests
38
+ end
39
+
40
+ it 'returns an array of request objects' do
41
+ allow(client).to receive(:http_get_paginated_array!)
42
+ .with('/catalog-service/api/consumer/requests')
43
+ .and_return([ { 'id' => '1' }, { 'id' => '2' } ])
44
+
45
+ items = requests.all_requests
46
+
47
+ expect(items[0]).to be_an_instance_of(Vra::Request)
48
+ expect(items[1]).to be_an_instance_of(Vra::Request)
49
+ end
50
+ end
51
+
52
+ describe '#by_id' do
53
+ it 'returns a request object' do
54
+ expect(Vra::Request).to receive(:new).with(client, '12345')
55
+
56
+ requests.by_id('12345')
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,394 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'spec_helper'
20
+ require 'json'
21
+
22
+ shared_examples_for 'a resource action' do |action_method, action_name|
23
+ context 'when the action is available' do
24
+ it 'calls gets the action ID and submits the request' do
25
+ expect(resource).to receive(:action_id_by_name).with(action_name).and_return('action-123')
26
+ expect(resource).to receive(:submit_action_request).with('action-123')
27
+ resource.send(action_method)
28
+ end
29
+ end
30
+
31
+ context 'when the action is not available' do
32
+ it 'raises an exception' do
33
+ expect(resource).to receive(:action_id_by_name).with(action_name).and_return nil
34
+ expect { resource.send(action_method) }.to raise_error(Vra::Exception::NotFound)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe Vra::Resource do
40
+ let(:client) do
41
+ Vra::Client.new(username: 'user@corp.local',
42
+ password: 'password',
43
+ tenant: 'tenant',
44
+ base_url: 'https://vra.corp.local')
45
+ end
46
+
47
+ let(:resource_id) { '31a7badc-6562-458d-84f3-ec58d74a6953' }
48
+ let(:vm_payload) do
49
+ JSON.parse(File.read(File.join(File.dirname(__FILE__),
50
+ 'fixtures',
51
+ 'resource',
52
+ 'vm_resource.json')))
53
+ end
54
+
55
+ let(:vm_payload_no_ops) do
56
+ JSON.parse(File.read(File.join(File.dirname(__FILE__),
57
+ 'fixtures',
58
+ 'resource',
59
+ 'vm_resource_no_operations.json')))
60
+ end
61
+
62
+ let(:non_vm_payload) do
63
+ JSON.parse(File.read(File.join(File.dirname(__FILE__),
64
+ 'fixtures',
65
+ 'resource',
66
+ 'non_vm_resource.json')))
67
+ end
68
+
69
+ describe '#initialize' do
70
+ it 'raises an error if no ID or resource data have been provided' do
71
+ expect { Vra::Resource.new }.to raise_error(ArgumentError)
72
+ end
73
+
74
+ it 'raises an error if an ID and resource data have both been provided' do
75
+ expect { Vra::Resource.new(id: 123, data: 'foo') }.to raise_error(ArgumentError)
76
+ end
77
+
78
+ context 'when an ID is provided' do
79
+ it 'calls fetch_resource_data' do
80
+ resource = Vra::Resource.allocate
81
+ expect(resource).to receive(:fetch_resource_data)
82
+ resource.send(:initialize, client, id: resource_id)
83
+ end
84
+ end
85
+
86
+ context 'when resource data is provided' do
87
+ it 'populates the ID correctly' do
88
+ resource = Vra::Resource.new(client, data: vm_payload)
89
+ expect(resource.id).to eq resource_id
90
+ end
91
+ end
92
+ end
93
+
94
+ describe '#fetch_resource_data' do
95
+ it 'calls http_get! against the resources API endpoint' do
96
+ expect(client).to receive(:http_get!)
97
+ .with("/catalog-service/api/consumer/resources/#{resource_id}")
98
+ .and_return("{}")
99
+
100
+ Vra::Resource.new(client, id: resource_id)
101
+ end
102
+ end
103
+
104
+ context 'when a valid VM resource instance has been created' do
105
+ let(:resource) { Vra::Resource.new(client, data: vm_payload) }
106
+
107
+ describe '#name' do
108
+ it 'returns the correct name' do
109
+ expect(resource.name).to eq 'hol-dev-11'
110
+ end
111
+ end
112
+
113
+ describe '#description' do
114
+ it 'returns the correct description' do
115
+ expect(resource.description).to eq 'test-description'
116
+ end
117
+ end
118
+
119
+ describe '#status' do
120
+ it 'returns the correct status' do
121
+ expect(resource.status).to eq 'ACTIVE'
122
+ end
123
+ end
124
+
125
+ describe '#vm?' do
126
+ context 'when the resource type is Infrastructure.Virtual' do
127
+ let(:resource_data) { { 'resourceTypeRef' => { 'id' => 'Infrastructure.Virtual' } } }
128
+ it 'returns true' do
129
+ allow(resource).to receive(:resource_data).and_return(resource_data)
130
+ expect(resource.vm?).to eq(true)
131
+ end
132
+ end
133
+
134
+ context 'when the resource type is Infrastructure.Cloud' do
135
+ let(:resource_data) { { 'resourceTypeRef' => { 'id' => 'Infrastructure.Cloud' } } }
136
+ it 'returns true' do
137
+ allow(resource).to receive(:resource_data).and_return(resource_data)
138
+ expect(resource.vm?).to eq(true)
139
+ end
140
+ end
141
+
142
+ context 'when the resource type is an unknown type' do
143
+ let(:resource_data) { { 'resourceTypeRef' => { 'id' => 'Infrastructure.Unknown' } } }
144
+ it 'returns false' do
145
+ allow(resource).to receive(:resource_data).and_return(resource_data)
146
+ expect(resource.vm?).to eq(false)
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '#tenant_id' do
152
+ it 'returns the correct tenant ID' do
153
+ expect(resource.tenant_id).to eq 'vsphere.local'
154
+ end
155
+ end
156
+
157
+ describe '#tenant_name' do
158
+ it 'returns the correct tenant name' do
159
+ expect(resource.tenant_name).to eq 'vsphere.local'
160
+ end
161
+ end
162
+
163
+ describe '#subtenant_id' do
164
+ it 'returns the correct subtenant ID' do
165
+ expect(resource.subtenant_id).to eq '5327ddd3-1a4e-4663-9e9d-63db86ffc8af'
166
+ end
167
+ end
168
+
169
+ describe '#subtenant_name' do
170
+ it 'returns the correct subtenant name' do
171
+ expect(resource.subtenant_name).to eq 'Rainpole Developers'
172
+ end
173
+ end
174
+
175
+ describe '#owner_ids' do
176
+ it 'returns the correct owner IDs' do
177
+ expect(resource.owner_ids).to eq %w(user1@corp.local user2@corp.local)
178
+ end
179
+ end
180
+
181
+ describe '#owner_names' do
182
+ it 'returns the correct owner names' do
183
+ expect(resource.owner_names).to eq [ 'Joe User', 'Jane User' ]
184
+ end
185
+ end
186
+
187
+ describe '#machine_status' do
188
+ context 'when no MachineStatus exists' do
189
+ let(:resource_data) { { 'resourceData' => { 'entries' => [] } } }
190
+
191
+ it 'raises an exception' do
192
+ allow(resource).to receive(:resource_data).and_return(resource_data)
193
+ expect { resource.machine_status }.to raise_error(RuntimeError)
194
+ end
195
+ end
196
+
197
+ context 'when MachineStatus Exists' do
198
+ let(:resource_data) do
199
+ {
200
+ 'resourceData' => {
201
+ 'entries' => [
202
+ {
203
+ 'key' => 'MachineStatus',
204
+ 'value' => { 'type' => 'string', 'value' => 'Off' }
205
+ }
206
+ ]
207
+ }
208
+ }
209
+ end
210
+
211
+ it 'returns the correct status value' do
212
+ allow(resource).to receive(:resource_data).and_return(resource_data)
213
+ expect(resource.machine_status).to eq('Off')
214
+ end
215
+ end
216
+ end
217
+
218
+ describe '#machine_on?' do
219
+ it 'returns true if the machine_status is On' do
220
+ allow(resource).to receive(:machine_status).and_return('On')
221
+ expect(resource.machine_on?).to eq(true)
222
+ end
223
+
224
+ it 'returns false if the machine_status is not On' do
225
+ allow(resource).to receive(:machine_status).and_return('Off')
226
+ expect(resource.machine_on?).to eq(false)
227
+ end
228
+ end
229
+
230
+ describe '#machine_off?' do
231
+ it 'returns true if the machine_status is Off' do
232
+ allow(resource).to receive(:machine_status).and_return('Off')
233
+ expect(resource.machine_off?).to eq(true)
234
+ end
235
+
236
+ it 'returns false if the machine_status is not Off' do
237
+ allow(resource).to receive(:machine_status).and_return('On')
238
+ expect(resource.machine_off?).to eq(false)
239
+ end
240
+ end
241
+
242
+ describe '#machine_turning_on?' do
243
+ it 'returns true if the machine_status is TurningOn' do
244
+ allow(resource).to receive(:machine_status).and_return('TurningOn')
245
+ expect(resource.machine_turning_on?).to eq(true)
246
+ end
247
+
248
+ it 'returns true if the machine_status is MachineActivated' do
249
+ allow(resource).to receive(:machine_status).and_return('MachineActivated')
250
+ expect(resource.machine_turning_on?).to eq(true)
251
+ end
252
+
253
+ it 'returns false if the machine_status is not TurningOn' do
254
+ allow(resource).to receive(:machine_status).and_return('On')
255
+ expect(resource.machine_turning_on?).to eq(false)
256
+ end
257
+ end
258
+
259
+ describe '#machine_turning_off?' do
260
+ it 'returns true if the machine_status is TurningOff' do
261
+ allow(resource).to receive(:machine_status).and_return('TurningOff')
262
+ expect(resource.machine_turning_off?).to eq(true)
263
+ end
264
+
265
+ it 'returns true if the machine_status is ShuttingDown' do
266
+ allow(resource).to receive(:machine_status).and_return('ShuttingDown')
267
+ expect(resource.machine_turning_off?).to eq(true)
268
+ end
269
+
270
+ it 'returns false if the machine_status is not TurningOff or ShuttingDown' do
271
+ allow(resource).to receive(:machine_status).and_return('Off')
272
+ expect(resource.machine_turning_off?).to eq(false)
273
+ end
274
+ end
275
+
276
+ describe '#machine_in_provisioned_state?' do
277
+ it 'returns true if the machine_status is MachineProvisioned' do
278
+ allow(resource).to receive(:machine_status).and_return('MachineProvisioned')
279
+ expect(resource.machine_in_provisioned_state?).to eq(true)
280
+ end
281
+
282
+ it 'returns false if the machine_status is not MachineProvisioned' do
283
+ allow(resource).to receive(:machine_status).and_return('On')
284
+ expect(resource.machine_in_provisioned_state?).to eq(false)
285
+ end
286
+ end
287
+
288
+ describe '#network_interfaces' do
289
+ it 'returns an array of 2 elements' do
290
+ expect(resource.network_interfaces.size).to be 2
291
+ end
292
+
293
+ it 'contains the correct data' do
294
+ nic1, nic2 = resource.network_interfaces
295
+
296
+ expect(nic1['NETWORK_NAME']).to eq 'VM Network'
297
+ expect(nic1['NETWORK_ADDRESS']).to eq '192.168.110.200'
298
+ expect(nic1['NETWORK_MAC_ADDRESS']).to eq '00:50:56:ae:95:3c'
299
+
300
+ expect(nic2['NETWORK_NAME']).to eq 'Management Network'
301
+ expect(nic2['NETWORK_ADDRESS']).to eq '192.168.220.200'
302
+ expect(nic2['NETWORK_MAC_ADDRESS']).to eq '00:50:56:ae:95:3d'
303
+ end
304
+ end
305
+
306
+ describe '#ip_addresses' do
307
+ it 'returns the correct IP addresses' do
308
+ expect(resource.ip_addresses).to eq [ '192.168.110.200', '192.168.220.200' ]
309
+ end
310
+
311
+ it 'returns nil if there are no network interfaces' do
312
+ allow(resource).to receive(:network_interfaces).and_return nil
313
+ expect(resource.ip_addresses).to be_nil
314
+ end
315
+ end
316
+
317
+ describe '#actions' do
318
+ it 'does not call #fetch_resource_data' do
319
+ expect(resource).not_to receive(:fetch_resource_data)
320
+ resource.actions
321
+ end
322
+ end
323
+
324
+ describe '#action_id_by_name' do
325
+ it 'returns the correct action ID for the destroy action' do
326
+ expect(resource.action_id_by_name('Destroy')).to eq 'ace8ba42-e724-48d8-9614-9b3a62b5a464'
327
+ end
328
+
329
+ it 'returns nil if there are no resource operations' do
330
+ allow(resource).to receive(:actions).and_return nil
331
+ expect(resource.action_id_by_name('Destroy')).to be_nil
332
+ end
333
+
334
+ it 'returns nil if there are actions, but none with the right name' do
335
+ allow(resource).to receive(:actions).and_return([ { 'name' => 'some action' }, { 'name' => 'another action' } ])
336
+ expect(resource.action_id_by_name('Destroy')).to be_nil
337
+ end
338
+ end
339
+
340
+ describe '#destroy' do
341
+ it_behaves_like 'a resource action', :destroy, 'Destroy'
342
+ end
343
+
344
+ describe '#shutdown' do
345
+ it_behaves_like 'a resource action', :shutdown, 'Shutdown'
346
+ end
347
+
348
+ describe '#poweroff' do
349
+ it_behaves_like 'a resource action', :poweroff, 'Power Off'
350
+ end
351
+
352
+ describe '#poweron' do
353
+ it_behaves_like 'a resource action', :poweron, 'Power On'
354
+ end
355
+
356
+ describe '#submit_action_request' do
357
+ before do
358
+ allow(resource).to receive(:action_request_payload).and_return({})
359
+ response = double('response', code: 200, headers: { location: '/requests/request-12345' })
360
+ allow(client).to receive(:http_post).with('/catalog-service/api/consumer/requests', '{}').and_return(response)
361
+ end
362
+
363
+ it 'calls http_post' do
364
+ expect(client).to receive(:http_post).with('/catalog-service/api/consumer/requests', '{}')
365
+
366
+ resource.submit_action_request('action-123')
367
+ end
368
+
369
+ it 'returns a Vra::Request object' do
370
+ expect(resource.submit_action_request('action-123')).to be_an_instance_of(Vra::Request)
371
+ end
372
+ end
373
+ end
374
+
375
+ context 'when a valid VM resource instance with no operations is created' do
376
+ let(:resource) { Vra::Resource.new(client, data: vm_payload_no_ops) }
377
+
378
+ describe '#actions' do
379
+ it 'calls #fetch_resource_data' do
380
+ expect(resource).to receive(:fetch_resource_data)
381
+ resource.actions
382
+ end
383
+ end
384
+ end
385
+
386
+ context 'when a valid non-VM resource instance has been created' do
387
+ let(:resource) { Vra::Resource.new(client, data: non_vm_payload) }
388
+
389
+ it 'returns nil for network_interfaces and ip_addresses' do
390
+ expect(resource.network_interfaces).to be_nil
391
+ expect(resource.ip_addresses).to be_nil
392
+ end
393
+ end
394
+ end