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
@@ -0,0 +1,190 @@
1
+ require 'vagrant-openstack-provider/spec_helper'
2
+
3
+ include VagrantPlugins::Openstack::Action
4
+ include VagrantPlugins::Openstack::HttpUtils
5
+
6
+ describe VagrantPlugins::Openstack::Action::ConnectOpenstack do
7
+
8
+ let(:app) do
9
+ double.tap do |app|
10
+ app.stub(:call)
11
+ end
12
+ end
13
+
14
+ let(:config) do
15
+ double.tap do |config|
16
+ config.stub(:openstack_auth_url) { 'http://keystoneAuthV2' }
17
+ config.stub(:openstack_compute_url) { nil }
18
+ config.stub(:openstack_network_url) { nil }
19
+ config.stub(:tenant_name) { 'testTenant' }
20
+ config.stub(:username) { 'username' }
21
+ config.stub(:password) { 'password' }
22
+ end
23
+ end
24
+
25
+ let(:neutron) do
26
+ double.tap do |neutron|
27
+ neutron.stub(:get_api_version_list).with(anything) do
28
+ [
29
+ {
30
+ 'status' => 'CURRENT',
31
+ 'id' => 'v2.0',
32
+ 'links' => [
33
+ {
34
+ 'href' => 'http://neutron/v2.0',
35
+ 'rel' => 'self'
36
+ }
37
+ ]
38
+ }
39
+ ]
40
+ end
41
+ end
42
+ end
43
+
44
+ let(:env) do
45
+ Hash.new.tap do |env|
46
+ env[:ui] = double
47
+ env[:ui].stub(:info).with(anything)
48
+ env[:ui].stub(:warn).with(anything)
49
+ env[:machine] = double('machine')
50
+ env[:machine].stub(:provider_config) { config }
51
+ env[:openstack_client] = double('openstack_client')
52
+ env[:openstack_client].stub(:neutron) { neutron }
53
+ end
54
+ end
55
+
56
+ before(:all) do
57
+ ConnectOpenstack.send(:public, *ConnectOpenstack.private_instance_methods)
58
+ end
59
+
60
+ before :each do
61
+ VagrantPlugins::Openstack.session.reset
62
+ @action = ConnectOpenstack.new(app, env)
63
+ end
64
+
65
+ describe 'ConnectOpenstack' do
66
+ context 'with one endpoint by service' do
67
+ it 'read service catalog and stores endpoints URL in session' do
68
+ catalog = [
69
+ {
70
+ 'endpoints' => [
71
+ {
72
+ 'publicURL' => 'http://nova/v2/projectId',
73
+ 'id' => '1'
74
+ }
75
+ ],
76
+ 'type' => 'compute',
77
+ 'name' => 'nova'
78
+ },
79
+ {
80
+ 'endpoints' => [
81
+ {
82
+ 'publicURL' => 'http://neutron',
83
+ 'id' => '2'
84
+ }
85
+ ],
86
+ 'type' => 'network',
87
+ 'name' => 'neutron'
88
+ }
89
+ ]
90
+
91
+ double.tap do |keystone|
92
+ keystone.stub(:authenticate).with(anything) { catalog }
93
+ env[:openstack_client].stub(:keystone) { keystone }
94
+ end
95
+ env[:openstack_client].stub(:neutron) { neutron }
96
+
97
+ @action.call(env)
98
+
99
+ expect(env[:openstack_client].session.endpoints)
100
+ .to eq(compute: 'http://nova/v2/projectId', network: 'http://neutron/v2.0')
101
+ end
102
+ end
103
+
104
+ context 'with multiple endpoints for a service' do
105
+ it 'takes the first one' do
106
+ catalog = [
107
+ {
108
+ 'endpoints' => [
109
+ {
110
+ 'publicURL' => 'http://neutron/alt',
111
+ 'id' => '2'
112
+ },
113
+ {
114
+ 'publicURL' => 'http://neutron',
115
+ 'id' => '3'
116
+ }
117
+ ],
118
+ 'type' => 'network',
119
+ 'name' => 'neutron'
120
+ }
121
+ ]
122
+
123
+ double.tap do |keystone|
124
+ keystone.stub(:authenticate).with(anything) { catalog }
125
+ env[:openstack_client].stub(:keystone) { keystone }
126
+ end
127
+ env[:openstack_client].stub(:neutron) { neutron }
128
+
129
+ @action.call(env)
130
+
131
+ expect(env[:openstack_client].session.endpoints).to eq(network: 'http://neutron/v2.0')
132
+ end
133
+ end
134
+
135
+ context 'with multiple versions for network service' do
136
+
137
+ let(:neutron) do
138
+ double.tap do |neutron|
139
+ neutron.stub(:get_api_version_list).with(anything) do
140
+ [
141
+ {
142
+ 'status' => 'CURRENT',
143
+ 'id' => 'v2.0',
144
+ 'links' => [
145
+ {
146
+ 'href' => 'http://neutron/v2.0',
147
+ 'rel' => 'self'
148
+ }
149
+ ]
150
+ },
151
+ {
152
+ 'status' => '...',
153
+ 'id' => 'v1.0',
154
+ 'links' => [
155
+ {
156
+ 'href' => 'http://neutron/v1.0',
157
+ 'rel' => 'self'
158
+ }
159
+ ]
160
+ }
161
+ ]
162
+ end
163
+ end
164
+ end
165
+
166
+ it 'raise a MultipleApiVersion error' do
167
+ catalog = [
168
+ {
169
+ 'endpoints' => [
170
+ {
171
+ 'publicURL' => 'http://neutron',
172
+ 'id' => '3'
173
+ }
174
+ ],
175
+ 'type' => 'network',
176
+ 'name' => 'neutron'
177
+ }
178
+ ]
179
+
180
+ double.tap do |keystone|
181
+ keystone.stub(:authenticate).with(anything) { catalog }
182
+ env[:openstack_client].stub(:keystone) { keystone }
183
+ end
184
+ env[:openstack_client].stub(:neutron) { neutron }
185
+
186
+ expect { @action.call(env) }.to raise_error(Errors::MultipleApiVersion)
187
+ end
188
+ end
189
+ end
190
+ end
@@ -1,8 +1,12 @@
1
1
  require 'vagrant-openstack-provider/spec_helper'
