Class: RbVmomi::VIM::OvfManager

Inherits:
Object
  • Object
show all
Defined in:
lib/rbvmomi/vim/OvfManager.rb

Overview

TODO:

Use an HTTP library instead of executing curl.

Note:

deployOVF and requires curl. If curl is not in your PATH then set the CURL environment variable to point to it.

Instance Method Summary collapse

Instance Method Details

#deployOVF(opts) ⇒ Object

Deploy an OVF.

Parameters:

  • opts (Hash)

    The options hash.

Options Hash (opts):

  • :uri (String)

    Location of the OVF.

  • :vmName (String)

    Name of the new VM.

  • :vmFolder (VIM::Folder)

    Folder to place the VM in.

  • :host (VIM::HostSystem)

    Host to use.

  • :resourcePool (VIM::ResourcePool)

    Resource pool to use.

  • :datastore (VIM::Datastore)

    Datastore to use.

  • :diskProvisioning (String) — default: thin

    Disk provisioning mode.

  • :networkMappings (Hash)

    Network mappings.

  • :propertyMappings (Hash)

    Property mappings.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rbvmomi/vim/OvfManager.rb', line 19

def deployOVF opts
  opts = { :networkMappings => {},
           :propertyMappings => {},
           :diskProvisioning => :thin }.merge opts

  %w(uri vmName vmFolder host resourcePool datastore).each do |k|
    fail "parameter #{k} required" unless opts[k.to_sym]
  end

  ovfImportSpec = RbVmomi::VIM::OvfCreateImportSpecParams(
    :hostSystem => opts[:host],
    :locale => "US",
    :entityName => opts[:vmName],
    :deploymentOption => "",
    :networkMapping => opts[:networkMappings].map{|from, to| RbVmomi::VIM::OvfNetworkMapping(:name => from, :network => to)},
    :propertyMapping => opts[:propertyMappings].map{|key, value| RbVmomi::VIM::KeyValue(:key => key, :value => value)},
    :diskProvisioning => opts[:diskProvisioning]
  )

  result = CreateImportSpec(
    :ovfDescriptor => open(opts[:uri]).read,
    :resourcePool => opts[:resourcePool],
    :datastore => opts[:datastore],
    :cisp => ovfImportSpec
  )

  raise result.error[0].localizedMessage if result.error && !result.error.empty?

  if result.warning
    result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
  end

  nfcLease = opts[:resourcePool].ImportVApp(:spec => result.importSpec,
                                            :folder => opts[:vmFolder],
                                            :host => opts[:host])

  nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
  raise nfcLease.error if nfcLease.state == "error"
  begin
    nfcLease.HttpNfcLeaseProgress(:percent => 5)
    progress = 5.0
    result.fileItem.each do |fileItem|
      deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
      if !deviceUrl
        raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
      end

      # XXX handle file:// URIs
      ovfFilename = opts[:uri].to_s
      tmp = ovfFilename.split(/\//)
      tmp.pop
      tmp << fileItem.path
      filename = tmp.join("/")

      method = fileItem.create ? "PUT" : "POST"

      keepAliveThread = Thread.new do
        while true
          sleep 2 * 60
          nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
        end
      end

      href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
      downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
      uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
      # Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
      # to the uploadCmd. It is not clear to me why, but that leads to 
      # trucation of the uploaded disk. Without this option curl can't tell
      # the progress, but who cares
      system("#{downloadCmd} | #{uploadCmd}", STDOUT => "/dev/null")
      
      keepAliveThread.kill
      keepAliveThread.join
      
      progress += (90.0 / result.fileItem.length)
      nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
    end

    nfcLease.HttpNfcLeaseProgress(:percent => 100)
    vm = nfcLease.info.entity
    nfcLease.HttpNfcLeaseComplete
    vm
  end
rescue Exception
  nfcLease.HttpNfcLeaseAbort if nfcLease
  raise
end