Class: VSphereCloud::Client

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

Defined Under Namespace

Classes: AlreadyLoggedInException, DuplicateName, 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.



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

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.



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

def cloud_searcher
  @cloud_searcher
end

#service_contentObject (readonly)

Returns the value of attribute service_content.



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

def service_content
  @service_content
end

#service_instanceObject (readonly)

Returns the value of attribute service_instance.



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

def service_instance
  @service_instance
end

#soap_stubObject (readonly)

Returns the value of attribute soap_stub.



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

def soap_stub
  @soap_stub
end

Instance Method Details

#answer_vm(vm, question, answer) ⇒ Object



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

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

#create_datastore_folder(folder_path, datacenter) ⇒ Object



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

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



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

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



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

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

#delete_disk(datacenter, path) ⇒ Object



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

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



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

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

#delete_path(datacenter, path) ⇒ Object



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

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



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

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

#find_by_inventory_path(path) ⇒ Object



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

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



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

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



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

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



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

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



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
213
# File 'lib/cloud/vsphere/client.rb', line 182

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



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

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

#logoutObject



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

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



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

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 = dest_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.mob,
      "#{base_dest_path}#{extension}", dest_datacenter.mob, false
    )
  end

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

#move_into_folder(folder, objects) ⇒ Object



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

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

#move_into_root_folder(objects) ⇒ Object



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

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



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

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

#power_on_vm(datacenter, vm) ⇒ Object



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

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



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

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

#wait_for_task(task) ⇒ Object



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
180
# File 'lib/cloud/vsphere/client.rb', line 143

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