vagrant-rbvmomi 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +6 -0
- data/LICENSE +19 -0
- data/README.rdoc +78 -0
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/bin/rbvmomish +138 -0
- data/devel/analyze-vim-declarations.rb +213 -0
- data/devel/analyze-xml.rb +46 -0
- data/devel/benchmark.rb +117 -0
- data/devel/collisions.rb +18 -0
- data/devel/merge-internal-vmodl.rb +59 -0
- data/devel/merge-manual-vmodl.rb +32 -0
- data/examples/annotate.rb +54 -0
- data/examples/cached_ovf_deploy.rb +120 -0
- data/examples/clone_vm.rb +84 -0
- data/examples/create_vm-1.9.rb +93 -0
- data/examples/create_vm.rb +93 -0
- data/examples/extraConfig.rb +54 -0
- data/examples/lease_tool.rb +102 -0
- data/examples/logbundle.rb +63 -0
- data/examples/logtail.rb +60 -0
- data/examples/nfs_datastore.rb +95 -0
- data/examples/power.rb +59 -0
- data/examples/readme-1.rb +35 -0
- data/examples/readme-2.rb +51 -0
- data/examples/run.sh +41 -0
- data/examples/screenshot.rb +48 -0
- data/examples/vdf.rb +81 -0
- data/examples/vm_drs_behavior.rb +76 -0
- data/lib/rbvmomi.rb +12 -0
- data/lib/rbvmomi/basic_types.rb +375 -0
- data/lib/rbvmomi/connection.rb +270 -0
- data/lib/rbvmomi/deserialization.rb +248 -0
- data/lib/rbvmomi/fault.rb +17 -0
- data/lib/rbvmomi/pbm.rb +66 -0
- data/lib/rbvmomi/sms.rb +61 -0
- data/lib/rbvmomi/sms/SmsStorageManager.rb +7 -0
- data/lib/rbvmomi/trivial_soap.rb +114 -0
- data/lib/rbvmomi/trollop.rb +70 -0
- data/lib/rbvmomi/type_loader.rb +136 -0
- data/lib/rbvmomi/utils/admission_control.rb +398 -0
- data/lib/rbvmomi/utils/deploy.rb +336 -0
- data/lib/rbvmomi/utils/leases.rb +142 -0
- data/lib/rbvmomi/utils/perfdump.rb +628 -0
- data/lib/rbvmomi/vim.rb +128 -0
- data/lib/rbvmomi/vim/ComputeResource.rb +51 -0
- data/lib/rbvmomi/vim/Datacenter.rb +17 -0
- data/lib/rbvmomi/vim/Datastore.rb +68 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrAllTypeInfo.rb +75 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrDataTypeInfo.rb +20 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrManagedTypeInfo.rb +46 -0
- data/lib/rbvmomi/vim/Folder.rb +207 -0
- data/lib/rbvmomi/vim/HostSystem.rb +174 -0
- data/lib/rbvmomi/vim/ManagedEntity.rb +57 -0
- data/lib/rbvmomi/vim/ManagedObject.rb +60 -0
- data/lib/rbvmomi/vim/ObjectContent.rb +23 -0
- data/lib/rbvmomi/vim/ObjectUpdate.rb +23 -0
- data/lib/rbvmomi/vim/OvfManager.rb +200 -0
- data/lib/rbvmomi/vim/PerfCounterInfo.rb +26 -0
- data/lib/rbvmomi/vim/PerformanceManager.rb +110 -0
- data/lib/rbvmomi/vim/PropertyCollector.rb +25 -0
- data/lib/rbvmomi/vim/ReflectManagedMethodExecuter.rb +30 -0
- data/lib/rbvmomi/vim/ResourcePool.rb +55 -0
- data/lib/rbvmomi/vim/ServiceInstance.rb +55 -0
- data/lib/rbvmomi/vim/Task.rb +65 -0
- data/lib/rbvmomi/vim/VirtualMachine.rb +74 -0
- data/test/test_deserialization.rb +383 -0
- data/test/test_emit_request.rb +128 -0
- data/test/test_exceptions.rb +14 -0
- data/test/test_helper.rb +14 -0
- data/test/test_misc.rb +24 -0
- data/test/test_parse_response.rb +69 -0
- data/test/test_serialization.rb +311 -0
- data/vmodl.db +0 -0
- metadata +163 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
module RbVmomi
|
2
|
+
|
3
|
+
class VIM::HostSystem
|
4
|
+
def esxcli
|
5
|
+
@cached_esxcli ||= VIM::EsxcliNamespace.root(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def dtm
|
9
|
+
@cached_dtm ||= begin
|
10
|
+
RetrieveDynamicTypeManager()
|
11
|
+
rescue VIM::MethodNotFound
|
12
|
+
if summary.config.product.version >= '4.1.0'
|
13
|
+
if summary.config.product.version < '5.0.0' and direct?
|
14
|
+
VIM::InternalDynamicTypeManager(_connection, 'ha-dynamic-type-manager')
|
15
|
+
else
|
16
|
+
raise "esxcli not supported through VC before 5.0.0"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
raise "esxcli not supported before 4.1.0"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def dti
|
25
|
+
@cached_dti ||= dtm.DynamicTypeMgrQueryTypeInfo
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_dynamic_managed_object inst
|
29
|
+
wsdlName = dti.managedTypeInfo.find { |x| x.name == inst.moType }.wsdlName
|
30
|
+
_connection.type(wsdlName).new(_connection, inst.id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def cli_info_fetcher
|
34
|
+
# XXX there can be more than one
|
35
|
+
return @cached_cli_info_fetcher if @cached_cli_info_fetcher
|
36
|
+
inst = dtm.DynamicTypeMgrQueryMoInstances.find { |x| x.moType == 'vim.CLIInfo' }
|
37
|
+
@cached_cli_info_fetcher = create_dynamic_managed_object inst
|
38
|
+
end
|
39
|
+
|
40
|
+
def mme
|
41
|
+
@cached_mme ||= RetrieveManagedMethodExecuter()
|
42
|
+
end
|
43
|
+
|
44
|
+
def direct?
|
45
|
+
@ref == 'ha-host'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class VIM::EsxcliNamespace
|
50
|
+
ESXCLI_PREFIX = 'vim.EsxCLI.'
|
51
|
+
|
52
|
+
attr_reader :name, :parent, :host, :type, :instance, :type_info, :namespaces, :commands
|
53
|
+
|
54
|
+
def self.root host
|
55
|
+
type_hash = host.dti.toRbvmomiTypeHash
|
56
|
+
VIM.loader.add_types type_hash
|
57
|
+
all_instances = host.dtm.DynamicTypeMgrQueryMoInstances
|
58
|
+
instances = Hash[all_instances.select { |x| x.moType.start_with? ESXCLI_PREFIX }.
|
59
|
+
map { |x| [x.moType,x.id] }]
|
60
|
+
type_infos = Hash[host.dti.managedTypeInfo.map { |x| [x.name,x] }]
|
61
|
+
new('root', nil, host).tap do |root|
|
62
|
+
instances.each do |type,instance|
|
63
|
+
path = type.split('.')[2..-1]
|
64
|
+
ns = path.inject(root) { |b,v| b.namespaces[v] }
|
65
|
+
ns.realize type, instance, type_infos[type]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize name, parent, host
|
71
|
+
@name = name
|
72
|
+
@parent = parent
|
73
|
+
@host = host
|
74
|
+
@type = nil
|
75
|
+
@instance = nil
|
76
|
+
@type_info = nil
|
77
|
+
@namespaces = Hash.new { |h,k| h[k] = self.class.new k, self, host }
|
78
|
+
@commands = {}
|
79
|
+
@cached_cli_info = nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def realize type, instance, type_info
|
83
|
+
fail if @type or @instance
|
84
|
+
@type = type
|
85
|
+
@instance = instance
|
86
|
+
@type_info = type_info
|
87
|
+
@type_info.method.each do |method_type_info|
|
88
|
+
name = method_type_info.name
|
89
|
+
@commands[name] = VIM::EsxcliCommand.new self, method_type_info
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def type_name
|
94
|
+
if @type then @type
|
95
|
+
elsif @parent then "#{@parent.type_name}.#{@name}"
|
96
|
+
else 'vim.EsxCLI'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def cli_info
|
101
|
+
@cached_cli_info ||=
|
102
|
+
if @host.direct?
|
103
|
+
@host.cli_info_fetcher.VimCLIInfoFetchCLIInfo(:typeName => type_name)
|
104
|
+
else
|
105
|
+
@host.mme.execute(@host.cli_info_fetcher._ref,
|
106
|
+
"vim.CLIInfo.FetchCLIInfo", :typeName => type_name)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def obj
|
111
|
+
conn = @host._connection
|
112
|
+
conn.type(@type_info.wsdlName).new(conn, @instance)
|
113
|
+
end
|
114
|
+
|
115
|
+
def method_missing name, *args
|
116
|
+
name = name.to_s
|
117
|
+
if @namespaces.member? name and args.empty?
|
118
|
+
@namespaces[name]
|
119
|
+
elsif @commands.member? name
|
120
|
+
@commands[name].call *args
|
121
|
+
else
|
122
|
+
raise NoMethodError
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def pretty_print q
|
127
|
+
q.text @name
|
128
|
+
q.text ' '
|
129
|
+
q.group 2 do
|
130
|
+
q.text '{'
|
131
|
+
q.breakable
|
132
|
+
items = (@namespaces.values+@commands.values).sort_by(&:name)
|
133
|
+
q.seplist items, nil, :each do |v|
|
134
|
+
if v.is_a? VIM::EsxcliNamespace
|
135
|
+
q.pp v
|
136
|
+
else
|
137
|
+
q.text v.name
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
q.breakable
|
142
|
+
q.text '}'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class VIM::EsxcliCommand
|
147
|
+
attr_reader :ns, :type_info, :cli_info
|
148
|
+
|
149
|
+
def initialize ns, type_info
|
150
|
+
@ns = ns
|
151
|
+
@type_info = type_info
|
152
|
+
@cached_cli_info = nil
|
153
|
+
end
|
154
|
+
|
155
|
+
def name
|
156
|
+
@type_info.name
|
157
|
+
end
|
158
|
+
|
159
|
+
def cli_info
|
160
|
+
@cached_cli_info ||= @ns.cli_info.method.find { |x| x.name == @type_info.name }
|
161
|
+
end
|
162
|
+
|
163
|
+
def call args={}
|
164
|
+
if @ns.host.direct?
|
165
|
+
@ns.obj._call @type_info.wsdlName, args
|
166
|
+
else
|
167
|
+
real_args = Set.new(type_info.paramTypeInfo.map(&:name))
|
168
|
+
args = args.reject { |k,v| !real_args.member?(k.to_s) }
|
169
|
+
@ns.host.mme.execute(@ns.obj._ref, "#{@ns.type_name}.#{@type_info.name}", args)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class RbVmomi::VIM::ManagedEntity
|
2
|
+
# Retrieve the ancestors of the entity.
|
3
|
+
# @return [Array] Ancestors of this entity, starting with the root.
|
4
|
+
def path
|
5
|
+
self.class.paths([self])[self]
|
6
|
+
end
|
7
|
+
|
8
|
+
# Retrieve the ancestors of a list of entries.
|
9
|
+
# @return [Hash] Object-indexed hash of ancestors of entities, starting with the root.
|
10
|
+
def self.paths objs
|
11
|
+
filterSpec = RbVmomi::VIM.PropertyFilterSpec(
|
12
|
+
:objectSet => objs.map do |obj|
|
13
|
+
RbVmomi::VIM.ObjectSpec(
|
14
|
+
:obj => obj,
|
15
|
+
:selectSet => [
|
16
|
+
RbVmomi::VIM.TraversalSpec(
|
17
|
+
:name => "tsME",
|
18
|
+
:type => 'ManagedEntity',
|
19
|
+
:path => 'parent',
|
20
|
+
:skip => false,
|
21
|
+
:selectSet => [
|
22
|
+
RbVmomi::VIM.SelectionSpec(:name => "tsME")
|
23
|
+
]
|
24
|
+
)
|
25
|
+
]
|
26
|
+
)
|
27
|
+
end,
|
28
|
+
:propSet => [{
|
29
|
+
:pathSet => %w(name parent),
|
30
|
+
:type => 'ManagedEntity'
|
31
|
+
}]
|
32
|
+
)
|
33
|
+
|
34
|
+
propCollector = objs.first._connection.propertyCollector
|
35
|
+
result = propCollector.RetrieveProperties(:specSet => [filterSpec])
|
36
|
+
|
37
|
+
Hash[objs.map do |obj|
|
38
|
+
tree = {}
|
39
|
+
result.each { |x| tree[x.obj] = [x['parent'], x['name']] }
|
40
|
+
a = []
|
41
|
+
cur = obj
|
42
|
+
while cur
|
43
|
+
parent, name = *tree[cur]
|
44
|
+
a << [cur, name]
|
45
|
+
cur = parent
|
46
|
+
end
|
47
|
+
[obj, a.reverse]
|
48
|
+
end]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return a string representation of +path+ suitable for display.
|
52
|
+
# @return [String]
|
53
|
+
# @see #path
|
54
|
+
def pretty_path
|
55
|
+
path[1..-1].map { |x| x[1] } * '/'
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class RbVmomi::VIM::ManagedObject
|
2
|
+
# Wait for updates on an object until a condition becomes true.
|
3
|
+
#
|
4
|
+
# @param pathSet [Array] Property paths to wait for updates to.
|
5
|
+
# @yield Called when an update to a subscribed property occurs.
|
6
|
+
# @yieldreturn [Boolean] Whether to stop waiting.
|
7
|
+
#
|
8
|
+
# @todo Pass the current property values to the block.
|
9
|
+
def wait_until *pathSet, &b
|
10
|
+
all = pathSet.empty?
|
11
|
+
filter = _connection.propertyCollector.CreateFilter :spec => {
|
12
|
+
:propSet => [{ :type => self.class.wsdl_name, :all => all, :pathSet => pathSet }],
|
13
|
+
:objectSet => [{ :obj => self }],
|
14
|
+
}, :partialUpdates => false
|
15
|
+
ver = ''
|
16
|
+
loop do
|
17
|
+
result = _connection.propertyCollector.WaitForUpdates(:version => ver)
|
18
|
+
ver = result.version
|
19
|
+
if x = b.call
|
20
|
+
return x
|
21
|
+
end
|
22
|
+
end
|
23
|
+
ensure
|
24
|
+
filter.DestroyPropertyFilter if filter
|
25
|
+
end
|
26
|
+
|
27
|
+
# Efficiently retrieve multiple properties from an object.
|
28
|
+
# @param pathSet [Array] Properties to return.
|
29
|
+
# @return [Hash] Hash from property paths to values.
|
30
|
+
def collect! *pathSet
|
31
|
+
spec = {
|
32
|
+
:objectSet => [{ :obj => self }],
|
33
|
+
:propSet => [{
|
34
|
+
:pathSet => pathSet,
|
35
|
+
:type => self.class.wsdl_name
|
36
|
+
}]
|
37
|
+
}
|
38
|
+
ret = _connection.propertyCollector.RetrieveProperties(:specSet => [spec])
|
39
|
+
if ret && ret.length > 0
|
40
|
+
ret[0].to_hash
|
41
|
+
else
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Efficiently retrieve multiple properties from an object.
|
47
|
+
# @param pathSet (see #collect!)
|
48
|
+
# @yield [*values] Property values in same order as +pathSet+.
|
49
|
+
# @return [Array] Property values in same order as +pathSet+, or the return
|
50
|
+
# value from the block if it is given.
|
51
|
+
def collect *pathSet
|
52
|
+
h = collect! *pathSet
|
53
|
+
a = pathSet.map { |k| h[k.to_s] }
|
54
|
+
if block_given?
|
55
|
+
yield a
|
56
|
+
else
|
57
|
+
a
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class RbVmomi::VIM::ObjectContent
|
2
|
+
# Represent this ObjectContent as a hash.
|
3
|
+
# @return [Hash] A hash from property paths to values.
|
4
|
+
def to_hash
|
5
|
+
@cached_hash ||= to_hash_uncached
|
6
|
+
end
|
7
|
+
|
8
|
+
# Alias for +to_hash[k]+.
|
9
|
+
def [](k)
|
10
|
+
to_hash[k]
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def to_hash_uncached
|
16
|
+
h = {}
|
17
|
+
propSet.each do |x|
|
18
|
+
fail if h.member? x.name
|
19
|
+
h[x.name] = x.val
|
20
|
+
end
|
21
|
+
h
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class RbVmomi::VIM::ObjectUpdate
|
2
|
+
# Represent this ObjectUpdate as a hash.
|
3
|
+
# @return [Hash] A hash from property paths to values.
|
4
|
+
def to_hash
|
5
|
+
@cached_hash ||= to_hash_uncached
|
6
|
+
end
|
7
|
+
|
8
|
+
# Alias for +to_hash[k]+.
|
9
|
+
def [](k)
|
10
|
+
to_hash[k]
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def to_hash_uncached
|
16
|
+
h = {}
|
17
|
+
changeSet.each do |x|
|
18
|
+
fail if h.member? x.name
|
19
|
+
h[x.name] = x.val
|
20
|
+
end
|
21
|
+
h
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# @note +deployOVF+ and requires +curl+. If +curl+ is not in your +PATH+
|
2
|
+
# then set the +CURL+ environment variable to point to it.
|
3
|
+
# @todo Use an HTTP library instead of executing +curl+.
|
4
|
+
class RbVmomi::VIM::OvfManager
|
5
|
+
CURLBIN = ENV['CURL'] || "curl" #@private
|
6
|
+
|
7
|
+
# Deploy an OVF.
|
8
|
+
#
|
9
|
+
# @param [Hash] opts The options hash.
|
10
|
+
# @option opts [String] :uri Location of the OVF.
|
11
|
+
# @option opts [String] :vmName Name of the new VM.
|
12
|
+
# @option opts [VIM::Folder] :vmFolder Folder to place the VM in.
|
13
|
+
# @option opts [VIM::HostSystem] :host Host to use.
|
14
|
+
# @option opts [VIM::ResourcePool] :resourcePool Resource pool to use.
|
15
|
+
# @option opts [VIM::Datastore] :datastore Datastore to use.
|
16
|
+
# @option opts [String] :diskProvisioning (thin) Disk provisioning mode.
|
17
|
+
# @option opts [Hash] :networkMappings Network mappings.
|
18
|
+
# @option opts [Hash] :propertyMappings Property mappings.
|
19
|
+
def deployOVF opts
|
20
|
+
opts = { :networkMappings => {},
|
21
|
+
:propertyMappings => {},
|
22
|
+
:diskProvisioning => :thin }.merge opts
|
23
|
+
|
24
|
+
%w(uri vmName vmFolder host resourcePool datastore).each do |k|
|
25
|
+
fail "parameter #{k} required" unless opts[k.to_sym]
|
26
|
+
end
|
27
|
+
|
28
|
+
ovfImportSpec = RbVmomi::VIM::OvfCreateImportSpecParams(
|
29
|
+
:hostSystem => opts[:host],
|
30
|
+
:locale => "US",
|
31
|
+
:entityName => opts[:vmName],
|
32
|
+
:deploymentOption => "",
|
33
|
+
:networkMapping => opts[:networkMappings].map{|from, to| RbVmomi::VIM::OvfNetworkMapping(:name => from, :network => to)},
|
34
|
+
:propertyMapping => opts[:propertyMappings].to_a,
|
35
|
+
:diskProvisioning => opts[:diskProvisioning]
|
36
|
+
)
|
37
|
+
|
38
|
+
result = CreateImportSpec(
|
39
|
+
:ovfDescriptor => open(opts[:uri]).read,
|
40
|
+
:resourcePool => opts[:resourcePool],
|
41
|
+
:datastore => opts[:datastore],
|
42
|
+
:cisp => ovfImportSpec
|
43
|
+
)
|
44
|
+
|
45
|
+
raise result.error[0].localizedMessage if result.error && !result.error.empty?
|
46
|
+
|
47
|
+
if result.warning
|
48
|
+
result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
|
49
|
+
end
|
50
|
+
|
51
|
+
importSpec = result.importSpec
|
52
|
+
if importSpec && importSpec.instantiationOst && importSpec.instantiationOst.child
|
53
|
+
importSpec.instantiationOst.child.each do |child|
|
54
|
+
child.section.map do |section|
|
55
|
+
section.xml = _handle_ost(section.xml, opts)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
nfcLease = opts[:resourcePool].ImportVApp(:spec => importSpec,
|
61
|
+
:folder => opts[:vmFolder],
|
62
|
+
:host => opts[:host])
|
63
|
+
|
64
|
+
nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
|
65
|
+
raise nfcLease.error if nfcLease.state == "error"
|
66
|
+
begin
|
67
|
+
nfcLease.HttpNfcLeaseProgress(:percent => 5)
|
68
|
+
timeout, = nfcLease.collect 'info.leaseTimeout'
|
69
|
+
puts "DEBUG: Timeout: #{timeout}"
|
70
|
+
if timeout < 4 * 60
|
71
|
+
puts "WARNING: OVF upload NFC lease timeout less than 4 minutes"
|
72
|
+
end
|
73
|
+
progress = 5.0
|
74
|
+
result.fileItem.each do |fileItem|
|
75
|
+
leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
|
76
|
+
# Retry nfcLease.collect because of PR 969599:
|
77
|
+
# If retrying property collector works, this means there is a network
|
78
|
+
# or VC overloading problem.
|
79
|
+
retrynum = 5
|
80
|
+
i = 1
|
81
|
+
while i <= retrynum && !leaseState
|
82
|
+
puts "Retrying at iteration #{i}"
|
83
|
+
sleep 1
|
84
|
+
leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
|
85
|
+
i += 1
|
86
|
+
end
|
87
|
+
if leaseState != "ready"
|
88
|
+
raise "NFC lease is no longer ready: #{leaseState}: #{leaseError}"
|
89
|
+
end
|
90
|
+
if leaseInfo == nil
|
91
|
+
raise "NFC lease disappeared?"
|
92
|
+
end
|
93
|
+
deviceUrl = leaseInfo.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
|
94
|
+
if !deviceUrl
|
95
|
+
raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
|
96
|
+
end
|
97
|
+
|
98
|
+
ovfFilename = opts[:uri].to_s
|
99
|
+
tmp = ovfFilename.split(/\//)
|
100
|
+
tmp.pop
|
101
|
+
tmp << fileItem.path
|
102
|
+
filename = tmp.join("/")
|
103
|
+
|
104
|
+
# If filename doesn't have a URI scheme, we're considering it a local file
|
105
|
+
if URI(filename).scheme.nil?
|
106
|
+
filename = "file://" + filename
|
107
|
+
end
|
108
|
+
|
109
|
+
method = fileItem.create ? "PUT" : "POST"
|
110
|
+
|
111
|
+
keepAliveThread = Thread.new do
|
112
|
+
while true
|
113
|
+
nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
|
114
|
+
sleep 1 * 60
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
i = 1
|
119
|
+
ip = nil
|
120
|
+
begin
|
121
|
+
begin
|
122
|
+
puts "Iteration #{i}: Trying to get host's IP address ..."
|
123
|
+
ip = opts[:host].config.network.vnic[0].spec.ip.ipAddress
|
124
|
+
rescue Exception=>e
|
125
|
+
puts "Iteration #{i}: Couldn't get host's IP address: #{e}"
|
126
|
+
end
|
127
|
+
sleep 1
|
128
|
+
i += 1
|
129
|
+
end while i <= 5 && !ip
|
130
|
+
raise "Couldn't get host's IP address" unless ip
|
131
|
+
href = deviceUrl.url.gsub("*", ip)
|
132
|
+
downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
|
133
|
+
uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
|
134
|
+
# Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
|
135
|
+
# to the uploadCmd. It is not clear to me why, but that leads to
|
136
|
+
# trucation of the uploaded disk. Without this option curl can't tell
|
137
|
+
# the progress, but who cares
|
138
|
+
system("#{downloadCmd} | #{uploadCmd}", STDOUT => "/dev/null")
|
139
|
+
|
140
|
+
keepAliveThread.kill
|
141
|
+
keepAliveThread.join
|
142
|
+
|
143
|
+
progress += (90.0 / result.fileItem.length)
|
144
|
+
nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
|
145
|
+
end
|
146
|
+
|
147
|
+
nfcLease.HttpNfcLeaseProgress(:percent => 100)
|
148
|
+
raise nfcLease.error if nfcLease.state == "error"
|
149
|
+
i = 1
|
150
|
+
vm = nil
|
151
|
+
begin
|
152
|
+
begin
|
153
|
+
puts "Iteration #{i}: Trying to access nfcLease.info.entity ..."
|
154
|
+
vm = nfcLease.info.entity
|
155
|
+
rescue Exception=>e
|
156
|
+
puts "Iteration #{i}: Couldn't access nfcLease.info.entity: #{e}"
|
157
|
+
end
|
158
|
+
sleep 1
|
159
|
+
i += 1
|
160
|
+
end while i <= 5 && !vm
|
161
|
+
raise "Couldn't access nfcLease.info.entity" unless vm
|
162
|
+
|
163
|
+
# Ignore sporadic connection errors caused by PR 1019166..
|
164
|
+
# Three attempts are made to execute HttpNfcLeaseComplete.
|
165
|
+
# Not critical if none goes through, as long as vm is obtained
|
166
|
+
#
|
167
|
+
# TODO: find the reason why HttpNfcLeaseComplete gets a wrong
|
168
|
+
# response (RetrievePropertiesResponse)
|
169
|
+
i = 0
|
170
|
+
begin
|
171
|
+
nfcLease.HttpNfcLeaseComplete
|
172
|
+
puts "HttpNfcLeaseComplete succeeded"
|
173
|
+
rescue RbVmomi::VIM::InvalidState
|
174
|
+
puts "HttpNfcLeaseComplete already finished.."
|
175
|
+
rescue Exception => e
|
176
|
+
puts "HttpNfcLeaseComplete failed at iteration #{i} with exception: #{e}"
|
177
|
+
i += 1
|
178
|
+
retry if i < 3
|
179
|
+
puts "Giving up HttpNfcLeaseComplete.."
|
180
|
+
end
|
181
|
+
vm
|
182
|
+
end
|
183
|
+
rescue Exception
|
184
|
+
(nfcLease.HttpNfcLeaseAbort rescue nil) if nfcLease
|
185
|
+
raise
|
186
|
+
end
|
187
|
+
|
188
|
+
def _handle_ost ost, opts = {}
|
189
|
+
ost = Nokogiri::XML(ost)
|
190
|
+
if opts[:vservice] == ['com.vmware.vim.vsm:extension_vservice']
|
191
|
+
ost.xpath('//vmw:Annotations/vmw:Providers/vmw:Provider').each do |x|
|
192
|
+
x['vmw:selected'] = 'selected'
|
193
|
+
end
|
194
|
+
ost.xpath('//vmw:Annotations/vmw:Providers').each do |x|
|
195
|
+
x['vmw:selected'] = 'com.vmware.vim.vsm:extension_vservice'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
ost.to_s
|
199
|
+
end
|
200
|
+
end
|