2
+ require 'sshkey'
2
3
 
3
4
  include VagrantPlugins::Openstack::Action
5
+ include VagrantPlugins::Openstack::HttpUtils
6
+ include VagrantPlugins::Openstack::Domain
4
7
 
5
8
  describe VagrantPlugins::Openstack::Action::CreateServer do
9
+ include FakeFS::SpecHelpers
6
10
 
7
11
  let(:config) do
8
12
  double('config').tap do |config|
@@ -12,13 +16,49 @@ describe VagrantPlugins::Openstack::Action::CreateServer do
12
16
  config.stub(:tenant_name) { 'testTenant' }
13
17
  config.stub(:username) { 'username' }
14
18
  config.stub(:password) { 'password' }
19
+ config.stub(:server_name) { 'testName' }
20
+ config.stub(:availability_zone) { 'AZ-01' }
21
+ config.stub(:floating_ip) { nil }
22
+ config.stub(:floating_ip_pool) { nil }
23
+ config.stub(:keypair_name) { nil }
24
+ config.stub(:public_key_path) { nil }
25
+ config.stub(:networks) { nil }
26
+ end
27
+ end
28
+
29
+ let(:image) do
30
+ double('image').tap do |image|
31
+ image.stub(:name) { 'image_name' }
32
+ image.stub(:id) { 'image123' }
33
+ end
34
+ end
35
+
36
+ let(:ssh_key) do
37
+ double('ssh_key').tap do |key|
38
+ key.stub(:ssh_public_key) { 'ssh public key' }
39
+ key.stub(:private_key) { 'private key' }
40
+ end
41
+ end
42
+
43
+ let(:flavor) do
44
+ double('flavor').tap do |flavor|
45
+ flavor.stub(:name) { 'flavor_name' }
46
+ flavor.stub(:id) { 'flavor123' }
15
47
  end
