vagrant-openstack-provider 0.2.0 → 0.3.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.
Files changed (55) hide show
  1. checksums.yaml +8 -8
  2. data/Appraisals +6 -6
  3. data/CHANGELOG.md +44 -1
  4. data/Gemfile +10 -6
  5. data/Vagrantfile +7 -15
  6. data/functional_tests/Vagrantfile +58 -0
  7. data/functional_tests/keys/vagrant-openstack +27 -0
  8. data/functional_tests/keys/vagrant-openstack.pub +1 -0
  9. data/functional_tests/run_tests.sh +142 -0
  10. data/gemfiles/latest_stable.gemfile +5 -0
  11. data/gemfiles/oldest_current.gemfile +5 -0
  12. data/gemfiles/previous_release.gemfile +5 -0
  13. data/lib/vagrant-openstack-provider/action.rb +17 -2
  14. data/lib/vagrant-openstack-provider/action/connect_openstack.rb +60 -8
  15. data/lib/vagrant-openstack-provider/action/create_server.rb +131 -43
  16. data/lib/vagrant-openstack-provider/action/delete_server.rb +2 -0
  17. data/lib/vagrant-openstack-provider/action/read_ssh_info.rb +22 -3
  18. data/lib/vagrant-openstack-provider/action/resume.rb +2 -0
  19. data/lib/vagrant-openstack-provider/action/stop_server.rb +1 -0
  20. data/lib/vagrant-openstack-provider/action/suspend.rb +2 -0
  21. data/lib/vagrant-openstack-provider/action/sync_folders.rb +3 -2
  22. data/lib/vagrant-openstack-provider/action/wait_active.rb +29 -0
  23. data/lib/vagrant-openstack-provider/action/wait_stop.rb +1 -1
  24. data/lib/vagrant-openstack-provider/client/domain.rb +26 -0
  25. data/lib/vagrant-openstack-provider/client/http_utils.rb +96 -0
  26. data/lib/vagrant-openstack-provider/client/keystone.rb +30 -41
  27. data/lib/vagrant-openstack-provider/client/neutron.rb +24 -11
  28. data/lib/vagrant-openstack-provider/client/nova.rb +99 -104
  29. data/lib/vagrant-openstack-provider/client/openstack.rb +4 -0
  30. data/lib/vagrant-openstack-provider/client/request_logger.rb +24 -0
  31. data/lib/vagrant-openstack-provider/command/abstract_command.rb +31 -0
  32. data/lib/vagrant-openstack-provider/command/flavor_list.rb +21 -0
  33. data/lib/vagrant-openstack-provider/command/floatingip_list.rb +34 -0
  34. data/lib/vagrant-openstack-provider/command/image_list.rb +21 -0
  35. data/lib/vagrant-openstack-provider/command/main.rb +51 -0
  36. data/lib/vagrant-openstack-provider/command/network_list.rb +21 -0
  37. data/lib/vagrant-openstack-provider/command/utils.rb +22 -0
  38. data/lib/vagrant-openstack-provider/config.rb +31 -3
  39. data/lib/vagrant-openstack-provider/errors.rb +28 -0
  40. data/lib/vagrant-openstack-provider/plugin.rb +5 -0
  41. data/lib/vagrant-openstack-provider/version.rb +1 -1
  42. data/locales/en.yml +45 -1
  43. data/spec/vagrant-openstack-provider/action/connect_openstack_spec.rb +190 -0
  44. data/spec/vagrant-openstack-provider/action/create_server_spec.rb +166 -1
  45. data/spec/vagrant-openstack-provider/action/read_ssh_info_spec.rb +109 -0
  46. data/spec/vagrant-openstack-provider/client/keystone_spec.rb +32 -48
  47. data/spec/vagrant-openstack-provider/client/neutron_spec.rb +42 -4
  48. data/spec/vagrant-openstack-provider/client/nova_spec.rb +247 -6
  49. data/spec/vagrant-openstack-provider/client/utils_spec.rb +58 -5
  50. data/spec/vagrant-openstack-provider/command/floatingip_list_spec.rb +67 -0
  51. data/spec/vagrant-openstack-provider/config_spec.rb +21 -6
  52. data/spec/vagrant-openstack-provider/spec_helper.rb +7 -0
  53. data/{numergyrc → stackrc} +4 -1
  54. metadata +24 -4
  55. data/lib/vagrant-openstack-provider/client/utils.rb +0 -38
