esx 0.2.4 → 0.3.1

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/README.md CHANGED
@@ -102,6 +102,8 @@ __esx create-vm --user root --password foo --name esx-rubiojr --disk-file /path/
102
102
 
103
103
  # Testing
104
104
 
105
+ Run 'bundler install' to install required deps.
106
+
105
107
  Run rspec from the base dir. By default, the tests try to connect to an ESX host named esx-test-host with user root and no password. Edit spec/spec_helper.rb to fit your needs.
106
108
 
107
109
  # Copyright
data/bin/esx CHANGED
@@ -71,15 +71,96 @@ class InfoCommand < BaseCommand
71
71
  end
72
72
  end
73
73
 
74
+ class DestroyVMCommand < BaseCommand
75
+
76
+ parameter "ADDRESS", "ESX host address"
77
+ option "--vm-name", "VM_NAME", "Virtual Machine to destroy"
78
+
79
+ def execute
80
+ begin
81
+ host = ESX::Host.connect address, user, password
82
+ host.virtual_machines.each do |vm|
83
+ if vm.name == vm_name
84
+ print "Destroying Virtual Machine '#{vm.name}'..."
85
+ vm.power_off unless vm.power_state == 'poweredOff'
86
+ vm.destroy
87
+ puts "Done."
88
+ end
89
+ end
90
+ rescue Exception => e
91
+ $stderr.puts "Can't connect to the host #{address}."
92
+ if debug?
93
+ $stderr.puts e.message
94
+ end
95
+ exit 1
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ class PowerOffVMCommand < BaseCommand
102
+
103
+ parameter "ADDRESS", "ESX host address"
104
+ option "--vm-name", "VM_NAME", "Virtual Machine to Power Off"
105
+
106
+ def execute
107
+ begin
108
+ host = ESX::Host.connect address, user, password
109
+ host.virtual_machines.each do |vm|
110
+ if vm.name == vm_name and vm.power_state == 'poweredOn'
111
+ print "Powering Off VM #{vm_name}... "
112
+ vm.power_off
113
+ puts "Done."
114
+ end
115
+ end
116
+ rescue Exception => e
117
+ $stderr.puts "Can't connect to the host #{address}."
118
+ if debug?
119
+ $stderr.puts e.message
120
+ end
121
+ exit 1
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ class PowerOnVMCommand < BaseCommand
128
+
129
+ parameter "ADDRESS", "ESX host address"
130
+ option "--vm-name", "VM_NAME", "Virtual Machine to Power On"
131
+
132
+ def execute
133
+ begin
134
+ host = ESX::Host.connect address, user, password
135
+ host.virtual_machines.each do |vm|
136
+ if vm.name == vm_name and vm.power_state != 'poweredOn'
137
+ print "Powering On VM #{vm_name}... "
138
+ vm.power_on
139
+ puts "Done."
140
+ end
141
+ end
142
+ rescue Exception => e
143
+ $stderr.puts "Can't connect to the host #{address}."
144
+ if debug?
145
+ $stderr.puts e.message
146
+ end
147
+ exit 1
148
+ end
149
+ end
150
+
151
+ end
152
+
153
+
74
154
  class CreateVMCommand < BaseCommand
75
155
 
76
156
  parameter "ADDRESS", "ESX host address"
77
157
  option "--disk-file", "DISK_FILE", "VMDK file to import", :attribute_name => :disk_file
78
- option "--disk-size", "DISK_SIZE", "VM Disk size", :attribute_name => :disk_size, :default => 8192
158
+ option "--disk-size", "DISK_SIZE", "VM Disk size in MB", :attribute_name => :disk_size, :default => 8192
79
159
  option "--guest-id", "GUEST_ID", "GuestID value", :attribute_name => :guest_id, :default => 'otherGuest'
80
160
  option "--name", "VM NAME", "Virtual Machine name (required)"
81
161
  option "--memory", "MEMORY", "VM Memory size in MB", :default => 512
82
162
  option "--mac-address", "MAC", "VM Nic1 MAC address", :default => nil