16
48
  end
17
49
 
18
50
  let(:neutron) do
19
51
  double('neutron').tap do |neutron|
20
52
  neutron.stub(:get_private_networks).with(anything) do
21
- [{ id: 'net-id-1', name: 'net-1' }, { id: 'net-id-2', name: 'net-2' }]
53
+ [Item.new('net-id-1', 'net-1'), Item.new('net-id-2', 'net-2')]
54
+ end
55
+ end
56
+ end
57
+
58
+ let(:nova) do
59
+ double('nova').tap do |nova|
60
+ nova.stub(:get_all_floating_ips).with(anything) do
61
+ [FloatingIP.new('80.81.82.83', 'pool-1', nil), FloatingIP.new('30.31.32.33', 'pool-2', '1234')]
22
62
  end
23
63
  end
24
64
  end
@@ -29,8 +69,10 @@ describe VagrantPlugins::Openstack::Action::CreateServer do
29
69
  env[:ui].stub(:info).with(anything)
30
70
  env[:machine] = double('machine')
31
71
  env[:machine].stub(:provider_config) { config }
72
+ env[:machine].stub(:data_dir) { '/data/dir' }
32
73
  env[:openstack_client] = double('openstack_client')
33
74
  env[:openstack_client].stub(:neutron) { neutron }
75
+ env[:openstack_client].stub(:nova) { nova }
34
76
  end
35
77
  end
36
78
 
@@ -39,6 +81,129 @@ describe VagrantPlugins::Openstack::Action::CreateServer do
39
81
  @action = CreateServer.new(nil, nil)
40
82
  end
41
83
 