@@ -51,7 +51,6 @@ describe VagrantPlugins::Openstack::KeystoneClient do
51
51
  end
52
52
 
53
53
  context 'with good credentials' do
54
-
55
54
  it 'store token and tenant id' do
56
55
  stub_request(:post, 'http://keystoneAuthV2')
57
56
  .with(
@@ -66,52 +65,6 @@ describe VagrantPlugins::Openstack::KeystoneClient do
66
65
 
67
66
  session.token.should eq('0123456789')
68
67
  session.project_id.should eq('testTenantId')
69
- session.endpoints[:compute].should eq('http://nova')
70
- session.endpoints[:network].should eq('http://neutron')
71
- end
72
-
73
- context 'with compute endpoint override' do
74
- it 'store token and tenant id' do
75
- config.stub(:openstack_compute_url) { 'http://novaOverride' }
76
-
77
- stub_request(:post, 'http://keystoneAuthV2')
78
- .with(
79
- body: keystone_request_body,
80
- headers: keystone_request_headers)
81
- .to_return(
82
- status: 200,
83
- body: keystone_response_body,
84
- headers: keystone_request_headers)
85
-
86
- @keystone_client.authenticate(env)
87
-
88
- session.token.should eq('0123456789')
89
- session.project_id.should eq('testTenantId')
90
- session.endpoints[:compute].should eq('http://novaOverride')
91
- session.endpoints[:network].should eq('http://neutron')
92
- end
93
- end
94
-
95
- context 'with network endpoint override' do
96
- it 'store token and tenant id' do
97
- config.stub(:openstack_network_url) { 'http://neutronOverride' }
98
-
99
- stub_request(:post, 'http://keystoneAuthV2')
100
- .with(
101
- body: keystone_request_body,
102
- headers: keystone_request_headers)
103
- .to_return(
104
- status: 200,
105
- body: keystone_response_body,
106
- headers: keystone_request_headers)
107
-
108
- @keystone_client.authenticate(env)
109
-
110
- session.token.should eq('0123456789')
111
- session.project_id.should eq('testTenantId')
112
- session.endpoints[:compute].should eq('http://nova')
113
- session.endpoints[:network].should eq('http://neutronOverride')
114
- end
115
68
  end
116
69
  end
117
70
 
@@ -132,9 +85,40 @@ describe VagrantPlugins::Openstack::KeystoneClient do
132
85
  }',
133
86
  headers: keystone_request_headers)
134
87
 
135
- expect { @keystone_client.authenticate(env) }.to raise_error(RestClient::Unauthorized)
88
+ expect { @keystone_client.authenticate(env) }.to raise_error(Errors::AuthenticationFailed)
89
+ end
90
+ end
91
+
92
+ context 'with bad endpoint' do
93
+ it 'raise a BadAuthenticationEndpoint error' do
94
+ stub_request(:post, 'http://keystoneAuthV2')
95
+ .with(
96
+ body: keystone_request_body,
97
+ headers: keystone_request_headers)
98
+ .to_return(
99
+ status: 404)
100
+
101
+ expect { @keystone_client.authenticate(env) }.to raise_error(Errors::BadAuthenticationEndpoint)
136
102
  end
137
103
  end
138
104
 
105
+ context 'with internal server error' do
106
+ it 'raise a VagrantOpenstackError error with response body as message' do
107
+ stub_request(:post, 'http://keystoneAuthV2')
108
+ .with(
109
+ body: keystone_request_body,
110
+ headers: keystone_request_headers)
111
+ .to_return(
112
+ status: 500,
113
+ body: 'Internal server error')
114
+
115
+ begin
116
+ @keystone_client.authenticate(env)
117
+ fail 'Expected Errors::VagrantOpenstackError'
118
+ rescue Errors::VagrantOpenstackError => e
119
+ e.message.should eq('Internal server error')
120
+ end
121
+ end
122
+ end
139
123
  end
140
124
  end
@@ -43,10 +43,48 @@ describe VagrantPlugins::Openstack::NeutronClient do
43
43
  networks = @neutron_client.get_private_networks(env)
44
44
 
45
45
  expect(networks.length).to eq(2)
