kitchen-vcenter 2.6.0 → 2.7.6
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/lib/kitchen-vcenter/version.rb +1 -1
- data/lib/kitchen/driver/vcenter.rb +26 -9
- data/lib/support/clone_vm.rb +124 -11
- metadata +3 -45
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 336491e73efecaf915ea3d66abee8ec788a918b5f4f9a6b89a9a186622f1fbc4
|
|
4
|
+
data.tar.gz: 1c90b4a62e44c40837955a48afde23509c0afccbae563430fc6bfdc3ff7caae0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bff63dd4a20821ce5ec1f8a2032ceae2962b4d26345810c23ebf44dc5548afc85b642342f617f54d8be79b8075b815f65c20df48070b718897216102cdeab2fc
|
|
7
|
+
data.tar.gz: 8384025e3a26ea8a33122f770aecb961a608f96deab7e349d4501676b1ce8628fc4035b65f0428be363fb31d845c677644729f95382de9d017be03d2e15650f6
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
require "kitchen"
|
|
19
19
|
require "vsphere-automation-cis"
|
|
20
20
|
require "vsphere-automation-vcenter"
|
|
21
|
-
|
|
21
|
+
require_relative "../../kitchen-vcenter/version"
|
|
22
|
+
require_relative "../../support/clone_vm"
|
|
22
23
|
require "securerandom"
|
|
23
24
|
require "uri"
|
|
24
25
|
|
|
@@ -50,6 +51,7 @@ module Kitchen
|
|
|
50
51
|
default_config :vm_wait_interval, 2.0
|
|
51
52
|
default_config :vm_rollback, false
|
|
52
53
|
default_config :customize, nil
|
|
54
|
+
default_config :guest_customization, nil
|
|
53
55
|
default_config :interface, nil
|
|
54
56
|
default_config :active_discovery, false
|
|
55
57
|
default_config :active_discovery_command, nil
|
|
@@ -57,6 +59,7 @@ module Kitchen
|
|
|
57
59
|
default_config :vm_username, "vagrant"
|
|
58
60
|
default_config :vm_password, "vagrant"
|
|
59
61
|
default_config :vm_win_network, "Ethernet0"
|
|
62
|
+
default_config :transform_ip, nil
|
|
60
63
|
|
|
61
64
|
default_config :benchmark, false
|
|
62
65
|
default_config :benchmark_file, "kitchen-vcenter.csv"
|
|
@@ -82,6 +85,8 @@ module Kitchen
|
|
|
82
85
|
#
|
|
83
86
|
# @param [Object] state is the state of the vm
|
|
84
87
|
def create(state)
|
|
88
|
+
debug format("Starting kitchen-vcenter %s", ::KitchenVcenter::VERSION)
|
|
89
|
+
|
|
85
90
|
save_and_validate_parameters
|
|
86
91
|
connect
|
|
87
92
|
|
|
@@ -112,10 +117,13 @@ module Kitchen
|
|
|
112
117
|
end
|
|
113
118
|
|
|
114
119
|
# Check that the datacenter exists
|
|
115
|
-
|
|
120
|
+
dc_folder = File.dirname(config[:datacenter])
|
|
121
|
+
dc_folder = nil if dc_folder == "."
|
|
122
|
+
dc_name = File.basename(config[:datacenter])
|
|
123
|
+
datacenter_exists?(dc_folder, dc_name)
|
|
116
124
|
|
|
117
125
|
# Get datacenter and cluster information
|
|
118
|
-
datacenter = get_datacenter(
|
|
126
|
+
datacenter = get_datacenter(dc_folder, dc_name)
|
|
119
127
|
cluster_id = get_cluster_id(config[:cluster])
|
|
120
128
|
|
|
121
129
|
# Using the clone class, create a machine for TK
|
|
@@ -152,12 +160,14 @@ module Kitchen
|
|
|
152
160
|
wait_timeout: config[:vm_wait_timeout],
|
|
153
161
|
wait_interval: config[:vm_wait_interval],
|
|
154
162
|
customize: config[:customize],
|
|
163
|
+
guest_customization: config[:guest_customization],
|
|
155
164
|
active_discovery: config[:active_discovery],
|
|
156
165
|
active_discovery_command: config[:active_discovery_command],
|
|
157
166
|
vm_os: config[:vm_os],
|
|
158
167
|
vm_username: config[:vm_username],
|
|
159
168
|
vm_password: config[:vm_password],
|
|
160
169
|
vm_win_network: config[:vm_win_network],
|
|
170
|
+
transform_ip: config[:transform_ip],
|
|
161
171
|
benchmark: config[:benchmark],
|
|
162
172
|
benchmark_file: config[:benchmark_file],
|
|
163
173
|
}
|
|
@@ -283,10 +293,13 @@ module Kitchen
|
|
|
283
293
|
|
|
284
294
|
# Sees in the datacenter exists or not
|
|
285
295
|
#
|
|
296
|
+
# @param [folder] folder is the name of the folder in which the Datacenter is stored in inventory, possibly nil
|
|
286
297
|
# @param [name] name is the name of the datacenter
|
|
287
|
-
def datacenter_exists?(name)
|
|
298
|
+
def datacenter_exists?(folder, name)
|
|
288
299
|
dc_api = VSphereAutomation::VCenter::DatacenterApi.new(api_client)
|
|
289
|
-
|
|
300
|
+
opts = { filter_names: name }
|
|
301
|
+
opts[:filter_folders] = get_folder(folder, "DATACENTER") if folder
|
|
302
|
+
dcs = dc_api.list(opts).value
|
|
290
303
|
|
|
291
304
|
raise format("Unable to find data center: %s", name) if dcs.empty?
|
|
292
305
|
end
|
|
@@ -321,9 +334,10 @@ module Kitchen
|
|
|
321
334
|
# Gets the folder you want to create the VM
|
|
322
335
|
#
|
|
323
336
|
# @param [name] name is the name of the folder
|
|
324
|
-
|
|
337
|
+
# @param [type] type is the type of the folder, one of VIRTUAL_MACHINE, DATACENTER, possibly other values
|
|
338
|
+
def get_folder(name, type = "VIRTUAL_MACHINE")
|
|
325
339
|
folder_api = VSphereAutomation::VCenter::FolderApi.new(api_client)
|
|
326
|
-
folders = folder_api.list({ filter_names: name, filter_type:
|
|
340
|
+
folders = folder_api.list({ filter_names: name, filter_type: type }).value
|
|
327
341
|
|
|
328
342
|
raise format("Unable to find folder: %s", name) if folders.empty?
|
|
329
343
|
|
|
@@ -344,10 +358,13 @@ module Kitchen
|
|
|
344
358
|
|
|
345
359
|
# Gets the info of the datacenter
|
|
346
360
|
#
|
|
361
|
+
# @param [folder] folder is the name of the folder in which the Datacenter is stored in inventory, possibly nil
|
|
347
362
|
# @param [name] name is the name of the Datacenter
|
|
348
|
-
def get_datacenter(name)
|
|
363
|
+
def get_datacenter(folder, name)
|
|
349
364
|
dc_api = VSphereAutomation::VCenter::DatacenterApi.new(api_client)
|
|
350
|
-
|
|
365
|
+
opts = { filter_names: name }
|
|
366
|
+
opts[:filter_folders] = get_folder(folder, "DATACENTER") if folder
|
|
367
|
+
dcs = dc_api.list(opts).value
|
|
351
368
|
|
|
352
369
|
raise format("Unable to find data center: %s", name) if dcs.empty?
|
|
353
370
|
|
data/lib/support/clone_vm.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "kitchen"
|
|
2
2
|
require "rbvmomi"
|
|
3
|
-
|
|
3
|
+
require_relative "guest_operations"
|
|
4
4
|
|
|
5
5
|
class Support
|
|
6
6
|
class CloneError < RuntimeError; end
|
|
@@ -81,6 +81,17 @@ class Support
|
|
|
81
81
|
raise Support::CloneError.new("Timeout waiting for IP address") if ip.nil?
|
|
82
82
|
raise Support::CloneError.new(format("Error getting accessible IP address, got %s. Check DHCP server and scope exhaustion", ip)) if ip =~ /^169\.254\./
|
|
83
83
|
|
|
84
|
+
# Allow IP rewriting (e.g. for 1:1 NAT)
|
|
85
|
+
if options[:transform_ip]
|
|
86
|
+
Kitchen.logger.info format("Received IP: %s", ip)
|
|
87
|
+
|
|
88
|
+
# rubocop:disable Security/Eval
|
|
89
|
+
ip = lambda { eval options[:transform_ip] }.call
|
|
90
|
+
# rubocop:enable Security/Eval
|
|
91
|
+
|
|
92
|
+
Kitchen.logger.info format("Transformed to IP: %s", ip)
|
|
93
|
+
end
|
|
94
|
+
|
|
84
95
|
@ip = ip
|
|
85
96
|
end
|
|
86
97
|
|
|
@@ -210,13 +221,13 @@ class Support
|
|
|
210
221
|
case options[:vm_os].downcase.to_sym
|
|
211
222
|
when :linux
|
|
212
223
|
# @todo: allow override if no dhclient
|
|
213
|
-
|
|
224
|
+
[
|
|
214
225
|
"/sbin/modprobe -r vmxnet3",
|
|
215
226
|
"/sbin/modprobe vmxnet3",
|
|
216
227
|
"/sbin/dhclient",
|
|
217
228
|
]
|
|
218
229
|
when :windows
|
|
219
|
-
|
|
230
|
+
[
|
|
220
231
|
"netsh interface set Interface #{options[:vm_win_network]} disable",
|
|
221
232
|
"netsh interface set Interface #{options[:vm_win_network]} enable",
|
|
222
233
|
"ipconfig /renew",
|
|
@@ -251,6 +262,8 @@ class Support
|
|
|
251
262
|
# "wmic nicconfig get IPAddress",
|
|
252
263
|
# "netsh interface ip show ipaddress #{options[:vm_win_network]}"
|
|
253
264
|
end
|
|
265
|
+
else
|
|
266
|
+
options[:active_discovery_command]
|
|
254
267
|
end
|
|
255
268
|
end
|
|
256
269
|
|
|
@@ -395,15 +408,109 @@ class Support
|
|
|
395
408
|
options[:clone_type] == :full
|
|
396
409
|
end
|
|
397
410
|
|
|
411
|
+
def root_folder
|
|
412
|
+
@root_folder ||= vim.serviceInstance.content.rootFolder
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
#
|
|
416
|
+
# @return [String]
|
|
417
|
+
#
|
|
418
|
+
def datacenter
|
|
419
|
+
options[:datacenter]
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
#
|
|
423
|
+
# @return [RbVmomi::VIM::Datacenter]
|
|
424
|
+
#
|
|
425
|
+
def find_datacenter
|
|
426
|
+
vim.serviceInstance.find_datacenter(datacenter)
|
|
427
|
+
rescue RbVmomi::Fault
|
|
428
|
+
root_folder.childEntity.grep(RbVmomi::VIM::Datacenter).find { |x| x.name == datacenter }
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def ip?(string)
|
|
432
|
+
IPAddr.new(string)
|
|
433
|
+
true
|
|
434
|
+
rescue IPAddr::InvalidAddressError
|
|
435
|
+
false
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def customization_spec
|
|
439
|
+
unless options[:guest_customization]
|
|
440
|
+
return false
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
unless ip?(options[:guest_customization][:ip_address])
|
|
444
|
+
raise Support::CloneError.new("Guest customization error: ip_address is required to be formatted as an IPv4 address")
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
unless ip?(options[:guest_customization][:subnet_mask])
|
|
448
|
+
raise Support::CloneError.new("Guest customization error: subnet_mask is required to be formatted as an IPv4 address")
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
options[:guest_customization][:gateway].each do |v|
|
|
452
|
+
unless ip?(v)
|
|
453
|
+
raise Support::CloneError.new("Guest customization error: gateway is required to be formatted as an IPv4 address")
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
options[:guest_customization][:dns_server_list].each do |v|
|
|
458
|
+
unless ip?(v)
|
|
459
|
+
raise Support::CloneError.new("Guest customization error: dns_server_list is required to be formatted as an IPv4 address")
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
unless %i{dns_domain timezone dns_server_list dns_suffix_list ip_address gateway subnet_mask}.all? { |k| options[:guest_customization].key? k }
|
|
464
|
+
raise Support::CloneError.new("Guest customization error: currently all options are required to support guest customization")
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
if !options[:guest_customization][:dns_server_list].is_a?(Array)
|
|
468
|
+
raise Support::CloneError.new("Guest customization error: dns_server_list must be an array")
|
|
469
|
+
elsif !options[:guest_customization][:dns_suffix_list].is_a?(Array)
|
|
470
|
+
raise Support::CloneError.new("Guest customization error: dns_suffix_list must be an array")
|
|
471
|
+
elsif !options[:guest_customization][:gateway].is_a?(Array)
|
|
472
|
+
raise Support::CloneError.new("Guest customization error: gateway must be an array")
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
spec = RbVmomi::VIM::CustomizationSpec.new(
|
|
476
|
+
identity: RbVmomi::VIM::CustomizationLinuxPrep.new(
|
|
477
|
+
domain: options[:guest_customization][:dns_domain],
|
|
478
|
+
hostName: RbVmomi::VIM::CustomizationFixedName.new(
|
|
479
|
+
name: name
|
|
480
|
+
),
|
|
481
|
+
hwClockUTC: true,
|
|
482
|
+
timeZone: options[:guest_customization][:timezone]
|
|
483
|
+
),
|
|
484
|
+
globalIPSettings: RbVmomi::VIM::CustomizationGlobalIPSettings.new(
|
|
485
|
+
dnsServerList: options[:guest_customization][:dns_server_list],
|
|
486
|
+
dnsSuffixList: options[:guest_customization][:dns_suffix_list]
|
|
487
|
+
),
|
|
488
|
+
nicSettingMap: [RbVmomi::VIM::CustomizationAdapterMapping.new(
|
|
489
|
+
adapter: RbVmomi::VIM::CustomizationIPSettings.new(
|
|
490
|
+
ip: RbVmomi::VIM::CustomizationFixedIp(
|
|
491
|
+
ipAddress: options[:guest_customization][:ip_address]
|
|
492
|
+
),
|
|
493
|
+
gateway: options[:guest_customization][:gateway],
|
|
494
|
+
subnetMask: options[:guest_customization][:subnet_mask],
|
|
495
|
+
dnsDomain: options[:guest_customization][:dns_domain]
|
|
496
|
+
)
|
|
497
|
+
)]
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
spec
|
|
501
|
+
end
|
|
502
|
+
|
|
398
503
|
def clone
|
|
399
504
|
benchmark_start if benchmark?
|
|
400
505
|
|
|
401
506
|
# set the datacenter name
|
|
402
|
-
dc =
|
|
507
|
+
dc = find_datacenter
|
|
508
|
+
|
|
509
|
+
# get guest customization spec
|
|
510
|
+
guest_customization = customization_spec
|
|
403
511
|
|
|
404
512
|
# reference template using full inventory path
|
|
405
|
-
|
|
406
|
-
inventory_path = format("/%s/vm/%s", options[:datacenter], options[:template])
|
|
513
|
+
inventory_path = format("/%s/vm/%s", datacenter, options[:template])
|
|
407
514
|
src_vm = root_folder.findByInventoryPath(inventory_path)
|
|
408
515
|
raise Support::CloneError.new(format("Unable to find template: %s", options[:template])) if src_vm.nil?
|
|
409
516
|
|
|
@@ -432,10 +539,11 @@ class Support
|
|
|
432
539
|
# Change network, if wanted
|
|
433
540
|
unless options[:network_name].nil?
|
|
434
541
|
networks = dc.network.select { |n| n.name == options[:network_name] }
|
|
435
|
-
raise Support::CloneError.new(format("Could not find network named %s",
|
|
542
|
+
raise Support::CloneError.new(format("Could not find network named %s", options[:network_name])) if networks.empty?
|
|
436
543
|
|
|
437
544
|
Kitchen.logger.warn format("Found %d networks named %s, picking first one", networks.count, options[:network_name]) if networks.count > 1
|
|
438
545
|
network_obj = networks.first
|
|
546
|
+
network_device = network_device(src_vm)
|
|
439
547
|
|
|
440
548
|
if network_obj.is_a? RbVmomi::VIM::DistributedVirtualPortgroup
|
|
441
549
|
Kitchen.logger.info format("Assigning network %s...", network_obj.pretty_path)
|
|
@@ -443,7 +551,6 @@ class Support
|
|
|
443
551
|
vds_obj = network_obj.config.distributedVirtualSwitch
|
|
444
552
|
Kitchen.logger.info format("Using vDS '%s' for network connectivity...", vds_obj.name)
|
|
445
553
|
|
|
446
|
-
network_device = network_device(src_vm)
|
|
447
554
|
network_device.backing = RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo(
|
|
448
555
|
port: RbVmomi::VIM.DistributedVirtualSwitchPortConnection(
|
|
449
556
|
portgroupKey: network_obj.key,
|
|
@@ -520,9 +627,15 @@ class Support
|
|
|
520
627
|
benchmark_checkpoint("initialized") if benchmark?
|
|
521
628
|
task = src_vm.InstantClone_Task(spec: clone_spec)
|
|
522
629
|
else
|
|
523
|
-
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
|
524
|
-
|
|
525
|
-
|
|
630
|
+
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
|
631
|
+
location: relocate_spec,
|
|
632
|
+
powerOn: options[:poweron] && options[:customize].nil?,
|
|
633
|
+
template: false
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
if guest_customization
|
|
637
|
+
clone_spec.customization = guest_customization
|
|
638
|
+
end
|
|
526
639
|
|
|
527
640
|
benchmark_checkpoint("initialized") if benchmark?
|
|
528
641
|
task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: name)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-vcenter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.6
|
|
4
|
+
version: 2.7.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chef Software
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-07-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rbvmomi
|
|
@@ -30,20 +30,6 @@ dependencies:
|
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '3.0'
|
|
33
|
-
- !ruby/object:Gem::Dependency
|
|
34
|
-
name: savon
|
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '2.11'
|
|
40
|
-
type: :runtime
|
|
41
|
-
prerelease: false
|
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - "~>"
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '2.11'
|
|
47
33
|
- !ruby/object:Gem::Dependency
|
|
48
34
|
name: test-kitchen
|
|
49
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -78,34 +64,6 @@ dependencies:
|
|
|
78
64
|
- - "~>"
|
|
79
65
|
- !ruby/object:Gem::Version
|
|
80
66
|
version: '0.4'
|
|
81
|
-
- !ruby/object:Gem::Dependency
|
|
82
|
-
name: bundler
|
|
83
|
-
requirement: !ruby/object:Gem::Requirement
|
|
84
|
-
requirements:
|
|
85
|
-
- - ">="
|
|
86
|
-
- !ruby/object:Gem::Version
|
|
87
|
-
version: '0'
|
|
88
|
-
type: :development
|
|
89
|
-
prerelease: false
|
|
90
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
91
|
-
requirements:
|
|
92
|
-
- - ">="
|
|
93
|
-
- !ruby/object:Gem::Version
|
|
94
|
-
version: '0'
|
|
95
|
-
- !ruby/object:Gem::Dependency
|
|
96
|
-
name: rake
|
|
97
|
-
requirement: !ruby/object:Gem::Requirement
|
|
98
|
-
requirements:
|
|
99
|
-
- - ">="
|
|
100
|
-
- !ruby/object:Gem::Version
|
|
101
|
-
version: '0'
|
|
102
|
-
type: :development
|
|
103
|
-
prerelease: false
|
|
104
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
105
|
-
requirements:
|
|
106
|
-
- - ">="
|
|
107
|
-
- !ruby/object:Gem::Version
|
|
108
|
-
version: '0'
|
|
109
67
|
description: Test Kitchen driver for VMware vCenter using SDK
|
|
110
68
|
email:
|
|
111
69
|
- oss@chef.io
|
|
@@ -130,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
130
88
|
requirements:
|
|
131
89
|
- - ">="
|
|
132
90
|
- !ruby/object:Gem::Version
|
|
133
|
-
version: '2.
|
|
91
|
+
version: '2.4'
|
|
134
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
93
|
requirements:
|
|
136
94
|
- - ">="
|