84
+ describe 'create_server' do
85
+ context 'with all options specified' do
86
+ it 'calls nova with all the options' do
87
+ nova.stub(:create_server).with(
88
+ env,
89
+ name: 'testName',
90
+ flavor_ref: flavor.id,
91
+ image_ref: image.id,
92
+ networks: ['test-networks'],
93
+ keypair: 'test-keypair',
94
+ availability_zone: 'test-az') do '1234'
95
+ end
96
+
97
+ options = {
98
+ flavor: flavor,
99
+ image: image,
100
+ networks: ['test-networks'],
101
+ keypair_name: 'test-keypair',
102
+ availability_zone: 'test-az'
103
+ }
104
+ expect(@action.create_server(env, options)).to eq '1234'
105
+ end
106
+ end
107
+ end
108
+
109
+ describe 'resolve_floating_ip' do
110
+ context 'with config.floating_ip specified' do
111
+ it 'return the specified floating ip' do
112
+ config.stub(:floating_ip) { '80.80.80.80' }
113
+ @action.resolve_floating_ip(env).should eq('80.80.80.80')
114
+ end
115
+ end
116
+
117
+ context 'with config.floating_pool specified' do
118
+ context 'if any ip in the same pool is available' do
119
+ it 'return one of the available ips' do
120
+ nova.stub(:get_all_floating_ips).with(anything) do
121
+ [FloatingIP.new('80.81.82.84', 'pool-1', '1234'),
122
+ FloatingIP.new('80.81.82.83', 'pool-1', nil)]
123
+ end
124
+ config.stub(:floating_ip_pool) { 'pool-1' }
125
+ @action.resolve_floating_ip(env).should eq('80.81.82.83')
126
+ end
127
+ end
128
+
129
+ context 'if no ip in the same pool is available' do
130
+ it 'allocate a new floating_ip from the pool' do
131
+ nova.stub(:get_all_floating_ips).with(anything) do
132
+ [FloatingIP.new('80.81.82.83', 'pool-1', '1234')]
133
+ end
134
+ nova.stub(:allocate_floating_ip).with(env, 'pool-1') do
135
+ FloatingIP.new('80.81.82.84', 'pool-1', nil)
136
+ end
137
+ config.stub(:floating_ip_pool) { 'pool-1' }
138
+ @action.resolve_floating_ip(env).should eq('80.81.82.84')
139
+ end
140
+ end
141
+ end
142
+
143
+ context 'with neither floating_ip nor floating_ip_pool' do
144
+ context 'if any ip is not associated with an instance' do
145
+ it 'return the available ip in the list of floating ips' do
146
+ nova.stub(:get_all_floating_ips).with(anything) do
147
+ [FloatingIP.new('80.81.82.84', 'pool-1', '1234'), FloatingIP.new('80.81.82.83', 'pool-1', nil)]
148
+ end
149
+ @action.resolve_floating_ip(env).should eq('80.81.82.83')
150
+ end
151
+ end
152
+
153
+ context 'if all ips are already associated with an instance' do
154
+ it 'fails with an UnableToResolveFloatingIP error' do
155
+ nova.stub(:get_all_floating_ips).with(anything) do
156
+ [FloatingIP.new('80.81.82.84', 'pool-1', '1234'), FloatingIP.new('80.81.82.83', 'pool-1', '2345')]
157
+ end
158
+ expect { @action.resolve_floating_ip(env) }.to raise_error(Errors::UnableToResolveFloatingIP)
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ describe 'resolve_keypair' do
165
+ context 'with keypair_name provided' do
166
+ it 'return the provided keypair_name' do
167
+ config.stub(:keypair_name) { 'my-keypair' }
168
+ @action.resolve_keypair(env).should eq('my-keypair')
169
+ end
170
+ end
171
+
172
+ context 'with keypair_name and public_key_path provided' do
173
+ it 'return the provided keypair_name' do
174
+ config.stub(:keypair_name) { 'my-keypair' }
175
+ config.stub(:public_key_path) { '/path/to/key' }
176
+ @action.resolve_keypair(env).should eq('my-keypair')
177
+ end
178
+ end
179
+
180
+ context 'with public_key_path provided' do
181
+ it 'return the keypair_name created into nova' do
182
+ config.stub(:public_key_path) { '/path/to/key' }
183
+ nova.stub(:import_keypair_from_file).with(env, '/path/to/key') { 'my-keypair-imported' }
184
+ @action.resolve_keypair(env).should eq('my-keypair-imported')
185
+ end
186
+ end
187
+
188
+ context 'with no keypair_name and no public_key_path provided' do
189
+ it 'generates a new keypair and return the keypair name imported into nova' do
190
+ config.stub(:keypair_name) { nil }
191
+ config.stub(:public_key_path) { nil }
192
+ @action.stub(:generate_keypair) { 'my-keypair-imported' }
193
+ @action.resolve_keypair(env).should eq('my-keypair-imported')
194
+ end
195
+ end
196
+ end
197
+
198
+ describe 'generate_keypair' do
199
+ it 'returns a generated keypair name imported into nova' do
200
+ nova.stub(:import_keypair) { 'my-keypair-imported' }
201
+ SSHKey.stub(:generate) { ssh_key }
202
+ File.should_receive(:write).with('/data/dir/my-keypair-imported', 'private key')
203
+ @action.generate_keypair(env).should eq('my-keypair-imported')
204
+ end
205
+ end
206
+
42
207
  describe 'resolve_networks' do
43
208
 
44
209
  context 'with only ids of existing networks' do