46
- expect(networks[0][:id]).to eq('net-1')
47
- expect(networks[0][:name]).to eq('net1')
48
- expect(networks[1][:id]).to eq('net-2')
49
- expect(networks[1][:name]).to eq('net2')
46
+ expect(networks[0].id).to eq('net-1')
47
+ expect(networks[0].name).to eq('net1')
48
+ expect(networks[1].id).to eq('net-2')
49
+ expect(networks[1].name).to eq('net2')
50
+ end
51
+ end
52
+ end
53
+
54
+ describe 'get_api_version_list' do
55
+ context 'basic' do
56
+ it 'returns version list' do
57
+ stub_request(:get, 'http://neutron/')
58
+ .with(header: { 'Accept' => 'application/json' })
59
+ .to_return(
60
+ status: 200,
61
+ body: '{
62
+ "versions": [
63
+ {
64
+ "status": "...",
65
+ "id": "v1.0",
66
+ "links": [
67
+ {
68
+ "href": "http://neutron/v1.0",
69
+ "rel": "self"
70
+ }
71
+ ]
72
+ },
73
+ {
74
+ "status": "CURRENT",
75
+ "id": "v2.0",
76
+ "links": [
77
+ {
78
+ "href": "http://neutron/v2.0",
79
+ "rel": "self"
80
+ }
81
+ ]
82
+ }
83
+ ]}')
84
+
85
+ versions = @neutron_client.get_api_version_list(env)
86
+
87
+ expect(versions.size).to eq(2)
50
88
  end
51
89
  end
52
90
  end
@@ -1,6 +1,10 @@
1
1
  require 'vagrant-openstack-provider/spec_helper'
2
2
 
3
3
  describe VagrantPlugins::Openstack::NovaClient do
4
+ include FakeFS::SpecHelpers::All
5
+
6
+ let(:filename) { 'key.pub' }
7
+ let(:ssh_key_content) { 'my public key' }
4
8
 
5
9
  let(:config) do
6
10
  double('config').tap do |config|
@@ -12,6 +16,12 @@ describe VagrantPlugins::Openstack::NovaClient do
12
16
  end
13
17
  end
14
18
 
19
+ let(:file) do
20
+ double('file').tap do |file|
21
+ file.stub(:read) { ssh_key_content }
22
+ end
23
+ end
24
+
15
25
  let(:env) do
16
26
  Hash.new.tap do |env|
17
27
  env[:ui] = double('ui')
@@ -97,7 +107,7 @@ describe VagrantPlugins::Openstack::NovaClient do
97
107
  })
98
108
  .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
99
109
 
100
- instance_id = @nova_client.create_server(env, 'inst', 'img', 'flav', nil, 'key')
110
+ instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', networks: nil, keypair: 'key')
101
111
 
102
112
  expect(instance_id).to eq('o1o2o3')
103
113
  end
@@ -116,7 +126,27 @@ describe VagrantPlugins::Openstack::NovaClient do
116
126
  })
117
127
  .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
118
128
 
119
- instance_id = @nova_client.create_server(env, 'inst', 'img', 'flav', %w(net1 net2), 'key')
129
+ instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', networks: %w(net1 net2), keypair: 'key')
130
+
131
+ expect(instance_id).to eq('o1o2o3')
132
+ end
133
+ end
134
+
135
+ context 'with availability_zone' do
136
+ it 'returns new instance id' do
137
+
138
+ stub_request(:post, 'http://nova/a1b2c3/servers')
139
+ .with(
140
+ body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key","availability_zone":"avz"}}',
141
+ headers:
142
+ {
143
+ 'Accept' => 'application/json',
144
+ 'Content-Type' => 'application/json',
145
+ 'X-Auth-Token' => '123456'
146
+ })
147
+ .to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
148
+
149
+ instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav', keypair: 'key', availability_zone: 'avz')
120
150
 
121
151
  expect(instance_id).to eq('o1o2o3')
122
152
  end
@@ -143,13 +173,88 @@ describe VagrantPlugins::Openstack::NovaClient do
143
173
  end
144
174
  end
145
175
 
