rbvmomi 1.0.2 → 1.1.0
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/.yardopts +5 -0
- data/README.rdoc +71 -0
- data/Rakefile +11 -0
- data/VERSION +1 -1
- data/devel/analyze-xml.rb +29 -29
- data/{test/test.rb → examples/create_vm.rb} +40 -15
- data/examples/extraConfig.rb +54 -0
- data/examples/power.rb +57 -0
- data/examples/readme-1.rb +35 -0
- data/examples/readme-2.rb +51 -0
- data/lib/rbvmomi.rb +3 -282
- data/lib/rbvmomi/{types.rb → basic_types.rb} +37 -97
- data/lib/rbvmomi/connection.rb +239 -0
- data/lib/rbvmomi/fault.rb +17 -0
- data/lib/{trivial_soap.rb → rbvmomi/trivial_soap.rb} +31 -13
- data/lib/rbvmomi/trollop.rb +6 -2
- data/lib/rbvmomi/type_loader.rb +72 -0
- data/lib/rbvmomi/vim.rb +76 -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/Folder.rb +112 -0
- data/lib/rbvmomi/vim/ManagedEntity.rb +46 -0
- data/lib/rbvmomi/vim/ManagedObject.rb +55 -0
- data/lib/rbvmomi/vim/ObjectContent.rb +23 -0
- data/lib/rbvmomi/vim/ObjectUpdate.rb +23 -0
- data/lib/rbvmomi/vim/OvfManager.rb +93 -0
- data/lib/rbvmomi/vim/ResourcePool.rb +18 -0
- data/lib/rbvmomi/vim/ServiceInstance.rb +53 -0
- data/lib/rbvmomi/vim/Task.rb +31 -0
- data/lib/rbvmomi/vim/VirtualMachine.rb +7 -0
- data/test/test_deserialization.rb +11 -55
- data/test/test_emit_request.rb +13 -10
- data/test/test_exceptions.rb +16 -0
- data/test/test_parse_response.rb +2 -10
- data/test/test_serialization.rb +14 -11
- metadata +41 -25
- data/.gitignore +0 -4
- data/README.md +0 -12
- data/lib/rbvmomi/extensions.rb +0 -491
- data/lib/rbvmomi/profile.rb +0 -22
- data/test/runner.rb +0 -3
@@ -0,0 +1,51 @@
|
|
1
|
+
class RbVmomi::VIM::ComputeResource
|
2
|
+
# Aggregate cluster information.
|
3
|
+
#
|
4
|
+
# @note Values are returned in a hash.
|
5
|
+
#
|
6
|
+
# @return [Mhz] totalCPU: Sum of the frequencies of each CPU in the cluster.
|
7
|
+
# @return [Mhz] usedCPU: CPU cycles used across the cluster.
|
8
|
+
# @return [MB] totalMem: Total RAM.
|
9
|
+
# @return [MB] usedMem: Used RAM.
|
10
|
+
def stats
|
11
|
+
filterSpec = RbVmomi::VIM.PropertyFilterSpec(
|
12
|
+
objectSet: [{
|
13
|
+
obj: self,
|
14
|
+
selectSet: [
|
15
|
+
RbVmomi::VIM.TraversalSpec(
|
16
|
+
name: 'tsHosts',
|
17
|
+
type: 'ComputeResource',
|
18
|
+
path: 'host',
|
19
|
+
skip: false,
|
20
|
+
)
|
21
|
+
]
|
22
|
+
}],
|
23
|
+
propSet: [{
|
24
|
+
pathSet: %w(name overallStatus summary.hardware.cpuMhz
|
25
|
+
summary.hardware.numCpuCores summary.hardware.memorySize
|
26
|
+
summary.quickStats.overallCpuUsage
|
27
|
+
summary.quickStats.overallMemoryUsage),
|
28
|
+
type: 'HostSystem'
|
29
|
+
}]
|
30
|
+
)
|
31
|
+
|
32
|
+
result = @soap.propertyCollector.RetrieveProperties(specSet: [filterSpec])
|
33
|
+
|
34
|
+
stats = {
|
35
|
+
totalCPU: 0,
|
36
|
+
totalMem: 0,
|
37
|
+
usedCPU: 0,
|
38
|
+
usedMem: 0,
|
39
|
+
}
|
40
|
+
|
41
|
+
result.each do |x|
|
42
|
+
next if x['overallStatus'] == 'red'
|
43
|
+
stats[:totalCPU] += x['summary.hardware.cpuMhz'] * x['summary.hardware.numCpuCores']
|
44
|
+
stats[:totalMem] += x['summary.hardware.memorySize'] / (1024*1024)
|
45
|
+
stats[:usedCPU] += x['summary.quickStats.overallCpuUsage'] || 0
|
46
|
+
stats[:usedMem] += x['summary.quickStats.overallMemoryUsage'] || 0
|
47
|
+
end
|
48
|
+
|
49
|
+
stats
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class RbVmomi::VIM::Datacenter
|
2
|
+
# Traverse the given inventory +path+ to find a ComputeResource.
|
3
|
+
def find_compute_resource path
|
4
|
+
hostFolder.traverse path, RbVmomi::VIM::ComputeResource
|
5
|
+
end
|
6
|
+
|
7
|
+
# Find the Datastore with the given +name+.
|
8
|
+
def find_datastore name
|
9
|
+
datastore.find { |x| x.name == name }
|
10
|
+
end
|
11
|
+
|
12
|
+
# Traverse the given inventory +path+ to find a VirtualMachine.
|
13
|
+
def find_vm path
|
14
|
+
vmFolder.traverse path, RbVmomi::VIM::VirtualMachine
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# @note +download+ and +upload+ require +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::Datastore
|
5
|
+
CURLBIN = ENV['CURL'] || "curl" #@private
|
6
|
+
|
7
|
+
# Check whether a file exists on this datastore.
|
8
|
+
# @param path [String] Path on the datastore.
|
9
|
+
def exists? path
|
10
|
+
req = Net::HTTP::Head.new mkuripath(path)
|
11
|
+
req.initialize_http_header 'cookie' => @soap.cookie
|
12
|
+
resp = @soap.http.request req
|
13
|
+
case resp
|
14
|
+
when Net::HTTPSuccess
|
15
|
+
true
|
16
|
+
when Net::HTTPNotFound
|
17
|
+
false
|
18
|
+
else
|
19
|
+
fail resp.inspect
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Download a file from this datastore.
|
24
|
+
# @param remote_path [String] Source path on the datastore.
|
25
|
+
# @param local_path [String] Destination path on the local machine.
|
26
|
+
# @return [void]
|
27
|
+
def download remote_path, local_path
|
28
|
+
url = "http#{@soap.http.use_ssl? ? 's' : ''}://#{@soap.http.address}:#{@soap.http.port}#{mkuripath(remote_path)}"
|
29
|
+
pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f',
|
30
|
+
"-o", local_path,
|
31
|
+
"-b", @soap.cookie,
|
32
|
+
url,
|
33
|
+
out: '/dev/null'
|
34
|
+
Process.waitpid(pid, 0)
|
35
|
+
fail "download failed" unless $?.success?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Upload a file to this datastore.
|
39
|
+
# @param remote_path [String] Destination path on the datastore.
|
40
|
+
# @param local_path [String] Source path on the local machine.
|
41
|
+
# @return [void]
|
42
|
+
def upload remote_path, local_path
|
43
|
+
url = "http#{@soap.http.use_ssl? ? 's' : ''}://#{@soap.http.address}:#{@soap.http.port}#{mkuripath(remote_path)}"
|
44
|
+
pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f',
|
45
|
+
"-T", local_path,
|
46
|
+
"-b", @soap.cookie,
|
47
|
+
url,
|
48
|
+
out: '/dev/null'
|
49
|
+
Process.waitpid(pid, 0)
|
50
|
+
fail "upload failed" unless $?.success?
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def datacenter
|
56
|
+
return @datacenter if @datacenter
|
57
|
+
x = parent
|
58
|
+
while not x.is_a? Datacenter
|
59
|
+
x = x.parent
|
60
|
+
end
|
61
|
+
fail unless x.is_a? Datacenter
|
62
|
+
@datacenter = x
|
63
|
+
end
|
64
|
+
|
65
|
+
def mkuripath path
|
66
|
+
"/folder/#{URI.escape path}?dcPath=#{URI.escape datacenter.name}&dsName=#{URI.escape name}"
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
class RbVmomi::VIM::Folder
|
2
|
+
# Retrieve a child entity
|
3
|
+
# @param name [String] Name of the child.
|
4
|
+
# @param type [Class] Return nil unless the found entity <tt>is_a? type</tt>.
|
5
|
+
# @return [VIM::ManagedEntity]
|
6
|
+
def find name, type=Object
|
7
|
+
x = @soap.searchIndex.FindChild(entity: self, name: name)
|
8
|
+
x if x.is_a? type
|
9
|
+
end
|
10
|
+
|
11
|
+
# Alias to <tt>traverse path, type, true</tt>
|
12
|
+
# @see #traverse
|
13
|
+
def traverse! path, type=Object
|
14
|
+
traverse path, type, true
|
15
|
+
end
|
16
|
+
|
17
|
+
# Retrieve a descendant of this Folder.
|
18
|
+
# @param path [String] Path delimited by '/'.
|
19
|
+
# @param type (see Folder#find)
|
20
|
+
# @param create [Boolean] If set, create folders that don't exist.
|
21
|
+
# @return (see Folder#find)
|
22
|
+
# @todo Move +create+ functionality into another method.
|
23
|
+
def traverse path, type=Object, create=false
|
24
|
+
es = path.split('/').reject(&:empty?)
|
25
|
+
return self if es.empty?
|
26
|
+
final = es.pop
|
27
|
+
|
28
|
+
p = es.inject(self) do |f,e|
|
29
|
+
f.find(e, Folder) || (create && f.CreateFolder(name: e)) || return
|
30
|
+
end
|
31
|
+
|
32
|
+
if x = p.find(final, type)
|
33
|
+
x
|
34
|
+
elsif create and type == Folder
|
35
|
+
p.CreateFolder(name: final)
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Alias to +childEntity+.
|
42
|
+
def children
|
43
|
+
childEntity
|
44
|
+
end
|
45
|
+
|
46
|
+
# Efficiently retrieve properties from descendants of this folder.
|
47
|
+
#
|
48
|
+
# @param propSpecs [Hash] Specification of which properties to retrieve from
|
49
|
+
# which entities. Keys may be symbols, strings, or
|
50
|
+
# classes identifying ManagedEntity subtypes to be
|
51
|
+
# included in the results. Values are an array of
|
52
|
+
# property paths (strings) or the symbol :all.
|
53
|
+
#
|
54
|
+
# @return [Hash] Tree of inventory items. Folders are hashes from child name
|
55
|
+
# to child result. Objects are hashes from property path to
|
56
|
+
# value.
|
57
|
+
#
|
58
|
+
# @todo Return ObjectContent instead of the leaf hash.
|
59
|
+
def inventory propSpecs={}
|
60
|
+
propSet = [{ type: 'Folder', pathSet: ['name', 'parent'] }]
|
61
|
+
propSpecs.each do |k,v|
|
62
|
+
case k
|
63
|
+
when RbVmomi::VIM::ManagedEntity
|
64
|
+
k = k.wsdl_name
|
65
|
+
when Symbol, String
|
66
|
+
k = k.to_s
|
67
|
+
else
|
68
|
+
fail "key must be a ManagedEntity"
|
69
|
+
end
|
70
|
+
|
71
|
+
h = { type: k }
|
72
|
+
if v == :all
|
73
|
+
h[:all] = true
|
74
|
+
elsif v.is_a? Array
|
75
|
+
h[:pathSet] = v + %w(parent)
|
76
|
+
else
|
77
|
+
fail "value must be an array of property paths or :all"
|
78
|
+
end
|
79
|
+
propSet << h
|
80
|
+
end
|
81
|
+
|
82
|
+
filterSpec = RbVmomi::VIM.PropertyFilterSpec(
|
83
|
+
objectSet: [
|
84
|
+
obj: self,
|
85
|
+
selectSet: [
|
86
|
+
RbVmomi::VIM.TraversalSpec(
|
87
|
+
name: 'tsFolder',
|
88
|
+
type: 'Folder',
|
89
|
+
path: 'childEntity',
|
90
|
+
skip: false,
|
91
|
+
selectSet: [
|
92
|
+
RbVmomi::VIM.SelectionSpec(name: 'tsFolder')
|
93
|
+
]
|
94
|
+
)
|
95
|
+
]
|
96
|
+
],
|
97
|
+
propSet: propSet
|
98
|
+
)
|
99
|
+
|
100
|
+
result = @soap.propertyCollector.RetrieveProperties(specSet: [filterSpec])
|
101
|
+
|
102
|
+
tree = { self => {} }
|
103
|
+
result.each do |x|
|
104
|
+
obj = x.obj
|
105
|
+
next if obj == self
|
106
|
+
h = Hash[x.propSet.map { |y| [y.name, y.val] }]
|
107
|
+
tree[h['parent']][h['name']] = [obj, h]
|
108
|
+
tree[obj] = {} if obj.is_a? RbVmomi::VIM::Folder
|
109
|
+
end
|
110
|
+
tree
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,46 @@
|
|
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
|
+
filterSpec = RbVmomi::VIM.PropertyFilterSpec(
|
6
|
+
objectSet: [{
|
7
|
+
obj: self,
|
8
|
+
selectSet: [
|
9
|
+
RbVmomi::VIM.TraversalSpec(
|
10
|
+
name: 'tsME',
|
11
|
+
type: 'ManagedEntity',
|
12
|
+
path: 'parent',
|
13
|
+
skip: false,
|
14
|
+
selectSet: [
|
15
|
+
RbVmomi::VIM.SelectionSpec(name: 'tsME')
|
16
|
+
]
|
17
|
+
)
|
18
|
+
]
|
19
|
+
}],
|
20
|
+
propSet: [{
|
21
|
+
pathSet: %w(name parent),
|
22
|
+
type: 'ManagedEntity'
|
23
|
+
}]
|
24
|
+
)
|
25
|
+
|
26
|
+
result = @soap.propertyCollector.RetrieveProperties(specSet: [filterSpec])
|
27
|
+
|
28
|
+
tree = {}
|
29
|
+
result.each { |x| tree[x.obj] = [x['parent'], x['name']] }
|
30
|
+
a = []
|
31
|
+
cur = self
|
32
|
+
while cur
|
33
|
+
parent, name = *tree[cur]
|
34
|
+
a << [cur, name]
|
35
|
+
cur = parent
|
36
|
+
end
|
37
|
+
a.reverse
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return a string representation of +path+ suitable for display.
|
41
|
+
# @return [String]
|
42
|
+
# @see #path
|
43
|
+
def pretty_path
|
44
|
+
path[1..-1].map { |x| x[1] } * '/'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,55 @@
|
|
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 = @soap.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 = @soap.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
|
+
@soap.propertyCollector.RetrieveProperties(specSet: [spec])[0].to_hash
|
39
|
+
end
|
40
|
+
|
41
|
+
# Efficiently retrieve multiple properties from an object.
|
42
|
+
# @param pathSet (see #collect!)
|
43
|
+
# @yield [*values] Property values in same order as +pathSet+.
|
44
|
+
# @return [Array] Property values in same order as +pathSet+, or the return
|
45
|
+
# value from the block if it is given.
|
46
|
+
def collect *pathSet
|
47
|
+
h = collect! *pathSet
|
48
|
+
a = pathSet.map { |k| h[k.to_s] }
|
49
|
+
if block_given?
|
50
|
+
yield a
|
51
|
+
else
|
52
|
+
a
|
53
|
+
end
|
54
|
+
end
|
55
|
+
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,93 @@
|
|
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].map{|key, value| RbVmomi::VIM::KeyValue(key: key, value: value)},
|
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
|
+
nfcLease = opts[:resourcePool].ImportVApp(spec: result.importSpec,
|
52
|
+
folder: opts[:vmFolder],
|
53
|
+
host: opts[:host])
|
54
|
+
|
55
|
+
nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
|
56
|
+
raise nfcLease.error if nfcLease.state == "error"
|
57
|
+
|
58
|
+
begin
|
59
|
+
nfcLease.HttpNfcLeaseProgress(percent: 5)
|
60
|
+
progress = 0.0
|
61
|
+
result.fileItem.each do |fileItem|
|
62
|
+
deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
|
63
|
+
if !deviceUrl
|
64
|
+
raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
|
65
|
+
end
|
66
|
+
|
67
|
+
# XXX handle file:// URIs
|
68
|
+
ovfFilename = opts[:uri].to_s
|
69
|
+
tmp = ovfFilename.split(/\//)
|
70
|
+
tmp.pop
|
71
|
+
tmp << fileItem.path
|
72
|
+
filename = tmp.join("/")
|
73
|
+
|
74
|
+
method = fileItem.create ? "PUT" : "POST"
|
75
|
+
|
76
|
+
href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
|
77
|
+
downloadCmd = "#{CURLBIN} -L '#{filename}'"
|
78
|
+
uploadCmd = "#{CURLBIN} -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' -H 'Content-Length: #{fileItem.size}' '#{href}'"
|
79
|
+
system("#{downloadCmd} | #{uploadCmd}")
|
80
|
+
progress += (95.0 / result.fileItem.length)
|
81
|
+
nfcLease.HttpNfcLeaseProgress(percent: progress.to_i)
|
82
|
+
end
|
83
|
+
|
84
|
+
nfcLease.HttpNfcLeaseProgress(percent: 100)
|
85
|
+
vm = nfcLease.info.entity
|
86
|
+
nfcLease.HttpNfcLeaseComplete
|
87
|
+
vm
|
88
|
+
end
|
89
|
+
rescue Exception
|
90
|
+
nfcLease.HttpNfcLeaseAbort
|
91
|
+
raise
|
92
|
+
end
|
93
|
+
end
|