vagrant-conoha 0.1.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 (109) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rubocop.yml +35 -0
  4. data/CHANGELOG.md +3 -0
  5. data/Gemfile +19 -0
  6. data/LICENSE +23 -0
  7. data/Rakefile +25 -0
  8. data/Vagrantfile +71 -0
  9. data/dummy.box +0 -0
  10. data/example_box/README.md +13 -0
  11. data/example_box/metadata.json +3 -0
  12. data/functional_tests/Vagrantfile +58 -0
  13. data/functional_tests/keys/vagrant-openstack +27 -0
  14. data/functional_tests/keys/vagrant-openstack.pub +1 -0
  15. data/functional_tests/run_tests.sh +142 -0
  16. data/lib/vagrant-conoha.rb +29 -0
  17. data/lib/vagrant-conoha/action.rb +227 -0
  18. data/lib/vagrant-conoha/action/abstract_action.rb +22 -0
  19. data/lib/vagrant-conoha/action/connect_openstack.rb +60 -0
  20. data/lib/vagrant-conoha/action/create_server.rb +154 -0
  21. data/lib/vagrant-conoha/action/create_stack.rb +68 -0
  22. data/lib/vagrant-conoha/action/delete_server.rb +53 -0
  23. data/lib/vagrant-conoha/action/delete_stack.rb +73 -0
  24. data/lib/vagrant-conoha/action/message.rb +19 -0
  25. data/lib/vagrant-conoha/action/provision.rb +60 -0
  26. data/lib/vagrant-conoha/action/read_ssh_info.rb +72 -0
  27. data/lib/vagrant-conoha/action/read_state.rb +43 -0
  28. data/lib/vagrant-conoha/action/resume.rb +24 -0
  29. data/lib/vagrant-conoha/action/start_server.rb +24 -0
  30. data/lib/vagrant-conoha/action/stop_server.rb +25 -0
  31. data/lib/vagrant-conoha/action/suspend.rb +24 -0
  32. data/lib/vagrant-conoha/action/sync_folders.rb +129 -0
  33. data/lib/vagrant-conoha/action/wait_accessible.rb +61 -0
  34. data/lib/vagrant-conoha/action/wait_active.rb +33 -0
  35. data/lib/vagrant-conoha/action/wait_stop.rb +33 -0
  36. data/lib/vagrant-conoha/catalog/openstack_catalog.rb +67 -0
  37. data/lib/vagrant-conoha/client/cinder.rb +39 -0
  38. data/lib/vagrant-conoha/client/domain.rb +159 -0
  39. data/lib/vagrant-conoha/client/glance.rb +65 -0
  40. data/lib/vagrant-conoha/client/heat.rb +49 -0
  41. data/lib/vagrant-conoha/client/http_utils.rb +116 -0
  42. data/lib/vagrant-conoha/client/keystone.rb +77 -0
  43. data/lib/vagrant-conoha/client/neutron.rb +48 -0
  44. data/lib/vagrant-conoha/client/nova.rb +212 -0
  45. data/lib/vagrant-conoha/client/openstack.rb +59 -0
  46. data/lib/vagrant-conoha/client/request_logger.rb +23 -0
  47. data/lib/vagrant-conoha/client/rest_utils.rb +25 -0
  48. data/lib/vagrant-conoha/command/abstract_command.rb +51 -0
  49. data/lib/vagrant-conoha/command/flavor_list.rb +24 -0
  50. data/lib/vagrant-conoha/command/image_list.rb +29 -0
  51. data/lib/vagrant-conoha/command/main.rb +51 -0
  52. data/lib/vagrant-conoha/command/network_list.rb +25 -0
  53. data/lib/vagrant-conoha/command/openstack_command.rb +16 -0
  54. data/lib/vagrant-conoha/command/reset.rb +20 -0
  55. data/lib/vagrant-conoha/command/subnet_list.rb +22 -0
  56. data/lib/vagrant-conoha/command/utils.rb +22 -0
  57. data/lib/vagrant-conoha/command/volume_list.rb +25 -0
  58. data/lib/vagrant-conoha/config.rb +390 -0
  59. data/lib/vagrant-conoha/config/http.rb +39 -0
  60. data/lib/vagrant-conoha/config_resolver.rb +285 -0
  61. data/lib/vagrant-conoha/errors.rb +187 -0
  62. data/lib/vagrant-conoha/logging.rb +39 -0
  63. data/lib/vagrant-conoha/plugin.rb +48 -0
  64. data/lib/vagrant-conoha/provider.rb +50 -0
  65. data/lib/vagrant-conoha/utils.rb +26 -0
  66. data/lib/vagrant-conoha/version.rb +15 -0
  67. data/lib/vagrant-conoha/version_checker.rb +76 -0
  68. data/locales/en.yml +393 -0
  69. data/spec/vagrant-conoha/action/connect_openstack_spec.rb +695 -0
  70. data/spec/vagrant-conoha/action/create_server_spec.rb +225 -0
  71. data/spec/vagrant-conoha/action/create_stack_spec.rb +99 -0
  72. data/spec/vagrant-conoha/action/delete_server_spec.rb +89 -0
  73. data/spec/vagrant-conoha/action/delete_stack_spec.rb +63 -0
  74. data/spec/vagrant-conoha/action/message_spec.rb +33 -0
  75. data/spec/vagrant-conoha/action/provision_spec.rb +104 -0
  76. data/spec/vagrant-conoha/action/read_ssh_info_spec.rb +190 -0
  77. data/spec/vagrant-conoha/action/read_state_spec.rb +81 -0
  78. data/spec/vagrant-conoha/action/resume_server_spec.rb +49 -0
  79. data/spec/vagrant-conoha/action/start_server_spec.rb +49 -0
  80. data/spec/vagrant-conoha/action/stop_server_spec.rb +49 -0
  81. data/spec/vagrant-conoha/action/suspend_server_spec.rb +49 -0
  82. data/spec/vagrant-conoha/action/sync_folders_spec.rb +155 -0
  83. data/spec/vagrant-conoha/action/wait_accessible_spec.rb +67 -0
  84. data/spec/vagrant-conoha/action/wait_active_spec.rb +53 -0
  85. data/spec/vagrant-conoha/action/wait_stop_spec.rb +53 -0
  86. data/spec/vagrant-conoha/action_spec.rb +120 -0
  87. data/spec/vagrant-conoha/client/cinder_spec.rb +127 -0
  88. data/spec/vagrant-conoha/client/glance_spec.rb +143 -0
  89. data/spec/vagrant-conoha/client/heat_spec.rb +128 -0
  90. data/spec/vagrant-conoha/client/keystone_spec.rb +150 -0
  91. data/spec/vagrant-conoha/client/neutron_spec.rb +171 -0
  92. data/spec/vagrant-conoha/client/nova_spec.rb +757 -0
  93. data/spec/vagrant-conoha/client/utils_spec.rb +176 -0
  94. data/spec/vagrant-conoha/command/flavor_list_spec.rb +43 -0
  95. data/spec/vagrant-conoha/command/image_list_spec.rb +95 -0
  96. data/spec/vagrant-conoha/command/network_list_spec.rb +65 -0
  97. data/spec/vagrant-conoha/command/reset_spec.rb +24 -0
  98. data/spec/vagrant-conoha/command/subnet_list_spec.rb +45 -0
  99. data/spec/vagrant-conoha/command/volume_list_spec.rb +40 -0
  100. data/spec/vagrant-conoha/config_resolver_spec.rb +860 -0
  101. data/spec/vagrant-conoha/config_spec.rb +373 -0
  102. data/spec/vagrant-conoha/e2e_spec.rb.save +27 -0
  103. data/spec/vagrant-conoha/provider_spec.rb +13 -0
  104. data/spec/vagrant-conoha/spec_helper.rb +37 -0
  105. data/spec/vagrant-conoha/utils_spec.rb +129 -0
  106. data/spec/vagrant-conoha/version_checker_spec.rb +39 -0
  107. data/stackrc +25 -0
  108. data/vagrant-conoha.gemspec +32 -0
  109. metadata +343 -0
