rbvmomi 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  RbVmomi is a Ruby interface to the vSphere API. Like the Perl and Java SDKs,
6
6
  you can use it to manage ESX and VirtualCenter servers. The current release
7
- supports the vSphere 4.1 API. RbVmomi specific documentation is
7
+ supports the vSphere 5.0 API. RbVmomi specific documentation is
8
8
  online[http://rdoc.info/github/rlane/rbvmomi/master/frames] and is meant to
9
9
  be used alongside the official documentation[http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/index.html].
10
10
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.3
1
+ 1.3.0
@@ -49,6 +49,6 @@ case cmd
49
49
  when 'list'
50
50
  vm.config.extraConfig.each { |x| puts "#{x.key}: #{x.value}" }
51
51
  when 'set'
52
- extraConfig = ARGV.map { |x| x.split("=", 2) }.map { |k,v| { :key => k, :value => v } }
52
+ extraConfig = ARGV[2..-1].map { |x| x.split("=", 2) }.map { |k,v| { :key => k, :value => v } }
53
53
  vm.ReconfigVM_Task(:spec => VIM.VirtualMachineConfigSpec(:extraConfig => extraConfig)).wait_for_completion
54
54
  end
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ require 'trollop'
3
+ require 'rbvmomi'
4
+ require 'rbvmomi/trollop'
5
+
6
+ VIM = RbVmomi::VIM
7
+ CMDS = %w(mount unmount)
8
+
9
+ opts = Trollop.options do
10
+ banner <<-EOS
11
+ Mount/Unmount an NFS datastore from a cluster or single host system.
12
+
13
+ Usage:
14
+ nfs_datastore.rb [options] resource mount nfs-hostname:/remote/path [name]
15
+ nfs_datastore.rb [options] resource unmount nfs-hostname:/remote/path [name]
16
+
17
+ Commands: #{CMDS * ' '}
18
+
19
+ VIM connection options:
20
+ EOS
21
+
22
+ rbvmomi_connection_opts
23
+
24
+ text <<-EOS
25
+
26
+ VM location options:
27
+ EOS
28
+
29
+ rbvmomi_datacenter_opt
30
+
31
+ text <<-EOS
32
+
33
+ Other options:
34
+ EOS
35
+
36
+ stop_on CMDS
37
+ end
38
+
39
+ Trollop.die("must specify host") unless opts[:host]
40
+
41
+ cr_path = ARGV[0] or Trollop.die("no system name given")
42
+ cmd = ARGV[1] or Trollop.die("no command given")
43
+ abort "invalid command" unless CMDS.member? cmd
44
+ nfs_spec = ARGV[2] or Trollop.die("no nfs path given")
45
+ remoteHost, remotePath = nfs_spec.split(":")
46
+ localPath = ARGV[3] || remoteHost
47
+ mode = "readOnly" #hardcoded.
48
+
49
+ vim = VIM.connect opts
50
+ dc = vim.serviceInstance.find_datacenter(opts[:datacenter]) or abort "datacenter not found"
51
+ cr = dc.find_compute_resource(cr_path) || dc.hostFolder.children.find(cr_path).first
52
+ abort "compute resource not found" unless cr
53
+
54
+ case cr
55
+ when VIM::ClusterComputeResource
56
+ hosts = cr.host
57
+ when VIM::ComputeResource
58
+ hosts = [cr]
59
+ else
60
+ abort "invalid resource"
61
+ end
62
+
63
+ hosts.each do |host|
64
+ hds = host.configManager.datastoreSystem
65
+
66
+ ds = hds.datastore.select {|ds|
67
+ ds.info.respond_to?(:nas) and
68
+ ds.info.name == localPath and
69
+ ds.info.nas.remoteHost == remoteHost and
70
+ ds.info.nas.remotePath == remotePath
71
+ }.first
72
+
73
+ case cmd
74
+ when 'mount'
75
+ if ds
76
+ puts "already mounted on #{host.name} as #{ds.name}"
77
+ else
78
+ ds =
79
+ hds.CreateNasDatastore(:spec => VIM.HostNasVolumeSpec(:remoteHost => remoteHost,
80
+ :remotePath => remotePath,
81
+ :localPath => localPath,
82
+ :accessMode => mode))
83
+ puts "mounted on #{host.name} as #{ds.name}"
84
+ end
85
+ when 'unmount'
86
+ if ds
87
+ hds.RemoveDatastore(:datastore => ds)
88
+ puts "unmounted from #{host.name}"
89
+ else
90
+ puts "not mounted on #{host.name}"
91
+ end
92
+ else
93
+ abort "invalid command"
94
+ end
95
+ end
@@ -111,6 +111,10 @@ class DataObject < ObjectWithProperties
111
111
  @props[sym] = val
112
112
  end
113
113
 
114
+ def []= sym, val
115
+ _set_property sym, val
116
+ end
117
+
114
118
  def == o
115
119
  return false unless o.class == self.class
116
120
  keys = (props.keys + o.props.keys).uniq
@@ -165,7 +169,7 @@ class ManagedObject < ObjectWithMethods
165
169
  }])[0]
