knife-vsphere 0.9.0 → 0.9.5
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.
- data/lib/chef/knife/base_vsphere_command.rb +304 -0
- data/lib/chef/knife/vsphere_customization_list.rb +29 -29
- data/lib/chef/knife/vsphere_datastore_list.rb +59 -58
- data/lib/chef/knife/vsphere_pool_list.rb +45 -45
- data/lib/chef/knife/vsphere_template_list.rb +32 -32
- data/lib/chef/knife/vsphere_vlan_list.rb +38 -37
- data/lib/chef/knife/vsphere_vm_clone.rb +414 -414
- data/lib/chef/knife/vsphere_vm_config.rb +48 -0
- data/lib/chef/knife/vsphere_vm_delete.rb +39 -39
- data/lib/chef/knife/vsphere_vm_execute.rb +67 -68
- data/lib/chef/knife/vsphere_vm_list.rb +46 -46
- data/lib/chef/knife/vsphere_vm_query.rb +3 -4
- data/lib/chef/knife/vsphere_vm_snapshot.rb +56 -56
- data/lib/chef/knife/vsphere_vm_state.rb +46 -46
- data/lib/chef/knife/vsphere_vm_vmdk_add.rb +67 -67
- data/lib/knife-vsphere/version.rb +1 -1
- metadata +4 -3
- data/lib/chef/knife/BaseVsphereCommand.rb +0 -304
@@ -4,7 +4,7 @@
|
|
4
4
|
#
|
5
5
|
|
6
6
|
require 'chef/knife'
|
7
|
-
require 'chef/knife/
|
7
|
+
require 'chef/knife/base_vsphere_command'
|
8
8
|
require 'rbvmomi'
|
9
9
|
require 'netaddr'
|
10
10
|
|
@@ -13,9 +13,9 @@ PsOff = 'poweredOff'
|
|
13
13
|
PsSuspended = 'suspended'
|
14
14
|
|
15
15
|
PowerStates = {
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
PsOn => 'powered on',
|
17
|
+
PsOff => 'powered off',
|
18
|
+
PsSuspended => 'suspended'
|
19
19
|
}
|
20
20
|
|
21
21
|
# Manage power state of a virtual machine
|
@@ -26,19 +26,19 @@ class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
|
|
26
26
|
get_common_options
|
27
27
|
|
28
28
|
option :state,
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
:short => "-s STATE",
|
30
|
+
:long => "--state STATE",
|
31
|
+
:description => "The power state to transition the VM into; one of on|off|suspended"
|
32
32
|
|
33
33
|
option :wait_port,
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
:short => "-w PORT",
|
35
|
+
:long => "--wait-port PORT",
|
36
|
+
:description => "Wait for VM to be accessible on a port"
|
37
37
|
|
38
38
|
option :shutdown,
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
:short => "-g",
|
40
|
+
:long => "--shutdown",
|
41
|
+
:description => "Guest OS shutdown"
|
42
42
|
|
43
43
|
def run
|
44
44
|
|
@@ -56,7 +56,7 @@ class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
|
|
56
56
|
baseFolder = find_folder(get_config(:folder));
|
57
57
|
|
58
58
|
vm = find_in_folder(baseFolder, RbVmomi::VIM::VirtualMachine, vmname) or
|
59
|
-
|
59
|
+
abort "VM #{vmname} not found"
|
60
60
|
|
61
61
|
state = vm.runtime.powerState
|
62
62
|
|
@@ -65,45 +65,45 @@ class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
|
|
65
65
|
else
|
66
66
|
|
67
67
|
case config[:state]
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
68
|
+
when 'on'
|
69
|
+
if state == PsOn
|
70
|
+
puts "Virtual machine #{vmname} was already powered on"
|
71
|
+
else
|
72
|
+
vm.PowerOnVM_Task.wait_for_completion
|
73
|
+
puts "Powered on virtual machine #{vmname}"
|
74
|
+
end
|
75
|
+
when 'off'
|
76
|
+
if state == PsOff
|
77
|
+
puts "Virtual machine #{vmname} was already powered off"
|
78
|
+
else
|
79
|
+
if get_config(:shutdown)
|
80
|
+
vm.ShutdownGuest
|
81
|
+
print "Waiting for virtual machine #{vmname} to shut down..."
|
82
|
+
until vm.runtime.powerState == PsOff do
|
83
|
+
sleep 2
|
84
|
+
print "."
|
85
|
+
end
|
86
|
+
puts "done"
|
87
|
+
else
|
88
|
+
vm.PowerOffVM_Task.wait_for_completion
|
89
|
+
puts "Powered off virtual machine #{vmname}"
|
85
90
|
end
|
86
|
-
|
91
|
+
end
|
92
|
+
when 'suspend'
|
93
|
+
if state == PowerStates['suspended']
|
94
|
+
puts "Virtual machine #{vmname} was already suspended"
|
87
95
|
else
|
88
|
-
vm.
|
89
|
-
puts "
|
96
|
+
vm.SuspendVM_Task.wait_for_completion
|
97
|
+
puts "Suspended virtual machine #{vmname}"
|
90
98
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
puts "Virtual machine #{vmname} was already suspended"
|
95
|
-
else
|
96
|
-
vm.SuspendVM_Task.wait_for_completion
|
97
|
-
puts "Suspended virtual machine #{vmname}"
|
98
|
-
end
|
99
|
-
when 'reset'
|
100
|
-
vm.ResetVM_Task.wait_for_completion
|
101
|
-
puts "Reset virtual machine #{vmname}"
|
99
|
+
when 'reset'
|
100
|
+
vm.ResetVM_Task.wait_for_completion
|
101
|
+
puts "Reset virtual machine #{vmname}"
|
102
102
|
end
|
103
103
|
|
104
104
|
if get_config(:wait_port)
|
105
105
|
print "Waiting for port #{get_config(:wait_port)}..."
|
106
|
-
print "." until tcp_test_port_vm(vm,get_config(:wait_port))
|
106
|
+
print "." until tcp_test_port_vm(vm, get_config(:wait_port))
|
107
107
|
puts "done"
|
108
108
|
end
|
109
109
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# License:: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
require 'chef/knife'
|
6
|
-
require 'chef/knife/
|
6
|
+
require 'chef/knife/base_vsphere_command'
|
7
7
|
|
8
8
|
# Lists all known virtual machines in the configured datacenter
|
9
9
|
class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
@@ -12,19 +12,19 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
12
12
|
|
13
13
|
get_common_options
|
14
14
|
|
15
|
-
option :vmdk_type,
|
16
|
-
|
17
|
-
|
15
|
+
option :vmdk_type,
|
16
|
+
:long => "--vmdk-type TYPE",
|
17
|
+
:description => "Type of VMDK"
|
18
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"
|
19
|
+
$default[:vmdk_type] = "thin"
|
20
20
|
|
21
|
-
option :target_lun,
|
22
|
-
|
23
|
-
|
21
|
+
option :target_lun,
|
22
|
+
:long => "--target-lun NAME",
|
23
|
+
:description => "name of target LUN"
|
24
24
|
|
25
25
|
def run
|
26
26
|
$stdout.sync = true
|
27
|
-
|
27
|
+
|
28
28
|
vmname = @name_args[0]
|
29
29
|
if vmname.nil?
|
30
30
|
show_usage
|
@@ -43,27 +43,26 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
43
43
|
vdm = vim.serviceContent.virtualDiskManager
|
44
44
|
vm = get_vm(vmname)
|
45
45
|
if vm.nil?
|
46
|
-
|
47
|
-
|
46
|
+
puts "Could not find #{vmname}"
|
47
|
+
return
|
48
48
|
end
|
49
49
|
|
50
50
|
target_lun = get_config(:target_lun) unless get_config(:target_lun).nil?
|
51
51
|
vmdk_size_kb = size.to_i * 1024 * 1024
|
52
|
-
vmdk_size_B = size.to_i * 1024 * 1024 * 1024
|
53
52
|
|
54
53
|
if target_lun.nil?
|
55
|
-
vmdk_datastore = choose_datastore(vm.datastore,size)
|
54
|
+
vmdk_datastore = choose_datastore(vm.datastore, size)
|
56
55
|
exit -1 if vmdk_datastore.nil?
|
57
56
|
else
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
67
66
|
end
|
68
67
|
|
69
68
|
puts "Choosing: #{vmdk_datastore.name}"
|
@@ -74,27 +73,27 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
74
73
|
vms = vmdk_datastore.vm
|
75
74
|
vmFiles = pc.collectMultiple vms, 'layoutEx.file'
|
76
75
|
vmFiles.keys.each do |vm|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
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
|
83
81
|
end
|
84
82
|
end
|
83
|
+
end
|
85
84
|
end
|
86
85
|
vmdk_fileName = "#{vmname}/#{vmname}_#{next_vmdk}.vmdk"
|
87
86
|
vmdk_name = "[#{vmdk_datastore.name}] #{vmdk_fileName}"
|
88
87
|
vmdk_type = get_config(:vmdk_type)
|
89
88
|
vmdk_type = "preallocated" if vmdk_type == "thick"
|
90
89
|
puts "Next vmdk name is => #{vmdk_name}"
|
91
|
-
|
90
|
+
|
92
91
|
# create the disk
|
93
92
|
if not vmdk_datastore.exists? vmdk_fileName
|
94
93
|
vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec(
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
:adapterType => "lsiLogic",
|
95
|
+
:capacityKb => vmdk_size_kb,
|
96
|
+
:diskType => vmdk_type
|
98
97
|
)
|
99
98
|
ui.info "Creating VMDK"
|
100
99
|
ui.info "#{ui.color "Capacity:", :cyan} #{size} GB"
|
@@ -104,9 +103,9 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
104
103
|
ui.info "#{ui.color "Skipping disk creation process because --noop specified.", :red}"
|
105
104
|
else
|
106
105
|
vdm.CreateVirtualDisk_Task(
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
:datacenter => get_datacenter,
|
107
|
+
:name => vmdk_name,
|
108
|
+
:spec => vmdk_spec
|
110
109
|
).wait_for_completion
|
111
110
|
end
|
112
111
|
end
|
@@ -119,26 +118,26 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
119
118
|
vm.config.hardware.device.each do |device|
|
120
119
|
if device.class == RbVmomi::VIM::VirtualLsiLogicController
|
121
120
|
if scsi_tree[device.controllerKey].nil?
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
scsi_tree[device.key]=Hash.new()
|
122
|
+
scsi_tree[device.key]['children'] = Array.new();
|
123
|
+
scsi_tree[device.key]['device'] = device;
|
125
124
|
end
|
126
125
|
end
|
127
126
|
if device.class == RbVmomi::VIM::VirtualDisk
|
128
127
|
if scsi_tree[device.controllerKey].nil?
|
129
|
-
|
130
|
-
|
128
|
+
scsi_tree[device.controllerKey]=Hash.new()
|
129
|
+
scsi_tree[device.controllerKey]['children'] = Array.new();
|
131
130
|
end
|
132
131
|
scsi_tree[device.controllerKey]['children'].push(device)
|
133
132
|
end
|
134
133
|
end
|
135
134
|
scsi_tree.keys.sort.each do |controller|
|
136
135
|
if scsi_tree[controller]['children'].length < 15
|
137
|
-
|
136
|
+
available_controllers.push(scsi_tree[controller]['device'].deviceInfo.label)
|
138
137
|
end
|
139
138
|
end
|
140
139
|
|
141
|
-
if available_controllers.length > 0
|
140
|
+
if available_controllers.length > 0
|
142
141
|
use_controller = available_controllers[0]
|
143
142
|
puts "using #{use_controller}"
|
144
143
|
else
|
@@ -147,22 +146,22 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
147
146
|
|
148
147
|
# Add a controller if none are available
|
149
148
|
puts "no controllers available. Will attempt to create"
|
150
|
-
new_scsi_key
|
149
|
+
new_scsi_key = scsi_tree.keys.sort[scsi_tree.length - 1] + 1
|
151
150
|
new_scsi_busNumber = scsi_tree[scsi_tree.keys.sort[scsi_tree.length - 1]]['device'].busNumber + 1
|
152
151
|
|
153
152
|
controller_device = RbVmomi::VIM::VirtualLsiLogicController(
|
154
|
-
|
155
|
-
|
156
|
-
|
153
|
+
:key => new_scsi_key,
|
154
|
+
:busNumber => new_scsi_busNumber,
|
155
|
+
:sharedBus => :noSharing
|
157
156
|
)
|
158
157
|
|
159
158
|
device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
|
160
|
-
|
161
|
-
|
159
|
+
:device => controller_device,
|
160
|
+
:operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add")
|
162
161
|
)
|
163
|
-
|
162
|
+
|
164
163
|
vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
|
165
|
-
|
164
|
+
:deviceChange => [device_config_spec]
|
166
165
|
)
|
167
166
|
|
168
167
|
if get_config(:noop)
|
@@ -172,10 +171,10 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
172
171
|
end
|
173
172
|
else
|
174
173
|
ui.info "Controllers maxed out at 4."
|
175
|
-
exit -1
|
174
|
+
exit -1
|
176
175
|
end
|
177
176
|
end
|
178
|
-
|
177
|
+
|
179
178
|
# now go back and get the new device's name
|
180
179
|
vm.config.hardware.device.each do |device|
|
181
180
|
if device.class == RbVmomi::VIM::VirtualLsiLogicController
|
@@ -186,7 +185,7 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
186
185
|
end
|
187
186
|
|
188
187
|
# add the disk
|
189
|
-
controller = find_device(vm,use_controller)
|
188
|
+
controller = find_device(vm, use_controller)
|
190
189
|
|
191
190
|
used_unitNumbers = Array.new()
|
192
191
|
scsi_tree.keys.sort.each do |c|
|
@@ -197,39 +196,40 @@ class Chef::Knife::VsphereVmVmdkAdd < Chef::Knife::BaseVsphereCommand
|
|
197
196
|
end
|
198
197
|
end
|
199
198
|
end
|
199
|
+
|
200
200
|
available_unitNumbers = Array.new
|
201
201
|
(0 .. 15).each do |scsi_id|
|
202
|
-
if used_unitNumbers.grep(scsi_id).length > 0
|
202
|
+
if used_unitNumbers.grep(scsi_id).length > 0
|
203
203
|
else
|
204
|
-
|
204
|
+
available_unitNumbers.push(scsi_id)
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
208
|
# ensure we don't try to add the controllers SCSI ID
|
209
209
|
new_unitNumber = available_unitNumbers.sort[0]
|
210
|
-
|
210
|
+
puts "using SCSI ID #{new_unitNumber}"
|
211
211
|
|
212
212
|
vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo(
|
213
|
-
|
214
|
-
|
215
|
-
|
213
|
+
:datastore => vmdk_datastore,
|
214
|
+
:diskMode => "persistent",
|
215
|
+
:fileName => vmdk_name
|
216
216
|
)
|
217
217
|
|
218
218
|
device = RbVmomi::VIM::VirtualDisk(
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
219
|
+
:backing => vmdk_backing,
|
220
|
+
:capacityInKB => vmdk_size_kb,
|
221
|
+
:controllerKey => controller.key,
|
222
|
+
:key => -1,
|
223
|
+
:unitNumber => new_unitNumber
|
224
224
|
)
|
225
225
|
|
226
226
|
device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
|
227
|
-
|
228
|
-
|
227
|
+
:device => device,
|
228
|
+
:operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation("add")
|
229
229
|
)
|
230
230
|
|
231
231
|
vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
|
232
|
-
|
232
|
+
:deviceChange => [device_config_spec]
|
233
233
|
)
|
234
234
|
|
235
235
|
if get_config(:noop)
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: knife-vsphere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.9.
|
5
|
+
version: 0.9.5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ezra Pagel
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-09-06 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -55,13 +55,14 @@ extensions: []
|
|
55
55
|
extra_rdoc_files: []
|
56
56
|
|
57
57
|
files:
|
58
|
-
- lib/chef/knife/
|
58
|
+
- lib/chef/knife/base_vsphere_command.rb
|
59
59
|
- lib/chef/knife/vsphere_customization_list.rb
|
60
60
|
- lib/chef/knife/vsphere_datastore_list.rb
|
61
61
|
- lib/chef/knife/vsphere_pool_list.rb
|
62
62
|
- lib/chef/knife/vsphere_template_list.rb
|
63
63
|
- lib/chef/knife/vsphere_vlan_list.rb
|
64
64
|
- lib/chef/knife/vsphere_vm_clone.rb
|
65
|
+
- lib/chef/knife/vsphere_vm_config.rb
|
65
66
|
- lib/chef/knife/vsphere_vm_delete.rb
|
66
67
|
- lib/chef/knife/vsphere_vm_execute.rb
|
67
68
|
- lib/chef/knife/vsphere_vm_list.rb
|
@@ -1,304 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Ezra Pagel (<ezra@cpan.org>)
|
3
|
-
# Contributor:: Jesse Campbell (<hikeit@gmail.com>)
|
4
|
-
# License:: Apache License, Version 2.0
|
5
|
-
#
|
6
|
-
|
7
|
-
require 'chef/knife'
|
8
|
-
require 'rbvmomi'
|
9
|
-
|
10
|
-
# Base class for vsphere knife commands
|
11
|
-
class Chef
|
12
|
-
class Knife
|
13
|
-
class BaseVsphereCommand < Knife
|
14
|
-
|
15
|
-
deps do
|
16
|
-
require 'chef/knife/bootstrap'
|
17
|
-
Chef::Knife::Bootstrap.load_deps
|
18
|
-
require 'fog'
|
19
|
-
require 'socket'
|
20
|
-
require 'net/ssh/multi'
|
21
|
-
require 'readline'
|
22
|
-
require 'chef/json_compat'
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.get_common_options
|
26
|
-
unless defined? $default
|
27
|
-
$default = Hash.new
|
28
|
-
end
|
29
|
-
|
30
|
-
option :vsphere_user,
|
31
|
-
:short => "-u USERNAME",
|
32
|
-
:long => "--vsuser USERNAME",
|
33
|
-
:description => "The username for vsphere"
|
34
|
-
|
35
|
-
option :vsphere_pass,
|
36
|
-
:short => "-p PASSWORD",
|
37
|
-
:long => "--vspass PASSWORD",
|
38
|
-
:description => "The password for vsphere"
|
39
|
-
|
40
|
-
option :vsphere_host,
|
41
|
-
:long => "--vshost HOST",
|
42
|
-
:description => "The vsphere host"
|
43
|
-
|
44
|
-
option :vsphere_dc,
|
45
|
-
:short => "-d DATACENTER",
|
46
|
-
:long => "--vsdc DATACENTER",
|
47
|
-
:description => "The Datacenter for vsphere"
|
48
|
-
|
49
|
-
option :vsphere_path,
|
50
|
-
:long => "--vspath SOAP_PATH",
|
51
|
-
:description => "The vsphere SOAP endpoint path"
|
52
|
-
$default[:vsphere_path] = "/sdk"
|
53
|
-
|
54
|
-
option :vsphere_port,
|
55
|
-
:long => "--vsport PORT",
|
56
|
-
:description => "The VI SDK port number to use"
|
57
|
-
$default[:vsphere_port] = 443
|
58
|
-
|
59
|
-
option :vshere_nossl,
|
60
|
-
:long => "--vsnossl",
|
61
|
-
:description => "Disable SSL connectivity"
|
62
|
-
|
63
|
-
option :vsphere_insecure,
|
64
|
-
:long => "--vsinsecure",
|
65
|
-
:description => "Disable SSL certificate verification"
|
66
|
-
|
67
|
-
option :folder,
|
68
|
-
:short => "-f FOLDER",
|
69
|
-
:long => "--folder FOLDER",
|
70
|
-
:description => "The folder to get VMs from"
|
71
|
-
$default[:folder] = ''
|
72
|
-
end
|
73
|
-
|
74
|
-
def get_config(key)
|
75
|
-
key = key.to_sym
|
76
|
-
rval = config[key] || Chef::Config[:knife][key] || $default[key]
|
77
|
-
Chef::Log.debug("value for config item #{key}: #{rval}")
|
78
|
-
rval
|
79
|
-
end
|
80
|
-
|
81
|
-
def get_vim_connection
|
82
|
-
|
83
|
-
conn_opts = {
|
84
|
-
:host => get_config(:vsphere_host),
|
85
|
-
:path => get_config(:vshere_path),
|
86
|
-
:port => get_config(:vsphere_port),
|
87
|
-
:use_ssl => !get_config(:vsphere_nossl),
|
88
|
-
:user => get_config(:vsphere_user),
|
89
|
-
:password => get_config(:vsphere_pass),
|
90
|
-
:insecure => get_config(:vsphere_insecure)
|
91
|
-
}
|
92
|
-
|
93
|
-
# Grab the password from the command line
|
94
|
-
# if tt is not in the config file
|
95
|
-
if not conn_opts[:password]
|
96
|
-
conn_opts[:password] = get_password
|
97
|
-
end
|
98
|
-
|
99
|
-
# opt :debug, "Log SOAP messages", :short => 'd', :default => (ENV['RBVMOMI_DEBUG'] || false)
|
100
|
-
|
101
|
-
vim = RbVmomi::VIM.connect conn_opts
|
102
|
-
config[:vim] = vim
|
103
|
-
return vim
|
104
|
-
end
|
105
|
-
|
106
|
-
def get_password
|
107
|
-
@password ||= ui.ask("Enter your password: ") { |q| q.echo = false }
|
108
|
-
end
|
109
|
-
|
110
|
-
def get_vm(vmname)
|
111
|
-
vim = get_vim_connection
|
112
|
-
baseFolder = find_folder(get_config(:folder));
|
113
|
-
retval = traverse_folders_for_vm(baseFolder,vmname)
|
114
|
-
return retval
|
115
|
-
end
|
116
|
-
|
117
|
-
def traverse_folders_for_vm(folder,vmname)
|
118
|
-
# not sure why @vm is necessary, but it returns class Array
|
119
|
-
# instead of class VirtualMachine without it... ugh
|
120
|
-
@vm = nil
|
121
|
-
folders = find_all_in_folder(folder, RbVmomi::VIM::Folder)
|
122
|
-
folders.each do |child|
|
123
|
-
traverse_folders_for_vm(child,vmname)
|
124
|
-
vms = find_all_in_folder(folder,RbVmomi::VIM::VirtualMachine)
|
125
|
-
vms.each do |vm|
|
126
|
-
if vm.name == vmname
|
127
|
-
@vm = vm
|
128
|
-
return @vm
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
return @vm
|
133
|
-
end
|
134
|
-
|
135
|
-
def get_datacenter
|
136
|
-
dc = config[:vim].serviceInstance.find_datacenter(get_config(:vsphere_dc)) or abort "datacenter not found"
|
137
|
-
end
|
138
|
-
|
139
|
-
def find_folder(folderName)
|
140
|
-
dcname = get_config(:vsphere_dc)
|
141
|
-
dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
|
142
|
-
baseEntity = dc.vmFolder
|
143
|
-
entityArray = folderName.split('/')
|
144
|
-
entityArray.each do |entityArrItem|
|
145
|
-
if entityArrItem != ''
|
146
|
-
baseEntity = baseEntity.childEntity.grep(RbVmomi::VIM::Folder).find { |f| f.name == entityArrItem } or
|
147
|
-
abort "no such folder #{folderName} while looking for #{entityArrItem}"
|
148
|
-
end
|
149
|
-
end
|
150
|
-
baseEntity
|
151
|
-
end
|
152
|
-
|
153
|
-
def find_network(networkName)
|
154
|
-
dcname = get_config(:vsphere_dc)
|
155
|
-
dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
|
156
|
-
baseEntity = dc.network
|
157
|
-
baseEntity.find { |f| f.name == networkName } or abort "no such network #{networkName}"
|
158
|
-
end
|
159
|
-
|
160
|
-
def find_pool(poolName)
|
161
|
-
dcname = get_config(:vsphere_dc)
|
162
|
-
dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
|
163
|
-
baseEntity = dc.hostFolder
|
164
|
-
entityArray = poolName.split('/')
|
165
|
-
entityArray.each do |entityArrItem|
|
166
|
-
if entityArrItem != ''
|
167
|
-
if baseEntity.is_a? RbVmomi::VIM::Folder
|
168
|
-
baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or
|
169
|
-
abort "no such pool #{poolName} while looking for #{entityArrItem}"
|
170
|
-
elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource
|
171
|
-
baseEntity = baseEntity.resourcePool.resourcePool.find { |f| f.name == entityArrItem } or
|
172
|
-
abort "no such pool #{poolName} while looking for #{entityArrItem}"
|
173
|
-
elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool
|
174
|
-
baseEntity = baseEntity.resourcePool.find { |f| f.name == entityArrItem } or
|
175
|
-
abort "no such pool #{poolName} while looking for #{entityArrItem}"
|
176
|
-
else
|
177
|
-
abort "Unexpected Object type encountered #{baseEntity.type} while finding resourcePool"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
baseEntity = baseEntity.resourcePool if not baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and baseEntity.respond_to?(:resourcePool)
|
183
|
-
baseEntity
|
184
|
-
end
|
185
|
-
|
186
|
-
def choose_datastore(dstores,size)
|
187
|
-
vmdk_size_kb = size.to_i * 1024 * 1024
|
188
|
-
vmdk_size_B = size.to_i * 1024 * 1024 * 1024
|
189
|
-
|
190
|
-
candidates = []
|
191
|
-
dstores.each do |store|
|
192
|
-
avail = number_to_human_size(store.summary[:freeSpace])
|
193
|
-
cap = number_to_human_size(store.summary[:capacity])
|
194
|
-
puts "#{ui.color("Datastore", :cyan)}: #{store.name} (#{avail}(#{store.summary[:freeSpace]}) / #{cap})"
|
195
|
-
|
196
|
-
# vm's can span multiple datastores, so instead of grabbing the first one
|
197
|
-
# let's find the first datastore with the available space on a LUN the vm
|
198
|
-
# is already using, or use a specified LUN (if given)
|
199
|
-
|
200
|
-
|
201
|
-
if ( store.summary[:freeSpace] - vmdk_size_B ) > 0
|
202
|
-
# also let's not use more than 90% of total space to save room for snapshots.
|
203
|
-
cap_remains = 100 * ( (store.summary[:freeSpace].to_f - vmdk_size_B.to_f ) / store.summary[:capacity].to_f )
|
204
|
-
if(cap_remains.to_i > 10)
|
205
|
-
candidates.push(store)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
if candidates.length > 0
|
210
|
-
vmdk_datastore = candidates[0]
|
211
|
-
else
|
212
|
-
puts "Insufficient space on all LUNs designated or assigned to the virtual machine. Please specify a new target."
|
213
|
-
vmdk_datastore = nil
|
214
|
-
end
|
215
|
-
return vmdk_datastore
|
216
|
-
end
|
217
|
-
|
218
|
-
|
219
|
-
def find_datastores_regex(regex)
|
220
|
-
stores = Array.new()
|
221
|
-
puts "Looking for all datastores that match /#{regex}/"
|
222
|
-
dcname = get_config(:vsphere_dc)
|
223
|
-
dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
|
224
|
-
baseEntity = dc.datastore
|
225
|
-
baseEntity.each do |ds|
|
226
|
-
if ds.name.match /#{regex}/
|
227
|
-
stores.push ds
|
228
|
-
end
|
229
|
-
end
|
230
|
-
return stores
|
231
|
-
end
|
232
|
-
|
233
|
-
def find_datastore(dsName)
|
234
|
-
dcname = get_config(:vsphere_dc)
|
235
|
-
dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
|
236
|
-
baseEntity = dc.datastore
|
237
|
-
baseEntity.find { |f| f.info.name == dsName } or abort "no such datastore #{dsName}"
|
238
|
-
end
|
239
|
-
|
240
|
-
def find_device(vm,deviceName)
|
241
|
-
vm.config.hardware.device.each do |device|
|
242
|
-
return device if device.deviceInfo.label == deviceName
|
243
|
-
end
|
244
|
-
nil
|
245
|
-
end
|
246
|
-
|
247
|
-
def find_all_in_folder(folder, type)
|
248
|
-
if folder.instance_of?(RbVmomi::VIM::ClusterComputeResource)
|
249
|
-
folder = folder.resourcePool
|
250
|
-
end
|
251
|
-
if folder.instance_of?(RbVmomi::VIM::ResourcePool)
|
252
|
-
folder.resourcePool.grep(type)
|
253
|
-
elsif folder.instance_of?(RbVmomi::VIM::Folder)
|
254
|
-
folder.childEntity.grep(type)
|
255
|
-
else
|
256
|
-
puts "Unknown type #{folder.class}, not enumerating"
|
257
|
-
nil
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def find_in_folder(folder, type, name)
|
262
|
-
folder.childEntity.grep(type).find { |o| o.name == name }
|
263
|
-
end
|
264
|
-
|
265
|
-
def fatal_exit(msg)
|
266
|
-
ui.fatal(msg)
|
267
|
-
exit 1
|
268
|
-
end
|
269
|
-
|
270
|
-
def tcp_test_port_vm(vm,port)
|
271
|
-
ip = vm.guest.ipAddress
|
272
|
-
if ip.nil?
|
273
|
-
sleep 2
|
274
|
-
return false
|
275
|
-
end
|
276
|
-
tcp_test_port(ip, port)
|
277
|
-
end
|
278
|
-
|
279
|
-
def tcp_test_port(hostname,port)
|
280
|
-
tcp_socket = TCPSocket.new(hostname, port)
|
281
|
-
readable = IO.select([tcp_socket], nil, nil, 5)
|
282
|
-
if readable
|
283
|
-
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}") if port == 22
|
284
|
-
true
|
285
|
-
else
|
286
|
-
false
|
287
|
-
end
|
288
|
-
rescue Errno::ETIMEDOUT
|
289
|
-
false
|
290
|
-
rescue Errno::EPERM
|
291
|
-
false
|
292
|
-
rescue Errno::ECONNREFUSED
|
293
|
-
sleep 2
|
294
|
-
false
|
295
|
-
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
296
|
-
sleep 2
|
297
|
-
false
|
298
|
-
ensure
|
299
|
-
tcp_socket && tcp_socket.close
|
300
|
-
end
|
301
|
-
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|