beaker-openstack 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.
- checksums.yaml +15 -0
- data/.gitignore +26 -0
- data/.simplecov +9 -0
- data/Gemfile +25 -0
- data/LICENSE +202 -0
- data/README.md +69 -0
- data/Rakefile +166 -0
- data/beaker-openstack.gemspec +38 -0
- data/bin/beaker-openstack +32 -0
- data/lib/beaker-openstack/version.rb +3 -0
- data/lib/beaker/hypervisor/openstack.rb +363 -0
- data/openstack.md +166 -0
- data/spec/beaker/hypervisor/openstack_spec.rb +238 -0
- data/spec/spec_helper.rb +17 -0
- metadata +212 -0
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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: []
|