166
170
 
167
171
  if ret.propSet.empty?
168
- fail if ret.missingSet.empty?
172
+ return nil if ret.missingSet.empty?
169
173
  raise ret.missingSet[0].fault
170
174
  else
171
175
  ret.propSet[0].val
@@ -20,8 +20,17 @@ class RbVmomi::TrivialSoap
20
20
  restart_http
21
21
  end
22
22
 
23
+ def close
24
+ @http.finish rescue IOError
25
+ end
26
+
23
27
  def restart_http
24
- @http.finish if @http
28
+ begin
29
+ @http.finish if @http
30
+ rescue Exception => ex
31
+ puts "WARNING: Ignoring exception: #{ex.message}"
32
+ puts ex.backtrace.join("\n")
33
+ end
25
34
  @http = Net::HTTP.new(@opts[:host], @opts[:port], @opts[:proxyHost], @opts[:proxyPort])
26
35
  if @opts[:ssl]
27
36
  require 'net/https'
@@ -77,8 +86,12 @@ class RbVmomi::TrivialSoap
77
86
  end
78
87
  end
79
88
  end_time = Time.now
89
+
90
+ if response.is_a? Net::HTTPServiceUnavailable
91
+ raise "Got HTTP 503: Service unavailable"
92
+ end
80
93
 
81
- @cookie = response['set-cookie'] if response.key? 'set-cookie'
94
+ self.cookie = response['set-cookie'] if response.key? 'set-cookie'
82
95
 
83
96
  nk = Nokogiri(response.body)
84
97
 
@@ -1,5 +1,6 @@
1
1
  # Copyright (c) 2010 VMware, Inc. All Rights Reserved.
2
2
  require 'set'
3
+ require 'monitor'
3
4
 
4
5
  module RbVmomi
5
6
 
@@ -21,6 +22,7 @@ class TypeLoader
21
22
  def initialize target, fn
22
23
  @target = target
23
24
  @db = TypeStore.new fn
25
+ @lock = Monitor.new
24
26
  end
25
27
 
26
28
  def init
@@ -42,8 +44,10 @@ class TypeLoader
42
44
 
43
45
  def load_type name
44
46
  fail unless name.is_a? String
45
- @target.const_set name, make_type(name)
46
- load_extension name
47
+ @lock.synchronize do
48
+ @target.const_set name, make_type(name)
49
+ load_extension name
50
+ end
47
51
  nil
48
52
  end
49
53
 
data/lib/rbvmomi/vim.rb CHANGED
@@ -35,11 +35,37 @@ class VIM < Connection
35
35
  vim.serviceContent.sessionManager.Login :userName => opts[:user], :password => opts[:password]
36
36
  unless rev_given
37
37
  rev = vim.serviceContent.about.apiVersion
38
- vim.rev = [rev, '4.1'].min
38
+ vim.rev = [rev, '5.0'].min
39
39
  end
40
40
  end
41
41
  end
42
42
 
43
+ def close
44
+ VIM::SessionManager(self, 'SessionManager').Logout
45
+ super
46
+ end
47
+
48
+ def cookie= cookie
49
+ super
50
+ ObjectSpace.undefine_finalizer self
51
+ ObjectSpace.define_finalizer(self, self.class.finalizer(cookie,@opts))
52
+ end
53
+
54
+ def self.finalizer cookie, opts
55
+ proc do |object_id|
56
+ new(opts).tap do |vim|
57
+ vim.instance_variable_set :@cookie, cookie
58
+ vim.close
59
+ end
60
+ nil
61
+ end
62
+ end
63
+
64
+ def rev= x
65
+ super
66
+ @serviceContent = nil
67
+ end
68
+
43
69
  # Return the ServiceInstance
44
70
  #
45
71
  # The ServiceInstance is the root of the vSphere inventory.
@@ -75,7 +101,7 @@ class VIM < Connection
75
101
  pp.text "VIM(#{@opts[:host]})"
76
102
  end
77
103
 
78
- @extension_dirs = [File.join(File.dirname(__FILE__), "vim")]
104
+ @extension_dirs = [File.join(File.dirname(__FILE__), "vim")] + (ENV['RBVMOMI_VIM_EXTENSION_PATH']||'').split(':')
79
105
 
80
106
  # Directories to search for extensions
81
107
  def self.extension_dirs
@@ -84,6 +84,8 @@ class RbVmomi::VIM::Folder
84
84
  x
85
85
  elsif create and type == RbVmomi::VIM::Folder
86
86
  p.CreateFolder(:name => final)
87
+ elsif create and type == RbVmomi::VIM::Datacenter
88
+ p.CreateDatacenter(:name => final)
87
89
  else
