Skip to content

Commit

Permalink
Improve the speed of finding an individual VM (#422)
Browse files Browse the repository at this point in the history
* Improve the speed of finding an individual VM

This PR makes use of the
[ContainerView](https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.view.ViewManager.html)
to retrieve a cut down list of servers from which the desired object can
be found, after which the object itself can be downloaded. Previously,
we'd download each VM (about 3.5K and several round trips to the server)
to find the VM we want.

From
```
sean~/play/knife-vsphere (find_speed %)$ time knife vsphere vm disk list myserver
  0          Hard disk 1      nosnapshots_ds4 64.00 GiB

real    1m56.153s
user    0m9.536s
sys    0m1.713s
```
to
```
sean~/play/knife-vsphere (find_speed *%)$ time be knife vsphere vm disk list myserver
/Users/sean/.gem/ruby/2.4.1/gems/builder-3.2.2/lib/builder/xchar.rb:111: warning: constant ::Fixnum is deprecated
  0          Hard disk 1      nosnapshots_ds4 64.00 GiB

real    0m2.929s
user    0m1.038s
sys    0m0.236s
```

This'll have to be retrofitted to the other commands, which we can do
over time.

See vmware-archive/rbvmomi#117 for some more context

* Use the new finding on property set

* Add this to vm state, too

* Add same thing to vm config

* Add vm lookup to snapshot
  • Loading branch information
swalberg committed Mar 19, 2018
1 parent de4ef52 commit 8b1ab19
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 38 deletions.
41 changes: 41 additions & 0 deletions lib/chef/knife/search_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Some helpers for faster searching of the inventory
module SearchHelper
# Retrieves all the VM objects and returns their ObjectContents
# Note that since it's a ObjectContent coming back, the individual
# object's [] will return only the properties you asked for
# and `#obj` will return the actual object (but make a call to the server)
# param [Array<String>] properties to retrieve
# @return [Array<RbVmomi::VIM::ObjectContent>]
def get_all_vm_objects(properties = ['name'])
pc = vim_connection.serviceInstance.content.propertyCollector
viewmgr = vim_connection.serviceInstance.content.viewManager
root_folder = vim_connection.serviceInstance.content.rootFolder
vmview = viewmgr.CreateContainerView(container: root_folder,
type: ['VirtualMachine'],
recursive: true)

filter_spec = RbVmomi::VIM.PropertyFilterSpec(
objectSet: [
obj: vmview,
skip: true,
selectSet: [
RbVmomi::VIM.TraversalSpec(
name: 'traverseEntities',
type: 'ContainerView',
path: 'view',
skip: false
)
]
],
propSet: [
{ type: 'VirtualMachine', pathSet: properties }
]
)
pc.RetrieveProperties(specSet: [filter_spec])
end

def get_vm_by_name(vmname)
vm = get_all_vm_objects.detect { |r| r['name'] == vmname }
vm ? vm.obj : nil
end
end
9 changes: 3 additions & 6 deletions lib/chef/knife/vsphere_vm_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

require 'chef/knife'
require 'chef/knife/base_vsphere_command'
require 'rbvmomi'
require 'netaddr'
require 'chef/knife/search_helper'

# VsphereVMconfig extends the BaseVspherecommand
class Chef::Knife::VsphereVmConfig < Chef::Knife::BaseVsphereCommand
include SearchHelper
banner "knife vsphere vm config VMNAME PROPERTY VALUE.
See \"http://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.ConfigSpec.html\"
for allowed ATTRIBUTE values (any property of type xs:string is supported)."
Expand Down Expand Up @@ -39,10 +39,7 @@ def run

vim_connection

dc = datacenter
folder = find_folder(get_config(:folder)) || dc.vmFolder

vm = traverse_folders_for_vm(folder, vmname) || abort("VM #{vmname} not found")
vm = get_vm_by_name(vmname) || fatal_exit("Could not find #{vmname}")

properties = {}
properties[property_name] = property_value
Expand Down
7 changes: 4 additions & 3 deletions lib/chef/knife/vsphere_vm_disk_list.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
require 'chef/knife'
require 'chef/knife/base_vsphere_command'
require 'chef/knife/search_helper'

# List the disks attached to a VM
# VsphereVmdisklist extends the BaseVspherecommand
class Chef::Knife::VsphereVmDiskList < Chef::Knife::BaseVsphereCommand
include SearchHelper

banner 'knife vsphere vm disk list VMNAME'

common_options
Expand All @@ -18,9 +21,7 @@ def run
fatal_exit 'You must specify a virtual machine name'
end

vim_connection
vm = get_vm(vmname)
fatal_exit "Could not find #{vmname}" unless vm
vm = get_vm_by_name(vmname) || fatal_exit("Could not find #{vmname}")

disks = vm.config.hardware.device.select do |device|
device.is_a? RbVmomi::VIM::VirtualDisk
Expand Down
7 changes: 3 additions & 4 deletions lib/chef/knife/vsphere_vm_property_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

require 'chef/knife'
require 'chef/knife/base_vsphere_command'
require 'rbvmomi'
require 'netaddr'
require 'chef/knife/search_helper'

# VsphereVMPropertySet extends Basevspherecommand
class Chef::Knife::VsphereVmPropertySet < Chef::Knife::BaseVsphereCommand
include SearchHelper
banner 'knife vsphere vm property set VMNAME PROPERTY VALUE. Sets a vApp Property on VMNAME.'

common_options
Expand Down Expand Up @@ -42,9 +42,8 @@ def run
vim_connection

dc = datacenter
folder = find_folder(get_config(:folder)) || dc.vmFolder

vm = find_in_folder(folder, RbVmomi::VIM::VirtualMachine, vmname) || abort("VM #{vmname} not found")
vm = get_vm_by_name(vmname) || fatal_exit("Could not find #{vmname}")

if vm.config.vAppConfig && vm.config.vAppConfig.property
existing_property = vm.config.vAppConfig.property.find { |p| p.props[:id] == property_name.to_s }
Expand Down
15 changes: 4 additions & 11 deletions lib/chef/knife/vsphere_vm_snapshot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

require 'chef/knife'
require 'chef/knife/base_vsphere_command'
require 'rbvmomi'
require 'netaddr'
require 'chef/knife/search_helper'

# Manage snapshots of a virtual machine
class Chef::Knife::VsphereVmSnapshot < Chef::Knife::BaseVsphereCommand
include SearchHelper
banner 'knife vsphere vm snapshot VMNAME (options)'

common_options
Expand Down Expand Up @@ -44,7 +44,7 @@ class Chef::Knife::VsphereVmSnapshot < Chef::Knife::BaseVsphereCommand
description: 'Indicates whether to wait for creation/removal to complete',
boolean: false

option :find,
option :find, # imma deprecate this
long: '--find',
description: 'Finds the virtual machine by searching all folders'

Expand Down Expand Up @@ -77,14 +77,7 @@ def run

vim_connection

vm = if get_config(:find)
puts "No folder entered, searching for #{vmname}"
src_folder = find_folder(get_config(:folder))
traverse_folders_for_vm(src_folder, vmname)
else
base_folder = find_folder get_config(:folder)
find_in_folder(base_folder, RbVmomi::VIM::VirtualMachine, vmname) || abort("VM #{vmname} not found")
end
vm = get_vm_by_name(vmname) || fatal_exit("Could not find #{vmname}")

if vm.snapshot
snapshot_list = vm.snapshot.rootSnapshotList
Expand Down
17 changes: 3 additions & 14 deletions lib/chef/knife/vsphere_vm_state.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

require 'chef/knife'
require 'chef/knife/base_vsphere_command'
require 'rbvmomi'
require 'netaddr'
require 'chef/knife/search_helper'

# Manage power state of a virtual machine
# VsphereVmState extends the BaseVspherecommand
class Chef::Knife::VsphereVmState < Chef::Knife::BaseVsphereCommand
include SearchHelper
# The Different power states that vSphere reports
POWER_STATES = {
PS_ON => 'powered on',
Expand Down Expand Up @@ -56,18 +56,7 @@ def run

vim_connection

if get_config(:recursive)
vms = get_vms(vmname)
if vms.length > 1
abort "More than one VM with name #{vmname} found:\n" + vms.map { |vm| get_path_to_object(vm) }.join("\n")
end
abort "VM #{vmname} not found" if vms.length == 0
vm = vms[0]
else
base_folder = find_folder(get_config(:folder))

vm = find_in_folder(base_folder, RbVmomi::VIM::VirtualMachine, vmname) || abort("VM #{vmname} not found")
end
vm = get_vm_by_name(vmname) || fatal_exit("Could not find #{vmname}")

state = vm.runtime.powerState

Expand Down

0 comments on commit 8b1ab19

Please sign in to comment.