176
+ describe 'import_keypair_from_file' do
177
+ context 'with token and project_id acquainted' do
178
+ it 'returns newly created keypair name' do
179
+ File.should_receive(:exist?).with(filename).and_return(true)
180
+ File.should_receive(:open).with(filename).and_return(file)
181
+ Kernel.stub!(:rand).and_return(2_036_069_739_008)
182
+
183
+ stub_request(:post, 'http://nova/a1b2c3/os-keypairs')
184
+ .with(
185
+ body: "{\"keypair\":{\"name\":\"vagrant-generated-pzcvcpa8\",\"public_key\":\"#{ssh_key_content}\"}}",
186
+ headers: {
187
+ 'Accept' => 'application/json',
188
+ 'Content-Type' => 'application/json',
189
+ 'X-Auth-Token' => '123456' })
190
+ .to_return(status: 200, body: '
191
+ {
192
+ "keypair": {
193
+ "name": "created_key_name"
194
+ }
195
+ }')
196
+
197
+ @nova_client.import_keypair_from_file(env, filename)
198
+
199
+ end
200
+ end
201
+ end
202
+
203
+ describe 'delete_keypair_if_vagrant' do
204
+ context 'with token and project_id acquainted' do
205
+ context 'with keypair not generated by vagrant' do
206
+ it 'do nothing' do
207
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
208
+ .with(headers:
209
+ {
210
+ 'Accept' => 'application/json',
211
+ 'X-Auth-Token' => '123456'
212
+ })
213
+ .to_return(status: 200, body: '
214
+ {
215
+ "server": {
216
+ "id": "o1o2o3",
217
+ "key_name": "other_key"
218
+ }
219
+ }
220
+ ')
221
+
222
+ @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
223
+ end
224
+ end
225
+ context 'with keypair generated by vagrant' do
226
+ it 'deletes the key on nova' do
227
+ stub_request(:delete, 'http://nova/a1b2c3/os-keypairs/vagrant-generated-1234')
228
+ .with(headers: { 'X-Auth-Token' => '123456' })
229
+ .to_return(status: 202)
230
+ stub_request(:get, 'http://nova/a1b2c3/servers/o1o2o3')
231
+ .with(headers:
232
+ {
233
+ 'Accept' => 'application/json',
234
+ 'X-Auth-Token' => '123456'
235
+ })
236
+ .to_return(status: 200, body: '
237
+ {
238
+ "server": {
239
+ "id": "o1o2o3",
240
+ "key_name": "vagrant-generated-1234"
241
+ }
242
+ }
243
+ ')
244
+
245
+ @nova_client.delete_keypair_if_vagrant(env, 'o1o2o3')
246
+ end
247
+ end
248
+ end
249
+ end
250
+
146
251
  describe 'suspend_server' do
147
252
  context 'with token and project_id acquainted' do
148
253
  it 'returns new instance id' do
149
254
 
150
255
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
151
256
  .with(
152
- body: '{ "suspend": null }',
257
+ body: '{"suspend":null}',
153
258
  headers:
154
259
  {
155
260
  'Accept' => 'application/json',
@@ -169,7 +274,7 @@ describe VagrantPlugins::Openstack::NovaClient do
169
274
 
170
275
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
171
276
  .with(
172
- body: '{ "resume": null }',
277
+ body: '{"resume":null}',
173
278
  headers:
174
279
  {
175
280
  'Accept' => 'application/json',
@@ -189,7 +294,7 @@ describe VagrantPlugins::Openstack::NovaClient do
189
294
 
190
295
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
191
296
  .with(
192
- body: '{ "os-stop": null }',
297
+ body: '{"os-stop":null}',
193
298
  headers:
194
299
  {
195
300
  'Accept' => 'application/json',
@@ -210,7 +315,7 @@ describe VagrantPlugins::Openstack::NovaClient do
210
315
 
211
316
  stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
212
317
  .with(
213
- body: '{ "os-start": null }',
318
+ body: '{"os-start":null}',
214
319
  headers:
215
320
  {
216
321
  'Accept' => 'application/json',
@@ -225,6 +330,76 @@ describe VagrantPlugins::Openstack::NovaClient do
225
330
  end
226
331
  end
227
332
 
333
+ describe 'get_all_floating_ips' do
334
+ context 'with token and project_id acquainted' do
335
+ it 'returns all floating ips' do
336
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
337
+ .with(headers:
338
+ {
339
+ 'Accept' => 'application/json',
340
+ 'Accept-Encoding' => 'gzip, deflate',
341
+ 'User-Agent' => 'Ruby',
342
+ 'X-Auth-Token' => '123456'
343
+ })
344
+ .to_return(status: 200, body: '
345
+ {
346
+ "floating_ips": [
347
+ {"instance_id": "1234",
348
+ "ip": "185.39.216.45",
349
+ "fixed_ip": "192.168.0.54",
350
+ "id": "2345",
351
+ "pool": "PublicNetwork-01"
352
+ },
353
+ {
354
+ "instance_id": null,
355
+ "ip": "185.39.216.95",
356
+ "fixed_ip": null,
357
+ "id": "3456",
358
+ "pool": "PublicNetwork-02"
359
+ }]
360
+ }')
361
+
362
+ floating_ips = @nova_client.get_all_floating_ips(env)
363
+
364
+ expect(floating_ips).to have(2).items
365
+ expect(floating_ips[0].ip).to eql('185.39.216.45')
366
+ expect(floating_ips[0].instance_id).to eql('1234')
367
+ expect(floating_ips[0].pool).to eql('PublicNetwork-01')
368
+ expect(floating_ips[1].ip).to eql('185.39.216.95')
369
+ expect(floating_ips[1].instance_id).to be(nil)
370
+ expect(floating_ips[1].pool).to eql('PublicNetwork-02')
371
+ end
372
+ end
373
+ end
374
+
375
+ describe 'get_all_floating_ips' do
376
+ context 'with token and project_id acquainted' do
377
+ it 'return newly allocated floating_ip' do
378
+ stub_request(:post, 'http://nova/a1b2c3/os-floating-ips')
379
+ .with(body: '{"pool":"pool-1"}',
380
+ headers: {
381
+ 'Accept' => 'application/json',
382
+ 'Content-Type' => 'application/json',
383
+ 'X-Auth-Token' => '123456' })
384
+ .to_return(status: 200, body: '
385
+ {
386
+ "floating_ip": {
387
+ "instance_id": null,
388
+ "ip": "183.45.67.89",
389
+ "fixed_ip": null,
390
+ "id": "o1o2o3",
391
+ "pool": "pool-1"
392
+ }
393
+ }')
394
+ floating_ip = @nova_client.allocate_floating_ip(env, 'pool-1')
395
+
396
+ expect(floating_ip.ip).to eql('183.45.67.89')
397
+ expect(floating_ip.instance_id).to be(nil)
398
+ expect(floating_ip.pool).to eql('pool-1')
399
+ end
400
+ end
401
+ end
402
+
228
403
  describe 'get_server_details' do
229
404
  context 'with token and project_id acquainted' do
230
405
  it 'returns server details' do
@@ -368,6 +543,72 @@ describe VagrantPlugins::Openstack::NovaClient do
368
543
  expect { @nova_client.add_floating_ip(env, 'o1o2o3', '1.2.3.4') }.to raise_error(RuntimeError)
369
544
  end
370
545
  end
546
+ end
547
+
548
+ describe 'get_floating_ip_pools' do
549
+ context 'with token and project_id acquainted' do
550
+ it 'should return floating ip pool' do
551
+
552
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ip-pools')
553
+ .with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => '123456' })
554
+ .to_return(status: 200, body: '
555
+ {
556
+ "floating_ip_pools": [
557
+ {
558
+ "name": "pool1"
559
+ },
560
+ {
561
+ "name": "pool2"
562
+ }
563
+ ]
564
+ }
565
+ ')
566
+
567
+ pools = @nova_client.get_floating_ip_pools(env)
568
+
569
+ expect(pools[0]['name']).to eq('pool1')
570
+ expect(pools[1]['name']).to eq('pool2')
571
+ end
572
+ end
573
+ end
371
574
 
575
+ describe 'get_floating_ips' do
576
+ context 'with token and project_id acquainted' do
577
+ it 'should return floating ip list' do
578
+
579
+ stub_request(:get, 'http://nova/a1b2c3/os-floating-ips')
580
+ .with(headers: { 'Accept' => 'application/json', 'X-Auth-Token' => '123456' })
581
+ .to_return(status: 200, body: '
582
+ {
583
+ "floating_ips": [
584
+ {
585
+ "fixed_ip": null,
586
+ "id": 1,
587
+ "instance_id": null,
588
+ "ip": "10.10.10.1",
589
+ "pool": "pool1"
590
+ },
591
+ {
592
+ "fixed_ip": null,
593
+ "id": 2,
594
+ "instance_id": "inst001",
595
+ "ip": "10.10.10.2",
596
+ "pool": "pool2"
597
+ }
598
+ ]
599
+ }
600
+ ')
601
+
602
+ ips = @nova_client.get_floating_ips(env)
603
+
604
+ expect(ips[0]['ip']).to eq('10.10.10.1')
605
+ expect(ips[0]['instance_id']).to eq(nil)
606
+ expect(ips[0]['pool']).to eq('pool1')
607
+
608
+ expect(ips[1]['ip']).to eq('10.10.10.2')
609
+ expect(ips[1]['instance_id']).to eq('inst001')
610
+ expect(ips[1]['pool']).to eq('pool2')
611
+ end
612
+ end
372
613
  end
373
614
  end