163
+ option "--vm-network", "VM NETWORK", "Network where nic is attached to", :default => 'VM Network'
83
164
  option "--tmpdir", "TMP DIR", "tmp dir used to download files", :default => "/tmp"
84
165
  option "--datastore", "DATASTORE", "Datastore used to host the disk", :default => "datastore1"
85
166
  option "--poweron", :flag, "Power on the VM after creation"
@@ -103,7 +184,7 @@ class CreateVMCommand < BaseCommand
103
184
  vm = host.create_vm :vm_name => name,
104
185
  :datastore => datastore, :disk_type => :flat, :memory => memory,
105
186
  :disk_size => disk_size,
106
- :guest_id => guest_id, :mac_address => mac_address
187
+ :guest_id => guest_id, :nics => [{:mac_address => mac_address, :network => vm_network}]
107
188
  else
108
189
  df = disk_file.dup
109
190
  if df.strip.chomp =~ /^http/
@@ -205,6 +286,9 @@ end
205
286
  class DefaultCommand < Clamp::Command
206
287
  default_subcommand "info", "Display host info", InfoCommand
207
288
  subcommand "create-vm", "Create a VM", CreateVMCommand
289
+ subcommand "poweron-vm", "Power On a VM", PowerOnVMCommand
290
+ subcommand "poweroff-vm", "Power Off a VM", PowerOffVMCommand
291
+ subcommand "destroy-vm", "Destroy VM", DestroyVMCommand
208
292
  end
209
293
 
210
294
  begin
data/lib/esx.rb CHANGED
@@ -6,7 +6,7 @@ require 'net/ssh'
6
6
 
7
7
  module ESX
8
8
 
9
- VERSION = '0.2.4'
9
+ VERSION = '0.3.1'
10
10
 
11
11
  class Host
12
12
 
@@ -44,26 +44,34 @@ module ESX
44
44
 
45
45
  # Host memory size in bytes
46
46
  #
47
+ # returns a Fixnum
48
+ #
47
49
  def memory_size
48
- @_host.hardware.memorySize
50
+ @_host.hardware.memorySize.to_i
49
51
  end
50
52
 
51
53
  # Number of CPU cores available in this host
52
54
  #
55
+ # returns a String
56
+ #
53
57
  def cpu_cores
54
58
  @_host.hardware.cpuInfo.numCpuCores
55
59
  end
56
60
 
57
61
  # Power state of this host
58
62
  #
63
+ # poweredOn, poweredOff
64
+ #
59
65
  def power_state
60
66
  @_host.summary.runtime.powerState
61
67
  end
62
68
 
63
69
  # Host memory usage in bytes
70
+ #
71
+ # returns a Fixnum
64
72
  #
65
73
  def memory_usage
66
- @_host.summary.quickStats.overallMemoryUsage.megabytes.to.bytes.to_i
74
+ @_host.summary.quickStats.overallMemoryUsage * 1024 * 1024
67
75
  end
68
76
 
69
77
 
@@ -124,10 +132,6 @@ module ESX
124
132
  :key => 1000,
125
133
  :busNumber => 0,
126
134
  :sharedBus => :noSharing)
127
- },
128
- {
129
- :operation => :add,
130
- :device => RbVmomi::VIM.VirtualE1000(create_net_dev(specification))
131
135
  }
132
136
  ],
133
137
  :extraConfig => [
@@ -137,7 +141,21 @@ module ESX
137
141
  }
138
142
  ]
139
143
  }
140
-
144
+
145
+ #Add multiple nics
146
+ nics_count = 0
147
+ if spec[:nics]
148
+ spec[:nics].each do |nic_spec|
149
+ vm_cfg[:deviceChange].push(
150
+ {
151
+ :operation => :add,
152
+ :device => RbVmomi::VIM.VirtualE1000(create_net_dev(nics_count, nic_spec))
153
+
154
+ }
155
+ )
156
+ nics_count += 1
157
+ end
158
+ end
141
159
  # VMDK provided, replace the empty vmdk