@@ -0,0 +1,109 @@
1
+ require 'vagrant-openstack-provider/spec_helper'
2
+
3
+ include VagrantPlugins::Openstack::Action
4
+ include VagrantPlugins::Openstack::HttpUtils
5
+ include VagrantPlugins::Openstack::Domain
6
+
7
+ describe VagrantPlugins::Openstack::Action::ReadSSHInfo do
8
+
9
+ let(:config) do
10
+ double('config').tap do |config|
11
+ config.stub(:openstack_auth_url) { 'http://keystoneAuthV2' }
12
+ config.stub(:openstack_compute_url) { nil }
13
+ config.stub(:openstack_network_url) { nil }
14
+ config.stub(:tenant_name) { 'testTenant' }
15
+ config.stub(:username) { 'username' }
16
+ config.stub(:password) { 'password' }
17
+ config.stub(:ssh_username) { 'sshuser' }
18
+ config.stub(:floating_ip) { nil }
19
+ config.stub(:floating_ip_pool) { nil }
20
+ end
21
+ end
22
+
23
+ let(:neutron) do
24
+ double('neutron').tap do |neutron|
25
+ neutron.stub(:get_private_networks).with(anything) do
26
+ [Item.new('net-id-1', 'net-1'), Item.new('net-id-2', 'net-2')]
27
+ end
28
+ end
29
+ end
30
+
31
+ let(:nova) do
32
+ double('nova').tap do |nova|
33
+ nova.stub(:get_all_floating_ips).with(anything) do
34
+ [FloatingIP.new('80.81.82.83', 'pool-1', nil), FloatingIP.new('30.31.32.33', 'pool-2', '1234')]
35
+ end
36
+ end
37
+ end
38
+
39
+ let(:env) do
40
+ Hash.new.tap do |env|
41
+ env[:ui] = double('ui')
42
+ env[:ui].stub(:info).with(anything)
43
+ env[:machine] = double('machine')
44
+ env[:machine].stub(:provider_config) { config }
45
+ env[:machine].stub(:id) { '1234' }
46
+ env[:machine].stub(:data_dir) { '/data/dir' }
47
+ env[:openstack_client] = double('openstack_client')
48
+ env[:openstack_client].stub(:neutron) { neutron }
49
+ env[:openstack_client].stub(:nova) { nova }
50
+ end
51
+ end
52
+
53
+ before :each do
54
+ ReadSSHInfo.send(:public, *ReadSSHInfo.private_instance_methods)
55
+ @action = ReadSSHInfo.new(nil, nil)
56
+ end
57
+
58
+ describe 'read_ssh_info' do
59
+ context 'with config.floating_ip specified' do
60
+ context 'with keypair_name specified' do
61
+ it 'returns the specified floating ip' do
62
+ config.stub(:floating_ip) { '80.80.80.80' }
63
+ config.stub(:keypair_name) { 'my_keypair' }
64
+ @action.read_ssh_info(env).should eq(host: '80.80.80.80', port: 22, username: 'sshuser')
65
+ end
66
+ end
67
+
68
+ context 'with public_key_path specified' do
69
+ it 'returns the specified floating ip' do
70
+ config.stub(:floating_ip) { '80.80.80.80' }
71
+ config.stub(:keypair_name) { nil }
72
+ config.stub(:public_key_path) { '/public/key/path' }
73
+ @action.read_ssh_info(env).should eq(host: '80.80.80.80', port: 22, username: 'sshuser')
74
+ end
75
+ end
76
+
77
+ context 'with neither keypair_name nor public_key_path specified' do
78
+ it 'returns the specified floating ip ' do
79
+ config.stub(:floating_ip) { '80.80.80.80' }
80
+ config.stub(:keypair_name) { nil }
81
+ config.stub(:public_key_path) { nil }
82
+ @action.stub(:get_keypair_name) { 'my_keypair_name' }
83
+ @action.read_ssh_info(env).should eq(host: '80.80.80.80', port: 22, username: 'sshuser', private_key_path: '/data/dir/my_keypair_name')
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ describe 'read_ssh_info' do
90
+ context 'without config.floating_ip specified' do
91
+ it 'return the a floating_ip found by querying server details' do
92
+ nova.stub(:get_server_details).with(env, '1234') do
93
+ {
94
+ 'addresses' => {
95
+ 'toto' => [{
96
+ 'addr' => '13.13.13.13'
97
+ }, {
98
+ 'addr' => '12.12.12.12',
99
+ 'OS-EXT-IPS:type' => 'floating'
100
+ }]
101
+ }
102
+ }
103
+ end
104
+ config.stub(:keypair_name) { 'my_keypair' }
105
+ @action.read_ssh_info(env).should eq(host: '12.12.12.12', port: 22, username: 'sshuser')
106
+ end
107
+ end
108
+ end
109
+ end