kitchen-openstack 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/kitchen/driver/openstack.rb +12 -12
- data/lib/kitchen/driver/openstack/volume.rb +7 -0
- data/lib/kitchen/driver/openstack_version.rb +2 -2
- metadata +5 -17
- data/.gitignore +0 -23
- data/.rubocop.yml +0 -16
- data/.travis.yml +0 -19
- data/CHANGELOG.md +0 -556
- data/Gemfile +0 -7
- data/LICENSE.txt +0 -17
- data/Rakefile +0 -20
- data/kitchen-openstack.gemspec +0 -38
- data/spec/kitchen/driver/openstack/volume_spec.rb +0 -127
- data/spec/kitchen/driver/openstack_spec.rb +0 -1360
- data/spec/spec_helper.rb +0 -18
data/Gemfile
DELETED
data/LICENSE.txt
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
Author:: Jonathan Hartman (<j@p4nt5.com>)
|
2
|
-
Author:: JJ Asghar (<jj@chef.io>)
|
3
|
-
|
4
|
-
Copyright (c) 2013 Jonathan Hartman
|
5
|
-
Copyright (c) 2015 Chef Software, Inc
|
6
|
-
|
7
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
-
you may not use this file except in compliance with the License.
|
9
|
-
You may obtain a copy of the License at
|
10
|
-
|
11
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
|
13
|
-
Unless required by applicable law or agreed to in writing, software
|
14
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
-
See the License for the specific language governing permissions and
|
17
|
-
limitations under the License.
|
data/Rakefile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# Encoding: UTF-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "bundler/setup"
|
5
|
-
require "bundler/gem_tasks"
|
6
|
-
require "chefstyle"
|
7
|
-
require "rubocop/rake_task"
|
8
|
-
require "rspec/core/rake_task"
|
9
|
-
|
10
|
-
RuboCop::RakeTask.new
|
11
|
-
|
12
|
-
desc "Display LOC stats"
|
13
|
-
task :loc do
|
14
|
-
puts "\n## LOC Stats"
|
15
|
-
sh "countloc -r lib/kitchen"
|
16
|
-
end
|
17
|
-
|
18
|
-
RSpec::Core::RakeTask.new(:spec)
|
19
|
-
|
20
|
-
task default: %i{rubocop loc spec}
|
data/kitchen-openstack.gemspec
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# Encoding: UTF-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
lib = File.expand_path("../lib", __FILE__)
|
5
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
-
require "kitchen/driver/openstack_version"
|
7
|
-
|
8
|
-
Gem::Specification.new do |spec|
|
9
|
-
spec.name = "kitchen-openstack"
|
10
|
-
spec.version = Kitchen::Driver::OPENSTACK_VERSION
|
11
|
-
spec.authors = ["Jonathan Hartman", "JJ Asghar"]
|
12
|
-
spec.email = ["j@p4nt5.com", "jj@chef.io"]
|
13
|
-
spec.description = "A Test Kitchen OpenStack Nova driver"
|
14
|
-
spec.summary = spec.description
|
15
|
-
spec.homepage = "https://github.com/test-kitchen/kitchen-openstack"
|
16
|
-
spec.license = "Apache-2.0"
|
17
|
-
|
18
|
-
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.required_ruby_version = ">= 2.0.0"
|
22
|
-
|
23
|
-
spec.add_dependency "test-kitchen", ">= 1.4.1", "< 3"
|
24
|
-
spec.add_dependency "fog-openstack", "~> 0.1"
|
25
|
-
spec.add_dependency "unf"
|
26
|
-
spec.add_dependency "ohai"
|
27
|
-
|
28
|
-
spec.add_development_dependency "bundler"
|
29
|
-
spec.add_development_dependency "rake"
|
30
|
-
spec.add_development_dependency "chefstyle"
|
31
|
-
spec.add_development_dependency "cane"
|
32
|
-
spec.add_development_dependency "countloc"
|
33
|
-
spec.add_development_dependency "rspec"
|
34
|
-
spec.add_development_dependency "simplecov"
|
35
|
-
spec.add_development_dependency "simplecov-console"
|
36
|
-
spec.add_development_dependency "coveralls"
|
37
|
-
spec.add_development_dependency "github_changelog_generator"
|
38
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
# Encoding: UTF-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require_relative "../../../spec_helper"
|
5
|
-
require_relative "../../../../lib/kitchen/driver/openstack/volume"
|
6
|
-
|
7
|
-
require "logger"
|
8
|
-
require "stringio"
|
9
|
-
require "rspec"
|
10
|
-
require "kitchen"
|
11
|
-
require "ohai"
|
12
|
-
|
13
|
-
describe Kitchen::Driver::Openstack::Volume do
|
14
|
-
let(:os) do
|
15
|
-
{
|
16
|
-
openstack_username: "twilight",
|
17
|
-
openstack_domain_id: "default",
|
18
|
-
openstack_api_key: "sparkle",
|
19
|
-
openstack_auth_url: "http:",
|
20
|
-
openstack_project_name: "trixie",
|
21
|
-
openstack_region: "syd",
|
22
|
-
openstack_service_name: "the_service",
|
23
|
-
}
|
24
|
-
end
|
25
|
-
let(:logger_io) { StringIO.new }
|
26
|
-
let(:logger) { Kitchen::Logger.new(logdev: logger_io) }
|
27
|
-
describe "#volume" do
|
28
|
-
let(:vol_driver) do
|
29
|
-
described_class.new(logger)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "creates a new block device connection" do
|
33
|
-
allow(Fog::Volume).to receive(:new) { |arg| arg }
|
34
|
-
expect(vol_driver.send(:volume, os)).to eq(os)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
describe "#create_volume" do
|
38
|
-
let(:config) do
|
39
|
-
{
|
40
|
-
server_name: "applejack",
|
41
|
-
block_device_mapping: {
|
42
|
-
snapshot_id: "444",
|
43
|
-
volume_size: "5",
|
44
|
-
creation_timeout: "30",
|
45
|
-
},
|
46
|
-
}
|
47
|
-
end
|
48
|
-
|
49
|
-
let(:create_volume) do
|
50
|
-
{
|
51
|
-
body: { "volume" => { "id" => "555" } },
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
let(:volume_model) do
|
56
|
-
{
|
57
|
-
id: "555",
|
58
|
-
status: "ACTIVE",
|
59
|
-
# wait_for: true
|
60
|
-
# ready?: true
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
let(:volume) do
|
65
|
-
double(
|
66
|
-
create_volume: create_volume,
|
67
|
-
volumes: [volume_model]
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
let(:wait_for) do
|
72
|
-
{
|
73
|
-
ready?: true,
|
74
|
-
status: "ACTIVE",
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
|
-
let(:vol_driver) do
|
79
|
-
d = described_class.new(logger)
|
80
|
-
allow(d).to receive(:volume).and_return(volume)
|
81
|
-
allow(d).to receive(:volume_model).and_return(true)
|
82
|
-
d
|
83
|
-
end
|
84
|
-
|
85
|
-
it "creates a volume" do
|
86
|
-
# This seems like a hack
|
87
|
-
# how would we do this on the volume_model instead?
|
88
|
-
# This makes rspec work
|
89
|
-
# but the vol_driver doesnt have these methods properties?
|
90
|
-
allow(vol_driver).to receive(:status).and_return("ACTIVE")
|
91
|
-
allow(vol_driver).to receive(:ready?).and_return(true)
|
92
|
-
allow(volume_model).to receive(:wait_for)
|
93
|
-
.with(an_instance_of(String)).and_yield
|
94
|
-
|
95
|
-
# allow(vol_driver).a
|
96
|
-
expect(vol_driver.send(:create_volume, config, os)).to eq("555")
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe "#get_bdm" do
|
101
|
-
let(:config) do
|
102
|
-
{
|
103
|
-
block_device_mapping: {
|
104
|
-
make_volue: true,
|
105
|
-
snapshot_id: "333",
|
106
|
-
volume_id: "555",
|
107
|
-
volume_size: "5",
|
108
|
-
volume_device_name: "vda",
|
109
|
-
delete_on_termination: true,
|
110
|
-
},
|
111
|
-
}
|
112
|
-
end
|
113
|
-
|
114
|
-
let(:vol_driver) do
|
115
|
-
d = described_class.new(logger)
|
116
|
-
allow(d).to receive(:create_volume).and_return("555")
|
117
|
-
d
|
118
|
-
end
|
119
|
-
|
120
|
-
it "returns the block device mapping config" do
|
121
|
-
expects = config[:block_device_mapping]
|
122
|
-
expects.delete_if { |k, _| k == :make_volume }
|
123
|
-
expects.delete_if { |k, _| k == :snapshot_id }
|
124
|
-
expect(vol_driver.send(:get_bdm, config, os)).to eq(expects)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
@@ -1,1360 +0,0 @@
|
|
1
|
-
# Encoding: UTF-8
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require_relative "../../spec_helper"
|
5
|
-
require_relative "../../../lib/kitchen/driver/openstack"
|
6
|
-
|
7
|
-
require "logger"
|
8
|
-
require "stringio"
|
9
|
-
require "rspec"
|
10
|
-
require "kitchen"
|
11
|
-
require "kitchen/driver/openstack"
|
12
|
-
require "kitchen/provisioner/dummy"
|
13
|
-
require "kitchen/transport/dummy"
|
14
|
-
require "kitchen/verifier/dummy"
|
15
|
-
require "ohai"
|
16
|
-
require "excon"
|
17
|
-
require "fog/openstack"
|
18
|
-
|
19
|
-
describe Kitchen::Driver::Openstack do
|
20
|
-
let(:logged_output) { StringIO.new }
|
21
|
-
let(:logger) { Logger.new(logged_output) }
|
22
|
-
let(:config) { {} }
|
23
|
-
let(:state) { {} }
|
24
|
-
let(:instance_name) { "potatoes" }
|
25
|
-
let(:transport) { Kitchen::Transport::Dummy.new }
|
26
|
-
let(:platform) { Kitchen::Platform.new(name: "fake_platform") }
|
27
|
-
let(:driver) { Kitchen::Driver::Openstack.new(config) }
|
28
|
-
|
29
|
-
let(:instance) do
|
30
|
-
double(
|
31
|
-
name: instance_name,
|
32
|
-
transport: transport,
|
33
|
-
logger: logger,
|
34
|
-
platform: platform,
|
35
|
-
to_str: "instance"
|
36
|
-
)
|
37
|
-
end
|
38
|
-
|
39
|
-
let(:driver) { described_class.new(config) }
|
40
|
-
|
41
|
-
before(:each) do
|
42
|
-
allow_any_instance_of(described_class).to receive(:instance)
|
43
|
-
.and_return(instance)
|
44
|
-
allow(File).to receive(:exist?).and_call_original
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "#finalize_config" do
|
48
|
-
before(:each) { allow(File).to receive(:exist?).and_return(false) }
|
49
|
-
end
|
50
|
-
|
51
|
-
describe "#initialize" do
|
52
|
-
context "default options" do
|
53
|
-
it "uses the normal SSH status check" do
|
54
|
-
expect(driver[:no_ssh_tcp_check]).to eq(false)
|
55
|
-
end
|
56
|
-
|
57
|
-
it "sets a default TCP check wait time" do
|
58
|
-
expect(driver[:no_ssh_tcp_check_sleep]).to eq(120)
|
59
|
-
end
|
60
|
-
|
61
|
-
it "sets a default Openstack API read timeout" do
|
62
|
-
expect(driver[:read_timeout]).to eq(60)
|
63
|
-
end
|
64
|
-
|
65
|
-
it "sets a default Openstack API write timeout" do
|
66
|
-
expect(driver[:write_timeout]).to eq(60)
|
67
|
-
end
|
68
|
-
|
69
|
-
it "sets a default ssh connection timeout" do
|
70
|
-
expect(driver[:connect_timeout]).to eq(60)
|
71
|
-
end
|
72
|
-
|
73
|
-
nils = %i{
|
74
|
-
server_name
|
75
|
-
openstack_project_name
|
76
|
-
openstack_region
|
77
|
-
openstack_service_name
|
78
|
-
floating_ip_pool
|
79
|
-
floating_ip
|
80
|
-
availability_zone
|
81
|
-
security_groups
|
82
|
-
network_ref
|
83
|
-
metadata
|
84
|
-
}
|
85
|
-
nils.each do |i|
|
86
|
-
it "defaults to no #{i}" do
|
87
|
-
expect(driver[i]).to eq(nil)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context "overridden options" do
|
93
|
-
let(:config) do
|
94
|
-
{
|
95
|
-
image_ref: "22",
|
96
|
-
image_id: "4391b03e-f7fb-46fd-a356-fa5e42f6d728",
|
97
|
-
flavor_ref: "33",
|
98
|
-
flavor_id: "19a2281e-591e-4b47-be06-631c3c7704e8",
|
99
|
-
public_key_path: "/tmp",
|
100
|
-
username: "admin",
|
101
|
-
port: "2222",
|
102
|
-
server_name: "puppy",
|
103
|
-
server_name_prefix: "parsnip",
|
104
|
-
openstack_project_name: "that_one",
|
105
|
-
openstack_region: "atlantis",
|
106
|
-
openstack_service_name: "the_service",
|
107
|
-
floating_ip_pool: "swimmers",
|
108
|
-
floating_ip: "11111",
|
109
|
-
network_ref: "0xCAFFE",
|
110
|
-
network_id: "57d6e41a-f369-4c92-9ebe-1fbf198bc783",
|
111
|
-
use_ssh_agent: true,
|
112
|
-
connect_timeout: 123,
|
113
|
-
read_timeout: 234,
|
114
|
-
write_timeout: 345,
|
115
|
-
block_device_mapping: {
|
116
|
-
make_volume: true,
|
117
|
-
snapshot_id: "44",
|
118
|
-
volume_id: "55",
|
119
|
-
volume_size: "5",
|
120
|
-
device_name: "vda",
|
121
|
-
delete_on_termination: true,
|
122
|
-
},
|
123
|
-
metadata: {
|
124
|
-
name: "test",
|
125
|
-
ohai: "chef",
|
126
|
-
},
|
127
|
-
}
|
128
|
-
end
|
129
|
-
|
130
|
-
it "uses all the overridden options" do
|
131
|
-
drv = driver
|
132
|
-
config.each do |k, v|
|
133
|
-
expect(drv[k]).to eq(v)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it "overrides server name prefix with explicit server name, if given" do
|
138
|
-
expect(driver[:server_name]).to eq(config[:server_name])
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe "#create" do
|
144
|
-
let(:server) do
|
145
|
-
double(id: "test123", wait_for: true, public_ip_addresses: %w{1.2.3.4})
|
146
|
-
end
|
147
|
-
let(:driver) do
|
148
|
-
d = super()
|
149
|
-
allow(d).to receive(:default_name).and_return("a_monkey!")
|
150
|
-
allow(d).to receive(:create_server).and_return(server)
|
151
|
-
allow(d).to receive(:wait_for_sshd).with("1.2.3.4", "root", port: "22")
|
152
|
-
.and_return(true)
|
153
|
-
allow(d).to receive(:get_ip).and_return("1.2.3.4")
|
154
|
-
allow(d).to receive(:add_ohai_hint).and_return(true)
|
155
|
-
allow(d).to receive(:do_ssh_setup).and_return(true)
|
156
|
-
allow(d).to receive(:sleep)
|
157
|
-
allow(d).to receive(:wait_for_ssh_key_access).and_return("SSH key authetication successful") # rubocop:disable Metrics/LineLength
|
158
|
-
allow(d).to receive(:disable_ssl_validation).and_return(false)
|
159
|
-
d
|
160
|
-
end
|
161
|
-
|
162
|
-
context "when a server is already created" do
|
163
|
-
it "does not create a new instance" do
|
164
|
-
state[:server_id] = "1"
|
165
|
-
expect(driver).not_to receive(:create_server)
|
166
|
-
driver.create(state)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
context "required options provided" do
|
171
|
-
let(:config) do
|
172
|
-
{
|
173
|
-
openstack_username: "hello",
|
174
|
-
openstack_domain_id: "default",
|
175
|
-
openstack_api_key: "world",
|
176
|
-
openstack_auth_url: "http:",
|
177
|
-
openstack_project_name: "www",
|
178
|
-
glance_cache_wait_timeout: 600,
|
179
|
-
disable_ssl_validation: false,
|
180
|
-
}
|
181
|
-
end
|
182
|
-
let(:server) do
|
183
|
-
double(id: "test123", wait_for: true, public_ip_addresses: %w{1.2.3.4})
|
184
|
-
end
|
185
|
-
|
186
|
-
let(:driver) do
|
187
|
-
d = described_class.new(config)
|
188
|
-
allow(d).to receive(:config_server_name).and_return("a_monkey!")
|
189
|
-
allow(d).to receive(:create_server).and_return(server)
|
190
|
-
allow(server).to receive(:id).and_return("test123")
|
191
|
-
|
192
|
-
# Inside the yield block we are calling ready? So we fake it here
|
193
|
-
allow(d).to receive(:ready?).and_return(true)
|
194
|
-
allow(server).to receive(:wait_for)
|
195
|
-
.with(an_instance_of(Integer)).and_yield
|
196
|
-
|
197
|
-
allow(d).to receive(:get_ip).and_return("1.2.3.4")
|
198
|
-
allow(d).to receive(:bourne_shell?).and_return(false)
|
199
|
-
d
|
200
|
-
end
|
201
|
-
|
202
|
-
it "returns nil, but modifies the state" do
|
203
|
-
expect(driver.send(:create, state)).to eq(nil)
|
204
|
-
expect(state[:server_id]).to eq("test123")
|
205
|
-
end
|
206
|
-
|
207
|
-
it "throws an Action error when trying to create_server" do
|
208
|
-
allow(driver).to receive(:create_server).and_raise(Fog::Errors::Error)
|
209
|
-
expect { driver.send(:create, state) }.to raise_error(Kitchen::ActionFailed) # rubocop:disable Metrics/LineLength
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
describe "#destroy" do
|
215
|
-
let(:server_id) { "12345" }
|
216
|
-
let(:hostname) { "example.com" }
|
217
|
-
let(:state) { { server_id: server_id, hostname: hostname } }
|
218
|
-
let(:server) { double(nil?: false, destroy: true) }
|
219
|
-
let(:servers) { double(get: server) }
|
220
|
-
let(:compute) { double(servers: servers) }
|
221
|
-
|
222
|
-
let(:driver) do
|
223
|
-
d = super()
|
224
|
-
allow(d).to receive(:compute).and_return(compute)
|
225
|
-
d
|
226
|
-
end
|
227
|
-
|
228
|
-
context "a live server that needs to be destroyed" do
|
229
|
-
it "destroys the server" do
|
230
|
-
expect(state).to receive(:delete).with(:server_id)
|
231
|
-
expect(state).to receive(:delete).with(:hostname)
|
232
|
-
driver.destroy(state)
|
233
|
-
end
|
234
|
-
|
235
|
-
it "does not disable SSL cert validation" do
|
236
|
-
expect(driver).to_not receive(:disable_ssl_validation)
|
237
|
-
driver.destroy(state)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
context "no server ID present" do
|
242
|
-
let(:state) { {} }
|
243
|
-
|
244
|
-
it "does nothing" do
|
245
|
-
allow(driver).to receive(:compute)
|
246
|
-
expect(driver).to_not receive(:compute)
|
247
|
-
expect(state).to_not receive(:delete)
|
248
|
-
driver.destroy(state)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
context "a server that was already destroyed" do
|
253
|
-
let(:servers) do
|
254
|
-
s = double("servers")
|
255
|
-
allow(s).to receive(:get).with("12345").and_return(nil)
|
256
|
-
s
|
257
|
-
end
|
258
|
-
let(:compute) { double(servers: servers) }
|
259
|
-
let(:driver) do
|
260
|
-
d = super()
|
261
|
-
allow(d).to receive(:compute).and_return(compute)
|
262
|
-
d
|
263
|
-
end
|
264
|
-
|
265
|
-
it "does not try to destroy the server again" do
|
266
|
-
allow_message_expectations_on_nil
|
267
|
-
driver.destroy(state)
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
context "SSL validation disabled" do
|
272
|
-
let(:config) { { disable_ssl_validation: true } }
|
273
|
-
|
274
|
-
it "disables SSL cert validation" do
|
275
|
-
expect(driver).to receive(:disable_ssl_validation)
|
276
|
-
driver.destroy(state)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
context "Deallocate floating IP" do
|
281
|
-
let(:config) do
|
282
|
-
{
|
283
|
-
floating_ip_pool: "swimmers",
|
284
|
-
allocate_floating_ip: true,
|
285
|
-
}
|
286
|
-
end
|
287
|
-
let(:ip) { "1.1.1.1" }
|
288
|
-
let(:ip_id) { "123" }
|
289
|
-
|
290
|
-
let(:network_response) do
|
291
|
-
double(body: { "floatingips" => [{ "id" => ip_id }] })
|
292
|
-
end
|
293
|
-
|
294
|
-
let(:network) do
|
295
|
-
s = double("network")
|
296
|
-
expect(s).to receive(:list_floating_ips).with(floating_ip_address: ip).and_return(network_response) # rubocop:disable Metrics/LineLength
|
297
|
-
expect(s).to receive(:delete_floating_ip).with(ip_id)
|
298
|
-
s
|
299
|
-
end
|
300
|
-
|
301
|
-
let(:driver) do
|
302
|
-
d = super()
|
303
|
-
allow(d).to receive(:get_public_private_ips).and_return([ip, nil])
|
304
|
-
allow(d).to receive(:compute).and_return(compute)
|
305
|
-
allow(d).to receive(:network).and_return(network)
|
306
|
-
d
|
307
|
-
end
|
308
|
-
it "deallocates the ip" do
|
309
|
-
driver.destroy(state)
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
describe "#openstack_server" do
|
315
|
-
let(:config) do
|
316
|
-
{
|
317
|
-
openstack_username: "a",
|
318
|
-
openstack_domain_id: "default",
|
319
|
-
openstack_api_key: "b",
|
320
|
-
openstack_auth_url: "http://",
|
321
|
-
openstack_project_name: "me",
|
322
|
-
openstack_region: "ORD",
|
323
|
-
openstack_service_name: "stack",
|
324
|
-
connection_options:
|
325
|
-
{
|
326
|
-
read_timeout: 60,
|
327
|
-
write_timeout: 60,
|
328
|
-
connect_timeout: 60,
|
329
|
-
},
|
330
|
-
}
|
331
|
-
end
|
332
|
-
|
333
|
-
it "returns a hash of server settings" do
|
334
|
-
expected = config.merge(provider: "OpenStack")
|
335
|
-
expect(driver.send(:openstack_server)).to eq(expected)
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
describe "#required_server_settings" do
|
340
|
-
it "returns the required settings for an OpenStack server" do
|
341
|
-
expected = %i{
|
342
|
-
openstack_username openstack_api_key openstack_auth_url openstack_domain_id
|
343
|
-
}
|
344
|
-
expect(driver.send(:required_server_settings)).to eq(expected)
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
describe "#optional_server_settings" do
|
349
|
-
it "returns the optional settings for an OpenStack server" do
|
350
|
-
excluded = %i{
|
351
|
-
openstack_username openstack_api_key openstack_auth_url openstack_domain_id
|
352
|
-
}
|
353
|
-
expect(driver.send(:optional_server_settings)).not_to include(*excluded)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
describe "#compute" do
|
358
|
-
let(:config) do
|
359
|
-
{
|
360
|
-
openstack_username: "monkey",
|
361
|
-
openstack_domain_id: "default",
|
362
|
-
openstack_api_key: "potato",
|
363
|
-
openstack_auth_url: "http:",
|
364
|
-
openstack_project_name: "link",
|
365
|
-
openstack_region: "ord",
|
366
|
-
openstack_service_name: "the_service",
|
367
|
-
connection_options:
|
368
|
-
{
|
369
|
-
read_timeout: 60,
|
370
|
-
write_timeout: 60,
|
371
|
-
connect_timeout: 60,
|
372
|
-
},
|
373
|
-
}
|
374
|
-
end
|
375
|
-
|
376
|
-
context "all requirements provided" do
|
377
|
-
it "creates a new compute connection" do
|
378
|
-
allow(Fog::Compute).to receive(:new) { |arg| arg }
|
379
|
-
res = config.merge(provider: "OpenStack")
|
380
|
-
expect(driver.send(:compute)).to eq(res)
|
381
|
-
end
|
382
|
-
|
383
|
-
it "creates a new network connection" do
|
384
|
-
allow(Fog::Network).to receive(:new) { |arg| arg }
|
385
|
-
res = config.merge(provider: "OpenStack")
|
386
|
-
expect(driver.send(:network)).to eq(res)
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
context "only an API key provided" do
|
391
|
-
let(:config) { { openstack_api_key: "1234" } }
|
392
|
-
|
393
|
-
it "raises an error" do
|
394
|
-
expect { driver.send(:compute) }.to raise_error(ArgumentError)
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
context "only a username provided" do
|
399
|
-
let(:config) { { openstack_username: "monkey" } }
|
400
|
-
|
401
|
-
it "raises an error" do
|
402
|
-
expect { driver.send(:compute) }.to raise_error(ArgumentError)
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
describe "#create_server" do
|
408
|
-
let(:config) do
|
409
|
-
{
|
410
|
-
server_name: "hello",
|
411
|
-
image_ref: "111",
|
412
|
-
flavor_ref: "1",
|
413
|
-
availability_zone: nil,
|
414
|
-
block_device_mapping: {
|
415
|
-
volume_size: "5",
|
416
|
-
volume_id: "333",
|
417
|
-
volume_device_name: "vda",
|
418
|
-
delete_on_termination: "true",
|
419
|
-
},
|
420
|
-
}
|
421
|
-
end
|
422
|
-
let(:servers) do
|
423
|
-
s = double("servers")
|
424
|
-
allow(s).to receive(:create) { |arg| arg }
|
425
|
-
s
|
426
|
-
end
|
427
|
-
let(:vlan1_net) { double(id: "1", name: "vlan1") }
|
428
|
-
let(:vlan2_net) { double(id: "2", name: "vlan2") }
|
429
|
-
let(:ubuntu_image) { double(id: "111", name: "ubuntu") }
|
430
|
-
let(:fedora_image) { double(id: "222", name: "fedora") }
|
431
|
-
let(:tiny_flavor) { double(id: "1", name: "tiny") }
|
432
|
-
let(:small_flavor) { double(id: "2", name: "small") }
|
433
|
-
let(:compute) do
|
434
|
-
double(
|
435
|
-
servers: servers,
|
436
|
-
images: [ubuntu_image, fedora_image],
|
437
|
-
flavors: [tiny_flavor, small_flavor]
|
438
|
-
)
|
439
|
-
end
|
440
|
-
let(:network) do
|
441
|
-
double(networks: double(all: [vlan1_net, vlan2_net]))
|
442
|
-
end
|
443
|
-
let(:block_device_mapping) do
|
444
|
-
{
|
445
|
-
volume_id: "333",
|
446
|
-
volume_size: "5",
|
447
|
-
volume_device_name: "vda",
|
448
|
-
delete_on_termination: "true",
|
449
|
-
}
|
450
|
-
end
|
451
|
-
let(:driver) do
|
452
|
-
d = super()
|
453
|
-
allow(d).to receive(:compute).and_return(compute)
|
454
|
-
allow(d).to receive(:network).and_return(network)
|
455
|
-
allow(d).to receive(:get_bdm).and_return(block_device_mapping)
|
456
|
-
d
|
457
|
-
end
|
458
|
-
|
459
|
-
context "a default config" do
|
460
|
-
before(:each) do
|
461
|
-
@expected = config.merge(name: config[:server_name])
|
462
|
-
@expected.delete_if { |k, _| k == :server_name }
|
463
|
-
end
|
464
|
-
|
465
|
-
it "creates the server using a compute connection" do
|
466
|
-
expect(driver.send(:create_server)).to eq(@expected)
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
|
-
context "a provided key name" do
|
471
|
-
let(:config) do
|
472
|
-
{
|
473
|
-
server_name: "hello",
|
474
|
-
image_ref: "111",
|
475
|
-
flavor_ref: "1",
|
476
|
-
availability_zone: nil,
|
477
|
-
key_name: "tarpals",
|
478
|
-
}
|
479
|
-
end
|
480
|
-
|
481
|
-
before(:each) do
|
482
|
-
@expected = config.merge(name: config[:server_name])
|
483
|
-
@expected.delete_if { |k, _| k == :server_name }
|
484
|
-
end
|
485
|
-
|
486
|
-
it "passes that key name to Fog" do
|
487
|
-
expect(driver.send(:create_server)).to eq(@expected)
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
context "a provided security group" do
|
492
|
-
let(:config) do
|
493
|
-
{
|
494
|
-
server_name: "hello",
|
495
|
-
image_ref: "111",
|
496
|
-
flavor_ref: "1",
|
497
|
-
availability_zone: nil,
|
498
|
-
key_name: "tarpals",
|
499
|
-
security_groups: ["ping-and-ssh"],
|
500
|
-
}
|
501
|
-
end
|
502
|
-
|
503
|
-
before(:each) do
|
504
|
-
@expected = config.merge(name: config[:server_name])
|
505
|
-
@expected.delete_if { |k, _| k == :server_name }
|
506
|
-
end
|
507
|
-
|
508
|
-
it "passes that security group to Fog" do
|
509
|
-
expect(driver.send(:create_server)).to eq(@expected)
|
510
|
-
end
|
511
|
-
end
|
512
|
-
|
513
|
-
context "a provided availability zone" do
|
514
|
-
let(:config) do
|
515
|
-
{
|
516
|
-
server_name: "hello",
|
517
|
-
image_ref: "111",
|
518
|
-
flavor_ref: "1",
|
519
|
-
availability_zone: "elsewhere",
|
520
|
-
key_name: "tarpals",
|
521
|
-
}
|
522
|
-
end
|
523
|
-
|
524
|
-
before(:each) do
|
525
|
-
@expected = config.merge(name: config[:server_name])
|
526
|
-
@expected.delete_if { |k, _| k == :server_name }
|
527
|
-
end
|
528
|
-
|
529
|
-
it "passes that availability zone to Fog" do
|
530
|
-
expect(driver.send(:create_server)).to eq(@expected)
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
context "image_id specified" do
|
535
|
-
let(:config) do
|
536
|
-
{
|
537
|
-
server_name: "hello",
|
538
|
-
image_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
539
|
-
flavor_ref: "1",
|
540
|
-
}
|
541
|
-
end
|
542
|
-
|
543
|
-
it "exact id match" do
|
544
|
-
expect(servers).to receive(:create).with(
|
545
|
-
name: "hello",
|
546
|
-
image_ref: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
547
|
-
flavor_ref: "1",
|
548
|
-
availability_zone: nil
|
549
|
-
)
|
550
|
-
driver.send(:create_server)
|
551
|
-
end
|
552
|
-
end
|
553
|
-
|
554
|
-
context "image_id and image_ref specified" do
|
555
|
-
let(:config) do
|
556
|
-
{
|
557
|
-
server_name: "hello",
|
558
|
-
image_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
559
|
-
image_ref: "111",
|
560
|
-
flavor_ref: "1",
|
561
|
-
}
|
562
|
-
end
|
563
|
-
|
564
|
-
it "raises an exception" do
|
565
|
-
expect { driver.send(:create_server) }.to \
|
566
|
-
raise_error(Kitchen::ActionFailed)
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
context "flavor_id specified" do
|
571
|
-
let(:config) do
|
572
|
-
{
|
573
|
-
server_name: "hello",
|
574
|
-
flavor_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
575
|
-
image_ref: "111",
|
576
|
-
}
|
577
|
-
end
|
578
|
-
|
579
|
-
it "exact id match" do
|
580
|
-
expect(servers).to receive(:create).with(
|
581
|
-
name: "hello",
|
582
|
-
flavor_ref: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
583
|
-
image_ref: "111",
|
584
|
-
availability_zone: nil
|
585
|
-
)
|
586
|
-
driver.send(:create_server)
|
587
|
-
end
|
588
|
-
end
|
589
|
-
|
590
|
-
context "flavor_id and flavor_ref specified" do
|
591
|
-
let(:config) do
|
592
|
-
{
|
593
|
-
server_name: "hello",
|
594
|
-
image_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
595
|
-
flavor_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
596
|
-
flavor_ref: "1",
|
597
|
-
}
|
598
|
-
end
|
599
|
-
|
600
|
-
it "raises an exception" do
|
601
|
-
expect { driver.send(:create_server) }.to \
|
602
|
-
raise_error(Kitchen::ActionFailed)
|
603
|
-
end
|
604
|
-
end
|
605
|
-
|
606
|
-
context "image/flavor specifies id" do
|
607
|
-
let(:config) do
|
608
|
-
{
|
609
|
-
server_name: "hello",
|
610
|
-
image_ref: "111",
|
611
|
-
flavor_ref: "1",
|
612
|
-
}
|
613
|
-
end
|
614
|
-
|
615
|
-
it "exact id match" do
|
616
|
-
expect(servers).to receive(:create).with(name: "hello",
|
617
|
-
image_ref: "111",
|
618
|
-
flavor_ref: "1",
|
619
|
-
availability_zone: nil)
|
620
|
-
driver.send(:create_server)
|
621
|
-
end
|
622
|
-
end
|
623
|
-
|
624
|
-
context "image/flavor specifies name" do
|
625
|
-
let(:config) do
|
626
|
-
{
|
627
|
-
server_name: "hello",
|
628
|
-
image_ref: "fedora",
|
629
|
-
flavor_ref: "small",
|
630
|
-
}
|
631
|
-
end
|
632
|
-
|
633
|
-
it "exact name match" do
|
634
|
-
expect(servers).to receive(:create).with(name: "hello",
|
635
|
-
image_ref: "222",
|
636
|
-
flavor_ref: "2",
|
637
|
-
availability_zone: nil)
|
638
|
-
driver.send(:create_server)
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
context "image/flavor specifies regex" do
|
643
|
-
let(:config) do
|
644
|
-
{
|
645
|
-
server_name: "hello",
|
646
|
-
# pass regex as string as yml returns string values
|
647
|
-
image_ref: "/edo/",
|
648
|
-
flavor_ref: "/in/",
|
649
|
-
}
|
650
|
-
end
|
651
|
-
|
652
|
-
it "regex name match" do
|
653
|
-
expect(servers).to receive(:create).with(name: "hello",
|
654
|
-
image_ref: "222",
|
655
|
-
flavor_ref: "1",
|
656
|
-
availability_zone: nil)
|
657
|
-
driver.send(:create_server)
|
658
|
-
end
|
659
|
-
end
|
660
|
-
|
661
|
-
context "network specifies network_id" do
|
662
|
-
let(:config) do
|
663
|
-
{
|
664
|
-
server_name: "hello",
|
665
|
-
image_ref: "111",
|
666
|
-
flavor_ref: "1",
|
667
|
-
network_id: "0922b7aa-0a2f-4e68-8ff7-2886c4fc472d",
|
668
|
-
}
|
669
|
-
end
|
670
|
-
|
671
|
-
it "exact id match" do
|
672
|
-
networks = [
|
673
|
-
{ "net_id" => "0922b7aa-0a2f-4e68-8ff7-2886c4fc472d" },
|
674
|
-
]
|
675
|
-
expect(servers).to receive(:create).with(name: "hello",
|
676
|
-
image_ref: "111",
|
677
|
-
flavor_ref: "1",
|
678
|
-
availability_zone: nil,
|
679
|
-
nics: networks)
|
680
|
-
driver.send(:create_server)
|
681
|
-
end
|
682
|
-
end
|
683
|
-
|
684
|
-
context "network_id and network_ref specified" do
|
685
|
-
let(:config) do
|
686
|
-
{
|
687
|
-
server_name: "hello",
|
688
|
-
image_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
689
|
-
flavor_id: "1e1f4346-e3ea-48ba-9d1b-0002bfcb8981",
|
690
|
-
network_id: "0922b7aa-0a2f-4e68-8ff7-2886c4fc472d",
|
691
|
-
network_ref: "1",
|
692
|
-
}
|
693
|
-
end
|
694
|
-
|
695
|
-
it "raises an exception" do
|
696
|
-
expect { driver.send(:create_server) }.to \
|
697
|
-
raise_error(Kitchen::ActionFailed)
|
698
|
-
end
|
699
|
-
end
|
700
|
-
|
701
|
-
context "network specifies id" do
|
702
|
-
let(:config) do
|
703
|
-
{
|
704
|
-
server_name: "hello",
|
705
|
-
image_ref: "111",
|
706
|
-
flavor_ref: "1",
|
707
|
-
network_ref: "1",
|
708
|
-
}
|
709
|
-
end
|
710
|
-
|
711
|
-
it "exact id match" do
|
712
|
-
networks = [
|
713
|
-
{ "net_id" => "1" },
|
714
|
-
]
|
715
|
-
expect(servers).to receive(:create).with(
|
716
|
-
name: "hello",
|
717
|
-
image_ref: "111",
|
718
|
-
flavor_ref: "1",
|
719
|
-
availability_zone: nil,
|
720
|
-
nics: networks
|
721
|
-
)
|
722
|
-
driver.send(:create_server)
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
|
-
context "network specifies name" do
|
727
|
-
let(:config) do
|
728
|
-
{
|
729
|
-
server_name: "hello",
|
730
|
-
image_ref: "111",
|
731
|
-
flavor_ref: "1",
|
732
|
-
network_ref: "vlan1",
|
733
|
-
}
|
734
|
-
end
|
735
|
-
|
736
|
-
it "exact id match" do
|
737
|
-
networks = [
|
738
|
-
{ "net_id" => "1" },
|
739
|
-
]
|
740
|
-
expect(servers).to receive(:create).with(
|
741
|
-
name: "hello",
|
742
|
-
image_ref: "111",
|
743
|
-
flavor_ref: "1",
|
744
|
-
availability_zone: nil,
|
745
|
-
nics: networks
|
746
|
-
)
|
747
|
-
driver.send(:create_server)
|
748
|
-
end
|
749
|
-
end
|
750
|
-
|
751
|
-
context "multiple networks specifies id" do
|
752
|
-
let(:config) do
|
753
|
-
{
|
754
|
-
server_name: "hello",
|
755
|
-
image_ref: "111",
|
756
|
-
flavor_ref: "1",
|
757
|
-
network_ref: %w{1 2},
|
758
|
-
}
|
759
|
-
end
|
760
|
-
|
761
|
-
it "exact id match" do
|
762
|
-
networks = [
|
763
|
-
{ "net_id" => "1" },
|
764
|
-
{ "net_id" => "2" },
|
765
|
-
]
|
766
|
-
expect(servers).to receive(:create).with(
|
767
|
-
name: "hello",
|
768
|
-
image_ref: "111",
|
769
|
-
flavor_ref: "1",
|
770
|
-
availability_zone: nil,
|
771
|
-
nics: networks
|
772
|
-
)
|
773
|
-
driver.send(:create_server)
|
774
|
-
end
|
775
|
-
end
|
776
|
-
|
777
|
-
context "user_data specified" do
|
778
|
-
let(:config) do
|
779
|
-
{
|
780
|
-
server_name: "hello",
|
781
|
-
image_ref: "111",
|
782
|
-
flavor_ref: "1",
|
783
|
-
user_data: "cloud-init.txt",
|
784
|
-
}
|
785
|
-
end
|
786
|
-
let(:data) { "#cloud-config\n" }
|
787
|
-
|
788
|
-
before(:each) do
|
789
|
-
allow(File).to receive(:exist?).and_return(true)
|
790
|
-
allow(File).to receive(:open).and_return(data)
|
791
|
-
end
|
792
|
-
|
793
|
-
it "passes file contents" do
|
794
|
-
expect(servers).to receive(:create).with(
|
795
|
-
name: "hello",
|
796
|
-
image_ref: "111",
|
797
|
-
flavor_ref: "1",
|
798
|
-
availability_zone: nil,
|
799
|
-
user_data: data
|
800
|
-
)
|
801
|
-
driver.send(:create_server)
|
802
|
-
end
|
803
|
-
end
|
804
|
-
|
805
|
-
context "config drive enabled" do
|
806
|
-
let(:config) do
|
807
|
-
{
|
808
|
-
server_name: "hello",
|
809
|
-
image_ref: "111",
|
810
|
-
flavor_ref: "1",
|
811
|
-
config_drive: true,
|
812
|
-
}
|
813
|
-
end
|
814
|
-
|
815
|
-
it "enables config drive" do
|
816
|
-
expect(servers).to receive(:create).with(
|
817
|
-
name: "hello",
|
818
|
-
image_ref: "111",
|
819
|
-
flavor_ref: "1",
|
820
|
-
availability_zone: nil,
|
821
|
-
config_drive: true
|
822
|
-
)
|
823
|
-
driver.send(:create_server)
|
824
|
-
end
|
825
|
-
end
|
826
|
-
|
827
|
-
context "metadata specified" do
|
828
|
-
let(:config) do
|
829
|
-
{
|
830
|
-
server_name: "hello",
|
831
|
-
image_ref: "111",
|
832
|
-
flavor_ref: "1",
|
833
|
-
metadata: {
|
834
|
-
name: "hello",
|
835
|
-
ohai: "chef",
|
836
|
-
},
|
837
|
-
}
|
838
|
-
end
|
839
|
-
let(:data) do
|
840
|
-
{
|
841
|
-
name: "hello",
|
842
|
-
ohai: "chef",
|
843
|
-
}
|
844
|
-
end
|
845
|
-
|
846
|
-
it "passes metadata contents" do
|
847
|
-
expect(servers).to receive(:create).with(
|
848
|
-
name: "hello",
|
849
|
-
image_ref: "111",
|
850
|
-
flavor_ref: "1",
|
851
|
-
availability_zone: nil,
|
852
|
-
metadata: data
|
853
|
-
)
|
854
|
-
driver.send(:create_server)
|
855
|
-
end
|
856
|
-
end
|
857
|
-
end
|
858
|
-
|
859
|
-
describe "#default_name" do
|
860
|
-
let(:login) { "user" }
|
861
|
-
let(:hostname) { "host" }
|
862
|
-
|
863
|
-
before(:each) do
|
864
|
-
allow(Etc).to receive(:getlogin).and_return(login)
|
865
|
-
allow(Socket).to receive(:gethostname).and_return(hostname)
|
866
|
-
end
|
867
|
-
|
868
|
-
context "local node with a long hostname" do
|
869
|
-
let(:hostname) { "ab.c" * 20 }
|
870
|
-
|
871
|
-
it "limits the generated name to 63 characters" do
|
872
|
-
expect(driver.send(:default_name).length).to be <= 63
|
873
|
-
end
|
874
|
-
end
|
875
|
-
|
876
|
-
context "a login and hostname with punctuation in them" do
|
877
|
-
let(:login) { "some.u-se-r" }
|
878
|
-
let(:hostname) { "a.host-name" }
|
879
|
-
let(:instance_name) { "a.instance-name" }
|
880
|
-
|
881
|
-
it "strips out the dots to prevent bad server names" do
|
882
|
-
expect(driver.send(:default_name)).to_not include(".")
|
883
|
-
end
|
884
|
-
|
885
|
-
it "strips out all but the three hyphen separators" do
|
886
|
-
expect(driver.send(:default_name).count("-")).to eq(3)
|
887
|
-
end
|
888
|
-
end
|
889
|
-
|
890
|
-
context "a non-login shell" do
|
891
|
-
let(:login) { nil }
|
892
|
-
|
893
|
-
it "subs in a placeholder login string" do
|
894
|
-
expect(driver.send(:default_name)).to match(/^potatoes-*-/)
|
895
|
-
end
|
896
|
-
end
|
897
|
-
end
|
898
|
-
|
899
|
-
describe "#server_name_prefix" do
|
900
|
-
let(:login) { "user" }
|
901
|
-
let(:hostname) { "host" }
|
902
|
-
let(:prefix) { "parsnip" }
|
903
|
-
|
904
|
-
# These are still used in the "blank prefix" test
|
905
|
-
before(:each) do
|
906
|
-
allow(Etc).to receive(:getlogin).and_return(login)
|
907
|
-
allow(Socket).to receive(:gethostname).and_return(hostname)
|
908
|
-
end
|
909
|
-
|
910
|
-
context "very long prefix provided" do
|
911
|
-
let(:long_prefix) { "a" * 70 }
|
912
|
-
|
913
|
-
it "limits the generated name to 63 characters" do
|
914
|
-
expect(driver.send(:server_name_prefix, long_prefix).length)
|
915
|
-
.to be <= 63
|
916
|
-
end
|
917
|
-
end
|
918
|
-
end
|
919
|
-
|
920
|
-
describe "#attach_ip_from_pool" do
|
921
|
-
let(:server) { nil }
|
922
|
-
let(:pool) { "swimmers" }
|
923
|
-
let(:ip) { "1.1.1.1" }
|
924
|
-
let(:address) do
|
925
|
-
double(ip: ip, fixed_ip: nil, instance_id: nil, pool: pool)
|
926
|
-
end
|
927
|
-
let(:compute) { double(addresses: [address]) }
|
928
|
-
|
929
|
-
before(:each) do
|
930
|
-
allow(driver).to receive(:attach_ip).with(server, ip).and_return("bing!")
|
931
|
-
allow(driver).to receive(:compute).and_return(compute)
|
932
|
-
end
|
933
|
-
|
934
|
-
it "determines an IP to attempt to attach" do
|
935
|
-
expect(driver.send(:attach_ip_from_pool, server, pool)).to eq("bing!")
|
936
|
-
end
|
937
|
-
|
938
|
-
context "no free addresses in the specified pool" do
|
939
|
-
let(:address) do
|
940
|
-
double(ip: ip, fixed_ip: nil, instance_id: nil,
|
941
|
-
pool: "some_other_pool")
|
942
|
-
end
|
943
|
-
|
944
|
-
it "raises an exception" do
|
945
|
-
expect { driver.send(:attach_ip_from_pool, server, pool) }.to \
|
946
|
-
raise_error(Kitchen::ActionFailed)
|
947
|
-
end
|
948
|
-
end
|
949
|
-
end
|
950
|
-
|
951
|
-
describe "#allocate_ip_from_pool" do
|
952
|
-
let(:server) { nil }
|
953
|
-
let(:pool) { "swimmers" }
|
954
|
-
let(:config) { { allocate_floating_ip: true } }
|
955
|
-
let(:network_id) { 123 }
|
956
|
-
let(:ip) { "1.1.1.1" }
|
957
|
-
let(:address) do
|
958
|
-
double(ip: ip, fixed_ip: nil, instance_id: nil, pool: pool)
|
959
|
-
end
|
960
|
-
let(:list_networks_response) do
|
961
|
-
double(body: { "networks" => [{ "name" => pool, "id" => network_id }] })
|
962
|
-
end
|
963
|
-
let(:create_ip_network_response) do
|
964
|
-
double(body: { "floatingip" => { "floating_ip_address" => ip } })
|
965
|
-
end
|
966
|
-
let(:network) { double(list_networks: list_networks_response, create_floating_ip: create_ip_network_response) } # rubocop:disable Metrics/LineLength
|
967
|
-
|
968
|
-
before(:each) do
|
969
|
-
allow(driver).to receive(:attach_ip).with(server, ip).and_return("bing!")
|
970
|
-
allow(driver).to receive(:network).and_return(network)
|
971
|
-
end
|
972
|
-
|
973
|
-
it "determines an IP to attempt to attach" do
|
974
|
-
expect(driver.send(:attach_ip_from_pool, server, pool)).to eq("bing!")
|
975
|
-
end
|
976
|
-
end
|
977
|
-
|
978
|
-
describe "#attach_ip" do
|
979
|
-
let(:ip) { "1.1.1.1" }
|
980
|
-
let(:addresses) { {} }
|
981
|
-
let(:server) do
|
982
|
-
s = double("server")
|
983
|
-
expect(s).to receive(:associate_address).with(ip).and_return(true)
|
984
|
-
allow(s).to receive(:addresses).and_return(addresses)
|
985
|
-
s
|
986
|
-
end
|
987
|
-
|
988
|
-
it "associates the IP address with the server" do
|
989
|
-
expect(driver.send(:attach_ip, server, ip)).to eq(true)
|
990
|
-
end
|
991
|
-
end
|
992
|
-
|
993
|
-
describe "#get_ip" do
|
994
|
-
let(:addresses) { nil }
|
995
|
-
let(:public_ip_addresses) { nil }
|
996
|
-
let(:private_ip_addresses) { nil }
|
997
|
-
let(:ip_addresses) { nil }
|
998
|
-
let(:parsed_ips) { [[], []] }
|
999
|
-
let(:driver) do
|
1000
|
-
d = super()
|
1001
|
-
allow(d).to receive(:parse_ips).and_return(parsed_ips)
|
1002
|
-
d
|
1003
|
-
end
|
1004
|
-
let(:server) do
|
1005
|
-
double(addresses: addresses,
|
1006
|
-
public_ip_addresses: public_ip_addresses,
|
1007
|
-
private_ip_addresses: private_ip_addresses,
|
1008
|
-
ip_addresses: ip_addresses,
|
1009
|
-
wait_for: { duration: 0 })
|
1010
|
-
end
|
1011
|
-
|
1012
|
-
context "both public and private IPs" do
|
1013
|
-
let(:public_ip_addresses) { %w{1::1 1.2.3.4} }
|
1014
|
-
let(:private_ip_addresses) { %w{5.5.5.5} }
|
1015
|
-
let(:parsed_ips) { [%w{1.2.3.4}, %w{5.5.5.5}] }
|
1016
|
-
|
1017
|
-
it "returns a public IPv4 address" do
|
1018
|
-
expect(driver.send(:get_ip, server)).to eq("1.2.3.4")
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
context "only public IPs" do
|
1023
|
-
let(:public_ip_addresses) { %w{4.3.2.1 2::1} }
|
1024
|
-
let(:parsed_ips) { [%w{4.3.2.1}, []] }
|
1025
|
-
|
1026
|
-
it "returns a public IPv4 address" do
|
1027
|
-
expect(driver.send(:get_ip, server)).to eq("4.3.2.1")
|
1028
|
-
end
|
1029
|
-
end
|
1030
|
-
|
1031
|
-
context "only private IPs" do
|
1032
|
-
let(:private_ip_addresses) { %w{3::1 5.5.5.5} }
|
1033
|
-
let(:parsed_ips) { [[], %w{5.5.5.5}] }
|
1034
|
-
|
1035
|
-
it "returns a private IPv4 address" do
|
1036
|
-
expect(driver.send(:get_ip, server)).to eq("5.5.5.5")
|
1037
|
-
end
|
1038
|
-
end
|
1039
|
-
|
1040
|
-
context "no predictable network name" do
|
1041
|
-
let(:ip_addresses) { %w{3::1 5.5.5.5} }
|
1042
|
-
let(:parsed_ips) { [[], %w{5.5.5.5}] }
|
1043
|
-
|
1044
|
-
it "returns the first IP that matches the IP version" do
|
1045
|
-
expect(driver.send(:get_ip, server)).to eq("5.5.5.5")
|
1046
|
-
end
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
context "IPs in user-defined network group" do
|
1050
|
-
let(:config) { { openstack_network_name: "mynetwork" } }
|
1051
|
-
let(:addresses) do
|
1052
|
-
{
|
1053
|
-
"mynetwork" => [
|
1054
|
-
{ "addr" => "7.7.7.7" },
|
1055
|
-
{ "addr" => "4::1" },
|
1056
|
-
],
|
1057
|
-
}
|
1058
|
-
end
|
1059
|
-
|
1060
|
-
it "returns a IPv4 address in user-defined network group" do
|
1061
|
-
expect(driver.send(:get_ip, server)).to eq("7.7.7.7")
|
1062
|
-
end
|
1063
|
-
end
|
1064
|
-
|
1065
|
-
context "when a floating ip is provided" do
|
1066
|
-
let(:config) { { floating_ip: "1.2.3.4" } }
|
1067
|
-
|
1068
|
-
it "returns the floating ip and skips reloading" do
|
1069
|
-
allow(driver).to receive(:config).and_return(config)
|
1070
|
-
|
1071
|
-
expect(server).to_not receive(:wait_for)
|
1072
|
-
expect(driver.send(:get_ip, server)).to eq("1.2.3.4")
|
1073
|
-
end
|
1074
|
-
end
|
1075
|
-
|
1076
|
-
context "an OpenStack deployment without the floating IP extension" do
|
1077
|
-
before do
|
1078
|
-
allow(server).to receive(:public_ip_addresses).and_raise(
|
1079
|
-
Fog::Compute::OpenStack::NotFound
|
1080
|
-
)
|
1081
|
-
allow(server).to receive(:private_ip_addresses).and_raise(
|
1082
|
-
Fog::Compute::OpenStack::NotFound
|
1083
|
-
)
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
context "both public and private IPs in the addresses hash" do
|
1087
|
-
let(:addresses) do
|
1088
|
-
{
|
1089
|
-
"public" => [{ "addr" => "6.6.6.6" }, { "addr" => "7.7.7.7" }],
|
1090
|
-
"private" => [{ "addr" => "8.8.8.8" }, { "addr" => "9.9.9.9" }],
|
1091
|
-
}
|
1092
|
-
end
|
1093
|
-
let(:parsed_ips) { [%w{6.6.6.6 7.7.7.7}, %w{8.8.8.8 9.9.9.9}] }
|
1094
|
-
|
1095
|
-
it "selects the first public IP" do
|
1096
|
-
expect(driver.send(:get_ip, server)).to eq("6.6.6.6")
|
1097
|
-
end
|
1098
|
-
end
|
1099
|
-
|
1100
|
-
context "when openstack_network_name is provided" do
|
1101
|
-
let(:addresses) do
|
1102
|
-
{
|
1103
|
-
"public" => [{ "addr" => "6.6.6.6" }, { "addr" => "7.7.7.7" }],
|
1104
|
-
"private" => [{ "addr" => "8.8.8.8" }, { "addr" => "9.9.9.9" }],
|
1105
|
-
}
|
1106
|
-
end
|
1107
|
-
let(:config) { { openstack_network_name: "public" } }
|
1108
|
-
|
1109
|
-
it "should respond with the first address from the addresses" do
|
1110
|
-
allow(driver).to receive(:config).and_return(config)
|
1111
|
-
|
1112
|
-
expect(driver.send(:get_ip, server)).to eq("6.6.6.6")
|
1113
|
-
end
|
1114
|
-
end
|
1115
|
-
|
1116
|
-
context "when openstack_network_name is provided and use_ipv6 is false" do
|
1117
|
-
let(:addresses) do
|
1118
|
-
{
|
1119
|
-
"public" => [{ "addr" => "4::1" }, { "addr" => "7.7.7.7" }],
|
1120
|
-
"private" => [{ "addr" => "5::1" }, { "addr" => "9.9.9.9" }],
|
1121
|
-
}
|
1122
|
-
end
|
1123
|
-
let(:config) { { openstack_network_name: "public" } }
|
1124
|
-
|
1125
|
-
it "should respond with the first IPv4 address from the addresses" do
|
1126
|
-
allow(driver).to receive(:config).and_return(config)
|
1127
|
-
|
1128
|
-
expect(driver.send(:get_ip, server)).to eq("7.7.7.7")
|
1129
|
-
end
|
1130
|
-
end
|
1131
|
-
|
1132
|
-
context "when openstack_network_name is provided and use_ipv6 is true" do
|
1133
|
-
let(:addresses) do
|
1134
|
-
{
|
1135
|
-
"public" => [{ "addr" => "4::1" }, { "addr" => "7.7.7.7" }],
|
1136
|
-
"private" => [{ "addr" => "5::1" }, { "addr" => "9.9.9.9" }],
|
1137
|
-
}
|
1138
|
-
end
|
1139
|
-
let(:config) { { openstack_network_name: "public", use_ipv6: true } }
|
1140
|
-
|
1141
|
-
it "should respond with the first IPv6 address from the addresses" do
|
1142
|
-
allow(driver).to receive(:config).and_return(config)
|
1143
|
-
|
1144
|
-
expect(driver.send(:get_ip, server)).to eq("4::1")
|
1145
|
-
end
|
1146
|
-
end
|
1147
|
-
|
1148
|
-
context "only public IPs in the address hash" do
|
1149
|
-
let(:addresses) do
|
1150
|
-
{ "public" => [{ "addr" => "6.6.6.6" }, { "addr" => "7.7.7.7" }] }
|
1151
|
-
end
|
1152
|
-
let(:parsed_ips) { [%w{6.6.6.6 7.7.7.7}, []] }
|
1153
|
-
|
1154
|
-
it "selects the first public IP" do
|
1155
|
-
expect(driver.send(:get_ip, server)).to eq("6.6.6.6")
|
1156
|
-
end
|
1157
|
-
end
|
1158
|
-
|
1159
|
-
context "only private IPs in the address hash" do
|
1160
|
-
let(:addresses) do
|
1161
|
-
{ "private" => [{ "addr" => "8.8.8.8" }, { "addr" => "9.9.9.9" }] }
|
1162
|
-
end
|
1163
|
-
let(:parsed_ips) { [[], %w{8.8.8.8 9.9.9.9}] }
|
1164
|
-
|
1165
|
-
it "selects the first private IP" do
|
1166
|
-
expect(driver.send(:get_ip, server)).to eq("8.8.8.8")
|
1167
|
-
end
|
1168
|
-
end
|
1169
|
-
end
|
1170
|
-
|
1171
|
-
context "no IP addresses whatsoever" do
|
1172
|
-
it "raises an exception" do
|
1173
|
-
expected = Kitchen::ActionFailed
|
1174
|
-
expect { driver.send(:get_ip, server) }.to raise_error(expected)
|
1175
|
-
end
|
1176
|
-
end
|
1177
|
-
|
1178
|
-
context "when network information is not found" do
|
1179
|
-
before do
|
1180
|
-
allow(server).to receive(:wait_for).and_raise(Fog::Errors::TimeoutError)
|
1181
|
-
end
|
1182
|
-
|
1183
|
-
it "raises an exception" do
|
1184
|
-
expected = Kitchen::ActionFailed
|
1185
|
-
expect { driver.send(:get_ip, server) }.to raise_error(expected)
|
1186
|
-
end
|
1187
|
-
end
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
describe "#parse_ips" do
|
1191
|
-
let(:pub_v4) { %w{1.1.1.1 2.2.2.2} }
|
1192
|
-
let(:pub_v6) { %w{1::1 2::2} }
|
1193
|
-
let(:priv_v4) { %w{3.3.3.3 4.4.4.4} }
|
1194
|
-
let(:priv_v6) { %w{3::3 4::4} }
|
1195
|
-
let(:pub) { pub_v4 + pub_v6 }
|
1196
|
-
let(:priv) { priv_v4 + priv_v6 }
|
1197
|
-
|
1198
|
-
context "both public and private IPs" do
|
1199
|
-
context "IPv4 (default)" do
|
1200
|
-
it "returns only the v4 IPs" do
|
1201
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([pub_v4, priv_v4])
|
1202
|
-
end
|
1203
|
-
end
|
1204
|
-
|
1205
|
-
context "IPv6" do
|
1206
|
-
let(:config) { { use_ipv6: true } }
|
1207
|
-
|
1208
|
-
it "returns only the v6 IPs" do
|
1209
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([pub_v6, priv_v6])
|
1210
|
-
end
|
1211
|
-
end
|
1212
|
-
end
|
1213
|
-
|
1214
|
-
context "only public IPs" do
|
1215
|
-
let(:priv) { nil }
|
1216
|
-
|
1217
|
-
context "IPv4 (default)" do
|
1218
|
-
it "returns only the v4 IPs" do
|
1219
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([pub_v4, []])
|
1220
|
-
end
|
1221
|
-
end
|
1222
|
-
|
1223
|
-
context "IPv6" do
|
1224
|
-
let(:config) { { use_ipv6: true } }
|
1225
|
-
|
1226
|
-
it "returns only the v6 IPs" do
|
1227
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([pub_v6, []])
|
1228
|
-
end
|
1229
|
-
end
|
1230
|
-
end
|
1231
|
-
|
1232
|
-
context "only private IPs" do
|
1233
|
-
let(:pub) { nil }
|
1234
|
-
|
1235
|
-
context "IPv4 (default)" do
|
1236
|
-
it "returns only the v4 IPs" do
|
1237
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([[], priv_v4])
|
1238
|
-
end
|
1239
|
-
end
|
1240
|
-
|
1241
|
-
context "IPv6" do
|
1242
|
-
let(:config) { { use_ipv6: true } }
|
1243
|
-
|
1244
|
-
it "returns only the v6 IPs" do
|
1245
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([[], priv_v6])
|
1246
|
-
end
|
1247
|
-
end
|
1248
|
-
end
|
1249
|
-
|
1250
|
-
context "no IPs whatsoever" do
|
1251
|
-
let(:pub) { nil }
|
1252
|
-
let(:priv) { nil }
|
1253
|
-
|
1254
|
-
context "IPv4 (default)" do
|
1255
|
-
it "returns empty lists" do
|
1256
|
-
expect(driver.send(:parse_ips, pub, priv)).to eq([[], []])
|
1257
|
-
end
|
1258
|
-
end
|
1259
|
-
|
1260
|
-
context "IPv6" do
|
1261
|
-
let(:config) { { use_ipv6: true } }
|
1262
|
-
|
1263
|
-
it "returns empty lists" do
|
1264
|
-
expect(driver.send(:parse_ips, nil, nil)).to eq([[], []])
|
1265
|
-
end
|
1266
|
-
end
|
1267
|
-
end
|
1268
|
-
end
|
1269
|
-
|
1270
|
-
describe "#add_ohai_hint" do
|
1271
|
-
let(:state) { { hostname: "host" } }
|
1272
|
-
let(:ssh) do
|
1273
|
-
s = double("ssh")
|
1274
|
-
allow(s).to receive(:run) { |args| args }
|
1275
|
-
s
|
1276
|
-
end
|
1277
|
-
it "opens an SSH session to the server" do
|
1278
|
-
driver.send(:add_ohai_hint, state)
|
1279
|
-
end
|
1280
|
-
|
1281
|
-
it "opens an Winrm session to the server" do
|
1282
|
-
allow(driver).to receive(:bourne_shell?).and_return(false)
|
1283
|
-
allow(driver).to receive(:windows_os?).and_return(true)
|
1284
|
-
driver.send(:add_ohai_hint, state)
|
1285
|
-
end
|
1286
|
-
end
|
1287
|
-
|
1288
|
-
describe "#disable_ssl_validation" do
|
1289
|
-
it "turns off Excon SSL cert validation" do
|
1290
|
-
expect(driver.send(:disable_ssl_validation)).to eq(false)
|
1291
|
-
end
|
1292
|
-
end
|
1293
|
-
|
1294
|
-
describe "#countdown" do
|
1295
|
-
it "counts down to future time with 0 seconds with almost no time" do
|
1296
|
-
current = Time.now
|
1297
|
-
driver.send(:countdown, 0)
|
1298
|
-
after = Time.now
|
1299
|
-
expect(after - current).to be >= 0
|
1300
|
-
expect(after - current).to be < 10
|
1301
|
-
end
|
1302
|
-
|
1303
|
-
it "counts down to future time with 1 seconds with at least 9 seconds" do
|
1304
|
-
current = Time.now
|
1305
|
-
driver.send(:countdown, 1)
|
1306
|
-
after = Time.now
|
1307
|
-
expect(after - current).to be >= 9
|
1308
|
-
end
|
1309
|
-
end
|
1310
|
-
|
1311
|
-
describe "#wait_for_server" do
|
1312
|
-
let(:config) { { server_wait: 0 } }
|
1313
|
-
let(:state) { { hostname: "host" } }
|
1314
|
-
|
1315
|
-
it "waits for connection to be available" do
|
1316
|
-
expect(driver.send(:wait_for_server, state)).to be(nil)
|
1317
|
-
end
|
1318
|
-
|
1319
|
-
it "Fails when calling transport but still destroys the created system" do
|
1320
|
-
allow(instance.transport).to receive(:connection).and_raise(ArgumentError)
|
1321
|
-
expect(driver).to receive(:destroy)
|
1322
|
-
|
1323
|
-
expect { driver.send(:wait_for_server, state) }
|
1324
|
-
.to raise_error(ArgumentError)
|
1325
|
-
end
|
1326
|
-
end
|
1327
|
-
|
1328
|
-
describe "#get_bdm" do
|
1329
|
-
let(:logger) { Logger.new(logged_output) }
|
1330
|
-
let(:config) do
|
1331
|
-
{
|
1332
|
-
openstack_username: "a",
|
1333
|
-
openstack_domain_id: "default",
|
1334
|
-
openstack_api_key: "b",
|
1335
|
-
openstack_auth_url: "http://",
|
1336
|
-
openstack_project_name: "me",
|
1337
|
-
openstack_region: "ORD",
|
1338
|
-
openstack_service_name: "stack",
|
1339
|
-
image_ref: "22",
|
1340
|
-
flavor_ref: "33",
|
1341
|
-
username: "admin",
|
1342
|
-
port: "2222",
|
1343
|
-
server_name: "puppy",
|
1344
|
-
server_name_prefix: "parsnip",
|
1345
|
-
floating_ip_pool: "swimmers",
|
1346
|
-
floating_ip: "11111",
|
1347
|
-
network_ref: "0xCAFFE",
|
1348
|
-
block_device_mapping: {
|
1349
|
-
volume_id: "55",
|
1350
|
-
volume_size: "5",
|
1351
|
-
device_name: "vda",
|
1352
|
-
delete_on_termination: true,
|
1353
|
-
},
|
1354
|
-
}
|
1355
|
-
end
|
1356
|
-
it "returns just the BDM config" do
|
1357
|
-
expect(driver.send(:get_bdm, config)).to eq(config[:block_device_mapping])
|
1358
|
-
end
|
1359
|
-
end
|
1360
|
-
end
|