88
90
  nil
89
91
  end
@@ -54,10 +54,9 @@ class RbVmomi::VIM::OvfManager
54
54
 
55
55
  nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
56
56
  raise nfcLease.error if nfcLease.state == "error"
57
-
58
57
  begin
59
58
  nfcLease.HttpNfcLeaseProgress(:percent => 5)
60
- progress = 0.0
59
+ progress = 5.0
61
60
  result.fileItem.each do |fileItem|
62
61
  deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
63
62
  if !deviceUrl
@@ -73,11 +72,26 @@ class RbVmomi::VIM::OvfManager
73
72
 
74
73
  method = fileItem.create ? "PUT" : "POST"
75
74
 
75
+ keepAliveThread = Thread.new do
76
+ while true
77
+ sleep 2 * 60
78
+ nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
79
+ end
80
+ end
81
+
76
82
  href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
77
83
  downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
78
- uploadCmd = "#{CURLBIN} -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' -H 'Content-Length: #{fileItem.size}' '#{URI::escape(href)}'"
79
- system("#{downloadCmd} | #{uploadCmd}")
80
- progress += (95.0 / result.fileItem.length)
84
+ uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
85
+ # Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
86
+ # to the uploadCmd. It is not clear to me why, but that leads to
87
+ # trucation of the uploaded disk. Without this option curl can't tell
88
+ # the progress, but who cares
89
+ system("#{downloadCmd} | #{uploadCmd}", STDOUT => "/dev/null")
90
+
91
+ keepAliveThread.kill
92
+ keepAliveThread.join
93
+
94
+ progress += (90.0 / result.fileItem.length)
81
95
  nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
82
96
  end
83
97
 
@@ -0,0 +1,23 @@
1
+ class RbVmomi::VIM::PropertyCollector
2
+ def collectMultiple objs, *pathSet
3
+ klasses = objs.map{|x| x.class}.uniq
4
+ klass = if klasses.length > 1
5
+ # common superclass
6
+ klasses.map(&:ancestors).inject(&:&)[0]
7
+ else
8
+ klasses.first
9
+ end
10
+
11
+ spec = {
12
+ :objectSet => objs.map{|x| { :obj => x }},
13
+ :propSet => [{
14
+ :pathSet => pathSet,
15
+ :type => klass.wsdl_name
16
+ }]
17
+ }
18
+ res = RetrieveProperties(:specSet => [spec])
19
+ Hash[res.map do |x|
20
+ [x.obj, x.to_hash]
21
+ end]
22
+ end
23
+ end
@@ -43,11 +43,13 @@ class RbVmomi::VIM::ServiceInstance
43
43
  end
44
44
  end
45
45
 
46
- yield task_props
46
+ yield task_props if block_given?
47
47
  end
48
48
  ensure
49
49
  @soap.propertyCollector.CancelWaitForUpdates
50
50
  filter.DestroyPropertyFilter
51
51
  end
52
+
53
+ task_props
52
54
  end
53
55
  end
@@ -4,4 +4,10 @@ class RbVmomi::VIM::VirtualMachine
4
4
  def macs
5
5
  Hash[self.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).map { |x| [x.deviceInfo.label, x.macAddress] }]
6
6
  end
7
+
8
+ # Retrieve all virtual disk devices.
9
+ # @return [Array] Array of virtual disk devices.
10
+ def disks
11
+ self.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
12
+ end
7
13
  end
data/vmodl.db CHANGED
Binary file
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rbvmomi
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.2.3
5
+ version: 1.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Rich Lane
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-05 00:00:00 -07:00
13
+ date: 2011-09-02 00:00:00 -07:00
14
14
  default_executable: rbvmomish
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -72,6 +72,7 @@ files:
72
72
  - examples/extraConfig.rb
73
73
  - examples/logbundle.rb
74
74
  - examples/logtail.rb
75
+ - examples/nfs_datastore.rb
75
76
  - examples/power.rb
76
77
  - examples/readme-1.rb
77
78
  - examples/readme-2.rb
@@ -96,6 +97,7 @@ files:
96
97
  - lib/rbvmomi/vim/ObjectContent.rb
97
98
  - lib/rbvmomi/vim/ObjectUpdate.rb
98
99
  - lib/rbvmomi/vim/OvfManager.rb
100
+ - lib/rbvmomi/vim/PropertyCollector.rb
99
101
  - lib/rbvmomi/vim/ResourcePool.rb
100
102
  - lib/rbvmomi/vim/ServiceInstance.rb
101
103
  - lib/rbvmomi/vim/Task.rb
@@ -144,6 +146,7 @@ test_files:
144
146
  - examples/extraConfig.rb
145
147
  - examples/logbundle.rb
146
148
  - examples/logtail.rb
149
+ - examples/nfs_datastore.rb
147
150
  - examples/power.rb
148
151
  - examples/readme-1.rb
149
152
  - examples/readme-2.rb