kitchen-vcenter 2.6.5 → 2.7.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41ac2e9801330f72776a2158cf23a4934378259dc00cfd5b8cfe721d51f218ca
4
- data.tar.gz: 939091edf9800da1ad0ff1762ad5db04dd44f9fb5ba1e8db6d2dcbca9d2b7aa8
3
+ metadata.gz: 7085ec77febee812284fdba85d1002f2f1d6bae3ee1e02a7f264efb761217a30
4
+ data.tar.gz: df5e365f5821f623f7d8328ed7381ad710d9a62534970102fce3a4600195917b
5
5
  SHA512:
6
- metadata.gz: 260ee45c053dcb818eb71714d3bc5e177aa29f1492c429a5febe8b93a83f126fc42af9bf46f82e1339f59b79e5547ed0c6471ae46c523b9dbed8055c4b96b2d0
7
- data.tar.gz: 92587c0c703d82be2c0749b59e8c34c895d2a0a2ec6869594d7add00e405bc5610a18bdad20aae9d9a95de5a0add32160d2c27adaf963a5d19cc09fda05c24da
6
+ metadata.gz: 744634197d4ba4c19fb461226f42afbbca219e77054829ba5cb3a7a2b1b7cd10c29d94a3bb1416b840b04dc26bd5a6ba3a1dffa2827c3af9009f9f67130a3eb3
7
+ data.tar.gz: 389178a1c61df997e790cc06cbb3a3d5ae7aa7d6303e946f5cf8ef7499fe65003a6419d7f1a120d6c0da99d3f524b68cdf4dae6e1ee2beab5929a2d47ae5f945
@@ -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.5"
23
+ VERSION = "2.7.12"
24
24
  end
@@ -18,9 +18,10 @@
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
- require "securerandom"
23
- require "uri"
23
+ require "securerandom" unless defined?(SecureRandom)
24
+ require "uri" unless defined?(URI)
24
25
 
25
26
  # The main kitchen module
26
27
  module Kitchen
@@ -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
@@ -129,7 +137,7 @@ module Kitchen
129
137
  unless config[:folder].nil?
130
138
  config[:folder] = {
131
139
  name: config[:folder],
132
- id: get_folder(config[:folder]),
140
+ id: get_folder(config[:folder], "VIRTUAL_MACHINE", datacenter),
133
141
  }
134
142
  end
135
143
 
@@ -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,13 +334,20 @@ 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
+ # @param [datacenter] datacenter is the datacenter of the folder
339
+ def get_folder(name, type = "VIRTUAL_MACHINE", datacenter = nil)
325
340
  folder_api = VSphereAutomation::VCenter::FolderApi.new(api_client)
326
- folders = folder_api.list({ filter_names: name, filter_type: "VIRTUAL_MACHINE" }).value
341
+ parent_path, basename = File.split(name)
342
+ filter = { filter_names: basename, filter_type: type }
343
+ filter[:filter_datacenters] = datacenter if datacenter
344
+ filter[:filter_parent_folders] = get_folder(parent_path, type, datacenter) unless parent_path == "."
345
+
346
+ folders = folder_api.list(filter).value
327
347
 
328
- raise format("Unable to find folder: %s", name) if folders.empty?
348
+ raise format("Unable to find folder: %s", basename) if folders.empty?
329
349
 
330
- raise format("%s returned too many folders", name) if folders.length > 1
350
+ raise format("`%s` returned too many folders", basename) if folders.length > 1
331
351
 
332
352
  folders.first.folder
333
353
  end
@@ -344,10 +364,13 @@ module Kitchen
344
364
 
345
365
  # Gets the info of the datacenter
346
366
  #
367
+ # @param [folder] folder is the name of the folder in which the Datacenter is stored in inventory, possibly nil
347
368
  # @param [name] name is the name of the Datacenter
348
- def get_datacenter(name)
369
+ def get_datacenter(folder, name)
349
370
  dc_api = VSphereAutomation::VCenter::DatacenterApi.new(api_client)
350
- dcs = dc_api.list({ filter_names: name }).value
371
+ opts = { filter_names: name }
372
+ opts[:filter_folders] = get_folder(folder, "DATACENTER") if folder
373
+ dcs = dc_api.list(opts).value
351
374
 
352
375
  raise format("Unable to find data center: %s", name) if dcs.empty?
353
376
 
@@ -403,14 +426,14 @@ module Kitchen
403
426
  # impact on small environments, but on large deployments with lots of clusters and pools,
404
427
  # provisioned machines are likely to "jump around" available hosts.
405
428
  #
406
- # This behaviour is carried on from versions 1.2.1 and lower, but likely to be removed in
429
+ # This behavior is carried on from versions 1.2.1 and lower, but likely to be removed in
407
430
  # a new major version due to these insufficiencies and the confusing code for it
408
431
 
409
- # Remove default pool for first pass (<= 1.2.1 behaviour to pick first user-defined pool found)
432
+ # Remove default pool for first pass (<= 1.2.1 behavior to pick first user-defined pool found)
410
433
  resource_pools = rp_api.list.value.delete_if { |pool| pool.name == "Resources" }
411
434
  debug("Search of all resource pools found: " + resource_pools.map(&:name).to_s)
412
435
 
413
- # Revert to default pool, if no user-defined pool found (> 1.2.1 behaviour)
436
+ # Revert to default pool, if no user-defined pool found (> 1.2.1 behavior)
414
437
  # (This one might not be found under some circumstances by the statement above)
415
438
  return get_resource_pool("Resources") if resource_pools.empty?
416
439
  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
 
@@ -417,12 +428,85 @@ class Support
417
428
  root_folder.childEntity.grep(RbVmomi::VIM::Datacenter).find { |x| x.name == datacenter }
418
429
  end
419
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
+
420
501
  def clone
421
502
  benchmark_start if benchmark?
422
503
 
423
504
  # set the datacenter name
424
505
  dc = find_datacenter
425
506
 
507
+ # get guest customization spec
508
+ guest_customization = customization_spec
509
+
426
510
  # reference template using full inventory path
427
511
  inventory_path = format("/%s/vm/%s", datacenter, options[:template])
428
512
  src_vm = root_folder.findByInventoryPath(inventory_path)
@@ -541,9 +625,15 @@ class Support
541
625
  benchmark_checkpoint("initialized") if benchmark?
542
626
  task = src_vm.InstantClone_Task(spec: clone_spec)
543
627
  else
544
- clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(location: relocate_spec,
545
- powerOn: options[:poweron] && options[:customize].nil?,
546
- 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
547
637
 
548
638
  benchmark_checkpoint("initialized") if benchmark?
549
639
  task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: name)
@@ -1,5 +1,5 @@
1
1
  require "rbvmomi"
2
- require "net/http"
2
+ require "net/http" unless defined?(Net::HTTP)
3
3
 
4
4
  class Support
5
5
  # Encapsulate VMware Tools GOM interaction, inspired by github:dnuffer/raidopt
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.5
4
+ version: 2.7.12
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-03-16 00:00:00.000000000 Z
11
+ date: 2020-08-21 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
  - - ">="