vagrant-openstack-provider 0.4.1 → 0.5.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -2
- data/CHANGELOG.md +22 -0
- data/Gemfile +8 -15
- data/Vagrantfile +12 -10
- data/gemfiles/latest_stable.gemfile +6 -16
- data/gemfiles/minimal_release.gemfile +10 -0
- data/gemfiles/previous_release.gemfile +6 -16
- data/lib/vagrant-openstack-provider/action/connect_openstack.rb +2 -1
- data/lib/vagrant-openstack-provider/action/create_server.rb +40 -248
- data/lib/vagrant-openstack-provider/action/read_ssh_info.rb +30 -29
- data/lib/vagrant-openstack-provider/action/sync_folders.rb +19 -9
- data/lib/vagrant-openstack-provider/action/wait_accessible.rb +58 -0
- data/lib/vagrant-openstack-provider/action/wait_active.rb +5 -3
- data/lib/vagrant-openstack-provider/action/wait_stop.rb +5 -3
- data/lib/vagrant-openstack-provider/action.rb +19 -11
- data/lib/vagrant-openstack-provider/client/http_utils.rb +3 -2
- data/lib/vagrant-openstack-provider/client/neutron.rb +11 -1
- data/lib/vagrant-openstack-provider/client/nova.rb +49 -30
- data/lib/vagrant-openstack-provider/command/abstract_command.rb +10 -1
- data/lib/vagrant-openstack-provider/command/flavor_list.rb +1 -1
- data/lib/vagrant-openstack-provider/command/floatingip_list.rb +1 -1
- data/lib/vagrant-openstack-provider/command/image_list.rb +1 -1
- data/lib/vagrant-openstack-provider/command/main.rb +2 -1
- data/lib/vagrant-openstack-provider/command/network_list.rb +8 -2
- data/lib/vagrant-openstack-provider/command/reset.rb +21 -0
- data/lib/vagrant-openstack-provider/command/utils.rb +1 -1
- data/lib/vagrant-openstack-provider/command/volume_list.rb +1 -1
- data/lib/vagrant-openstack-provider/config.rb +16 -1
- data/lib/vagrant-openstack-provider/config_resolver.rb +262 -0
- data/lib/vagrant-openstack-provider/errors.rb +40 -0
- data/lib/vagrant-openstack-provider/plugin.rb +3 -3
- data/lib/vagrant-openstack-provider/utils.rb +21 -0
- data/lib/vagrant-openstack-provider/version.rb +1 -1
- data/locales/en.yml +35 -1
- data/spec/vagrant-openstack-provider/action/create_server_spec.rb +121 -368
- data/spec/vagrant-openstack-provider/action/delete_server_spec.rb +54 -0
- data/spec/vagrant-openstack-provider/action/message_spec.rb +34 -0
- data/spec/vagrant-openstack-provider/action/read_ssh_info_spec.rb +34 -17
- data/spec/vagrant-openstack-provider/action/read_state_spec.rb +70 -0
- data/spec/vagrant-openstack-provider/action/resume_server_spec.rb +50 -0
- data/spec/vagrant-openstack-provider/action/start_server_spec.rb +50 -0
- data/spec/vagrant-openstack-provider/action/stop_server_spec.rb +50 -0
- data/spec/vagrant-openstack-provider/action/suspend_server_spec.rb +50 -0
- data/spec/vagrant-openstack-provider/action/sync_folders_spec.rb +155 -0
- data/spec/vagrant-openstack-provider/action/wait_accessible_spec.rb +68 -0
- data/spec/vagrant-openstack-provider/action/wait_active_spec.rb +47 -0
- data/spec/vagrant-openstack-provider/action/wait_stop_spec.rb +47 -0
- data/spec/vagrant-openstack-provider/action_spec.rb +121 -0
- data/spec/vagrant-openstack-provider/client/cinder_spec.rb +1 -1
- data/spec/vagrant-openstack-provider/client/keystone_spec.rb +1 -1
- data/spec/vagrant-openstack-provider/client/neutron_spec.rb +37 -1
- data/spec/vagrant-openstack-provider/client/nova_spec.rb +60 -7
- data/spec/vagrant-openstack-provider/client/utils_spec.rb +1 -1
- data/spec/vagrant-openstack-provider/command/flavor_list_spec.rb +44 -0
- data/spec/vagrant-openstack-provider/command/floatingip_list_spec.rb +19 -2
- data/spec/vagrant-openstack-provider/command/image_list_spec.rb +48 -0
- data/spec/vagrant-openstack-provider/command/network_list_spec.rb +67 -0
- data/spec/vagrant-openstack-provider/command/reset_spec.rb +25 -0
- data/spec/vagrant-openstack-provider/command/volume_list_spec.rb +10 -2
- data/spec/vagrant-openstack-provider/config_resolver_spec.rb +680 -0
- data/spec/vagrant-openstack-provider/config_spec.rb +15 -1
- data/spec/vagrant-openstack-provider/spec_helper.rb +3 -0
- data/spec/vagrant-openstack-provider/utils_spec.rb +103 -0
- data/vagrant-openstack-provider.gemspec +4 -2
- metadata +78 -11
- data/Appraisals +0 -13
- data/gemfiles/oldest_current.gemfile +0 -20
@@ -47,7 +47,7 @@ describe VagrantPlugins::Openstack::KeystoneClient do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
before :each do
|
50
|
-
@keystone_client = VagrantPlugins::Openstack
|
50
|
+
@keystone_client = VagrantPlugins::Openstack.keystone
|
51
51
|
end
|
52
52
|
|
53
53
|
context 'with good credentials' do
|
@@ -14,7 +14,7 @@ describe VagrantPlugins::Openstack::NeutronClient do
|
|
14
14
|
session.token = '123456'
|
15
15
|
session.project_id = 'a1b2c3'
|
16
16
|
session.endpoints = { network: 'http://neutron' }
|
17
|
-
@neutron_client = VagrantPlugins::Openstack
|
17
|
+
@neutron_client = VagrantPlugins::Openstack.neutron
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'get_private_networks' do
|
@@ -51,6 +51,42 @@ describe VagrantPlugins::Openstack::NeutronClient do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
describe 'get_all_networks' do
|
55
|
+
context 'with token' do
|
56
|
+
it 'returns all networks for project in session' do
|
57
|
+
|
58
|
+
stub_request(:get, 'http://neutron/networks')
|
59
|
+
.with(
|
60
|
+
headers:
|
61
|
+
{
|
62
|
+
'Accept' => 'application/json',
|
63
|
+
'X-Auth-Token' => '123456'
|
64
|
+
})
|
65
|
+
.to_return(
|
66
|
+
status: 200,
|
67
|
+
body: '
|
68
|
+
{
|
69
|
+
"networks": [
|
70
|
+
{ "name": "PublicNetwork", "tenant_id": "admin-tenant-id", "id": "net-pub" },
|
71
|
+
{ "name": "net1", "tenant_id": "a1b2c3", "id": "net-1" },
|
72
|
+
{ "name": "net2", "tenant_id": "a1b2c3", "id": "net-2" }
|
73
|
+
]
|
74
|
+
}
|
75
|
+
')
|
76
|
+
|
77
|
+
networks = @neutron_client.get_all_networks(env)
|
78
|
+
|
79
|
+
expect(networks.length).to eq(3)
|
80
|
+
expect(networks[0].id).to eq('net-pub')
|
81
|
+
expect(networks[0].name).to eq('PublicNetwork')
|
82
|
+
expect(networks[1].id).to eq('net-1')
|
83
|
+
expect(networks[1].name).to eq('net1')
|
84
|
+
expect(networks[2].id).to eq('net-2')
|
85
|
+
expect(networks[2].name).to eq('net2')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
54
90
|
describe 'get_api_version_list' do
|
55
91
|
context 'basic' do
|
56
92
|
it 'returns version list' do
|
@@ -39,7 +39,29 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
39
39
|
session.token = '123456'
|
40
40
|
session.project_id = 'a1b2c3'
|
41
41
|
session.endpoints = { compute: 'http://nova/a1b2c3' }
|
42
|
-
@nova_client = VagrantPlugins::Openstack
|
42
|
+
@nova_client = VagrantPlugins::Openstack.nova
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'instance_exists' do
|
46
|
+
context 'instance not found' do
|
47
|
+
it 'raise an InstanceNotFound error' do
|
48
|
+
stub_request(:post, 'http://nova/a1b2c3/servers/o1o2o3/action')
|
49
|
+
.with(
|
50
|
+
body: '{"os-start":null}',
|
51
|
+
headers:
|
52
|
+
{
|
53
|
+
'Accept' => 'application/json',
|
54
|
+
'Content-Type' => 'application/json',
|
55
|
+
'X-Auth-Token' => '123456'
|
56
|
+
})
|
57
|
+
.to_return(
|
58
|
+
status: 404,
|
59
|
+
body: '{"itemNotFound": {"message": "Instance could not be found", "code": 404}}')
|
60
|
+
|
61
|
+
expect { @nova_client.start_server(env, 'o1o2o3') }.to raise_error(VagrantPlugins::Openstack::Errors::InstanceNotFound)
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
43
65
|
end
|
44
66
|
|
45
67
|
describe 'get_all_flavors' do
|
@@ -119,7 +141,7 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
119
141
|
stub_request(:post, 'http://nova/a1b2c3/servers')
|
120
142
|
.with(
|
121
143
|
body: '{"server":{"name":"inst","imageRef":"img","flavorRef":"flav","key_name":"key",'\
|
122
|
-
'"security_groups":["default"],"user_data":"
|
144
|
+
'"security_groups":[{"name":"default"}],"user_data":"dXNlcl9kYXRhX3Rlc3Q=\n","metadata":"metadata_test"},'\
|
123
145
|
'"scheduler_hints":"sched_hints_test"}',
|
124
146
|
headers:
|
125
147
|
{
|
@@ -136,7 +158,7 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
136
158
|
flavor_ref: 'flav',
|
137
159
|
networks: nil,
|
138
160
|
keypair: 'key',
|
139
|
-
security_groups: ['default'],
|
161
|
+
security_groups: [{ name: 'default' }],
|
140
162
|
user_data: 'user_data_test',
|
141
163
|
metadata: 'metadata_test',
|
142
164
|
scheduler_hints: 'sched_hints_test')
|
@@ -145,7 +167,7 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
145
167
|
end
|
146
168
|
end
|
147
169
|
|
148
|
-
context 'with
|
170
|
+
context 'with two networks' do
|
149
171
|
it 'returns new instance id' do
|
150
172
|
|
151
173
|
stub_request(:post, 'http://nova/a1b2c3/servers')
|
@@ -159,7 +181,8 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
159
181
|
})
|
160
182
|
.to_return(status: 202, body: '{ "server": { "id": "o1o2o3" } }')
|
161
183
|
|
162
|
-
instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav',
|
184
|
+
instance_id = @nova_client.create_server(env, name: 'inst', image_ref: 'img', flavor_ref: 'flav',
|
185
|
+
networks: [{ uuid: 'net1' }, { uuid: 'net2' }], keypair: 'key')
|
163
186
|
|
164
187
|
expect(instance_id).to eq('o1o2o3')
|
165
188
|
end
|
@@ -230,7 +253,7 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
230
253
|
it 'returns newly created keypair name' do
|
231
254
|
File.should_receive(:exist?).with(filename).and_return(true)
|
232
255
|
File.should_receive(:open).with(filename).and_return(file)
|
233
|
-
Kernel.stub
|
256
|
+
Kernel.stub(:rand).and_return(2_036_069_739_008)
|
234
257
|
|
235
258
|
stub_request(:post, 'http://nova/a1b2c3/os-keypairs')
|
236
259
|
.with(
|
@@ -413,7 +436,8 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
413
436
|
|
414
437
|
floating_ips = @nova_client.get_all_floating_ips(env)
|
415
438
|
|
416
|
-
expect(floating_ips).
|
439
|
+
expect(floating_ips).not_to be_nil
|
440
|
+
expect(floating_ips.size).to eq(2)
|
417
441
|
expect(floating_ips[0].ip).to eql('185.39.216.45')
|
418
442
|
expect(floating_ips[0].instance_id).to eql('1234')
|
419
443
|
expect(floating_ips[0].pool).to eql('PublicNetwork-01')
|
@@ -663,4 +687,33 @@ describe VagrantPlugins::Openstack::NovaClient do
|
|
663
687
|
end
|
664
688
|
end
|
665
689
|
end
|
690
|
+
|
691
|
+
describe 'attach_volume' do
|
692
|
+
context 'with token and project_id acquainted' do
|
693
|
+
context 'with volume id and device' do
|
694
|
+
it 'call the nova api' do
|
695
|
+
stub_request(:post, 'http://nova/a1b2c3/servers/9876/os-volume_attachments')
|
696
|
+
.with(headers:
|
697
|
+
{
|
698
|
+
'Accept' => 'application/json',
|
699
|
+
'X-Auth-Token' => '123456'
|
700
|
+
},
|
701
|
+
body: '{"volumeAttachment":{"volumeId":"n1n2","device":"/dev/vdg"}}')
|
702
|
+
.to_return(status: 200, body: '
|
703
|
+
{
|
704
|
+
"volumeAttachment": {
|
705
|
+
"device": "/dev/vdg",
|
706
|
+
"id": "attachment-01",
|
707
|
+
"serverId": "9876",
|
708
|
+
"volumeId": "n1n2"
|
709
|
+
}
|
710
|
+
}
|
711
|
+
')
|
712
|
+
|
713
|
+
attachment = @nova_client.attach_volume(env, '9876', 'n1n2', '/dev/vdg')
|
714
|
+
expect(attachment['id']).to eq('attachment-01')
|
715
|
+
end
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
666
719
|
end
|
@@ -128,7 +128,7 @@ describe VagrantPlugins::Openstack::HttpUtils do
|
|
128
128
|
end
|
129
129
|
|
130
130
|
context 'response code is 404' do
|
131
|
-
it 'should
|
131
|
+
it 'should raise a VagrantOpenstackError with conflict message' do
|
132
132
|
mock_resp = double.tap do |mock|
|
133
133
|
mock.stub(:code).and_return(404)
|
134
134
|
mock.stub(:headers)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'vagrant-openstack-provider/spec_helper'
|
2
|
+
|
3
|
+
describe VagrantPlugins::Openstack::Command::FlavorList do
|
4
|
+
describe 'cmd' do
|
5
|
+
|
6
|
+
let(:nova) do
|
7
|
+
double('nova').tap do |nova|
|
8
|
+
nova.stub(:get_all_flavors) do
|
9
|
+
[
|
10
|
+
Flavor.new('001', 'small', '1', '1024', '10'),
|
11
|
+
Flavor.new('002', 'large', '4', '4096', '100')
|
12
|
+
]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:env) do
|
18
|
+
Hash.new.tap do |env|
|
19
|
+
env[:ui] = double('ui')
|
20
|
+
env[:ui].stub(:info).with(anything)
|
21
|
+
env[:openstack_client] = double
|
22
|
+
env[:openstack_client].stub(:nova) { nova }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
before :each do
|
27
|
+
@flavor_list_cmd = VagrantPlugins::Openstack::Command::FlavorList.new(nil, env)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'prints flovor list from server' do
|
31
|
+
nova.should_receive(:get_all_flavors).with(env)
|
32
|
+
|
33
|
+
expect(env[:ui]).to receive(:info).with('
|
34
|
+
+-----+-------+------+----------+----------------+
|
35
|
+
| Id | Name | vCPU | RAM (Mo) | Disk size (Go) |
|
36
|
+
+-----+-------+------+----------+----------------+
|
37
|
+
| 001 | small | 1 | 1024 | 10 |
|
38
|
+
| 002 | large | 4 | 4096 | 100 |
|
39
|
+
+-----+-------+------+----------+----------------+')
|
40
|
+
|
41
|
+
@flavor_list_cmd.cmd('flavor-list', [], env)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -49,10 +49,27 @@ describe VagrantPlugins::Openstack::Command::FloatingIpList do
|
|
49
49
|
@floating_ip_list_cmd = VagrantPlugins::Openstack::Command::FloatingIpList.new(nil, env)
|
50
50
|
end
|
51
51
|
|
52
|
-
it '
|
52
|
+
it 'prints floating ip and floating ip pool from server' do
|
53
53
|
nova.should_receive(:get_floating_ip_pools).with(env)
|
54
54
|
nova.should_receive(:get_floating_ips).with(env)
|
55
|
-
|
55
|
+
|
56
|
+
expect(env[:ui]).to receive(:info).with('
|
57
|
+
+-------------------+
|
58
|
+
| Floating IP pools |
|
59
|
+
+-------------------+
|
60
|
+
| pool1 |
|
61
|
+
| pool2 |
|
62
|
+
+-------------------+').ordered
|
63
|
+
|
64
|
+
expect(env[:ui]).to receive(:info).with('
|
65
|
+
+----+------------+-------+-------------+
|
66
|
+
| Id | IP | Pool | Instance id |
|
67
|
+
+----+------------+-------+-------------+
|
68
|
+
| 1 | 10.10.10.1 | pool1 | |
|
69
|
+
| 2 | 10.10.10.2 | pool2 | inst001 |
|
70
|
+
+----+------------+-------+-------------+').ordered
|
71
|
+
|
72
|
+
@floating_ip_list_cmd.cmd('floatingip-list', [], env)
|
56
73
|
end
|
57
74
|
end
|
58
75
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'vagrant-openstack-provider/spec_helper'
|
2
|
+
|
3
|
+
describe VagrantPlugins::Openstack::Command::ImageList do
|
4
|
+
describe 'cmd' do
|
5
|
+
|
6
|
+
let(:nova) do
|
7
|
+
double('nova').tap do |nova|
|
8
|
+
nova.stub(:get_all_images) do
|
9
|
+
[
|
10
|
+
Item.new('0001', 'ubuntu'),
|
11
|
+
Item.new('0002', 'centos'),
|
12
|
+
Item.new('0003', 'debian')
|
13
|
+
]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:env) do
|
19
|
+
Hash.new.tap do |env|
|
20
|
+
env[:ui] = double('ui')
|
21
|
+
env[:ui].stub(:info).with(anything)
|
22
|
+
env[:openstack_client] = double
|
23
|
+
env[:openstack_client].stub(:nova) { nova }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
before :each do
|
28
|
+
@image_list_cmd = VagrantPlugins::Openstack::Command::ImageList.new(['--'], env)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'prints image list from server' do
|
32
|
+
|
33
|
+
allow(@image_list_cmd).to receive(:with_target_vms).and_return(nil)
|
34
|
+
|
35
|
+
nova.should_receive(:get_all_images).with(env)
|
36
|
+
|
37
|
+
expect(env[:ui]).to receive(:info).with('
|
38
|
+
+------+--------+
|
39
|
+
| Id | Name |
|
40
|
+
+------+--------+
|
41
|
+
| 0001 | ubuntu |
|
42
|
+
| 0002 | centos |
|
43
|
+
| 0003 | debian |
|
44
|
+
+------+--------+')
|
45
|
+
@image_list_cmd.cmd('image-list', [], env)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'vagrant-openstack-provider/spec_helper'
|
2
|
+
|
3
|
+
describe VagrantPlugins::Openstack::Command::NetworkList do
|
4
|
+
describe 'cmd' do
|
5
|
+
|
6
|
+
let(:neutron) do
|
7
|
+
double('neutron').tap do |neutron|
|
8
|
+
neutron.stub(:get_private_networks) do
|
9
|
+
[
|
10
|
+
Item.new('net-01', 'internal'),
|
11
|
+
Item.new('net-02', 'external')
|
12
|
+
]
|
13
|
+
end
|
14
|
+
neutron.stub(:get_all_networks) do
|
15
|
+
[
|
16
|
+
Item.new('pub-01', 'public'),
|
17
|
+
Item.new('net-01', 'internal'),
|
18
|
+
Item.new('net-02', 'external')
|
19
|
+
]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:env) do
|
25
|
+
Hash.new.tap do |env|
|
26
|
+
env[:ui] = double('ui')
|
27
|
+
env[:ui].stub(:info).with(anything)
|
28
|
+
env[:openstack_client] = double
|
29
|
+
env[:openstack_client].stub(:neutron) { neutron }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
before :each do
|
34
|
+
@network_list_cmd = VagrantPlugins::Openstack::Command::NetworkList.new(nil, env)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'prints network list from server' do
|
38
|
+
neutron.should_receive(:get_private_networks).with(env)
|
39
|
+
|
40
|
+
expect(env[:ui]).to receive(:info).with('
|
41
|
+
+--------+----------+
|
42
|
+
| Id | Name |
|
43
|
+
+--------+----------+
|
44
|
+
| net-01 | internal |
|
45
|
+
| net-02 | external |
|
46
|
+
+--------+----------+')
|
47
|
+
|
48
|
+
@network_list_cmd.cmd('network-list', [], env)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'prints all networks list from server' do
|
52
|
+
neutron.should_receive(:get_all_networks).with(env)
|
53
|
+
|
54
|
+
expect(env[:ui]).to receive(:info).with('
|
55
|
+
+--------+----------+
|
56
|
+
| Id | Name |
|
57
|
+
+--------+----------+
|
58
|
+
| pub-01 | public |
|
59
|
+
| net-01 | internal |
|
60
|
+
| net-02 | external |
|
61
|
+
+--------+----------+')
|
62
|
+
|
63
|
+
@network_list_cmd.cmd('network-list', ['all'], env)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'vagrant-openstack-provider/spec_helper'
|
2
|
+
|
3
|
+
describe VagrantPlugins::Openstack::Command::Reset do
|
4
|
+
describe 'cmd' do
|
5
|
+
|
6
|
+
let(:env) do
|
7
|
+
Hash.new.tap do |env|
|
8
|
+
env[:ui] = double('ui')
|
9
|
+
env[:ui].stub(:info).with(anything)
|
10
|
+
env[:machine] = double('machine')
|
11
|
+
env[:machine].stub(:data_dir) { '/my/data/dir' }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@reset_cmd = VagrantPlugins::Openstack::Command::Reset.new(nil, env)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'resets vagrant openstack machines' do
|
20
|
+
expect(env[:ui]).to receive(:info).with('Vagrant OpenStack Provider has been reset')
|
21
|
+
expect(FileUtils).to receive(:remove_dir).with('/my/data/dir')
|
22
|
+
@reset_cmd.cmd('reset', [], env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'vagrant-openstack-provider/spec_helper'
|
2
2
|
|
3
|
-
describe VagrantPlugins::Openstack::Command::
|
3
|
+
describe VagrantPlugins::Openstack::Command::VolumeList do
|
4
4
|
describe 'cmd' do
|
5
5
|
|
6
6
|
let(:cinder) do
|
@@ -25,8 +25,16 @@ describe VagrantPlugins::Openstack::Command::FloatingIpList do
|
|
25
25
|
@volume_list_cmd = VagrantPlugins::Openstack::Command::VolumeList.new(nil, env)
|
26
26
|
end
|
27
27
|
|
28
|
-
it '
|
28
|
+
it 'prints volumes list from server' do
|
29
29
|
cinder.should_receive(:get_all_volumes).with(env)
|
30
|
+
expect(env[:ui]).to receive(:info).with('
|
31
|
+
+-----+--------+-----------+-----------+-------------------------------------+
|
32
|
+
| Id | Name | Size (Go) | Status | Attachment (instance id and device) |
|
33
|
+
+-----+--------+-----------+-----------+-------------------------------------+
|
34
|
+
| 987 | vol-01 | 2 | available | |
|
35
|
+
| 654 | vol-02 | 4 | in-use | inst-01 (/dev/vdc) |
|
36
|
+
+-----+--------+-----------+-----------+-------------------------------------+')
|
37
|
+
|
30
38
|
@volume_list_cmd.cmd('volume-list', [], env)
|
31
39
|
end
|
32
40
|
end
|
@@ -0,0 +1,680 @@
|
|
1
|
+
require 'vagrant-openstack-provider/spec_helper'
|
2
|
+
|
3
|
+
describe VagrantPlugins::Openstack::ConfigResolver do
|
4
|
+
|
5
|
+
let(:config) do
|
6
|
+
double('config').tap do |config|
|
7
|
+
config.stub(:tenant_name) { 'testTenant' }
|
8
|
+
config.stub(:server_name) { 'testName' }
|
9
|
+
config.stub(:floating_ip) { nil }
|
10
|
+
config.stub(:floating_ip_pool) { nil }
|
11
|
+
config.stub(:floating_ip_pool_always_allocate) { false }
|
12
|
+
config.stub(:keypair_name) { nil }
|
13
|
+
config.stub(:public_key_path) { nil }
|
14
|
+
config.stub(:networks) { nil }
|
15
|
+
config.stub(:volumes) { nil }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:ssh_key) do
|
20
|
+
double('ssh_key').tap do |key|
|
21
|
+
key.stub(:ssh_public_key) { 'ssh public key' }
|
22
|
+
key.stub(:private_key) { 'private key' }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:neutron) do
|
27
|
+
double('neutron').tap do |neutron|
|
28
|
+
neutron.stub(:get_private_networks).with(anything) do
|
29
|
+
[Item.new('001', 'net-01'),
|
30
|
+
Item.new('002', 'net-02'),
|
31
|
+
Item.new('003', 'net-03'),
|
32
|
+
Item.new('004', 'net-04'),
|
33
|
+
Item.new('005', 'net-05'),
|
34
|
+
Item.new('006', 'net-06'),
|
35
|
+
Item.new('007', 'net-07-08'),
|
36
|
+
Item.new('008', 'net-07-08')]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:nova) do
|
42
|
+
double('nova').tap do |nova|
|
43
|
+
nova.stub(:get_all_floating_ips).with(anything) do
|
44
|
+
[FloatingIP.new('80.81.82.83', 'pool-1', nil), FloatingIP.new('30.31.32.33', 'pool-2', '1234')]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:cinder) do
|
50
|
+
double('cinder').tap do |cinder|
|
51
|
+
cinder.stub(:get_all_volumes).with(anything) do
|
52
|
+
[Volume.new('001', 'vol-01', '1', 'available', 'true', nil, nil),
|
53
|
+
Volume.new('002', 'vol-02', '2', 'available', 'true', nil, nil),
|
54
|
+
Volume.new('003', 'vol-03', '3', 'available', 'true', nil, nil),
|
55
|
+
Volume.new('004', 'vol-04', '4', 'available', 'false', nil, nil),
|
56
|
+
Volume.new('005', 'vol-05', '5', 'available', 'false', nil, nil),
|
57
|
+
Volume.new('006', 'vol-06', '6', 'available', 'false', nil, nil),
|
58
|
+
Volume.new('007', 'vol-07-08', '6', 'available', 'false', nil, nil),
|
59
|
+
Volume.new('008', 'vol-07-08', '6', 'available', 'false', nil, nil)]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
let(:session) do
|
65
|
+
double('session').tap do |s|
|
66
|
+
s.stub(:endpoints) do
|
67
|
+
{
|
68
|
+
identity: 'http://keystone',
|
69
|
+
compute: 'http://nova',
|
70
|
+
volume: 'http://cinder',
|
71
|
+
network: 'http://neutron'
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
let(:env) do
|
78
|
+
Hash.new.tap do |env|
|
79
|
+
env[:ui] = double('ui')
|
80
|
+
env[:ui].stub(:info).with(anything)
|
81
|
+
env[:machine] = double('machine')
|
82
|
+
env[:machine].stub(:provider_config) { config }
|
83
|
+
env[:machine].stub(:data_dir) { '/data/dir' }
|
84
|
+
env[:machine].stub(:config) { machine_config }
|
85
|
+
env[:openstack_client] = double('openstack_client')
|
86
|
+
env[:openstack_client].stub(:neutron) { neutron }
|
87
|
+
env[:openstack_client].stub(:nova) { nova }
|
88
|
+
env[:openstack_client].stub(:cinder) { cinder }
|
89
|
+
env[:openstack_client].stub(:session) { session }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
let(:ssh_config) do
|
94
|
+
double('ssh_config').tap do |config|
|
95
|
+
config.stub(:username) { nil }
|
96
|
+
config.stub(:port) { nil }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
let(:machine_config) do
|
101
|
+
double('machine_config').tap do |config|
|
102
|
+
config.stub(:ssh) { ssh_config }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
before :each do
|
107
|
+
ConfigResolver.send(:public, *ConfigResolver.private_instance_methods)
|
108
|
+
@action = ConfigResolver.new
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'resolve_ssh_username' do
|
112
|
+
context 'with machine.ssh.username' do
|
113
|
+
it 'returns machine.ssh.username' do
|
114
|
+
ssh_config.stub(:username) { 'machine ssh username' }
|
115
|
+
config.stub(:ssh_username) { nil }
|
116
|
+
expect(@action.resolve_ssh_username(env)).to eq('machine ssh username')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
context 'with machine.ssh.username and config.ssh_username' do
|
120
|
+
it 'returns machine.ssh.username' do
|
121
|
+
ssh_config.stub(:username) { 'machine ssh username' }
|
122
|
+
config.stub(:ssh_username) { 'provider ssh username' }
|
123
|
+
expect(@action.resolve_ssh_username(env)).to eq('machine ssh username')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
context 'with config.ssh_username' do
|
127
|
+
it 'returns config.ssh_username' do
|
128
|
+
ssh_config.stub(:username) { nil }
|
129
|
+
config.stub(:ssh_username) { 'provider ssh username' }
|
130
|
+
expect(@action.resolve_ssh_username(env)).to eq('provider ssh username')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
context 'with no ssh username config' do
|
134
|
+
it 'fails' do
|
135
|
+
ssh_config.stub(:username) { nil }
|
136
|
+
config.stub(:ssh_username) { nil }
|
137
|
+
expect { @action.resolve_ssh_username(env) }.to raise_error(Errors::NoMatchingSshUsername)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'resolve_flavor' do
|
143
|
+
context 'with id' do
|
144
|
+
it 'returns the specified flavor' do
|
145
|
+
config.stub(:flavor) { 'fl-001' }
|
146
|
+
nova.stub(:get_all_flavors).with(anything) do
|
147
|
+
[Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
|
148
|
+
Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
|
149
|
+
end
|
150
|
+
@action.resolve_flavor(env).should eq(Flavor.new('fl-001', 'flavor-01', 2, 1024, 10))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
context 'with name' do
|
154
|
+
it 'returns the specified flavor' do
|
155
|
+
config.stub(:flavor) { 'flavor-02' }
|
156
|
+
nova.stub(:get_all_flavors).with(anything) do
|
157
|
+
[Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
|
158
|
+
Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
|
159
|
+
end
|
160
|
+
@action.resolve_flavor(env).should eq(Flavor.new('fl-002', 'flavor-02', 4, 2048, 50))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
context 'with invalid identifier' do
|
164
|
+
it 'raise an error' do
|
165
|
+
config.stub(:flavor) { 'not-existing' }
|
166
|
+
nova.stub(:get_all_flavors).with(anything) do
|
167
|
+
[Flavor.new('fl-001', 'flavor-01', 2, 1024, 10),
|
168
|
+
Flavor.new('fl-002', 'flavor-02', 4, 2048, 50)]
|
169
|
+
end
|
170
|
+
expect { @action.resolve_flavor(env) }.to raise_error(Errors::NoMatchingFlavor)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe 'resolve_image' do
|
176
|
+
context 'with id' do
|
177
|
+
it 'returns the specified flavor' do
|
178
|
+
config.stub(:image) { 'img-001' }
|
179
|
+
nova.stub(:get_all_images).with(anything) do
|
180
|
+
[Item.new('img-001', 'image-01'),
|
181
|
+
Item.new('img-002', 'image-02')]
|
182
|
+
end
|
183
|
+
@action.resolve_image(env).should eq(Item.new('img-001', 'image-01'))
|
184
|
+
end
|
185
|
+
end
|
186
|
+
context 'with name' do
|
187
|
+
it 'returns the specified flavor' do
|
188
|
+
config.stub(:image) { 'image-02' }
|
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-002', 'image-02'))
|
194
|
+
end
|
195
|
+
end
|
196
|
+
context 'with invalid identifier' do
|
197
|
+
it 'raise an error' do
|
198
|
+
config.stub(:image) { 'not-existing' }
|
199
|
+
nova.stub(:get_all_images).with(anything) do
|
200
|
+
[Item.new('img-001', 'image-01'),
|
201
|
+
Item.new('img-002', 'image-02')]
|
202
|
+
end
|
203
|
+
expect { @action.resolve_image(env) }.to raise_error(Errors::NoMatchingImage)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe 'resolve_floating_ip' do
|
209
|
+
context 'with config.floating_ip specified' do
|
210
|
+
it 'return the specified floating ip' do
|
211
|
+
config.stub(:floating_ip) { '80.80.80.80' }
|
212
|
+
@action.resolve_floating_ip(env).should eq('80.80.80.80')
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'with config.floating_pool specified' do
|
217
|
+
context 'if any ip in the same pool is available' do
|
218
|
+
context 'with config.floating_pool_always_allocate true' do
|
219
|
+
it 'allocate a new floating_ip from the pool' do
|
220
|
+
config.stub(:floating_ip_pool_always_allocate) { true }
|
221
|
+
nova.stub(:get_all_floating_ips).with(anything) do
|
222
|
+
[FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
|
223
|
+
FloatingIP.new('80.81.82.83', 'pool-1', nil)]
|
224
|
+
end
|
225
|
+
nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
|
226
|
+
FloatingIP.new('80.81.82.84', 'pool-1', nil)
|
227
|
+
end
|
228
|
+
config.stub(:floating_ip_pool) { 'pool-1' }
|
229
|
+
@action.resolve_floating_ip(env).should eq('80.81.82.84')
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context 'with config.floating_pool_always_allocate false' do
|
234
|
+
it 'return one of the available ips' do
|
235
|
+
config.stub(:floating_ip_pool_always_allocate) { false }
|
236
|
+
nova.stub(:get_all_floating_ips).with(anything) do
|
237
|
+
[FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
|
238
|
+
FloatingIP.new('80.81.82.83', 'pool-1', nil)]
|
239
|
+
end
|
240
|
+
config.stub(:floating_ip_pool) { 'pool-1' }
|
241
|
+
@action.resolve_floating_ip(env).should eq('80.81.82.83')
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'if no ip in the same pool is available' do
|
247
|
+
it 'allocate a new floating_ip from the pool' do
|
248
|
+
nova.stub(:get_all_floating_ips).with(anything) do
|
249
|
+
[FloatingIP.new('80.81.82.83', 'pool-1', '1234')]
|
250
|
+
end
|
251
|
+
nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
|
252
|
+
FloatingIP.new('80.81.82.84', 'pool-1', nil)
|
253
|
+
end
|
254
|
+
config.stub(:floating_ip_pool) { 'pool-1' }
|
255
|
+
@action.resolve_floating_ip(env).should eq('80.81.82.84')
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'with neither floating_ip nor floating_ip_pool' do
|
261
|
+
it 'fails with an UnableToResolveFloatingIP error' do
|
262
|
+
config.stub(:floating_ip) { nil }
|
263
|
+
config.stub(:floating_ip_pool) { nil }
|
264
|
+
expect { @action.resolve_floating_ip(env) }.to raise_error(Errors::UnableToResolveFloatingIP)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe 'resolve_keypair' do
|
270
|
+
context 'with keypair_name provided' do
|
271
|
+
it 'return the provided keypair_name' do
|
272
|
+
config.stub(:keypair_name) { 'my-keypair' }
|
273
|
+
@action.resolve_keypair(env).should eq('my-keypair')
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'with keypair_name and public_key_path provided' do
|
278
|
+
it 'return the provided keypair_name' do
|
279
|
+
config.stub(:keypair_name) { 'my-keypair' }
|
280
|
+
config.stub(:public_key_path) { '/path/to/key' }
|
281
|
+
@action.resolve_keypair(env).should eq('my-keypair')
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'with public_key_path provided' do
|
286
|
+
it 'return the keypair_name created into nova' do
|
287
|
+
config.stub(:public_key_path) { '/path/to/key' }
|
288
|
+
nova.stub(:import_keypair_from_file).with(env, '/path/to/key') { 'my-keypair-imported' }
|
289
|
+
@action.resolve_keypair(env).should eq('my-keypair-imported')
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context 'with no keypair_name and no public_key_path provided' do
|
294
|
+
it 'generates a new keypair and return the keypair name imported into nova' do
|
295
|
+
config.stub(:keypair_name) { nil }
|
296
|
+
config.stub(:public_key_path) { nil }
|
297
|
+
@action.stub(:generate_keypair) { 'my-keypair-imported' }
|
298
|
+
@action.resolve_keypair(env).should eq('my-keypair-imported')
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe 'generate_keypair' do
|
304
|
+
it 'returns a generated keypair name imported into nova' do
|
305
|
+
nova.stub(:import_keypair) { 'my-keypair-imported' }
|
306
|
+
SSHKey.stub(:generate) { ssh_key }
|
307
|
+
File.should_receive(:write).with('/data/dir/my-keypair-imported', 'private key')
|
308
|
+
File.should_receive(:chmod).with(0600, '/data/dir/my-keypair-imported')
|
309
|
+
@action.generate_keypair(env).should eq('my-keypair-imported')
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe 'resolve_networks' do
|
314
|
+
context 'neutron service is available' do
|
315
|
+
context 'with network configured in all possible ways' do
|
316
|
+
it 'returns normalized network list' do
|
317
|
+
|
318
|
+
config.stub(:networks) do
|
319
|
+
['001',
|
320
|
+
'net-02',
|
321
|
+
{ id: '003', address: '1.2.3.4' },
|
322
|
+
{ name: 'net-04', address: '5.6.7.8' },
|
323
|
+
{ name: 'net-05' },
|
324
|
+
{ id: '006' }]
|
325
|
+
end
|
326
|
+
|
327
|
+
expect(@action.resolve_networks(env)).to eq [{ uuid: '001' },
|
328
|
+
{ uuid: '002' },
|
329
|
+
{ uuid: '003', fixed_ip: '1.2.3.4' },
|
330
|
+
{ uuid: '004', fixed_ip: '5.6.7.8' },
|
331
|
+
{ uuid: '005' },
|
332
|
+
{ uuid: '006' }]
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context 'with invalid network object' do
|
337
|
+
it 'raises an error' do
|
338
|
+
config.stub(:networks) { [1] }
|
339
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::InvalidNetworkObject)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context 'with string that is neither an id nor name matching a network' do
|
344
|
+
it 'raises an error' do
|
345
|
+
config.stub(:networks) { ['not-exist'] }
|
346
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::UnresolvedNetwork)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
context 'with hash containing a bad id' do
|
351
|
+
it 'raises an error' do
|
352
|
+
config.stub(:networks) { [{ id: 'not-exist' }] }
|
353
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::UnresolvedNetworkId)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context 'with hash containing a bad name' do
|
358
|
+
it 'raises an error' do
|
359
|
+
config.stub(:networks) { [{ name: 'not-exist' }] }
|
360
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::UnresolvedNetworkName)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context 'with empty hash' do
|
365
|
+
it 'raises an error' do
|
366
|
+
config.stub(:networks) { [{}] }
|
367
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::ConflictNetworkNameId)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
context 'with hash containing both id and name' do
|
372
|
+
it 'raises an error' do
|
373
|
+
config.stub(:networks) { [{ id: '001', name: 'net-01' }] }
|
374
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::ConflictNetworkNameId)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context 'with hash containing a name matching more than one network' do
|
379
|
+
it 'raises an error' do
|
380
|
+
config.stub(:networks) { [{ name: 'net-07-08' }] }
|
381
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::MultipleNetworkName)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
context 'neutron service is not available' do
|
387
|
+
context 'with network configured in all possible ways' do
|
388
|
+
it 'returns normalized network list' do
|
389
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
390
|
+
config.stub(:networks) do
|
391
|
+
['001',
|
392
|
+
{ id: '003', address: '1.2.3.4' },
|
393
|
+
{ id: '006' }]
|
394
|
+
end
|
395
|
+
|
396
|
+
expect(@action.resolve_networks(env)).to eq [{ uuid: '001' },
|
397
|
+
{ uuid: '003', fixed_ip: '1.2.3.4' },
|
398
|
+
{ uuid: '006' }]
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
context 'with hash containing both id and name' do
|
403
|
+
it 'raises an error' do
|
404
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
405
|
+
config.stub(:networks) { [{ id: '001', name: 'net-01' }] }
|
406
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::ConflictNetworkNameId)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
context 'with hash containing name' do
|
411
|
+
it 'raises an error' do
|
412
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
413
|
+
config.stub(:networks) { [{ name: 'net-01' }] }
|
414
|
+
expect { @action.resolve_networks(env) }.to raise_error(Errors::NetworkServiceUnavailable)
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
describe 'resolve_volume_boot' do
|
421
|
+
context 'cinder service is available' do
|
422
|
+
context 'with string volume id' do
|
423
|
+
it 'returns normalized volume' do
|
424
|
+
config.stub(:volume_boot) { '001' }
|
425
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
context 'with string volume name' do
|
430
|
+
it 'returns normalized volume' do
|
431
|
+
config.stub(:volume_boot) { 'vol-01' }
|
432
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
context 'with hash volume id' do
|
437
|
+
it 'returns normalized volume' do
|
438
|
+
config.stub(:volume_boot) { { id: '001' } }
|
439
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
context 'with hash volume name' do
|
444
|
+
it 'returns normalized volume' do
|
445
|
+
config.stub(:volume_boot) { { name: 'vol-01' } }
|
446
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
context 'with hash volume id and device' do
|
451
|
+
it 'returns normalized volume' do
|
452
|
+
config.stub(:volume_boot) { { id: '001', device: 'vdb' } }
|
453
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vdb'
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
context 'with hash volume name and device' do
|
458
|
+
it 'returns normalized volume' do
|
459
|
+
config.stub(:volume_boot) { { name: 'vol-01', device: 'vdb' } }
|
460
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vdb'
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
context 'with empty hash' do
|
465
|
+
it 'raises an error' do
|
466
|
+
config.stub(:volume_boot) { {} }
|
467
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictVolumeNameId)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
context 'with invalid volume object' do
|
472
|
+
it 'raises an error' do
|
473
|
+
config.stub(:volume_boot) { 1 }
|
474
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::InvalidVolumeObject)
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
context 'with hash containing a bad id' do
|
479
|
+
it 'raises an error' do
|
480
|
+
config.stub(:volume_boot) { { id: 'not-exist' } }
|
481
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::UnresolvedVolumeId)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
context 'with hash containing a bad name' do
|
486
|
+
it 'raises an error' do
|
487
|
+
config.stub(:volume_boot) { { name: 'not-exist' } }
|
488
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::UnresolvedVolumeName)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
context 'with hash containing both id and name' do
|
493
|
+
it 'raises an error' do
|
494
|
+
config.stub(:volume_boot) { { id: '001', name: 'vol-01' } }
|
495
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictVolumeNameId)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
context 'with hash containing a name matching more than one volume' do
|
500
|
+
it 'raises an error' do
|
501
|
+
config.stub(:volume_boot) { { name: 'vol-07-08' } }
|
502
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::MultipleVolumeName)
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
context 'cinder service is not available' do
|
508
|
+
context 'with string volume id' do
|
509
|
+
it 'returns normalized volume' do
|
510
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
511
|
+
config.stub(:volume_boot) { '001' }
|
512
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
context 'with hash volume id' do
|
517
|
+
it 'returns normalized volume' do
|
518
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
519
|
+
config.stub(:volume_boot) { { id: '001' } }
|
520
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vda'
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
context 'with hash volume name' do
|
525
|
+
it 'raise an error' do
|
526
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
527
|
+
config.stub(:volume_boot) { { name: 'vol-01' } }
|
528
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::VolumeServiceUnavailable)
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
context 'with hash volume id and device' do
|
533
|
+
it 'returns normalized volume' do
|
534
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
535
|
+
config.stub(:volume_boot) { { id: '001', device: 'vdb' } }
|
536
|
+
expect(@action.resolve_volume_boot(env)).to eq id: '001', device: 'vdb'
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
context 'with hash volume name and device' do
|
541
|
+
it 'raise an error' do
|
542
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
543
|
+
config.stub(:volume_boot) { { name: 'vol-01', device: 'vdb' } }
|
544
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::VolumeServiceUnavailable)
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
context 'with invalid volume object' do
|
549
|
+
it 'raises an error' do
|
550
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
551
|
+
config.stub(:volume_boot) { 1 }
|
552
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::InvalidVolumeObject)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
context 'with hash containing both id and name' do
|
557
|
+
it 'raises an error' do
|
558
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
559
|
+
config.stub(:volume_boot) { { id: '001', name: 'vol-01' } }
|
560
|
+
expect { @action.resolve_volume_boot(env) }.to raise_error(Errors::ConflictVolumeNameId)
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
describe 'resolve_volumes' do
|
567
|
+
context 'cinder service is available' do
|
568
|
+
context 'with volume attached in all possible ways' do
|
569
|
+
it 'returns normalized volume list' do
|
570
|
+
|
571
|
+
config.stub(:volumes) do
|
572
|
+
['001',
|
573
|
+
'vol-02',
|
574
|
+
{ id: '003', device: '/dev/vdz' },
|
575
|
+
{ name: 'vol-04', device: '/dev/vdy' },
|
576
|
+
{ name: 'vol-05' },
|
577
|
+
{ id: '006' }]
|
578
|
+
end
|
579
|
+
|
580
|
+
expect(@action.resolve_volumes(env)).to eq [{ id: '001', device: nil },
|
581
|
+
{ id: '002', device: nil },
|
582
|
+
{ id: '003', device: '/dev/vdz' },
|
583
|
+
{ id: '004', device: '/dev/vdy' },
|
584
|
+
{ id: '005', device: nil },
|
585
|
+
{ id: '006', device: nil }]
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
context 'with invalid volume object' do
|
590
|
+
it 'raises an error' do
|
591
|
+
config.stub(:volumes) { [1] }
|
592
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::InvalidVolumeObject)
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
context 'with string that is neither an id nor name matching a volume' do
|
597
|
+
it 'raises an error' do
|
598
|
+
config.stub(:volumes) { ['not-exist'] }
|
599
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::UnresolvedVolume)
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
context 'with hash containing a bad id' do
|
604
|
+
it 'raises an error' do
|
605
|
+
config.stub(:volumes) { [{ id: 'not-exist' }] }
|
606
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::UnresolvedVolumeId)
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
context 'with hash containing a bad name' do
|
611
|
+
it 'raises an error' do
|
612
|
+
config.stub(:volumes) { [{ name: 'not-exist' }] }
|
613
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::UnresolvedVolumeName)
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
context 'with empty hash' do
|
618
|
+
it 'raises an error' do
|
619
|
+
config.stub(:volumes) { [{}] }
|
620
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::ConflictVolumeNameId)
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
context 'with hash containing both id and name' do
|
625
|
+
it 'raises an error' do
|
626
|
+
config.stub(:volumes) { [{ id: '001', name: 'vol-01' }] }
|
627
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::ConflictVolumeNameId)
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
context 'with hash containing a name matching more than one volume' do
|
632
|
+
it 'raises an error' do
|
633
|
+
config.stub(:volumes) { [{ name: 'vol-07-08' }] }
|
634
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::MultipleVolumeName)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
context 'cinder service is not available' do
|
640
|
+
context 'with volume attached in all possible ways' do
|
641
|
+
it 'returns normalized volume list' do
|
642
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
643
|
+
config.stub(:volumes) do
|
644
|
+
['001',
|
645
|
+
{ id: '003', device: '/dev/vdz' },
|
646
|
+
{ id: '006' }]
|
647
|
+
end
|
648
|
+
|
649
|
+
expect(@action.resolve_volumes(env)).to eq [{ id: '001', device: nil },
|
650
|
+
{ id: '003', device: '/dev/vdz' },
|
651
|
+
{ id: '006', device: nil }]
|
652
|
+
end
|
653
|
+
|
654
|
+
context 'with hash containing both id and name' do
|
655
|
+
it 'raises an error' do
|
656
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
657
|
+
config.stub(:volumes) { [{ id: '001', name: 'vol-01' }] }
|
658
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::ConflictVolumeNameId)
|
659
|
+
end
|
660
|
+
end
|
661
|
+
context 'with hash containing name' do
|
662
|
+
it 'raises an error' do
|
663
|
+
session.stub(:endpoints) { { identity: 'http://keystone', compute: 'http://nova' } }
|
664
|
+
config.stub(:volumes) { [{ name: 'vol-01' }] }
|
665
|
+
expect { @action.resolve_volumes(env) }.to raise_error(Errors::VolumeServiceUnavailable)
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
describe 'resolve_security_groups' do
|
673
|
+
context 'with Hash and String objects' do
|
674
|
+
it 'returns normalized Hash list' do
|
675
|
+
config.stub(:security_groups) { ['group1', { name: 'group2' }] }
|
676
|
+
expect(@action.resolve_security_groups(env)).to eq([{ name: 'group1' }, { name: 'group2' }])
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
end
|