knife-vsphere 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/knife/base_vsphere_command.rb +383 -371
  3. data/lib/chef/knife/customization_helper.rb +40 -0
  4. data/lib/chef/knife/vsphere_cluster_list.rb +47 -0
  5. data/lib/chef/knife/vsphere_cpu_ratio.rb +41 -45
  6. data/lib/chef/knife/vsphere_customization_list.rb +24 -29
  7. data/lib/chef/knife/vsphere_datastore_list.rb +68 -72
  8. data/lib/chef/knife/vsphere_datastore_maxfree.rb +48 -49
  9. data/lib/chef/knife/vsphere_datastorecluster_list.rb +66 -71
  10. data/lib/chef/knife/vsphere_datastorecluster_maxfree.rb +75 -84
  11. data/lib/chef/knife/vsphere_folder_list.rb +28 -30
  12. data/lib/chef/knife/vsphere_hosts_list.rb +42 -42
  13. data/lib/chef/knife/vsphere_pool_list.rb +46 -48
  14. data/lib/chef/knife/vsphere_pool_query.rb +58 -58
  15. data/lib/chef/knife/vsphere_template_list.rb +30 -32
  16. data/lib/chef/knife/vsphere_vlan_create.rb +51 -0
  17. data/lib/chef/knife/vsphere_vlan_list.rb +35 -37
  18. data/lib/chef/knife/vsphere_vm_clone.rb +834 -581
  19. data/lib/chef/knife/vsphere_vm_config.rb +48 -46
  20. data/lib/chef/knife/vsphere_vm_delete.rb +70 -66
  21. data/lib/chef/knife/vsphere_vm_execute.rb +62 -66
  22. data/lib/chef/knife/vsphere_vm_list.rb +57 -61
  23. data/lib/chef/knife/vsphere_vm_markastemplate.rb +48 -54
  24. data/lib/chef/knife/vsphere_vm_migrate.rb +73 -0
  25. data/lib/chef/knife/vsphere_vm_move.rb +88 -0
  26. data/lib/chef/knife/vsphere_vm_net.rb +57 -0
  27. data/lib/chef/knife/vsphere_vm_property_get.rb +44 -46
  28. data/lib/chef/knife/vsphere_vm_property_set.rb +83 -84
  29. data/lib/chef/knife/vsphere_vm_query.rb +48 -48
  30. data/lib/chef/knife/vsphere_vm_snapshot.rb +124 -130
  31. data/lib/chef/knife/vsphere_vm_state.rb +122 -127
  32. data/lib/chef/knife/vsphere_vm_toolsconfig.rb +54 -52
  33. data/lib/chef/knife/vsphere_vm_vmdk_add.rb +234 -241
  34. data/lib/chef/knife/vsphere_vm_wait_sysprep.rb +54 -0
  35. data/lib/knife-vsphere/version.rb +3 -4
  36. metadata +43 -15
  37. data/lib/chef/knife/vshpere_vm_migrate.rb +0 -80
  38. data/lib/chef/knife/vshpere_vm_move.rb +0 -92
  39. data/lib/chef/knife/vshpere_vm_net.rb +0 -57
