kitchen-openstack 7.0.1 → 8.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 +477 -81
- data/lib/kitchen/driver/openstack/clouds.rb +124 -23
- data/lib/kitchen/driver/openstack/config.rb +97 -30
- data/lib/kitchen/driver/openstack/helpers.rb +44 -5
- data/lib/kitchen/driver/openstack/networking.rb +127 -32
- data/lib/kitchen/driver/openstack/server_helper.rb +92 -20
- data/lib/kitchen/driver/openstack/volume.rb +121 -25
- data/lib/kitchen/driver/openstack.rb +99 -15
- data/lib/kitchen/driver/openstack_version.rb +7 -1
- metadata +2 -2
|
@@ -34,8 +34,17 @@ require_relative "openstack/volume"
|
|
|
34
34
|
|
|
35
35
|
module Kitchen
|
|
36
36
|
module Driver
|
|
37
|
-
#
|
|
37
|
+
# Test Kitchen driver for OpenStack Nova.
|
|
38
|
+
#
|
|
39
|
+
# Creates and destroys Nova instances, optionally attaching floating IPs,
|
|
40
|
+
# Cinder volumes and specific Neutron networks. Credentials come from
|
|
41
|
+
# kitchen.yml, `OS_*` environment variables, or a standard
|
|
42
|
+
# `clouds.yaml` -- see {Clouds} for the precedence rules.
|
|
38
43
|
class Openstack < Kitchen::Driver::Base
|
|
44
|
+
# Settings Fog requires as Strings. Fog re-coerces anything that looks
|
|
45
|
+
# numeric back to an Integer, so these are stringified on the way in.
|
|
46
|
+
#
|
|
47
|
+
# @return [Array<Symbol>]
|
|
39
48
|
FOG_STRING_SETTINGS = %i{
|
|
40
49
|
openstack_username
|
|
41
50
|
openstack_api_key
|
|
@@ -70,13 +79,6 @@ module Kitchen
|
|
|
70
79
|
default_config :clouds_yaml_path, nil
|
|
71
80
|
default_config :server_name, nil
|
|
72
81
|
|
|
73
|
-
# Merge clouds.yaml values into config so they are visible in
|
|
74
|
-
# `kitchen diagnose` and available to all driver methods.
|
|
75
|
-
def finalize_config!(instance)
|
|
76
|
-
super
|
|
77
|
-
apply_clouds_config
|
|
78
|
-
self
|
|
79
|
-
end
|
|
80
82
|
default_config :server_name_prefix, nil
|
|
81
83
|
default_config :key_name, nil
|
|
82
84
|
default_config :port, "22"
|
|
@@ -103,6 +105,28 @@ module Kitchen
|
|
|
103
105
|
default_config :write_timeout, 60
|
|
104
106
|
default_config :metadata, nil
|
|
105
107
|
|
|
108
|
+
# Merges clouds.yaml and `OS_*` values into the config hash.
|
|
109
|
+
#
|
|
110
|
+
# Done at finalize time rather than lazily so the resolved values show up
|
|
111
|
+
# in `kitchen diagnose` and are available to every driver method.
|
|
112
|
+
#
|
|
113
|
+
# @param instance [Kitchen::Instance] the instance this driver serves
|
|
114
|
+
# @return [self]
|
|
115
|
+
def finalize_config!(instance)
|
|
116
|
+
super
|
|
117
|
+
apply_clouds_config
|
|
118
|
+
self
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Creates a Nova instance and waits until it is reachable.
|
|
122
|
+
#
|
|
123
|
+
# Idempotent: returns immediately if `state` already names a server.
|
|
124
|
+
#
|
|
125
|
+
# @param state [Hash] mutable instance state; gains `:server_id` and
|
|
126
|
+
# `:hostname`
|
|
127
|
+
# @return [void]
|
|
128
|
+
# @raise [Kitchen::ActionFailed] on any Fog or Excon failure
|
|
129
|
+
# @raise [Kitchen::InstanceFailure] if the server builds to ERROR state
|
|
106
130
|
def create(state)
|
|
107
131
|
config_server_name
|
|
108
132
|
if state[:server_id]
|
|
@@ -138,6 +162,14 @@ module Kitchen
|
|
|
138
162
|
raise ActionFailed, e.message
|
|
139
163
|
end
|
|
140
164
|
|
|
165
|
+
# Destroys the Nova instance named by `state`, releasing its floating IP
|
|
166
|
+
# first when this driver allocated one.
|
|
167
|
+
#
|
|
168
|
+
# Safe to call when the server is already gone.
|
|
169
|
+
#
|
|
170
|
+
# @param state [Hash] mutable instance state; loses `:server_id` and
|
|
171
|
+
# `:hostname`
|
|
172
|
+
# @return [void]
|
|
141
173
|
def destroy(state)
|
|
142
174
|
return if state[:server_id].nil?
|
|
143
175
|
|
|
@@ -150,12 +182,7 @@ module Kitchen
|
|
|
150
182
|
pub, priv = get_public_private_ips(server)
|
|
151
183
|
pub, = parse_ips(pub, priv)
|
|
152
184
|
pub_ip = pub[config[:public_ip_order].to_i] || nil
|
|
153
|
-
if pub_ip
|
|
154
|
-
info "Retrieve the ID of floating IP <#{pub_ip}>"
|
|
155
|
-
floating_ip_id = network.list_floating_ips(floating_ip_address: pub_ip).body["floatingips"][0]["id"]
|
|
156
|
-
network.delete_floating_ip(floating_ip_id)
|
|
157
|
-
info "OpenStack Floating IP <#{pub_ip}> released."
|
|
158
|
-
end
|
|
185
|
+
release_floating_ip(pub_ip) if pub_ip
|
|
159
186
|
end
|
|
160
187
|
server.destroy
|
|
161
188
|
end
|
|
@@ -166,6 +193,29 @@ module Kitchen
|
|
|
166
193
|
|
|
167
194
|
private
|
|
168
195
|
|
|
196
|
+
# Releases a floating IP back to its pool.
|
|
197
|
+
#
|
|
198
|
+
# A floating IP that Neutron no longer knows about is not an error worth
|
|
199
|
+
# failing a destroy over, so an unknown address is logged and skipped.
|
|
200
|
+
#
|
|
201
|
+
# @param pub_ip [String] the floating IP to release
|
|
202
|
+
# @return [void]
|
|
203
|
+
def release_floating_ip(pub_ip)
|
|
204
|
+
info "Retrieve the ID of floating IP <#{pub_ip}>"
|
|
205
|
+
net = network
|
|
206
|
+
floating_ips = net.list_floating_ips(floating_ip_address: pub_ip).body["floatingips"]
|
|
207
|
+
if floating_ips.nil? || floating_ips.empty?
|
|
208
|
+
warn "No floating IP found matching <#{pub_ip}>; nothing to release."
|
|
209
|
+
return
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
net.delete_floating_ip(floating_ips[0]["id"])
|
|
213
|
+
info "OpenStack Floating IP <#{pub_ip}> released."
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Builds the settings hash handed to every Fog service constructor.
|
|
217
|
+
#
|
|
218
|
+
# @return [Hash] Fog connection settings
|
|
169
219
|
def openstack_server
|
|
170
220
|
server_def = {
|
|
171
221
|
connection_options: {},
|
|
@@ -176,36 +226,61 @@ module Kitchen
|
|
|
176
226
|
server_def
|
|
177
227
|
end
|
|
178
228
|
|
|
229
|
+
# Settings always sent to Fog, even when nil.
|
|
230
|
+
#
|
|
231
|
+
# @return [Array<Symbol>]
|
|
179
232
|
def required_server_settings
|
|
180
233
|
%i{openstack_username openstack_api_key openstack_auth_url openstack_domain_id}
|
|
181
234
|
end
|
|
182
235
|
|
|
236
|
+
# Every other `openstack_*` setting Fog recognizes, sent only when set.
|
|
237
|
+
#
|
|
238
|
+
# @return [Array<Symbol>]
|
|
183
239
|
def optional_server_settings
|
|
184
240
|
Fog::OpenStack::Compute.recognized.select do |k|
|
|
185
241
|
k.to_s.start_with?("openstack")
|
|
186
242
|
end - required_server_settings
|
|
187
243
|
end
|
|
188
244
|
|
|
245
|
+
# Settings passed through to Excon rather than to Fog itself.
|
|
246
|
+
#
|
|
247
|
+
# `ssl_ca_file` belongs here, not in the Fog settings: Fog does not
|
|
248
|
+
# recognize it, so a CA bundle from `OS_CACERT` or a clouds.yaml
|
|
249
|
+
# `cacert` entry would otherwise be parsed and then silently dropped.
|
|
250
|
+
#
|
|
251
|
+
# @return [Array<Symbol>]
|
|
189
252
|
def connection_options
|
|
190
|
-
%i{read_timeout write_timeout connect_timeout}
|
|
253
|
+
%i{read_timeout write_timeout connect_timeout ssl_ca_file}
|
|
191
254
|
end
|
|
192
255
|
|
|
256
|
+
# @return [Fog::OpenStack::Network] a Neutron connection
|
|
193
257
|
def network
|
|
194
258
|
Fog::OpenStack::Network.new(openstack_server)
|
|
195
259
|
end
|
|
196
260
|
|
|
261
|
+
# @return [Fog::OpenStack::Compute] a Nova connection
|
|
197
262
|
def compute
|
|
198
263
|
Fog::OpenStack::Compute.new(openstack_server)
|
|
199
264
|
end
|
|
200
265
|
|
|
266
|
+
# @return [Kitchen::Driver::Openstack::Volume] a Cinder helper
|
|
201
267
|
def volume
|
|
202
268
|
Volume.new(logger)
|
|
203
269
|
end
|
|
204
270
|
|
|
271
|
+
# Resolves the block device mapping to send to Nova.
|
|
272
|
+
#
|
|
273
|
+
# @param config [Hash] the driver config
|
|
274
|
+
# @return [Hash] a Nova block device mapping
|
|
205
275
|
def get_bdm(config)
|
|
206
276
|
volume.get_bdm(config, openstack_server)
|
|
207
277
|
end
|
|
208
278
|
|
|
279
|
+
# Coerces one setting to the type Fog expects.
|
|
280
|
+
#
|
|
281
|
+
# @param setting [Symbol] the Fog config key
|
|
282
|
+
# @param value [Object] the configured value
|
|
283
|
+
# @return [Object] the coerced value
|
|
209
284
|
def normalize_fog_setting(setting, value)
|
|
210
285
|
return value if value.nil?
|
|
211
286
|
return normalize_identity_api_version(value) if setting == :openstack_identity_api_version
|
|
@@ -214,11 +289,20 @@ module Kitchen
|
|
|
214
289
|
value.to_s
|
|
215
290
|
end
|
|
216
291
|
|
|
292
|
+
# Normalizes the identity API version into a form Fog will not mangle.
|
|
293
|
+
#
|
|
217
294
|
# Fog::Service#coerce_options re-coerces any value where
|
|
218
295
|
# `value.to_s.to_i.to_s == value.to_s` back to an Integer, which
|
|
219
296
|
# then breaks Fog::OpenStack::Auth::Token.build (it calls `=~`
|
|
220
297
|
# on the value). Prefixing with "v" keeps Fog from coercing and
|
|
221
298
|
# still satisfies Token.build's `/(v)*2(\.0)*/i` regex check.
|
|
299
|
+
#
|
|
300
|
+
# @example
|
|
301
|
+
# normalize_identity_api_version(3) #=> "v3"
|
|
302
|
+
# normalize_identity_api_version("2.0") #=> "v2.0"
|
|
303
|
+
#
|
|
304
|
+
# @param value [String, Integer] the configured identity API version
|
|
305
|
+
# @return [String] a version string prefixed with "v"
|
|
222
306
|
def normalize_identity_api_version(value)
|
|
223
307
|
str = value.to_s.strip
|
|
224
308
|
return str if str.empty?
|
|
@@ -23,6 +23,12 @@ module Kitchen
|
|
|
23
23
|
#
|
|
24
24
|
# @author Jonathan Hartman <j@p4nt5.com>
|
|
25
25
|
module Driver
|
|
26
|
-
|
|
26
|
+
# The kitchen-openstack gem version.
|
|
27
|
+
#
|
|
28
|
+
# Read by the gemspec and bumped by Release Please, so it must stay a
|
|
29
|
+
# plain string literal on a single line.
|
|
30
|
+
#
|
|
31
|
+
# @return [String]
|
|
32
|
+
OPENSTACK_VERSION = "8.0.0"
|
|
27
33
|
end
|
|
28
34
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-openstack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 8.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonathan Hartman
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-
|
|
12
|
+
date: 2026-08-23 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: test-kitchen
|