142
160
  vm_cfg[:deviceChange].push(create_disk_spec(:disk_file => spec[:disk_file],
143
161
  :disk_type => spec[:disk_type],
@@ -147,17 +165,18 @@ module ESX
147
165
  VM.wrap(@_datacenter.vmFolder.CreateVM_Task(:config => vm_cfg, :pool => @_datacenter.hostFolder.children.first.resourcePool).wait_for_completion)
148
166
  end
149
167
 
150
- def create_net_dev(spec)
168
+ def create_net_dev(nic_id, spec)
151
169
  h = {
152
- :key => 0,
170
+ :key => nic_id,
153
171
  :deviceInfo => {
154
- :label => 'Network Adapter 1',
155
- :summary => 'VM Network'
172
+ :label => "Network Adapter #{nic_id}",
173
+ :summary => spec[:network] || 'VM Network'
156
174
  },
157
175
  :backing => RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo(
158
- :deviceName => 'VM Network'
176
+ :deviceName => spec[:network] || 'VM Network'
159
177
  )
160
178
  }
179
+
161
180
  if spec[:mac_address]
162
181
  h[:macAddress] = spec[:mac_address]
163
182
  h[:addressType] = 'manual'
@@ -298,7 +317,7 @@ module ESX
298
317
  def self.wrap(vm)
299
318
  _vm = VM.new
300
319
  _vm.name = vm.name
301
- _vm.memory_size = vm.summary.config.memorySizeMB.megabytes.to.bytes
320
+ _vm.memory_size = vm.summary.config.memorySizeMB*1024*1024
302
321
  _vm.cpus = vm.summary.config.numCpu
303
322
  _vm.ethernet_cards_number = vm.summary.config.numEthernetCards
304
323
  _vm.virtual_disks_number = vm.summary.config.numVirtualDisks
@@ -324,22 +343,9 @@ module ESX
324
343
  end
325
344
 
326
345
  # Destroy the VirtualMaching removing it from the inventory
327
- #
328
- # This operation does not destroy VM disks
329
- #
346
+ # and deleting the disk files
330
347
  def destroy
331
- disks = vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
332
- #disks.select { |x| x.backing.parent == nil }.each do |disk|
333
- # spec = {
334
- # :deviceChange => [
335
- # {
336
- # :operation => :remove,
337
- # :device => disk
338
- # }
339
- # ]
340
- # }
341
- # vm_object.ReconfigVM_Task(:spec => spec).wait_for_completion
342
- #end
348
+ #disks = vm_object.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
343
349
  vm_object.Destroy_Task.wait_for_completion
344
350
  end
345
351
 
Binary file
@@ -24,4 +24,27 @@ module ESXTestHelpers
24
24
  ""
25
25
  end
26
26
 
27
+ def test_data_dir
28
+ File.dirname(__FILE__) + '/data'
29
+ end
30
+
31
+ def test_host_object
32
+ @test_host = ESX::Host.connect(esx_host, esx_user, esx_password)
33
+ end
34
+
35
+ def create_simple_vm
36
+ name = 'test1GB'
37
+ disk_size = 1024
38
+ datastore = 'datastore1'
39
+ guest_id = 'otherGuest'
40
+ memory = 512
41
+ nics = [{ :mac_address => nil, :network => nil }]
42
+
43
+ vm = test_host_object.create_vm :vm_name => name,
44
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
45
+ :disk_size => disk_size,
46
+ :guest_id => guest_id, :nics => nics
47
+ vm
48
+ end
49
+
27
50
  end
@@ -7,6 +7,12 @@ describe "ESX host" do
7
7
  @test_host = ESX::Host.connect(esx_host, esx_user, esx_password)
8
8
  end
9
9
 
10
+ after do
11
+ @test_host.virtual_machines.each do |vm|
12
+ vm.destroy
13
+ end
14
+ end
15
+
10
16
  it "connects to and ESX with a valid user/pass" do
11
17
  host = nil
12
18
  lambda do
@@ -18,4 +24,125 @@ describe "ESX host" do
18
24
  it "retrives the host name" do
19
25
  @test_host.name.should_not be_nil
20
26
  end
27
+
28
+ it "has no virtual machines" do
29
+ @test_host.virtual_machines.should be_empty
30
+ end
31
+
32
+ it "creates one one virtual machine with a 1GB empty disk, 512MB RAB, 1NIC" do
33
+ name = 'test1GB'
34
+ disk_size = 1024
35
+ datastore = 'datastore1'
36
+ guest_id = 'otherGuest'
37
+ memory = 512
38
+ nics = [{ :mac_address => nil, :network => nil }]
39
+
40
+ vm = @test_host.create_vm :vm_name => name,
41
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
42
+ :disk_size => disk_size,
43
+ :guest_id => guest_id, :nics => nics
44
+ @test_host.virtual_machines.size.should eql(1)
45
+
46
+ vm = @test_host.virtual_machines.find { |vm| vm.name == 'test1GB' }
47
+ vm.should_not be_nil
48
+ vm.memory_size.should eql(512 * 1024 * 1024)
49
+ vm.ethernet_cards_number.should eql(1)
50
+ vm.virtual_disks_number.should eql(1)
51
+ end
52
+
53
+ it "should be able to create a VM with 2 nics" do
54
+ name = 'test1GB'
55
+ disk_size = 1024
56
+ datastore = 'datastore1'
57
+ guest_id = 'otherGuest'
58
+ memory = 512
59
+ nics = [{ :mac_address => nil, :network => nil }, { :mac_address => nil, :network => nil }]
60
+
61
+ vm = @test_host.create_vm :vm_name => name,
62
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
63
+ :disk_size => disk_size,
64
+ :guest_id => guest_id, :nics => nics
65
+
66
+ vm.ethernet_cards_number.should eql(2)
67
+ end
68
+
69
+ it "should create a VM with 0 NICs if no NIC config is specified" do
70
+ name = 'test1GB'
71
+ disk_size = 1024
72
+ datastore = 'datastore1'
73
+ guest_id = 'otherGuest'
74
+ memory = 512
75
+
76
+ vm = @test_host.create_vm :vm_name => name,
77
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
78
+ :disk_size => disk_size,
79
+ :guest_id => guest_id
80
+
81
+ vm.ethernet_cards_number.should eql(0)
82
+ end
83
+
84
+ it "should create a VM with 1 NICs and an autogenerated MAC address" do
85
+ name = 'test1GB'
86
+ disk_size = 1024
87
+ datastore = 'datastore1'
88
+ guest_id = 'otherGuest'
89
+ memory = 512
90
+ nics = [{}]
91
+
92
+ vm = @test_host.create_vm :vm_name => name,
93
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
94
+ :disk_size => disk_size,
95
+ :guest_id => guest_id, :nics => nics
96
+
97
+ vm.ethernet_cards_number.should eql(1)
98
+ vm.nics.first.mac.should eql("")
99
+ end
100
+
101
+ it "has an array of datastores with one datastore named datastore1" do
102
+ @test_host.datastores.is_a?(Array).should be_true
103
+ @test_host.datastores.first.should be_a ESX::Datastore
104
+ @test_host.datastores.first.name.should eql('datastore1')
105
+ end
106
+
107
+ it "should be able to create and destroy a VM" do
108
+ name = 'test1GB'
109
+ disk_size = 1024
110
+ datastore = 'datastore1'
111
+ guest_id = 'otherGuest'
112
+ memory = 512
113
+ nics = [{ :mac_address => nil, :network => nil }]
114
+
115
+ vm = @test_host.create_vm :vm_name => name,
116
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
117
+ :disk_size => disk_size,
118
+ :guest_id => guest_id, :nics => nics
119
+ @test_host.virtual_machines.size.should eql(1)
120
+ vm = @test_host.virtual_machines.find { |vm| vm.name == 'test1GB' }
121
+ vm.destroy
122
+ @test_host.virtual_machines.size.should eql(0)
123
+ end
124
+
125
+ it "should be able to create a VM with a custom MAC address" do
126
+ name = 'test1GB'
127
+ disk_size = 1024
128
+ datastore = 'datastore1'
129
+ guest_id = 'otherGuest'
130
+ memory = 512
131
+ nics = [{ :mac_address => '00:01:02:03:04:05', :network => nil }]
132
+
133
+ vm = @test_host.create_vm :vm_name => name,
134
+ :datastore => datastore, :disk_type => :flat, :memory => memory,
135
+ :disk_size => disk_size,
136
+ :guest_id => guest_id, :nics => nics
137
+ vm = @test_host.virtual_machines.find { |vm| vm.name == name }
138
+ vm.nics.first.mac.should eql('00:01:02:03:04:05')
139
+ end
140
+
141
+ it "should have valid property types" do
142
+ @test_host.memory_size.should be_a Fixnum
143
+ @test_host.memory_size.should be > 0
144
+ @test_host.memory_usage.should be_a Fixnum
145
+ @test_host.memory_usage.should be > 0
146
+ end
147
+
21
148
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ESX Virtual Machine" do
4
+ include ESXTestHelpers
5
+
6
+ before do
7
+ @test_host = ESX::Host.connect(esx_host, esx_user, esx_password)
8
+ end
9
+
10
+ after do
11
+ @test_host.virtual_machines.each do |vm|
12
+ vm.destroy
13
+ end
14
+ end
15
+
16
+ it "should have an Array of NetworkInterfaces" do
17
+ vm = create_simple_vm
18
+ vm.nics.size.should eql(1)
19
+ vm.nics.first.should be_a ESX::NetworkInterface
20
+ end
21
+
22
+ it "should have valid property types" do
23
+ vm = create_simple_vm
24
+ vm.memory_size.should be_a Fixnum
25
+ vm.memory_size.should be > 0
26
+ vm.nics.should be_an Array
27
+ vm.power_state.should be_a String
28
+ end
29
+
30
+ end
31
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: esx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-29 00:00:00.000000000 Z
12
+ date: 2012-01-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &11459820 !ruby/object:Gem::Requirement
16
+ requirement: &17898020 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *11459820
24
+ version_requirements: *17898020
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &11457160 !ruby/object:Gem::Requirement
27
+ requirement: &17894660 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *11457160
35
+ version_requirements: *17894660
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jeweler
38
- requirement: &11469480 !ruby/object:Gem::Requirement
38
+ requirement: &17928200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *11469480
46
+ version_requirements: *17928200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: simplecov
49
- requirement: &11467120 !ruby/object:Gem::Requirement
49
+ requirement: &17926060 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *11467120
57
+ version_requirements: *17926060
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: alchemist
60
- requirement: &11497120 !ruby/object:Gem::Requirement
60
+ requirement: &17922780 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *11497120
68
+ version_requirements: *17922780
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rbvmomi
71
- requirement: &11493140 !ruby/object:Gem::Requirement
71
+ requirement: &17949440 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *11493140
79
+ version_requirements: *17949440
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: terminal-table
82
- requirement: &11584320 !ruby/object:Gem::Requirement
82
+ requirement: &17947300 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *11584320
90
+ version_requirements: *17947300
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: net-ssh
93
- requirement: &11582280 !ruby/object:Gem::Requirement
93
+ requirement: &17945200 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *11582280
101
+ version_requirements: *17945200
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: net-scp
104
- requirement: &11580560 !ruby/object:Gem::Requirement
104
+ requirement: &17942780 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :runtime
111
111
  prerelease: false
112
- version_requirements: *11580560
112
+ version_requirements: *17942780
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: clamp
115
- requirement: &11578480 !ruby/object:Gem::Requirement
115
+ requirement: &17969780 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '0'
121
121
  type: :runtime
122
122
  prerelease: false
123
- version_requirements: *11578480
123
+ version_requirements: *17969780
124
124
  description: Manage VMWare ESX hosts with ease
125
125
  email: rubiojr@frameos.org
126
126
  executables:
@@ -138,8 +138,10 @@ files:
138
138
  - bin/esx
139
139
  - examples/basics.rb
140
140
  - lib/esx.rb
141
+ - spec/data/tc.vmdk
141
142
  - spec/spec_helper.rb
142
143
  - spec/unit/host_spec.rb
144
+ - spec/unit/vm_spec.rb
143
145
  homepage: http://github.com/rubiojr/esx
144
146
  licenses:
145
147
  - MIT