mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
(#9124) Add ability to reload the model of a cloning VM
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.
This commit is contained in:
parent
96ada81149
commit
dc9a2e4808
5 changed files with 85 additions and 10 deletions
|
@ -23,6 +23,7 @@ module Fog
|
|||
request :find_all_by_uuid
|
||||
request :find_all_by_instance_uuid
|
||||
request :find_template_by_instance_uuid
|
||||
request :find_vm_by_ref
|
||||
|
||||
class Mock
|
||||
|
||||
|
|
|
@ -46,14 +46,14 @@ module Fog
|
|||
{
|
||||
:id => is_ready ? vm.config.instanceUuid : vm._ref,
|
||||
:name => vm.name,
|
||||
:uuid => is_ready ? vm.config.uuid : 'unavailable',
|
||||
:instance_uuid => is_ready ? vm.config.instanceUuid : 'unavailable',
|
||||
:uuid => is_ready ? vm.config.uuid : nil,
|
||||
:instance_uuid => is_ready ? vm.config.instanceUuid : nil,
|
||||
:hostname => vm.summary.guest.hostName,
|
||||
:operatingsystem => vm.summary.guest.guestFullName,
|
||||
:ipaddress => vm.summary.guest.ipAddress,
|
||||
:power_state => vm.runtime.powerState,
|
||||
:connection_state => vm.runtime.connectionState,
|
||||
:hypervisor => vm.runtime.host ? vm.runtime.host.name : 'unknown',
|
||||
:hypervisor => vm.runtime.host ? vm.runtime.host.name : nil,
|
||||
:tools_state => vm.summary.guest.toolsStatus,
|
||||
:tools_version => vm.summary.guest.toolsVersionStatus,
|
||||
:mac_addresses => is_ready ? vm.macs : nil,
|
||||
|
|
|
@ -19,8 +19,15 @@ module Fog
|
|||
load(vm_attributes)
|
||||
end
|
||||
|
||||
def get(instance_uuid)
|
||||
vm_mob = connection.find_all_by_instance_uuid(instance_uuid).first
|
||||
def get(id)
|
||||
# Is the id a managed_object_reference? This may be the case if we're reloading
|
||||
# a model of a VM in the process of being cloned, since it
|
||||
# will not have a instance_uuid yet.
|
||||
if id =~ /^vm-/
|
||||
vm_mob = connection.find_vm_by_ref(:vm_ref => id)
|
||||
else
|
||||
vm_mob = connection.find_all_by_instance_uuid(id).first
|
||||
end
|
||||
if server_attributes = model.attribute_hash_from_mob(vm_mob)
|
||||
new(server_attributes)
|
||||
end
|
||||
|
|
28
lib/fog/vsphere/requests/compute/find_vm_by_ref.rb
Normal file
28
lib/fog/vsphere/requests/compute/find_vm_by_ref.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Vsphere
|
||||
class Real
|
||||
|
||||
# REVISIT: This is a naive implementation and not very efficient since
|
||||
# we find ALL VM's and then iterate over them looking for the managed object
|
||||
# reference id... There should be an easier way to obtain a reference to a
|
||||
# VM using only the name or the _ref. This request is primarily intended to
|
||||
# reload the attributes of a cloning VM which does not yet have an instance_uuid
|
||||
def find_vm_by_ref(params = {})
|
||||
list_virtual_machines.detect(lambda { raise Fog::Vsphere::Errors::NotFound }) do |vm|
|
||||
vm._ref == params[:vm_ref]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def find_vm_by_ref(params = {})
|
||||
Fog::Mock.not_implmented
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,8 +4,16 @@ module Fog
|
|||
class Real
|
||||
|
||||
def vm_clone(params = {})
|
||||
raise ArgumentError, ":instance_uuid and :name are required" if params.empty?
|
||||
# First, find the Managed Object of the template VM
|
||||
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.
|
||||
|
@ -24,8 +32,36 @@ module Fog
|
|||
:powerOn => true,
|
||||
:template => false)
|
||||
task = vm.CloneVM_Task(:folder => vm.parent, :name => params[:name], :spec => clone_spec)
|
||||
# REVISIT: We may want to return an identifier for the asyncronous task
|
||||
task.info.state
|
||||
# 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
|
||||
|
@ -33,7 +69,10 @@ module Fog
|
|||
class Mock
|
||||
|
||||
def vm_clone(params = {})
|
||||
"running"
|
||||
{
|
||||
:vm_ref => 'vm-123',
|
||||
:task_ref => 'task-1234'
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue