Class: VagrantPlugins::VSphere::Action::Clone

Inherits:
Object
  • Object
show all
Includes:
Util::VimHelpers
Defined in:
lib/vSphere/action/clone.rb

Instance Method Summary collapse

Methods included from Util::VimHelpers

#find_clustercompute_or_compute_resource, #get_compute_resource, #get_customization_spec_info_by_name, #get_datacenter, #get_datastore, #get_network_by_name, #get_resource_pool, #get_vm_by_uuid

Constructor Details

#initialize(app, _env) ⇒ Clone

Returns a new instance of Clone.



11
12
13
# File 'lib/vSphere/action/clone.rb', line 11

def initialize(app, _env)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/vSphere/action/clone.rb', line 15

def call(env)
  machine = env[:machine]
  config = machine.provider_config
  connection = env[:vSphere_connection]
  name = get_name machine, config, env[:root_path]
  dc = get_datacenter connection, machine
  template = dc.find_vm config.template_name
  fail Errors::VSphereError, :'missing_template' if template.nil?
  vm_base_folder = get_vm_base_folder dc, template, config
  fail Errors::VSphereError, :'invalid_base_path' if vm_base_folder.nil?

  begin
    # Storage DRS does not support vSphere linked clones. http://www.vmware.com/files/pdf/techpaper/vsphere-storage-drs-interoperability.pdf
    ds = get_datastore dc, machine
    fail Errors::VSphereError, :'invalid_configuration_linked_clone_with_sdrs' if config.linked_clone && ds.is_a?(RbVmomi::VIM::StoragePod)

    location = get_location ds, dc, machine, template
    spec = RbVmomi::VIM.VirtualMachineCloneSpec location: location, powerOn: true, template: false
    spec[:config] = RbVmomi::VIM.VirtualMachineConfigSpec
    customization_info = get_customization_spec_info_by_name connection, machine

    spec[:customization] = get_customization_spec(machine, customization_info) unless customization_info.nil?

    env[:ui].info "Setting custom address: #{config.addressType}" unless config.addressType.nil?
    add_custom_address_type(template, spec, config.addressType) unless config.addressType.nil?

    env[:ui].info "Setting custom mac: #{config.mac}" unless config.mac.nil?
    add_custom_mac(template, spec, config.mac) unless config.mac.nil?

    env[:ui].info "Setting custom vlan: #{config.vlan}" unless config.vlan.nil?
    add_custom_vlan(template, dc, spec, config.vlan) unless config.vlan.nil?

    env[:ui].info "Setting custom memory: #{config.memory_mb}" unless config.memory_mb.nil?
    add_custom_memory(spec, config.memory_mb) unless config.memory_mb.nil?

    env[:ui].info "Setting custom cpu count: #{config.cpu_count}" unless config.cpu_count.nil?
    add_custom_cpu(spec, config.cpu_count) unless config.cpu_count.nil?

    env[:ui].info "Setting custom cpu reservation: #{config.cpu_reservation}" unless config.cpu_reservation.nil?
    add_custom_cpu_reservation(spec, config.cpu_reservation) unless config.cpu_reservation.nil?

    env[:ui].info "Setting custom memmory reservation: #{config.mem_reservation}" unless config.mem_reservation.nil?
    add_custom_mem_reservation(spec, config.mem_reservation) unless config.mem_reservation.nil?
    add_custom_extra_config(spec, config.extra_config) unless config.extra_config.empty?
    add_custom_notes(spec, config.notes) unless config.notes.nil?

    if !config.clone_from_vm && ds.is_a?(RbVmomi::VIM::StoragePod)

      storage_mgr = connection.serviceContent.storageResourceManager
      pod_spec = RbVmomi::VIM.StorageDrsPodSelectionSpec(storagePod: ds)
      # TODO: May want to add option on type?
      storage_spec = RbVmomi::VIM.StoragePlacementSpec(type: 'clone', cloneName: name, folder: vm_base_folder, podSelectionSpec: pod_spec, vm: template, cloneSpec: spec)

      env[:ui].info I18n.t('vsphere.requesting_sdrs_recommendation')
      env[:ui].info " -- DatastoreCluster: #{ds.name}"
      env[:ui].info " -- Template VM: #{template.pretty_path}"
      env[:ui].info " -- Target VM: #{vm_base_folder.pretty_path}/#{name}"

      result = storage_mgr.RecommendDatastores(storageSpec: storage_spec)

      recommendation = result.recommendations[0]
      key = recommendation.key ||= ''
      if key == ''
        fail Errors::VSphereError, :missing_datastore_recommendation
      end

      env[:ui].info I18n.t('vsphere.creating_cloned_vm_sdrs')
      env[:ui].info " -- Storage DRS recommendation: #{recommendation.target.name} #{recommendation.reasonText}"

      apply_sr_result = storage_mgr.ApplyStorageDrsRecommendation_Task(key: [key]).wait_for_completion
      new_vm = apply_sr_result.vm

    else
      env[:ui].info I18n.t('vsphere.creating_cloned_vm')
      env[:ui].info " -- #{config.clone_from_vm ? 'Source' : 'Template'} VM: #{template.pretty_path}"
      env[:ui].info " -- Target VM: #{vm_base_folder.pretty_path}/#{name}"

      new_vm = template.CloneVM_Task(folder: vm_base_folder, name: name, spec: spec).wait_for_completion

      config.custom_attributes.each do |k, v|
        env[:ui].info "Setting custom attribute: #{k}=#{v}"
        new_vm.setCustomValue(key: k, value: v)
      end
    end
  rescue Errors::VSphereError
    raise
  rescue StandardError => e
    raise Errors::VSphereError.new, e.message
  end

  # TODO: handle interrupted status in the environment, should the vm be destroyed?

  machine.id = new_vm.config.uuid

  wait_for_sysprep(env, new_vm, connection, 600, 10) if config.wait_for_sysprep && machine.config.vm.guest.eql?(:windows)

  env[:ui].info I18n.t('vsphere.vm_clone_success')

  @app.call env
end