Class: VSphereCloud::Client

Inherits:
Object
  • Object
show all
Includes:
VimSdk
Defined in:
lib/cloud/vsphere/client.rb

Defined Under Namespace

Classes: AlreadyLoggedInException, FileNotFoundException, NotLoggedInException, TaskException

Constant Summary

Constants included from VimSdk

VimSdk::BASE_VERSION, VimSdk::DYNAMIC_TYPES, VimSdk::SOAP_BODY_END, VimSdk::SOAP_BODY_START, VimSdk::SOAP_BODY_TAG, VimSdk::SOAP_END, VimSdk::SOAP_ENVELOPE_END, VimSdk::SOAP_ENVELOPE_START, VimSdk::SOAP_ENVELOPE_TAG, VimSdk::SOAP_FAULT_TAG, VimSdk::SOAP_HEADER_END, VimSdk::SOAP_HEADER_START, VimSdk::SOAP_HEADER_TAG, VimSdk::SOAP_NAMESPACE_MAP, VimSdk::SOAP_START, VimSdk::VERSION1, VimSdk::XMLNS_SOAPENC, VimSdk::XMLNS_SOAPENV, VimSdk::XMLNS_VMODL_BASE, VimSdk::XMLNS_XSD, VimSdk::XMLNS_XSI, VimSdk::XML_ENCODING, VimSdk::XML_HEADER

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, options = {}) ⇒ Client

Returns a new instance of Client.



12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/cloud/vsphere/client.rb', line 12

def initialize(host, options={})
  @soap_stub = SoapStub.new(host, options[:soap_log]).create

  @service_instance =Vim::ServiceInstance.new('ServiceInstance', @soap_stub)
  @service_content = @service_instance.content

  @metrics_cache  = {}
  @lock = Mutex.new
  @logger = options.fetch(:logger) { Bosh::Clouds::Config.logger }

  @cloud_searcher = CloudSearcher.new(service_content, @logger)
end

Instance Attribute Details

#cloud_searcherObject (readonly)

Returns the value of attribute cloud_searcher.



10
11
12
# File 'lib/cloud/vsphere/client.rb', line 10

def cloud_searcher
  @cloud_searcher
end

#service_contentObject (readonly)

Returns the value of attribute service_content.



10
11
12
# File 'lib/cloud/vsphere/client.rb', line 10

def service_content
  @service_content
end

#service_instanceObject (readonly)

Returns the value of attribute service_instance.



10
11
12
# File 'lib/cloud/vsphere/client.rb', line 10

def service_instance
  @service_instance
end

#soap_stubObject (readonly)

Returns the value of attribute soap_stub.



10
11
12
# File 'lib/cloud/vsphere/client.rb', line 10

def soap_stub
  @soap_stub
end

Instance Method Details

#answer_vm(vm, question, answer) ⇒ Object



53
54
55
# File 'lib/cloud/vsphere/client.rb', line 53

def answer_vm(vm, question, answer)
  vm.answer(question, answer)
end

#create_datastore_folder(folder_path, datacenter) ⇒ Object



114
115
116
# File 'lib/cloud/vsphere/client.rb', line 114

def create_datastore_folder(folder_path, datacenter)
  @service_content.file_manager.make_directory(folder_path, datacenter, true)
end

#create_disk(datacenter, datastore, disk_cid, disk_folder, disk_size_in_mb) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/cloud/vsphere/client.rb', line 220

def create_disk(datacenter, datastore, disk_cid, disk_folder, disk_size_in_mb)
  disk_path = "[#{datastore.name}] #{disk_folder}/#{disk_cid}.vmdk"

  create_parent_folder(datacenter, disk_path)

  disk_spec = VimSdk::Vim::VirtualDiskManager::FileBackedVirtualDiskSpec.new
  disk_spec.disk_type = 'preallocated'
  disk_spec.capacity_kb = disk_size_in_mb * 1024
  disk_spec.adapter_type = 'lsiLogic'

  task = service_content.virtual_disk_manager.create_virtual_disk(
    disk_path,
    datacenter.mob,
    disk_spec
  )
  wait_for_task(task)

  Resources::Disk.new(disk_cid, disk_size_in_mb, datastore, disk_path)
