beaker-openstack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,238 @@
1
+ require 'spec_helper'
2
+ require 'fog'
3
+
4
+ module Beaker
5
+ describe Openstack do
6
+
7
+ let(:options) { make_opts.merge({'logger' => double().as_null_object}) }
8
+
9
+ let(:openstack) {
10
+ Openstack.new(@hosts, options)
11
+ }
12
+
13
+ before :each do
14
+ @hosts = make_hosts()
15
+
16
+ @compute_client = double().as_null_object
17
+ @network_client = double().as_null_object
18
+
19
+ allow( Fog::Compute ).to receive( :new ).and_return( @compute_client )
20
+ allow( Fog::Network ).to receive( :new ).and_return( @network_client )
21
+ end
22
+
23
+ context 'keystone version support' do
24
+ it 'supports keystone v2' do
25
+ credentials = openstack.instance_eval('@credentials')
26
+ expect(credentials[:openstack_user_domain]).to be_nil
27
+ expect(credentials[:openstack_project_domain]).to be_nil
28
+ end
29
+
30
+ it 'supports keystone v3 with implicit arguments' do
31
+ v3_options = options
32
+ v3_options[:openstack_auth_url] = 'https://example.com/identity/v3/auth'
33
+
34
+ credentials = Openstack.new(@hosts, v3_options).instance_eval('@credentials')
35
+ expect(credentials[:openstack_user_domain]).to eq('Default')
36
+ expect(credentials[:openstack_project_domain]).to eq('Default')
37
+ end
38
+
39
+ it 'supports keystone v3 with explicit arguments' do
40
+ v3_options = options
41
+ v3_options[:openstack_auth_url] = 'https://example.com/identity/v3/auth'
42
+ v3_options[:openstack_user_domain] = 'acme.com'
43
+ v3_options[:openstack_project_domain] = 'R&D'
44
+
45
+ credentials = Openstack.new(@hosts, v3_options).instance_eval('@credentials')
46
+ expect(credentials[:openstack_user_domain]).to eq('acme.com')
47
+ expect(credentials[:openstack_project_domain]).to eq('R&D')
48
+ end
49
+ end
50
+
51
+ describe '#provision' do
52
+
53
+ it 'check openstack options during initialization' do
54
+ options = openstack.instance_eval('@options')
55
+ expect(options['openstack_api_key']).to eq('P1as$w0rd')
56
+ expect(options['openstack_username']).to eq('user')
57
+ expect(options['openstack_auth_url']).to eq('http://openstack_hypervisor.labs.net:5000/v2.0/tokens')
58
+ expect(options['openstack_tenant']).to eq('testing')
59
+ expect(options['openstack_network']).to eq('testing')
60
+ expect(options['openstack_keyname']).to eq('nopass')
61
+ expect(options['security_group']).to eq(['my_sg', 'default'])
62
+ expect(options['floating_ip_pool']).to eq('my_pool')
63
+ end
64
+
65
+ it 'check hosts options during initialization' do
66
+ @hosts.each do |host|
67
+ expect(host['image']).to eq('default_image')
68
+ expect(host['flavor']).to eq('m1.large')
69
+ expect(host['user_data']).to eq('#cloud-config\nmanage_etc_hosts: true\nfinal_message: "The host is finally up!"')
70
+ end
71
+ end
72
+
73
+ it 'check host options during server creation' do
74
+
75
+ mock_flavor = Object.new
76
+ allow( mock_flavor ).to receive( :id ).and_return( 12345 )
77
+ allow( openstack ).to receive( :flavor ).and_return( mock_flavor )
78
+ expect( openstack ).to receive( :flavor ).with( 'm1.large' )
79
+
80
+ mock_image = Object.new
81
+ allow( mock_image ).to receive( :id ).and_return( 54321 )
82
+ allow( openstack ).to receive( :image ).and_return( mock_image )
83
+ expect( openstack ).to receive( :image ).with( 'default_image' )
84
+
85
+ mock_servers = double().as_null_object
86
+ allow( @compute_client ).to receive( :servers ).and_return( mock_servers )
87
+
88
+ expect(mock_servers).to receive(:create).with(hash_including(
89
+ :user_data => '#cloud-config\nmanage_etc_hosts: true\nfinal_message: "The host is finally up!"',
90
+ :flavor_ref => 12345,
91
+ :image_ref => 54321)
92
+ )
93
+
94
+ @hosts.each do |host|
95
+ allow(host).to receive(:wait_for_port).and_return(true)
96
+ end
97
+
98
+ openstack.provision
99
+ end
100
+
101
+ it 'generates valid keynames during server creation' do
102
+ # Simulate getting a dynamic IP from OpenStack to test key generation code
103
+ # after provisioning. See _validate_new_key_pair in openstack/nova for reference
104
+ mock_ip = double().as_null_object
105
+ allow( openstack ).to receive( :get_ip ).and_return( mock_ip )
106
+ allow( mock_ip ).to receive( :ip ).and_return( '172.16.0.1' )
107
+ openstack.instance_eval('@options')['openstack_keyname'] = nil
108
+
109
+ @hosts.each do |host|
110
+ allow(host).to receive(:wait_for_port).and_return(true)
111
+ end
112
+
113
+ openstack.provision
114
+
115
+ @hosts.each do |host|
116
+ expect(host[:keyname]).to match(/^[_\-0-9a-zA-Z]+$/)
117
+ end
118
+ end
119
+
120
+ it 'get_ip always allocates a new floatingip' do
121
+ # Assume beaker is being executed in parallel N times by travis (or similar).
122
+ # IPs are allocated (but not associated) before an instance is created; it is
123
+ # hightly possible the first instance will allocate a new IP and create an ssh
124
+ # key. While the instance is being created the other N-1 instances come along,
125
+ # find the unused IP and try to use it as well which causes keyname clashes
126
+ # and other IP related shenannigans. Ensure we allocate a new IP each and every
127
+ # time
128
+ mock_addresses = double().as_null_object
129
+ mock_ip = double().as_null_object
130
+ allow(@compute_client).to receive(:addresses).and_return(mock_addresses)
131
+ allow(mock_addresses).to receive(:create).and_return(mock_ip)
132
+ expect(mock_addresses).to receive(:create).exactly(3).times
133
+ (1..3).each { openstack.get_ip }
134
+ end
135
+
136
+ context 'volume creation option' do
137
+ it 'provisions volume by default' do
138
+ mock_flavor = Object.new
139
+ allow( mock_flavor ).to receive( :id ).and_return( 12345 )
140
+ allow( openstack ).to receive( :flavor ).and_return( mock_flavor )
141
+ mock_image = Object.new
142
+ allow( mock_image ).to receive( :id ).and_return( 54321 )
143
+ allow( openstack ).to receive( :image ).and_return( mock_image )
144
+ mock_servers = double().as_null_object
145
+ allow( @compute_client ).to receive( :servers ).and_return( mock_servers )
146
+
147
+ @hosts.each do |host|
148
+ allow(host).to receive(:wait_for_port).and_return(true)
149
+ expect(openstack).to receive(:provision_storage)
150
+ end
151
+
152
+ openstack.provision
153
+ end
154
+
155
+ it 'skips provisioning when disabled' do
156
+ mock_flavor = Object.new
157
+ allow( mock_flavor ).to receive( :id ).and_return( 12345 )
158
+ allow( openstack ).to receive( :flavor ).and_return( mock_flavor )
159
+ mock_image = Object.new
160
+ allow( mock_image ).to receive( :id ).and_return( 54321 )
161
+ allow( openstack ).to receive( :image ).and_return( mock_image )
162
+ mock_servers = double().as_null_object
163
+ allow( @compute_client ).to receive( :servers ).and_return( mock_servers )
164
+
165
+ openstack.instance_eval('@options')['openstack_volume_support'] = false
166
+
167
+ @hosts.each do |host|
168
+ allow(host).to receive(:wait_for_port).and_return(true)
169
+ expect(openstack).not_to receive(:provision_storage)
170
+ end
171
+
172
+ openstack.provision
173
+ end
174
+ end
175
+ end
176
+
177
+ describe '#provision_storage' do
178
+
179
+ it 'creates volumes with cinder v1' do
180
+ # Mock a volume
181
+ allow(openstack).to receive(:get_volumes).and_return({'volume1' => {'size' => 1000000 }})
182
+
183
+ # Stub out the call to create the client and hard code the return value
184
+ allow(openstack).to receive(:volume_client_create).and_return(nil)
185
+ client = double().as_null_object
186
+ openstack.instance_variable_set(:@volume_client, client)
187
+ allow(openstack).to receive(:get_volume_api_version).and_return(1)
188
+
189
+ # Check the parameters are valid, correct 'name' parameter and correct size conversion
190
+ mock_volume = double().as_null_object
191
+ expect(client).to receive(:create).with(:display_name => 'volume1',
192
+ :description => 'Beaker volume: host=alan volume=volume1',
193
+ :size => 1000
194
+ ).and_return(mock_volume)
195
+ allow(mock_volume).to receive(:wait_for).and_return(nil)
196
+
197
+ # Perform the test!
198
+ mock_vm = double().as_null_object
199
+ allow(mock_volume).to receive(:id).and_return('Fake ID')
200
+ expect(mock_vm).to receive(:attach_volume).with('Fake ID', '/dev/vdb')
201
+
202
+ mock_host = double().as_null_object
203
+ allow(mock_host).to receive(:name).and_return('alan')
204
+
205
+ openstack.provision_storage mock_host, mock_vm
206
+ end
207
+
208
+ it 'creates volumes with cinder v2' do
209
+ # Mock a volume
210
+ allow(openstack).to receive(:get_volumes).and_return({'volume1' => {'size' => 1000000 }})
211
+
212
+ # Stub out the call to create the client and hard code the return value
213
+ allow(openstack).to receive(:volume_client_create).and_return(nil)
214
+ client = double().as_null_object
215
+ openstack.instance_variable_set(:@volume_client, client)
216
+ allow(openstack).to receive(:get_volume_api_version).and_return(-1)
217
+
218
+ # Check the parameters are valid, correct 'name' parameter and correct size conversion
219
+ mock_volume = double().as_null_object
220
+ expect(client).to receive(:create).with(:name => 'volume1',
221
+ :description => 'Beaker volume: host=alan volume=volume1',
222
+ :size => 1000
223
+ ).and_return(mock_volume)
224
+ allow(mock_volume).to receive(:wait_for).and_return(nil)
225
+
226
+ # Perform the test!
227
+ mock_vm = double().as_null_object
228
+ allow(mock_volume).to receive(:id).and_return('Fake ID')
229
+ expect(mock_vm).to receive(:attach_volume).with('Fake ID', '/dev/vdb')
230
+
231
+ mock_host = double().as_null_object
232
+ allow(mock_host).to receive(:name).and_return('alan')
233
+
234
+ openstack.provision_storage mock_host, mock_vm
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,17 @@
1
+ require 'simplecov'
2
+ require 'rspec/its'
3
+ require 'beaker'
4
+
5
+ Dir.glob(Dir.pwd + '/lib/beaker/hypervisor/*.rb') {|file| require file}
6
+
7
+ # setup & require beaker's spec_helper.rb
8
+ beaker_gem_spec = Gem::Specification.find_by_name('beaker')
9
+ beaker_gem_dir = beaker_gem_spec.gem_dir
10
+ beaker_spec_path = File.join(beaker_gem_dir, 'spec')
11
+ $LOAD_PATH << beaker_spec_path
12
+ require File.join(beaker_spec_path, 'spec_helper.rb')
13
+
14
+ RSpec.configure do |config|
15
+ config.include TestFileHelpers
16
+ config.include HostHelpers
17
+ end
metadata ADDED
@@ -0,0 +1,212 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beaker-openstack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rishi Javia, Kevin Imber, Tony Vu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-its
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fakefs
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '10.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '10.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: markdown
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: thin
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: stringify-hash
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: 0.0.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: 0.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: fog
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: '1.38'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: '1.38'
167
+ description: For use for the Beaker acceptance testing tool
168
+ email:
169
+ - rishi.javia@puppet.com, kevin.imber@puppet.com, tony.vu@puppet.com
170
+ executables:
171
+ - beaker-openstack
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - .gitignore
176
+ - .simplecov
177
+ - Gemfile
178
+ - LICENSE
179
+ - README.md
180
+ - Rakefile
181
+ - beaker-openstack.gemspec
182
+ - bin/beaker-openstack
183
+ - lib/beaker-openstack/version.rb
184
+ - lib/beaker/hypervisor/openstack.rb
185
+ - openstack.md
186
+ - spec/beaker/hypervisor/openstack_spec.rb
187
+ - spec/spec_helper.rb
188
+ homepage: https://github.com/puppetlabs/beaker-openstack
189
+ licenses:
190
+ - Apache2
191
+ metadata: {}
192
+ post_install_message:
193
+ rdoc_options: []
194
+ require_paths:
195
+ - lib
196
+ required_ruby_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ! '>='
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ required_rubygems_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ requirements: []
207
+ rubyforge_project:
208
+ rubygems_version: 2.4.6
209
+ signing_key:
210
+ specification_version: 4
211
+ summary: Beaker DSL Extension Helpers!
212
+ test_files: []