@@ -1,52 +1,54 @@
1
- # Author:: Malte Heidenreich
2
- # License:: Apache License, Version 2.0
3
-
4
- require 'chef/knife'
5
- require 'chef/knife/base_vsphere_command'
6
- require 'rbvmomi'
7
- require 'netaddr'
8
-
9
- class Chef::Knife::VsphereVmToolsconfig < Chef::Knife::BaseVsphereCommand
10
- banner "knife vsphere vm toolsconfig PROPERTY VALUE. See \"https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.ToolsConfigInfo.html\" for available properties and types."
11
-
12
- option :empty,
13
- :short => "-e",
14
- :long => "--empty",
15
- :description => "Allow empty string"
16
- get_common_options
17
-
18
- def run
19
- $stdout.sync = true
20
- vmname = @name_args[0]
21
- if vmname.nil?
22
- show_usage
23
- fatal_exit("You must specify a virtual machine name")
24
- end
25
-
26
- property = @name_args[1]
27
- if property.nil?
28
- show_usage
29
- fatal_exit("You must specify a property to modify")
30
- end
31
-
32
- value = @name_args[2]
33
- if value.nil? && !get_config(:empty)
34
- show_usage
35
- fatal_exit("You must specify a value")
36
- end
37
-
38
- value = "" if get_config(:empty)
39
-
40
- vim = get_vim_connection
41
-
42
- dc = get_datacenter
43
- folder = find_folder(get_config(:folder)) || dc.vmFolder
44
-
45
- vm = traverse_folders_for_vm(folder, vmname) or abort "VM #{vmname} not found"
46
-
47
- vmConfigSpec = RbVmomi::VIM.VirtualMachineConfigSpec(:tools => RbVmomi::VIM.ToolsConfigInfo(property => value))
48
- vm.ReconfigVM_Task(:spec => vmConfigSpec)
49
-
50
- puts "property #{property} updated successfully"
51
- end
52
- end
1
+ # Author:: Malte Heidenreich
2
+ # License:: Apache License, Version 2.0
3
+
4
+ require 'chef/knife'
5
+ require 'chef/knife/base_vsphere_command'
6
+ require 'rbvmomi'
7
+ require 'netaddr'
8
+
9
+ class Chef::Knife::VsphereVmToolsconfig < Chef::Knife::BaseVsphereCommand
10
+ banner "knife vsphere vm toolsconfig PROPERTY VALUE.
11
+ See \"https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.ToolsConfigInfo.html\"
12
+ for available properties and types."
13
+
14
+ option :empty,
15
+ short: '-e',
16
+ long: '--empty',
17
+ description: 'Allow empty string'
18
+ common_options
19
+
20
+ def run
21
+ $stdout.sync = true
22
+ vmname = @name_args[0]
23
+ if vmname.nil?
24
+ show_usage
25
+ fatal_exit('You must specify a virtual machine name')
26
+ end
27
+
28
+ property = @name_args[1]
29
+ if property.nil?
30
+ show_usage
31
+ fatal_exit('You must specify a property to modify')
32
+ end
33
+
34
+ value = @name_args[2]
35
+ if value.nil? && !get_config(:empty)
36
+ show_usage
37
+ fatal_exit('You must specify a value')
38
+ end
39
+
40
+ value = '' if get_config(:empty)
41
+
42
+ vim_connection
43
+
44
+ dc = datacenter
45
+ folder = find_folder(get_config(:folder)) || dc.vmFolder
46
+
47
+ vm = traverse_folders_for_vm(folder, vmname) || abort("VM #{vmname} not found")
48
+
49
+ vm_config_spec = RbVmomi::VIM.VirtualMachineConfigSpec(tools: RbVmomi::VIM.ToolsConfigInfo(property => value))
50
+ vm.ReconfigVM_Task(spec: vm_config_spec)
51
+
52
+ puts "property #{property} updated successfully"
53
+ end
54
+ end
@@ -1,241 +1,234 @@
1
- #
2
- # Author:: Brian Flad (<bflad417@gmail.com>)
3
- # License:: Apache License, Version 2.0
4
- #
5
- require 'chef/knife'
6
- require 'chef/knife/base_vsphere_command'
7
-
8
- # Lists all known virtual machines in the configured datacenter
9
- class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
10
-
11
- banner "knife vsphere vm vmdk add"
12
-
13
- get_common_options
14
-
15
- option :vmdk_type,
16
- :long => "--vmdk-type TYPE",
17
- :description => "Type of VMDK"
18
- # this is a bad idea as it will let you overcommit SAN by 400% or more. thick is a more "sane" default
19
- $default[:vmdk_type] = "thin"
20
-
21
- option :target_lun,
22
- :long => "--target-lun NAME",
23
- :description => "name of target LUN"
24
-
25
- def run
26
- $stdout.sync = true
27
-
28
- vmname = @name_args[0]
29
- if vmname.nil?
30
- show_usage
31
- ui.fatal("You must specify a virtual machine name")
32
- exit 1
33
- end
34
-
35
- size = @name_args[1]
36
- if size.nil?
37
- ui.fatal "You need a VMDK size!"
38
- show_usage
39
- exit 1
40
- end
41
-
42
- vim = get_vim_connection
43
- vdm = vim.serviceContent.virtualDiskManager
44
- vm = get_vm(vmname)
45
- if vm.nil?
46
- puts "Could not find #{vmname}"
47
- return
48
- end
49
-
50
- target_lun = get_config(:target_lun) unless get_config(:target_lun).nil?
51
- vmdk_size_kb = size.to_i * 1024 * 1024
52
-
53
- if target_lun.nil?
54
- vmdk_datastore = choose_datastore(vm.datastore, size)
55
- exit -1 if vmdk_datastore.nil?
56
- else
57
- vmdk_datastores = find_datastores_regex(target_lun)
58
- vmdk_datastore = choose_datastore(vmdk_datastores, size)
59
- exit -1 if vmdk_datastore.nil?
60
- vmdk_dir = "[#{vmdk_datastore.name}] #{vmname}"
61
- # create the vm folder on the LUN or subsequent operations will fail.
62
- if not vmdk_datastore.exists? vmname
63
- dc = get_datacenter
64
- dc._connection.serviceContent.fileManager.MakeDirectory :name => vmdk_dir, :datacenter => dc, :createParentDirectories => false
65
- end
66
- end
67
-
68
- puts "Choosing: #{vmdk_datastore.name}"
69
-
70
- # now we need to inspect the files in this datastore to get our next file name
71
- next_vmdk = 1
72
- pc = vmdk_datastore._connection.serviceContent.propertyCollector
73
- vms = vmdk_datastore.vm
74
- vmFiles = pc.collectMultiple vms, 'layoutEx.file'
75
- vmFiles.keys.each do |vm|
76
- vmFiles[vm]["layoutEx.file"].each do |layout|
77
- if layout.name.match(/^\[#{vmdk_datastore.name}\] #{vmname}\/#{vmname}_([0-9]+).vmdk/)
78
- num = $1
79
- if next_vmdk <= num.to_i
80
- next_vmdk = num.to_i + 1
81
- end
82
- end
83
- end
84
- end
85
- vmdk_fileName = "#{vmname}/#{vmname}_#{next_vmdk}.vmdk"
86
- vmdk_name = "[#{vmdk_datastore.name}] #{vmdk_fileName}"
87
- vmdk_type = get_config(:vmdk_type)
88
- vmdk_type = "preallocated" if vmdk_type == "thick"
89
- puts "Next vmdk name is => #{vmdk_name}"
90
-
91
- # create the disk
92
- if not vmdk_datastore.exists? vmdk_fileName
93
- vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec(
94
- :adapterType => "lsiLogic",
95
- :capacityKb => vmdk_size_kb,
96
- :diskType => vmdk_type
97
- )
98
- ui.info "Creating VMDK"
99
- ui.info "#{ui.color "Capacity:", :cyan} #{size} GB"
100
- ui.info "#{ui.color "Disk:", :cyan} #{vmdk_name}"
101
-
102
- if get_config(:noop)
103
- ui.info "#{ui.color "Skipping disk creation process because --noop specified.", :red}"
104
- else
105
- vdm.CreateVirtualDisk_Task(
106
- :datacenter => get_datacenter,
107
- :name => vmdk_name,
108
- :spec => vmdk_spec
109
- ).wait_for_completion
110
- end
111
- end
112
- ui.info "Attaching VMDK to #{vmname}"
113
-
114
- # now we run through the SCSI controllers to see if there's an available one
115
- available_controllers = Array.new()
116
- use_controller = nil
117
- scsi_tree = Hash.new()
118
- vm.config.hardware.device.each do |device|
119
- if device.is_a? RbVmomi::VIM::VirtualSCSIController
120
- if scsi_tree[device.controllerKey].nil?
121
- scsi_tree[device.key]=Hash.new()
122
- scsi_tree[device.key]['children'] = Array.new();
123
- end
124
- scsi_tree[device.key]['device'] = device;
125
- end
126
- if device.class == RbVmomi::VIM::VirtualDisk
127
- if scsi_tree[device.controllerKey].nil?
128
- scsi_tree[device.controllerKey]=Hash.new()
129
- scsi_tree[device.controllerKey]['children'] = Array.new();
130
- end
131
- scsi_tree[device.controllerKey]['children'].push(device)
132
- end
133
- end
134
- scsi_tree.keys.sort.each do |controller|
135
- if scsi_tree[controller]['children'].length < 15
136
- available_controllers.push(scsi_tree[controller]['device'].deviceInfo.label)
137
- end
138
- end
139
-
140
- if available_controllers.length > 0
141
- use_controller = available_controllers[0]
142
- puts "using #{use_controller}"
143
- else
144
-
145
- if scsi_tree.keys.length < 4
146
-
147
- # Add a controller if none are available
148
- puts "no controllers available. Will attempt to create"
149
- new_scsi_key = scsi_tree.keys.sort[scsi_tree.length - 1] + 1
150
- new_scsi_busNumber = scsi_tree[scsi_tree.keys.sort[scsi_tree.length - 1]]['device'].busNumber + 1
151
-
152
- controller_device = RbVmomi::VIM::VirtualLsiLogicController(
153
- :key => new_scsi_key,
154
- :busNumber => new_scsi_busNumber,
155
- :sharedBus => :noSharing
156
- )
157
-
158
- device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
159
- :device => controller_device,
160
- :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add")
161
- )
162
-
163
- vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
164
- :deviceChange => [device_config_spec]
165
- )
166
-
167
- if get_config(:noop)
168
- ui.info "#{ui.color "Skipping controller creation process because --noop specified.", :red}"
169
- else
170
- vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion
171
- end
172
- else
173
- ui.info "Controllers maxed out at 4."
174
- exit -1
175
- end
176
- end
177
-
178
- # now go back and get the new device's name
179
- vm.config.hardware.device.each do |device|
180
- if device.class == RbVmomi::VIM::VirtualLsiLogicController
181
- if device.key == new_scsi_key
182
- use_controller = device.deviceInfo.label
183
- end
184
- end
185
- end
186
-
187
- # add the disk
188
- controller = find_device(vm, use_controller)
189
-
190
- used_unitNumbers = Array.new()
191
- scsi_tree.keys.sort.each do |c|
192
- if controller.key == scsi_tree[c]['device'].key
193
- used_unitNumbers.push(scsi_tree[c]['device'].scsiCtlrUnitNumber)
194
- scsi_tree[c]['children'].each do |disk|
195
- used_unitNumbers.push(disk.unitNumber)
196
- end
197
- end
198
- end
199
-
200
- available_unitNumbers = Array.new
201
- (0 .. 15).each do |scsi_id|
202
- if used_unitNumbers.grep(scsi_id).length > 0
203
- else
204
- available_unitNumbers.push(scsi_id)
205
- end
206
- end
207
-
208
- # ensure we don't try to add the controllers SCSI ID
209
- new_unitNumber = available_unitNumbers.sort[0]
210
- puts "using SCSI ID #{new_unitNumber}"
211
-
212
- vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo(
213
- :datastore => vmdk_datastore,
214
- :diskMode => "persistent",
215
- :fileName => vmdk_name
216
- )
217
-
218
- device = RbVmomi::VIM::VirtualDisk(
219
- :backing => vmdk_backing,
220
- :capacityInKB => vmdk_size_kb,
221
- :controllerKey => controller.key,
222
- :key => -1,
223
- :unitNumber => new_unitNumber
224
- )
225
-
226
- device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
227
- :device => device,
228
- :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add")
229
- )
230
-
231
- vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
232
- :deviceChange => [device_config_spec]
233
- )
234
-
235
- if get_config(:noop)
236
- ui.info "#{ui.color "Skipping disk attaching process because --noop specified.", :red}"
237
- else
238
- vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion
239
- end
240
- end
241
- end
1
+ #
2
+ # Author:: Brian Flad (<bflad417@gmail.com>)
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ require 'chef/knife'
6
+ require 'chef/knife/base_vsphere_command'
7
+
8
+ # Add a new disk to a virtual machine
9
+ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
10
+ banner 'knife vsphere vm vmdk add VMNAME DISK_GB'
11
+
12
+ common_options
13
+
14
+ option :vmdk_type,
15
+ long: '--vmdk-type TYPE',
16
+ description: 'Type of VMDK',
17
+ # this is a bad idea as it will let you overcommit SAN by 400% or more. thick is a more "sane" default
18
+ default: 'thin'
19
+
20
+ option :target_lun,
21
+ long: '--target-lun NAME',
22
+ description: 'name of target LUN'
23
+
24
+ def run
25
+ $stdout.sync = true
26
+
27
+ vmname = @name_args[0]
28
+ if vmname.nil?
29
+ show_usage
30
+ ui.fatal('You must specify a virtual machine name')
31
+ exit 1
32
+ end
33
+
34
+ size = @name_args[1]
35
+ if size.nil?
36
+ ui.fatal 'You need a VMDK size!'
37
+ show_usage
38
+ exit 1
39
+ end
40
+
41
+ vim = vim_connection
42
+ vdm = vim.serviceContent.virtualDiskManager
43
+ vm = get_vm(vmname)
44
+ if vm.nil?
45
+ puts "Could not find #{vmname}"
46
+ return
47
+ end
48
+
49
+ target_lun = get_config(:target_lun) unless get_config(:target_lun).nil?
50
+ vmdk_size_kb = size.to_i * 1024 * 1024
51
+
52
+ if target_lun.nil?
53
+ vmdk_datastore = choose_datastore(vm.datastore, size)
54
+ exit(-1) if vmdk_datastore.nil?
55
+ else
56
+ vmdk_datastores = find_datastores_regex(target_lun)
57
+ vmdk_datastore = choose_datastore(vmdk_datastores, size)
58
+ exit(-1) if vmdk_datastore.nil?
59
+ vmdk_dir = "[#{vmdk_datastore.name}] #{vmname}"
60
+ # create the vm folder on the LUN or subsequent operations will fail.
61
+ unless vmdk_datastore.exists? vmname
62
+ dc = datacenter
63
+ dc._connection.serviceContent.fileManager.MakeDirectory name: vmdk_dir, datacenter: dc, createParentDirectories: false
64
+ end
65
+ end
66
+
67
+ puts "Choosing: #{vmdk_datastore.name}"
68
+
69
+ # now we need to inspect the files in this datastore to get our next file name
70
+ next_vmdk = 1
71
+ pc = vmdk_datastore._connection.serviceContent.propertyCollector
72
+ vms = vmdk_datastore.vm
73
+ vm_files = pc.collectMultiple vms, 'layoutEx.file'
74
+ vm_files.keys.each do |vmFile|
75
+ vm_files[vmFile]['layoutEx.file'].each do |layout|
76
+ if layout.name.match(/^\[#{vmdk_datastore.name}\] #{vmname}\/#{vmname}_([0-9]+).vmdk/)
77
+ num = Regexp.last_match(1)
78
+ next_vmdk = num.to_i + 1 if next_vmdk <= num.to_i
79
+ end
80
+ end
81
+ end
82
+ vmdk_file_name = "#{vmname}/#{vmname}_#{next_vmdk}.vmdk"
83
+ vmdk_name = "[#{vmdk_datastore.name}] #{vmdk_file_name}"
84
+ vmdk_type = get_config(:vmdk_type)
85
+ vmdk_type = 'preallocated' if vmdk_type == 'thick'
86
+ puts "Next vmdk name is => #{vmdk_name}"
87
+
88
+ # create the disk
89
+ unless vmdk_datastore.exists? vmdk_file_name
90
+ vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec(
91
+ adapterType: 'lsiLogic',
92
+ capacityKb: vmdk_size_kb,
93
+ diskType: vmdk_type
94
+ )
95
+ ui.info 'Creating VMDK'
96
+ ui.info "#{ui.color 'Capacity:', :cyan} #{size} GB"
97
+ ui.info "#{ui.color 'Disk:', :cyan} #{vmdk_name}"
98
+
99
+ if get_config(:noop)
100
+ ui.info "#{ui.color 'Skipping disk creation process because --noop specified.', :red}"
101
+ else
102
+ vdm.CreateVirtualDisk_Task(
103
+ datacenter: datacenter,
104
+ name: vmdk_name,
105
+ spec: vmdk_spec
106
+ ).wait_for_completion
107
+ end
108
+ end
109
+ ui.info "Attaching VMDK to #{vmname}"
110
+
111
+ # now we run through the SCSI controllers to see if there's an available one
112
+ available_controllers = []
113
+ use_controller = nil
114
+ scsi_tree = {}
115
+ vm.config.hardware.device.each do |device|
116
+ if device.is_a? RbVmomi::VIM::VirtualSCSIController
117
+ if scsi_tree[device.controllerKey].nil?
118
+ scsi_tree[device.key] = {}
119
+ scsi_tree[device.key]['children'] = []
120
+ end
121
+ scsi_tree[device.key]['device'] = device
122
+ end
123
+ next unless device.class == RbVmomi::VIM::VirtualDisk
124
+ if scsi_tree[device.controllerKey].nil?
125
+ scsi_tree[device.controllerKey] = {}
126
+ scsi_tree[device.controllerKey]['children'] = []
127
+ end
128
+ scsi_tree[device.controllerKey]['children'].push(device)
129
+ end
130
+ scsi_tree.keys.sort.each do |controller|
131
+ if scsi_tree[controller]['children'].length < 15
132
+ available_controllers.push(scsi_tree[controller]['device'].deviceInfo.label)
133
+ end
134
+ end
135
+
136
+ if available_controllers.length > 0
137
+ use_controller = available_controllers[0]
138
+ puts "using #{use_controller}"
139
+ else
140
+
141
+ if scsi_tree.keys.length < 4
142
+
143
+ # Add a controller if none are available
144
+ puts 'no controllers available. Will attempt to create'
145
+ new_scsi_key = scsi_tree.keys.sort[scsi_tree.length - 1] + 1
146
+ new_scsi_bus_number = scsi_tree[scsi_tree.keys.sort[scsi_tree.length - 1]]['device'].busNumber + 1
147
+
148
+ controller_device = RbVmomi::VIM::VirtualLsiLogicController(
149
+ key: new_scsi_key,
150
+ busNumber: new_scsi_bus_number,
151
+ sharedBus: :noSharing
152
+ )
153
+
154
+ device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
155
+ device: controller_device,
156
+ operation: RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add')
157
+ )
158
+
159
+ vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
160
+ deviceChange: [device_config_spec]
161
+ )
162
+
163
+ if get_config(:noop)
164
+ ui.info "#{ui.color 'Skipping controller creation process because --noop specified.', :red}"
165
+ else
166
+ vm.ReconfigVM_Task(spec: vm_config_spec).wait_for_completion
167
+ end
168
+ else
169
+ ui.info 'Controllers maxed out at 4.'
170
+ exit(-1)
171
+ end
172
+ end
173
+
174
+ # now go back and get the new device's name
175
+ vm.config.hardware.device.each do |device|
176
+ if device.class == RbVmomi::VIM::VirtualLsiLogicController
177
+ use_controller = device.deviceInfo.label if device.key == new_scsi_key
178
+ end
179
+ end
180
+
181
+ # add the disk
182
+ controller = find_device(vm, use_controller)
183
+
184
+ used_unit_numbers = []
185
+ scsi_tree.keys.sort.each do |c|
186
+ next unless controller.key == scsi_tree[c]['device'].key
187
+ used_unit_numbers.push(scsi_tree[c]['device'].scsiCtlrUnitNumber)
188
+ scsi_tree[c]['children'].each do |disk|
189
+ used_unit_numbers.push(disk.unitNumber)
190
+ end
191
+ end
192
+
193
+ available_unit_numbers = []
194
+ (0..15).each do |scsi_id|
195
+ if used_unit_numbers.grep(scsi_id).length > 0
196
+ else
197
+ available_unit_numbers.push(scsi_id)
198
+ end
199
+ end
200
+
201
+ # ensure we don't try to add the controllers SCSI ID
202
+ new_unit_number = available_unit_numbers.sort[0]
203
+ puts "using SCSI ID #{new_unit_number}"
204
+
205
+ vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo(
206
+ datastore: vmdk_datastore,
207
+ diskMode: 'persistent',
208
+ fileName: vmdk_name
209
+ )
210
+
211
+ device = RbVmomi::VIM::VirtualDisk(
212
+ backing: vmdk_backing,
213
+ capacityInKB: vmdk_size_kb,
214
+ controllerKey: controller.key,
215
+ key: -1,
216
+ unitNumber: new_unit_number
217
+ )
218
+
219
+ device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
220
+ device: device,
221
+ operation: RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add')
222
+ )
223
+
224
+ vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
225
+ deviceChange: [device_config_spec]
226
+ )
227
+
228
+ if get_config(:noop)
229
+ ui.info "#{ui.color 'Skipping disk attaching process because --noop specified.', :red}"
230
+ else
231
+ vm.ReconfigVM_Task(spec: vm_config_spec).wait_for_completion
232
+ end
233
+ end
234
+ end