Skip to content

Commit

Permalink
Add CachedOvfDeployer, AdmissionControlledResourceScheduler,
Browse files Browse the repository at this point in the history
LeaseTool classes and example scripts to use them.

The three classes automate common deployment and management
tasks in a large scale and highly automated vSphere environment,
especially in Test/Dev.
  • Loading branch information
administrator committed Aug 15, 2012
1 parent 5dc0ca3 commit 2109d27
Show file tree
Hide file tree
Showing 6 changed files with 1,088 additions and 0 deletions.
120 changes: 120 additions & 0 deletions examples/cached_ovf_deploy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env ruby
require 'trollop'
require 'rbvmomi'
require 'rbvmomi/trollop'
require 'rbvmomi/utils/deploy'
require 'rbvmomi/utils/admission_control'
require 'yaml'

VIM = RbVmomi::VIM

opts = Trollop.options do
banner <<-EOS
Deploy an OVF to a cluster, using a cached template if available.
Usage:
cached_ovf_deploy.rb [options] <vmname> <ovfurl>
VIM connection options:
EOS

rbvmomi_connection_opts

text <<-EOS
VM location options:
EOS

rbvmomi_datacenter_opt
rbvmomi_datastore_opt

text <<-EOS
Other options:
EOS

opt :template_name, "Name to give to the (cached) template", :type => :string
opt :template_path, "Path where templates are stored", :default => 'templates', :type => :string
opt :computer_path, "Path to the cluster to deploy into", :type => :string
opt :network, "Name of the network to attach template to", :type => :string
opt :vm_folder_path, "Path to VM folder to deploy VM into", :type => :string
opt :lease, "Lease in days", :type => :int, :default => 3
end

Trollop.die("must specify host") unless opts[:host]
Trollop.die("no cluster path given") unless opts[:computer_path]
template_folder_path = opts[:template_path]
template_name = opts[:template_name] or Trollop.die("no template name given")
vm_name = ARGV[0] or Trollop.die("no VM name given")
ovf_url = ARGV[1] or Trollop.die("No OVF URL given")

vim = VIM.connect opts
dc = vim.serviceInstance.find_datacenter(opts[:datacenter]) or abort "datacenter not found"

root_vm_folder = dc.vmFolder
vm_folder = root_vm_folder
if opts[:vm_folder_path]
vm_folder = root_vm_folder.traverse(opts[:vm_folder_path], VIM::Folder)
end
template_folder = root_vm_folder.traverse!(template_folder_path, VIM::Folder)

scheduler = AdmissionControlledResourceScheduler.new(
vim,
:datacenter => dc,
:computer_names => [opts[:computer_path]],
:vm_folder => vm_folder,
:rp_path => '/',
:datastore_paths => [opts[:datastore]],
:max_vms_per_pod => nil, # No limits
:min_ds_free => nil, # No limits
)
scheduler.make_placement_decision

datastore = scheduler.datastore
computer = scheduler.pick_computer
# XXX: Do this properly
if opts[:network]
network = computer.network.find{|x| x.name == opts[:network]}
else
network = computer.network[0]
end

lease_tool = LeaseTool.new
lease = opts[:lease] * 24 * 60 * 60
deployer = CachedOvfDeployer.new(
vim, network, computer, template_folder, vm_folder, datastore
)
template = deployer.lookup_template template_name

if !template
puts "#{Time.now}: Uploading/Preparing OVF template ..."

template = deployer.upload_ovf_as_template(
ovf_url, template_name,
:run_without_interruptions => true,
:config => lease_tool.set_lease_in_vm_config({}, lease)
)
end

puts "#{Time.now}: Cloning template ..."
config = {
:numCPUs => opts[:cpus],
:memoryMB => opts[:memory],
}
config = lease_tool.set_lease_in_vm_config(config, lease)
vm = deployer.linked_clone template, vm_name, config