end

#create_folder(name) ⇒ Object



118
119
120
# File 'lib/cloud/vsphere/client.rb', line 118

def create_folder(name)
  @service_content.root_folder.create_folder(name)
end

#delete_disk(datacenter, path) ⇒ Object



92
93
94
95
96
97
# File 'lib/cloud/vsphere/client.rb', line 92

def delete_disk(datacenter, path)
  base_path = path.chomp(File.extname(path))
  [".vmdk", "-flat.vmdk"].each do |extension|
    delete_path(datacenter, "#{base_path}#{extension}")
  end
end

#delete_folder(folder) ⇒ Object



132
133
134
135
# File 'lib/cloud/vsphere/client.rb', line 132

def delete_folder(folder)
  task = folder.destroy
  wait_for_task(task)
end

#delete_path(datacenter, path) ⇒ Object



81
82
83
84
85
86
87
88
89
90
# File 'lib/cloud/vsphere/client.rb', line 81

def delete_path(datacenter, path)
  task = @service_content.file_manager.delete_file(path, datacenter)
  begin
    wait_for_task(task)
  rescue => e
    unless e.message =~ /File .* was not found/
      raise e
    end
  end
end

#delete_vm(vm) ⇒ Object



48
49
50
51
# File 'lib/cloud/vsphere/client.rb', line 48

def delete_vm(vm)
  task = vm.destroy
  wait_for_task(task)
end

#find_by_inventory_path(path) ⇒ Object



137
138
139
140
# File 'lib/cloud/vsphere/client.rb', line 137

def find_by_inventory_path(path)
  full_path = Array(path).join("/")
  @service_content.search_index.find_by_inventory_path(full_path)
end

#find_disk(disk_cid, datastore, disk_folder) ⇒ Object



214
215
216
217
218
# File 'lib/cloud/vsphere/client.rb', line 214

def find_disk(disk_cid, datastore, disk_folder)
  disk_path = "[#{datastore.name}] #{disk_folder}/#{disk_cid}.vmdk"
  disk_size_in_mb = find_disk_size_using_browser(datastore, disk_cid, disk_folder)
  disk_size_in_mb.nil? ? nil : Resources::Disk.new(disk_cid, disk_size_in_mb, datastore, disk_path)
end

#find_parent(obj, parent_type) ⇒ Object



36
37
38
39
40
41
# File 'lib/cloud/vsphere/client.rb', line 36

def find_parent(obj, parent_type)
  while obj && obj.class != parent_type
    obj = @cloud_searcher.get_property(obj, obj.class, "parent", :ensure_all => true)
  end
  obj
end

#get_cdrom_device(vm) ⇒ Object



76
77
78
79
# File 'lib/cloud/vsphere/client.rb', line 76

def get_cdrom_device(vm)
  devices = @cloud_searcher.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
  devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualCdrom) }
end

#get_perf_counters(mobs, names, options = {}) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/cloud/vsphere/client.rb', line 181

def get_perf_counters(mobs, names, options = {})
  metrics = find_perf_metric_names(mobs.first, names)
  metric_ids = metrics.values

  metric_name_by_id = {}
  metrics.each { |name, metric| metric_name_by_id[metric.counter_id] = name }

  queries = []
  mobs.each do |mob|
    queries << Vim::PerformanceManager::QuerySpec.new(
        :entity => mob,
        :metric_id => metric_ids,
        :format => Vim::PerformanceManager::Format::CSV,
        :interval_id => options[:interval_id] || 20,
        :max_sample => options[:max_sample])
  end

  query_perf_response = @service_content.perf_manager.query_stats(queries)

  result = {}
  query_perf_response.each do |mob_stats|
    mob_entry = {}
    counters = mob_stats.value
    counters.each do |counter_stats|
      counter_id = counter_stats.id.counter_id
      values = counter_stats.value
      mob_entry[metric_name_by_id[counter_id]] = values
    end
    result[mob_stats.entity] = mob_entry
  end
  result
