vagrant-rbvmomi 1.8.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.
- 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
|