kitchen-openstack 1.5.2 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/.travis.yml +1 -2
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/Rakefile +3 -5
- data/kitchen-openstack.gemspec +5 -5
- data/lib/kitchen/driver/openstack.rb +67 -82
- data/lib/kitchen/driver/openstack_version.rb +4 -2
- data/spec/kitchen/driver/openstack_spec.rb +288 -251
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7616b4cab10679974a5948b4136caa7740e88154
|
4
|
+
data.tar.gz: 5fde868ddac4a5d8c64cc8b21d2cade8821588c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b39b884a8057e61c4891a7438a866aa6651372e65baf6a0e899a6ad96dc5e0737916dbc6314e0494ab4463d81d3244325677fc12d9a67f2d067755171d1a49d8
|
7
|
+
data.tar.gz: fcc37f270a4c08495604f6d5efcc0882c1056ae7e6626373107261f6de4d4f71f81254598479a33c4b527d1fe7f484e10d285deebd91923eb5f706e5be754c93
|
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# 1.5.3 / 2014-08-01
|
2
|
+
|
3
|
+
* PR [#53][] - Rework how server names are generated, disallowing possibly
|
4
|
+
error-causing punctuation in resultant names
|
5
|
+
|
1
6
|
# 1.5.2 / 2014-05-31
|
2
7
|
|
3
8
|
### Bug Fixes
|
@@ -101,6 +106,7 @@ certain specified NICs; via [@monsterzz][]
|
|
101
106
|
|
102
107
|
* Initial release! Woo!
|
103
108
|
|
109
|
+
[#53]: https://github.com/test-kitchen/kitchen-openstack/pull/53
|
104
110
|
[#50]: https://github.com/test-kitchen/kitchen-openstack/pull/50
|
105
111
|
[#49]: https://github.com/test-kitchen/kitchen-openstack/pull/49
|
106
112
|
[#48]: https://github.com/test-kitchen/kitchen-openstack/pull/48
|
data/README.md
CHANGED
@@ -34,7 +34,7 @@ Provide, at a minimum, the required driver options in your `.kitchen.yml` file:
|
|
34
34
|
openstack_username: [YOUR OPENSTACK USERNAME]
|
35
35
|
openstack_api_key: [YOUR OPENSTACK API KEY]
|
36
36
|
openstack_auth_url: [YOUR OPENSTACK AUTH URL]
|
37
|
-
require_chef_omnibus:
|
37
|
+
require_chef_omnibus: [e.g. 'true' or a version number if you need Chef]
|
38
38
|
image_ref: [SERVER IMAGE ID]
|
39
39
|
flavor_ref: [SERVER FLAVOR ID]
|
40
40
|
|
data/Rakefile
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
# Encoding: UTF-8
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
|
-
require '
|
4
|
+
require 'rubocop/rake_task'
|
5
5
|
require 'cane/rake_task'
|
6
6
|
require 'rspec/core/rake_task'
|
7
7
|
|
8
8
|
Cane::RakeTask.new
|
9
9
|
|
10
|
-
|
11
|
-
task.file_set '**/*.rb'
|
12
|
-
end
|
10
|
+
RuboCop::RakeTask.new
|
13
11
|
|
14
12
|
desc 'Display LOC stats'
|
15
13
|
task :loc do
|
@@ -19,4 +17,4 @@ end
|
|
19
17
|
|
20
18
|
RSpec::Core::RakeTask.new(:spec)
|
21
19
|
|
22
|
-
task :
|
20
|
+
task default: [:cane, :rubocop, :loc, :spec]
|
data/kitchen-openstack.gemspec
CHANGED
@@ -9,14 +9,14 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.version = Kitchen::Driver::OPENSTACK_VERSION
|
10
10
|
spec.authors = ['Jonathan Hartman']
|
11
11
|
spec.email = ['j@p4nt5.com']
|
12
|
-
spec.description =
|
12
|
+
spec.description = 'A Test Kitchen OpenStack Nova driver'
|
13
13
|
spec.summary = spec.description
|
14
14
|
spec.homepage = 'https://github.com/test-kitchen/kitchen-openstack'
|
15
15
|
spec.license = 'Apache'
|
16
16
|
|
17
|
-
spec.files = `git ls-files`.split(
|
18
|
-
spec.executables = spec.files.grep(
|
19
|
-
spec.test_files = spec.files.grep(
|
17
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
18
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
|
22
22
|
spec.add_dependency 'test-kitchen', '~> 1.1'
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
|
28
28
|
spec.add_development_dependency 'bundler'
|
29
29
|
spec.add_development_dependency 'rake'
|
30
|
-
spec.add_development_dependency '
|
30
|
+
spec.add_development_dependency 'rubocop'
|
31
31
|
spec.add_development_dependency 'cane'
|
32
32
|
spec.add_development_dependency 'countloc'
|
33
33
|
spec.add_development_dependency 'rspec'
|
@@ -34,10 +34,10 @@ module Kitchen
|
|
34
34
|
|
35
35
|
default_config :server_name, nil
|
36
36
|
default_config :key_name, nil
|
37
|
-
default_config :private_key_path do
|
38
|
-
%w
|
37
|
+
default_config :private_key_path do
|
38
|
+
%w(id_rsa id_dsa).map do |k|
|
39
39
|
f = File.expand_path "~/.ssh/#{k}"
|
40
|
-
f if File.
|
40
|
+
f if File.exist?(f)
|
41
41
|
end.compact.first
|
42
42
|
end
|
43
43
|
default_config :public_key_path do |driver|
|
@@ -57,11 +57,15 @@ module Kitchen
|
|
57
57
|
|
58
58
|
def create(state)
|
59
59
|
config[:server_name] ||= generate_name(instance.name)
|
60
|
-
config[:disable_ssl_validation]
|
60
|
+
config[:disable_ssl_validation] && disable_ssl_validation
|
61
61
|
server = create_server
|
62
62
|
state[:server_id] = server.id
|
63
63
|
info "OpenStack instance <#{state[:server_id]}> created."
|
64
|
-
server.wait_for
|
64
|
+
server.wait_for do
|
65
|
+
print '.'
|
66
|
+
ready?
|
67
|
+
end
|
68
|
+
info "\n(server ready)"
|
65
69
|
if config[:floating_ip_pool]
|
66
70
|
attach_ip_from_pool(server, config[:floating_ip_pool])
|
67
71
|
elsif config[:floating_ip]
|
@@ -69,17 +73,15 @@ module Kitchen
|
|
69
73
|
end
|
70
74
|
state[:hostname] = get_ip(server)
|
71
75
|
state[:ssh_key] = config[:private_key_path]
|
72
|
-
wait_for_sshd(state[:hostname], config[:username],
|
73
|
-
|
76
|
+
wait_for_sshd(state[:hostname], config[:username], port: config[:port])
|
77
|
+
info '(ssh ready)'
|
74
78
|
if config[:key_name]
|
75
79
|
info "Using OpenStack keypair <#{config[:key_name]}>"
|
76
80
|
end
|
77
81
|
info "Using public SSH key <#{config[:public_key_path]}>"
|
78
82
|
info "Using private SSH key <#{config[:private_key_path]}>"
|
79
|
-
add_ohai_hint(state
|
80
|
-
unless config[:key_name]
|
81
|
-
do_ssh_setup(state, config, server)
|
82
|
-
end
|
83
|
+
add_ohai_hint(state)
|
84
|
+
do_ssh_setup(state, config, server) unless config[:key_name]
|
83
85
|
rescue Fog::Errors::Error, Excon::Errors::Error => ex
|
84
86
|
raise ActionFailed, ex.message
|
85
87
|
end
|
@@ -87,7 +89,7 @@ module Kitchen
|
|
87
89
|
def destroy(state)
|
88
90
|
return if state[:server_id].nil?
|
89
91
|
|
90
|
-
config[:disable_ssl_validation]
|
92
|
+
config[:disable_ssl_validation] && disable_ssl_validation
|
91
93
|
server = compute.servers.get(state[:server_id])
|
92
94
|
server.destroy unless server.nil?
|
93
95
|
info "OpenStack instance <#{state[:server_id]}> destroyed."
|
@@ -99,20 +101,21 @@ module Kitchen
|
|
99
101
|
|
100
102
|
def openstack_server
|
101
103
|
server_def = {
|
102
|
-
:
|
103
|
-
:openstack_username => config[:openstack_username],
|
104
|
-
:openstack_api_key => config[:openstack_api_key],
|
105
|
-
:openstack_auth_url => config[:openstack_auth_url]
|
104
|
+
provider: 'OpenStack'
|
106
105
|
}
|
107
|
-
|
108
|
-
|
109
|
-
]
|
110
|
-
optional.each do |o|
|
111
|
-
config[o] and server_def[o] = config[o]
|
112
|
-
end
|
106
|
+
required_server_settings.each { |s| server_def[s] = config[s] }
|
107
|
+
optional_server_settings.each { |s| server_def[s] = config[s] }
|
113
108
|
server_def
|
114
109
|
end
|
115
110
|
|
111
|
+
def required_server_settings
|
112
|
+
[:openstack_username, :openstack_api_key, :openstack_auth_url]
|
113
|
+
end
|
114
|
+
|
115
|
+
def optional_server_settings
|
116
|
+
[:openstack_tenant, :openstack_region, :openstack_service_name]
|
117
|
+
end
|
118
|
+
|
116
119
|
def network
|
117
120
|
Fog::Network.new(openstack_server)
|
118
121
|
end
|
@@ -148,22 +151,18 @@ module Kitchen
|
|
148
151
|
|
149
152
|
def init_config
|
150
153
|
{
|
151
|
-
:
|
152
|
-
:
|
153
|
-
:
|
154
|
+
name: config[:server_name],
|
155
|
+
image_ref: find_image(config[:image_ref]).id,
|
156
|
+
flavor_ref: find_flavor(config[:flavor_ref]).id
|
154
157
|
}
|
155
158
|
end
|
156
159
|
|
157
160
|
def optional_config(c)
|
158
161
|
case c
|
159
162
|
when :security_groups
|
160
|
-
if config[c].
|
161
|
-
config[c]
|
162
|
-
end
|
163
|
+
config[c] if config[c].is_a?(Array)
|
163
164
|
when :user_data
|
164
|
-
if File.exist?(config[c])
|
165
|
-
File.open(config[c]) { |f| f.read }
|
166
|
-
end
|
165
|
+
File.open(config[c]) { |f| f.read } if File.exist?(config[c])
|
167
166
|
else
|
168
167
|
config[c]
|
169
168
|
end
|
@@ -171,61 +170,53 @@ module Kitchen
|
|
171
170
|
|
172
171
|
def find_image(image_ref)
|
173
172
|
image = find_matching(compute.images, image_ref)
|
174
|
-
|
173
|
+
fail(ActionFailed, 'Image not found') unless image
|
175
174
|
debug "Selected image: #{image.id} #{image.name}"
|
176
175
|
image
|
177
176
|
end
|
178
177
|
|
179
178
|
def find_flavor(flavor_ref)
|
180
179
|
flavor = find_matching(compute.flavors, flavor_ref)
|
181
|
-
|
180
|
+
fail(ActionFailed, 'Flavor not found') unless flavor
|
182
181
|
debug "Selected flavor: #{flavor.id} #{flavor.name}"
|
183
182
|
flavor
|
184
183
|
end
|
185
184
|
|
186
185
|
def find_network(network_ref)
|
187
186
|
net = find_matching(network.networks.all, network_ref)
|
188
|
-
|
187
|
+
fail(ActionFailed, 'Network not found') unless net
|
189
188
|
debug "Selected net: #{net.id} #{net.name}"
|
190
189
|
net
|
191
190
|
end
|
192
191
|
|
192
|
+
# Generate what should be a unique server name up to 63 total chars
|
193
|
+
# Base name: 15
|
194
|
+
# Username: 15
|
195
|
+
# Hostname: 23
|
196
|
+
# Random string: 7
|
197
|
+
# Separators: 3
|
198
|
+
# ================
|
199
|
+
# Total: 63
|
193
200
|
def generate_name(base)
|
194
|
-
# Generate what should be a unique server name up to 63 total chars
|
195
|
-
# Base name: 15
|
196
|
-
# Username: 15
|
197
|
-
# Hostname: 23
|
198
|
-
# Random string: 7
|
199
|
-
# Separators: 3
|
200
|
-
# ================
|
201
|
-
# Total: 63
|
202
201
|
sep = '-'
|
203
202
|
pieces = [
|
204
|
-
base,
|
205
|
-
Etc.getlogin,
|
206
|
-
Socket.gethostname,
|
203
|
+
base.gsub(/\W/, '')[0..14],
|
204
|
+
Etc.getlogin.gsub(/\W/, '')[0..14],
|
205
|
+
Socket.gethostname.gsub(/\W/, '')[0..22],
|
207
206
|
Array.new(7) { rand(36).to_s(36) }.join
|
208
207
|
]
|
209
|
-
|
210
|
-
|
211
|
-
pieces[2] = pieces[2][0..-2]
|
212
|
-
elsif pieces[1].length > 15
|
213
|
-
pieces[1] = pieces[1][0..-2]
|
214
|
-
elsif pieces[0].length > 15
|
215
|
-
pieces[0] = pieces[0][0..-2]
|
216
|
-
end
|
217
|
-
end
|
218
|
-
pieces.join sep
|
208
|
+
puts "Name: #{pieces.join(sep)}"
|
209
|
+
pieces.join(sep)
|
219
210
|
end
|
220
211
|
|
221
212
|
def attach_ip_from_pool(server, pool)
|
222
213
|
@@ip_pool_lock.synchronize do
|
223
214
|
info "Attaching floating IP from <#{pool}> pool"
|
224
|
-
free_addrs = compute.addresses.
|
225
|
-
i.ip if i.fixed_ip.nil?
|
215
|
+
free_addrs = compute.addresses.map do |i|
|
216
|
+
i.ip if i.fixed_ip.nil? && i.instance_id.nil? && i.pool == pool
|
226
217
|
end.compact
|
227
218
|
if free_addrs.empty?
|
228
|
-
|
219
|
+
fail ActionFailed, "No available IPs in pool <#{pool}>"
|
229
220
|
end
|
230
221
|
config[:floating_ip] = free_addrs[0]
|
231
222
|
attach_ip(server, free_addrs[0])
|
@@ -252,11 +243,11 @@ module Kitchen
|
|
252
243
|
rescue Fog::Compute::OpenStack::NotFound
|
253
244
|
# See Fog issue: https://github.com/fog/fog/issues/2160
|
254
245
|
addrs = server.addresses
|
255
|
-
addrs['public']
|
256
|
-
addrs['private']
|
246
|
+
addrs['public'] && pub = addrs['public'].map { |i| i['addr'] }
|
247
|
+
addrs['private'] && priv = addrs['private'].map { |i| i['addr'] }
|
257
248
|
end
|
258
249
|
pub, priv = parse_ips(pub, priv)
|
259
|
-
pub.first || priv.first ||
|
250
|
+
pub.first || priv.first || fail(ActionFailed, 'Could not find an IP')
|
260
251
|
end
|
261
252
|
|
262
253
|
def parse_ips(pub, priv)
|
@@ -266,27 +257,28 @@ module Kitchen
|
|
266
257
|
else
|
267
258
|
[pub, priv].each { |n| n.select! { |i| IPAddr.new(i).ipv4? } }
|
268
259
|
end
|
269
|
-
|
260
|
+
[pub, priv]
|
270
261
|
end
|
271
262
|
|
272
|
-
def add_ohai_hint(state
|
263
|
+
def add_ohai_hint(state)
|
273
264
|
info 'Adding OpenStack hint for ohai'
|
274
265
|
ssh = Fog::SSH.new(*build_ssh_args(state))
|
275
266
|
ssh.run([
|
276
|
-
%
|
277
|
-
%
|
267
|
+
%(sudo mkdir -p #{Ohai::Config[:hints_path][0]}),
|
268
|
+
%(sudo touch #{Ohai::Config[:hints_path][0]}/openstack.json)
|
278
269
|
])
|
279
270
|
end
|
280
271
|
|
281
272
|
def do_ssh_setup(state, config, server)
|
282
273
|
info "Setting up SSH access for key <#{config[:public_key_path]}>"
|
283
|
-
ssh = Fog::SSH.new(state[:hostname],
|
284
|
-
|
274
|
+
ssh = Fog::SSH.new(state[:hostname],
|
275
|
+
config[:username],
|
276
|
+
password: server.password)
|
285
277
|
pub_key = open(config[:public_key_path]).read
|
286
278
|
ssh.run([
|
287
|
-
%
|
288
|
-
%
|
289
|
-
%
|
279
|
+
%(mkdir .ssh),
|
280
|
+
%(echo "#{pub_key}" >> ~/.ssh/authorized_keys),
|
281
|
+
%(passwd -l #{config[:username]})
|
290
282
|
])
|
291
283
|
end
|
292
284
|
|
@@ -297,25 +289,18 @@ module Kitchen
|
|
297
289
|
|
298
290
|
def find_matching(collection, name)
|
299
291
|
name = name.to_s
|
300
|
-
if name.start_with?('/')
|
301
|
-
regex =
|
292
|
+
if name.start_with?('/') && name.end_with?('/')
|
293
|
+
regex = Regexp.new(name[1...-1])
|
302
294
|
# check for regex name match
|
303
|
-
collection.each
|
304
|
-
return single if regex =~ single.name
|
305
|
-
end
|
295
|
+
collection.each { |single| return single if regex =~ single.name }
|
306
296
|
else
|
307
297
|
# check for exact id match
|
308
|
-
collection.each
|
309
|
-
return single if single.id == name
|
310
|
-
end
|
298
|
+
collection.each { |single| return single if single.id == name }
|
311
299
|
# check for exact name match
|
312
|
-
collection.each
|
313
|
-
return single if single.name == name
|
314
|
-
end
|
300
|
+
collection.each { |single| return single if single.name == name }
|
315
301
|
end
|
316
302
|
nil
|
317
303
|
end
|
318
|
-
|
319
304
|
end
|
320
305
|
end
|
321
306
|
end
|
@@ -17,8 +17,10 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
19
|
module Kitchen
|
20
|
+
# Version string for OpenStack Kitchen driver
|
21
|
+
#
|
22
|
+
# @author Jonathan Hartman <j@p4nt5.com>
|
20
23
|
module Driver
|
21
|
-
|
22
|
-
OPENSTACK_VERSION = '1.5.2'
|
24
|
+
OPENSTACK_VERSION = '1.5.3'
|
23
25
|
end
|
24
26
|
end
|
@@ -34,7 +34,7 @@ describe Kitchen::Driver::Openstack do
|
|
34
34
|
|
35
35
|
let(:instance) do
|
36
36
|
double(
|
37
|
-
:
|
37
|
+
name: 'potatoes', logger: logger, to_str: 'instance'
|
38
38
|
)
|
39
39
|
end
|
40
40
|
|
@@ -45,9 +45,9 @@ describe Kitchen::Driver::Openstack do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
before(:each) do
|
48
|
-
File.
|
49
|
-
File.
|
50
|
-
File.
|
48
|
+
allow(File).to receive(:exist?).and_call_original
|
49
|
+
allow(File).to receive(:exist?).with(dsa).and_return(true)
|
50
|
+
allow(File).to receive(:exist?).with(rsa).and_return(true)
|
51
51
|
end
|
52
52
|
|
53
53
|
describe '#initialize'do
|
@@ -64,9 +64,8 @@ describe Kitchen::Driver::Openstack do
|
|
64
64
|
|
65
65
|
context 'only a DSA SSH key available for the user' do
|
66
66
|
before(:each) do
|
67
|
-
File.
|
68
|
-
File.
|
69
|
-
File.stub(:exists?).with(dsa).and_return(true)
|
67
|
+
allow(File).to receive(:exist?).and_return(false)
|
68
|
+
allow(File).to receive(:exist?).with(dsa).and_return(true)
|
70
69
|
end
|
71
70
|
|
72
71
|
it 'uses the local user\'s DSA private key' do
|
@@ -80,9 +79,8 @@ describe Kitchen::Driver::Openstack do
|
|
80
79
|
|
81
80
|
context 'only a RSA SSH key available for the user' do
|
82
81
|
before(:each) do
|
83
|
-
File.
|
84
|
-
File.
|
85
|
-
File.stub(:exists?).with(rsa).and_return(true)
|
82
|
+
allow(File).to receive(:exist?).and_return(false)
|
83
|
+
allow(File).to receive(:exist?).with(rsa).and_return(true)
|
86
84
|
end
|
87
85
|
|
88
86
|
it 'uses the local user\'s RSA private key' do
|
@@ -118,19 +116,19 @@ describe Kitchen::Driver::Openstack do
|
|
118
116
|
context 'overridden options' do
|
119
117
|
let(:config) do
|
120
118
|
{
|
121
|
-
:
|
122
|
-
:
|
123
|
-
:
|
124
|
-
:
|
125
|
-
:
|
126
|
-
:
|
127
|
-
:
|
128
|
-
:
|
129
|
-
:
|
130
|
-
:
|
131
|
-
:
|
132
|
-
:
|
133
|
-
:
|
119
|
+
image_ref: '22',
|
120
|
+
flavor_ref: '33',
|
121
|
+
public_key_path: '/tmp',
|
122
|
+
username: 'admin',
|
123
|
+
port: '2222',
|
124
|
+
server_name: 'puppy',
|
125
|
+
openstack_tenant: 'that_one',
|
126
|
+
openstack_region: 'atlantis',
|
127
|
+
openstack_service_name: 'the_service',
|
128
|
+
private_key_path: '/path/to/id_rsa',
|
129
|
+
floating_ip_pool: 'swimmers',
|
130
|
+
floating_ip: '11111',
|
131
|
+
network_ref: '0xCAFFE'
|
134
132
|
}
|
135
133
|
end
|
136
134
|
|
@@ -145,31 +143,29 @@ describe Kitchen::Driver::Openstack do
|
|
145
143
|
|
146
144
|
describe '#create' do
|
147
145
|
let(:server) do
|
148
|
-
double(:
|
149
|
-
:public_ip_addresses => %w{1.2.3.4})
|
146
|
+
double(id: 'test123', wait_for: true, public_ip_addresses: %w(1.2.3.4))
|
150
147
|
end
|
151
148
|
let(:driver) do
|
152
149
|
d = Kitchen::Driver::Openstack.new(config)
|
153
150
|
d.instance = instance
|
154
|
-
d.
|
155
|
-
|
156
|
-
d.
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
d.
|
161
|
-
d.
|
162
|
-
d.stub(:do_ssh_setup).and_return(true)
|
151
|
+
allow(d).to receive(:generate_name).with('potatoes')
|
152
|
+
.and_return('a_monkey!')
|
153
|
+
allow(d).to receive(:create_server).and_return(server)
|
154
|
+
allow(d).to receive(:wait_for_sshd).with('1.2.3.4', 'root', port: '22')
|
155
|
+
.and_return(true)
|
156
|
+
allow(d).to receive(:get_ip).and_return('1.2.3.4')
|
157
|
+
allow(d).to receive(:add_ohai_hint).and_return(true)
|
158
|
+
allow(d).to receive(:do_ssh_setup).and_return(true)
|
163
159
|
d
|
164
160
|
end
|
165
161
|
|
166
162
|
context 'required options provided' do
|
167
163
|
let(:config) do
|
168
164
|
{
|
169
|
-
:
|
170
|
-
:
|
171
|
-
:
|
172
|
-
:
|
165
|
+
openstack_username: 'hello',
|
166
|
+
openstack_api_key: 'world',
|
167
|
+
openstack_auth_url: 'http:',
|
168
|
+
openstack_tenant: 'www'
|
173
169
|
}
|
174
170
|
end
|
175
171
|
|
@@ -189,16 +185,16 @@ describe Kitchen::Driver::Openstack do
|
|
189
185
|
end
|
190
186
|
|
191
187
|
it 'does not disable SSL validation' do
|
192
|
-
driver.
|
188
|
+
expect(driver).to_not receive(:disable_ssl_validation)
|
193
189
|
driver.create(state)
|
194
190
|
end
|
195
191
|
end
|
196
192
|
|
197
193
|
context 'SSL validation disabled' do
|
198
|
-
let(:config) { { :
|
194
|
+
let(:config) { { disable_ssl_validation: true } }
|
199
195
|
|
200
196
|
it 'disables SSL cert validation' do
|
201
|
-
driver.
|
197
|
+
expect(driver).to receive(:disable_ssl_validation)
|
202
198
|
driver.create(state)
|
203
199
|
end
|
204
200
|
end
|
@@ -207,27 +203,27 @@ describe Kitchen::Driver::Openstack do
|
|
207
203
|
describe '#destroy' do
|
208
204
|
let(:server_id) { '12345' }
|
209
205
|
let(:hostname) { 'example.com' }
|
210
|
-
let(:state) { { :
|
211
|
-
let(:server) { double(
|
212
|
-
let(:servers) { double(:
|
213
|
-
let(:compute) { double(:
|
206
|
+
let(:state) { { server_id: server_id, hostname: hostname } }
|
207
|
+
let(:server) { double(nil?: false, destroy: true) }
|
208
|
+
let(:servers) { double(get: server) }
|
209
|
+
let(:compute) { double(servers: servers) }
|
214
210
|
|
215
211
|
let(:driver) do
|
216
212
|
d = Kitchen::Driver::Openstack.new(config)
|
217
213
|
d.instance = instance
|
218
|
-
d.
|
214
|
+
allow(d).to receive(:compute).and_return(compute)
|
219
215
|
d
|
220
216
|
end
|
221
217
|
|
222
218
|
context 'a live server that needs to be destroyed' do
|
223
219
|
it 'destroys the server' do
|
224
|
-
state.
|
225
|
-
state.
|
220
|
+
expect(state).to receive(:delete).with(:server_id)
|
221
|
+
expect(state).to receive(:delete).with(:hostname)
|
226
222
|
driver.destroy(state)
|
227
223
|
end
|
228
224
|
|
229
225
|
it 'does not disable SSL cert validation' do
|
230
|
-
driver.
|
226
|
+
expect(driver).to_not receive(:disable_ssl_validation)
|
231
227
|
driver.destroy(state)
|
232
228
|
end
|
233
229
|
end
|
@@ -236,9 +232,9 @@ describe Kitchen::Driver::Openstack do
|
|
236
232
|
let(:state) { Hash.new }
|
237
233
|
|
238
234
|
it 'does nothing' do
|
239
|
-
driver.
|
240
|
-
driver.
|
241
|
-
state.
|
235
|
+
allow(driver).to receive(:compute)
|
236
|
+
expect(driver).to_not receive(:compute)
|
237
|
+
expect(state).to_not receive(:delete)
|
242
238
|
driver.destroy(state)
|
243
239
|
end
|
244
240
|
end
|
@@ -246,14 +242,14 @@ describe Kitchen::Driver::Openstack do
|
|
246
242
|
context 'a server that was already destroyed' do
|
247
243
|
let(:servers) do
|
248
244
|
s = double('servers')
|
249
|
-
s.
|
245
|
+
allow(s).to receive(:get).with('12345').and_return(nil)
|
250
246
|
s
|
251
247
|
end
|
252
|
-
let(:compute) { double(:
|
248
|
+
let(:compute) { double(servers: servers) }
|
253
249
|
let(:driver) do
|
254
250
|
d = Kitchen::Driver::Openstack.new(config)
|
255
251
|
d.instance = instance
|
256
|
-
d.
|
252
|
+
allow(d).to receive(:compute).and_return(compute)
|
257
253
|
d
|
258
254
|
end
|
259
255
|
|
@@ -264,43 +260,79 @@ describe Kitchen::Driver::Openstack do
|
|
264
260
|
end
|
265
261
|
|
266
262
|
context 'SSL validation disabled' do
|
267
|
-
let(:config) { { :
|
263
|
+
let(:config) { { disable_ssl_validation: true } }
|
268
264
|
|
269
265
|
it 'disables SSL cert validation' do
|
270
|
-
driver.
|
266
|
+
expect(driver).to receive(:disable_ssl_validation)
|
271
267
|
driver.destroy(state)
|
272
268
|
end
|
273
269
|
end
|
274
270
|
end
|
275
271
|
|
272
|
+
describe '#openstack_server' do
|
273
|
+
let(:config) do
|
274
|
+
{
|
275
|
+
openstack_username: 'a',
|
276
|
+
openstack_api_key: 'b',
|
277
|
+
openstack_auth_url: 'http://',
|
278
|
+
openstack_tenant: 'me',
|
279
|
+
openstack_region: 'ORD',
|
280
|
+
openstack_service_name: 'stack'
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'returns a hash of server settings' do
|
285
|
+
expected = config.merge(provider: 'OpenStack')
|
286
|
+
expect(driver.send(:openstack_server)).to eq(expected)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe '#required_server_settings' do
|
291
|
+
it 'returns the required settings for an OpenStack server' do
|
292
|
+
expected = [
|
293
|
+
:openstack_username, :openstack_api_key, :openstack_auth_url
|
294
|
+
]
|
295
|
+
expect(driver.send(:required_server_settings)).to eq(expected)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe '#optional_server_settings' do
|
300
|
+
it 'returns the optional settings for an OpenStack server' do
|
301
|
+
expected = [
|
302
|
+
:openstack_tenant, :openstack_region, :openstack_service_name
|
303
|
+
]
|
304
|
+
expect(driver.send(:optional_server_settings)).to eq(expected)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
276
308
|
describe '#compute' do
|
277
309
|
let(:config) do
|
278
310
|
{
|
279
|
-
:
|
280
|
-
:
|
281
|
-
:
|
282
|
-
:
|
283
|
-
:
|
284
|
-
:
|
311
|
+
openstack_username: 'monkey',
|
312
|
+
openstack_api_key: 'potato',
|
313
|
+
openstack_auth_url: 'http:',
|
314
|
+
openstack_tenant: 'link',
|
315
|
+
openstack_region: 'ord',
|
316
|
+
openstack_service_name: 'the_service'
|
285
317
|
}
|
286
318
|
end
|
287
319
|
|
288
320
|
context 'all requirements provided' do
|
289
321
|
it 'creates a new compute connection' do
|
290
|
-
Fog::Compute.
|
291
|
-
res = config.merge(
|
322
|
+
allow(Fog::Compute).to receive(:new) { |arg| arg }
|
323
|
+
res = config.merge(provider: 'OpenStack')
|
292
324
|
expect(driver.send(:compute)).to eq(res)
|
293
325
|
end
|
294
326
|
|
295
327
|
it 'creates a new network connection' do
|
296
|
-
Fog::Network.
|
297
|
-
res = config.merge(
|
328
|
+
allow(Fog::Network).to receive(:new) { |arg| arg }
|
329
|
+
res = config.merge(provider: 'OpenStack')
|
298
330
|
expect(driver.send(:network)).to eq(res)
|
299
331
|
end
|
300
332
|
end
|
301
333
|
|
302
334
|
context 'only an API key provided' do
|
303
|
-
let(:config) { { :
|
335
|
+
let(:config) { { openstack_api_key: '1234' } }
|
304
336
|
|
305
337
|
it 'raises an error' do
|
306
338
|
expect { driver.send(:compute) }.to raise_error(ArgumentError)
|
@@ -308,7 +340,7 @@ describe Kitchen::Driver::Openstack do
|
|
308
340
|
end
|
309
341
|
|
310
342
|
context 'only a username provided' do
|
311
|
-
let(:config) { { :
|
343
|
+
let(:config) { { openstack_username: 'monkey' } }
|
312
344
|
|
313
345
|
it 'raises an error' do
|
314
346
|
expect { driver.send(:compute) }.to raise_error(ArgumentError)
|
@@ -319,51 +351,45 @@ describe Kitchen::Driver::Openstack do
|
|
319
351
|
describe '#create_server' do
|
320
352
|
let(:config) do
|
321
353
|
{
|
322
|
-
:
|
323
|
-
:
|
324
|
-
:
|
325
|
-
:
|
354
|
+
server_name: 'hello',
|
355
|
+
image_ref: '111',
|
356
|
+
flavor_ref: '1',
|
357
|
+
public_key_path: 'tarpals'
|
326
358
|
}
|
327
359
|
end
|
328
360
|
let(:servers) do
|
329
361
|
s = double('servers')
|
330
|
-
s.
|
362
|
+
allow(s).to receive(:create) { |arg| arg }
|
331
363
|
s
|
332
364
|
end
|
333
|
-
let(:vlan1_net) { double(:
|
334
|
-
let(:vlan2_net) { double(:
|
335
|
-
let(:ubuntu_image) { double(:
|
336
|
-
let(:fedora_image) { double(:
|
337
|
-
let(:tiny_flavor) { double(:
|
338
|
-
let(:small_flavor) { double(:
|
365
|
+
let(:vlan1_net) { double(id: '1', name: 'vlan1') }
|
366
|
+
let(:vlan2_net) { double(id: '2', name: 'vlan2') }
|
367
|
+
let(:ubuntu_image) { double(id: '111', name: 'ubuntu') }
|
368
|
+
let(:fedora_image) { double(id: '222', name: 'fedora') }
|
369
|
+
let(:tiny_flavor) { double(id: '1', name: 'tiny') }
|
370
|
+
let(:small_flavor) { double(id: '2', name: 'small') }
|
339
371
|
let(:compute) do
|
340
372
|
double(
|
341
|
-
:
|
342
|
-
:
|
343
|
-
:
|
373
|
+
servers: servers,
|
374
|
+
images: [ubuntu_image, fedora_image],
|
375
|
+
flavors: [tiny_flavor, small_flavor]
|
344
376
|
)
|
345
377
|
end
|
346
378
|
let(:network) do
|
347
|
-
double(
|
348
|
-
:networks => double(
|
349
|
-
:all => [vlan1_net, vlan2_net]
|
350
|
-
)
|
351
|
-
)
|
379
|
+
double(networks: double(all: [vlan1_net, vlan2_net]))
|
352
380
|
end
|
353
381
|
let(:driver) do
|
354
382
|
d = Kitchen::Driver::Openstack.new(config)
|
355
383
|
d.instance = instance
|
356
|
-
d.
|
357
|
-
d.
|
384
|
+
allow(d).to receive(:compute).and_return(compute)
|
385
|
+
allow(d).to receive(:network).and_return(network)
|
358
386
|
d
|
359
387
|
end
|
360
388
|
|
361
389
|
context 'a default config' do
|
362
390
|
before(:each) do
|
363
|
-
@expected = config.merge(:
|
364
|
-
@expected.delete_if
|
365
|
-
k == :server_name
|
366
|
-
end
|
391
|
+
@expected = config.merge(name: config[:server_name])
|
392
|
+
@expected.delete_if { |k, _| k == :server_name }
|
367
393
|
end
|
368
394
|
|
369
395
|
it 'creates the server using a compute connection' do
|
@@ -374,17 +400,15 @@ describe Kitchen::Driver::Openstack do
|
|
374
400
|
context 'a provided public key path' do
|
375
401
|
let(:config) do
|
376
402
|
{
|
377
|
-
:
|
378
|
-
:
|
379
|
-
:
|
380
|
-
:
|
403
|
+
server_name: 'hello',
|
404
|
+
image_ref: '111',
|
405
|
+
flavor_ref: '1',
|
406
|
+
public_key_path: 'tarpals'
|
381
407
|
}
|
382
408
|
end
|
383
409
|
before(:each) do
|
384
|
-
@expected = config.merge(:
|
385
|
-
@expected.delete_if
|
386
|
-
k == :server_name
|
387
|
-
end
|
410
|
+
@expected = config.merge(name: config[:server_name])
|
411
|
+
@expected.delete_if { |k, _| k == :server_name }
|
388
412
|
end
|
389
413
|
|
390
414
|
it 'passes that public key path to Fog' do
|
@@ -395,19 +419,17 @@ describe Kitchen::Driver::Openstack do
|
|
395
419
|
context 'a provided key name' do
|
396
420
|
let(:config) do
|
397
421
|
{
|
398
|
-
:
|
399
|
-
:
|
400
|
-
:
|
401
|
-
:
|
402
|
-
:
|
422
|
+
server_name: 'hello',
|
423
|
+
image_ref: '111',
|
424
|
+
flavor_ref: '1',
|
425
|
+
public_key_path: 'montgomery',
|
426
|
+
key_name: 'tarpals'
|
403
427
|
}
|
404
428
|
end
|
405
429
|
|
406
430
|
before(:each) do
|
407
|
-
@expected = config.merge(:
|
408
|
-
@expected.delete_if
|
409
|
-
k == :server_name
|
410
|
-
end
|
431
|
+
@expected = config.merge(name: config[:server_name])
|
432
|
+
@expected.delete_if { |k, _| k == :server_name }
|
411
433
|
end
|
412
434
|
|
413
435
|
it 'passes that key name to Fog' do
|
@@ -418,20 +440,18 @@ describe Kitchen::Driver::Openstack do
|
|
418
440
|
context 'a provided security group' do
|
419
441
|
let(:config) do
|
420
442
|
{
|
421
|
-
:
|
422
|
-
:
|
423
|
-
:
|
424
|
-
:
|
425
|
-
:
|
426
|
-
:
|
443
|
+
server_name: 'hello',
|
444
|
+
image_ref: '111',
|
445
|
+
flavor_ref: '1',
|
446
|
+
public_key_path: 'montgomery',
|
447
|
+
key_name: 'tarpals',
|
448
|
+
security_groups: ['ping-and-ssh']
|
427
449
|
}
|
428
450
|
end
|
429
451
|
|
430
452
|
before(:each) do
|
431
|
-
@expected = config.merge(:
|
432
|
-
@expected.delete_if
|
433
|
-
k == :server_name
|
434
|
-
end
|
453
|
+
@expected = config.merge(name: config[:server_name])
|
454
|
+
@expected.delete_if { |k, _| k == :server_name }
|
435
455
|
end
|
436
456
|
|
437
457
|
it 'passes that security group to Fog' do
|
@@ -442,17 +462,18 @@ describe Kitchen::Driver::Openstack do
|
|
442
462
|
context 'image/flavor specifies id' do
|
443
463
|
let(:config) do
|
444
464
|
{
|
445
|
-
:
|
446
|
-
:
|
447
|
-
:
|
448
|
-
:
|
465
|
+
server_name: 'hello',
|
466
|
+
image_ref: '111',
|
467
|
+
flavor_ref: '1',
|
468
|
+
public_key_path: 'tarpals'
|
449
469
|
}
|
450
470
|
end
|
451
471
|
|
452
472
|
it 'exact id match' do
|
453
|
-
servers.
|
454
|
-
|
455
|
-
|
473
|
+
expect(servers).to receive(:create).with(name: 'hello',
|
474
|
+
image_ref: '111',
|
475
|
+
flavor_ref: '1',
|
476
|
+
public_key_path: 'tarpals')
|
456
477
|
driver.send(:create_server)
|
457
478
|
end
|
458
479
|
end
|
@@ -460,17 +481,18 @@ describe Kitchen::Driver::Openstack do
|
|
460
481
|
context 'image/flavor specifies name' do
|
461
482
|
let(:config) do
|
462
483
|
{
|
463
|
-
:
|
464
|
-
:
|
465
|
-
:
|
466
|
-
:
|
484
|
+
server_name: 'hello',
|
485
|
+
image_ref: 'fedora',
|
486
|
+
flavor_ref: 'small',
|
487
|
+
public_key_path: 'tarpals'
|
467
488
|
}
|
468
489
|
end
|
469
490
|
|
470
491
|
it 'exact name match' do
|
471
|
-
servers.
|
472
|
-
|
473
|
-
|
492
|
+
expect(servers).to receive(:create).with(name: 'hello',
|
493
|
+
image_ref: '222',
|
494
|
+
flavor_ref: '2',
|
495
|
+
public_key_path: 'tarpals')
|
474
496
|
driver.send(:create_server)
|
475
497
|
end
|
476
498
|
end
|
@@ -478,18 +500,19 @@ describe Kitchen::Driver::Openstack do
|
|
478
500
|
context 'image/flavor specifies regex' do
|
479
501
|
let(:config) do
|
480
502
|
{
|
481
|
-
:
|
503
|
+
server_name: 'hello',
|
482
504
|
# pass regex as string as yml returns string values
|
483
|
-
:
|
484
|
-
:
|
485
|
-
:
|
505
|
+
image_ref: '/edo/',
|
506
|
+
flavor_ref: '/in/',
|
507
|
+
public_key_path: 'tarpals'
|
486
508
|
}
|
487
509
|
end
|
488
510
|
|
489
511
|
it 'regex name match' do
|
490
|
-
servers.
|
491
|
-
|
492
|
-
|
512
|
+
expect(servers).to receive(:create).with(name: 'hello',
|
513
|
+
image_ref: '222',
|
514
|
+
flavor_ref: '1',
|
515
|
+
public_key_path: 'tarpals')
|
493
516
|
driver.send(:create_server)
|
494
517
|
end
|
495
518
|
end
|
@@ -497,11 +520,11 @@ describe Kitchen::Driver::Openstack do
|
|
497
520
|
context 'network specifies id' do
|
498
521
|
let(:config) do
|
499
522
|
{
|
500
|
-
:
|
501
|
-
:
|
502
|
-
:
|
503
|
-
:
|
504
|
-
:
|
523
|
+
server_name: 'hello',
|
524
|
+
image_ref: '111',
|
525
|
+
flavor_ref: '1',
|
526
|
+
public_key_path: 'tarpals',
|
527
|
+
network_ref: '1'
|
505
528
|
}
|
506
529
|
end
|
507
530
|
|
@@ -509,12 +532,12 @@ describe Kitchen::Driver::Openstack do
|
|
509
532
|
networks = [
|
510
533
|
{ 'net_id' => '1' }
|
511
534
|
]
|
512
|
-
servers.
|
513
|
-
:
|
514
|
-
:
|
515
|
-
:
|
516
|
-
:
|
517
|
-
:
|
535
|
+
expect(servers).to receive(:create).with(
|
536
|
+
name: 'hello',
|
537
|
+
image_ref: '111',
|
538
|
+
flavor_ref: '1',
|
539
|
+
public_key_path: 'tarpals',
|
540
|
+
nics: networks
|
518
541
|
)
|
519
542
|
driver.send(:create_server)
|
520
543
|
end
|
@@ -523,11 +546,11 @@ describe Kitchen::Driver::Openstack do
|
|
523
546
|
context 'network specifies name' do
|
524
547
|
let(:config) do
|
525
548
|
{
|
526
|
-
:
|
527
|
-
:
|
528
|
-
:
|
529
|
-
:
|
530
|
-
:
|
549
|
+
server_name: 'hello',
|
550
|
+
image_ref: '111',
|
551
|
+
flavor_ref: '1',
|
552
|
+
public_key_path: 'tarpals',
|
553
|
+
network_ref: 'vlan1'
|
531
554
|
}
|
532
555
|
end
|
533
556
|
|
@@ -535,12 +558,12 @@ describe Kitchen::Driver::Openstack do
|
|
535
558
|
networks = [
|
536
559
|
{ 'net_id' => '1' }
|
537
560
|
]
|
538
|
-
servers.
|
539
|
-
:
|
540
|
-
:
|
541
|
-
:
|
542
|
-
:
|
543
|
-
:
|
561
|
+
expect(servers).to receive(:create).with(
|
562
|
+
name: 'hello',
|
563
|
+
image_ref: '111',
|
564
|
+
flavor_ref: '1',
|
565
|
+
public_key_path: 'tarpals',
|
566
|
+
nics: networks
|
544
567
|
)
|
545
568
|
driver.send(:create_server)
|
546
569
|
end
|
@@ -549,25 +572,25 @@ describe Kitchen::Driver::Openstack do
|
|
549
572
|
context 'multiple networks specifies id' do
|
550
573
|
let(:config) do
|
551
574
|
{
|
552
|
-
:
|
553
|
-
:
|
554
|
-
:
|
555
|
-
:
|
556
|
-
:
|
575
|
+
server_name: 'hello',
|
576
|
+
image_ref: '111',
|
577
|
+
flavor_ref: '1',
|
578
|
+
public_key_path: 'tarpals',
|
579
|
+
network_ref: %w(1 2)
|
557
580
|
}
|
558
581
|
end
|
559
582
|
|
560
583
|
it 'exact id match' do
|
561
584
|
networks = [
|
562
585
|
{ 'net_id' => '1' },
|
563
|
-
{ 'net_id' => '2' }
|
586
|
+
{ 'net_id' => '2' }
|
564
587
|
]
|
565
|
-
servers.
|
566
|
-
:
|
567
|
-
:
|
568
|
-
:
|
569
|
-
:
|
570
|
-
:
|
588
|
+
expect(servers).to receive(:create).with(
|
589
|
+
name: 'hello',
|
590
|
+
image_ref: '111',
|
591
|
+
flavor_ref: '1',
|
592
|
+
public_key_path: 'tarpals',
|
593
|
+
nics: networks
|
571
594
|
)
|
572
595
|
driver.send(:create_server)
|
573
596
|
end
|
@@ -576,27 +599,27 @@ describe Kitchen::Driver::Openstack do
|
|
576
599
|
context 'user_data specified' do
|
577
600
|
let(:config) do
|
578
601
|
{
|
579
|
-
:
|
580
|
-
:
|
581
|
-
:
|
582
|
-
:
|
583
|
-
:
|
602
|
+
server_name: 'hello',
|
603
|
+
image_ref: '111',
|
604
|
+
flavor_ref: '1',
|
605
|
+
public_key_path: 'tarpals',
|
606
|
+
user_data: 'cloud-init.txt'
|
584
607
|
}
|
585
608
|
end
|
586
609
|
let(:data) { "#cloud-config\n" }
|
587
610
|
|
588
611
|
before(:each) do
|
589
|
-
File.
|
590
|
-
File.
|
612
|
+
allow(File).to receive(:exist?).and_return(true)
|
613
|
+
allow(File).to receive(:open).and_return(data)
|
591
614
|
end
|
592
615
|
|
593
|
-
it '
|
594
|
-
servers.
|
595
|
-
:
|
596
|
-
:
|
597
|
-
:
|
598
|
-
:
|
599
|
-
:
|
616
|
+
it 'passes file contents' do
|
617
|
+
expect(servers).to receive(:create).with(
|
618
|
+
name: 'hello',
|
619
|
+
image_ref: '111',
|
620
|
+
flavor_ref: '1',
|
621
|
+
public_key_path: 'tarpals',
|
622
|
+
user_data: data)
|
600
623
|
driver.send(:create_server)
|
601
624
|
end
|
602
625
|
end
|
@@ -604,8 +627,8 @@ describe Kitchen::Driver::Openstack do
|
|
604
627
|
|
605
628
|
describe '#generate_name' do
|
606
629
|
before(:each) do
|
607
|
-
Etc.
|
608
|
-
Socket.
|
630
|
+
allow(Etc).to receive(:getlogin).and_return('user')
|
631
|
+
allow(Socket).to receive(:gethostname).and_return('host')
|
609
632
|
end
|
610
633
|
|
611
634
|
it 'generates a name' do
|
@@ -615,41 +638,55 @@ describe Kitchen::Driver::Openstack do
|
|
615
638
|
|
616
639
|
context 'local node with a long hostname' do
|
617
640
|
before(:each) do
|
618
|
-
Socket.
|
619
|
-
Socket.stub(:gethostname).and_return('ab.c' * 20)
|
641
|
+
allow(Socket).to receive(:gethostname).and_return('ab.c' * 20)
|
620
642
|
end
|
621
643
|
|
622
644
|
it 'limits the generated name to 63 characters' do
|
623
|
-
expect(driver.send(:generate_name, 'long').length).to
|
645
|
+
expect(driver.send(:generate_name, 'long').length).to be <= (63)
|
624
646
|
end
|
625
647
|
end
|
626
648
|
|
627
649
|
context 'node with a long hostname, username, and base name' do
|
628
650
|
before(:each) do
|
629
|
-
Socket.
|
630
|
-
|
631
|
-
|
632
|
-
Etc.unstub(:getlogin)
|
633
|
-
Etc.stub(:getlogin).and_return('user' * 20)
|
651
|
+
allow(Socket).to receive(:gethostname).and_return('abc' * 20)
|
652
|
+
allow(Etc).to receive(:getlogin).and_return('user' * 20)
|
634
653
|
end
|
635
654
|
|
636
655
|
it 'limits the generated name to 63 characters' do
|
637
656
|
expect(driver.send(:generate_name, 'long' * 20).length).to eq(63)
|
638
657
|
end
|
639
658
|
end
|
659
|
+
|
660
|
+
context 'a login and hostname with punctuation in them' do
|
661
|
+
let(:base) { 'a.base-name' }
|
662
|
+
|
663
|
+
before(:each) do
|
664
|
+
allow(Etc).to receive(:getlogin).and_return('some.u-se-r' * 20)
|
665
|
+
allow(Socket).to receive(:gethostname).and_return('a.host-name' * 20)
|
666
|
+
end
|
667
|
+
|
668
|
+
it 'strips out the dots to prevent bad server names' do
|
669
|
+
expect(driver.send(:generate_name, base)).to_not include('.')
|
670
|
+
end
|
671
|
+
|
672
|
+
it 'strips out all but the three hyphen separators' do
|
673
|
+
expect(driver.send(:generate_name, base).count('-')).to eq(3)
|
674
|
+
end
|
675
|
+
end
|
640
676
|
end
|
641
677
|
|
642
678
|
describe '#attach_ip_from_pool' do
|
643
679
|
let(:server) { nil }
|
644
680
|
let(:pool) { 'swimmers' }
|
645
681
|
let(:ip) { '1.1.1.1' }
|
646
|
-
let(:address)
|
647
|
-
:
|
648
|
-
|
682
|
+
let(:address) do
|
683
|
+
double(ip: ip, fixed_ip: nil, instance_id: nil, pool: pool)
|
684
|
+
end
|
685
|
+
let(:compute) { double(addresses: [address]) }
|
649
686
|
|
650
687
|
before(:each) do
|
651
|
-
driver.
|
652
|
-
driver.
|
688
|
+
allow(driver).to receive(:attach_ip).with(server, ip).and_return('bing!')
|
689
|
+
allow(driver).to receive(:compute).and_return(compute)
|
653
690
|
end
|
654
691
|
|
655
692
|
it 'determines an IP to attempt to attach' do
|
@@ -657,8 +694,10 @@ describe Kitchen::Driver::Openstack do
|
|
657
694
|
end
|
658
695
|
|
659
696
|
context 'no free addresses in the specified pool' do
|
660
|
-
let(:address)
|
661
|
-
:
|
697
|
+
let(:address) do
|
698
|
+
double(ip: ip, fixed_ip: nil, instance_id: nil,
|
699
|
+
pool: 'some_other_pool')
|
700
|
+
end
|
662
701
|
|
663
702
|
it 'raises an exception' do
|
664
703
|
expect { driver.send(:attach_ip_from_pool, server, pool) }.to \
|
@@ -672,8 +711,8 @@ describe Kitchen::Driver::Openstack do
|
|
672
711
|
let(:addresses) { {} }
|
673
712
|
let(:server) do
|
674
713
|
s = double('server')
|
675
|
-
s.
|
676
|
-
s.
|
714
|
+
expect(s).to receive(:associate_address).with(ip).and_return(true)
|
715
|
+
allow(s).to receive(:addresses).and_return(addresses)
|
677
716
|
s
|
678
717
|
end
|
679
718
|
|
@@ -691,19 +730,19 @@ describe Kitchen::Driver::Openstack do
|
|
691
730
|
let(:driver) do
|
692
731
|
d = Kitchen::Driver::Openstack.new(config)
|
693
732
|
d.instance = instance
|
694
|
-
d.
|
733
|
+
allow(d).to receive(:parse_ips).and_return(parsed_ips)
|
695
734
|
d
|
696
735
|
end
|
697
736
|
let(:server) do
|
698
|
-
double(:
|
699
|
-
|
700
|
-
|
737
|
+
double(addresses: addresses,
|
738
|
+
public_ip_addresses: public_ip_addresses,
|
739
|
+
private_ip_addresses: private_ip_addresses)
|
701
740
|
end
|
702
741
|
|
703
742
|
context 'both public and private IPs' do
|
704
|
-
let(:public_ip_addresses) { %w
|
705
|
-
let(:private_ip_addresses) { %w
|
706
|
-
let(:parsed_ips) { [%w
|
743
|
+
let(:public_ip_addresses) { %w(1::1 1.2.3.4) }
|
744
|
+
let(:private_ip_addresses) { %w(5.5.5.5) }
|
745
|
+
let(:parsed_ips) { [%w(1.2.3.4), %w(5.5.5.5)] }
|
707
746
|
|
708
747
|
it 'returns a public IPv4 address' do
|
709
748
|
expect(driver.send(:get_ip, server)).to eq('1.2.3.4')
|
@@ -711,8 +750,8 @@ describe Kitchen::Driver::Openstack do
|
|
711
750
|
end
|
712
751
|
|
713
752
|
context 'only public IPs' do
|
714
|
-
let(:public_ip_addresses) { %w
|
715
|
-
let(:parsed_ips) { [%w
|
753
|
+
let(:public_ip_addresses) { %w(4.3.2.1 2::1) }
|
754
|
+
let(:parsed_ips) { [%w(4.3.2.1), []] }
|
716
755
|
|
717
756
|
it 'returns a public IPv4 address' do
|
718
757
|
expect(driver.send(:get_ip, server)).to eq('4.3.2.1')
|
@@ -720,8 +759,8 @@ describe Kitchen::Driver::Openstack do
|
|
720
759
|
end
|
721
760
|
|
722
761
|
context 'only private IPs' do
|
723
|
-
let(:private_ip_addresses) { %w
|
724
|
-
let(:parsed_ips) { [[], %w
|
762
|
+
let(:private_ip_addresses) { %w(3::1 5.5.5.5) }
|
763
|
+
let(:parsed_ips) { [[], %w(5.5.5.5)] }
|
725
764
|
|
726
765
|
it 'returns a private IPv4 address' do
|
727
766
|
expect(driver.send(:get_ip, server)).to eq('5.5.5.5')
|
@@ -729,7 +768,7 @@ describe Kitchen::Driver::Openstack do
|
|
729
768
|
end
|
730
769
|
|
731
770
|
context 'IPs in user-defined network group' do
|
732
|
-
let(:config) { { :
|
771
|
+
let(:config) { { openstack_network_name: 'mynetwork' } }
|
733
772
|
let(:addresses) do
|
734
773
|
{
|
735
774
|
'mynetwork' => [
|
@@ -747,10 +786,10 @@ describe Kitchen::Driver::Openstack do
|
|
747
786
|
context 'an OpenStack deployment without the floating IP extension' do
|
748
787
|
let(:server) do
|
749
788
|
s = double('server')
|
750
|
-
s.
|
751
|
-
s.
|
789
|
+
allow(s).to receive(:addresses).and_return(addresses)
|
790
|
+
allow(s).to receive(:public_ip_addresses).and_raise(
|
752
791
|
Fog::Compute::OpenStack::NotFound)
|
753
|
-
s.
|
792
|
+
allow(s).to receive(:private_ip_addresses).and_raise(
|
754
793
|
Fog::Compute::OpenStack::NotFound)
|
755
794
|
s
|
756
795
|
end
|
@@ -762,7 +801,7 @@ describe Kitchen::Driver::Openstack do
|
|
762
801
|
'private' => [{ 'addr' => '8.8.8.8' }, { 'addr' => '9.9.9.9' }]
|
763
802
|
}
|
764
803
|
end
|
765
|
-
let(:parsed_ips) { [%w
|
804
|
+
let(:parsed_ips) { [%w(6.6.6.6 7.7.7.7), %w(8.8.8.8 9.9.9.9)] }
|
766
805
|
|
767
806
|
it 'selects the first public IP' do
|
768
807
|
expect(driver.send(:get_ip, server)).to eq('6.6.6.6')
|
@@ -773,7 +812,7 @@ describe Kitchen::Driver::Openstack do
|
|
773
812
|
let(:addresses) do
|
774
813
|
{ 'public' => [{ 'addr' => '6.6.6.6' }, { 'addr' => '7.7.7.7' }] }
|
775
814
|
end
|
776
|
-
let(:parsed_ips) { [%w
|
815
|
+
let(:parsed_ips) { [%w(6.6.6.6 7.7.7.7), []] }
|
777
816
|
|
778
817
|
it 'selects the first public IP' do
|
779
818
|
expect(driver.send(:get_ip, server)).to eq('6.6.6.6')
|
@@ -784,7 +823,7 @@ describe Kitchen::Driver::Openstack do
|
|
784
823
|
let(:addresses) do
|
785
824
|
{ 'private' => [{ 'addr' => '8.8.8.8' }, { 'addr' => '9.9.9.9' }] }
|
786
825
|
end
|
787
|
-
let(:parsed_ips) { [[], %w
|
826
|
+
let(:parsed_ips) { [[], %w(8.8.8.8 9.9.9.9)] }
|
788
827
|
|
789
828
|
it 'selects the first private IP' do
|
790
829
|
expect(driver.send(:get_ip, server)).to eq('8.8.8.8')
|
@@ -800,10 +839,10 @@ describe Kitchen::Driver::Openstack do
|
|
800
839
|
end
|
801
840
|
|
802
841
|
describe '#parse_ips' do
|
803
|
-
let(:pub_v4) { %w
|
804
|
-
let(:pub_v6) { %w
|
805
|
-
let(:priv_v4) { %w
|
806
|
-
let(:priv_v6) { %w
|
842
|
+
let(:pub_v4) { %w(1.1.1.1 2.2.2.2) }
|
843
|
+
let(:pub_v6) { %w(1::1 2::2) }
|
844
|
+
let(:priv_v4) { %w(3.3.3.3 4.4.4.4) }
|
845
|
+
let(:priv_v6) { %w(3::3 4::4) }
|
807
846
|
let(:pub) { pub_v4 + pub_v6 }
|
808
847
|
let(:priv) { priv_v4 + priv_v6 }
|
809
848
|
|
@@ -815,7 +854,7 @@ describe Kitchen::Driver::Openstack do
|
|
815
854
|
end
|
816
855
|
|
817
856
|
context 'IPv6' do
|
818
|
-
let(:config) { { :
|
857
|
+
let(:config) { { use_ipv6: true } }
|
819
858
|
|
820
859
|
it 'returns only the v6 IPs' do
|
821
860
|
expect(driver.send(:parse_ips, pub, priv)).to eq([pub_v6, priv_v6])
|
@@ -833,7 +872,7 @@ describe Kitchen::Driver::Openstack do
|
|
833
872
|
end
|
834
873
|
|
835
874
|
context 'IPv6' do
|
836
|
-
let(:config) { { :
|
875
|
+
let(:config) { { use_ipv6: true } }
|
837
876
|
|
838
877
|
it 'returns only the v6 IPs' do
|
839
878
|
expect(driver.send(:parse_ips, pub, priv)).to eq([pub_v6, []])
|
@@ -851,7 +890,7 @@ describe Kitchen::Driver::Openstack do
|
|
851
890
|
end
|
852
891
|
|
853
892
|
context 'IPv6' do
|
854
|
-
let(:config) { { :
|
893
|
+
let(:config) { { use_ipv6: true } }
|
855
894
|
|
856
895
|
it 'returns only the v6 IPs' do
|
857
896
|
expect(driver.send(:parse_ips, pub, priv)).to eq([[], priv_v6])
|
@@ -870,7 +909,7 @@ describe Kitchen::Driver::Openstack do
|
|
870
909
|
end
|
871
910
|
|
872
911
|
context 'IPv6' do
|
873
|
-
let(:config) { { :
|
912
|
+
let(:config) { { use_ipv6: true } }
|
874
913
|
|
875
914
|
it 'returns empty lists' do
|
876
915
|
expect(driver.send(:parse_ips, nil, nil)).to eq([[], []])
|
@@ -880,21 +919,21 @@ describe Kitchen::Driver::Openstack do
|
|
880
919
|
end
|
881
920
|
|
882
921
|
describe '#do_ssh_setup' do
|
883
|
-
let(:config) { { :
|
884
|
-
let(:server) { double(:
|
885
|
-
let(:state) { { :
|
886
|
-
let(:read) { double(:
|
922
|
+
let(:config) { { public_key_path: '/pub_key' } }
|
923
|
+
let(:server) { double(password: 'aloha') }
|
924
|
+
let(:state) { { hostname: 'host' } }
|
925
|
+
let(:read) { double(read: 'a_key') }
|
887
926
|
let(:ssh) do
|
888
927
|
s = double('ssh')
|
889
|
-
s.
|
928
|
+
allow(s).to receive(:run) { |args| args }
|
890
929
|
s
|
891
930
|
end
|
892
931
|
|
893
932
|
it 'opens an SSH session to the server' do
|
894
|
-
Fog::SSH.
|
895
|
-
|
896
|
-
driver.
|
897
|
-
read.
|
933
|
+
allow(Fog::SSH).to receive(:new).with('host', 'root', password: 'aloha')
|
934
|
+
.and_return(ssh)
|
935
|
+
allow(driver).to receive(:open).with('/pub_key').and_return(read)
|
936
|
+
allow(read).to receive(:read).and_return('a_key')
|
898
937
|
res = driver.send(:do_ssh_setup, state, config, server)
|
899
938
|
expected = [
|
900
939
|
'mkdir .ssh',
|
@@ -906,18 +945,16 @@ describe Kitchen::Driver::Openstack do
|
|
906
945
|
end
|
907
946
|
|
908
947
|
describe '#add_ohai_hint' do
|
909
|
-
let(:
|
910
|
-
let(:server) { double(:password => 'aloha') }
|
911
|
-
let(:state) { { :hostname => 'host' } }
|
948
|
+
let(:state) { { hostname: 'host' } }
|
912
949
|
let(:ssh) do
|
913
950
|
s = double('ssh')
|
914
|
-
s.
|
951
|
+
allow(s).to receive(:run) { |args| args }
|
915
952
|
s
|
916
953
|
end
|
917
954
|
it 'opens an SSH session to the server' do
|
918
|
-
Fog::SSH.
|
919
|
-
|
920
|
-
res = driver.send(:add_ohai_hint, state
|
955
|
+
allow(Fog::SSH).to receive(:new).with('host', 'root', anything)
|
956
|
+
.and_return(ssh)
|
957
|
+
res = driver.send(:add_ohai_hint, state)
|
921
958
|
expected = [
|
922
959
|
"sudo mkdir -p #{Ohai::Config[:hints_path][0]}",
|
923
960
|
"sudo touch #{Ohai::Config[:hints_path][0]}/openstack.json"
|