kitchen-vra 3.3.2 → 3.3.4
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/.github/workflows/publish.yml +23 -8
- data/.gitignore +3 -1
- data/.markdownlint.yaml +2 -1
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +7 -1
- data/.yamllint +6 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +98 -48
- data/CONTRIBUTING.md +84 -0
- data/Gemfile +20 -1
- data/README.md +260 -31
- data/Rakefile +20 -2
- data/kitchen-vra.gemspec +3 -9
- data/lib/kitchen/driver/vra.rb +183 -32
- data/lib/kitchen/driver/vra_version.rb +4 -1
- data/release-please-config.json +12 -0
- data/renovate.json +8 -0
- data/spec/vra_spec.rb +98 -1
- metadata +14 -83
- data/.github/dependabot.yml +0 -8
- data/.github/workflows/please-release.yml +0 -16
- data/.mdlrc +0 -1
data/lib/kitchen/driver/vra.rb
CHANGED
|
@@ -22,16 +22,42 @@ require "kitchen"
|
|
|
22
22
|
require "highline/import"
|
|
23
23
|
require "openssl" unless defined?(OpenSSL)
|
|
24
24
|
require "base64" unless defined?(Base64)
|
|
25
|
-
require "digest
|
|
25
|
+
require "digest" unless defined?(Digest)
|
|
26
|
+
require "fileutils" unless defined?(FileUtils)
|
|
26
27
|
require "vra"
|
|
27
28
|
require_relative "vra_version"
|
|
28
29
|
|
|
29
30
|
module Kitchen
|
|
31
|
+
# Test Kitchen's driver plugins.
|
|
30
32
|
module Driver
|
|
33
|
+
# Test Kitchen driver for VMware vRealize Automation (vRA) 8.x.
|
|
34
|
+
#
|
|
35
|
+
# Unlike a cloud driver that creates a machine directly, this driver
|
|
36
|
+
# submits a request against a vRA catalog item and waits for vRA's own
|
|
37
|
+
# automation to build a deployment. The blueprint behind that catalog item
|
|
38
|
+
# decides what gets built; this driver only supplies the image, flavor,
|
|
39
|
+
# and project, then waits for a single VM to come back.
|
|
40
|
+
#
|
|
41
|
+
# The blueprint must return exactly one VM. A blueprint returning several,
|
|
42
|
+
# or none, fails the +create+ rather than guessing which one to test.
|
|
43
|
+
#
|
|
44
|
+
# @see https://www.vmware.com/products/vrealize-automation.html vRealize Automation
|
|
31
45
|
class Vra < Kitchen::Driver::Base # rubocop:disable Metrics/ClassLength
|
|
32
46
|
kitchen_driver_api_version 2
|
|
33
47
|
plugin_version Kitchen::Driver::VRA_VERSION
|
|
34
48
|
|
|
49
|
+
# Location of the credential cache, relative to the working directory.
|
|
50
|
+
CREDENTIALS_CACHE_FILE = ".kitchen/cached_vra"
|
|
51
|
+
|
|
52
|
+
# Cipher used for the credential cache. GCM is authenticated, so a cache
|
|
53
|
+
# written for a different +base_url+, or one that has been altered on
|
|
54
|
+
# disk, fails to decrypt rather than yielding garbage credentials.
|
|
55
|
+
CREDENTIALS_CIPHER = "aes-256-gcm"
|
|
56
|
+
|
|
57
|
+
# Marker for the cache file layout, so a later format change can reject
|
|
58
|
+
# old files instead of misreading them.
|
|
59
|
+
CREDENTIALS_CACHE_VERSION = "v1"
|
|
60
|
+
|
|
35
61
|
default_config :username, nil
|
|
36
62
|
default_config :password, nil
|
|
37
63
|
required_config :base_url
|
|
@@ -68,10 +94,20 @@ module Kitchen
|
|
|
68
94
|
In vRA 8.x, the 'tenant' configuration is no longer relevant for authentication.
|
|
69
95
|
Please use the 'domain' configuration in its place.".dup)
|
|
70
96
|
|
|
97
|
+
# @return [String] the driver's display name in `kitchen list`
|
|
71
98
|
def name
|
|
72
99
|
"vRA"
|
|
73
100
|
end
|
|
74
101
|
|
|
102
|
+
# Resolves the vRA username and password, prompting if necessary.
|
|
103
|
+
#
|
|
104
|
+
# Sources are tried in order: explicit config, then the +VRA_USER_NAME+
|
|
105
|
+
# and +VRA_USER_PASSWORD+ environment variables, then the credential
|
|
106
|
+
# cache, then an interactive prompt.
|
|
107
|
+
#
|
|
108
|
+
# @param force_change [Boolean] prompt even if credentials already
|
|
109
|
+
# resolved, used to re-ask after an authentication failure
|
|
110
|
+
# @return [void]
|
|
75
111
|
def check_config(force_change = false)
|
|
76
112
|
config[:username] = config[:username] || ENV["VRA_USER_NAME"]
|
|
77
113
|
config[:password] = config[:password] || ENV["VRA_USER_PASSWORD"]
|
|
@@ -82,43 +118,104 @@ module Kitchen
|
|
|
82
118
|
c_save if config[:cache_credentials]
|
|
83
119
|
end
|
|
84
120
|
|
|
121
|
+
# Writes the resolved credentials to {CREDENTIALS_CACHE_FILE}.
|
|
122
|
+
#
|
|
123
|
+
# The file is obfuscated rather than secured: the key is derived from
|
|
124
|
+
# +base_url+, which is not a secret, so anyone holding both the file and
|
|
125
|
+
# the kitchen config can recover the credentials. It keeps passwords out
|
|
126
|
+
# of plain sight on disk; it is not a substitute for a secret store.
|
|
127
|
+
#
|
|
128
|
+
# @return [void]
|
|
85
129
|
def c_save
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
file.write(output)
|
|
98
|
-
file.close
|
|
99
|
-
rescue
|
|
100
|
-
puts "Unable to save credentials"
|
|
130
|
+
FileUtils.mkdir_p(File.dirname(CREDENTIALS_CACHE_FILE))
|
|
131
|
+
fields = [config[:username], config[:password]].flat_map { |value| encrypt_credential(value) }
|
|
132
|
+
|
|
133
|
+
File.open(CREDENTIALS_CACHE_FILE, File::WRONLY | File::CREAT | File::TRUNC, 0o600) do |file|
|
|
134
|
+
file.write(([CREDENTIALS_CACHE_VERSION] + fields).join(":"))
|
|
135
|
+
end
|
|
136
|
+
# The mode above only applies when the file is created, so narrow the
|
|
137
|
+
# permissions of a cache left behind by an earlier run as well.
|
|
138
|
+
File.chmod(0o600, CREDENTIALS_CACHE_FILE)
|
|
139
|
+
rescue => e
|
|
140
|
+
warn("Unable to save credentials to #{CREDENTIALS_CACHE_FILE}: #{e.message}")
|
|
101
141
|
end
|
|
102
142
|
|
|
143
|
+
# Reads credentials back from {CREDENTIALS_CACHE_FILE}.
|
|
144
|
+
#
|
|
145
|
+
# A cache that cannot be decrypted -- a different +base_url+, a truncated
|
|
146
|
+
# or edited file, an older layout -- is reported and ignored, leaving the
|
|
147
|
+
# credentials unset so the caller falls through to prompting.
|
|
148
|
+
#
|
|
149
|
+
# @return [void]
|
|
103
150
|
def c_load
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
151
|
+
return unless File.exist?(CREDENTIALS_CACHE_FILE)
|
|
152
|
+
|
|
153
|
+
version, *fields = File.read(CREDENTIALS_CACHE_FILE).strip.split(":")
|
|
154
|
+
raise "unrecognized cache format" unless version == CREDENTIALS_CACHE_VERSION && fields.length == 6
|
|
155
|
+
|
|
156
|
+
# Decrypt both before assigning either, so a partially readable cache
|
|
157
|
+
# cannot leave half the credentials set.
|
|
158
|
+
username = decrypt_credential(*fields[0, 3])
|
|
159
|
+
password = decrypt_credential(*fields[3, 3])
|
|
160
|
+
|
|
161
|
+
config[:username] = username
|
|
162
|
+
config[:password] = password
|
|
163
|
+
rescue => e
|
|
164
|
+
warn("Failed to load cached credentials from #{CREDENTIALS_CACHE_FILE}: #{e.message}")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Encrypts one credential for the cache file.
|
|
168
|
+
#
|
|
169
|
+
# @param value [String] the credential to encrypt
|
|
170
|
+
# @return [Array<String>] Base64-encoded IV, authentication tag, and
|
|
171
|
+
# ciphertext, in that order
|
|
172
|
+
def encrypt_credential(value)
|
|
173
|
+
cipher = OpenSSL::Cipher.new(CREDENTIALS_CIPHER)
|
|
174
|
+
cipher.encrypt
|
|
175
|
+
cipher.key = credentials_key
|
|
176
|
+
iv = cipher.random_iv
|
|
177
|
+
encrypted = cipher.update(value.to_s) + cipher.final
|
|
178
|
+
|
|
179
|
+
[iv, cipher.auth_tag, encrypted].map { |part| Base64.strict_encode64(part) }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Decrypts one credential from the cache file.
|
|
183
|
+
#
|
|
184
|
+
# @param iv [String] Base64-encoded initialization vector
|
|
185
|
+
# @param auth_tag [String] Base64-encoded GCM authentication tag
|
|
186
|
+
# @param encrypted [String] Base64-encoded ciphertext
|
|
187
|
+
# @return [String] the decrypted credential
|
|
188
|
+
# @raise [OpenSSL::Cipher::CipherError] if the key or tag does not match
|
|
189
|
+
def decrypt_credential(iv, auth_tag, encrypted)
|
|
190
|
+
cipher = OpenSSL::Cipher.new(CREDENTIALS_CIPHER)
|
|
191
|
+
cipher.decrypt
|
|
192
|
+
cipher.key = credentials_key
|
|
193
|
+
cipher.iv = Base64.strict_decode64(iv)
|
|
194
|
+
cipher.auth_tag = Base64.strict_decode64(auth_tag)
|
|
195
|
+
|
|
196
|
+
cipher.update(Base64.strict_decode64(encrypted)) + cipher.final
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Derives the cache key from +base_url+.
|
|
200
|
+
#
|
|
201
|
+
# SHA-256 is used for its digest length: {CREDENTIALS_CIPHER} requires a
|
|
202
|
+
# 32-byte key, which +Digest::SHA256.digest+ returns exactly.
|
|
203
|
+
#
|
|
204
|
+
# @return [String] a 32-byte key
|
|
205
|
+
def credentials_key
|
|
206
|
+
Digest::SHA256.digest(config[:base_url].to_s)
|
|
120
207
|
end
|
|
121
208
|
|
|
209
|
+
# Requests a deployment from vRA and waits until it can be logged into.
|
|
210
|
+
#
|
|
211
|
+
# Returns immediately if the state already names a deployment, so a
|
|
212
|
+
# re-run does not build a second one.
|
|
213
|
+
#
|
|
214
|
+
# @param state [Hash] mutable instance state; gains +deployment_id+,
|
|
215
|
+
# +hostname+, and +ssh_key+
|
|
216
|
+
# @return [void]
|
|
217
|
+
# @raise [RuntimeError] if the vRA request fails or does not yield
|
|
218
|
+
# exactly one VM
|
|
122
219
|
def create(state)
|
|
123
220
|
return if state[:deployment_id]
|
|
124
221
|
|
|
@@ -131,6 +228,15 @@ module Kitchen
|
|
|
131
228
|
info("Server #{server.deployment_id} (#{server.name}) ready.")
|
|
132
229
|
end
|
|
133
230
|
|
|
231
|
+
# Works out the address Test Kitchen should connect to.
|
|
232
|
+
#
|
|
233
|
+
# With +use_dns+ set, the server's name is used, optionally suffixed with
|
|
234
|
+
# +dns_suffix+. Otherwise the IP address is preferred, falling back to
|
|
235
|
+
# the name with a warning when vRA reports no address.
|
|
236
|
+
#
|
|
237
|
+
# @param server [Vra::Resource] the VM vRA built
|
|
238
|
+
# @return [String] a hostname or IP address
|
|
239
|
+
# @raise [RuntimeError] if +use_dns+ is set but vRA returned no name
|
|
134
240
|
def hostname_for(server)
|
|
135
241
|
if config[:use_dns]
|
|
136
242
|
raise "No server name returned for the vRA request" if server.name.nil?
|
|
@@ -147,6 +253,11 @@ module Kitchen
|
|
|
147
253
|
end
|
|
148
254
|
end
|
|
149
255
|
|
|
256
|
+
# Submits the catalog request and waits for vRA to finish building it.
|
|
257
|
+
#
|
|
258
|
+
# @return [Vra::Resource] the single VM the blueprint produced
|
|
259
|
+
# @raise [RuntimeError] if the request failed, or produced zero or more
|
|
260
|
+
# than one VM
|
|
150
261
|
def request_server
|
|
151
262
|
info("Building vRA catalog request...")
|
|
152
263
|
|
|
@@ -167,6 +278,16 @@ module Kitchen
|
|
|
167
278
|
servers.first
|
|
168
279
|
end
|
|
169
280
|
|
|
281
|
+
# Waits for the transport to accept a connection, retrying on failure.
|
|
282
|
+
#
|
|
283
|
+
# Backs off in five-second steps up to thirty seconds between attempts.
|
|
284
|
+
# Once +server_ready_retries+ is exceeded the deployment is destroyed
|
|
285
|
+
# before the error is re-raised, so a machine that never comes up is not
|
|
286
|
+
# left running and billable.
|
|
287
|
+
#
|
|
288
|
+
# @param state [Hash] instance state describing how to connect
|
|
289
|
+
# @param server [Vra::Resource] the VM being waited on
|
|
290
|
+
# @return [void]
|
|
170
291
|
def wait_for_server(state, server)
|
|
171
292
|
info("Server #{server.id} (#{server.name}) created. Waiting until ready...")
|
|
172
293
|
|
|
@@ -193,6 +314,14 @@ module Kitchen
|
|
|
193
314
|
end
|
|
194
315
|
end
|
|
195
316
|
|
|
317
|
+
# Destroys the vRA deployment, if one exists.
|
|
318
|
+
#
|
|
319
|
+
# A deployment that vRA no longer knows about, or that offers no destroy
|
|
320
|
+
# action, is treated as already gone rather than an error. The cached
|
|
321
|
+
# credentials file is removed afterwards.
|
|
322
|
+
#
|
|
323
|
+
# @param state [Hash] instance state naming the deployment
|
|
324
|
+
# @return [void]
|
|
196
325
|
def destroy(state)
|
|
197
326
|
return if state[:deployment_id].nil?
|
|
198
327
|
|
|
@@ -217,6 +346,14 @@ module Kitchen
|
|
|
217
346
|
info("Removed cached file")
|
|
218
347
|
end
|
|
219
348
|
|
|
349
|
+
# Builds the vRA catalog request for the configured blueprint.
|
|
350
|
+
#
|
|
351
|
+
# When +catalog_name+ is given it is resolved to a catalog ID first.
|
|
352
|
+
# A deployment name is only sent when +unique_name+ is false; otherwise
|
|
353
|
+
# vRA is left to name the deployment after its request ID.
|
|
354
|
+
#
|
|
355
|
+
# @return [Vra::CatalogRequest] a request ready to submit
|
|
356
|
+
# @raise [Kitchen::InstanceFailure] if no catalog could be resolved
|
|
220
357
|
def catalog_request # rubocop:disable Metrics/MethodLength
|
|
221
358
|
unless config[:catalog_name].nil?
|
|
222
359
|
info("Fetching Catalog ID by Catalog Name")
|
|
@@ -251,6 +388,12 @@ module Kitchen
|
|
|
251
388
|
catalog_request
|
|
252
389
|
end
|
|
253
390
|
|
|
391
|
+
# The vRA API client, built from the resolved credentials.
|
|
392
|
+
#
|
|
393
|
+
# On any failure the credentials are re-prompted, on the assumption that
|
|
394
|
+
# what failed was authentication.
|
|
395
|
+
#
|
|
396
|
+
# @return [Vra::Client]
|
|
254
397
|
def vra_client
|
|
255
398
|
check_config config[:cache_credentials]
|
|
256
399
|
@client ||= ::Vra::Client.new(
|
|
@@ -264,6 +407,14 @@ module Kitchen
|
|
|
264
407
|
check_config true
|
|
265
408
|
end
|
|
266
409
|
|
|
410
|
+
# Polls a vRA request until it completes or times out.
|
|
411
|
+
#
|
|
412
|
+
# Polls every +request_refresh_rate+ seconds, logging each change of
|
|
413
|
+
# status, and gives up after +request_timeout+ seconds.
|
|
414
|
+
#
|
|
415
|
+
# @param request [Vra::Request] the request to poll
|
|
416
|
+
# @return [void]
|
|
417
|
+
# @raise [Timeout::Error] if the request does not complete in time
|
|
267
418
|
def wait_for_request(request)
|
|
268
419
|
# config = check_config config
|
|
269
420
|
|
|
@@ -18,8 +18,11 @@
|
|
|
18
18
|
# limitations under the License.
|
|
19
19
|
#
|
|
20
20
|
|
|
21
|
+
# Test Kitchen's top-level namespace.
|
|
21
22
|
module Kitchen
|
|
23
|
+
# Test Kitchen's driver plugins.
|
|
22
24
|
module Driver
|
|
23
|
-
|
|
25
|
+
# The version of the kitchen-vra gem.
|
|
26
|
+
VRA_VERSION = "3.3.4"
|
|
24
27
|
end
|
|
25
28
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packages": {
|
|
3
|
+
".": {
|
|
4
|
+
"package-name": "kitchen-vra",
|
|
5
|
+
"changelog-path": "CHANGELOG.md",
|
|
6
|
+
"release-type": "ruby",
|
|
7
|
+
"include-component-in-tag": false,
|
|
8
|
+
"version-file": "lib/kitchen/driver/vra_version.rb"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
|
12
|
+
}
|
data/renovate.json
ADDED
data/spec/vra_spec.rb
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
#
|
|
20
20
|
|
|
21
21
|
require "spec_helper"
|
|
22
|
+
require "tmpdir"
|
|
23
|
+
require "fileutils"
|
|
22
24
|
require "kitchen/driver/vra"
|
|
23
25
|
require "kitchen/provisioner/dummy"
|
|
24
26
|
require "kitchen/transport/dummy"
|
|
@@ -447,7 +449,7 @@ describe Kitchen::Driver::Vra do
|
|
|
447
449
|
}
|
|
448
450
|
end
|
|
449
451
|
|
|
450
|
-
it "sets extra
|
|
452
|
+
it "sets extra parameters" do
|
|
451
453
|
expect(catalog_request).to receive(:set_parameters).with("key1", { type: "string", value: "value1" })
|
|
452
454
|
expect(catalog_request).to receive(:set_parameters).with("key2", { type: "integer", value: 123 })
|
|
453
455
|
driver.catalog_request
|
|
@@ -510,4 +512,99 @@ describe Kitchen::Driver::Vra do
|
|
|
510
512
|
end
|
|
511
513
|
end
|
|
512
514
|
end
|
|
515
|
+
|
|
516
|
+
describe "credential caching" do
|
|
517
|
+
let(:cache_dir) { Dir.mktmpdir("kitchen-vra-spec") }
|
|
518
|
+
let(:cache_file) { File.join(cache_dir, ".kitchen", "cached_vra") }
|
|
519
|
+
|
|
520
|
+
# c_save/c_load address the cache by a path relative to the working
|
|
521
|
+
# directory, so each example runs inside a throwaway directory.
|
|
522
|
+
around do |example|
|
|
523
|
+
Dir.chdir(cache_dir) { example.run }
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
after { FileUtils.remove_entry(cache_dir) }
|
|
527
|
+
|
|
528
|
+
describe "#c_save" do
|
|
529
|
+
it "creates the cache file" do
|
|
530
|
+
driver.c_save
|
|
531
|
+
expect(File.exist?(cache_file)).to be true
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
it "creates the .kitchen directory when it does not exist" do
|
|
535
|
+
expect { driver.c_save }.to change { Dir.exist?(File.join(cache_dir, ".kitchen")) }.from(false).to(true)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
it "writes the file readable only by its owner" do
|
|
539
|
+
driver.c_save
|
|
540
|
+
expect(File.stat(cache_file).mode & 0o777).to eq(0o600)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
it "does not write the password in the clear" do
|
|
544
|
+
driver.c_save
|
|
545
|
+
expect(File.read(cache_file)).not_to include("mypassword")
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
describe "#c_load" do
|
|
550
|
+
it "restores credentials written by #c_save" do
|
|
551
|
+
driver.c_save
|
|
552
|
+
|
|
553
|
+
reader = Kitchen::Driver::Vra.new(config.reject { |k, _v| %i{username password}.include?(k) })
|
|
554
|
+
allow(reader).to receive(:instance).and_return(instance)
|
|
555
|
+
reader.c_load
|
|
556
|
+
|
|
557
|
+
expect(reader[:username]).to eq("myuser")
|
|
558
|
+
expect(reader[:password]).to eq("mypassword")
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
it "does nothing when no cache file exists" do
|
|
562
|
+
driver.c_load
|
|
563
|
+
expect(driver[:username]).to eq("myuser")
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
it "refuses a cache written against a different base_url" do
|
|
567
|
+
driver.c_save
|
|
568
|
+
|
|
569
|
+
other = Kitchen::Driver::Vra.new(config.merge(base_url: "https://other.corp.local")
|
|
570
|
+
.reject { |k, _v| %i{username password}.include?(k) })
|
|
571
|
+
allow(other).to receive(:instance).and_return(instance)
|
|
572
|
+
expect(other).to receive(:warn).with(/Failed to load cached credentials/)
|
|
573
|
+
other.c_load
|
|
574
|
+
|
|
575
|
+
expect(other[:username]).to be_nil
|
|
576
|
+
expect(other[:password]).to be_nil
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
it "refuses a corrupted cache rather than returning garbage" do
|
|
580
|
+
driver.c_save
|
|
581
|
+
File.write(cache_file, File.read(cache_file).succ)
|
|
582
|
+
|
|
583
|
+
loader = Kitchen::Driver::Vra.new(config.reject { |k, _v| %i{username password}.include?(k) })
|
|
584
|
+
allow(loader).to receive(:instance).and_return(instance)
|
|
585
|
+
expect(loader).to receive(:warn).with(/Failed to load cached credentials/)
|
|
586
|
+
loader.c_load
|
|
587
|
+
|
|
588
|
+
expect(loader[:username]).to be_nil
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
describe "#check_config" do
|
|
593
|
+
it "uses the cache instead of prompting" do
|
|
594
|
+
driver.c_save
|
|
595
|
+
|
|
596
|
+
reader = Kitchen::Driver::Vra.new(config.reject { |k, _v| %i{username password}.include?(k) })
|
|
597
|
+
allow(reader).to receive(:instance).and_return(instance)
|
|
598
|
+
allow(ENV).to receive(:[]).and_call_original
|
|
599
|
+
allow(ENV).to receive(:[]).with("VRA_USER_NAME").and_return(nil)
|
|
600
|
+
allow(ENV).to receive(:[]).with("VRA_USER_PASSWORD").and_return(nil)
|
|
601
|
+
expect(reader).not_to receive(:ask)
|
|
602
|
+
|
|
603
|
+
reader.check_config
|
|
604
|
+
|
|
605
|
+
expect(reader[:username]).to eq("myuser")
|
|
606
|
+
expect(reader[:password]).to eq("mypassword")
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
end
|
|
513
610
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-vra
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.3.
|
|
4
|
+
version: 3.3.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- Chef
|
|
7
|
+
- Chef Community Tools Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: test-kitchen
|
|
@@ -87,7 +87,7 @@ dependencies:
|
|
|
87
87
|
version: 2.2.3
|
|
88
88
|
- - "<"
|
|
89
89
|
- !ruby/object:Gem::Version
|
|
90
|
-
version:
|
|
90
|
+
version: 3.1.0
|
|
91
91
|
type: :runtime
|
|
92
92
|
prerelease: false
|
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -97,77 +97,7 @@ dependencies:
|
|
|
97
97
|
version: 2.2.3
|
|
98
98
|
- - "<"
|
|
99
99
|
- !ruby/object:Gem::Version
|
|
100
|
-
version:
|
|
101
|
-
- !ruby/object:Gem::Dependency
|
|
102
|
-
name: rake
|
|
103
|
-
requirement: !ruby/object:Gem::Requirement
|
|
104
|
-
requirements:
|
|
105
|
-
- - "~>"
|
|
106
|
-
- !ruby/object:Gem::Version
|
|
107
|
-
version: '13.0'
|
|
108
|
-
type: :development
|
|
109
|
-
prerelease: false
|
|
110
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
111
|
-
requirements:
|
|
112
|
-
- - "~>"
|
|
113
|
-
- !ruby/object:Gem::Version
|
|
114
|
-
version: '13.0'
|
|
115
|
-
- !ruby/object:Gem::Dependency
|
|
116
|
-
name: rspec
|
|
117
|
-
requirement: !ruby/object:Gem::Requirement
|
|
118
|
-
requirements:
|
|
119
|
-
- - "~>"
|
|
120
|
-
- !ruby/object:Gem::Version
|
|
121
|
-
version: '3.2'
|
|
122
|
-
type: :development
|
|
123
|
-
prerelease: false
|
|
124
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
125
|
-
requirements:
|
|
126
|
-
- - "~>"
|
|
127
|
-
- !ruby/object:Gem::Version
|
|
128
|
-
version: '3.2'
|
|
129
|
-
- !ruby/object:Gem::Dependency
|
|
130
|
-
name: simplecov
|
|
131
|
-
requirement: !ruby/object:Gem::Requirement
|
|
132
|
-
requirements:
|
|
133
|
-
- - "~>"
|
|
134
|
-
- !ruby/object:Gem::Version
|
|
135
|
-
version: '0.10'
|
|
136
|
-
type: :development
|
|
137
|
-
prerelease: false
|
|
138
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
139
|
-
requirements:
|
|
140
|
-
- - "~>"
|
|
141
|
-
- !ruby/object:Gem::Version
|
|
142
|
-
version: '0.10'
|
|
143
|
-
- !ruby/object:Gem::Dependency
|
|
144
|
-
name: webmock
|
|
145
|
-
requirement: !ruby/object:Gem::Requirement
|
|
146
|
-
requirements:
|
|
147
|
-
- - "~>"
|
|
148
|
-
- !ruby/object:Gem::Version
|
|
149
|
-
version: '3.14'
|
|
150
|
-
type: :development
|
|
151
|
-
prerelease: false
|
|
152
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
153
|
-
requirements:
|
|
154
|
-
- - "~>"
|
|
155
|
-
- !ruby/object:Gem::Version
|
|
156
|
-
version: '3.14'
|
|
157
|
-
- !ruby/object:Gem::Dependency
|
|
158
|
-
name: chefstyle
|
|
159
|
-
requirement: !ruby/object:Gem::Requirement
|
|
160
|
-
requirements:
|
|
161
|
-
- - "~>"
|
|
162
|
-
- !ruby/object:Gem::Version
|
|
163
|
-
version: 2.2.1
|
|
164
|
-
type: :development
|
|
165
|
-
prerelease: false
|
|
166
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
167
|
-
requirements:
|
|
168
|
-
- - "~>"
|
|
169
|
-
- !ruby/object:Gem::Version
|
|
170
|
-
version: 2.2.1
|
|
100
|
+
version: 3.1.0
|
|
171
101
|
description: A Test Kitchen driver for VMware vRealize Automation (vRA)
|
|
172
102
|
email:
|
|
173
103
|
- oss@chef.io
|
|
@@ -176,15 +106,16 @@ extensions: []
|
|
|
176
106
|
extra_rdoc_files: []
|
|
177
107
|
files:
|
|
178
108
|
- ".github/CODEOWNERS"
|
|
179
|
-
- ".github/dependabot.yml"
|
|
180
109
|
- ".github/workflows/linters.yml"
|
|
181
|
-
- ".github/workflows/please-release.yml"
|
|
182
110
|
- ".github/workflows/publish.yml"
|
|
183
111
|
- ".gitignore"
|
|
184
112
|
- ".markdownlint.yaml"
|
|
185
|
-
- ".
|
|
113
|
+
- ".release-please-manifest.json"
|
|
186
114
|
- ".rubocop.yml"
|
|
115
|
+
- ".yamllint"
|
|
116
|
+
- ".yardopts"
|
|
187
117
|
- CHANGELOG.md
|
|
118
|
+
- CONTRIBUTING.md
|
|
188
119
|
- Gemfile
|
|
189
120
|
- LICENSE.txt
|
|
190
121
|
- README.md
|
|
@@ -192,6 +123,8 @@ files:
|
|
|
192
123
|
- kitchen-vra.gemspec
|
|
193
124
|
- lib/kitchen/driver/vra.rb
|
|
194
125
|
- lib/kitchen/driver/vra_version.rb
|
|
126
|
+
- release-please-config.json
|
|
127
|
+
- renovate.json
|
|
195
128
|
- spec/spec_helper.rb
|
|
196
129
|
- spec/vra_spec.rb
|
|
197
130
|
homepage: https://github.com/test-kitchen/kitchen-vra
|
|
@@ -206,17 +139,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
206
139
|
requirements:
|
|
207
140
|
- - ">="
|
|
208
141
|
- !ruby/object:Gem::Version
|
|
209
|
-
version: '
|
|
142
|
+
version: '3.1'
|
|
210
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
144
|
requirements:
|
|
212
145
|
- - ">="
|
|
213
146
|
- !ruby/object:Gem::Version
|
|
214
147
|
version: '0'
|
|
215
148
|
requirements: []
|
|
216
|
-
rubygems_version: 3.
|
|
149
|
+
rubygems_version: 3.5.9
|
|
217
150
|
signing_key:
|
|
218
151
|
specification_version: 4
|
|
219
152
|
summary: A Test Kitchen driver for VMware vRealize Automation (vRA)
|
|
220
|
-
test_files:
|
|
221
|
-
- spec/spec_helper.rb
|
|
222
|
-
- spec/vra_spec.rb
|
|
153
|
+
test_files: []
|
data/.github/dependabot.yml
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
'on':
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- main
|
|
6
|
-
|
|
7
|
-
name: release-please
|
|
8
|
-
jobs:
|
|
9
|
-
release-please:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: google-github-actions/release-please-action@v3
|
|
13
|
-
with:
|
|
14
|
-
release-type: ruby
|
|
15
|
-
package-name: kitchen-vra
|
|
16
|
-
version-file: lib/kitchen/driver/vra_version.rb
|
data/.mdlrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
rules "~MD036", "~MD013", "~MD024", "~MD029"
|