end

#login(username, password, locale) ⇒ Object



25
26
27
28
# File 'lib/cloud/vsphere/client.rb', line 25

def (username, password, locale)
  raise AlreadyLoggedInException if @session
  @session = @service_content.session_manager.(username, password, locale)
end

#logoutObject



30
31
32
33
34
# File 'lib/cloud/vsphere/client.rb', line 30

def logout
  raise NotLoggedInException unless @session
  @session = nil
  @service_content.session_manager.logout
end

#move_disk(source_datacenter, source_path, dest_datacenter, dest_path) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/cloud/vsphere/client.rb', line 99

def move_disk(source_datacenter, source_path, dest_datacenter, dest_path)
  create_parent_folder(dest_datacenter, dest_path)
  tasks = []
  base_source_path = source_path.chomp(File.extname(source_path))
  base_dest_path = source_path.chomp(File.extname(dest_path))
  [".vmdk", "-flat.vmdk"].each do |extension|
    tasks << @service_content.file_manager.move_file(
      "#{base_source_path}#{extension}", source_datacenter,
      "#{base_dest_path}#{extension}", dest_datacenter, false
    )
  end

  tasks.each { |task| wait_for_task(task) }
end

#move_into_folder(folder, objects) ⇒ Object



122
123
124
125
# File 'lib/cloud/vsphere/client.rb', line 122

def move_into_folder(folder, objects)
  task = folder.move_into(objects)
  wait_for_task(task)
end

#move_into_root_folder(objects) ⇒ Object



127
128
129
130
# File 'lib/cloud/vsphere/client.rb', line 127

def move_into_root_folder(objects)
  task = @service_content.root_folder.move_into(objects)
  wait_for_task(task)
end

#power_off_vm(vm_mob) ⇒ Object



71
72
73
74
# File 'lib/cloud/vsphere/client.rb', line 71

def power_off_vm(vm_mob)
  task = vm_mob.power_off
  wait_for_task(task)
end

#power_on_vm(datacenter, vm) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/cloud/vsphere/client.rb', line 57

def power_on_vm(datacenter, vm)
  task = datacenter.power_on_vm([vm], nil)
  result = wait_for_task(task)

  raise 'Recommendations were detected, you may be running in Manual DRS mode. Aborting.' if result.recommendations.any?

  if result.attempted.empty?
    raise "Could not power on VM: #{result.not_attempted.map(&:msg).join(', ')}"
  else
    task = result.attempted.first.task
    wait_for_task(task)
  end
end

#reconfig_vm(vm, config) ⇒ Object



43
44
45
46
# File 'lib/cloud/vsphere/client.rb', line 43

def reconfig_vm(vm, config)
  task = vm.reconfigure(config)
  wait_for_task(task)
end

#wait_for_task(task) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/cloud/vsphere/client.rb', line 142

def wait_for_task(task)
  interval = 1.0
  started = Time.now
  loop do
    properties = @cloud_searcher.get_properties(
      [task],
      Vim::Task,
      ["info.progress", "info.state", "info.result", "info.error"],
      ensure: ["info.state"]
    )[task]

    duration = Time.now - started
    raise "Task taking too long" if duration > 3600 # 1 hour

    # Update the polling interval based on task progress
    if properties["info.progress"] && properties["info.progress"] > 0
      interval = ((duration * 100 / properties["info.progress"]) - duration) / 5
      if interval < 1
        interval = 1
      elsif interval > 10
        interval = 10
      elsif interval > duration
        interval = duration
      end
    end

    case properties["info.state"]
      when Vim::TaskInfo::State::RUNNING
        sleep(interval)
      when Vim::TaskInfo::State::QUEUED
        sleep(interval)
      when Vim::TaskInfo::State::SUCCESS
        return properties["info.result"]
      when Vim::TaskInfo::State::ERROR
        raise task_exception_for_vim_fault(properties["info.error"])
    end
  end
end