    # File lib/fog/vsphere/requests/compute/vm_clone.rb, line 33
            def vm_clone(options = {})
              # Option handling
              options = vm_clone_check_options(options)

              notfound = lambda { raise Fog::Compute::Vsphere::NotFound, "Could not find VM template" }

              # Find the template in the folder.  This is more efficient than
              # searching ALL VM's looking for the template.
              # Tap gets rid of the leading empty string and "Datacenters" element
              # and returns the array.
              path_elements = options['path'].split('/').tap { |ary| ary.shift 2 }
              # The DC name itself.
              template_dc = path_elements.shift
              # If the first path element contains "vm" this denotes the vmFolder
              # and needs to be shifted out
              path_elements.shift if path_elements[0] == 'vm'
              # The template name.  The remaining elements are the folders in the
              # datacenter.
              template_name = path_elements.pop
              # Make sure @datacenters is populated.  We need the instances from the Hash keys.
              self.datacenters
              # Get the datacenter managed object from the hash
              dc = @datacenters[template_dc]
              # Get the VM Folder (Group) efficiently
              vm_folder = dc.vmFolder
              # Walk the tree resetting the folder pointer as we go
              folder = path_elements.inject(vm_folder) do |current_folder, sub_folder_name|
                # JJM VIM::Folder#find appears to be quite efficient as it uses the
                # searchIndex It certainly appears to be faster than
                # VIM::Folder#inventory since that returns _all_ managed objects of
                # a certain type _and_ their properties.
                sub_folder = current_folder.find(sub_folder_name, RbVmomi::VIM::Folder)
                raise ArgumentError, "Could not descend into #{sub_folder_name}.  Please check your path." unless sub_folder
                sub_folder
              end

              # Now find the template itself using the efficient find method
              vm_mob_ref = folder.find(template_name, RbVmomi::VIM::VirtualMachine)

              # Now find _a_ resource pool to use for the clone
              # (REVISIT: We need to support cloning into a specific RP)

              if ( vm_mob_ref.resourcePool == nil )
                # If the template is really a template then there is no associated resource pool,
                # so we need to find one using the template's parent host or cluster
                esx_host = vm_mob_ref.collect!('runtime.host')['runtime.host']
                # The parent of the ESX host itself is a ComputeResource which has a resourcePool
                resource_pool = esx_host.parent.resourcePool
              else
                # If the vm given did return a valid resource pool, default to using it for the clone.
                # Even if specific pools aren't implemented in this environment, we will still get back
                # at least the cluster or host we can pass on to the clone task
                resource_pool = vm_mob_ref.resourcePool
              end

              relocation_spec=nil
              if ( options['linked_clone'] )
                # cribbed heavily from the rbvmomi clone_vm.rb
                # this chunk of code reconfigures the disk of the clone source to be read only,
                # and then creates a delta disk on top of that, this is required by the API in order to create
                # linked clondes
                disks = vm_mob_ref.config.hardware.device.select do |vm_device|
                  vm_device.class == RbVmomi::VIM::VirtualDisk
                end
                disks.select{|vm_device| vm_device.backing.parent == nil}.each do |disk|
                  disk_spec = {
                    :deviceChange => [
                      {
                        :operation => :remove,
                        :device => disk
                      },
                      {
                        :operation => :add,
                        :fileOperation => :create,
                        :device => disk.dup.tap{|disk_backing|
                          disk_backing.backing = disk_backing.backing.dup;
                          disk_backing.backing.fileName = "[#{disk.backing.datastore.name}]";
                          disk_backing.backing.parent = disk.backing
                        }
                      },
                    ]
                  }
                  vm_mob_ref.ReconfigVM_Task(:spec => disk_spec).wait_for_completion
                end
                # Next, create a Relocation Spec instance
                relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => resource_pool,
                                                                          :diskMoveType => :moveChildMostDiskBacking)
              else
                relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => resource_pool,
                                                                          :transform => options['transform'] || 'sparse')
              end
              # And the clone specification
              clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocation_spec,
                                                                :powerOn  => options['power_on'] || true,
                                                                :template => false)
              task = vm_mob_ref.CloneVM_Task(:folder => vm_mob_ref.parent, :name => options['name'], :spec => clone_spec)
              # Waiting for the VM to complete allows us to get the VirtulMachine
              # object of the new machine when it's done.  It is HIGHLY recommended
              # to set 'wait' => true if your app wants to wait.  Otherwise, you're
              # going to have to reload the server model over and over which
              # generates a lot of time consuming API calls to vmware.
              if options['wait'] then
                # REVISIT: It would be awesome to call a block passed to this
                # request to notify the application how far along in the process we
                # are.  I'm thinking of updating a progress bar, etc...
                new_vm = task.wait_for_completion
              else
                tries = 0
                new_vm = begin
                  # Try and find the new VM (folder.find is quite efficient)
                  folder.find(options['name'], RbVmomi::VIM::VirtualMachine) or raise Fog::Vsphere::Errors::NotFound
                rescue Fog::Vsphere::Errors::NotFound
                  tries += 1
                  if tries <= 10 then
                    sleep 15
                    retry
                  end
                  nil
                end
              end

              # Return hash
              {
                'vm_ref'        => new_vm ? new_vm._ref : nil,
                'vm_attributes' => new_vm ? convert_vm_mob_ref_to_attr_hash(new_vm) : {},
                'task_ref'      => task._ref
              }
            end