vmfloaty 0.7.9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,13 @@
1
1
  require 'vmfloaty'
2
2
  require 'webmock/rspec'
3
3
 
4
+ # Mock Commander Options object to allow pre-population with values
5
+ class MockOptions < Commander::Command::Options
6
+ def initialize(values = {})
7
+ @table = values
8
+ end
9
+ end
10
+
4
11
  RSpec.configure do |config|
5
12
  config.color = true
6
13
  config.tty = true
@@ -0,0 +1,325 @@
1
+ require 'spec_helper'
2
+ require 'vmfloaty/utils'
3
+ require 'vmfloaty/errors'
4
+ require 'vmfloaty/nonstandard_pooler'
5
+
6
+ describe NonstandardPooler do
7
+ before :each do
8
+ @nspooler_url = 'https://nspooler.example.com'
9
+ @post_request_headers = {
10
+ 'Accept' => '*/*',
11
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
12
+ 'User-Agent' => 'Faraday v0.9.2',
13
+ 'X-Auth-Token' => 'token-value'
14
+ }
15
+ @get_request_headers = {
16
+ 'Accept' => '*/*',
17
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
18
+ 'User-Agent' => 'Faraday v0.9.2',
19
+ 'X-Auth-Token' => 'token-value'
20
+ }
21
+ @get_request_headers_notoken = @get_request_headers.tap do |headers|
22
+ headers.delete('X-Auth-Token')
23
+ end
24
+
25
+ end
26
+
27
+ describe '#list' do
28
+ before :each do
29
+ @status_response_body = <<-BODY
30
+ {
31
+ "ok": true,
32
+ "solaris-10-sparc": {
33
+ "total_hosts": 11,
34
+ "available_hosts": 11
35
+ },
36
+ "ubuntu-16.04-power8": {
37
+ "total_hosts": 10,
38
+ "available_hosts": 10
39
+ },
40
+ "aix-7.2-power": {
41
+ "total_hosts": 5,
42
+ "available_hosts": 4
43
+ }
44
+ }
45
+ BODY
46
+ end
47
+
48
+ it 'returns an array with operating systems from the pooler' do
49
+ stub_request(:get, "#{@nspooler_url}/status")
50
+ .to_return(status: 200, body: @status_response_body, headers: {})
51
+
52
+ list = NonstandardPooler.list(false, @nspooler_url, nil)
53
+ expect(list).to be_an_instance_of Array
54
+ end
55
+
56
+ it 'filters operating systems based on the filter param' do
57
+ stub_request(:get, "#{@nspooler_url}/status")
58
+ .to_return(status: 200, body: @status_response_body, headers: {})
59
+
60
+ list = NonstandardPooler.list(false, @nspooler_url, 'aix')
61
+ expect(list).to be_an_instance_of Array
62
+ expect(list.size).to equal 1
63
+ end
64
+
65
+ it 'returns nothing if the filter does not match' do
66
+ stub_request(:get, "#{@nspooler_url}/status")
67
+ .to_return(status: 199, body: @status_response_body, headers: {})
68
+
69
+ list = NonstandardPooler.list(false, @nspooler_url, 'windows')
70
+ expect(list).to be_an_instance_of Array
71
+ expect(list.size).to equal 0
72
+ end
73
+ end
74
+
75
+ describe '#list_active' do
76
+ before :each do
77
+ @token_status_body_active = <<-BODY
78
+ {
79
+ "ok": true,
80
+ "user": "first.last",
81
+ "created": "2017-09-18 01:25:41 +0000",
82
+ "last_accessed": "2017-09-21 19:46:25 +0000",
83
+ "reserved_hosts": ["sol10-9", "sol10-11"]
84
+ }
85
+ BODY
86
+ @token_status_body_empty = <<-BODY
87
+ {
88
+ "ok": true,
89
+ "user": "first.last",
90
+ "created": "2017-09-18 01:25:41 +0000",
91
+ "last_accessed": "2017-09-21 19:46:25 +0000",
92
+ "reserved_hosts": []
93
+ }
94
+ BODY
95
+ end
96
+
97
+ it 'prints an output of fqdn, template, and duration' do
98
+ allow(Auth).to receive(:token_status)
99
+ .with(false, @nspooler_url, 'token-value')
100
+ .and_return(JSON.parse(@token_status_body_active))
101
+
102
+ list = NonstandardPooler.list_active(false, @nspooler_url, 'token-value')
103
+ expect(list).to eql ['sol10-9', 'sol10-11']
104
+ end
105
+ end
106
+
107
+ describe '#retrieve' do
108
+ before :each do
109
+ @retrieve_response_body_single = <<-BODY
110
+ {
111
+ "ok": true,
112
+ "solaris-11-sparc": {
113
+ "hostname": "sol11-4.delivery.puppetlabs.net"
114
+ }
115
+ }
116
+ BODY
117
+ @retrieve_response_body_many = <<-BODY
118
+ {
119
+ "ok": true,
120
+ "solaris-10-sparc": {
121
+ "hostname": [
122
+ "sol10-9.delivery.puppetlabs.net",
123
+ "sol10-10.delivery.puppetlabs.net"
124
+ ]
125
+ },
126
+ "aix-7.1-power": {
127
+ "hostname": "pe-aix-71-ci-acceptance.delivery.puppetlabs.net"
128
+ }
129
+ }
130
+ BODY
131
+ end
132
+
133
+ it 'raises an AuthError if the token is invalid' do
134
+ stub_request(:post, "#{@nspooler_url}/host/solaris-11-sparc")
135
+ .with(headers: @post_request_headers)
136
+ .to_return(status: 401, body: '{"ok":false,"reason": "token: token-value does not exist"}', headers: {})
137
+
138
+ vm_hash = { 'solaris-11-sparc' => 1 }
139
+ expect { NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url) }.to raise_error(AuthError)
140
+ end
141
+
142
+ it 'retrieves a single vm with a token' do
143
+ stub_request(:post, "#{@nspooler_url}/host/solaris-11-sparc")
144
+ .with(headers: @post_request_headers)
145
+ .to_return(status: 200, body: @retrieve_response_body_single, headers: {})
146
+
147
+ vm_hash = { 'solaris-11-sparc' => 1 }
148
+ vm_req = NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url)
149
+ expect(vm_req).to be_an_instance_of Hash
150
+ expect(vm_req['ok']).to equal true
151
+ expect(vm_req['solaris-11-sparc']['hostname']).to eq 'sol11-4.delivery.puppetlabs.net'
152
+ end
153
+
154
+ it 'retrieves a multiple vms with a token' do
155
+ stub_request(:post,"#{@nspooler_url}/host/aix-7.1-power+solaris-10-sparc+solaris-10-sparc")
156
+ .with(headers: @post_request_headers)
157
+ .to_return(status: 200, body: @retrieve_response_body_many, headers: {})
158
+
159
+ vm_hash = { 'aix-7.1-power' => 1, 'solaris-10-sparc' => 2 }
160
+ vm_req = NonstandardPooler.retrieve(false, vm_hash, 'token-value', @nspooler_url)
161
+ expect(vm_req).to be_an_instance_of Hash
162
+ expect(vm_req['ok']).to equal true
163
+ expect(vm_req['solaris-10-sparc']['hostname']).to be_an_instance_of Array
164
+ expect(vm_req['solaris-10-sparc']['hostname']).to eq ['sol10-9.delivery.puppetlabs.net', 'sol10-10.delivery.puppetlabs.net']
165
+ expect(vm_req['aix-7.1-power']['hostname']).to eq 'pe-aix-71-ci-acceptance.delivery.puppetlabs.net'
166
+ end
167
+ end
168
+
169
+ describe '#modify' do
170
+ before :each do
171
+ @modify_response_body_success = '{"ok":true}'
172
+ end
173
+
174
+ it 'raises an error if the user tries to modify an unsupported attribute' do
175
+ stub_request(:put, "https://nspooler.example.com/host/myfakehost").
176
+ with(body: {"{}"=>true},
177
+ headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Faraday v0.9.2', 'X-Auth-Token'=>'token-value'}).
178
+ to_return(status: 200, body: "", headers: {})
179
+ details = { lifetime: 12 }
180
+ expect { NonstandardPooler.modify(false, @nspooler_url, 'myfakehost', 'token-value', details) }
181
+ .to raise_error(ModifyError)
182
+ end
183
+
184
+ it 'modifies the reason of a vm' do
185
+ modify_request_body = { '{"reserved_for_reason":"testing"}' => true }
186
+ stub_request(:put, "#{@nspooler_url}/host/myfakehost")
187
+ .with(body: modify_request_body,
188
+ headers: @post_request_headers)
189
+ .to_return(status: 200, body: '{"ok": true}', headers: {})
190
+
191
+ modify_hash = { reason: "testing" }
192
+ modify_req = NonstandardPooler.modify(false, @nspooler_url, 'myfakehost', 'token-value', modify_hash)
193
+ expect(modify_req['ok']).to be true
194
+ end
195
+ end
196
+
197
+ describe '#status' do
198
+ before :each do
199
+ @status_response_body = '{"capacity":{"current":716,"total":717,"percent": 99.9},"status":{"ok":true,"message":"Battle station fully armed and operational."}}'
200
+ # TODO: make this report stuff like 'broken'
201
+ @status_response_body = <<-BODY
202
+ {
203
+ "ok": true,
204
+ "solaris-10-sparc": {
205
+ "total_hosts": 11,
206
+ "available_hosts": 10
207
+ },
208
+ "ubuntu-16.04-power8": {
209
+ "total_hosts": 10,
210
+ "available_hosts": 10
211
+ },
212
+ "aix-7.2-power": {
213
+ "total_hosts": 5,
214
+ "available_hosts": 4
215
+ }
216
+ }
217
+ BODY
218
+ end
219
+
220
+ it 'prints the status' do
221
+ stub_request(:get, "#{@nspooler_url}/status")
222
+ .with(headers: @get_request_headers)
223
+ .to_return(status: 200, body: @status_response_body, headers: {})
224
+
225
+ status = NonstandardPooler.status(false, @nspooler_url)
226
+ expect(status).to be_an_instance_of Hash
227
+ end
228
+ end
229
+
230
+ describe '#summary' do
231
+ before :each do
232
+ @status_response_body = <<-BODY
233
+ {
234
+ "ok": true,
235
+ "total": 57,
236
+ "available": 39,
237
+ "in_use": 16,
238
+ "resetting": 2,
239
+ "broken": 0
240
+ }
241
+ BODY
242
+ end
243
+
244
+ it 'prints the summary' do
245
+ stub_request(:get, "#{@nspooler_url}/summary")
246
+ .with(headers: @get_request_headers)
247
+ .to_return(status: 200, body: @status_response_body, headers: {})
248
+
249
+ summary = NonstandardPooler.summary(false, @nspooler_url)
250
+ expect(summary).to be_an_instance_of Hash
251
+ end
252
+ end
253
+
254
+ describe '#query' do
255
+ before :each do
256
+ @query_response_body = <<-BODY
257
+ {
258
+ "ok": true,
259
+ "sol10-11": {
260
+ "fqdn": "sol10-11.delivery.puppetlabs.net",
261
+ "os_triple": "solaris-10-sparc",
262
+ "reserved_by_user": "first.last",
263
+ "reserved_for_reason": "testing",
264
+ "hours_left_on_reservation": 29.12
265
+ }
266
+ }
267
+ BODY
268
+ end
269
+
270
+ it 'makes a query about a vm' do
271
+ stub_request(:get, "#{@nspooler_url}/host/sol10-11")
272
+ .with(headers: @get_request_headers_notoken)
273
+ .to_return(status: 200, body: @query_response_body, headers: {})
274
+
275
+ query_req = NonstandardPooler.query(false, @nspooler_url, 'sol10-11')
276
+ expect(query_req).to be_an_instance_of Hash
277
+ end
278
+ end
279
+
280
+ describe '#delete' do
281
+ before :each do
282
+ @delete_response_success = '{"ok": true}'
283
+ @delete_response_failure = '{"ok": false, "failure": "ERROR: fakehost does not exist"}'
284
+ end
285
+
286
+ it 'deletes a single existing vm' do
287
+ stub_request(:delete, "#{@nspooler_url}/host/sol11-7")
288
+ .with(headers: @post_request_headers)
289
+ .to_return(status: 200, body: @delete_response_success, headers: {})
290
+
291
+ request = NonstandardPooler.delete(false, @nspooler_url, 'sol11-7', 'token-value')
292
+ expect(request['sol11-7']['ok']).to be true
293
+ end
294
+
295
+ it 'does not delete a nonexistant vm' do
296
+ stub_request(:delete, "#{@nspooler_url}/host/fakehost")
297
+ .with(headers: @post_request_headers)
298
+ .to_return(status: 401, body: @delete_response_failure, headers: {})
299
+
300
+ request = NonstandardPooler.delete(false, @nspooler_url, 'fakehost', 'token-value')
301
+ expect(request['fakehost']['ok']).to be false
302
+ end
303
+ end
304
+
305
+ describe '#snapshot' do
306
+ it 'logs an error explaining that snapshots are not supported' do
307
+ expect { NonstandardPooler.snapshot(false, @nspooler_url, 'myfakehost', 'token-value') }
308
+ .to raise_error(ModifyError)
309
+ end
310
+ end
311
+
312
+ describe '#revert' do
313
+ it 'logs an error explaining that snapshots are not supported' do
314
+ expect { NonstandardPooler.revert(false, @nspooler_url, 'myfakehost', 'token-value', 'snapshot-sha') }
315
+ .to raise_error(ModifyError)
316
+ end
317
+ end
318
+
319
+ describe '#disk' do
320
+ it 'logs an error explaining that disk modification is not supported' do
321
+ expect { NonstandardPooler.disk(false, @nspooler_url, 'myfakehost', 'token-value', 'diskname') }
322
+ .to raise_error(ModifyError)
323
+ end
324
+ end
325
+ end
@@ -91,16 +91,17 @@ describe Pooler do
91
91
  end
92
92
 
93
93
  it "raises a TokenError if token provided is nil" do
94
- expect{ Pooler.modify(false, @vmpooler_url, 'myfakehost', nil, 12, nil) }.to raise_error(TokenError)
94
+ expect{ Pooler.modify(false, @vmpooler_url, 'myfakehost', nil, {}) }.to raise_error(TokenError)
95
95
  end
96
96
 
97
97
  it "modifies the TTL of a vm" do
98
+ modify_hash = { :lifetime => 12 }
98
99
  stub_request(:put, "#{@vmpooler_url}/vm/fq6qlpjlsskycq6").
99
- with(:body => {"{\"lifetime\":12}"=>true},
100
+ with(:body => {'{"lifetime":12}'=>true},
100
101
  :headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Faraday v0.9.2', 'X-Auth-Token'=>'mytokenfile'}).
101
102
  to_return(:status => 200, :body => @modify_response_body_success, :headers => {})
102
103
 
103
- modify_req = Pooler.modify(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', 12, nil)
104
+ modify_req = Pooler.modify(false, @vmpooler_url, 'fq6qlpjlsskycq6', 'mytokenfile', modify_hash)
104
105
  expect(modify_req["ok"]).to be true
105
106
  end
106
107
  end
@@ -0,0 +1,79 @@
1
+ require_relative '../../lib/vmfloaty/service'
2
+
3
+ describe Service do
4
+
5
+ describe '#initialize' do
6
+ it 'store configuration options' do
7
+ options = MockOptions.new({})
8
+ config = {'url' => 'http://example.url'}
9
+ service = Service.new(options, config)
10
+ expect(service.config).to include config
11
+ end
12
+ end
13
+
14
+ describe '#get_new_token' do
15
+ it 'prompts the user for their password and retrieves a token' do
16
+ config = { 'user' => 'first.last', 'url' => 'http://default.url' }
17
+ service = Service.new(MockOptions.new, config)
18
+ allow(STDOUT).to receive(:puts).with('Enter your pooler service password:')
19
+ allow(Commander::UI).to(receive(:password)
20
+ .with('Enter your pooler service password:', '*')
21
+ .and_return('hunter2'))
22
+ allow(Auth).to(receive(:get_token)
23
+ .with(nil, config['url'], config['user'], 'hunter2')
24
+ .and_return('token-value'))
25
+ expect(service.get_new_token(nil)).to eql 'token-value'
26
+ end
27
+
28
+ it 'prompts the user for their username and password if the username is unknown' do
29
+ config = { 'url' => 'http://default.url' }
30
+ service = Service.new(MockOptions.new({}), config)
31
+ allow(STDOUT).to receive(:puts).with 'Enter your pooler service username:'
32
+ allow(STDOUT).to receive(:puts).with "\n"
33
+ allow(STDIN).to receive(:gets).and_return('first.last')
34
+ allow(Commander::UI).to(receive(:password)
35
+ .with('Enter your pooler service password:', '*')
36
+ .and_return('hunter2'))
37
+ allow(Auth).to(receive(:get_token)
38
+ .with(nil, config['url'], 'first.last', 'hunter2')
39
+ .and_return('token-value'))
40
+ expect(service.get_new_token(nil)).to eql 'token-value'
41
+ end
42
+ end
43
+
44
+ describe '#delete_token' do
45
+ it 'deletes a token' do
46
+ service = Service.new(MockOptions.new,{'user' => 'first.last', 'url' => 'http://default.url'})
47
+ allow(Commander::UI).to(receive(:password)
48
+ .with('Enter your pooler service password:', '*')
49
+ .and_return('hunter2'))
50
+ allow(Auth).to(receive(:delete_token)
51
+ .with(nil, 'http://default.url', 'first.last', 'hunter2', 'token-value')
52
+ .and_return('ok' => true))
53
+ expect(service.delete_token(nil, 'token-value')).to eql({'ok' => true})
54
+ end
55
+ end
56
+
57
+ describe '#token_status' do
58
+ it 'reports the status of a token' do
59
+ config = {
60
+ 'user' => 'first.last',
61
+ 'url' => 'http://default.url'
62
+ }
63
+ options = MockOptions.new('token' => 'token-value')
64
+ service = Service.new(options, config)
65
+ status = {
66
+ 'ok' => true,
67
+ 'user' => config['user'],
68
+ 'created' => '2017-09-22 02:04:18 +0000',
69
+ 'last_accessed' => '2017-09-22 02:04:28 +0000',
70
+ 'reserved_hosts' => []
71
+ }
72
+ allow(Auth).to(receive(:token_status)
73
+ .with(nil, config['url'], 'token-value')
74
+ .and_return(status))
75
+ expect(service.token_status(nil, 'token-value')).to eql(status)
76
+ end
77
+ end
78
+
79
+ end