mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
dc9a2e4808
Without this patch it is very difficult to reload the model of a VM in the process of being cloned. All we have is the vmware managed object reference ID string and the name of the VM. This patch adds a number of improvements: First, the model of a VM being cloned can reload itself after the VM finishes cloning, even though we don't have an instance_uuid until the clone completes. Because the model can reload itself, it's now possible to do something like: c = Fog::Compute[:vsphere] new_vm_name = "test" c.vm_clone(:instance_uuid => "abc123", :name => new_vm_name) my_new_vm = c.servers.find { |vm| vm.name == new_vm_name } my_new_vm.wait_for { uuid } puts "New VM is ready! (It has a UUID)" my_new_vm.wait_for { ipaddress } puts "New VM is on the network!" Without this patch, a VM model could not reload itself with an id of 'vm-123', reloading the model only works if the ID is a UUID. In addition, a number of the attributes of the server model have been adjusted to be nil values when the VM is in the process of cloning. This makes it easier to use wait_for conditionals in blocks.
81 lines
3.2 KiB
Ruby
81 lines
3.2 KiB
Ruby
module Fog
|
|
module Compute
|
|
class Vsphere
|
|
class Real
|
|
|
|
def vm_clone(params = {})
|
|
params = { :force => false }.merge(params)
|
|
required_params = %w{ instance_uuid name }
|
|
required_params.each do |param|
|
|
raise ArgumentError, "#{required_params.join(', ')} are required" unless params.has_key? param.to_sym
|
|
end
|
|
# First, figure out if there's already a VM of the same name.
|
|
if not params[:force] and list_virtual_machines.detect { |vm| vm.name == params[:name] } then
|
|
raise Fog::Vsphere::Errors::ServiceError, "A VM already exists with name #{params[:name]}"
|
|
end
|
|
# Find the Managed Object reference of the template VM
|
|
vm = find_template_by_instance_uuid(params[:instance_uuid])
|
|
# We need to locate the datacenter object to find the
|
|
# default resource pool.
|
|
container = vm.parent
|
|
until container.kind_of? RbVmomi::VIM::Datacenter
|
|
container = container.parent
|
|
end
|
|
dc = container
|
|
# With the Datacenter Object we can obtain the resource pool
|
|
resource_pool = dc.hostFolder.children.first.resourcePool
|
|
# Next, create a Relocation Spec instance
|
|
relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => resource_pool,
|
|
:transform => 'sparse')
|
|
# And the clone specification
|
|
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocation_spec,
|
|
:powerOn => true,
|
|
:template => false)
|
|
task = vm.CloneVM_Task(:folder => vm.parent, :name => params[:name], :spec => clone_spec)
|
|
# REVISIT: The task object contains a reference to the template but does
|
|
# not appear to contain a reference to the newly created VM.
|
|
# This is a really naive way to find the managed object reference
|
|
# of the newly created VM.
|
|
tries = 0
|
|
new_vm = begin
|
|
list_virtual_machines.detect(lambda { raise Fog::Vsphere::Errors::NotFound }) do |vm|
|
|
next false if vm.name != params[:name]
|
|
begin
|
|
vm.config ? true : false
|
|
rescue RuntimeError
|
|
# This rescue is here because we want to make sure we find
|
|
# a VM _without_ a config, which indicates the VM is still cloning.
|
|
true
|
|
end
|
|
end
|
|
rescue Fog::Vsphere::Errors::NotFound
|
|
tries += 1
|
|
if tries <= 10 then
|
|
sleep 2
|
|
retry
|
|
end
|
|
nil
|
|
end
|
|
# Taking a hint from wait_for we return a hash to indicate this is a
|
|
# managed object reference
|
|
{
|
|
:vm_ref => new_vm ? new_vm._ref : nil,
|
|
:task_ref => task._ref
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
class Mock
|
|
|
|
def vm_clone(params = {})
|
|
{
|
|
:vm_ref => 'vm-123',
|
|
:task_ref => 'task-1234'
|
|
}
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|