knife-vsphere 0.9.9 → 1.0.0.pre
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 +7 -0
- data/lib/chef/knife/base_vsphere_command.rb +39 -0
- data/lib/chef/knife/vshpere_vm_move.rb +47 -47
- data/lib/chef/knife/vsphere_customization_list.rb +29 -29
- data/lib/chef/knife/vsphere_datastore_list.rb +58 -58
- data/lib/chef/knife/vsphere_pool_list.rb +44 -44
- data/lib/chef/knife/vsphere_vlan_list.rb +37 -37
- data/lib/chef/knife/vsphere_vm_clone.rb +20 -2
- data/lib/chef/knife/vsphere_vm_execute.rb +66 -66
- data/lib/chef/knife/vsphere_vm_markastemplate.rb +54 -0
- data/lib/chef/knife/vsphere_vm_snapshot.rb +129 -129
- data/lib/chef/knife/vsphere_vm_state.rb +127 -111
- data/lib/chef/knife/vsphere_vm_vmdk_add.rb +241 -241
- data/lib/knife-vsphere/version.rb +4 -4
- metadata +58 -59
@@ -1,111 +1,127 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Ezra Pagel (<ezra@cpan.org>)
|
3
|
-
# License:: Apache License, Version 2.0
|
4
|
-
#
|
5
|
-
|
6
|
-
require 'chef/knife'
|
7
|
-
require 'chef/knife/base_vsphere_command'
|
8
|
-
require 'rbvmomi'
|
9
|
-
require 'netaddr'
|
10
|
-
|
11
|
-
PsOn = 'poweredOn'
|
12
|
-
PsOff = 'poweredOff'
|
13
|
-
PsSuspended = 'suspended'
|
14
|
-
|
15
|
-
PowerStates = {
|
16
|
-
PsOn => 'powered on',
|
17
|
-
PsOff => 'powered off',
|
18
|
-
PsSuspended => 'suspended'
|
19
|
-
}
|
20
|
-
|
21
|
-
# Manage power state of a virtual machine
|
22
|
-
class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
|
23
|
-
|
24
|
-
banner "knife vsphere vm state VMNAME (options)"
|
25
|
-
|
26
|
-
get_common_options
|
27
|
-
|
28
|
-
option :state,
|
29
|
-
:short => "-s STATE",
|
30
|
-
:long => "--state STATE",
|
31
|
-
:description => "The power state to transition the VM into; one of on|off|suspended"
|
32
|
-
|
33
|
-
option :wait_port,
|
34
|
-
:short => "-w PORT",
|
35
|
-
:long => "--wait-port PORT",
|
36
|
-
:description => "Wait for VM to be accessible on a port"
|
37
|
-
|
38
|
-
option :shutdown,
|
39
|
-
:short => "-g",
|
40
|
-
:long => "--shutdown",
|
41
|
-
:description => "Guest OS shutdown"
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
1
|
+
#
|
2
|
+
# Author:: Ezra Pagel (<ezra@cpan.org>)
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'chef/knife'
|
7
|
+
require 'chef/knife/base_vsphere_command'
|
8
|
+
require 'rbvmomi'
|
9
|
+
require 'netaddr'
|
10
|
+
|
11
|
+
PsOn = 'poweredOn'
|
12
|
+
PsOff = 'poweredOff'
|
13
|
+
PsSuspended = 'suspended'
|
14
|
+
|
15
|
+
PowerStates = {
|
16
|
+
PsOn => 'powered on',
|
17
|
+
PsOff => 'powered off',
|
18
|
+
PsSuspended => 'suspended'
|
19
|
+
}
|
20
|
+
|
21
|
+
# Manage power state of a virtual machine
|
22
|
+
class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
|
23
|
+
|
24
|
+
banner "knife vsphere vm state VMNAME (options)"
|
25
|
+
|
26
|
+
get_common_options
|
27
|
+
|
28
|
+
option :state,
|
29
|
+
:short => "-s STATE",
|
30
|
+
:long => "--state STATE",
|
31
|
+
:description => "The power state to transition the VM into; one of on|off|suspended"
|
32
|
+
|
33
|
+
option :wait_port,
|
34
|
+
:short => "-w PORT",
|
35
|
+
:long => "--wait-port PORT",
|
36
|
+
:description => "Wait for VM to be accessible on a port"
|
37
|
+
|
38
|
+
option :shutdown,
|
39
|
+
:short => "-g",
|
40
|
+
:long => "--shutdown",
|
41
|
+
:description => "Guest OS shutdown"
|
42
|
+
|
43
|
+
option :recursive,
|
44
|
+
:short => "-r",
|
45
|
+
:long => "--recursive",
|
46
|
+
:description => "Search all folders"
|
47
|
+
|
48
|
+
def run
|
49
|
+
|
50
|
+
$stdout.sync = true
|
51
|
+
|
52
|
+
vmname = @name_args[0]
|
53
|
+
if vmname.nil?
|
54
|
+
show_usage
|
55
|
+
ui.fatal("You must specify a virtual machine name")
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
|
59
|
+
vim = get_vim_connection
|
60
|
+
|
61
|
+
if get_config(:recursive)
|
62
|
+
vms = get_vms(vmname)
|
63
|
+
if vms.length > 1
|
64
|
+
abort "More than one VM with name #{vmname} found:\n" + vms.map{ |vm| get_path_to_object(vm) }.join("\n")
|
65
|
+
end
|
66
|
+
if vms.length == 0
|
67
|
+
abort "VM #{vmname} not found"
|
68
|
+
end
|
69
|
+
vm = vms[0]
|
70
|
+
else
|
71
|
+
baseFolder = find_folder(get_config(:folder));
|
72
|
+
|
73
|
+
vm = find_in_folder(baseFolder, RbVmomi::VIM::VirtualMachine, vmname) or
|
74
|
+
abort "VM #{vmname} not found"
|
75
|
+
end
|
76
|
+
|
77
|
+
state = vm.runtime.powerState
|
78
|
+
|
79
|
+
if config[:state].nil?
|
80
|
+
puts "VM #{vmname} is currently " + PowerStates[vm.runtime.powerState]
|
81
|
+
else
|
82
|
+
|
83
|
+
case config[:state]
|
84
|
+
when 'on'
|
85
|
+
if state == PsOn
|
86
|
+
puts "Virtual machine #{vmname} was already powered on"
|
87
|
+
else
|
88
|
+
vm.PowerOnVM_Task.wait_for_completion
|
89
|
+
puts "Powered on virtual machine #{vmname}"
|
90
|
+
end
|
91
|
+
when 'off'
|
92
|
+
if state == PsOff
|
93
|
+
puts "Virtual machine #{vmname} was already powered off"
|
94
|
+
else
|
95
|
+
if get_config(:shutdown)
|
96
|
+
vm.ShutdownGuest
|
97
|
+
print "Waiting for virtual machine #{vmname} to shut down..."
|
98
|
+
until vm.runtime.powerState == PsOff do
|
99
|
+
sleep 2
|
100
|
+
print "."
|
101
|
+
end
|
102
|
+
puts "done"
|
103
|
+
else
|
104
|
+
vm.PowerOffVM_Task.wait_for_completion
|
105
|
+
puts "Powered off virtual machine #{vmname}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
when 'suspend'
|
109
|
+
if state == PowerStates['suspended']
|
110
|
+
puts "Virtual machine #{vmname} was already suspended"
|
111
|
+
else
|
112
|
+
vm.SuspendVM_Task.wait_for_completion
|
113
|
+
puts "Suspended virtual machine #{vmname}"
|
114
|
+
end
|
115
|
+
when 'reset'
|
116
|
+
vm.ResetVM_Task.wait_for_completion
|
117
|
+
puts "Reset virtual machine #{vmname}"
|
118
|
+
end
|
119
|
+
|
120
|
+
if get_config(:wait_port)
|
121
|
+
print "Waiting for port #{get_config(:wait_port)}..."
|
122
|
+
print "." until tcp_test_port_vm(vm, get_config(:wait_port))
|
123
|
+
puts "done"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -1,241 +1,241 @@
|
|
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.class == RbVmomi::VIM::VirtualLsiLogicController
|
120
|
-
if scsi_tree[device.controllerKey].nil?
|
121
|
-
scsi_tree[device.key]=Hash.new()
|
122
|
-
scsi_tree[device.key]['children'] = Array.new();
|
123
|
-
scsi_tree[device.key]['device'] = device;
|
124
|
-
end
|
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
|
+
# 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.class == RbVmomi::VIM::VirtualLsiLogicController
|
120
|
+
if scsi_tree[device.controllerKey].nil?
|
121
|
+
scsi_tree[device.key]=Hash.new()
|
122
|
+
scsi_tree[device.key]['children'] = Array.new();
|
123
|
+
scsi_tree[device.key]['device'] = device;
|
124
|
+
end
|
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
|