Class: Support::CloneVm
- Inherits:
-
Object
- Object
- Support::CloneVm
- Defined in:
- lib/support/clone_vm.rb
Instance Attribute Summary collapse
-
#ip ⇒ Object
readonly
Returns the value of attribute ip.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#vim ⇒ Object
readonly
Returns the value of attribute vim.
-
#vm ⇒ Object
readonly
Returns the value of attribute vm.
Instance Method Summary collapse
- #clone ⇒ Object
- #get_ip(vm) ⇒ Object
-
#initialize(conn_opts, options) ⇒ CloneVm
constructor
A new instance of CloneVm.
- #wait_for_ip(vm, timeout = 30.0, interval = 2.0) ⇒ Object
Constructor Details
#initialize(conn_opts, options) ⇒ CloneVm
Returns a new instance of CloneVm.
8 9 10 11 12 13 14 |
# File 'lib/support/clone_vm.rb', line 8 def initialize(conn_opts, ) @options = @name = [:name] # Connect to vSphere @vim ||= RbVmomi::VIM.connect conn_opts end |
Instance Attribute Details
#ip ⇒ Object (readonly)
Returns the value of attribute ip.
6 7 8 |
# File 'lib/support/clone_vm.rb', line 6 def ip @ip end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
6 7 8 |
# File 'lib/support/clone_vm.rb', line 6 def name @name end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
6 7 8 |
# File 'lib/support/clone_vm.rb', line 6 def @options end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
6 7 8 |
# File 'lib/support/clone_vm.rb', line 6 def path @path end |
#vim ⇒ Object (readonly)
Returns the value of attribute vim.
6 7 8 |
# File 'lib/support/clone_vm.rb', line 6 def vim @vim end |
#vm ⇒ Object (readonly)
Returns the value of attribute vm.
6 7 8 |
# File 'lib/support/clone_vm.rb', line 6 def vm @vm end |
Instance Method Details
#clone ⇒ Object
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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/support/clone_vm.rb', line 42 def clone # set the datacenter name dc = vim.serviceInstance.find_datacenter([:datacenter]) # reference template using full inventory path root_folder = @vim.serviceInstance.content.rootFolder inventory_path = format("/%s/vm/%s", [:datacenter], [:template]) src_vm = root_folder.findByInventoryPath(inventory_path) raise format("Unable to find template: %s", [:template]) if src_vm.nil? # Specify where the machine is going to be created relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec # Setting the host is not allowed for instant clone due to VM memory sharing relocate_spec.host = [:targethost].host unless [:clone_type] == :instant # Change to delta disks for linked clones relocate_spec.diskMoveType = :moveChildMostDiskBacking if [:clone_type] == :linked # Set the resource pool relocate_spec.pool = [:resource_pool] # Change network, if wanted unless [:network_name].nil? all_network_devices = src_vm.config.hardware.device.select do |device| device.is_a?(RbVmomi::VIM::VirtualEthernetCard) end # Only support for first NIC so far network_device = all_network_devices.first networks = dc.network.select { |n| n.name == [:network_name] } raise format("Could not find network named %s", option[:network_name]) if networks.empty? Kitchen.logger.warn format("Found %d networks named %s, picking first one", networks.count, [:network_name]) if networks.count > 1 network_obj = networks.first if network_obj.is_a? RbVmomi::VIM::DistributedVirtualPortgroup Kitchen.logger.info format("Assigning network %s...", network_obj.pretty_path) vds_obj = network_obj.config.distributedVirtualSwitch Kitchen.logger.info format("Using vDS '%s' for network connectivity...", vds_obj.name) network_device.backing = RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( port: RbVmomi::VIM.DistributedVirtualSwitchPortConnection( portgroupKey: network_obj.key, switchUuid: vds_obj.uuid ) ) elsif network_obj.is_a? RbVmomi::VIM::Network Kitchen.logger.info format("Assigning network %s...", [:network_name]) network_device.backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( deviceName: [:network_name] ) else raise format("Unknown network type %s for network name %s", network_obj.class.to_s, [:network_name]) end relocate_spec.deviceChange = [ RbVmomi::VIM.VirtualDeviceConfigSpec( operation: RbVmomi::VIM::VirtualDeviceConfigSpecOperation("edit"), device: network_device ) ] end # Set the folder to use dest_folder = [:folder].nil? ? dc.vmFolder : [:folder][:id] Kitchen.logger.info format("Cloning '%s' to create the VM...", [:template]) if [:clone_type] == :instant vcenter_data = vim.serviceInstance.content.about raise "Instant clones only supported with vCenter 6.7 or higher" unless vcenter_data.version.to_f >= 6.7 Kitchen.logger.debug format("Detected %s", vcenter_data.fullName) resources = dc.hostFolder.children hosts = resources.select { |resource| resource.class.to_s =~ /ComputeResource$/ }.map { |c| c.host }.flatten targethost = hosts.select { |host| host.summary.config.name == [:targethost].name }.first raise "No matching ComputeResource found in host folder" if targethost.nil? esx_data = targethost.summary.config.product raise "Instant clones only supported with ESX 6.7 or higher" unless esx_data.version.to_f >= 6.7 Kitchen.logger.debug format("Detected %s", esx_data.fullName) # Other tools check for VMWare Tools status, but that will be toolsNotRunning on frozen VMs raise "Need a running VM for instant clones" unless src_vm.runtime.powerState == "poweredOn" # In first iterations, only support the Frozen Source VM workflow. This is more efficient # but needs preparations (freezing the source VM). Running Source VM support is to be # added later raise "Need a frozen VM for instant clones, running source VM not supported yet" unless src_vm.runtime.instantCloneFrozen # Swapping NICs not needed anymore (blog posts mention this), instant clones get a new # MAC at least with 6.7.0 build 9433931 # @todo not working yet # relocate_spec.folder = dest_folder clone_spec = RbVmomi::VIM.VirtualMachineInstantCloneSpec(location: relocate_spec, name: name) task = src_vm.InstantClone_Task(spec: clone_spec) else clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(location: relocate_spec, powerOn: [:poweron], template: false) task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: name) end task.wait_for_completion # get the IP address of the machine for bootstrapping # machine name is based on the path, e.g. that includes the folder @path = [:folder].nil? ? name : format("%s/%s", [:folder][:name], name) @vm = dc.find_vm(path) if vm.nil? raise format("Unable to find machine: %s", path) else Kitchen.logger.info format("Waiting for VMware tools/network interfaces to become available (timeout: %d seconds)...", [:wait_timeout]) wait_for_ip(vm, [:wait_timeout], [:wait_interval]) Kitchen.logger.info format("Created machine %s with IP %s", name, ip) end end |
#get_ip(vm) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/support/clone_vm.rb', line 16 def get_ip(vm) @ip = nil unless vm.guest.net.empty? || !vm.guest.ipAddress @ip = vm.guest.net[0].ipConfig.ipAddress.detect do |addr| addr.origin != "linklayer" end.ipAddress end ip end |
#wait_for_ip(vm, timeout = 30.0, interval = 2.0) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/support/clone_vm.rb', line 28 def wait_for_ip(vm, timeout = 30.0, interval = 2.0) start = Time.new ip = nil loop do ip = get_ip(vm) break if ip || (Time.new - start) >= timeout sleep interval end raise "Timeout waiting for IP address or no VMware Tools installed on guest" if ip.nil? raise format("Error getting accessible IP address, got %s. Check DHCP server and scope exhaustion", ip) if ip =~ /^169\.254\./ end |