kitchen-vcenter 2.6.4 → 2.7.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48a7b054f396b0a0074fb6c20096ace9db63ed41ef81468a38eff3a106419d3f
4
- data.tar.gz: 6a2c17827fab3cfca5680b9358a42878e47162b9809139adf87ab990db516461
3
+ metadata.gz: 8386b994051575b7997042ebd3c818de171a8de1ca34a39e13672800b986f216
4
+ data.tar.gz: 611d99f79e9d90ba850b1b0f04f126f3ca8acbb7c5000861c2d32310602f8f63
5
5
  SHA512:
6
- metadata.gz: d6fd6e15dd7e011b029cb2d3f470777a44eee7f1bbd207c3748e61899e18caabcfa3d037e5cc7f1f88d87791f7bac9d5e238407615d7673629c9a10e356ca4b7
7
- data.tar.gz: 2677d2b44e2856f75f560ae3b78d7e6a3a656477f1686e5747e7f350c56094acd7dec0a9e93480aaf75896a5ecb890466ab47e66ffb9a0c20909b1ea0198a598
6
+ metadata.gz: 678e749a5da30a917227c6f057836177b0a70a7f2d3b79a5272b76ee1a26aa33191234fd31211a43d31e4137e1c6184c6b2307d7a75658bcd5e944214a4cf523
7
+ data.tar.gz: adf8a44b1a88c6274e1ee7070c7055b203fb033ebffb6723476fc3db6abfd6a8660fc16693a0cae8f4419bef34e550bc75de5a3c99a903f90e34b81bc252a531
@@ -20,5 +20,5 @@
20
20
  # The main kitchen-vcenter module
21
21
  module KitchenVcenter
22
22
  # The version of this version of test-kitchen we assume enterprises want.
23
- VERSION = "2.6.4"
23
+ VERSION = "2.7.9"
24
24
  end
@@ -18,6 +18,7 @@
18
18
  require "kitchen"
19
19
  require "vsphere-automation-cis"
20
20
  require "vsphere-automation-vcenter"
21
+ require_relative "../../kitchen-vcenter/version"
21
22
  require_relative "../../support/clone_vm"
22
23
  require "securerandom"
23
24
  require "uri"
@@ -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
- datacenter_exists?(config[:datacenter])
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(config[: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
- dcs = dc_api.list({ filter_names: name }).value
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
- def get_folder(name)
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: "VIRTUAL_MACHINE" }).value
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
- dcs = dc_api.list({ filter_names: name }).value
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
 
@@ -403,14 +420,14 @@ module Kitchen
403
420
  # impact on small environments, but on large deployments with lots of clusters and pools,
404
421
  # provisioned machines are likely to "jump around" available hosts.
405
422
  #
406
- # This behaviour is carried on from versions 1.2.1 and lower, but likely to be removed in
423
+ # This behavior is carried on from versions 1.2.1 and lower, but likely to be removed in
407
424
  # a new major version due to these insufficiencies and the confusing code for it
408
425
 
409
- # Remove default pool for first pass (<= 1.2.1 behaviour to pick first user-defined pool found)
426
+ # Remove default pool for first pass (<= 1.2.1 behavior to pick first user-defined pool found)
410
427
  resource_pools = rp_api.list.value.delete_if { |pool| pool.name == "Resources" }
411
428
  debug("Search of all resource pools found: " + resource_pools.map(&:name).to_s)
412
429
 
413
- # Revert to default pool, if no user-defined pool found (> 1.2.1 behaviour)
430
+ # Revert to default pool, if no user-defined pool found (> 1.2.1 behavior)
414
431
  # (This one might not be found under some circumstances by the statement above)
415
432
  return get_resource_pool("Resources") if resource_pools.empty?
416
433
  else
@@ -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
- return [
224
+ [
214
225
  "/sbin/modprobe -r vmxnet3",
215
226
  "/sbin/modprobe vmxnet3",
216
227
  "/sbin/dhclient",
217
228
  ]
218
229
  when :windows
219
- return [
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,8 +262,8 @@ class Support
251
262
  # "wmic nicconfig get IPAddress",
252
263
  # "netsh interface ip show ipaddress #{options[:vm_win_network]}"
253
264
  end
254
- else
255
- return options[:active_discovery_command]
265
+ else
266
+ options[:active_discovery_command]
256
267
  end
257
268
  end
258
269
 
@@ -397,15 +408,107 @@ class Support
397
408
  options[:clone_type] == :full
398
409
  end
399
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
+ 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
+ end
500
+
400
501
  def clone
401
502
  benchmark_start if benchmark?
402
503
 
403
504
  # set the datacenter name
404
- dc = vim.serviceInstance.find_datacenter(options[:datacenter])
505
+ dc = find_datacenter
506
+
507
+ # get guest customization spec
508
+ guest_customization = customization_spec
405
509
 
406
510
  # reference template using full inventory path
407
- root_folder = vim.serviceInstance.content.rootFolder
408
- inventory_path = format("/%s/vm/%s", options[:datacenter], options[:template])
511
+ inventory_path = format("/%s/vm/%s", datacenter, options[:template])
409
512
  src_vm = root_folder.findByInventoryPath(inventory_path)
410
513
  raise Support::CloneError.new(format("Unable to find template: %s", options[:template])) if src_vm.nil?
411
514
 
@@ -522,9 +625,15 @@ class Support
522
625
  benchmark_checkpoint("initialized") if benchmark?
523
626
  task = src_vm.InstantClone_Task(spec: clone_spec)
524
627
  else
525
- clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(location: relocate_spec,
526
- powerOn: options[:poweron] && options[:customize].nil?,
527
- template: false)
628
+ clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
629
+ location: relocate_spec,
630
+ powerOn: options[:poweron] && options[:customize].nil?,
631
+ template: false
632
+ )
633
+
634
+ if guest_customization
635
+ clone_spec.customization = guest_customization
636
+ end
528
637
 
529
638
  benchmark_checkpoint("initialized") if benchmark?
530
639
  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
4
+ version: 2.7.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-18 00:00:00.000000000 Z
11
+ date: 2020-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbvmomi
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '1.11'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '3.0'
22
+ version: '4.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '1.11'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '3.0'
32
+ version: '4.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: test-kitchen
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -64,34 +64,6 @@ dependencies:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0.4'
67
- - !ruby/object:Gem::Dependency
68
- name: bundler
69
- requirement: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: '0'
74
- type: :development
75
- prerelease: false
76
- version_requirements: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: '0'
81
- - !ruby/object:Gem::Dependency
82
- name: rake
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
67
  description: Test Kitchen driver for VMware vCenter using SDK
96
68
  email:
97
69
  - oss@chef.io
@@ -116,7 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
88
  requirements:
117
89
  - - ">="
118
90
  - !ruby/object:Gem::Version
119
- version: '2.3'
91
+ version: '2.4'
120
92
  required_rubygems_version: !ruby/object:Gem::Requirement
121
93
  requirements:
122
94
  - - ">="