puts "#{Time.now}: Powering On VM ..."
# XXX: Add a retrying version?
vm.PowerOnVM_Task.wait_for_completion

puts "#{Time.now}: Waiting for VM to be up ..."
ip = nil
while !(ip = vm.guest_ip)
sleep 5
end

puts "#{Time.now}: VM got IP: #{ip}"

puts "#{Time.now}: Done"

102 changes: 102 additions & 0 deletions examples/lease_tool.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env ruby
require 'trollop'
require 'rbvmomi'
require 'rbvmomi/trollop'
require 'rbvmomi/utils/leases'
require 'yaml'

VIM = RbVmomi::VIM
CMDS = ['set_lease_on_leaseless_vms', 'show_expired_vms',
'show_soon_expired_vms', 'kill_expired_vms']

opts = Trollop.options do
banner <<-EOS
Tool for managing leases on VMs where leases are stored in YAML on VM annotations.
Usage:
lease_tool.rb [options] <cmd>
Commands: #{CMDS * ' '}
VIM connection options:
EOS

rbvmomi_connection_opts

text <<-EOS
VM location options:
EOS

rbvmomi_datacenter_opt

text <<-EOS
Other options:
EOS

opt :vm_folder_path, "Path to VM folder to deploy VM into", :type => :string
opt :force, "Really perform VMs. Used with kill_expired_vms"

stop_on CMDS
end

Trollop.die("must specify host") unless opts[:host]
cmd = ARGV[0] or Trollop.die("no command given")
Trollop.die("no vm folder path given") unless opts[:vm_folder_path]

vim = VIM.connect opts
dc = vim.serviceInstance.find_datacenter(opts[:datacenter]) or abort "datacenter not found"

root_vm_folder = dc.vmFolder
vm_folder = root_vm_folder.traverse(opts[:vm_folder_path], VIM::Folder)

lease_tool = LeaseTool.new
vms_props_list = (['runtime.powerState'] + lease_tool.vms_props_list).uniq
inventory = vm_folder.inventory_flat('VirtualMachine' => vms_props_list)
inventory = inventory.select{|obj, props| obj.is_a?(VIM::VirtualMachine)}
case cmd
when 'set_lease_on_leaseless_vms'
lease_tool.set_lease_on_leaseless_vms(
inventory.keys, inventory,
:lease_minutes => 3 * 24 * 60 * 60 # 3 days
)
when 'show_expired_vms'
vms = lease_tool.filter_expired_vms inventory.keys, inventory
vms.each do |vm, time_to_expiration|
puts "VM '#{inventory[vm]['name']}' is expired"
end
when 'kill_expired_vms'
vms = lease_tool.filter_expired_vms inventory.keys, inventory
vms.each do |vm, time_to_expiration|
puts "VM '#{inventory[vm]['name']}' is expired"
if !opts[:force]
puts "NOT killing VM '#{inventory[vm]['name']}' because --force not set"
else
puts "Killing expired VM '#{inventory[vm]['name']}'"
# Destroying VMs is very stressful for vCenter, and we aren't in a rush
# so do one VM at a time
if inventory[vm]['runtime.powerState'] == 'poweredOn'
vm.PowerOffVM_Task.wait_for_completion
end
vm.Destroy_Task.wait_for_completion
end
end
when 'show_soon_expired_vms'
vms = lease_tool.filter_expired_vms(
inventory.keys, inventory,
:time_delta => 3.5 * 24 * 60 * 60, # 3.5 days
)
# We could send the user emails here, but for this example, just print the
# VMs that will expire within the next 3.5 days
vms.each do |vm, time_to_expiration|
if time_to_expiration > 0
hours_to_expiration = time_to_expiration / (60.0 * 60.0)
puts "VM '%s' expires in %.2fh" % [inventory[vm]['name'], hours_to_expiration]
else
puts "VM '#{inventory[vm]['name']}' is expired"
end
end
else
abort "invalid command"
end
Loading

0 comments on commit 2109d27

Please sign in to comment.