esx 0.4.1 → 0.4.2
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/CHANGELOG.md +9 -1
- data/Gemfile +5 -1
- data/Gemfile.lock +51 -0
- data/Rakefile +2 -1
- data/bin/esx +147 -13
- data/lib/esx.rb +83 -39
- data/templates/vmx_template.erb +27 -0
- metadata +141 -24
data/CHANGELOG.md
CHANGED
@@ -8,17 +8,20 @@
|
|
8
8
|
|
9
9
|
* Define a Logger object
|
10
10
|
|
11
|
+
```
|
11
12
|
ESX::Log.info "foobar"
|
13
|
+
```
|
12
14
|
|
13
15
|
* Added some debugging with Log.debug
|
14
|
-
|
15
16
|
* ESX::Host now has a *templates_dir* attribute and supports uploading and cloning templates:
|
16
17
|
|
18
|
+
```
|
17
19
|
host = ESX::Host.connect 'my-esx-host',
|
18
20
|
'root',
|
19
21
|
'password'
|
20
22
|
|
21
23
|
host.import_template "/path/to/template.vmdk"
|
24
|
+
```
|
22
25
|
|
23
26
|
This will copy the "template.vmdk" file to the default templates_dir in ESX. Default templates dir is "/vmfs/volumes/datastore1/esx-gem/templates".
|
24
27
|
|
@@ -26,13 +29,18 @@ The template is automatically converted to VMDK thin format.
|
|
26
29
|
|
27
30
|
Using the template:
|
28
31
|
|
32
|
+
```
|
29
33
|
host.copy_from_template "template.vmdk", "/vmfs/volumes/datastore1/foo.vmdk"
|
30
34
|
|
35
|
+
````
|
36
|
+
|
31
37
|
Sorter version:
|
32
38
|
|
39
|
+
```
|
33
40
|
host.import_disk "/path/to/local/template.vmdk", # local file
|
34
41
|
"/vmfs/volumes/datastore1/foo.vmdk", # remote path in ESX
|
35
42
|
{ :use_template => true }
|
43
|
+
```
|
36
44
|
|
37
45
|
If the template "template.vmdk" is found, use that. Otherwise import the disk, save it as a template and clone the template to "/vmfs/volumes/datastore1/foo.vmdk"
|
38
46
|
|
data/Gemfile
CHANGED
@@ -6,8 +6,12 @@ source "http://rubygems.org"
|
|
6
6
|
# Add dependencies to develop your gem here.
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
|
+
gem "net-ssh"
|
10
|
+
gem "net-scp"
|
11
|
+
gem "rbvmomi"
|
12
|
+
gem "alchemist"
|
9
13
|
gem "rspec", ">= 0"
|
10
|
-
gem "bundler", "
|
14
|
+
gem "bundler", "> 1.0.0"
|
11
15
|
gem "jeweler"
|
12
16
|
gem "simplecov", ">= 0"
|
13
17
|
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
alchemist (0.1.3)
|
5
|
+
builder (3.0.0)
|
6
|
+
diff-lcs (1.1.3)
|
7
|
+
git (1.2.5)
|
8
|
+
jeweler (1.8.4)
|
9
|
+
bundler (~> 1.0)
|
10
|
+
git (>= 1.2.5)
|
11
|
+
rake
|
12
|
+
rdoc
|
13
|
+
json (1.7.5)
|
14
|
+
multi_json (1.3.6)
|
15
|
+
net-scp (1.0.4)
|
16
|
+
net-ssh (>= 1.99.1)
|
17
|
+
net-ssh (2.5.2)
|
18
|
+
nokogiri (1.5.5)
|
19
|
+
rake (0.9.2.2)
|
20
|
+
rbvmomi (1.5.1)
|
21
|
+
builder
|
22
|
+
nokogiri (>= 1.4.1)
|
23
|
+
trollop
|
24
|
+
rdoc (3.12)
|
25
|
+
json (~> 1.4)
|
26
|
+
rspec (2.11.0)
|
27
|
+
rspec-core (~> 2.11.0)
|
28
|
+
rspec-expectations (~> 2.11.0)
|
29
|
+
rspec-mocks (~> 2.11.0)
|
30
|
+
rspec-core (2.11.1)
|
31
|
+
rspec-expectations (2.11.2)
|
32
|
+
diff-lcs (~> 1.1.3)
|
33
|
+
rspec-mocks (2.11.2)
|
34
|
+
simplecov (0.6.4)
|
35
|
+
multi_json (~> 1.0)
|
36
|
+
simplecov-html (~> 0.5.3)
|
37
|
+
simplecov-html (0.5.3)
|
38
|
+
trollop (1.16.2)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
alchemist
|
45
|
+
bundler (> 1.0.0)
|
46
|
+
jeweler
|
47
|
+
net-scp
|
48
|
+
net-ssh
|
49
|
+
rbvmomi
|
50
|
+
rspec
|
51
|
+
simplecov
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ Jeweler::Tasks.new do |gem|
|
|
12
12
|
gem.summary = %Q{Simple RbVmomi wrapper library to manage VMWare ESX hosts}
|
13
13
|
gem.description = %Q{Manage VMWare ESX hosts with ease}
|
14
14
|
gem.email = "rubiojr@frameos.org"
|
15
|
-
gem.authors = ["Sergio Rubio"]
|
15
|
+
gem.authors = ["Sergio Rubio","Massimo Maino"]
|
16
16
|
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
17
17
|
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
18
18
|
gem.add_runtime_dependency 'alchemist'
|
@@ -22,6 +22,7 @@ Jeweler::Tasks.new do |gem|
|
|
22
22
|
gem.add_runtime_dependency 'net-scp'
|
23
23
|
gem.add_runtime_dependency 'clamp'
|
24
24
|
gem.files.exclude 'spec/data/*'
|
25
|
+
gem.files.include 'templates/*'
|
25
26
|
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
27
|
end
|
27
28
|
Jeweler::RubygemsDotOrgTasks.new
|
data/bin/esx
CHANGED
@@ -5,12 +5,14 @@ require 'terminal-table/import'
|
|
5
5
|
require 'clamp'
|
6
6
|
require 'net/http'
|
7
7
|
require 'fileutils'
|
8
|
+
require 'json'
|
8
9
|
|
9
10
|
class BaseCommand < Clamp::Command
|
10
11
|
parameter "ADDRESS", "ESX host address"
|
11
12
|
option "--user", "USER", "Username", :default => "root"
|
12
13
|
option "--password", "PASSWORD", "Password", :default => ""
|
13
14
|
option "--debug", :flag, "Print debugging info"
|
15
|
+
option "--free-license", :flag, "If your Hypervisor have a free license", :default => false
|
14
16
|
end
|
15
17
|
|
16
18
|
class InfoCommand < BaseCommand
|
@@ -22,7 +24,7 @@ class InfoCommand < BaseCommand
|
|
22
24
|
def execute
|
23
25
|
begin
|
24
26
|
|
25
|
-
host = ESX::Host.connect(address, user, password)
|
27
|
+
host = ESX::Host.connect(address, user, password, true, {:free_license=>free_license?})
|
26
28
|
|
27
29
|
puts
|
28
30
|
name = host.name.upcase
|
@@ -78,9 +80,9 @@ class DestroyVMCommand < BaseCommand
|
|
78
80
|
|
79
81
|
def execute
|
80
82
|
begin
|
81
|
-
host = ESX::Host.connect address, user, password
|
83
|
+
host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?}
|
82
84
|
host.virtual_machines.each do |vm|
|
83
|
-
if vm.name == vm_name
|
85
|
+
if vm.name == vm_name
|
84
86
|
print "Destroying Virtual Machine '#{vm.name}'..."
|
85
87
|
vm.power_off unless vm.power_state == 'poweredOff'
|
86
88
|
vm.destroy
|
@@ -105,7 +107,7 @@ class PowerOffVMCommand < BaseCommand
|
|
105
107
|
|
106
108
|
def execute
|
107
109
|
begin
|
108
|
-
host = ESX::Host.connect address, user, password
|
110
|
+
host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?}
|
109
111
|
host.virtual_machines.each do |vm|
|
110
112
|
if vm.name == vm_name and vm.power_state == 'poweredOn'
|
111
113
|
print "Powering Off VM #{vm_name}... "
|
@@ -131,7 +133,7 @@ class PowerOnVMCommand < BaseCommand
|
|
131
133
|
|
132
134
|
def execute
|
133
135
|
begin
|
134
|
-
host = ESX::Host.connect address, user, password
|
136
|
+
host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?}
|
135
137
|
host.virtual_machines.each do |vm|
|
136
138
|
if vm.name == vm_name and vm.power_state != 'poweredOn'
|
137
139
|
print "Powering On VM #{vm_name}... "
|
@@ -150,6 +152,135 @@ class PowerOnVMCommand < BaseCommand
|
|
150
152
|
|
151
153
|
end
|
152
154
|
|
155
|
+
class DeleteNICCommand < BaseCommand
|
156
|
+
parameter "ADDRESS", "ESX host address"
|
157
|
+
option "--vm-name", "VM_NAME", "Virtual Machine"
|
158
|
+
option "--mac-address", "MAC_ADDRESS", "MAC address to remove"
|
159
|
+
option "--force", :flag, "Force reboot"
|
160
|
+
|
161
|
+
def execute
|
162
|
+
begin
|
163
|
+
host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?}
|
164
|
+
|
165
|
+
vm = host.virtual_machines.find{|x| x.name.eql? vm_name}
|
166
|
+
if vm
|
167
|
+
hd=vm.vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).find{|nic| nic.props[:macAddress].eql?mac_address}
|
168
|
+
if hd
|
169
|
+
spec = RbVmomi::VIM.VirtualMachineConfigSpec({:deviceChange => [{:operation => :remove,:device => hd}]})
|
170
|
+
unless free_license?
|
171
|
+
vm.vm_object.ReconfigVM_Task(:spec => spec).wait_for_completion
|
172
|
+
else
|
173
|
+
#TODO: This is horrible! Find a way to reconfigure the VM without downtime
|
174
|
+
key = hd.key
|
175
|
+
vmx_file = vm.vm_object.config.files.vmPathName.gsub("[","/vmfs/volumes/").gsub(/]\s*/,"/")
|
176
|
+
puts "VMX file: #{vmx_file}" if debug?
|
177
|
+
eth_name = host.remote_command("fgrep #{mac_address} #{vmx_file} | cut -d. -f1")
|
178
|
+
if eth_name
|
179
|
+
eth_name.strip!
|
180
|
+
puts "#{eth_name} found!" if debug?
|
181
|
+
host.remote_command "sed -i -e '/.*#{eth_name}\..*/d' #{vmx_file}"
|
182
|
+
end
|
183
|
+
if force?
|
184
|
+
vm.power_off
|
185
|
+
host.remote_command "vim-cmd vmsvc/unregister #{vm.vmid}"
|
186
|
+
id = host.remote_command "vim-cmd solo/registervm #{vmx_file}"
|
187
|
+
host.remote_command "vim-cmd vmsvc/power.on #{id}"
|
188
|
+
else
|
189
|
+
puts "You have to power-off the vm unregister it and register it agin."
|
190
|
+
end
|
191
|
+
end
|
192
|
+
puts "Done."
|
193
|
+
else
|
194
|
+
puts "No NIC with #{mac_address} mac address was found!"
|
195
|
+
end
|
196
|
+
else
|
197
|
+
puts "No Virtual Machine found!"
|
198
|
+
end
|
199
|
+
rescue Exception => e
|
200
|
+
$stderr.puts "Can't connect to the host #{address}."
|
201
|
+
if debug?
|
202
|
+
$stderr.puts e.message
|
203
|
+
end
|
204
|
+
exit 1
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
class AddNICCommand < BaseCommand
|
211
|
+
parameter "ADDRESS", "ESX host address"
|
212
|
+
option "--vm-name", "VM_NAME", "Virtual Machine"
|
213
|
+
option "--mac-address", "MAC_ADDRESS", "MAC address to add", :default => nil
|
214
|
+
option "--network", "NETWORK", "Network name for new interface"
|
215
|
+
option "--force", :flag, "Force reboot"
|
216
|
+
|
217
|
+
def execute
|
218
|
+
begin
|
219
|
+
host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?}
|
220
|
+
vm = host.virtual_machines.find{|x| x.name.eql? vm_name}
|
221
|
+
if vm
|
222
|
+
hd = vm.vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).find{|nic| nic.props[:macAddress].eql?mac_address}
|
223
|
+
s = vm.vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).size
|
224
|
+
if hd
|
225
|
+
puts "NIC with #{mac_address} mac address already exists!"
|
226
|
+
else
|
227
|
+
if mac_address
|
228
|
+
nics = {:macAddress => mac_address, :addressType => 'manual'}
|
229
|
+
else
|
230
|
+
nics = {:addressType => 'generated'}
|
231
|
+
end
|
232
|
+
spec = RbVmomi::VIM.VirtualMachineConfigSpec({:deviceChange => [{
|
233
|
+
:operation => :add,
|
234
|
+
:device => RbVmomi::VIM.VirtualE1000({
|
235
|
+
:key => s,
|
236
|
+
:deviceInfo => {
|
237
|
+
:label => "Network Adapter #{s}",
|
238
|
+
:summary => network || 'VM Network'
|
239
|
+
},
|
240
|
+
:backing => RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo(
|
241
|
+
:deviceName => network || 'VM Network'
|
242
|
+
)
|
243
|
+
}.merge(nics))
|
244
|
+
}]})
|
245
|
+
unless free_license?
|
246
|
+
vm.vm_object.ReconfigVM_Task(:spec => spec).wait_for_completion
|
247
|
+
else
|
248
|
+
#TODO: This is horrible! Find a way to reconfigure the VM without downtime
|
249
|
+
vmx_file = vm.vm_object.config.files.vmPathName.gsub("[","/vmfs/volumes/").gsub(/]\s*/,"/")
|
250
|
+
puts "VMX file: #{vmx_file}" if debug?
|
251
|
+
host.remote_command " echo 'ethernet#{s}.present = \"true\"' >> #{vmx_file}"
|
252
|
+
host.remote_command " echo 'ethernet#{s}.virtualDev = \"e1000\"' >> #{vmx_file}"
|
253
|
+
host.remote_command " echo 'ethernet#{s}.wakeOnPcktRcv = \"false\"' >> #{vmx_file}"
|
254
|
+
host.remote_command " echo 'ethernet#{s}.networkName = \"#{network || 'VM Network'}\"' >> #{vmx_file}"
|
255
|
+
if mac_address
|
256
|
+
host.remote_command " echo 'ethernet#{s}.addressType = \"static\"' >> #{vmx_file}"
|
257
|
+
host.remote_command " echo 'ethernet#{s}.address = \"#{mac_address}\"' >> #{vmx_file}"
|
258
|
+
else
|
259
|
+
host.remote_command " echo 'ethernet#{s}.addressType = \"generated\"' >> #{vmx_file}"
|
260
|
+
end
|
261
|
+
if force?
|
262
|
+
vm.power_off
|
263
|
+
host.remote_command "vim-cmd vmsvc/unregister #{vm.vmid}"
|
264
|
+
id = host.remote_command "vim-cmd solo/registervm #{vmx_file}"
|
265
|
+
host.remote_command "vim-cmd vmsvc/power.on #{id}"
|
266
|
+
else
|
267
|
+
puts "You have to power-off the vm unregister it and register it agin."
|
268
|
+
end
|
269
|
+
end
|
270
|
+
puts "Done."
|
271
|
+
end
|
272
|
+
else
|
273
|
+
puts "No Virtual Machine found!"
|
274
|
+
end
|
275
|
+
rescue Exception => e
|
276
|
+
$stderr.puts "Can't connect to the host #{address}."
|
277
|
+
if debug?
|
278
|
+
$stderr.puts e.message
|
279
|
+
end
|
280
|
+
exit 1
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
153
284
|
|
154
285
|
class CreateVMCommand < BaseCommand
|
155
286
|
|
@@ -167,7 +298,7 @@ class CreateVMCommand < BaseCommand
|
|
167
298
|
|
168
299
|
def execute
|
169
300
|
begin
|
170
|
-
host = ESX::Host.connect address, user, password
|
301
|
+
host = ESX::Host.connect address, user, password, true, {:free_license=>free_license?}
|
171
302
|
rescue Exception => e
|
172
303
|
$stderr.puts "Can't connect to the host #{address}."
|
173
304
|
if debug?
|
@@ -181,7 +312,7 @@ class CreateVMCommand < BaseCommand
|
|
181
312
|
downloaded_file = nil
|
182
313
|
if disk_file.nil?
|
183
314
|
# if --disk-file nil? create the VM without disk
|
184
|
-
vm = host.create_vm :vm_name => name,
|
315
|
+
vm = host.create_vm :vm_name => name,
|
185
316
|
:datastore => datastore, :disk_type => :flat, :memory => memory,
|
186
317
|
:disk_size => disk_size,
|
187
318
|
:guest_id => guest_id, :nics => [{:mac_address => mac_address, :network => vm_network}]
|
@@ -196,7 +327,7 @@ class CreateVMCommand < BaseCommand
|
|
196
327
|
puts
|
197
328
|
df = tmpfile
|
198
329
|
rescue Exception => e
|
199
|
-
FileUtils.rm_f(tmpfile)
|
330
|
+
FileUtils.rm_f(tmpfile)
|
200
331
|
$stderr.puts "Error downloading file from #{downloaded_file}."
|
201
332
|
$stderr.puts e.message if debug?
|
202
333
|
exit 1
|
@@ -220,10 +351,10 @@ class CreateVMCommand < BaseCommand
|
|
220
351
|
|
221
352
|
if not downloaded_file.nil?
|
222
353
|
puts "Deleting tmp file #{df}" if debug?
|
223
|
-
FileUtils.rm_f(df)
|
354
|
+
FileUtils.rm_f(df)
|
224
355
|
end
|
225
|
-
vm = host.create_vm :vm_name => name,
|
226
|
-
:disk_file => "#{name}/#{name}.vmdk",
|
356
|
+
vm = host.create_vm :vm_name => name,
|
357
|
+
:disk_file => "#{name}/#{name}.vmdk",
|
227
358
|
:datastore => datastore, :disk_type => :flat, :memory => memory,
|
228
359
|
:guest_id => guest_id, :nics => [{mac_address => mac_address, :network => vm_network}]
|
229
360
|
end
|
@@ -233,7 +364,7 @@ class CreateVMCommand < BaseCommand
|
|
233
364
|
end
|
234
365
|
|
235
366
|
def report_progress(progress, total, show_parts=true)
|
236
|
-
line_reset = "\r\e[0K"
|
367
|
+
line_reset = "\r\e[0K"
|
237
368
|
percent = (progress.to_f / total.to_f) * 100
|
238
369
|
line = "Progress: #{percent.to_i}%"
|
239
370
|
line << " (#{progress} / #{total})" if show_parts
|
@@ -284,11 +415,14 @@ class CreateVMCommand < BaseCommand
|
|
284
415
|
end
|
285
416
|
|
286
417
|
class DefaultCommand < Clamp::Command
|
287
|
-
default_subcommand
|
418
|
+
self.default_subcommand="info"
|
419
|
+
subcommand "info", "Display host info", InfoCommand
|
288
420
|
subcommand "create-vm", "Create a VM", CreateVMCommand
|
289
421
|
subcommand "poweron-vm", "Power On a VM", PowerOnVMCommand
|
290
422
|
subcommand "poweroff-vm", "Power Off a VM", PowerOffVMCommand
|
291
423
|
subcommand "destroy-vm", "Destroy VM", DestroyVMCommand
|
424
|
+
subcommand "add-nic", "Add NIC to a VM", AddNICCommand
|
425
|
+
subcommand "delete-nic", "Delete NIC from a VM", DeleteNICCommand
|
292
426
|
end
|
293
427
|
|
294
428
|
begin
|
data/lib/esx.rb
CHANGED
@@ -3,11 +3,12 @@ require 'rbvmomi'
|
|
3
3
|
require 'alchemist'
|
4
4
|
require 'net/scp'
|
5
5
|
require 'net/ssh'
|
6
|
+
require 'erb'
|
6
7
|
|
7
8
|
module ESX
|
8
9
|
|
9
|
-
VERSION = '0.4.
|
10
|
-
|
10
|
+
VERSION = '0.4.2'
|
11
|
+
|
11
12
|
if !defined? Log or Log.nil?
|
12
13
|
Log = Logger.new($stdout)
|
13
14
|
Log.formatter = proc do |severity, datetime, progname, msg|
|
@@ -20,7 +21,7 @@ module ESX
|
|
20
21
|
|
21
22
|
class Host
|
22
23
|
|
23
|
-
attr_reader :address, :user, :password
|
24
|
+
attr_reader :address, :user, :password, :free_license
|
24
25
|
attr_accessor :templates_dir
|
25
26
|
|
26
27
|
def initialize(address, user, password, opts = {})
|
@@ -28,6 +29,10 @@ module ESX
|
|
28
29
|
@password = password
|
29
30
|
@user = user
|
30
31
|
@templates_dir = opts[:templates_dir] || "/vmfs/volumes/datastore1/esx-gem/templates"
|
32
|
+
@free_license = opts[:free_license] || false
|
33
|
+
if @free_license and !@user.eql?"root"
|
34
|
+
raise Exception.new("Can't use Free License mode with user #{@user}. Please use 'root' user.")
|
35
|
+
end
|
31
36
|
end
|
32
37
|
|
33
38
|
# Connect to a ESX host
|
@@ -35,9 +40,9 @@ module ESX
|
|
35
40
|
# Requires hostname/ip, username and password
|
36
41
|
#
|
37
42
|
# Host connection is insecure by default
|
38
|
-
|
43
|
+
def self.connect(host, user, password, insecure = true, opts = {})
|
39
44
|
vim = RbVmomi::VIM.connect :host => host, :user => user, :password => password, :insecure => insecure
|
40
|
-
host = Host.new(host, user,password)
|
45
|
+
host = Host.new(host, user,password, opts)
|
41
46
|
host.vim = vim
|
42
47
|
host
|
43
48
|
end
|
@@ -77,16 +82,16 @@ module ESX
|
|
77
82
|
def power_state
|
78
83
|
@_host.summary.runtime.powerState
|
79
84
|
end
|
80
|
-
|
81
|
-
# Host memory usage in bytes
|
82
|
-
#
|
85
|
+
|
86
|
+
# Host memory usage in bytes
|
87
|
+
#
|
83
88
|
# returns a Fixnum
|
84
89
|
#
|
85
90
|
def memory_usage
|
86
91
|
@_host.summary.quickStats.overallMemoryUsage * 1024 * 1024
|
87
92
|
end
|
88
93
|
|
89
|
-
|
94
|
+
|
90
95
|
# Return a list of ESX::Datastore objects available in this host
|
91
96
|
#
|
92
97
|
def datastores
|
@@ -98,7 +103,7 @@ module ESX
|
|
98
103
|
end
|
99
104
|
|
100
105
|
# Create a Virtual Machine
|
101
|
-
#
|
106
|
+
#
|
102
107
|
# Requires a Hash with the following keys:
|
103
108
|
#
|
104
109
|
# {
|
@@ -112,7 +117,7 @@ module ESX
|
|
112
117
|
# :disk_type => flat, sparse (default flat)
|
113
118
|
# }
|
114
119
|
#
|
115
|
-
# supported guest_id list:
|
120
|
+
# supported guest_id list:
|
116
121
|
# http://pubs.vmware.com/vsphere-50/index.jsp?topic=/com.vmware.wssdk.apiref.doc_50/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html
|
117
122
|
#
|
118
123
|
# Default values above.
|
@@ -153,7 +158,7 @@ module ESX
|
|
153
158
|
}
|
154
159
|
]
|
155
160
|
}
|
156
|
-
|
161
|
+
|
157
162
|
#Add multiple nics
|
158
163
|
nics_count = 0
|
159
164
|
if spec[:nics]
|
@@ -162,19 +167,35 @@ module ESX
|
|
162
167
|
{
|
163
168
|
:operation => :add,
|
164
169
|
:device => RbVmomi::VIM.VirtualE1000(create_net_dev(nics_count, nic_spec))
|
165
|
-
|
170
|
+
|
166
171
|
}
|
167
172
|
)
|
168
173
|
nics_count += 1
|
169
174
|
end
|
170
175
|
end
|
171
176
|
# VMDK provided, replace the empty vmdk
|
172
|
-
vm_cfg[:deviceChange].push(create_disk_spec(:disk_file => spec[:disk_file],
|
177
|
+
vm_cfg[:deviceChange].push(create_disk_spec(:disk_file => spec[:disk_file],
|
173
178
|
:disk_type => spec[:disk_type],
|
174
179
|
:disk_size => spec[:disk_size],
|
175
180
|
:datastore => spec[:datastore]))
|
176
181
|
|
177
|
-
|
182
|
+
unless @free_license
|
183
|
+
VM.wrap(@_datacenter.vmFolder.CreateVM_Task(:config => vm_cfg, :pool => @_datacenter.hostFolder.children.first.resourcePool).wait_for_completion,self)
|
184
|
+
else
|
185
|
+
gem_root = Gem::Specification.find_by_name("esx").gem_dir
|
186
|
+
template_path = File.join(gem_root, 'templates', 'vmx_template.erb')
|
187
|
+
erb = ERB.new File.read(template_path)
|
188
|
+
vmx = erb.result binding
|
189
|
+
tmp_vmx = Tempfile.new 'vmx'
|
190
|
+
tmp_vmx.write vmx
|
191
|
+
tmp_vmx.close
|
192
|
+
ds = spec[:datastore]||'datastore1'
|
193
|
+
ds = ds.gsub('[','').gsub(']','')
|
194
|
+
vmx_path = "/vmfs/volumes/#{ds}/#{spec[:vm_name]}/#{spec[:vm_name]}.vmx"
|
195
|
+
upload_file tmp_vmx.path, vmx_path
|
196
|
+
remote_command "vim-cmd solo/registervm #{vmx_path}"
|
197
|
+
VM.wrap(@_datacenter.find_vm(spec[:vm_name]),self)
|
198
|
+
end
|
178
199
|
end
|
179
200
|
|
180
201
|
def create_net_dev(nic_id, spec)
|
@@ -199,10 +220,10 @@ module ESX
|
|
199
220
|
end
|
200
221
|
|
201
222
|
# Return product info as an array of strings containing
|
202
|
-
#
|
223
|
+
#
|
203
224
|
# fullName, apiType, apiVersion, osType, productLineId, vendor, version
|
204
|
-
#
|
205
|
-
def host_info
|
225
|
+
#
|
226
|
+
def host_info
|
206
227
|
[
|
207
228
|
@_host.summary.config.product.fullName,
|
208
229
|
@_host.summary.config.product.apiType,
|
@@ -215,11 +236,11 @@ module ESX
|
|
215
236
|
end
|
216
237
|
|
217
238
|
# Return a list of VM available in the inventory
|
218
|
-
#
|
239
|
+
#
|
219
240
|
def virtual_machines
|
220
241
|
vms = []
|
221
|
-
vm = @_datacenter.vmFolder.childEntity.each do |x|
|
222
|
-
vms << VM.wrap(x)
|
242
|
+
vm = @_datacenter.vmFolder.childEntity.each do |x|
|
243
|
+
vms << VM.wrap(x,self)
|
223
244
|
end
|
224
245
|
vms
|
225
246
|
end
|
@@ -283,8 +304,8 @@ module ESX
|
|
283
304
|
Net::SSH.start(@address, @user, :password => @password) do |ssh|
|
284
305
|
if (ssh.exec! "ls #{template} 2>/dev/null").nil?
|
285
306
|
Log.error "Template #{template_disk} does not exist"
|
286
|
-
raise "Template does not exist"
|
287
|
-
end
|
307
|
+
raise "Template does not exist"
|
308
|
+
end
|
288
309
|
ssh.exec!("rm -f #{template} && rm -f #{template_flat} 2>&1")
|
289
310
|
end
|
290
311
|
end
|
@@ -296,7 +317,7 @@ module ESX
|
|
296
317
|
return dest_file if template_exist?(dest_file)
|
297
318
|
Net::SSH.start(@address, @user, :password => @password) do |ssh|
|
298
319
|
if (ssh.exec! "ls -la #{@templates_dir} 2>/dev/null").nil?
|
299
|
-
# Create template dir
|
320
|
+
# Create template dir
|
300
321
|
Log.debug "Creating templates dir #{@templates_dir}"
|
301
322
|
ssh.exec "mkdir -p #{@templates_dir}"
|
302
323
|
end
|
@@ -326,7 +347,7 @@ module ESX
|
|
326
347
|
#
|
327
348
|
# if params has :use_template => true, the disk is saved as a template in
|
328
349
|
# @templates_dir and cloned from there.
|
329
|
-
#
|
350
|
+
#
|
330
351
|
# Destination directory must exist otherwise rises exception
|
331
352
|
#
|
332
353
|
def import_disk(source, destination, print_progress = false, params = {})
|
@@ -367,7 +388,11 @@ module ESX
|
|
367
388
|
end
|
368
389
|
end
|
369
390
|
end
|
370
|
-
|
391
|
+
|
392
|
+
def datacenter
|
393
|
+
@_datacenter
|
394
|
+
end
|
395
|
+
|
371
396
|
private
|
372
397
|
#
|
373
398
|
# disk_file
|
@@ -385,7 +410,7 @@ module ESX
|
|
385
410
|
datastore = params[:datastore]
|
386
411
|
datastore = datastore + " #{disk_file}" if not disk_file.nil?
|
387
412
|
spec = {}
|
388
|
-
if disk_type == :sparse
|
413
|
+
if disk_type == :sparse
|
389
414
|
spec = {
|
390
415
|
:operation => :add,
|
391
416
|
:device => RbVmomi::VIM.VirtualDisk(
|
@@ -417,52 +442,71 @@ module ESX
|
|
417
442
|
|
418
443
|
class VM
|
419
444
|
|
420
|
-
attr_accessor :memory_size, :cpus, :ethernet_cards_number
|
421
|
-
attr_accessor :name, :virtual_disks_number, :vm_object
|
445
|
+
attr_accessor :memory_size, :cpus, :ethernet_cards_number, :vmid
|
446
|
+
attr_accessor :name, :virtual_disks_number, :vm_object, :host
|
422
447
|
|
423
448
|
# Wraps a RbVmomi::VirtualMachine object
|
424
449
|
#
|
425
450
|
# **This method should never be called manually.**
|
426
451
|
#
|
427
|
-
def self.wrap(vm)
|
452
|
+
def self.wrap(vm,host)
|
428
453
|
_vm = VM.new
|
429
454
|
_vm.name = vm.name
|
430
455
|
## HACK: for some reason vm.summary.config.memorySizeMB returns nil
|
431
456
|
# under some conditions
|
432
457
|
_vm.memory_size = vm.summary.config.memorySizeMB*1024*1024 rescue 0
|
433
458
|
_vm.cpus = vm.summary.config.numCpu
|
434
|
-
_vm.ethernet_cards_number = vm.summary.config.numEthernetCards
|
459
|
+
_vm.ethernet_cards_number = vm.summary.config.numEthernetCards
|
435
460
|
_vm.virtual_disks_number = vm.summary.config.numVirtualDisks
|
436
461
|
_vm.vm_object = vm
|
462
|
+
_vm.host = host
|
463
|
+
_vm.vmid = vm.to_s.scan(/\"([0-9]+)\"/).flatten.first
|
437
464
|
_vm
|
438
465
|
end
|
439
466
|
|
440
467
|
# Returns the state of the VM as a string
|
441
468
|
# 'poweredOff', 'poweredOn'
|
442
|
-
#
|
469
|
+
#
|
443
470
|
def power_state
|
444
471
|
vm_object.summary.runtime.powerState
|
445
472
|
end
|
446
473
|
|
447
474
|
# Power On a VM
|
448
475
|
def power_on
|
449
|
-
|
476
|
+
unless host.free_license
|
477
|
+
vm_object.PowerOnVM_Task.wait_for_completion
|
478
|
+
else
|
479
|
+
host.remote_command "vim-cmd vmsvc/power.on #{vmid}"
|
480
|
+
end
|
450
481
|
end
|
451
482
|
|
452
483
|
# Power Off a VM
|
453
484
|
def power_off
|
454
|
-
|
485
|
+
unless host.free_license
|
486
|
+
vm_object.PowerOffVM_Task.wait_for_completion
|
487
|
+
else
|
488
|
+
host.remote_command "vim-cmd vmsvc/power.off #{vmid}"
|
489
|
+
end
|
455
490
|
end
|
456
491
|
|
457
492
|
# Destroy the VirtualMaching removing it from the inventory
|
458
493
|
# and deleting the disk files
|
459
494
|
def destroy
|
460
495
|
#disks = vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
|
461
|
-
|
496
|
+
unless host.free_license
|
497
|
+
vm_object.Destroy_Task.wait_for_completion
|
498
|
+
else
|
499
|
+
host.remote_command "vim-cmd vmsvc/power.off #{vmid}"
|
500
|
+
host.remote_command "vim-cmd vmsvc/destroy #{vmid}"
|
501
|
+
end
|
462
502
|
end
|
463
503
|
|
464
504
|
def reset
|
465
|
-
|
505
|
+
unless host.free_license
|
506
|
+
vm_object.ResetVM_Task.wait_for_completion
|
507
|
+
else
|
508
|
+
host.remote_command "vim-cmd vmsvc/power.reset #{vmid}"
|
509
|
+
end
|
466
510
|
end
|
467
511
|
|
468
512
|
def guest_info
|
@@ -487,7 +531,7 @@ module ESX
|
|
487
531
|
end
|
488
532
|
|
489
533
|
class NetworkInterface
|
490
|
-
|
534
|
+
|
491
535
|
attr_accessor :_wrapped_object
|
492
536
|
|
493
537
|
# Accepts VirtualEthernetCard and GuestNicInfo objects
|
@@ -509,7 +553,7 @@ module ESX
|
|
509
553
|
end
|
510
554
|
|
511
555
|
def mac
|
512
|
-
_wrapped_object.macAddress
|
556
|
+
_wrapped_object.macAddress
|
513
557
|
end
|
514
558
|
|
515
559
|
end
|
@@ -527,7 +571,7 @@ module ESX
|
|
527
571
|
def ip_address
|
528
572
|
_wrapped_object.ipAddress
|
529
573
|
end
|
530
|
-
|
574
|
+
|
531
575
|
def nics
|
532
576
|
n = []
|
533
577
|
_wrapped_object.net.each do |nic|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
.encoding = "UTF-8"
|
2
|
+
config.version = "8"
|
3
|
+
virtualHW.version = "7"
|
4
|
+
vmci0.present = "true"
|
5
|
+
displayName = "<%= spec[:vm_name] %>"
|
6
|
+
numvcpus = "<%= spec[:cpus] %>"
|
7
|
+
memsize = "<%= spec[:memory] %>"
|
8
|
+
scsi0.present = "true"
|
9
|
+
scsi0.sharedBus = "none"
|
10
|
+
scsi0.virtualDev = "lsilogic"
|
11
|
+
scsi0:0.present = "true"
|
12
|
+
scsi0:0.fileName = "<%= spec[:disk_file].split("/").last %>"
|
13
|
+
scsi0:0.deviceType = "scsi-hardDisk"
|
14
|
+
guestOS = <%= spec[:guest_id] %>
|
15
|
+
floppy0.present = "FALSE"
|
16
|
+
<% spec[:nics].each_with_index do |nic,index| %>
|
17
|
+
ethernet<%= index %>.present = "true"
|
18
|
+
ethernet<%= index %>.virtualDev = "e1000"
|
19
|
+
ethernet<%= index %>.wakeOnPcktRcv = "false"
|
20
|
+
ethernet<%= index %>.networkName = "<%= nic[:network] %>"
|
21
|
+
<% if nic[:mac_address] %>
|
22
|
+
ethernet<%= index %>.addressType = "static"
|
23
|
+
ethernet<%= index %>.address = "<%= nic[:mac_address] %>"
|
24
|
+
<% else %>
|
25
|
+
ethernet<%= index %>.addressType = "generated"
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
metadata
CHANGED
@@ -1,19 +1,84 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: esx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Sergio Rubio
|
9
|
+
- Massimo Maino
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
+
date: 2012-12-08 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: net-ssh
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: net-scp
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rbvmomi
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: alchemist
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
14
79
|
- !ruby/object:Gem::Dependency
|
15
80
|
name: rspec
|
16
|
-
requirement:
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
17
82
|
none: false
|
18
83
|
requirements:
|
19
84
|
- - ! '>='
|
@@ -21,21 +86,31 @@ dependencies:
|
|
21
86
|
version: '0'
|
22
87
|
type: :development
|
23
88
|
prerelease: false
|
24
|
-
version_requirements:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
25
95
|
- !ruby/object:Gem::Dependency
|
26
96
|
name: bundler
|
27
|
-
requirement:
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
28
98
|
none: false
|
29
99
|
requirements:
|
30
|
-
- -
|
100
|
+
- - ! '>'
|
31
101
|
- !ruby/object:Gem::Version
|
32
102
|
version: 1.0.0
|
33
103
|
type: :development
|
34
104
|
prerelease: false
|
35
|
-
version_requirements:
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>'
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.0.0
|
36
111
|
- !ruby/object:Gem::Dependency
|
37
112
|
name: jeweler
|
38
|
-
requirement:
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
39
114
|
none: false
|
40
115
|
requirements:
|
41
116
|
- - ! '>='
|
@@ -43,10 +118,15 @@ dependencies:
|
|
43
118
|
version: '0'
|
44
119
|
type: :development
|
45
120
|
prerelease: false
|
46
|
-
version_requirements:
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
47
127
|
- !ruby/object:Gem::Dependency
|
48
128
|
name: simplecov
|
49
|
-
requirement:
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
50
130
|
none: false
|
51
131
|
requirements:
|
52
132
|
- - ! '>='
|
@@ -54,10 +134,15 @@ dependencies:
|
|
54
134
|
version: '0'
|
55
135
|
type: :development
|
56
136
|
prerelease: false
|
57
|
-
version_requirements:
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
58
143
|
- !ruby/object:Gem::Dependency
|
59
144
|
name: alchemist
|
60
|
-
requirement:
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
61
146
|
none: false
|
62
147
|
requirements:
|
63
148
|
- - ! '>='
|
@@ -65,10 +150,15 @@ dependencies:
|
|
65
150
|
version: '0'
|
66
151
|
type: :runtime
|
67
152
|
prerelease: false
|
68
|
-
version_requirements:
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ! '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
69
159
|
- !ruby/object:Gem::Dependency
|
70
160
|
name: rbvmomi
|
71
|
-
requirement:
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
72
162
|
none: false
|
73
163
|
requirements:
|
74
164
|
- - ! '>='
|
@@ -76,10 +166,15 @@ dependencies:
|
|
76
166
|
version: '0'
|
77
167
|
type: :runtime
|
78
168
|
prerelease: false
|
79
|
-
version_requirements:
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
none: false
|
171
|
+
requirements:
|
172
|
+
- - ! '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
80
175
|
- !ruby/object:Gem::Dependency
|
81
176
|
name: terminal-table
|
82
|
-
requirement:
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
83
178
|
none: false
|
84
179
|
requirements:
|
85
180
|
- - ! '>='
|
@@ -87,10 +182,15 @@ dependencies:
|
|
87
182
|
version: '0'
|
88
183
|
type: :runtime
|
89
184
|
prerelease: false
|
90
|
-
version_requirements:
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
187
|
+
requirements:
|
188
|
+
- - ! '>='
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: '0'
|
91
191
|
- !ruby/object:Gem::Dependency
|
92
192
|
name: net-ssh
|
93
|
-
requirement:
|
193
|
+
requirement: !ruby/object:Gem::Requirement
|
94
194
|
none: false
|
95
195
|
requirements:
|
96
196
|
- - ! '>='
|
@@ -98,10 +198,15 @@ dependencies:
|
|
98
198
|
version: '0'
|
99
199
|
type: :runtime
|
100
200
|
prerelease: false
|
101
|
-
version_requirements:
|
201
|
+
version_requirements: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
203
|
+
requirements:
|
204
|
+
- - ! '>='
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
102
207
|
- !ruby/object:Gem::Dependency
|
103
208
|
name: net-scp
|
104
|
-
requirement:
|
209
|
+
requirement: !ruby/object:Gem::Requirement
|
105
210
|
none: false
|
106
211
|
requirements:
|
107
212
|
- - ! '>='
|
@@ -109,10 +214,15 @@ dependencies:
|
|
109
214
|
version: '0'
|
110
215
|
type: :runtime
|
111
216
|
prerelease: false
|
112
|
-
version_requirements:
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
218
|
+
none: false
|
219
|
+
requirements:
|
220
|
+
- - ! '>='
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
113
223
|
- !ruby/object:Gem::Dependency
|
114
224
|
name: clamp
|
115
|
-
requirement:
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
116
226
|
none: false
|
117
227
|
requirements:
|
118
228
|
- - ! '>='
|
@@ -120,7 +230,12 @@ dependencies:
|
|
120
230
|
version: '0'
|
121
231
|
type: :runtime
|
122
232
|
prerelease: false
|
123
|
-
version_requirements:
|
233
|
+
version_requirements: !ruby/object:Gem::Requirement
|
234
|
+
none: false
|
235
|
+
requirements:
|
236
|
+
- - ! '>='
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
version: '0'
|
124
239
|
description: Manage VMWare ESX hosts with ease
|
125
240
|
email: rubiojr@frameos.org
|
126
241
|
executables:
|
@@ -133,6 +248,7 @@ files:
|
|
133
248
|
- .document
|
134
249
|
- CHANGELOG.md
|
135
250
|
- Gemfile
|
251
|
+
- Gemfile.lock
|
136
252
|
- LICENSE.txt
|
137
253
|
- README.md
|
138
254
|
- Rakefile
|
@@ -142,6 +258,7 @@ files:
|
|
142
258
|
- spec/spec_helper.rb
|
143
259
|
- spec/unit/host_spec.rb
|
144
260
|
- spec/unit/vm_spec.rb
|
261
|
+
- templates/vmx_template.erb
|
145
262
|
homepage: http://github.com/rubiojr/esx
|
146
263
|
licenses:
|
147
264
|
- MIT
|
@@ -163,7 +280,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
163
280
|
version: '0'
|
164
281
|
requirements: []
|
165
282
|
rubyforge_project:
|
166
|
-
rubygems_version: 1.8.
|
283
|
+
rubygems_version: 1.8.24
|
167
284
|
signing_key:
|
168
285
|
specification_version: 3
|
169
286
|
summary: Simple RbVmomi wrapper library to manage VMWare ESX hosts
|