@@ -0,0 +1,40 @@
1
+ require 'vagrant-conoha/spec_helper'
2
+
3
+ describe VagrantPlugins::ConoHa::Command::VolumeList do
4
+ describe 'cmd' do
5
+ let(:cinder) do
6
+ double('cinder').tap do |cinder|
7
+ cinder.stub(:get_all_volumes) do
8
+ [Volume.new('987', 'vol-01', '2', 'available', 'true', nil, nil),
9
+ Volume.new('654', 'vol-02', '4', 'in-use', 'false', 'inst-01', '/dev/vdc')]
10
+ end
11
+ end
12
+ end
13
+
14
+ let(:env) do
15
+ {}.tap do |env|
16
+ env[:ui] = double('ui')
17
+ env[:ui].stub(:info).with(anything)
18
+ env[:openstack_client] = double
19
+ env[:openstack_client].stub(:cinder) { cinder }
20
+ end
21
+ end
22
+
23
+ before :each do
24
+ @volume_list_cmd = VagrantPlugins::ConoHa::Command::VolumeList.new(nil, env)
25
+ end
26
+
27
+ it 'prints volumes list from server' do
28
+ cinder.should_receive(:get_all_volumes).with(env)
29
+ expect(env[:ui]).to receive(:info).with('
30
+ +-----+--------+-----------+-----------+-------------------------------------+
31
+ | Id | Name | Size (Go) | Status | Attachment (instance id and device) |
32
+ +-----+--------+-----------+-----------+-------------------------------------+
33
+ | 987 | vol-01 | 2 | available | |
34
+ | 654 | vol-02 | 4 | in-use | inst-01 (/dev/vdc) |
35
+ +-----+--------+-----------+-----------+-------------------------------------+')
36
+
37
+ @volume_list_cmd.cmd('volume-list', [], env)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,860 @@
1
+ require 'vagrant-conoha/spec_helper'
2
+
3
+ describe VagrantPlugins::ConoHa::ConfigResolver do
4
+ let(:config) do
5
+ double('config').tap do |config|
6
+ config.stub(:tenant_name) { 'testTenant' }
7
+ config.stub(:server_name) { 'testName' }
8
+ config.stub(:floating_ip) { false }
9
+ config.stub(:floating_ip_pool) { false }
10
+ config.stub(:floating_ip_pool_always_allocate) { false }
11
+ config.stub(:keypair_name) { nil }
12
+ config.stub(:public_key_path) { nil }
13
+ config.stub(:networks) { nil }
14
+ config.stub(:volumes) { nil }
15
+ end
16
+ end
17
+
18
+ let(:ssh_key) do
19
+ double('ssh_key').tap do |key|
20
+ key.stub(:ssh_public_key) { 'ssh public key' }
21
+ key.stub(:private_key) { 'private key' }
22
+ end
23
+ end
24
+
25
+ let(:neutron) do
26
+ double('neutron').tap do |neutron|
27
+ neutron.stub(:get_all_networks).with(anything) do
28
+ [Item.new('001', 'net-01'),
29
+ Item.new('002', 'net-02'),
30
+ Item.new('003', 'net-03'),
31
+ Item.new('004', 'net-04'),
32
+ Item.new('005', 'net-05'),
33
+ Item.new('006', 'net-06'),
34
+ Item.new('007', 'net-07-08'),
35
+ Item.new('008', 'net-07-08')]
36
+ end
37
+ end
38
+ end
39
+
40
+ let(:nova) do
41
+ double('nova').tap do |nova|
42
+ nova.stub(:get_all_floating_ips).with(anything) do
43
+ [FloatingIP.new('80.81.82.83', 'pool-1', nil), FloatingIP.new('30.31.32.33', 'pool-2', '1234')]
44
+ end
45
+ end
46
+ end
47
+
48
+ let(:cinder) do
49
+ double('cinder').tap do |cinder|
50
+ cinder.stub(:get_all_volumes).with(anything) do
51
+ [Volume.new('001', 'vol-01', '1', 'available', 'true', nil, nil),
52
+ Volume.new('002', 'vol-02', '2', 'available', 'true', nil, nil),
53
+ Volume.new('003', 'vol-03', '3', 'available', 'true', nil, nil),
54
+ Volume.new('004', 'vol-04', '4', 'available', 'false', nil, nil),
55
+ Volume.new('005', 'vol-05', '5', 'available', 'false', nil, nil),
56
+ Volume.new('006', 'vol-06', '6', 'available', 'false', nil, nil),
57
+ Volume.new('007', 'vol-07-08', '6', 'available', 'false', nil, nil),
58
+ Volume.new('008', 'vol-07-08', '6', 'available', 'false', nil, nil)]
59
+ end
60
+ end
61
+ end
62
+
63
+ let(:session) do
64
+ double('session').tap do |s|
65
+ s.stub(:endpoints) do
66
+ {
67
+ identity: 'http://keystone',
68
+ compute: 'http://nova',
69
+ volume: 'http://cinder',
70
+ network: 'http://neutron'
71
+ }
72
+ end
73
+ end
74
+ end
75
+
76
+ let(:env) do
77
+ {}.tap do |env|
78
+ env[:ui] = double('ui')
79
+ env[:ui].stub(:info).with(anything)
80
+ env[:machine] = double('machine')
81
+ env[:machine].stub(:provider_config) { config }
82
+ env[:machine].stub(:data_dir) { '/data/dir' }
83
+ env[:machine].stub(:config) { machine_config }
84
+ env[:openstack_client] = double('openstack_client')
85
+ env[:openstack_client].stub(:neutron) { neutron }
86
+ env[:openstack_client].stub(:nova) { nova }
87
+ env[:openstack_client].stub(:cinder) { cinder }
88
+ env[:openstack_client].stub(:session) { session }
89
+ end
90
+ end
91
+
92
+ let(:ssh_config) do
93
+ double('ssh_config').tap do |config|
94
+ config.stub(:username) { nil }
95
+ config.stub(:port) { nil }
96
+ end
97
+ end
98
+
99
+ let(:machine_config) do
100
+ double('machine_config').tap do |config|
101
+ config.stub(:ssh) { ssh_config }
102
+ end
103
+ end
104
+
105
+ before :each do
106
+ ConfigResolver.send(:public, *ConfigResolver.private_instance_methods)
107
+ @action = ConfigResolver.new
108
+ end
109
+
110
+ describe 'resolve_ssh_username' do
111
+ context 'with machine.ssh.username' do
112
+ it 'returns machine.ssh.username' do
113
+ ssh_config.stub(:username) { 'machine ssh username' }
114
+ config.stub(:ssh_username) { nil }
115
+ expect(@action.resolve_ssh_username(env)).to eq('machine ssh username')
116
+ end
117
+ end
118
+ context 'with machine.ssh.username and config.ssh_username' do
119
+ it 'returns machine.ssh.username' do
120
+ ssh_config.stub(:username) { 'machine ssh username' }
121
+ config.stub(:ssh_username) { 'provider ssh username' }
122
+ expect(@action.resolve_ssh_username(env)).to eq('machine ssh username')
123
+ end
124
+ end
125
+ context 'with config.ssh_username' do
126
+ it 'returns config.ssh_username' do
127
+ ssh_config.stub(:username) { nil }
128
+ config.stub(:ssh_username) { 'provider ssh username' }
129
+ expect(@action.resolve_ssh_username(env)).to eq('provider ssh username')
130
+ end
131
+ end
132
+ context 'with no ssh username config' do
133
+ it 'fails' do
134
+ ssh_config.stub(:username) { nil }
135
+ config.stub(:ssh_username) { nil }
136
+ expect { @action.resolve_ssh_username(env) }.to raise_error(Errors::NoMatchingSshUsername)
137
+ end
138
+ end
139
+ end
140
+
141
+ describe 'resolve_flavor' do
142
+ context 'with id' do
143
+ it 'returns the specified flavor' do
144
+ config.stub(:flavor) { 'fl-001' }
145
+ nova.stub(:get_all_flavors).with(anything) do
146
+ [Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
147
+ Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
148
+ end
149
+ @action.resolve_flavor(env).should eq(Flavor.new('fl-001', 'flavor-01', 2, 1024, 10))
150
+ end
151
+ end
152
+ context 'with name' do
153
+ it 'returns the specified flavor' do
154
+ config.stub(:flavor) { 'flavor-02' }
155
+ nova.stub(:get_all_flavors).with(anything) do
156
+ [Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
157
+ Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
158
+ end
159
+ @action.resolve_flavor(env).should eq(Flavor.new('fl-002', 'flavor-02', 4, 2048, 50))
160
+ end
161
+ end
162
+ context 'with list' do
163
+ it 'returns the first matching flavor' do
164
+ config.stub(:flavor) { %w(not-existing flavor-02 flavor-01) }
165
+ nova.stub(:get_all_flavors).with(anything) do
166
+ [Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
167
+ Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
168
+ end
169
+ @action.resolve_flavor(env).should eq(Flavor.new('fl-002', 'flavor-02', 4, 2048, 50))
170
+ end
171
+ end
172
+ context 'with invalid identifier' do
173
+ it 'raise an error' do
174
+ config.stub(:flavor) { 'not-existing' }
175
+ nova.stub(:get_all_flavors).with(anything) do
176
+ [Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
177
+ Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
178
+ end
179
+ expect { @action.resolve_flavor(env) }.to raise_error(Errors::NoMatchingFlavor)
180
+ end
181
+ end
182
+ end
183
+
184
+ describe 'resolve_image' do
185
+ context 'with id' do
186
+ it 'returns the specified flavor' do
187
+ config.stub(:image) { 'img-001' }
188
+ config.stub(:volume_boot) { nil }
189
+ nova.stub(:get_all_images).with(anything) do
190
+ [Item.new('img-001', 'image-01'),
191
+ Item.new('img-002', 'image-02')]
192
+ end
193
+ @action.resolve_image(env).should eq(Item.new('img-001', 'image-01'))
194
+ end
195
+ end
196
+ context 'with name' do
197
+ it 'returns the specified flavor' do
198
+ config.stub(:image) { 'image-02' }
199
+ config.stub(:volume_boot) { nil }
200
+ nova.stub(:get_all_images).with(anything) do
201
+ [Item.new('img-001', 'image-01'),
202
+ Item.new('img-002', 'image-02')]
203
+ end
204
+ @action.resolve_image(env).should eq(Item.new('img-002', 'image-02'))
205
+ end
206
+ end
207
+ context 'with invalid identifier' do
208
+ it 'raise an error' do
209
+ config.stub(:image) { 'not-existing' }
210
+ config.stub(:volume_boot) { nil }
211
+ nova.stub(:get_all_images).with(anything) do
212
+ [Item.new('img-001', 'image-01'),
213
+ Item.new('img-002', 'image-02')]
214
+ end
215
+ expect { @action.resolve_image(env) }.to raise_error(Errors::NoMatchingImage)
216
+ end
217
+ end
218
+ context 'with no images in config' do
219
+ it 'return nil' do
220
+ config.stub(:image) { nil }
221
+ config.stub(:volume_boot) { nil }
222
+ nova.stub(:get_all_images).with(anything) do
223
+ [Item.new('img-001', 'image-01'),
224
+ Item.new('img-002', 'image-02')]
225
+ end
226
+ @action.resolve_image(env).should eq(nil)
227
+ end
228
+ end
229
+ end
230
+
231
+ # describe 'resolve_floating_ip' do
232
+ # context 'with config.floating_ip specified' do
233
+ # it 'return the specified floating ip' do
234
+ # config.stub(:floating_ip) { '80.80.80.80' }
235
+ # @action.resolve_floating_ip(env).should eq('80.80.80.80')
236
+ # end
237
+ # end
238
+
239
+ # context 'with only one config.floating_ip_pool specified' do
240
+ # context 'if an ip in the same pool is available' do
241
+ # context 'with config.floating_ip_pool_always_allocate true' do
242
+ # it 'allocate a new floating_ip from the pool' do
243
+ # config.stub(:floating_ip_pool_always_allocate) { true }
244
+ # nova.stub(:get_all_floating_ips).with(anything) do
245
+ # [FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
246
+ # FloatingIP.new('80.81.82.83', 'pool-1', nil)]
247
+ # end
248
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
249
+ # FloatingIP.new('80.81.82.85', 'pool-1', nil)
250
+ # end
251
+ # config.stub(:floating_ip_pool) { ['pool-1'] }
252
+ # @action.resolve_floating_ip(env).should eq('80.81.82.85')
253
+ # end
254
+ # end
255
+
256
+ # context 'with config.floating_ip_pool_always_allocate false' do
257
+ # it 'return one of the available ips' do
258
+ # config.stub(:floating_ip_pool_always_allocate) { false }
259
+ # nova.stub(:get_all_floating_ips).with(anything) do
260
+ # [FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
261
+ # FloatingIP.new('80.81.82.83', 'pool-1', nil)]
262
+ # end
263
+ # config.stub(:floating_ip_pool) { ['pool-1'] }
264
+ # @action.resolve_floating_ip(env).should eq('80.81.82.83')
265
+ # end
266
+ # end
267
+ # end
268
+
269
+ # context 'if no ip in the same pool is available' do
270
+ # it 'allocate a new floating_ip from the pool' do
271
+ # nova.stub(:get_all_floating_ips).with(anything) do
272
+ # [FloatingIP.new('80.81.82.83', 'pool-1', '1234')]
273
+ # end
274
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
275
+ # FloatingIP.new('80.81.82.84', 'pool-1', nil)
276
+ # end
277
+ # config.stub(:floating_ip_pool) { ['pool-1'] }
278
+ # @action.resolve_floating_ip(env).should eq('80.81.82.84')
279
+ # end
280
+ # end
281
+ # end
282
+
283
+ # context 'with several floating_ip_pool defined' do
284
+ # context 'if an ip in a pool is available' do
285
+ # context 'with config.floating_ip_pool_always_allocate true' do
286
+ # it 'allocate a new floating_ip from the first pool defined' do
287
+ # config.stub(:floating_ip_pool_always_allocate) { true }
288
+ # nova.stub(:get_all_floating_ips).with(anything) do
289
+ # [FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
290
+ # FloatingIP.new('80.81.82.83', 'pool-1', nil),
291
+ # FloatingIP.new('80.81.82.82', 'pool-2', '5678')]
292
+ # end
293
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
294
+ # FloatingIP.new('80.81.82.85', 'pool-1', nil)
295
+ # end
296
+ # config.stub(:floating_ip_pool) { %w(pool-1 pool-2) }
297
+ # @action.resolve_floating_ip(env).should eq('80.81.82.85')
298
+ # end
299
+ # end
300
+
301
+ # context 'with config.floating_ip_pool_always_allocate false' do
302
+ # it 'return one of the available ips' do
303
+ # config.stub(:floating_ip_pool_always_allocate) { false }
304
+ # nova.stub(:get_all_floating_ips).with(anything) do
305
+ # [FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
306
+ # FloatingIP.new('80.81.82.83', 'pool-2', nil)]
307
+ # end
308
+ # config.stub(:floating_ip_pool) { %w(pool-1 pool-2) }
309
+ # @action.resolve_floating_ip(env).should eq('80.81.82.83')
310
+ # end
311
+ # end
312
+ # end
313
+
314
+ # context 'if no ip in the pools is available' do
315
+ # context 'if allocate an ip in first pool is possible' do
316
+ # it 'allocate a new floating_ip from first pool' do
317
+ # nova.stub(:get_all_floating_ips).with(anything) do
318
+ # [FloatingIP.new('80.81.82.83', 'pool-1', '1234'),
319
+ # FloatingIP.new('80.81.82.82', 'pool-2', '5678')]
320
+ # end
321
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
322
+ # FloatingIP.new('80.81.82.84', 'pool-1', nil)
323
+ # end
324
+ # config.stub(:floating_ip_pool) { %w(pool-1 pool-2) }
325
+ # @action.resolve_floating_ip(env).should eq('80.81.82.84')
326
+ # end
327
+ # end
328
+
329
+ # context 'if allocate an ip in first pool is not possible' do
330
+ # it 'allocate a new floating_ip from second pool' do
331
+ # nova.stub(:get_all_floating_ips).with(anything) do
332
+ # [FloatingIP.new('80.81.82.83', 'pool-1', '1234'),
333
+ # FloatingIP.new('80.81.82.82', 'pool-2', '5678')]
334
+ # end
335
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-1').and_raise Errors::VagrantOpenstackError, message: 'error', code: 404
336
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-2') do
337
+ # FloatingIP.new('80.81.82.84', 'pool-2', nil)
338
+ # end
339
+ # config.stub(:floating_ip_pool) { %w(pool-1 pool-2) }
340
+ # @action.resolve_floating_ip(env).should eq('80.81.82.84')
341
+ # end
342
+ # end
343
+
344
+ # context 'if allocate an ip in either first and second pool is not possible' do
345
+ # it 'shoud raise an error', :simon do
346
+ # nova.stub(:get_all_floating_ips).with(anything) do
347
+ # [FloatingIP.new('80.81.82.83', 'pool-1', '1234'),
348
+ # FloatingIP.new('80.81.82.82', 'pool-2', '5678')]
349
+ # end
350
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-1').and_raise Errors::VagrantOpenstackError, message: 'error', code: 404
351
+ # nova.stub(:allocate_floating_ip).with(env, 'pool-2').and_raise Errors::VagrantOpenstackError, message: 'error', code: 404
352
+ # config.stub(:floating_ip_pool) { %w(pool-1 pool-2) }
353
+ # expect { @action.resolve_floating_ip(env) }.to raise_error(Errors::VagrantOpenstackError)
354
+ # end
355
+ # end
356
+ # end
357
+ # end
358
+
359
+ # context 'with neither floating_ip nor floating_ip_pool' do
360
+ # it 'fails with an UnableToResolveFloatingIP error' do
361
+ # config.stub(:floating_ip) { nil }
362
+ # config.stub(:floating_ip_pool) { nil }
363
+ # expect { @action.resolve_floating_ip(env) }.to raise_error(Errors::UnableToResolveFloatingIP)
364
+ # end
365
+ # end
366
+ # end
367
+
368
+ describe 'resolve_keypair' do
369
+ context 'with keypair_name provided' do
370
+ it 'return the provided keypair_name' do
371
+ config.stub(:keypair_name) { 'my-keypair' }
372
+ @action.resolve_keypair(env).should eq('my-keypair')
373
+ end
374
+ end
375
+
376
+ context 'with keypair_name and public_key_path provided' do
377
+ it 'return the provided keypair_name' do
378
+ config.stub(:keypair_name) { 'my-keypair' }
379
+ config.stub(:public_key_path) { '/path/to/key' }
380
+ @action.resolve_keypair(env).should eq('my-keypair')
381
+ end
382
+ end
383
+
384
+ context 'with public_key_path provided' do
385
+ it 'return the keypair_name created into nova' do
386
+ config.stub(:public_key_path) { '/path/to/key' }
387
+ nova.stub(:import_keypair_from_file).with(env, '/path/to/key') { 'my-keypair-imported' }
388
+ @action.resolve_keypair(env).should eq('my-keypair-imported')
389
+ end
390
+ end
391
+
392
+ context 'with no keypair_name and no public_key_path provided' do
393
+ it 'generates a new keypair and return the keypair name imported into nova' do
394
+ config.stub(:keypair_name) { nil }
395
+ config.stub(:public_key_path) { nil }
396
+ @action.stub(:generate_keypair) { 'my-keypair-imported' }
397
+ @action.resolve_keypair(env).should eq('my-keypair-imported')
398
+ end
399
+ end
400
+ end
401
+
402
+ describe 'generate_keypair' do
403
+ it 'returns a generated keypair name imported into nova' do
404
+ nova.stub(:import_keypair) { 'my-keypair-imported' }
405
+ SSHKey.stub(:generate) { ssh_key }
406
+ File.should_receive(:write).with('/data/dir/my-keypair-imported', 'private key')
407
+ File.should_receive(:chmod).with(0600, '/data/dir/my-keypair-imported')
408
+ @action.generate_keypair(env).should eq('my-keypair-imported')
409
+ end
410
+ end
411
+
412
+ describe 'resolve_networks' do
413
+ context 'neutron service is available' do
414
+ context 'with network configured in all possible ways' do
415
+ it 'returns normalized network list' do
416
+ config.stub(:networks) do
417
+ ['001',
418
+ 'net-02',
419
+ { id: '003', address: '1.2.3.4' },
420
+ { name: 'net-04', address: '5.6.7.8' },
421
+ { name: 'net-05' },
422
+ { id: '006' }]
423
+ end
424
+
425
+ expect(@action.resolve_networks(env)).to eq [{ uuid: '001' },
426
+ { uuid: '002' },
427
+ { uuid: '003', fixed_ip: '1.2.3.4' },
428
+ { uuid: '004', fixed_ip: '5.6.7.8' },
429
+ { uuid: '005' },
430
+ { uuid: '006' }]
431
+ end
432
+ end
433
+
434
+ context 'with invalid network object' do
435
+ it 'raises an error' do
436
+ config.stub(:networks) { [1] }
437
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::InvalidNetworkObject)
438
+ end
439
+ end
440
+
441
+ context 'with string that is neither an id nor name matching a network' do
442
+ it 'raises an error' do
443
+ config.stub(:networks) { ['not-exist'] }
444
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::UnresolvedNetwork)
445
+ end
446
+ end
447
+
448
+ context 'with hash containing a bad id' do
449
+ it 'raises an error' do
450
+ config.stub(:networks) { [{ id: 'not-exist' }] }
451
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::UnresolvedNetworkId)
452
+ end
453
+ end
454
+
455
+ context 'with hash containing a bad name' do
456
+ it 'raises an error' do
457
+ config.stub(:networks) { [{ name: 'not-exist' }] }
458
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::UnresolvedNetworkName)
459
+ end
460
+ end
461
+
462
+ context 'with empty hash' do
463
+ it 'raises an error' do
464
+ config.stub(:networks) { [{}] }
465
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::ConflictNetworkNameId)
466
+ end
467
+ end
468
+
469
+ context 'with hash containing both id and name' do
470
+ it 'raises an error' do
471
+ config.stub(:networks) { [{ id: '001', name: 'net-01' }] }
472
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::ConflictNetworkNameId)
473
+ end
474
+ end
475
+
476
+ context 'with hash containing a name matching more than one network' do
477
+ it 'raises an error' do
478
+ config.stub(:networks) { [{ name: 'net-07-08' }] }
479
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::MultipleNetworkName)
480
+ end
481
+ end
482
+ end
483
+
484
+ context 'neutron service is not available' do
485
+ context 'with network configured in all possible ways' do
486
+ it 'returns normalized network list' do
487
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
488
+ config.stub(:networks) do
489
+ ['001',
490
+ { id: '003', address: '1.2.3.4' },
491
+ { id: '006' }]
492
+ end
493
+
494
+ expect(@action.resolve_networks(env)).to eq [{ uuid: '001' },
495
+ { uuid: '003', fixed_ip: '1.2.3.4' },
496
+ { uuid: '006' }]
497
+ end
498
+ end
499
+
500
+ context 'with hash containing both id and name' do
501
+ it 'raises an error' do
502
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
503
+ config.stub(:networks) { [{ id: '001', name: 'net-01' }] }
504
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::ConflictNetworkNameId)
505
+ end
506
+ end
507
+
508
+ context 'with hash containing name' do
509
+ it 'raises an error' do
510
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
511
+ config.stub(:networks) { [{ name: 'net-01' }] }
512
+ expect { @action.resolve_networks(env) }.to raise_error(Errors::NetworkServiceUnavailable)
513
+ end
514
+ end
515
+ end
516
+ end
517
+
518
+ describe 'resolve_volume_boot' do
519
+ context 'cinder service is available' do
520
+ context 'with string volume id' do
521
+ it 'returns normalized volume' do
522
+ config.stub(:volume_boot) { '001' }
523
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
524
+ end
525
+ end
526
+
527
+ context 'with string volume name' do
528
+ it 'returns normalized volume' do
529
+ config.stub(:volume_boot) { 'vol-01' }
530
+ nova.stub(:get_all_images).with(anything) do
531
+ [Item.new('img-001', 'image-01'),
532
+ Item.new('img-002', 'image-02')]
533
+ end
534
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
535
+ end
536
+ end
537
+
538
+ context 'with hash volume id' do
539
+ it 'returns normalized volume' do
540
+ config.stub(:volume_boot) { { id: '001' } }
541
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
542
+ end
543
+ end
544
+
545
+ context 'with hash volume name' do
546
+ it 'returns normalized volume' do
547
+ config.stub(:volume_boot) { { name: 'vol-01' } }
548
+ nova.stub(:get_all_images).with(anything) do
549
+ [Item.new('img-001', 'image-01'),
550
+ Item.new('img-002', 'image-02')]
551
+ end
552
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
553
+ end
554
+ end
555
+
556
+ context 'with hash volume id and device' do
557
+ it 'returns normalized volume' do
558
+ config.stub(:volume_boot) { { id: '001', device: 'vdb' } }
559
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vdb'
560
+ end
561
+ end
562
+
563
+ context 'with hash volume name and device' do
564
+ it 'returns normalized volume' do
565
+ config.stub(:volume_boot) { { name: 'vol-01', device: 'vdb' } }
566
+ nova.stub(:get_all_images).with(anything) do
567
+ [Item.new('img-001', 'image-01'),
568
+ Item.new('img-002', 'image-02')]
569
+ end
570
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vdb'
571
+ end
572
+ end
573
+
574
+ context 'with empty hash' do
575
+ it 'raises an error' do
576
+ config.stub(:volume_boot) { {} }
577
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
578
+ end
579
+ end
580
+
581
+ context 'with invalid volume object' do
582
+ it 'raises an error' do
583
+ config.stub(:volume_boot) { 1 }
584
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::InvalidVolumeObject)
585
+ end
586
+ end
587
+
588
+ context 'with hash containing a bad id' do
589
+ it 'raises an error' do
590
+ config.stub(:volume_boot) { { id: 'not-exist' } }
591
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::UnresolvedVolumeId)
592
+ end
593
+ end
594
+
595
+ context 'with hash containing a bad name' do
596
+ it 'raises an error' do
597
+ config.stub(:volume_boot) { { name: 'not-exist' } }
598
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::UnresolvedVolumeName)
599
+ end
600
+ end
601
+
602
+ context 'with hash containing both id and name' do
603
+ it 'raises an error' do
604
+ config.stub(:volume_boot) { { id: '001', name: 'vol-01' } }
605
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictVolumeNameId)
606
+ end
607
+ end
608
+
609
+ context 'with hash containing a name matching more than one volume' do
610
+ it 'raises an error' do
611
+ config.stub(:volume_boot) { { name: 'vol-07-08' } }
612
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::MultipleVolumeName)
613
+ end
614
+ end
615
+
616
+ context 'with hash containing a name and an image_name' do
617
+ it 'raises an error' do
618
+ config.stub(:volume_boot) { { name: 'vol-01', image: 'img_001' } }
619
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
620
+ end
621
+ end
622
+
623
+ context 'with hash containing a name and a size' do
624
+ it 'raises an error' do
625
+ config.stub(:volume_boot) { { name: 'vol-01', size: '10' } }
626
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
627
+ end
628
+ end
629
+
630
+ context 'with hash containing a name and a delete_on_destroy indication' do
631
+ it 'raises an error' do
632
+ config.stub(:volume_boot) { { name: 'vol-01', delete_on_destroy: 'true' } }
633
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
634
+ end
635
+ end
636
+
637
+ context 'with hash containing a volume_id and an image_name' do
638
+ it 'raises an error' do
639
+ config.stub(:volume_boot) { { id: 'id', image: 'img_001' } }
640
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
641
+ end
642
+ end
643
+
644
+ context 'with hash containing a volume_id and a size' do
645
+ it 'raises an error' do
646
+ config.stub(:volume_boot) { { id: 'id', size: '10' } }
647
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
648
+ end
649
+ end
650
+
651
+ context 'with hash containing a volume_id and a delete_on_destroy indication' do
652
+ it 'raises an error' do
653
+ config.stub(:volume_boot) { { id: 'id', delete_on_destroy: 'true' } }
654
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictBootVolume)
655
+ end
656
+ end
657
+
658
+ context 'with hash containing an image_name without size' do
659
+ it 'raises an error' do
660
+ config.stub(:volume_boot) { { image: 'img-001' } }
661
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::UnresolvedVolume)
662
+ end
663
+ end
664
+
665
+ context 'with hash containing an image_name with a size' do
666
+ it 'return normalized volume' do
667
+ config.stub(:volume_boot) { { image: 'image-01', size: '10' } }
668
+ nova.stub(:get_all_images).with(anything) do
669
+ [Item.new('img-001', 'image-01'),
670
+ Item.new('img-002', 'image-02')]
671
+ end
672
+ expect(@action.resolve_volume_boot(env)).to eq image: 'img-001', device: 'vda', size: '10', delete_on_destroy: 'true'
673
+ end
674
+ end
675
+
676
+ context 'with hash containing an image_name, size, device and delete_on_destroy' do
677
+ it 'return normalized volume' do
678
+ config.stub(:volume_boot) { { image: 'image-01', size: '10', device: 'vdb', delete_on_destroy: 'false' } }
679
+ nova.stub(:get_all_images).with(anything) do
680
+ [Item.new('img-001', 'image-01'),
681
+ Item.new('img-002', 'image-02')]
682
+ end
683
+ expect(@action.resolve_volume_boot(env)).to eq image: 'img-001', device: 'vdb', size: '10', delete_on_destroy: 'false'
684
+ end
685
+ end
686
+ end
687
+
688
+ context 'cinder service is not available' do
689
+ context 'with string volume id' do
690
+ it 'returns normalized volume' do
691
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
692
+ config.stub(:volume_boot) { '001' }
693
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
694
+ end
695
+ end
696
+
697
+ context 'with hash volume id' do
698
+ it 'returns normalized volume' do
699
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
700
+ config.stub(:volume_boot) { { id: '001' } }
701
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
702
+ end
703
+ end
704
+
705
+ context 'with hash volume name' do
706
+ it 'raise an error' do
707
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
708
+ config.stub(:volume_boot) { { name: 'vol-01' } }
709
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::VolumeServiceUnavailable)
710
+ end
711
+ end
712
+
713
+ context 'with hash volume id and device' do
714
+ it 'returns normalized volume' do
715
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
716
+ config.stub(:volume_boot) { { id: '001', device: 'vdb' } }
717
+ expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vdb'
718
+ end
719
+ end
720
+
721
+ context 'with hash volume name and device' do
722
+ it 'raise an error' do
723
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
724
+ config.stub(:volume_boot) { { name: 'vol-01', device: 'vdb' } }
725
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::VolumeServiceUnavailable)
726
+ end
727
+ end
728
+
729
+ context 'with invalid volume object' do
730
+ it 'raises an error' do
731
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
732
+ config.stub(:volume_boot) { 1 }
733
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::InvalidVolumeObject)
734
+ end
735
+ end
736
+
737
+ context 'with hash containing both id and name' do
738
+ it 'raises an error' do
739
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
740
+ config.stub(:volume_boot) { { id: '001', name: 'vol-01' } }
741
+ expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictVolumeNameId)
742
+ end
743
+ end
744
+ end
745
+ end
746
+
747
+ describe 'resolve_volumes' do
748
+ context 'cinder service is available' do
749
+ context 'with volume attached in all possible ways' do
750
+ it 'returns normalized volume list' do
751
+ config.stub(:volumes) do
752
+ ['001',
753
+ 'vol-02',
754
+ { id: '003', device: '/dev/vdz' },
755
+ { name: 'vol-04', device: '/dev/vdy' },
756
+ { name: 'vol-05' },
757
+ { id: '006' }]
758
+ end
759
+
760
+ expect(@action.resolve_volumes(env)).to eq [{ id: '001', device: nil },
761
+ { id: '002', device: nil },
762
+ { id: '003', device: '/dev/vdz' },
763
+ { id: '004', device: '/dev/vdy' },
764
+ { id: '005', device: nil },
765
+ { id: '006', device: nil }]
766
+ end
767
+ end
768
+
769
+ context 'with invalid volume object' do
770
+ it 'raises an error' do
771
+ config.stub(:volumes) { [1] }
772
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::InvalidVolumeObject)
773
+ end
774
+ end
775
+
776
+ context 'with string that is neither an id nor name matching a volume' do
777
+ it 'raises an error' do
778
+ config.stub(:volumes) { ['not-exist'] }
779
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::UnresolvedVolume)
780
+ end
781
+ end
782
+
783
+ context 'with hash containing a bad id' do
784
+ it 'raises an error' do
785
+ config.stub(:volumes) { [{ id: 'not-exist' }] }
786
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::UnresolvedVolumeId)
787
+ end
788
+ end
789
+
790
+ context 'with hash containing a bad name' do
791
+ it 'raises an error' do
792
+ config.stub(:volumes) { [{ name: 'not-exist' }] }
793
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::UnresolvedVolumeName)
794
+ end
795
+ end
796
+
797
+ context 'with empty hash' do
798
+ it 'raises an error' do
799
+ config.stub(:volumes) { [{}] }
800
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::ConflictBootVolume)
801
+ end
802
+ end
803
+
804
+ context 'with hash containing both id and name' do
805
+ it 'raises an error' do
806
+ config.stub(:volumes) { [{ id: '001', name: 'vol-01' }] }
807
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::ConflictVolumeNameId)
808
+ end
809
+ end
810
+
811
+ context 'with hash containing a name matching more than one volume' do
812
+ it 'raises an error' do
813
+ config.stub(:volumes) { [{ name: 'vol-07-08' }] }
814
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::MultipleVolumeName)
815
+ end
816
+ end
817
+ end
818
+
819
+ context 'cinder service is not available' do
820
+ context 'with volume attached in all possible ways' do
821
+ it 'returns normalized volume list' do
822
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
823
+ config.stub(:volumes) do
824
+ ['001',
825
+ { id: '003', device: '/dev/vdz' },
826
+ { id: '006' }]
827
+ end
828
+
829
+ expect(@action.resolve_volumes(env)).to eq [{ id: '001', device: nil },
830
+ { id: '003', device: '/dev/vdz' },
831
+ { id: '006', device: nil }]
832
+ end
833
+
834
+ context 'with hash containing both id and name' do
835
+ it 'raises an error' do
836
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
837
+ config.stub(:volumes) { [{ id: '001', name: 'vol-01' }] }
838
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::ConflictVolumeNameId)
839
+ end
840
+ end
841
+ context 'with hash containing name' do
842
+ it 'raises an error' do
843
+ session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
844
+ config.stub(:volumes) { [{ name: 'vol-01' }] }
845
+ expect { @action.resolve_volumes(env) }.to raise_error(Errors::VolumeServiceUnavailable)
846
+ end
847
+ end
848
+ end
849
+ end
850
+ end
851
+
852
+ describe 'resolve_security_groups' do
853
+ context 'with Hash and String objects' do
854
+ it 'returns normalized Hash list' do
855
+ config.stub(:security_groups) { ['group1', { name: 'group2' }] }
856
+ expect(@action.resolve_security_groups(env)).to eq([{ name: 'group1' }, { name: 'group2' }])
857
+ end
858
+ end
859
+ end
860
+ end