From 81897e9bb824d721efcd020e7f49cf40c7c73404 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 2 Dec 2016 19:10:55 +0100 Subject: [PATCH 001/297] F 4913: vcenter default attributes. It's now a system ds TM and it's not PERSISTENT_ONLY --- share/etc/oned.conf | 4 ++-- src/nebula/NebulaTemplate.cc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 2f3a43d25f..d2058104cf 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -559,7 +559,7 @@ TM_MAD = [ DATASTORE_MAD = [ EXECUTABLE = "one_datastore", - ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,dev,iscsi_libvirt,vcenter -s shared,ssh,ceph,fs_lvm,qcow2" + ARGUMENTS = "-t 15 -d dummy,fs,lvm,ceph,dev,iscsi_libvirt,vcenter -s shared,ssh,ceph,fs_lvm,qcow2,vcenter" ] #******************************************************************************* @@ -1016,7 +1016,7 @@ DS_MAD_CONF = [ ] DS_MAD_CONF = [ - NAME = "vcenter", REQUIRED_ATTRS = "VCENTER_CLUSTER", PERSISTENT_ONLY = "YES", + NAME = "vcenter", REQUIRED_ATTRS = "VCENTER_CLUSTER", PERSISTENT_ONLY = "NO", MARKETPLACE_ACTIONS = "export" ] diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index fc24297f84..b1f4f7469c 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -135,6 +135,7 @@ void OpenNebulaTemplate::set_multiple_conf_default() set_conf_ds("shared", "", "NO"); set_conf_ds("ssh", "", "NO"); set_conf_ds("vmfs", "BRIDGE_LIST", "NO"); + set_conf_ds("vcenter", "VCENTER_CLUSTER", "NO"); set_conf_ds("ceph", "DISK_TYPE,BRIDGE_LIST,CEPH_HOST,CEPH_USER,CEPH_SECRET", "NO"); From f0d34ca603c3c00d3f5a6fa5bf78069fe630d0e9 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 2 Dec 2016 19:14:41 +0100 Subject: [PATCH 002/297] F 4913: Use VCENTER_NAME to monitor datastores --- src/datastore_mad/remotes/vcenter/monitor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index a07f8136c9..883ea0da77 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -39,7 +39,7 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] +ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_NAME"] hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] if ds_name.nil? || From 781a9928100889b09577b068f83d26763ea8d24b Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 2 Dec 2016 19:16:30 +0100 Subject: [PATCH 003/297] F 4913: Implement non-persistent images (clone and delete) --- src/tm_mad/vcenter/clone | 104 +++++++++++++++++- src/tm_mad/vcenter/delete | 24 +++- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 68 +++++++++--- 3 files changed, 181 insertions(+), 15 deletions(-) mode change 120000 => 100755 src/tm_mad/vcenter/clone diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone deleted file mode 120000 index 300563f2ad..0000000000 --- a/src/tm_mad/vcenter/clone +++ /dev/null @@ -1 +0,0 @@ -../common/dummy.sh \ No newline at end of file diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone new file mode 100755 index 0000000000..2ea33c32fe --- /dev/null +++ b/src/tm_mad/vcenter/clone @@ -0,0 +1,103 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +# clone fe:SOURCE host:remote_system_ds/disk.i vmid dsid +# - fe is the front-end hostname +# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk +# - host is the target host to deploy the VM +# - remote_system_ds is the path for the system datastore in the host +# - vmid is the id of the VM +# - dsid is the target datastore (0 is the system datastore) + +ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) +end + +$: << RUBY_LIB_LOCATION +$: << File.dirname(__FILE__) + +require 'opennebula' +require 'vcenter_driver' +require 'digest' + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to clone the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + +src = ARGV[0] +dst = ARGV[1] +vm_id = ARGV[2] +source_ds_id = ARGV[3] + +target_ds_id = dst.split("/")[-3] +disk_id = dst.split(".")[-1] + +src_host, src_path = src.split ":" +hostname, dst_path = dst.split ":" + +client = OpenNebula::Client.new +ds_pool = OpenNebula::DatastorePool.new(client) + +rc = ds_pool.info +if OpenNebula.is_error?(rc) + puts rc.message + exit -1 +end + +xml = "/DATASTORE_POOL/DATASTORE[ID='#{source_ds_id}']/TEMPLATE/VCENTER_NAME" +source_ds = ds_pool[xml] + +xml = "/DATASTORE_POOL/DATASTORE[ID='#{target_ds_id}']/TEMPLATE/VCENTER_NAME" +target_ds = ds_pool[xml] + +################################################################################ + +# Generate target path +target_path = "one_#{vm_id}_#{disk_id}.vmdk" + +################################################################################ + +# Check for errors +check_valid source_ds, "source_ds" +check_valid target_ds, "target_ds" +check_valid hostname, "hostname" +check_valid src_path, "src_path" + +################################################################################ + +begin + host_id = VCenterDriver::VIClient.translate_hostname(hostname) + vi_client = VCenterDriver::VIClient.new host_id + + vi_client.copy_virtual_disk(src_path, source_ds, target_path, target_ds) +rescue Exception => e + STDERR.puts "Error cloning img #{src_path} size. Reason: #{e.message}" + exit -1 +end diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index 039de76570..10dbf275ad 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -22,6 +22,15 @@ # - vmid is the id of the VM # - dsid is the target datastore (0 is the system datastore) +# Return if this has called for the whole directory, instead of for a specific +# disk. + +if !ARGV[0].match(/disk\.\d+$/) + exit(0) +end + +# ---------------------------------------------------------------------------- # + ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION @@ -34,11 +43,24 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' hostname, img_path = ARGV[0].split(":") vmid = ARGV[1] dsid = ARGV[2] +client = OpenNebula::Client.new +vm = OpenNebula::VirtualMachine.new_with_id(vmid, client) +vm.info + +disk_id = img_path.split(".")[-1] + +persistent = vm["TEMPLATE/DISK[DISK_ID=#{disk_id}]/PERSISTENT"] + +if persistent != "YES" + img_path = "one_#{vmid}_#{disk_id}.vmdk" +end + begin host_id = VCenterDriver::VIClient.translate_hostname(hostname) vi_client = VCenterDriver::VIClient.new host_id @@ -47,6 +69,6 @@ begin vi_client.delete_virtual_disk(img_path, ds_name) rescue Exception => e STDERR.puts "Error delete virtual disk #{img_path} in datastore #{dsid}."\ - " Reason: #{e.message}" + " Reason: #{e.message}\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index c671e3f976..4279a81d70 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -823,7 +823,7 @@ class VIClient end def self.find_ds_name(ds_id) - ds = OpenNebula::Datastore.new_with_id(ds_id) + ds = OpenNebula::Datastore.new_with_id(ds_id, OpenNebula::Client.new) rc = ds.info raise "Could not find datastore #{ds_id}" if OpenNebula.is_error?(rc) @@ -1524,6 +1524,7 @@ class VCenterVm reconfigure_vm(vm, xml, false, hostname) vm.PowerOnVM_Task.wait_for_completion + return vm.config.uuid end end @@ -1537,13 +1538,15 @@ class VCenterVm # @param disks VM attached disks ############################################################################ def self.cancel(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) + case lcm_state when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) when "CANCEL", "LCM_INIT", "CLEANUP_RESUBMIT", "SHUTDOWN", "CLEANUP_DELETE" hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) + + vm = connection.find_vm_template(deploy_id) begin if vm.summary.runtime.powerState == "poweredOn" @@ -1551,6 +1554,7 @@ class VCenterVm end rescue end + if keep_disks detach_all_disks(vm) else @@ -1661,7 +1665,8 @@ class VCenterVm hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) + vm = connection.find_vm_template(deploy_id) + vmid = get_vm_id case lcm_state when "SHUTDOWN" @@ -2628,8 +2633,6 @@ private end - - reconfigure_vm(vm, xml, true, hostname) # Power on the VM @@ -2860,11 +2863,11 @@ private hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) disks.each{|disk| - ds_name = disk.elements["DATASTORE"].text - img_name = disk.elements["SOURCE"].text - type_str = disk.elements["TYPE"].text + ds_name = disk.elements["DATASTORE"].text + img_name = get_disk_img_path(disk, vmid) + type_str = disk.elements["TYPE"].text - disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection)[:deviceChange] + disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection)[:deviceChange] } device_change += disk_array @@ -2888,6 +2891,7 @@ private end spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + vm.ReconfigVM_Task(:spec => spec).wait_for_completion end @@ -2924,7 +2928,7 @@ private end } - ds = datastores.select{|ds| ds.name == ds_name}[0] + ds = datastores.select{|ds| ds.name == ds_name}[0] controller, new_number = find_free_controller(vm) @@ -3165,14 +3169,20 @@ private hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) + vmid = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.vm.id" + end.first.value + spec = { :deviceChange => [] } disks.each{ |disk| - ds_and_img_name = "[#{disk['DATASTORE']}] #{disk['SOURCE']}" - vcenter_disk = vm.config.hardware.device.select { |d| is_disk?(d) && + img_name = get_disk_img_path(disk, vmid) + ds_and_img_name = "[#{disk['DATASTORE']}] #{img_name}" + + vcenter_disk = vm.config.hardware.device.select { |d| is_disk?(d) && d.backing.respond_to?(:fileName) && d.backing.fileName == ds_and_img_name }[0] - spec[:deviceChange] << { + spec[:deviceChange] << { :operation => :remove, :device => vcenter_disk } @@ -3180,5 +3190,37 @@ private vm.ReconfigVM_Task(:spec => spec).wait_for_completion end + + + ############################################################################ + # Returns the source path of a disk. It will use the 'SOURCE' path if + # persistent and one-#{vm_id}-#{disk_id}.vmdk otherwise + # @param disks VM attached disks, either an REXML document, or a hash + # @param vmid The VM ID + ############################################################################ + def self.get_disk_img_path(disk, vmid) + if disk.respond_to? :elements + # It's a REXML::Document, probably coming from self.reconfigure_vm + persistent = disk.elements["PERSISTENT"].text == "YES" rescue false + + if persistent + disk.elements["SOURCE"].text + else + disk_id = disk.elements["DISK_ID"].text + "one_#{vmid}_#{disk_id}.vmdk" + end + else + # It's a hash, probably coming from self.detach_attached_disks + persistent = disk["PERSISTENT"] == "YES" + + if persistent + disk["SOURCE"] + else + disk_id = disk["DISK_ID"] + "one_#{vmid}_#{disk_id}.vmdk" + end + end + end + end end From 6dc089f224759088ed55a57c6f2d14e8dd49e4ed Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 2 Dec 2016 19:16:50 +0100 Subject: [PATCH 004/297] F 4913: be more verbose --- src/vmm_mad/remotes/vcenter/cancel | 2 +- src/vmm_mad/remotes/vcenter/deploy | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index a221ebc597..a6b94259ef 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -55,6 +55,6 @@ begin VCenterDriver::VCenterVm.cancel(deploy_id, host, lcm_state, keep_disks, disks, cloned_tmplt) rescue Exception => e STDERR.puts "Cancel of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" + "due to \"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 12d0c2bff4..31e977d1eb 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -59,7 +59,6 @@ begin ops) rescue Exception => e STDERR.puts "Deploy of VM #{vm_id} on host #{host} with #{dfile} failed " + - "due to \"#{e.message}\"" + "due to \"#{e.message}\"\n#{e.backtrace}" exit -1 end - From cfbbb845dcffa20abb899ce4c5b096182688df44 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 2 Dec 2016 19:17:06 +0100 Subject: [PATCH 005/297] F 4913: Remove public cloud attribute --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 4279a81d70..8b3f48804a 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -1246,7 +1246,6 @@ class VCenterHost < ::OpenNebula::Host # System str_info << "HYPERVISOR=vcenter\n" - str_info << "PUBLIC_CLOUD=YES\n" str_info << "TOTALHOST=" << summary.numHosts.to_s << "\n" str_info << "AVAILHOST=" << summary.numEffectiveHosts.to_s << "\n" From ec638228a4623e6161f74408d3b7ed8790c3d81a Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 5 Dec 2016 12:05:57 +0100 Subject: [PATCH 006/297] F #4913: Temporary solution for DS/clone to other datastores This solutions is not adequate because it requires 2 API calls to the name of the vcenter datastore --- src/datastore_mad/remotes/vcenter/clone | 38 +++++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 62fe90228e..f0807acc42 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -17,7 +17,7 @@ # ---------------------------------------------------------------------------- # ############################################################################### -# This script is used retrieve the file size of a disk +# This script is used retrieve the file size of a disk ############################################################################### ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) @@ -31,6 +31,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) +require 'opennebula' require 'vcenter_driver' require 'digest' @@ -40,16 +41,41 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] +target_ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] +hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] +src_img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/CLONING_ID"] -if ds_name.nil? || hostname.nil? || img_path.nil? +if target_ds_name.nil? || hostname.nil? || img_path.nil? STDERR.puts "Not enough information to clone the image, missing datastore"\ " name or vcenter cluster name or image path." exit -1 end +# Get source image +client = OpenNebula::Client.new + +src_img = OpenNebula::Image.new_with_id(src_img_id, client) + +rc = src_img.info +if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit -1 +end + +src_ds_id = src_img['DATASTORE_ID'] + +# Get the source datastore +src_ds = OpenNebula::Datastore.new_with_id(src_ds_id, client) + +rc = src_ds.info +if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit -1 +end + +src_ds_name = src_ds["TEMPLATE/VCENTER_NAME"] + # Generate target path str_for_target_path = Time.now.to_s + id.to_s target_path = Digest::MD5.hexdigest(str_for_target_path) + ".vmdk" @@ -58,7 +84,7 @@ begin host_id = VCenterDriver::VIClient.translate_hostname(hostname) vi_client = VCenterDriver::VIClient.new host_id - puts vi_client.copy_virtual_disk(img_path, ds_name, target_path) + puts vi_client.copy_virtual_disk(img_path, src_ds_name, target_path, target_ds_name) rescue Exception => e STDERR.puts "Error cloning img #{img_path} size. Reason: #{e.message}" exit -1 From fedbfaafe4aaf70c3f3dea83fe4e83365ecb60be Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 5 Dec 2016 18:32:48 +0100 Subject: [PATCH 007/297] F #4913: Add support for save_as in the ds/mkfs script. Change the naming schema for new datablocks to an uuid. --- src/datastore_mad/remotes/vcenter/mkfs | 43 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index b2b7cf3e3b..97532ebf2c 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -17,7 +17,7 @@ # ---------------------------------------------------------------------------- # ############################################################################### -# This script is used retrieve the file size of a disk +# This script is used retrieve the file size of a disk ############################################################################### ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) @@ -32,11 +32,24 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'digest' + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to create the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ drv_action_enc = ARGV[0] id = ARGV[1] -drv_action =OpenNebula::XMLElement.new +drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] @@ -44,21 +57,25 @@ hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CL adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] -img_name = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/NAME"] +fs_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/FSTYPE"] -if ds_name.nil? || - hostname.nil? || - adapter_type.nil? || - disk_type.nil? || - size.nil? || - img_name.nil? - STDERR.puts "Not enough information to create the image." - exit -1 +str_for_target_path = Time.now.to_s + id.to_s +target_path = Digest::MD5.hexdigest(str_for_target_path) + +if fs_type == "save_as" + puts target_path + ".vmdk" + exit 0 end +check_valid ds_name, "ds_name" +check_valid hostname, "hostname" +check_valid adapter_type, "adapter_type" +check_valid disk_type, "disk_type" +check_valid size, "size" + begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + host_id = VCenterDriver::VIClient.translate_hostname(hostname) + vi_client = VCenterDriver::VIClient.new host_id puts vi_client.create_virtual_disk(img_name, ds_name, From a3a82e4e6e263a036224ff0021787ffb6e815a3b Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 5 Dec 2016 18:33:28 +0100 Subject: [PATCH 008/297] F #4913: Typo --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 8b3f48804a..caccb9513f 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -1665,7 +1665,6 @@ class VCenterVm connection = VIClient.new(hid) vm = connection.find_vm_template(deploy_id) - vmid = get_vm_id case lcm_state when "SHUTDOWN" From 42ae61e20039fd6b481e8316a9eb61cd6dd72d16 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 5 Dec 2016 18:33:54 +0100 Subject: [PATCH 009/297] F #4913: Add tm/cpds for vcenter --- src/tm_mad/vcenter/cpds | 115 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) mode change 120000 => 100755 src/tm_mad/vcenter/cpds diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds deleted file mode 120000 index 300563f2ad..0000000000 --- a/src/tm_mad/vcenter/cpds +++ /dev/null @@ -1 +0,0 @@ -../common/dummy.sh \ No newline at end of file diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds new file mode 100755 index 0000000000..fe84ae4486 --- /dev/null +++ b/src/tm_mad/vcenter/cpds @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +# cpds host:remote_system_ds/disk.i fe:SOURCE snap_id vmid ds_id +# - fe is the front-end hostname +# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk +# - host is the target host to deploy the VM +# - remote_system_ds is the path for the system datastore in the host +# - snap_id is the snapshot id. "-1" for none + +ONE_LOCATION = ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION = "/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) +else + RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" if !defined?(RUBY_LIB_LOCATION) +end + +$: << RUBY_LIB_LOCATION +$: << File.dirname(__FILE__) + +require 'opennebula' +require 'vcenter_driver' +require 'digest' + +client = OpenNebula::Client.new + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to perform cpds of the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + +src = ARGV[0] +target_path = ARGV[1] +snap_id = ARGV[2] +vmid = ARGV[3] +target_ds_id = ARGV[4] + +source_ds_id = src.split("/")[-3] +disk_id = src.split(".")[-1] + +hostname, src_path = src.split ":" + +################################################################################ + +vm = OpenNebula::VirtualMachine.new_with_id(vmid, client) +rc = vm.info +if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit -1 +end + +persistent = vm["TEMPLATE/DISK[DISK_ID=#{disk_id}]/PERSISTENT"] == "YES" + +if persistent + src_path = vm["TEMPLATE/DISK[DISK_ID=#{disk_id}]/SOURCE"] +else + src_path = "one_#{vmid}_#{disk_id}.vmdk" +end + +if vm.state == 3 + STDERR.puts "'disk-saveas' operation is not supported for running VMs." + exit 1 +end + +################################################################################ + +ds_pool = OpenNebula::DatastorePool.new(client) + +rc = ds_pool.info +if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit -1 +end + +xpath = "/DATASTORE_POOL/DATASTORE[ID='#{source_ds_id}']/TEMPLATE/VCENTER_NAME" +source_ds = ds_pool[xpath] + +xpath = "/DATASTORE_POOL/DATASTORE[ID='#{target_ds_id}']/TEMPLATE/VCENTER_NAME" +target_ds = ds_pool[xpath] + +################################################################################ + +begin + host_id = VCenterDriver::VIClient.translate_hostname(hostname) + vi_client = VCenterDriver::VIClient.new host_id + + vi_client.copy_virtual_disk(src_path, source_ds, target_path, target_ds) +rescue Exception => e + STDERR.puts "Error cloning img #{src_path} size. Reason: #{e.message}" + exit -1 +end From 22289618a772f7927489a2d0064fdd00c245d853 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 6 Dec 2016 17:28:29 +0100 Subject: [PATCH 010/297] F #4913: Support multiple disks and use VCENTER_NAME --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index caccb9513f..11e9b40deb 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -827,7 +827,7 @@ class VIClient rc = ds.info raise "Could not find datastore #{ds_id}" if OpenNebula.is_error?(rc) - return ds.name + return ds["/DATASTORE/TEMPLATE/VCENTER_NAME"] end ############################################################################ @@ -2860,12 +2860,15 @@ private disk_array = [] hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) + + position = 0 disks.each{|disk| - ds_name = disk.elements["DATASTORE"].text + ds_name = disk.elements["VCENTER_NAME"].text img_name = get_disk_img_path(disk, vmid) type_str = disk.elements["TYPE"].text - disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection)[:deviceChange] + disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection, position)[:deviceChange] + position += 1 } device_change += disk_array @@ -2888,7 +2891,7 @@ private spec_hash.merge!({ :deviceChange => device_change }) end - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) vm.ReconfigVM_Task(:spec => spec).wait_for_completion end @@ -2902,8 +2905,9 @@ private # @params size_kb[String] size in kb of the disk # @params vm[RbVmomi::VIM::VirtualMachine] VM if called from instance # @params connection[ViClient::connectoon] connection if called from instance + # @params position The number of disks to attach. Starts with 0. ############################################################################ - def self.attach_disk(hostname, deploy_id, ds_name, img_name, type, size_kb, vm=nil, connection=nil) + def self.attach_disk(hostname, deploy_id, ds_name, img_name, type, size_kb, vm=nil, connection=nil, position=0) only_return = true if !vm hid = VIClient::translate_hostname(hostname) @@ -2928,7 +2932,7 @@ private ds = datastores.select{|ds| ds.name == ds_name}[0] - controller, new_number = find_free_controller(vm) + controller, new_number = find_free_controller(vm, position) if type == "CDROM" vmdk_backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo( @@ -2992,6 +2996,7 @@ private :key => -1, :unitNumber => new_number ) + device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( :device => device, :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') @@ -3007,7 +3012,7 @@ private vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion end - def self.find_free_controller(vm) + def self.find_free_controller(vm, position=0) free_scsi_controllers = Array.new available_controller = nil scsi_schema = Hash.new @@ -3052,7 +3057,7 @@ private (controller = device ; break) if device.deviceInfo.label == available_controller_label } - new_unit_number = available_numbers.sort[0] + new_unit_number = available_numbers.sort[position] return controller, new_unit_number end @@ -3175,7 +3180,7 @@ private disks.each{ |disk| img_name = get_disk_img_path(disk, vmid) - ds_and_img_name = "[#{disk['DATASTORE']}] #{img_name}" + ds_and_img_name = "[#{disk['VCENTER_NAME']}] #{img_name}" vcenter_disk = vm.config.hardware.device.select { |d| is_disk?(d) && d.backing.respond_to?(:fileName) && From aae5b614143256333d77c51a2ae9f2e8b4c5411b Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 6 Dec 2016 17:29:58 +0100 Subject: [PATCH 011/297] F #4913: Add support for vcenter tm/mkimage --- src/tm_mad/vcenter/mkimage | 53 ++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 88bf25fe38..e40ba8d4ab 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -35,30 +35,51 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) +require 'opennebula' require 'vcenter_driver' +client = OpenNebula::Client.new + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to create the volatile disk. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + size = ARGV[0] fstype = ARGV[1] -hostname, img_path = ARGV[2].split(":") +hostname, img_name = ARGV[2].split(":") vmid = ARGV[3] dsid = ARGV[4] -begin - disk_id = img_path.split(".")[1] - vm = OpenNebula::VirtualMachine.new_with_id(vmid, - OpenNebula::Client.new) - vm.info - adapter_type = vm["VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/ADAPTER_TYPE"] - disk_type = vm["VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/DISK_TYPE"] -rescue Exception => e - STDERR.puts "Error getting attributes from VM template #{vmid}."\ - " Reason: #{e.message}" - exit -1 +disk_id = img_name.split(".")[-1] +img_name = "one_#{vmid}_#{disk_id}" + +################################################################################ + +vm = OpenNebula::VirtualMachine.new_with_id(vmid, client) + +rc = vm.info +if OpenNebula.is_error?(rc) + puts rc.message + exit -1 end -if disk_type.nil? or disk_type.empty? - disk_type = "thin" -end +adapter_type = vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/ADAPTER_TYPE"] +check_valid adapter_type, "adapter_type" + +# TODO get the DISK_TYPE +# disk_type = vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/DISK_TYPE"] +# if disk_type.nil? || disk_type.empty? +# disk_type = "thin" +# end +disk_type = "thin" begin host_id = VCenterDriver::VIClient.translate_hostname(hostname) @@ -74,4 +95,4 @@ rescue Exception => e STDERR.puts "Error creating virtual disk in #{ds_name}."\ " Reason: #{e.message}" exit -1 -end \ No newline at end of file +end From 0dec723848f4611a76abbbd1e56447342c60cac3 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 7 Dec 2016 11:38:39 +0100 Subject: [PATCH 012/297] F #4913: tm/mkswap not supported --- src/tm_mad/vcenter/mkswap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tm_mad/vcenter/mkswap b/src/tm_mad/vcenter/mkswap index 300563f2ad..9c454e8cd4 120000 --- a/src/tm_mad/vcenter/mkswap +++ b/src/tm_mad/vcenter/mkswap @@ -1 +1 @@ -../common/dummy.sh \ No newline at end of file +../common/not_supported.sh \ No newline at end of file From 176a9fa5b1b6f8b76918b597c30f0cb106866023 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 9 Dec 2016 18:52:12 +0100 Subject: [PATCH 013/297] F #4913: Split vcenter_driver into multiple files --- .../lib/vcenter_driver/cached_datastore.rb | 16 + .../remotes/lib/vcenter_driver/cached_host.rb | 93 + .../remotes/lib/vcenter_driver/host.rb | 320 +++ .../lib/vcenter_driver/rbvmomi_datastore.rb | 58 + .../remotes/lib/vcenter_driver/vi_client.rb | 940 +++++++++ .../lib/vcenter_driver/virtual_machine.rb | 1751 +++++++++++++++++ src/vmm_mad/remotes/lib/vcenter_driver2.rb | 57 + 7 files changed, 3235 insertions(+) create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/host.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver2.rb diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb new file mode 100644 index 0000000000..cc69ea33f0 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb @@ -0,0 +1,16 @@ +module VCenterDriver +class VCenterCachedDatastore + + def initialize(rbVmomiDatastore) + @ds = rbVmomiDatastore + @attributes = Hash.new + end + + def name + if !@attributes['name'] + @attributes['name']=@ds.name + end + @attributes['name'] + end +end +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb new file mode 100644 index 0000000000..5ca095a30a --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb @@ -0,0 +1,93 @@ +module VCenterDriver + +################################################################################ +# Cached Classes to speed up import and monitoring +################################################################################ +class VCenterCachedHost + + def initialize(rbVmomiHost) + @host = rbVmomiHost + @attributes = Hash.new + end + + def name + if !@attributes['name'] + @attributes['name']=@host.parent.name + end + @attributes['name'] + end + + def cluster_name + if !@attributes['cluster_name'] + @attributes['cluster_name']=@host.parent.name + end + @attributes['cluster_name'] + end + + def ds_list + if !@attributes['ds_list'] + @attributes['ds_list']="" + + datacenter = @host.parent + while !datacenter.is_a? RbVmomi::VIM::Datacenter + datacenter = datacenter.parent + end + + datastores=VIClient.get_entities( + datacenter.datastoreFolder, + 'Datastore') + + storage_pods = VIClient.get_entities(datacenter.datastoreFolder, + 'StoragePod') + storage_pods.each { |sp| + datastores << sp # Add Storage Pod + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + datastores.each { |ds| + @attributes['ds_list'] += ds.name + "," + } + @attributes['ds_list']=@attributes['ds_list'][0..-2] + end + @attributes['ds_list'] + end + + def rp_list + if !@attributes['rp_list'] + @attributes['rp_list']="" + @host.parent.resourcePool.resourcePool.each{|rp| + @attributes['rp_list'] += get_child_rp_names(rp, "") + } + @attributes['rp_list']=@attributes['rp_list'][0..-2] + end + @attributes['rp_list'] + end + + def get_child_rp_names(rp, parent_prefix) + rp_str = "" + + current_rp = (parent_prefix.empty? ? "" : parent_prefix + "/") + current_rp += rp.name + + if rp.resourcePool.size != 0 + rp.resourcePool.each{|child_rp| + rp_str += get_child_rp_names(child_rp, current_rp) + } + end + + rp_str += current_rp + "," + + return rp_str + end + + def cpumhz + if !@attributes['cpumhz'] + @attributes['cpumhz']=@host.summary.hardware.cpuMhz.to_f + end + @attributes['cpumhz'] + end +end +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb new file mode 100644 index 0000000000..d55f6b1139 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -0,0 +1,320 @@ +module VCenterDriver + +################################################################################ +# This class is an OpenNebula hosts that abstracts a vCenter cluster. It +# includes the functionality needed to monitor the cluster and report the ESX +# hosts and VM status of the cluster. +################################################################################ +class VCenterHost < ::OpenNebula::Host + attr_reader :vc_client, :vc_root, :cluster, :host, :client + + ############################################################################ + # Initialize the VCenterHost by looking for the associated objects of the + # VIM hierarchy + # client [VIClient] to interact with the associated vCenter + ############################################################################ + def initialize(client) + @client = client + @cluster = client.cluster + + @resource_pools = client.resource_pool + end + + ######################################################################## + # Creates an OpenNebula host representing a cluster in this VCenter + # @param cluster_name[String] the name of the cluster in the vcenter + # @param client [VIClient] to create the host + # @return In case of success [0, host_id] or [-1, error_msg] + ######################################################################## + def self.to_one(cluster_name, client) + one_host = ::OpenNebula::Host.new(::OpenNebula::Host.build_xml, + client.one) + + rc = one_host.allocate(cluster_name, 'vcenter', 'vcenter', + ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) + + return -1, rc.message if ::OpenNebula.is_error?(rc) + + template = "VCENTER_HOST=\"#{client.host}\"\n"\ + "VCENTER_PASSWORD=\"#{client.pass}\"\n"\ + "VCENTER_USER=\"#{client.user}\"\n" + + rc = one_host.update(template, false) + + if ::OpenNebula.is_error?(rc) + error = rc.message + + rc = one_host.delete + + if ::OpenNebula.is_error?(rc) + error << ". Host #{cluster_name} could not be"\ + " deleted: #{rc.message}." + end + + return -1, error + end + + return 0, one_host.id + end + + ############################################################################ + # Generate an OpenNebula monitor string for this host. Reference: + # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/Reference + # Guide/vim.ComputeResource.Summary.html + # - effectiveCpu: Effective CPU resources (in MHz) available to run + # VMs. This is the aggregated from all running hosts excluding hosts in + # maintenance mode or unresponsive are not counted. + # - effectiveMemory: Effective memory resources (in MB) available to run + # VMs. Equivalente to effectiveCpu. + # - numCpuCores: Number of physical CPU cores. + # - numEffectiveHosts: Total number of effective hosts. + # - numHosts:Total number of hosts. + # - totalCpu: Aggregated CPU resources of all hosts, in MHz. + # - totalMemory: Aggregated memory resources of all hosts, in bytes. + ############################################################################ + def monitor_cluster + #Load the host systems + summary = @cluster.summary + + mhz_core = summary.totalCpu.to_f / summary.numCpuCores.to_f + eff_core = summary.effectiveCpu.to_f / mhz_core + + free_cpu = sprintf('%.2f', eff_core * 100).to_f + total_cpu = summary.numCpuCores.to_f * 100 + used_cpu = sprintf('%.2f', total_cpu - free_cpu).to_f + + total_mem = summary.totalMemory.to_i / 1024 + free_mem = summary.effectiveMemory.to_i * 1024 + + str_info = "" + + # System + str_info << "HYPERVISOR=vcenter\n" + str_info << "TOTALHOST=" << summary.numHosts.to_s << "\n" + str_info << "AVAILHOST=" << summary.numEffectiveHosts.to_s << "\n" + + # CPU + str_info << "CPUSPEED=" << mhz_core.to_s << "\n" + str_info << "TOTALCPU=" << total_cpu.to_s << "\n" + str_info << "USEDCPU=" << used_cpu.to_s << "\n" + str_info << "FREECPU=" << free_cpu.to_s << "\n" + + # Memory + str_info << "TOTALMEMORY=" << total_mem.to_s << "\n" + str_info << "FREEMEMORY=" << free_mem.to_s << "\n" + str_info << "USEDMEMORY=" << (total_mem - free_mem).to_s + + str_info << monitor_resource_pools(@cluster.resourcePool, "", mhz_core) + end + + ############################################################################ + # Generate an OpenNebula monitor string for all resource pools of a cluster + # Reference: + # http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc + # /vim.ResourcePool.html + ############################################################################ + def monitor_resource_pools(parent_rp, parent_prefix, mhz_core) + return "" if parent_rp.resourcePool.size == 0 + + rp_info = "" + + parent_rp.resourcePool.each{|rp| + rpcpu = rp.config.cpuAllocation + rpmem = rp.config.memoryAllocation + # CPU + cpu_expandable = rpcpu.expandableReservation ? "YES" : "NO" + cpu_limit = rpcpu.limit == "-1" ? "UNLIMITED" : rpcpu.limit + cpu_reservation = rpcpu.reservation + cpu_num = rpcpu.reservation.to_f / mhz_core + cpu_shares_level = rpcpu.shares.level + cpu_shares = rpcpu.shares.shares + + # MEMORY + mem_expandable = rpmem.expandableReservation ? "YES" : "NO" + mem_limit = rpmem.limit == "-1" ? "UNLIMITED" : rpmem.limit + mem_reservation = rpmem.reservation.to_f + mem_shares_level = rpmem.shares.level + mem_shares = rpmem.shares.shares + + rp_name = (parent_prefix.empty? ? "" : parent_prefix + "/") + rp_name += rp.name + + rp_info << "\nRESOURCE_POOL = [" + rp_info << "NAME=\"#{rp_name}\"," + rp_info << "CPU_EXPANDABLE=#{cpu_expandable}," + rp_info << "CPU_LIMIT=#{cpu_limit}," + rp_info << "CPU_RESERVATION=#{cpu_reservation}," + rp_info << "CPU_RESERVATION_NUM_CORES=#{cpu_num}," + rp_info << "CPU_SHARES=#{cpu_shares}," + rp_info << "CPU_SHARES_LEVEL=#{cpu_shares_level}," + rp_info << "MEM_EXPANDABLE=#{mem_expandable}," + rp_info << "MEM_LIMIT=#{mem_limit}," + rp_info << "MEM_RESERVATION=#{mem_reservation}," + rp_info << "MEM_SHARES=#{mem_shares}," + rp_info << "MEM_SHARES_LEVEL=#{mem_shares_level}" + rp_info << "]" + + if rp.resourcePool.size != 0 + rp_info << monitor_resource_pools(rp, rp_name, mhz_core) + end + } + + return rp_info + end + + ############################################################################ + # Generate a template with information for each ESX Host. Reference: + # http://pubs.vmware.com/vi-sdk/visdk250/ReferenceGuide/vim.HostSystem.html + # - Summary: Basic information about the host, including connection state + # - hardware: Hardware configuration of the host. This might not be + # available for a disconnected host. + # - quickStats: Basic host statistics. + ############################################################################ + def monitor_host_systems + host_info = "" + + @cluster.host.each{|h| + next if h.runtime.connectionState != "connected" + + summary = h.summary + hw = summary.hardware + stats = summary.quickStats + + total_cpu = hw.numCpuCores * 100 + used_cpu = (stats.overallCpuUsage.to_f / hw.cpuMhz.to_f) * 100 + used_cpu = sprintf('%.2f', used_cpu).to_f # Trim precission + free_cpu = total_cpu - used_cpu + + total_memory = hw.memorySize/1024 + used_memory = stats.overallMemoryUsage*1024 + free_memory = total_memory - used_memory + + host_info << "\nHOST=[" + host_info << "STATE=on," + host_info << "HOSTNAME=\"" << h.name.to_s << "\"," + host_info << "MODELNAME=\"" << hw.cpuModel.to_s << "\"," + host_info << "CPUSPEED=" << hw.cpuMhz.to_s << "," + host_info << "MAX_CPU=" << total_cpu.to_s << "," + host_info << "USED_CPU=" << used_cpu.to_s << "," + host_info << "FREE_CPU=" << free_cpu.to_s << "," + host_info << "MAX_MEM=" << total_memory.to_s << "," + host_info << "USED_MEM=" << used_memory.to_s << "," + host_info << "FREE_MEM=" << free_memory.to_s + host_info << "]" + } + + return host_info + end + + def monitor_vms + # Only monitor from top level (Resource) Resource Pool + monitor_vms_in_rp(@resource_pools[-1]) + end + + + def monitor_vms_in_rp(rp) + str_info = "" + + if rp.resourcePool.size != 0 + rp.resourcePool.each{|child_rp| + str_info += monitor_vms_in_rp(child_rp) + } + end + + host_cache = {} + + rp.vm.each { |v| + begin + # Check cached objects + if !host_cache[v.runtime.host.to_s] + host_cache[v.runtime.host.to_s] = + VCenterCachedHost.new v.runtime.host + end + + host = host_cache[v.runtime.host.to_s] + + name = v.name + number = -1 + vm_extra_config = v.config.extraConfig + + # Check the running flag + running_flag = v.config.extraConfig.select{|val| + val[:key]=="opennebula.vm.running"} + if running_flag.size > 0 and running_flag[0] + running_flag = running_flag[0][:value] + end + + next if running_flag == "no" + + # Extract vmid if possible + matches = name.match(/^one-(\d*)(-(.*))?$/) + number = matches[1] if matches + extraconfig_vmid = v.config.extraConfig.select{|val| + val[:key]=="opennebula.vm.id"} + if extraconfig_vmid.size > 0 and extraconfig_vmid[0] + number = extraconfig_vmid[0][:value] + end + vm = VCenterVm.new(@client, v) + vm.monitor(host) + next if !vm.vm.config + str_info << "\nVM = [" + str_info << "ID=#{number}," + str_info << "DEPLOY_ID=\"#{vm.vm.config.uuid}\"," + str_info << "VM_NAME=\"#{name} - "\ + "#{host.cluster_name}\"," + if number == -1 + vm_template_to_one = + Base64.encode64(vm.vm_to_one(host)).gsub("\n","") + str_info << "IMPORT_TEMPLATE=\"#{vm_template_to_one}\"," + end + str_info << "POLL=\"#{vm.info}\"]" + rescue Exception => e + STDERR.puts e.inspect + STDERR.puts e.backtrace + end + } + return str_info + end + + def monitor_customizations + customizations = client.vim.serviceContent.customizationSpecManager.info + + text = '' + + customizations.each do |c| + t = "CUSTOMIZATION = [ " + t << %Q + t << %Q + + text << t + end + + text + end + + def get_available_ds + str_info = "" + + datastores = VIClient.get_entities(client.dc.datastoreFolder, + 'Datastore') + + storage_pods = VIClient.get_entities(client.dc.datastoreFolder, + 'StoragePod') + + storage_pods.each { |sp| + datastores << sp + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + datastores.each { |ds| + str_info += "VCENTER_DATASTORE=\"#{ds.name}\"\n" + } + str_info.chomp + end +end + + +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb new file mode 100644 index 0000000000..be1324dc44 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb @@ -0,0 +1,58 @@ + +class RbVmomi::VIM::Datastore + + # Download a file from this datastore. + # @param remote_path [String] Source path on the datastore. + # @param local_path [String] Destination path on the local machine. + # @return [void] + def download_to_stdout remote_path + url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" + + pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', + "-b", _connection.cookie, + url + + + Process.waitpid(pid, 0) + fail "download failed" unless $?.success? + end + + def is_descriptor? remote_path + url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" + + rout, wout = IO.pipe + + pid = spawn CURLBIN, "-I", "-k", '--noproxy', '*', '-f', + "-b", _connection.cookie, + url, + :out => wout, + :err => '/dev/null' + + Process.waitpid(pid, 0) + fail "read image header failed" unless $?.success? + + wout.close + size = rout.readlines.select{|l| l.start_with?("Content-Length")}[0].sub("Content-Length: ","") + rout.close + size.chomp.to_i < 4096 # If <4k, then is a descriptor + end + + def get_text_file remote_path + url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" + + rout, wout = IO.pipe + pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', + "-b", _connection.cookie, + url, + :out => wout, + :err => '/dev/null' + + Process.waitpid(pid, 0) + fail "get text file failed" unless $?.success? + + wout.close + output = rout.readlines + rout.close + return output + end +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb new file mode 100644 index 0000000000..745119b460 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -0,0 +1,940 @@ +module VCenterDriver + ################################################################################ + # This class represents a VCenter connection and an associated OpenNebula client + # The connection is associated to the VCenter backing a given OpenNebula host. + # For the VCenter driver each OpenNebula host represents a VCenter cluster + ################################################################################ + class VIClient + attr_reader :vim, :one, :root, :cluster, :user, :pass, :host, :dc + + def self.get_entities(folder, type, entities=[]) + return nil if folder == [] + + folder.childEntity.each do |child| + name, junk = child.to_s.split('(') + + case name + when "Folder" + VIClient.get_entities(child, type, entities) + when type + entities.push(child) + end + end + + return entities + end + + # Only retrieve properties with faster search + def get_entities_to_import(folder, type) + res = folder.inventory_flat(type => :all) + objects = [] + + res.each {|k,v| + if k.to_s.split('(').first == type + obj = {} + v.propSet.each{ |dynprop| + obj[dynprop.name] = dynprop.val + } + obj[:ref] = k._ref + objects << OpenStruct.new(obj) + end + } + return objects + end + + ############################################################################ + # Initialize the VIClient, and creates an OpenNebula client. The parameters + # are obtained from the associated OpenNebula host + # @param hid [Integer] The OpenNebula host id with VCenter attributes + ############################################################################ + def initialize(hid) + + initialize_one + + @one_host = ::OpenNebula::Host.new_with_id(hid, @one) + rc = @one_host.info + + if ::OpenNebula.is_error?(rc) + raise "Error getting host information: #{rc.message}" + end + + password = @one_host["TEMPLATE/VCENTER_PASSWORD"] + + if !@token.nil? + begin + cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") + + cipher.decrypt + cipher.key = @token + + password = cipher.update(Base64::decode64(password)) + password << cipher.final + rescue + raise "Error decrypting vCenter password" + end + end + + connection = { + :host => @one_host["TEMPLATE/VCENTER_HOST"], + :user => @one_host["TEMPLATE/VCENTER_USER"], + :password => password + } + + initialize_vim(connection) + + datacenters = VIClient.get_entities(@root, 'Datacenter') + + datacenters.each {|dc| + ccrs = VIClient.get_entities(dc.hostFolder, 'ClusterComputeResource') + + next if ccrs.nil? + + @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } + + (@dc = dc; break) if @cluster + } + + if @dc.nil? || @cluster.nil? + raise "Cannot find DataCenter or ClusterComputeResource for host." + end + end + + ######################################################################## + # Initialize a VIConnection based just on the VIM parameters. The + # OpenNebula client is also initialized + ######################################################################## + def self.new_connection(user_opts, one_client=nil) + + conn = allocate + + conn.initialize_one(one_client) + + conn.initialize_vim(user_opts) + + return conn + end + + ######################################################################## + # The associated cluster for this connection + ######################################################################## + def cluster + @cluster + end + + ######################################################################## + # Is this Cluster confined in a resource pool? + ######################################################################## + def rp_confined? + !@one_host["TEMPLATE/VCENTER_RESOURCE_POOL"].nil? + end + + ######################################################################## + # The associated resource pool for this connection + # @return [ResourcePool] an array of resource pools including the default + #  resource pool. If the connection is confined to a particular + #  resource pool, then return just that one + ######################################################################## + def resource_pool + rp_name = @one_host["TEMPLATE/VCENTER_RESOURCE_POOL"] + + if rp_name.nil? + rp_array = @cluster.resourcePool.resourcePool + rp_array << @cluster.resourcePool + rp_array + else + [find_resource_pool(rp_name)] + end + end + + ######################################################################## + # Get the default resource pool of the connection. Only valid if + # the connection is not confined in a resource pool + # @return ResourcePool the default resource pool + ######################################################################## + def default_resource_pool + @cluster.resourcePool + end + + ######################################################################## + # Searches the desired ResourcePool of the DataCenter for the current + # connection. Returns a RbVmomi::VIM::ResourcePool or the default pool + # if not found + # @param rpool [String] the ResourcePool name + ######################################################################## + def find_resource_pool(poolName) + baseEntity = @cluster + + entityArray = poolName.split('/') + entityArray.each do |entityArrItem| + if entityArrItem != '' + if baseEntity.is_a? RbVmomi::VIM::Folder + baseEntity = baseEntity.childEntity.find { |f| + f.name == entityArrItem + } or return @cluster.resourcePool + elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource + baseEntity = baseEntity.resourcePool.resourcePool.find { |f| + f.name == entityArrItem + } or return @cluster.resourcePool + elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool + baseEntity = baseEntity.resourcePool.find { |f| + f.name == entityArrItem + } or return @cluster.resourcePool + else + return @cluster.resourcePool + end + end + end + + if !baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and + baseEntity.respond_to?(:resourcePool) + baseEntity = baseEntity.resourcePool + end + + baseEntity + end + + ######################################################################## + # Searches the associated vmFolder of the DataCenter for the current + # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found + # + # Searches by moref, name, uuid and then iterates over all VMs + # + # @param uuid [String] the UUID of the VM or VM Template + # @param ref [String] VMware moref + # @param name [String] VM name in vCenter + ######################################################################## + def find_vm_fast(uuid, ref = nil, name = nil) + if ref + # It can raise ManagedObjectNotFound + begin + vm = RbVmomi::VIM::VirtualMachine.new(@dc._connection, ref) + return vm if vm.config && vm.config.uuid == uuid + rescue => e + end + end + + if name + begin + vm = @dc.vmFolder.find(name) + return vm if vm.config && vm.config.uuid == uuid + rescue + end + end + + return find_vm_template(uuid) + end + + ######################################################################## + # Searches the associated vmFolder of the DataCenter for the current + # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found + # @param uuid [String] the UUID of the VM or VM Template + ######################################################################## + def find_vm_template(uuid) + version = @vim.serviceContent.about.version + + found_vm = nil + found_vm = @dc.vmFolder.findByUuid(uuid, RbVmomi::VIM::VirtualMachine, @dc) + return found_vm if found_vm + + vms = VIClient.get_entities(@dc.vmFolder, 'VirtualMachine') + + return vms.find do |v| + begin + v.config && v.config.uuid == uuid + rescue RbVmomi::VIM::ManagedObjectNotFound + false + end + end + end + + ######################################################################## + # Searches the associated vmFolder of the DataCenter for the current + # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found + # @param vm_name [String] the UUID of the VM or VM Template + ######################################################################## + def find_vm(vm_name) + vms = VIClient.get_entities(@dc.vmFolder, 'VirtualMachine') + + return vms.find do |v| + begin + v.name == vm_name + rescue RbVmomi::VIM::ManagedObjectNotFound + false + end + end + end + + ######################################################################## + # Searches the associated datacenter for a particular datastore + # @param ds_name [String] name of the datastore + # @returns a RbVmomi::VIM::VirtualMachine or nil if not found + ######################################################################## + def get_datastore(ds_name) + datastores = VIClient.get_entities(@dc.datastoreFolder, 'Datastore') + + storage_pods = VIClient.get_entities(@dc.datastoreFolder, 'StoragePod') + storage_pods.each { |sp| + datastores << sp #Add StoragePod + + # Add individual datastores under StoragePod + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + ds = datastores.select{|ds| ds.name == ds_name}[0] + end + + ######################################################################## + # Builds a hash with the DataCenter / ClusterComputeResource hierarchy + # for this VCenter. + # @return [Hash] in the form + # {dc_name [String] => ClusterComputeResources Names [Array - String]} + ######################################################################## + def hierarchy(one_client=nil) + vc_hosts = {} + + datacenters = VIClient.get_entities(@root, 'Datacenter') + + hpool = OpenNebula::HostPool.new((one_client||@one)) + rc = hpool.info + + datacenters.each { |dc| + ccrs = VIClient.get_entities(dc.hostFolder, 'ClusterComputeResource') + vc_hosts[dc.name] = [] + ccrs.each { |c| + if !hpool["HOST[NAME=\"#{c.name}\"]"] + vc_hosts[dc.name] << c.name + end + } + } + + return vc_hosts + end + + ######################################################################## + # Builds a hash with the Datacenter / VM Templates for this VCenter + # @param one_client [OpenNebula::Client] Use this client instead of @one + # @return [Hash] in the form + # { dc_name [String] => Templates [Array] } + ######################################################################## + def vm_templates(one_client=nil) + vm_templates = {} + + tpool = OpenNebula::TemplatePool.new( + (one_client||@one), OpenNebula::Pool::INFO_ALL) + rc = tpool.info + if OpenNebula.is_error?(rc) + raise "Error contacting OpenNebula #{rc.message}" + end + + datacenters = VIClient.get_entities(@root, 'Datacenter') + + datacenters.each { |dc| + vms = get_entities_to_import(dc.vmFolder, 'VirtualMachine') + + tmp = vms.select { |v| v.config && (v.config.template == true) } + + one_tmp = [] + host_cache = {} + ds_cache = {} + + tmp.each { |t| + vi_tmp = VCenterVm.new(self, t) + + if !tpool["VMTEMPLATE/TEMPLATE/PUBLIC_CLOUD[\ + TYPE=\"vcenter\" \ + and VM_TEMPLATE=\"#{vi_tmp.vm.config.uuid}\"]"] + # Check cached objects + if !host_cache[vi_tmp.vm.runtime.host.to_s] + host_cache[vi_tmp.vm.runtime.host.to_s] = + VCenterCachedHost.new vi_tmp.vm.runtime.host + end + + if !ds_cache[t.datastore[0].to_s] + ds_cache[t.datastore[0].to_s] = + VCenterCachedDatastore.new t.datastore[0] + end + + host = host_cache[vi_tmp.vm.runtime.host.to_s] + ds = ds_cache[t.datastore[0].to_s] + + one_tmp << { + :name => "#{vi_tmp.vm.name} - #{host.cluster_name}", + :uuid => vi_tmp.vm.config.uuid, + :host => host.cluster_name, + :one => vi_tmp.to_one(host), + :ds => vi_tmp.to_one_ds(host, ds.name), + :default_ds => ds.name, + :rp => vi_tmp.to_one_rp(host), + :vcenter_ref => vi_tmp.vm._ref, + :vcenter_name => vi_tmp.vm.name + } + end + } + + vm_templates[dc.name] = one_tmp + } + + return vm_templates + end + + ######################################################################## + # Builds a hash with the Datacenter / CCR (Distributed)Networks + # for this VCenter + # @param one_client [OpenNebula::Client] Use this client instead of @one + # @return [Hash] in the form + # { dc_name [String] => Networks [Array] } + ######################################################################## + def vcenter_networks(one_client=nil) + vcenter_networks = {} + + vnpool = OpenNebula::VirtualNetworkPool.new( + (one_client||@one), OpenNebula::Pool::INFO_ALL) + rc = vnpool.info + if OpenNebula.is_error?(rc) + raise "Error contacting OpenNebula #{rc.message}" + end + + datacenters = VIClient.get_entities(@root, 'Datacenter') + + datacenters.each { |dc| + networks = VIClient.get_entities(dc.networkFolder, 'Network' ) + one_nets = [] + + networks.each { |n| + # Skip those not in cluster + next if !n[:host][0] + + # Networks can be in several cluster, create one per cluster + net_names = [] + Array(n[:host]).each{ |host_system| + net_name = "#{n.name} - #{host_system.parent.name}" + if !net_names.include?(net_name) + if !vnpool["VNET[BRIDGE=\"#{n[:name]}\"]/\ + TEMPLATE[VCENTER_TYPE=\"Port Group\"]"] + one_nets << { + :name => net_name, + :bridge => n.name, + :cluster => host_system.parent.name, + :type => "Port Group", + :one => "NAME = \"#{net_name}\"\n" \ + "BRIDGE = \"#{n[:name]}\"\n" \ + "VN_MAD = \"dummy\"\n" \ + "VCENTER_TYPE = \"Port Group\"" + } + net_names << net_name + end + end + } + } + + networks = VIClient.get_entities(dc.networkFolder, + 'DistributedVirtualPortgroup' ) + + networks.each { |n| + # Skip those not in cluster + next if !n[:host][0] + + # DistributedVirtualPortgroup can be in several cluster, + # create one per cluster + Array(n[:host][0]).each{ |host_system| + net_name = "#{n.name} - #{n[:host][0].parent.name}" + + if !vnpool["VNET[BRIDGE=\"#{n[:name]}\"]/\ + TEMPLATE[VCENTER_TYPE=\"Distributed Port Group\"]"] + vnet_template = "NAME = \"#{net_name}\"\n" \ + "BRIDGE = \"#{n[:name]}\"\n" \ + "VN_MAD = \"dummy\"\n" \ + "VCENTER_TYPE = \"Distributed Port Group\"" + + default_pc = n.config.defaultPortConfig + + has_vlan = false + vlan_str = "" + + if default_pc.methods.include? :vlan + has_vlan = default_pc.vlan.methods.include? :vlanId + end + + if has_vlan + vlan = n.config.defaultPortConfig.vlan.vlanId + + if vlan != 0 + if vlan.is_a? Array + vlan.each{|v| + vlan_str += v.start.to_s + ".." + + v.end.to_s + "," + } + vlan_str.chop! + else + vlan_str = vlan.to_s + end + end + end + + if !vlan_str.empty? + vnet_template << "VLAN_TAGGED_ID=#{vlan_str}\n" + end + + one_net = {:name => net_name, + :bridge => n.name, + :cluster => host_system.parent.name, + :type => "Distributed Port Group", + :one => vnet_template} + + one_net[:vlan] = vlan_str if !vlan_str.empty? + + one_nets << one_net + end + } + } + + vcenter_networks[dc.name] = one_nets + } + + return vcenter_networks + end + + + ######################################################################## + # Builds a hash with the Datacenter / Datastores for this VCenter + # @param one_client [OpenNebula::Client] Use this client instead of @one + # @return [Hash] in the form + # { dc_name [String] => Datastore [Array] of DS templates} + ######################################################################## + def vcenter_datastores(one_client=nil) + ds_templates = {} + + dspool = OpenNebula::DatastorePool.new( + (one_client||@one)) + rc = dspool.info + if OpenNebula.is_error?(rc) + raise "Error contacting OpenNebula #{rc.message}" + end + + hpool = OpenNebula::HostPool.new( + (one_client||@one)) + rc = hpool.info + if OpenNebula.is_error?(rc) + raise "Error contacting OpenNebula #{rc.message}" + end + + datacenters = VIClient.get_entities(@root, 'Datacenter') + + datacenters.each { |dc| + one_tmp = [] + datastores = VIClient.get_entities(dc.datastoreFolder, 'Datastore') + + storage_pods = VIClient.get_entities(dc.datastoreFolder, 'StoragePod') + storage_pods.each { |sp| + datastores << sp # Add StoragePod + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + datastores.each { |ds| + next if !ds.is_a? RbVmomi::VIM::Datastore and !ds.is_a? RbVmomi::VIM::StoragePod + # Find the Cluster from which to access this ds + + cluster_name = "" + if ds.is_a? RbVmomi::VIM::StoragePod + storage_pod_datastores = VIClient.get_entities(ds, 'Datastore') + storage_pod_datastores.each { |sp| + next if !sp.is_a? RbVmomi::VIM::Datastore + # Find the Cluster from which to access this ds + next if !sp.host[0] + cluster_name = sp.host[0].key.parent.name + break + } + else + next if !ds.host[0] + cluster_name = ds.host[0].key.parent.name + end + + if !dspool["DATASTORE[NAME=\"#{ds.name}\"]"] and + hpool["HOST[NAME=\"#{cluster_name}\"]"] + if ds.is_a? RbVmomi::VIM::StoragePod + one_tmp << { + :name => "#{ds.name}", + :total_mb => ((ds.summary.capacity.to_i / 1024) / 1024), + :free_mb => ((ds.summary.freeSpace.to_i / 1024) / 1024), + :cluster => cluster_name, + :one => "NAME=#{ds.name}\n"\ + "TM_MAD=vcenter\n"\ + "VCENTER_CLUSTER=#{cluster_name}\n"\ + "TYPE=SYSTEM_DS\n" # StoragePods must be set as SYSTEM_DS + } + else + one_tmp << { + :name => "#{ds.name}", + :total_mb => ((ds.summary.capacity.to_i / 1024) / 1024), + :free_mb => ((ds.summary.freeSpace.to_i / 1024) / 1024), + :cluster => cluster_name, + :one => "NAME=#{ds.name}\n"\ + "DS_MAD=vcenter\n"\ + "TM_MAD=vcenter\n"\ + "VCENTER_CLUSTER=#{cluster_name}\n" + } + end + end + } + ds_templates[dc.name] = one_tmp + } + + return ds_templates + end + + ############################################################################# + # Builds a hash with the Images for a particular datastore + # @param one_client [OpenNebula::Client] Use this client instead of @one + # @return [Array] of image templates + ############################################################################ + def vcenter_images(ds_name, one_client=nil) + img_types = ["FloppyImageFileInfo", + "IsoImageFileInfo", + "VmDiskFileInfo"] + + img_templates = [] + + ipool = OpenNebula::ImagePool.new((one_client||@one)) + rc = ipool.info + if OpenNebula.is_error?(rc) + raise "Error contacting OpenNebula #{rc.message}" + end + + dspool = OpenNebula::DatastorePool.new((one_client||@one)) + rc = dspool.info + if OpenNebula.is_error?(rc) + raise "Error contacting OpenNebula #{rc.message}" + end + + ds_id = dspool["DATASTORE[NAME=\"#{ds_name}\"]/ID"] + + if !ds_id + raise "Datastore not found in OpenNebula. Please import"\ + " it first and try again" + end + + datacenters = VIClient.get_entities(@root, 'Datacenter') + + datacenters.each { |dc| + + # Find datastore within datacenter + datastores = VIClient.get_entities(dc.datastoreFolder, 'Datastore') + + storage_pods = VIClient.get_entities(dc.datastoreFolder, 'StoragePod') + storage_pods.each { |sp| + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + ds = datastores.select{|ds| ds.name == ds_name}[0] + next if !ds + + # Cannot import from StoragePod directly + if ds.is_a? RbVmomi::VIM::StoragePod + raise "OpenNebula cannot import images from a StoragePod. Please import"\ + " it from the datastore which is a member of the StorageDRS cluster" + end + + # Create Search Spec + spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new + spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, + RbVmomi::VIM::IsoImageFileQuery.new] + spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, + :fileSize => true, + :fileType => true, + :modification => true) + spec.matchPattern=[] + + search_params = {'datastorePath' => "[#{ds.name}]", + 'searchSpec' => spec} + + # Perform search task and return results + search_task=ds.browser.SearchDatastoreSubFolders_Task(search_params) + search_task.wait_for_completion + + search_task.info.result.each { |image| + folderpath = "" + if image.folderPath[-1] != "]" + folderpath = image.folderPath.sub(/^\[#{ds_name}\] /, "") + end + + image = image.file[0] + + # Skip not relevant files + next if !img_types.include? image.class.to_s + + image_path = folderpath + image.path + + image_name = File.basename(image.path).reverse.sub("kdmv.","").reverse + + if !ipool["IMAGE[NAME=\"#{image_name} - #{ds_name}\"]"] + img_templates << { + :name => "#{image_name} - #{ds_name}", + :path => image_path, + :size => (image.fileSize / 1024).to_s, + :type => image.class.to_s, + :dsid => ds_id, + :one => "NAME=\"#{image_name} - #{ds_name}\"\n"\ + "PATH=\"vcenter://#{image_path}\"\n"\ + "PERSISTENT=\"YES\"\n"\ + } + + if image.class.to_s == "VmDiskFileInfo" + img_templates[-1][:one] += "TYPE=\"OS\"\n" + else + img_templates[-1][:one] += "TYPE=\"CDROM\"\n" + end + + if image.class.to_s == "VmDiskFileInfo" && + !image.diskType.nil? + img_templates[-1][:one] += "DISK_TYPE=#{image.diskType}\n" + end + end + } + } + + return img_templates + end + + def self.translate_hostname(hostname) + host_pool = OpenNebula::HostPool.new(::OpenNebula::Client.new()) + rc = host_pool.info + raise "Could not find host #{hostname}" if OpenNebula.is_error?(rc) + + host = host_pool.select {|host_element| host_element.name==hostname } + return host.first.id + end + + def self.find_ds_name(ds_id) + ds = OpenNebula::Datastore.new_with_id(ds_id, OpenNebula::Client.new) + rc = ds.info + raise "Could not find datastore #{ds_id}" if OpenNebula.is_error?(rc) + + return ds["/DATASTORE/TEMPLATE/VCENTER_NAME"] + end + + ############################################################################ + # Initialize an OpenNebula connection with the default ONE_AUTH + ############################################################################ + def initialize_one(one_client=nil) + begin + if one_client + @one = one_client + else + @one = ::OpenNebula::Client.new() + end + + system = ::OpenNebula::System.new(@one) + + config = system.get_configuration() + + if ::OpenNebula.is_error?(config) + raise "Error getting oned configuration : #{config.message}" + end + + @token = config["ONE_KEY"] + rescue Exception => e + raise "Error initializing OpenNebula client: #{e.message}" + end + end + + ############################################################################ + # Initialize a connection with vCenter. Options + # @param options[Hash] with: + # :user => The vcenter user + # :password => Password for the user + # :host => vCenter hostname or IP + # :insecure => SSL (optional, defaults to true) + ############################################################################ + def initialize_vim(user_opts={}) + opts = { + :insecure => true + }.merge(user_opts) + + @user = opts[:user] + @pass = opts[:password] + @host = opts[:host] + + begin + @vim = RbVmomi::VIM.connect(opts) + @root = @vim.root + @vdm = @vim.serviceContent.virtualDiskManager + @file_manager = @vim.serviceContent.fileManager + rescue Exception => e + raise "Error connecting to #{@host}: #{e.message}" + end + end + + ######################### Datastore Operations ############################# + + ############################################################################ + # Retrieve size for a VirtualDisk in a particular datastore + # @param ds_name [String] name of the datastore + # @param img_str [String] path to the VirtualDisk + # @return size of the file in Kb + ############################################################################ + def stat(ds_name, img_str) + img_path = File.dirname img_str + img_name = File.basename img_str + + # Find datastore within datacenter + ds = get_datastore(ds_name) + + # Create Search Spec + spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new + spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, + RbVmomi::VIM::IsoImageFileQuery.new] + spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, + :fileSize => true, + :fileType => true, + :modification => true) + spec.matchPattern=[img_name] + + search_params = {'datastorePath' => "[#{ds_name}] #{img_path}", + 'searchSpec' => spec} + + # Perform search task and return results + search_task=ds.browser.SearchDatastoreSubFolders_Task(search_params) + search_task.wait_for_completion + (search_task.info.result[0].file[0].fileSize / 1024) / 1024 + end + + ############################################################################ + # Returns Datastore information + # @param ds_name [String] name of the datastore + # @return [String] monitor information of the DS + ############################################################################ + def monitor_ds(ds_name) + # Find datastore within datacenter + ds = get_datastore(ds_name) + + total_mb = (ds.summary.capacity.to_i / 1024) / 1024 + free_mb = (ds.summary.freeSpace.to_i / 1024) / 1024 + used_mb = total_mb - free_mb + + if ds.is_a? RbVmomi::VIM::Datastore + ds_type = ds.summary.type + end + + "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" + end + + ############################################################################ + # Copy a VirtualDisk + # @param ds_name [String] name of the datastore + # @param img_str [String] path to the VirtualDisk + ############################################################################ + def copy_virtual_disk(source_path, source_ds, target_path, target_ds=nil) + target_ds = source_ds if target_ds.nil? + + copy_params= {:sourceName => "[#{source_ds}] #{source_path}", + :sourceDatacenter => @dc, + :destName => "[#{target_ds}] #{target_path}"} + + @vdm.CopyVirtualDisk_Task(copy_params).wait_for_completion + + target_path + end + + ############################################################################ + # Create a VirtualDisk + # @param img_name [String] name of the image + # @param ds_name [String] name of the datastore on which the VD will be + # created + # @param size [String] size of the new image in MB + # @param adapter_type [String] as described in + #  http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc/vim.VirtualDiskManager.VirtualDiskAdapterType.html + # @param disk_type [String] as described in + #  http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.VirtualDiskManager.VirtualDiskType.html + # @return name of the final image + ############################################################################ + def create_virtual_disk(img_name, ds_name, size, adapter_type, disk_type) + vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( + :adapterType => adapter_type, + :capacityKb => size.to_i*1024, + :diskType => disk_type + ) + + @vdm.CreateVirtualDisk_Task( + :datacenter => @dc, + :name => "[#{ds_name}] #{img_name}.vmdk", + :spec => vmdk_spec + ).wait_for_completion + + "#{img_name}.vmdk" + end + + ############################################################################ + # Delete a VirtualDisk + # @param img_name [String] name of the image + # @param ds_name [String] name of the datastore where the VD resides + ############################################################################ + def delete_virtual_disk(img_name, ds_name) + @vdm.DeleteVirtualDisk_Task( + name: "[#{ds_name}] #{img_name}", + datacenter: @dc + ).wait_for_completion + end + + ############################################################################ + # Delete a VirtualDisk + # @param directory [String] name of the new directory + # @param ds_name [String] name of the datastore where to create the dir + ############################################################################ + def create_directory(directory, ds_name) + begin + path = "[#{ds_name}] #{directory}" + @file_manager.MakeDirectory(:name => path, + :datacenter => @dc, + :createParentDirectories => true) + rescue RbVmomi::VIM::FileAlreadyExists => e + end + end + + ############################################################################ + # Silences standard output and error + ############################################################################ + def self.in_silence + begin + orig_stderr = $stderr.clone + orig_stdout = $stdout.clone + $stderr.reopen File.new('/dev/null', 'w') + $stdout.reopen File.new('/dev/null', 'w') + retval = yield + rescue Exception => e + $stdout.reopen orig_stdout + $stderr.reopen orig_stderr + raise e + ensure + $stdout.reopen orig_stdout + $stderr.reopen orig_stderr + end + retval + end + + ############################################################################ + # Silences standard output and error + ############################################################################ + def self.in_stderr_silence + begin + orig_stderr = $stderr.clone + $stderr.reopen File.new('/dev/null', 'w') + retval = yield + rescue Exception => e + $stderr.reopen orig_stderr + raise e + ensure + $stderr.reopen orig_stderr + end + retval + end + end +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb new file mode 100644 index 0000000000..292368bab9 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -0,0 +1,1751 @@ +module VCenterDriver +class VCenterVm + attr_reader :vm + + POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE + VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE + + ############################################################################ + # Creates a new VIVm using a RbVmomi::VirtualMachine object + # @param client [VCenterClient] client to connect to vCenter + # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil + ######################################################################## + def initialize(client, vm_vi ) + @vm = vm_vi + @client = client + + @used_cpu = 0 + @used_memory = 0 + + @netrx = 0 + @nettx = 0 + + @diskrdbytes = 0 + @diskwrbytes = 0 + @diskrdiops = 0 + @diskwriops = 0 + end + + ############################################################################ + # Deploys a VM + # @xml_text XML representation of the VM + ############################################################################ + def self.deploy(xml_text, lcm_state, deploy_id, hostname, datastore = nil, + ops = {}) + if lcm_state == "BOOT" || lcm_state == "BOOT_FAILURE" + return clone_vm(xml_text, hostname, datastore, ops) + else + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_fast(deploy_id, + ops[:ref], + ops[:name]) + xml = REXML::Document.new xml_text + + reconfigure_vm(vm, xml, false, hostname) + + vm.PowerOnVM_Task.wait_for_completion + + return vm.config.uuid + end + end + + ############################################################################ + # Cancels a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + # @param lcm_state state of the VM + # @param keep_disks keep or not VM disks in datastore + # @param disks VM attached disks + ############################################################################ + def self.cancel(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) + + case lcm_state + when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" + shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) + when "CANCEL", "LCM_INIT", "CLEANUP_RESUBMIT", "SHUTDOWN", "CLEANUP_DELETE" + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + begin + if vm.summary.runtime.powerState == "poweredOn" + vm.PowerOffVM_Task.wait_for_completion + end + rescue + end + + if keep_disks + detach_all_disks(vm) + else + detach_attached_disks(vm, disks, hostname) if disks + end + + # If the VM was instantiated to persistent, convert the VM to + # vCenter VM Template and update the OpenNebula new + # VM Template to point to the new vCenter VM Template + if !to_template.nil? + vm.MarkAsTemplate + + new_template = OpenNebula::Template.new_with_id(to_template, + OpenNebula::Client.new) + new_template.info + + public_cloud_str = "PUBLIC_CLOUD=[" + + new_template.to_hash["VMTEMPLATE"]["TEMPLATE"]["PUBLIC_CLOUD"].each{|k,v| + if k == "VM_TEMPLATE" + public_cloud_str += "VM_TEMPLATE=\"#{deploy_id}\",\n" + else + public_cloud_str += "#{k}=\"#{v}\",\n" + end + } + + public_cloud_str = public_cloud_str + "]" + + new_template.update(public_cloud_str, true) + else + vm.Destroy_Task.wait_for_completion + end + else + raise "LCM_STATE #{lcm_state} not supported for cancel" + end + end + + + ############################################################################ + # Saves a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.save(deploy_id, hostname, lcm_state) + case lcm_state + when "SAVE_MIGRATE" + raise "Migration between vCenters cluster not supported" + when "SAVE_SUSPEND", "SAVE_STOP" + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) + + vm.SuspendVM_Task.wait_for_completion + end + end + + ############################################################################ + # Resumes a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.resume(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) + + vm.PowerOnVM_Task.wait_for_completion + end + + ############################################################################ + # Reboots a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.reboot(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.RebootGuest.wait_for_completion + end + + ############################################################################ + # Resets a VM + # @param deploy_id vcetranslate_hostnamnter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + ############################################################################ + def self.reset(deploy_id, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + vm.ResetVM_Task.wait_for_completion + end + + ############################################################################ + # Shutdown a VM + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + # @param lcm_state state of the VM + # @param keep_disks keep or not VM disks in datastore + # @param disks VM attached disks + # @param to_template whether this VM has been instantiated as persistent + ############################################################################ + def self.shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + case lcm_state + when "SHUTDOWN" + begin + vm.ShutdownGuest + counter = 60*10 # 10 minutes + while counter > 0 + break if vm.runtime.powerState == "poweredOff" + counter -= 1 + sleep 1 + end + rescue + end + + if vm.runtime.powerState != "poweredOff" + vm.PowerOffVM_Task.wait_for_completion + end + + if keep_disks + detach_all_disks(vm) + else + detach_attached_disks(vm, disks, hostname) if disks + end + + # If the VM was instantiated to persistent, convert the VM to + # vCenter VM Template and update the OpenNebula new + # VM Template to point to the new vCenter VM Template + if !to_template.nil? + vm.MarkAsTemplate + + new_template = OpenNebula::Template.new_with_id(to_template, + OpenNebula::Client.new) + new_template.info + + public_cloud_str = "PUBLIC_CLOUD=[" + + new_template.to_hash["VMTEMPLATE"]["TEMPLATE"]["PUBLIC_CLOUD"].each{|k,v| + if k == "VM_TEMPLATE" + public_cloud_str += "VM_TEMPLATE=\"#{deploy_id}\"\n" + else + public_cloud_str += "#{k}=\"#{v}\",\n" + end + } + + public_cloud_str = public_cloud_str + "]" + + new_template.update(public_cloud_str, true) + else + vm.Destroy_Task.wait_for_completion + end + + when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" + begin + vm.ShutdownGuest + counter = 60*10 # 10 minutes + while counter > 0 + break if vm.runtime.powerState == "poweredOff" + counter -= 1 + sleep 1 + end + rescue + end + + if vm.runtime.powerState != "poweredOff" + vm.PowerOffVM_Task.wait_for_completion + end + end + end + + ############################################################################ + # Create VM snapshot + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + # @param snaphot_name name of the snapshot + ############################################################################ + def self.create_snapshot(deploy_id, hostname, snapshot_name) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + snapshot_hash = { + :name => snapshot_name, + :description => "OpenNebula Snapshot of VM #{deploy_id}", + :memory => true, + :quiesce => true + } + + vm = connection.find_vm_template(deploy_id) + + vm.CreateSnapshot_Task(snapshot_hash).wait_for_completion + + return snapshot_name + end + + ############################################################################ + # Find VM snapshot + # @param list root list of VM snapshots + # @param snaphot_name name of the snapshot + ############################################################################ + def self.find_snapshot(list, snapshot_name) + list.each do |i| + if i.name == snapshot_name + return i.snapshot + elsif !i.childSnapshotList.empty? + snap = find_snapshot(i.childSnapshotList, snapshot_name) + return snap if snap + end + end + + nil + end + + ############################################################################ + # Delete VM snapshot + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + # @param snaphot_name name of the snapshot + ############################################################################ + def self.delete_snapshot(deploy_id, hostname, snapshot_name) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + list = vm.snapshot.rootSnapshotList + + snapshot = find_snapshot(list, snapshot_name) + return nil if !snapshot + + delete_snapshot_hash = { + :_this => snapshot, + :removeChildren => false + } + + snapshot.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion + end + + ############################################################################ + # Revert VM snapshot + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + # @param snaphot_name name of the snapshot + ############################################################################ + def self.revert_snapshot(deploy_id, hostname, snapshot_name) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + list = vm.snapshot.rootSnapshotList + + snapshot = find_snapshot(list, snapshot_name) + return nil if !snapshot + + revert_snapshot_hash = { + :_this => snapshot + } + + snapshot.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion + end + + ############################################################################ + # Attach NIC to a VM + # @param deploy_id vcenter identifier of the VM + # @param mac MAC address of the NIC to be attached + # @param bridge name of the Network in vCenter + # @param model model of the NIC to be attached + # @param host hostname of the ESX where the VM is running + ############################################################################ + def self.attach_nic(deploy_id, mac, bridge, model, host) + hid = VIClient::translate_hostname(host) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + spec_nics = calculate_addnic_spec(vm, mac, bridge, model) + + spec_hash = {:deviceChange => [spec_nics]} + + + #B4897 track hot plugged nics + hotplugged_nics = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.hotplugged_nics" + end + + if hotplugged_nics && !hotplugged_nics.empty? + hotplugged_nics = hotplugged_nics[0][:value].to_s + hotplugged_nics << mac.to_s << ";" if !hotplugged_nics.include?(mac) + else + hotplugged_nics = "" + hotplugged_nics << mac.to_s << ";" + end + + config_array = [{:key=>"opennebula.hotplugged_nics", + :value=>hotplugged_nics}] + extra_config_spec = {:extraConfig =>config_array} + + spec_hash.merge!(extra_config_spec) + + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + + end + + ############################################################################ + # Detach NIC from a VM + ############################################################################ + def self.detach_nic(deploy_id, mac, host) + hid = VIClient::translate_hostname(host) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + nic = vm.config.hardware.device.find { |d| + is_nic?(d) && (d.macAddress == mac) + } + + raise "Could not find NIC with mac address #{mac}" if nic.nil? + + #B4897 track hot plugged nics + hotplugged_nics = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.hotplugged_nics" + end + + config_array = [] + if hotplugged_nics && !hotplugged_nics.empty? + hotplugged_nics = hotplugged_nics[0][:value].to_s + hotplugged_nics.slice!(mac + ";") # remove hotplugged nic + config_array = [{:key=>"opennebula.hotplugged_nics", + :value=>hotplugged_nics}] + end + + spec = { + :deviceChange => [ + :operation => :remove, + :device => nic + ], + :extraConfig => config_array + } + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + ############################################################################ + # Reconfigures a VM (context data) + # @param deploy_id vcenter identifier of the VM + # @param hostname name of the host (equals the vCenter cluster) + # @param xml_text XML repsentation of the VM + ############################################################################ + def self.reconfigure(deploy_id, hostname, xml_text) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) + + xml = REXML::Document.new xml_text + context = xml.root.elements["//TEMPLATE/CONTEXT"] + + if context + context_text = create_context(context) + context_spec = { + :extraConfig => [ + { :key=>"guestinfo.opennebula.context", + :value=> Base64.encode64(context_text) } + ] + } + + spec = RbVmomi::VIM.VirtualMachineConfigSpec(context_spec) + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + end + + ######################################################################## + # Initialize the vm monitor information + ######################################################################## + def monitor(host) + @summary = @vm.summary + @state = state_to_c(@summary.runtime.powerState) + + if @state != VM_STATE[:active] + @used_cpu = 0 + @used_memory = 0 + + @netrx = 0 + @nettx = 0 + + @diskrdbytes = 0 + @diskwrbytes = 0 + @diskrdiops = 0 + @diskwriops = 0 + return + end + + @used_memory = @summary.quickStats.hostMemoryUsage * 1024 + cpuMhz = @vm.runtime.host.summary.hardware.cpuMhz.to_f + + @used_cpu = + ((@summary.quickStats.overallCpuUsage.to_f / cpuMhz) * 100).to_s + @used_cpu = sprintf('%.2f',@used_cpu).to_s + + # Check for negative values + @used_memory = 0 if @used_memory.to_i < 0 + @used_cpu = 0 if @used_cpu.to_i < 0 + + @esx_host = @vm.summary.runtime.host.name + @guest_ip = @vm.guest.ipAddress + @guest_state = @vm.guest.guestState + @vmware_tools = @vm.guest.toolsRunningStatus + @vmtools_ver = @vm.guest.toolsVersion + @vmtools_verst = @vm.guest.toolsVersionStatus + + guest_ip_addresses = [] + + @vm.guest.net.each do |net| + net.ipConfig.ipAddress.each do |ip| + guest_ip_addresses << ip.ipAddress + end if net.ipConfig && net.ipConfig.ipAddress + end if @vm.guest.net + + @guest_ip_addresses = guest_ip_addresses.join(',') + + # PerfManager metrics + pm = @client.vim.serviceInstance.content.perfManager + + provider = pm.provider_summary [@vm].first + refresh_rate = provider.refreshRate + + vmid = -1 + extraconfig_vmid = @vm.config.extraConfig.select{|val| + val[:key]=="opennebula.vm.id"} + if extraconfig_vmid.size > 0 and extraconfig_vmid[0] + vmid = extraconfig_vmid[0][:value].to_i + end + + if vmid < 0 + @nettx = 0 + @netrx = 0 + @diskrdbytes = 0 + @diskwrbytes = 0 + @diskrdiops = 0 + @diskwriops = 0 + else + one_vm = OpenNebula::VirtualMachine.new_with_id(vmid, OpenNebula::Client.new) + one_vm.info + stats = [] + + if(one_vm["MONITORING/LAST_MON"] && one_vm["MONITORING/LAST_MON"].to_i != 0 ) + #Real time data stores max 1 hour. 1 minute has 3 samples + interval = (Time.now.to_i - one_vm["MONITORING/LAST_MON"].to_i) + + #If last poll was more than hour ago get 3 minutes, + #else calculate how many samples since last poll + samples = interval > 3600 ? 9 : (interval / refresh_rate) + 1 + max_samples = samples > 0 ? samples : 1 + + stats = pm.retrieve_stats( + [@vm], + ['net.transmitted','net.bytesRx','net.bytesTx','net.received', + 'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged', + 'virtualDisk.read','virtualDisk.write'], + {interval:refresh_rate, max_samples: max_samples} + ) + else + # First poll, get at least latest 3 minutes = 9 samples + stats = pm.retrieve_stats( + [@vm], + ['net.transmitted','net.bytesRx','net.bytesTx','net.received', + 'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged', + 'virtualDisk.read','virtualDisk.write'], + {interval:refresh_rate, max_samples: 9} + ) + end + + if stats.empty? || stats.first[1][:metrics].empty? + @nettx = 0 + @netrx = 0 + @diskrdbytes = 0 + @diskwrbytes = 0 + @diskrdiops = 0 + @diskwriops = 0 + else + metrics = stats.first[1][:metrics] + + nettx_kbpersec = 0 + if metrics['net.transmitted'] + metrics['net.transmitted'].each { |sample| + nettx_kbpersec += sample + } + end + + netrx_kbpersec = 0 + if metrics['net.bytesRx'] + metrics['net.bytesRx'].each { |sample| + netrx_kbpersec += sample + } + end + + read_kbpersec = 0 + if metrics['virtualDisk.read'] + metrics['virtualDisk.read'].each { |sample| + read_kbpersec += sample + } + end + + read_iops = 0 + if metrics['virtualDisk.numberReadAveraged'] + metrics['virtualDisk.numberReadAveraged'].each { |sample| + read_iops += sample + } + end + + write_kbpersec = 0 + if metrics['virtualDisk.write'] + metrics['virtualDisk.write'].each { |sample| + write_kbpersec += sample + } + end + + write_iops = 0 + if metrics['virtualDisk.numberWriteAveraged'] + metrics['virtualDisk.numberWriteAveraged'].each { |sample| + write_iops += sample + } + end + + @nettx = (nettx_kbpersec * 1024 * refresh_rate).to_i + @netrx = (netrx_kbpersec * 1024 * refresh_rate).to_i + + @diskrdiops = read_iops + @diskwriops = write_iops + @diskrdbytes = (read_kbpersec * 1024 * refresh_rate).to_i + @diskwrbytes = (write_kbpersec * 1024 * refresh_rate).to_i + + end + end + end + + ######################################################################## + # Generates a OpenNebula IM Driver valid string with the monitor info + ######################################################################## + def info + return 'STATE=d' if @state == 'd' + + str_info = "" + + str_info << "GUEST_IP=" << @guest_ip.to_s << " " if @guest_ip + if @guest_ip_addresses && !@guest_ip_addresses.empty? + str_info << "GUEST_IP_ADDRESSES=\\\"" << + @guest_ip_addresses.to_s << "\\\" " + end + str_info << "LAST_MON=" << Time.now.to_i.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:state]}=" << @state << " " + str_info << "#{POLL_ATTRIBUTE[:cpu]}=" << @used_cpu.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:memory]}=" << @used_memory.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:netrx]}=" << @netrx.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:nettx]}=" << @nettx.to_s << " " + str_info << "DISKRDBYTES=" << @diskrdbytes.to_s << " " + str_info << "DISKWRBYTES=" << @diskwrbytes.to_s << " " + str_info << "DISKRDIOPS=" << @diskrdiops.to_s << " " + str_info << "DISKWRIOPS=" << @diskwriops.to_s << " " + str_info << "ESX_HOST=\\\"" << @esx_host.to_s << "\\\" " + str_info << "GUEST_STATE=" << @guest_state.to_s << " " + str_info << "VMWARETOOLS_RUNNING_STATUS=" << @vmware_tools.to_s << " " + str_info << "VMWARETOOLS_VERSION=" << @vmtools_ver.to_s << " " + str_info << "VMWARETOOLS_VERSION_STATUS=" << @vmtools_verst.to_s << " " + str_info << "RESOURCE_POOL=\\\"" << @vm.resourcePool.name << "\\\" " + end + + ######################################################################## + # Generates an OpenNebula Template for this VCenterVm + ######################################################################## + def to_one(host) + cluster_name = host.cluster_name + + str = "NAME = \"#{@vm.name} - #{cluster_name}\"\n"\ + "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ + "HYPERVISOR = \"vcenter\"\n"\ + "PUBLIC_CLOUD = [\n"\ + " TYPE =\"vcenter\",\n"\ + " VM_TEMPLATE =\"#{@vm.config.uuid}\",\n"\ + " VCENTER_REF =\"#{@vm.ref}\",\n"\ + " VCENTER_NAME=\"#{@vm.name}\",\n"\ + " HOST =\"#{cluster_name}\"\n"\ + "]\n"\ + "GRAPHICS = [\n"\ + " TYPE =\"vnc\",\n"\ + " LISTEN =\"0.0.0.0\"\n"\ + "]\n"\ + "SCHED_REQUIREMENTS=\"NAME=\\\"#{cluster_name}\\\"\"\n"\ + "CONTEXT = ["\ + " NETWORK = \"YES\","\ + " SSH_PUBLIC_KEY = \"$USER[SSH_PUBLIC_KEY]\" ]" + + if @vm.config.annotation.nil? || @vm.config.annotation.empty? + str << "DESCRIPTION = \"vCenter Template imported by OpenNebula"\ + " from Cluster #{@vm.runtime.host.parent.name}\"\n" + else + notes = @vm.config.annotation.gsub("\\", "\\\\").gsub("\"", "\\\"") + str << "DESCRIPTION = \"#{notes}\"\n" + end + + case @vm.guest.guestFullName + when /CentOS/i + str << "LOGO=images/logos/centos.png" + when /Debian/i + str << "LOGO=images/logos/debian.png" + when /Red Hat/i + str << "LOGO=images/logos/redhat.png" + when /Ubuntu/i + str << "LOGO=images/logos/ubuntu.png" + when /Windows XP/i + str << "LOGO=images/logos/windowsxp.png" + when /Windows/i + str << "LOGO=images/logos/windows8.png" + when /Linux/i + str << "LOGO=images/logos/linux.png" + end + return str + end + + ######################################################################## + # Generates a Datastore user input + ######################################################################## + def to_one_ds(host, default_ds) + # Datastores User Input + str = "" + + if host.ds_list != "" + str = "M|list|Which datastore you want this VM to run on?|"\ + << "#{host.ds_list}|#{default_ds}" + end + + return str + end + + ######################################################################## + # Generates a Resource Pool user input + ######################################################################## + def to_one_rp(host) + # Resource Pool User Input + str = "" + + if host.rp_list != "" + str = "M|list|Which resource pool you want this VM to run"\ + " in?|#{host.rp_list}|#{host.rp_list.split(",")[0]}" + end + + return str + end + + ######################################################################## + # Generates an OpenNebula VirtualMachine for this VCenterVm + # + # + ######################################################################## + def vm_to_one(host) + cluster_name = host.cluster_name + + state = case state_to_c(@summary.runtime.powerState) + when 'a' + "RUNNING" + when 'd' + "POWEROFF" + end + + str = "NAME = \"#{@vm.name} - #{cluster_name}\"\n"\ + "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ + "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ + "HYPERVISOR = \"vcenter\"\n"\ + "PUBLIC_CLOUD = [\n"\ + " TYPE =\"vcenter\",\n"\ + " VM_TEMPLATE =\"#{@vm.config.uuid}\",\n"\ + " HOST =\"#{cluster_name}\"\n"\ + "]\n"\ + "IMPORT_VM_ID = \"#{@vm.config.uuid}\"\n"\ + "IMPORT_STATE = \"#{state}\"\n"\ + "SCHED_REQUIREMENTS=\"NAME=\\\"#{cluster_name}\\\"\"\n" + + vp = @vm.config.extraConfig.select{|v| + v[:key].downcase=="remotedisplay.vnc.port"} + keymap = @vm.config.extraConfig.select{|v| + v[:key].downcase=="remotedisplay.vnc.keymap"} + + if vp.size > 0 + str << "GRAPHICS = [\n"\ + " TYPE =\"vnc\",\n"\ + " LISTEN =\"0.0.0.0\",\n"\ + " PORT =\"#{vp[0][:value]}\"\n" + str << " ,KEYMAP =\"#{keymap[0][:value]}\"\n" if keymap[0] + str << "]\n" + end + + if @vm.config.annotation.nil? || @vm.config.annotation.empty? + str << "DESCRIPTION = \"vCenter Virtual Machine imported by"\ + " OpenNebula from Cluster #{cluster_name}\"\n" + else + notes = @vm.config.annotation.gsub("\\", "\\\\").gsub("\"", "\\\"") + str << "DESCRIPTION = \"#{notes}\"\n" + end + + case @vm.guest.guestFullName + when /CentOS/i + str << "LOGO=images/logos/centos.png" + when /Debian/i + str << "LOGO=images/logos/debian.png" + when /Red Hat/i + str << "LOGO=images/logos/redhat.png" + when /Ubuntu/i + str << "LOGO=images/logos/ubuntu.png" + when /Windows XP/i + str << "LOGO=images/logos/windowsxp.png" + when /Windows/i + str << "LOGO=images/logos/windows8.png" + when /Linux/i + str << "LOGO=images/logos/linux.png" + end + + return str + end + +private + + ######################################################################## + # Converts the VI string state to OpenNebula state convention + # Guest states are: + # - poweredOff The virtual machine is currently powered off. + # - poweredOn The virtual machine is currently powered on. + # - suspended The virtual machine is currently suspended. + ######################################################################## + def state_to_c(state) + case state + when 'poweredOn' + VM_STATE[:active] + when 'suspended' + VM_STATE[:paused] + when 'poweredOff' + VM_STATE[:deleted] + else + VM_STATE[:unknown] + end + end + + ######################################################################## + # Checks if a RbVmomi::VIM::VirtualDevice is a network interface + ######################################################################## + def self.is_nic?(device) + !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? + end + + ######################################################################## + # Checks if a RbVmomi::VIM::VirtualDevice is a disk + ######################################################################## + def self.is_disk?(device) + is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? + is_cdrom = !(device.class.ancestors.index(RbVmomi::VIM::VirtualCdrom)).nil? + is_disk or is_cdrom + end + + ######################################################################## + # Returns the spec to reconfig a VM and add a NIC + ######################################################################## + def self.calculate_addnic_spec(vm, mac, bridge, model, limit=nil, rsrv=nil) + model = model.nil? ? nil : model.downcase + network = vm.runtime.host.network.select{|n| n.name==bridge} + backing = nil + + if network.empty? + raise "Network #{bridge} not found in host #{vm.runtime.host.name}" + else + network = network[0] + end + + card_num = 1 # start in one, we want the next avaliable id + + vm.config.hardware.device.each{ |dv| + card_num = card_num + 1 if is_nic?(dv) + } + + nic_card = case model + when "virtuale1000", "e1000" + RbVmomi::VIM::VirtualE1000 + when "virtuale1000e", "e1000e" + RbVmomi::VIM::VirtualE1000e + when "virtualpcnet32", "pcnet32" + RbVmomi::VIM::VirtualPCNet32 + when "virtualsriovethernetcard", "sriovethernetcard" + RbVmomi::VIM::VirtualSriovEthernetCard + when "virtualvmxnetm", "vmxnetm" + RbVmomi::VIM::VirtualVmxnetm + when "virtualvmxnet2", "vmnet2" + RbVmomi::VIM::VirtualVmxnet2 + when "virtualvmxnet3", "vmxnet3" + RbVmomi::VIM::VirtualVmxnet3 + else # If none matches, use VirtualE1000 + RbVmomi::VIM::VirtualE1000 + end + + if network.class == RbVmomi::VIM::Network + backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( + :deviceName => bridge, + :network => network) + else + port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( + :switchUuid => + network.config.distributedVirtualSwitch.uuid, + :portgroupKey => network.key) + backing = + RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( + :port => port) + end + + card_spec = { + :key => 0, + :deviceInfo => { + :label => "net" + card_num.to_s, + :summary => bridge + }, + :backing => backing, + :addressType => mac ? 'manual' : 'generated', + :macAddress => mac + } + + if (limit or rsrv) and (limit > 0) + ra_spec = Hash.new + rsrv = limit if rsrv > limit + ra_spec[:limit] = limit if limit + ra_spec[:reservation] = rsrv if rsrv + ra_spec[:share] = RbVmomi::VIM.SharesInfo({ + :level => RbVmomi::VIM.SharesLevel("normal"), + :shares => 0 + }) + card_spec[:resourceAllocation] = + RbVmomi::VIM.VirtualEthernetCardResourceAllocation(ra_spec) + end + + return { + :operation => :add, + :device => nic_card.new(card_spec) + } + end + + ######################################################################## + # Clone a vCenter VM Template and leaves it powered on + ######################################################################## + def self.clone_vm(xml_text, hostname, datastore, ops = {}) + + host_id = VCenterDriver::VIClient.translate_hostname(hostname) + + # Retrieve hostname + + host = OpenNebula::Host.new_with_id(host_id, OpenNebula::Client.new()) + host.info # Not failing if host retrieval fails + + # Get VM prefix name + + if host["/HOST/TEMPLATE/VM_PREFIX"] and !host["/HOST/TEMPLATE/VM_PREFIX"].empty? + vmname_prefix = host["/HOST/TEMPLATE/VM_PREFIX"] + else # fall back to default value + vmname_prefix = "one-$i-" + end + + xml = REXML::Document.new xml_text + pcs = xml.root.get_elements("/VM/USER_TEMPLATE/PUBLIC_CLOUD") + + raise "Cannot find VCenter element in VM template." if pcs.nil? + + template = pcs.select { |t| + type = t.elements["TYPE"] + !type.nil? && type.text.downcase == "vcenter" + } + + # If there are multiple vCenter templates, find the right one + + if template.is_a? Array + all_vcenter_templates = template.clone + # If there is more than one coincidence, pick the first one + template = template.select {|t| + cluster_name = t.elements["HOST"] + !cluster_name.nil? && cluster_name.text == hostname + }[0] + # The template may not reference any specific CLUSTER + # (referenced to as HOST in the OpenNebula template) + # Therefore, here take the first one that does not + # specify a CLUSTER to see if we are lucky + if template.nil? + template = all_vcenter_templates.select {|t| + t.elements["HOST"].nil? + }[0] + end + end + + raise "Cannot find vCenter element in VM template." if template.nil? + + uuid = template.elements["VM_TEMPLATE"] + + raise "Cannot find VM_TEMPLATE in vCenter element." if uuid.nil? + + uuid = uuid.text + vmid = xml.root.elements["/VM/ID"].text + vmname_prefix.gsub!("$i", vmid) + vcenter_name = "#{vmname_prefix}#{xml.root.elements["/VM/NAME"].text}" + hid = xml.root.elements["/VM/HISTORY_RECORDS/HISTORY/HID"] + + raise "Cannot find host id in deployment file history." if hid.nil? + + connection = VIClient.new(hid) + vc_template = connection.find_vm_fast(uuid, ops[:ref], ops[:name]) + + # Find out requested and available resource pool + + req_rp = nil + if !xml.root.elements["/VM/USER_TEMPLATE/RESOURCE_POOL"].nil? + req_rp = xml.root.elements["/VM/USER_TEMPLATE/RESOURCE_POOL"].text + end + + if connection.rp_confined? + rp = connection.resource_pool.first + if req_rp && rp.name != req_rp + raise "Available resource pool in host [#{rp.name}]"\ + " does not match requested resource pool"\ + " [#{req_rp}]" + end + else + if req_rp # if there is requested resource pool, retrieve it + rp = connection.find_resource_pool(req_rp) + raise "Cannot find resource pool "\ + "#{template.elements["RESOURCE_POOL"].text}" if !rp + else # otherwise, get the default resource pool + rp = connection.default_resource_pool + end + end + + # Find out requested and available datastore + + if !xml.root.elements["/VM/USER_TEMPLATE/VCENTER_DATASTORE"].nil? + datastore = xml.root.elements["/VM/USER_TEMPLATE/VCENTER_DATASTORE"].text + end + + if datastore + datastores = VIClient.get_entities(connection.dc.datastoreFolder, + 'Datastore') + + storage_pods = VIClient.get_entities(connection.dc.datastoreFolder, + 'StoragePod') + + storpod = storage_pods.select{|sp| sp.name == datastore} + + storage_pods.each { |sp| + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + ds = datastores.select{|ds| ds.name == datastore}[0] + + raise "Cannot find datastore #{datastore}" if !ds && !storpod + + end + + relocate_spec_params = { + :pool => rp + } + + relocate_spec_params[:datastore] = ds if datastore + + relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking if ds + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + relocate_spec_params) + + # This running flag will prevent spurious poweroff states in the VM + + running_flag = [{:key=>"opennebula.vm.running",:value=>"no"}] + + running_flag_spec = RbVmomi::VIM.VirtualMachineConfigSpec( + {:extraConfig =>running_flag}) + + clone_parameters = { + :location => relocate_spec, + :powerOn => false, + :template => false, + :config => running_flag_spec + } + + customization = template.elements["CUSTOMIZATION_SPEC"] + + vim = connection.vim + + if !customization.nil? + begin + custom_spec = vim.serviceContent.customizationSpecManager. + GetCustomizationSpec(:name => customization.text) + + if custom_spec && spec=custom_spec.spec + clone_parameters[:customization] = spec + else + raise "Error getting customization spec" + end + + rescue + raise "Customization spec '#{customization.text}' not found" + end + end + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(clone_parameters) + + if storpod && !storpod.empty? && storpod[0].is_a?(RbVmomi::VIM::StoragePod) + + storage_manager = vim.serviceContent.storageResourceManager + + pod_spec = RbVmomi::VIM.StorageDrsPodSelectionSpec(storagePod: storpod[0]) + + storage_spec = RbVmomi::VIM.StoragePlacementSpec( + type: 'clone', + cloneName: vcenter_name, + folder: vc_template.parent, + podSelectionSpec: pod_spec, + vm: vc_template, + cloneSpec: clone_spec + ) + + result = storage_manager.RecommendDatastores(storageSpec: storage_spec) + + recommendation = result.recommendations[0] + + key = recommendation.key ||= '' + + if key == '' + raise "Missing Datastore recommendation for StoragePod (Storage DRS)" + end + + begin + apply_sr = storage_manager.ApplyStorageDrsRecommendation_Task(key: [key]).wait_for_completion + vm = apply_sr.vm + rescue Exception => e + raise "Cannot clone VM Template to StoragePod: #{e.message}" + end + else + + begin + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => vcenter_name, + :spec => clone_spec).wait_for_completion + rescue Exception => e + + if !e.message.start_with?('DuplicateName') + raise "Cannot clone VM Template: #{e.message}" + end + + vm = connection.find_vm(vcenter_name) + + raise "Cannot clone VM Template" if vm.nil? + + vm.Destroy_Task.wait_for_completion + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => vcenter_name, + :spec => clone_spec).wait_for_completion + end + + end + + reconfigure_vm(vm, xml, true, hostname) + + # Power on the VM + vm.PowerOnVM_Task.wait_for_completion + + # Set to yes the running flag + + config_array = [{:key=>"opennebula.vm.running",:value=>"yes"}] + spec = RbVmomi::VIM.VirtualMachineConfigSpec( + {:extraConfig =>config_array}) + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + + return vm.config.uuid + end + + ######################################################################## + # Reconfigures a VM with new deployment description + ######################################################################## + def self.reconfigure_vm(vm, xml, newvm, hostname) + vm_uuid = vm.config.uuid + vmid = xml.root.elements["/VM/ID"].text + context = xml.root.elements["/VM/TEMPLATE/CONTEXT"] + + token = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.token" + end + + if token && !token.empty? + token = token.first[:value] + else + token = nil + end + + # Add VMID to VM's extraConfig + + config_array = [{:key=>"opennebula.vm.id",:value=>vmid}] + + # VNC Section + + vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] + vnc_listen = xml.root.elements["/VM/TEMPLATE/GRAPHICS/LISTEN"] + vnc_keymap = xml.root.elements["/VM/TEMPLATE/GRAPHICS/KEYMAP"] + + if !vnc_listen + vnc_listen = "0.0.0.0" + else + vnc_listen = vnc_listen.text + end + + context_vnc_spec = {} + + if vnc_port + config_array += + [{:key=>"remotedisplay.vnc.enabled",:value=>"TRUE"}, + {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}, + {:key=>"remotedisplay.vnc.ip", :value=>vnc_listen}] + end + + config_array += [{:key=>"remotedisplay.vnc.keymap", + :value=>vnc_keymap.text}] if vnc_keymap + + # Context section + + if context + context_text = create_context(context) + + # OneGate + onegate_token_flag = xml.root.elements["/VM/TEMPLATE/CONTEXT/TOKEN"] + + if onegate_token_flag and onegate_token_flag.text == "YES" + if token + onegate_token_64 = token + else + # Create the OneGate token string + vmid_str = xml.root.elements["/VM/ID"].text + stime_str = xml.root.elements["/VM/STIME"].text + str_to_encrypt = "#{vmid_str}:#{stime_str}" + + user_id = xml.root.elements['//CREATED_BY'].text + + if user_id.nil? + STDERR.puts {"VMID:#{vmid} CREATED_BY not present" \ + " in the VM TEMPLATE"} + return nil + end + + user = OpenNebula::User.new_with_id(user_id, + OpenNebula::Client.new) + rc = user.info + + if OpenNebula.is_error?(rc) + STDERR.puts {"VMID:#{vmid} user.info" \ + " error: #{rc.message}"} + return nil + end + + token_password = user['TEMPLATE/TOKEN_PASSWORD'] + + if token_password.nil? + STDERR.puts {"VMID:#{vmid} TOKEN_PASSWORD not present"\ + " in the USER:#{user_id} TEMPLATE"} + return nil + end + + cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") + cipher.encrypt + cipher.key = token_password + onegate_token = cipher.update(str_to_encrypt) + onegate_token << cipher.final + + onegate_token_64 = Base64.encode64(onegate_token).chop + config_array << { + :key => 'opennebula.token', + :value => onegate_token_64 + } + end + + context_text += "ONEGATE_TOKEN='#{onegate_token_64}'\n" + end + + context_text = Base64.encode64(context_text.chop) + + config_array += + [{:key=>"guestinfo.opennebula.context", + :value=>context_text}] + end + + device_change = [] + + # NIC section, build the reconfig hash + + nics = xml.root.get_elements("/VM/TEMPLATE/NIC") + + # If the VM is not new, avoid readding NiCs + if !newvm + nic_array = [] + + # Get MACs from NICs inside VM template + one_mac_addresses = Array.new + nics.each{|nic| + one_mac_addresses << nic.elements["MAC"].text + } + + # B4897 - Get mac of NICs that were hot-plugged from vCenter extraConfig + hotplugged_nics = [] + extraconfig_nics = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.hotplugged_nics" + end + + if extraconfig_nics && !extraconfig_nics.empty? + hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") + end + + vm.config.hardware.device.each{ |dv| + if is_nic?(dv) + nics.each{|nic| + if nic.elements["MAC"].text == dv.macAddress + nics.delete(nic) + end + } + + # B4897 - Remove detached NICs from vCenter that were unplugged in POWEROFF + if !one_mac_addresses.include?(dv.macAddress) && hotplugged_nics.include?(dv.macAddress) + nic_array << { :operation => :remove, :device => dv} + hotplugged_nics.delete(dv.macAddress) + config_array << { + :key => 'opennebula.hotplugged_nics', + :value => hotplugged_nics.join(";") + } + end + end + } + + device_change += nic_array + end + + if !nics.nil? + nic_array = [] + nics.each{|nic| + mac = nic.elements["MAC"].text + bridge = nic.elements["BRIDGE"].text + model = nic.elements["MODEL"] ? nic.elements["MODEL"].text : nil + limit_in = nic.elements["INBOUND_PEAK_BW"] ? nic.elements["INBOUND_PEAK_BW"].text : "" + limit_out = nic.elements["OUTBOUND_PEAK_BW"] ? nic.elements["OUTBOUND_PEAK_BW"].text : "" + limit = nil + if !limit_in.empty? or !limit_out.empty? + limit=([limit_in.to_i, limit_out.to_i].min / 1024) * 8 + end + rsrv_in = nic.elements["INBOUND_AVG_BW"] ? nic.elements["INBOUND_AVG_BW"].text : "" + rsrv_out = nic.elements["OUTBOUND_AVG_BW"] ? nic.elements["OUTBOUND_AVG_BW"].text : "" + rsrv = nil + if !rsrv_in.empty? or !rsrv_out.empty? + rsrv=([rsrv_in.to_i, rsrv_out.to_i].min / 1024) * 8 + end + nic_array << calculate_addnic_spec(vm, + mac, + bridge, + model, + limit, + rsrv) + } + + device_change += nic_array + end + + # DISK section, build the reconfig hash + + disks = xml.root.get_elements("/VM/TEMPLATE/DISK") + disk_spec = {} + + # If the VM is not new, avoid reading DISKS + if !newvm + vm.config.hardware.device.select { |d| + if is_disk?(d) + disks.each{|disk| + if d.backing.respond_to?(:fileName) && + disk.elements["SOURCE"].text == d.backing.fileName && + disks.delete(disk) + end + } + end + } + end + + if !disks.nil? + disk_array = [] + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + position = 0 + disks.each{|disk| + ds_name = disk.elements["VCENTER_NAME"].text + img_name = get_disk_img_path(disk, vmid) + type_str = disk.elements["TYPE"].text + + disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection, position)[:deviceChange] + position += 1 + } + + device_change += disk_array + end + + # Capacity section + + cpu = xml.root.elements["/VM/TEMPLATE/VCPU"] ? xml.root.elements["/VM/TEMPLATE/VCPU"].text : 1 + memory = xml.root.elements["/VM/TEMPLATE/MEMORY"].text + capacity_spec = {:numCPUs => cpu.to_i, + :memoryMB => memory } + + # Perform the VM reconfiguration + if config_array != [] + context_vnc_spec = {:extraConfig =>config_array} + end + + spec_hash = context_vnc_spec.merge(capacity_spec) + if device_change.length > 0 + spec_hash.merge!({ :deviceChange => device_change }) + end + + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + ############################################################################ + # Attach disk to a VM + # @params hostname[String] vcenter cluster name in opennebula as host + # @params deploy_id[String] deploy id of the vm + # @params ds_name[String] name of the datastore + # @params img_name[String] path of the image + # @params size_kb[String] size in kb of the disk + # @params vm[RbVmomi::VIM::VirtualMachine] VM if called from instance + # @params connection[ViClient::connectoon] connection if called from instance + # @params position The number of disks to attach. Starts with 0. + ############################################################################ + def self.attach_disk(hostname, deploy_id, ds_name, img_name, type, size_kb, vm=nil, connection=nil, position=0) + only_return = true + if !vm + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + only_return = false + end + + # Find datastore within datacenter + datastores = VIClient.get_entities(connection.dc.datastoreFolder, + 'Datastore') + + storage_pods = VIClient.get_entities(connection.dc.datastoreFolder, + 'StoragePod') + storage_pods.each { |sp| + storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') + if not storage_pod_datastores.empty? + datastores.concat(storage_pod_datastores) + end + } + + ds = datastores.select{|ds| ds.name == ds_name}[0] + + controller, new_number = find_free_controller(vm, position) + + if type == "CDROM" + vmdk_backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo( + :datastore => ds, + :fileName => "[#{ds_name}] #{img_name}" + ) + + cd = vm.config.hardware.device.select {|hw| + hw.class == RbVmomi::VIM::VirtualCdrom}.first + + # If no CDROM drive present, we need to add it + if !cd + controller, new_unit_number = find_free_controller(vm) + cdrom_drive_spec = RbVmomi::VIM.VirtualMachineConfigSpec( + :deviceChange => [{ + :operation => :add, + :device => RbVmomi::VIM::VirtualCdrom( + :backing => vmdk_backing, + :key => -1, + :controllerKey => 15000, + :unitNumber => 0, + :connectable => RbVmomi::VIM::VirtualDeviceConnectInfo( + :startConnected => true, + :connected => true, + :allowGuestControl => true + ) + )}] + ) + + vm.ReconfigVM_Task(:spec => + cdrom_drive_spec).wait_for_completion + + return + else + device = RbVmomi::VIM::VirtualCdrom( + backing: vmdk_backing, + key: cd.key, + controllerKey: cd.controllerKey, + connectable: RbVmomi::VIM::VirtualDeviceConnectInfo( + startConnected: true, + connected: true, + allowGuestControl: true + ) + ) + device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( + :device => device, + :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('edit') + ) + end + else + vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo( + :datastore => ds, + :diskMode => 'persistent', + :fileName => "[#{ds_name}] #{img_name}" + ) + + device = RbVmomi::VIM::VirtualDisk( + :backing => vmdk_backing, + :capacityInKB => size_kb, + :controllerKey => controller.key, + :key => -1, + :unitNumber => new_number + ) + + device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( + :device => device, + :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') + ) + end + + vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( + :deviceChange => [device_config_spec] + ) + + return vm_config_spec if only_return + + vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion + end + + def self.find_free_controller(vm, position=0) + free_scsi_controllers = Array.new + available_controller = nil + scsi_schema = Hash.new + + used_numbers = Array.new + available_numbers = Array.new + + vm.config.hardware.device.each{ |dev| + if dev.is_a? RbVmomi::VIM::VirtualSCSIController + if scsi_schema[dev.controllerKey].nil? + scsi_schema[dev.key] = Hash.new + scsi_schema[dev.key][:lower] = Array.new + end + used_numbers << dev.scsiCtlrUnitNumber + scsi_schema[dev.key][:device] = dev + end + + next if dev.class != RbVmomi::VIM::VirtualDisk + used_numbers << dev.unitNumber + } + + 15.times{ |scsi_id| + available_numbers << scsi_id if used_numbers.grep(scsi_id).length <= 0 + } + + scsi_schema.keys.each{|controller| + if scsi_schema[controller][:lower].length < 15 + free_scsi_controllers << scsi_schema[controller][:device].deviceInfo.label + end + } + + if free_scsi_controllers.length > 0 + available_controller_label = free_scsi_controllers[0] + else + add_new_scsi(vm, scsi_schema) + return find_free_controller(vm) + end + + controller = nil + + vm.config.hardware.device.each { |device| + (controller = device ; break) if device.deviceInfo.label == available_controller_label + } + + new_unit_number = available_numbers.sort[position] + + return controller, new_unit_number + end + + def self.add_new_scsi(vm, scsi_schema) + controller = nil + + if scsi_schema.keys.length >= 4 + raise "Cannot add a new controller, maximum is 4." + end + + if scsi_schema.keys.length == 0 + scsi_key = 0 + scsi_number = 0 + else scsi_schema.keys.length < 4 + scsi_key = scsi_schema.keys.sort[-1] + 1 + scsi_number = scsi_schema[scsi_schema.keys.sort[-1]][:device].busNumber + 1 + end + + controller_device = RbVmomi::VIM::VirtualLsiLogicController( + :key => scsi_key, + :busNumber => scsi_number, + :sharedBus => :noSharing + ) + + device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( + :device => controller_device, + :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') + ) + + vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( + :deviceChange => [device_config_spec] + ) + + vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion + + vm.config.hardware.device.each { |device| + if device.class == RbVmomi::VIM::VirtualLsiLogicController && + device.key == scsi_key + controller = device.deviceInfo.label + end + } + + return controller + end + + ############################################################################ + # Detach a specific disk from a VM + # @params hostname[String] vcenter cluster name in opennebula as host + # @params deploy_id[String] deploy id of the vm + # @params ds_name[String] name of the datastore + # @params img_path[String] path of the image + ############################################################################ + def self.detach_disk(hostname, deploy_id, ds_name, img_path) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vm = connection.find_vm_template(deploy_id) + + ds_and_img_name = "[#{ds_name}] #{img_path}" + + disk = vm.config.hardware.device.select { |d| is_disk?(d) && + d.backing.respond_to?(:fileName) && + d.backing.fileName == ds_and_img_name } + + raise "Disk #{img_path} not found." if disk.nil? + + spec = { :deviceChange => [{ + :operation => :remove, + :device => disk[0] + }]} + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + ############################################################################ + # Detach all disks from a VM + # @params vm[VCenterVm] vCenter VM + ############################################################################ + def self.detach_all_disks(vm) + disks = vm.config.hardware.device.select { |d| is_disk?(d) } + + return if disks.nil? + + spec = { :deviceChange => [] } + + disks.each{|disk| + spec[:deviceChange] << { + :operation => :remove, + :device => disk + } + } + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + def self.create_context(context) + # Remove (9) and \n (11) + context_text = "# Context variables generated by OpenNebula\n" + context.elements.each{|context_element| + next if !context_element.text + context_text += context_element.name + "='" + + context_element.text.gsub("'", "\\'") + "'\n" + } + context_text + end + + ############################################################################ + # Detach attached disks from a VM + ############################################################################ + def self.detach_attached_disks(vm, disks, hostname) + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + + vmid = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.vm.id" + end.first.value + + spec = { :deviceChange => [] } + + disks.each{ |disk| + img_name = get_disk_img_path(disk, vmid) + ds_and_img_name = "[#{disk['VCENTER_NAME']}] #{img_name}" + + vcenter_disk = vm.config.hardware.device.select { |d| is_disk?(d) && + d.backing.respond_to?(:fileName) && + d.backing.fileName == ds_and_img_name }[0] + spec[:deviceChange] << { + :operation => :remove, + :device => vcenter_disk + } + } + + vm.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + + ############################################################################ + # Returns the source path of a disk. It will use the 'SOURCE' path if + # persistent and one-#{vm_id}-#{disk_id}.vmdk otherwise + # @param disks VM attached disks, either an REXML document, or a hash + # @param vmid The VM ID + ############################################################################ + def self.get_disk_img_path(disk, vmid) + if disk.respond_to? :elements + # It's a REXML::Document, probably coming from self.reconfigure_vm + persistent = disk.elements["PERSISTENT"].text == "YES" rescue false + + if persistent + disk.elements["SOURCE"].text + else + disk_id = disk.elements["DISK_ID"].text + "one_#{vmid}_#{disk_id}.vmdk" + end + else + # It's a hash, probably coming from self.detach_attached_disks + persistent = disk["PERSISTENT"] == "YES" + + if persistent + disk["SOURCE"] + else + disk_id = disk["DISK_ID"] + "one_#{vmid}_#{disk_id}.vmdk" + end + end + end + +end +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb new file mode 100644 index 0000000000..882c318f11 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver2.rb @@ -0,0 +1,57 @@ +# ---------------------------------------------------------------------------- # +# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +# ---------------------------------------------------------------------------- # +# Set up the environment for the driver # +# ---------------------------------------------------------------------------- # + +ONE_LOCATION = ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + BIN_LOCATION = "/usr/bin" if !defined?(BIN_LOCATION) + LIB_LOCATION = "/usr/lib/one" if !defined?(LIB_LOCATION) + ETC_LOCATION = "/etc/one/" if !defined?(ETC_LOCATION) + VAR_LOCATION = "/var/lib/one" if !defined?(VAR_LOCATION) +else + BIN_LOCATION = ONE_LOCATION + "/bin" if !defined?(BIN_LOCATION) + LIB_LOCATION = ONE_LOCATION + "/lib" if !defined?(LIB_LOCATION) + ETC_LOCATION = ONE_LOCATION + "/etc/" if !defined?(ETC_LOCATION) + VAR_LOCATION = ONE_LOCATION + "/var/" if !defined?(VAR_LOCATION) +end + +ENV['LANG'] = 'C' + +$: << LIB_LOCATION + '/ruby/vendors/rbvmomi/lib' +$: << LIB_LOCATION + '/ruby' +$: << LIB_LOCATION + '/ruby/vcenter_driver' + +require 'ostruct' +require 'rbvmomi' +require 'yaml' +require 'opennebula' +require 'base64' +require 'openssl' + +# ---------------------------------------------------------------------------- # +# vCenter Library # +# ---------------------------------------------------------------------------- # + +require 'rbvmomi_datastore' +require 'vi_client' +require 'cached_datastore' +require 'cached_host' +require 'host' +require 'virtual_machine' From 79470bf1e3aa805fd267d32a253be9699b300ab7 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Thu, 12 Jan 2017 18:33:37 +0100 Subject: [PATCH 014/297] F #4913: First refactored draft version. Monitoring works without network monitoring --- .../lib/vcenter_driver/cached_datastore.rb | 16 - .../remotes/lib/vcenter_driver/cached_host.rb | 93 - .../remotes/lib/vcenter_driver/datacenter.rb | 64 + .../remotes/lib/vcenter_driver/datastore.rb | 57 + .../remotes/lib/vcenter_driver/host.rb | 269 +-- .../remotes/lib/vcenter_driver/memoize.rb | 44 + .../lib/vcenter_driver/rbvmomi_datastore.rb | 58 - .../remotes/lib/vcenter_driver/vi_client.rb | 948 +-------- .../lib/vcenter_driver/virtual_machine.rb | 1706 ++--------------- src/vmm_mad/remotes/lib/vcenter_driver2.rb | 7 +- 10 files changed, 417 insertions(+), 2845 deletions(-) delete mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb delete mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb delete mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb deleted file mode 100644 index cc69ea33f0..0000000000 --- a/src/vmm_mad/remotes/lib/vcenter_driver/cached_datastore.rb +++ /dev/null @@ -1,16 +0,0 @@ -module VCenterDriver -class VCenterCachedDatastore - - def initialize(rbVmomiDatastore) - @ds = rbVmomiDatastore - @attributes = Hash.new - end - - def name - if !@attributes['name'] - @attributes['name']=@ds.name - end - @attributes['name'] - end -end -end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb deleted file mode 100644 index 5ca095a30a..0000000000 --- a/src/vmm_mad/remotes/lib/vcenter_driver/cached_host.rb +++ /dev/null @@ -1,93 +0,0 @@ -module VCenterDriver - -################################################################################ -# Cached Classes to speed up import and monitoring -################################################################################ -class VCenterCachedHost - - def initialize(rbVmomiHost) - @host = rbVmomiHost - @attributes = Hash.new - end - - def name - if !@attributes['name'] - @attributes['name']=@host.parent.name - end - @attributes['name'] - end - - def cluster_name - if !@attributes['cluster_name'] - @attributes['cluster_name']=@host.parent.name - end - @attributes['cluster_name'] - end - - def ds_list - if !@attributes['ds_list'] - @attributes['ds_list']="" - - datacenter = @host.parent - while !datacenter.is_a? RbVmomi::VIM::Datacenter - datacenter = datacenter.parent - end - - datastores=VIClient.get_entities( - datacenter.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(datacenter.datastoreFolder, - 'StoragePod') - storage_pods.each { |sp| - datastores << sp # Add Storage Pod - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - datastores.each { |ds| - @attributes['ds_list'] += ds.name + "," - } - @attributes['ds_list']=@attributes['ds_list'][0..-2] - end - @attributes['ds_list'] - end - - def rp_list - if !@attributes['rp_list'] - @attributes['rp_list']="" - @host.parent.resourcePool.resourcePool.each{|rp| - @attributes['rp_list'] += get_child_rp_names(rp, "") - } - @attributes['rp_list']=@attributes['rp_list'][0..-2] - end - @attributes['rp_list'] - end - - def get_child_rp_names(rp, parent_prefix) - rp_str = "" - - current_rp = (parent_prefix.empty? ? "" : parent_prefix + "/") - current_rp += rp.name - - if rp.resourcePool.size != 0 - rp.resourcePool.each{|child_rp| - rp_str += get_child_rp_names(child_rp, current_rp) - } - end - - rp_str += current_rp + "," - - return rp_str - end - - def cpumhz - if !@attributes['cpumhz'] - @attributes['cpumhz']=@host.summary.hardware.cpuMhz.to_f - end - @attributes['cpumhz'] - end -end -end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb new file mode 100644 index 0000000000..a5468f2c69 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -0,0 +1,64 @@ +module VCenterDriver + +class DatacenterFolder + attr_accessor :items + + def initialize(vcenter_client) + @vcenter_client = vcenter_client + @items = {} + end + + ######################################################################## + # Builds a hash with Datacenter-Ref / Datacenter to be used as a cache + # @return [Hash] in the form + # { dc_ref [Symbol] => Datacenter object } + ######################################################################## + def fetch! + VIClient.get_entities(@vcenter_client.vim.root, "Datacenter").each do |item| + _, item_name, _ = item.to_s.split('"') + @items[item_name.to_sym] = Datacenter.new(item) + end + end + + ######################################################################## + # Returns a Datacenter. Uses the cache if available. + # @param ref [Symbol] the vcenter ref + # @return Datacenter + ######################################################################## + def get(ref) + if !@items[ref.to_sym] + rbvmomi_dc = RbVmomi::VIM::Datacenter.new(@vcenter_client.vim, ref) + @items[ref.to_sym] = Datacenter.new(rbvmomi_dc) + end + + @items[ref.to_sym] + end +end + +class Datacenter + attr_accessor :item + + def initialize(item) + if !item.instance_of? RbVmomi::VIM::Datacenter + raise "Expecting type 'RbVmomi::VIM::Datacenter'. " << + "Got '#{item.class} instead." + end + + @item = item + end + + def datastore_folder + DatastoreFolder.new(@item.datastoreFolder) + end + + def host_folder + HostFolder.new(@item.hostFolder) + end + + # This is never cached + def self.new_from_ref(vi_client, ref) + self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref)) + end +end + +end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb new file mode 100644 index 0000000000..8c5c5ceb57 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -0,0 +1,57 @@ +module VCenterDriver + +class DatastoreFolder + attr_accessor :item, :items + + def initialize(item) + @item = item + @items = {} + end + + ######################################################################## + # Builds a hash with Datastore-Ref / Datastore to be used as a cache + # @return [Hash] in the form + # { ds_ref [Symbol] => Datastore object } + ######################################################################## + def fetch! + VIClient.get_entities(@item, "Datastore").each do |item| + _, item_name, _ = item.to_s.split('"') + @items[item_name.to_sym] = Datastore.new(item) + end + end + + ######################################################################## + # Returns a Datastore. Uses the cache if available. + # @param ref [Symbol] the vcenter ref + # @return Datastore + ######################################################################## + def get(ref) + if !@items[ref.to_sym] + rbvmomi_dc = RbVmomi::VIM::Datastore.new(@vcenter_client.vim, ref) + @items[ref.to_sym] = Datastore.new(rbvmomi_dc) + end + + @items[ref.to_sym] + end +end + +class Datastore + attr_accessor :item + + def initialize(item) + if !item.instance_of? RbVmomi::VIM::Datastore + raise "Expecting type 'RbVmomi::VIM::Datastore'. " << + "Got '#{item.class} instead." + end + + @item = item + end + + # This is never cached + def self.new_from_ref(vi_client, ref) + self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref)) + end +end + +end # module VCenterDriver + diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index d55f6b1139..b585c48094 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -1,80 +1,58 @@ module VCenterDriver -################################################################################ -# This class is an OpenNebula hosts that abstracts a vCenter cluster. It -# includes the functionality needed to monitor the cluster and report the ESX -# hosts and VM status of the cluster. -################################################################################ -class VCenterHost < ::OpenNebula::Host - attr_reader :vc_client, :vc_root, :cluster, :host, :client +class HostFolder + attr_accessor :item, :clusters - ############################################################################ - # Initialize the VCenterHost by looking for the associated objects of the - # VIM hierarchy - # client [VIClient] to interact with the associated vCenter - ############################################################################ - def initialize(client) - @client = client - @cluster = client.cluster - - @resource_pools = client.resource_pool + def initialize(item) + @item = item + @clusters = {} end - ######################################################################## - # Creates an OpenNebula host representing a cluster in this VCenter - # @param cluster_name[String] the name of the cluster in the vcenter - # @param client [VIClient] to create the host - # @return In case of success [0, host_id] or [-1, error_msg] - ######################################################################## - def self.to_one(cluster_name, client) - one_host = ::OpenNebula::Host.new(::OpenNebula::Host.build_xml, - client.one) + def fetch_clusters! + VIClient.get_entities(@item, 'ClusterComputeResource').each do |item| + _, item_name, _ = item.to_s.split('"') + @clusters[item_name.to_sym] = ClusterComputeResource.new(item) + end + end - rc = one_host.allocate(cluster_name, 'vcenter', 'vcenter', - ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) - - return -1, rc.message if ::OpenNebula.is_error?(rc) - - template = "VCENTER_HOST=\"#{client.host}\"\n"\ - "VCENTER_PASSWORD=\"#{client.pass}\"\n"\ - "VCENTER_USER=\"#{client.user}\"\n" - - rc = one_host.update(template, false) - - if ::OpenNebula.is_error?(rc) - error = rc.message - - rc = one_host.delete - - if ::OpenNebula.is_error?(rc) - error << ". Host #{cluster_name} could not be"\ - " deleted: #{rc.message}." - end - - return -1, error + def get_cluster(ref) + if !@clusters[ref.to_sym] + rbvmomi_dc = RbVmomi::VIM::ClusterComputeResource.new(@vcenter_client.vim, ref) + @clusters[ref.to_sym] = ClusterComputeResource.new(rbvmomi_dc) end - return 0, one_host.id + @clusters[ref.to_sym] + end +end + +class ClusterComputeResource + attr_accessor :item + + def initialize(item) + @item = item end - ############################################################################ - # Generate an OpenNebula monitor string for this host. Reference: - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/Reference - # Guide/vim.ComputeResource.Summary.html - # - effectiveCpu: Effective CPU resources (in MHz) available to run - # VMs. This is the aggregated from all running hosts excluding hosts in - # maintenance mode or unresponsive are not counted. - # - effectiveMemory: Effective memory resources (in MB) available to run - # VMs. Equivalente to effectiveCpu. - # - numCpuCores: Number of physical CPU cores. - # - numEffectiveHosts: Total number of effective hosts. - # - numHosts:Total number of hosts. - # - totalCpu: Aggregated CPU resources of all hosts, in MHz. - # - totalMemory: Aggregated memory resources of all hosts, in bytes. - ############################################################################ - def monitor_cluster + def fetch_resource_pools(rp, rp_array = []) + rp_array << rp + + rp.resourcePool.each do |child_rp| + fetch_resource_pools(child_rp, rp_array) + end + + rp_array + end + + def resource_pools + if @resource_pools.nil? + @resource_pools = fetch_resource_pools(@item.resourcePool) + end + + @resource_pools + end + + def monitor #Load the host systems - summary = @cluster.summary + summary = @item.summary mhz_core = summary.totalCpu.to_f / summary.numCpuCores.to_f eff_core = summary.effectiveCpu.to_f / mhz_core @@ -104,15 +82,10 @@ class VCenterHost < ::OpenNebula::Host str_info << "FREEMEMORY=" << free_mem.to_s << "\n" str_info << "USEDMEMORY=" << (total_mem - free_mem).to_s - str_info << monitor_resource_pools(@cluster.resourcePool, "", mhz_core) + + str_info << monitor_resource_pools(@item.resourcePool, "", mhz_core) end - ############################################################################ - # Generate an OpenNebula monitor string for all resource pools of a cluster - # Reference: - # http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc - # /vim.ResourcePool.html - ############################################################################ def monitor_resource_pools(parent_rp, parent_prefix, mhz_core) return "" if parent_rp.resourcePool.size == 0 @@ -162,18 +135,10 @@ class VCenterHost < ::OpenNebula::Host return rp_info end - ############################################################################ - # Generate a template with information for each ESX Host. Reference: - # http://pubs.vmware.com/vi-sdk/visdk250/ReferenceGuide/vim.HostSystem.html - # - Summary: Basic information about the host, including connection state - # - hardware: Hardware configuration of the host. This might not be - # available for a disconnected host. - # - quickStats: Basic host statistics. - ############################################################################ def monitor_host_systems host_info = "" - @cluster.host.each{|h| + @item.host.each do |h| next if h.runtime.connectionState != "connected" summary = h.summary @@ -201,120 +166,82 @@ class VCenterHost < ::OpenNebula::Host host_info << "USED_MEM=" << used_memory.to_s << "," host_info << "FREE_MEM=" << free_memory.to_s host_info << "]" - } + end return host_info end def monitor_vms - # Only monitor from top level (Resource) Resource Pool - monitor_vms_in_rp(@resource_pools[-1]) - end + str_info = "" + resource_pools.each do |rp| + str_info << monitor_vms_in_rp(rp) + end + return str_info + end def monitor_vms_in_rp(rp) str_info = "" - if rp.resourcePool.size != 0 - rp.resourcePool.each{|child_rp| - str_info += monitor_vms_in_rp(child_rp) - } - end + rp.vm.each do |v| + begin + vm = VirtualMachine.new(v) - host_cache = {} + number = -1 - rp.vm.each { |v| - begin - # Check cached objects - if !host_cache[v.runtime.host.to_s] - host_cache[v.runtime.host.to_s] = - VCenterCachedHost.new v.runtime.host - end + # Check the running flag + running_flag = vm["config.extraConfig"].select do |val| + val[:key] == "opennebula.vm.running" + end - host = host_cache[v.runtime.host.to_s] + if running_flag.size > 0 and running_flag[0] + running_flag = running_flag[0][:value] + end - name = v.name - number = -1 - vm_extra_config = v.config.extraConfig + next if running_flag == "no" - # Check the running flag - running_flag = v.config.extraConfig.select{|val| - val[:key]=="opennebula.vm.running"} - if running_flag.size > 0 and running_flag[0] - running_flag = running_flag[0][:value] - end + # Extract vmid if possible + matches = vm["name"].match(/^one-(\d*)(-(.*))?$/) + number = matches[1] if matches - next if running_flag == "no" + extraconfig_vmid = vm["config.extraConfig"].select do |val| + val[:key] == "opennebula.vm.id" + end - # Extract vmid if possible - matches = name.match(/^one-(\d*)(-(.*))?$/) - number = matches[1] if matches - extraconfig_vmid = v.config.extraConfig.select{|val| - val[:key]=="opennebula.vm.id"} - if extraconfig_vmid.size > 0 and extraconfig_vmid[0] - number = extraconfig_vmid[0][:value] - end - vm = VCenterVm.new(@client, v) - vm.monitor(host) - next if !vm.vm.config - str_info << "\nVM = [" - str_info << "ID=#{number}," - str_info << "DEPLOY_ID=\"#{vm.vm.config.uuid}\"," - str_info << "VM_NAME=\"#{name} - "\ - "#{host.cluster_name}\"," - if number == -1 - vm_template_to_one = - Base64.encode64(vm.vm_to_one(host)).gsub("\n","") - str_info << "IMPORT_TEMPLATE=\"#{vm_template_to_one}\"," - end - str_info << "POLL=\"#{vm.info}\"]" - rescue Exception => e - STDERR.puts e.inspect - STDERR.puts e.backtrace - end - } - return str_info - end + if extraconfig_vmid.size > 0 and extraconfig_vmid[0] + number = extraconfig_vmid[0][:value] + end - def monitor_customizations - customizations = client.vim.serviceContent.customizationSpecManager.info + vm.monitor - text = '' + next if !vm["config"] - customizations.each do |c| - t = "CUSTOMIZATION = [ " - t << %Q - t << %Q + str_info << %Q{ + VM = [ + ID="#{number}", + VM_NAME="#{vm["name"]} - #{vm["runtime.host.parent.name"]}", + DEPLOY_ID="#{vm["config.uuid"]}", + } - text << t - end + if number == -1 + vm_template_64 = Base64.encode64(vm.to_one).gsub("\n","") - text - end + str_info << "IMPORT_TEMPLATE=\"#{vm_template_64}\"," + end - def get_available_ds - str_info = "" - - datastores = VIClient.get_entities(client.dc.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(client.dc.datastoreFolder, - 'StoragePod') - - storage_pods.each { |sp| - datastores << sp - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) + str_info << "POLL=\"#{vm.info}\"]" + rescue Exception => e + STDERR.puts e.inspect + STDERR.puts e.backtrace end - } + end - datastores.each { |ds| - str_info += "VCENTER_DATASTORE=\"#{ds.name}\"\n" - } - str_info.chomp + return str_info.gsub(/^\s+/,"") + end + + def self.new_from_ref(vi_client, ref) + self.new(RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref)) end end - -end +end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb b/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb new file mode 100644 index 0000000000..deadd8e9f6 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb @@ -0,0 +1,44 @@ +module Memoize + def [](property) + @memoize = {} if !defined?(@memoize) + + if (value = @memoize[property]) + return value + end + + current_item = @item + + property_path = "" + + property.split(".").each do |elem| + if property_path.empty? + property_path << elem + else + property_path << "." << elem + end + + if (val = @memoize[property_path]) + current_item = val + else + begin + current_item = current_item.send(elem) + rescue Exception => e + current_item = nil + end + end + + break if current_item.nil? + + @memoize[property_path] = current_item + + end + + @memoize[property] = current_item + end + + def []=(property, value) + @memoize = {} if !defined?(@memoize) + + @memoize[property] = value + end +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb deleted file mode 100644 index be1324dc44..0000000000 --- a/src/vmm_mad/remotes/lib/vcenter_driver/rbvmomi_datastore.rb +++ /dev/null @@ -1,58 +0,0 @@ - -class RbVmomi::VIM::Datastore - - # Download a file from this datastore. - # @param remote_path [String] Source path on the datastore. - # @param local_path [String] Destination path on the local machine. - # @return [void] - def download_to_stdout remote_path - url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" - - pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', - "-b", _connection.cookie, - url - - - Process.waitpid(pid, 0) - fail "download failed" unless $?.success? - end - - def is_descriptor? remote_path - url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" - - rout, wout = IO.pipe - - pid = spawn CURLBIN, "-I", "-k", '--noproxy', '*', '-f', - "-b", _connection.cookie, - url, - :out => wout, - :err => '/dev/null' - - Process.waitpid(pid, 0) - fail "read image header failed" unless $?.success? - - wout.close - size = rout.readlines.select{|l| l.start_with?("Content-Length")}[0].sub("Content-Length: ","") - rout.close - size.chomp.to_i < 4096 # If <4k, then is a descriptor - end - - def get_text_file remote_path - url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" - - rout, wout = IO.pipe - pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', - "-b", _connection.cookie, - url, - :out => wout, - :err => '/dev/null' - - Process.waitpid(pid, 0) - fail "get text file failed" unless $?.success? - - wout.close - output = rout.readlines - rout.close - return output - end -end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 745119b460..66598a44bb 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -1,940 +1,30 @@ module VCenterDriver - ################################################################################ - # This class represents a VCenter connection and an associated OpenNebula client - # The connection is associated to the VCenter backing a given OpenNebula host. - # For the VCenter driver each OpenNebula host represents a VCenter cluster - ################################################################################ - class VIClient - attr_reader :vim, :one, :root, :cluster, :user, :pass, :host, :dc - def self.get_entities(folder, type, entities=[]) - return nil if folder == [] +class VIClient + attr_accessor :vim - folder.childEntity.each do |child| - name, junk = child.to_s.split('(') + def initialize(opts) + opts = {:insecure => true}.merge(opts) + @vim = RbVmomi::VIM.connect(opts) + end - case name - when "Folder" - VIClient.get_entities(child, type, entities) - when type - entities.push(child) - end - end - - return entities + def self.get_entities(folder, type, entities=[]) + if folder == [] + return nil end - # Only retrieve properties with faster search - def get_entities_to_import(folder, type) - res = folder.inventory_flat(type => :all) - objects = [] - - res.each {|k,v| - if k.to_s.split('(').first == type - obj = {} - v.propSet.each{ |dynprop| - obj[dynprop.name] = dynprop.val - } - obj[:ref] = k._ref - objects << OpenStruct.new(obj) - end - } - return objects - end - - ############################################################################ - # Initialize the VIClient, and creates an OpenNebula client. The parameters - # are obtained from the associated OpenNebula host - # @param hid [Integer] The OpenNebula host id with VCenter attributes - ############################################################################ - def initialize(hid) - - initialize_one - - @one_host = ::OpenNebula::Host.new_with_id(hid, @one) - rc = @one_host.info - - if ::OpenNebula.is_error?(rc) - raise "Error getting host information: #{rc.message}" - end - - password = @one_host["TEMPLATE/VCENTER_PASSWORD"] - - if !@token.nil? - begin - cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") - - cipher.decrypt - cipher.key = @token - - password = cipher.update(Base64::decode64(password)) - password << cipher.final - rescue - raise "Error decrypting vCenter password" - end - end - - connection = { - :host => @one_host["TEMPLATE/VCENTER_HOST"], - :user => @one_host["TEMPLATE/VCENTER_USER"], - :password => password - } - - initialize_vim(connection) - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each {|dc| - ccrs = VIClient.get_entities(dc.hostFolder, 'ClusterComputeResource') - - next if ccrs.nil? - - @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } - - (@dc = dc; break) if @cluster - } - - if @dc.nil? || @cluster.nil? - raise "Cannot find DataCenter or ClusterComputeResource for host." + folder.childEntity.each do |child| + the_name, junk = child.to_s.split('(') + case the_name + when "Folder" + get_entities(child, type, entities) + when type + entities.push(child) end end - ######################################################################## - # Initialize a VIConnection based just on the VIM parameters. The - # OpenNebula client is also initialized - ######################################################################## - def self.new_connection(user_opts, one_client=nil) - - conn = allocate - - conn.initialize_one(one_client) - - conn.initialize_vim(user_opts) - - return conn - end - - ######################################################################## - # The associated cluster for this connection - ######################################################################## - def cluster - @cluster - end - - ######################################################################## - # Is this Cluster confined in a resource pool? - ######################################################################## - def rp_confined? - !@one_host["TEMPLATE/VCENTER_RESOURCE_POOL"].nil? - end - - ######################################################################## - # The associated resource pool for this connection - # @return [ResourcePool] an array of resource pools including the default - #  resource pool. If the connection is confined to a particular - #  resource pool, then return just that one - ######################################################################## - def resource_pool - rp_name = @one_host["TEMPLATE/VCENTER_RESOURCE_POOL"] - - if rp_name.nil? - rp_array = @cluster.resourcePool.resourcePool - rp_array << @cluster.resourcePool - rp_array - else - [find_resource_pool(rp_name)] - end - end - - ######################################################################## - # Get the default resource pool of the connection. Only valid if - # the connection is not confined in a resource pool - # @return ResourcePool the default resource pool - ######################################################################## - def default_resource_pool - @cluster.resourcePool - end - - ######################################################################## - # Searches the desired ResourcePool of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::ResourcePool or the default pool - # if not found - # @param rpool [String] the ResourcePool name - ######################################################################## - def find_resource_pool(poolName) - baseEntity = @cluster - - entityArray = poolName.split('/') - entityArray.each do |entityArrItem| - if entityArrItem != '' - if baseEntity.is_a? RbVmomi::VIM::Folder - baseEntity = baseEntity.childEntity.find { |f| - f.name == entityArrItem - } or return @cluster.resourcePool - elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource - baseEntity = baseEntity.resourcePool.resourcePool.find { |f| - f.name == entityArrItem - } or return @cluster.resourcePool - elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool - baseEntity = baseEntity.resourcePool.find { |f| - f.name == entityArrItem - } or return @cluster.resourcePool - else - return @cluster.resourcePool - end - end - end - - if !baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and - baseEntity.respond_to?(:resourcePool) - baseEntity = baseEntity.resourcePool - end - - baseEntity - end - - ######################################################################## - # Searches the associated vmFolder of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found - # - # Searches by moref, name, uuid and then iterates over all VMs - # - # @param uuid [String] the UUID of the VM or VM Template - # @param ref [String] VMware moref - # @param name [String] VM name in vCenter - ######################################################################## - def find_vm_fast(uuid, ref = nil, name = nil) - if ref - # It can raise ManagedObjectNotFound - begin - vm = RbVmomi::VIM::VirtualMachine.new(@dc._connection, ref) - return vm if vm.config && vm.config.uuid == uuid - rescue => e - end - end - - if name - begin - vm = @dc.vmFolder.find(name) - return vm if vm.config && vm.config.uuid == uuid - rescue - end - end - - return find_vm_template(uuid) - end - - ######################################################################## - # Searches the associated vmFolder of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found - # @param uuid [String] the UUID of the VM or VM Template - ######################################################################## - def find_vm_template(uuid) - version = @vim.serviceContent.about.version - - found_vm = nil - found_vm = @dc.vmFolder.findByUuid(uuid, RbVmomi::VIM::VirtualMachine, @dc) - return found_vm if found_vm - - vms = VIClient.get_entities(@dc.vmFolder, 'VirtualMachine') - - return vms.find do |v| - begin - v.config && v.config.uuid == uuid - rescue RbVmomi::VIM::ManagedObjectNotFound - false - end - end - end - - ######################################################################## - # Searches the associated vmFolder of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found - # @param vm_name [String] the UUID of the VM or VM Template - ######################################################################## - def find_vm(vm_name) - vms = VIClient.get_entities(@dc.vmFolder, 'VirtualMachine') - - return vms.find do |v| - begin - v.name == vm_name - rescue RbVmomi::VIM::ManagedObjectNotFound - false - end - end - end - - ######################################################################## - # Searches the associated datacenter for a particular datastore - # @param ds_name [String] name of the datastore - # @returns a RbVmomi::VIM::VirtualMachine or nil if not found - ######################################################################## - def get_datastore(ds_name) - datastores = VIClient.get_entities(@dc.datastoreFolder, 'Datastore') - - storage_pods = VIClient.get_entities(@dc.datastoreFolder, 'StoragePod') - storage_pods.each { |sp| - datastores << sp #Add StoragePod - - # Add individual datastores under StoragePod - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == ds_name}[0] - end - - ######################################################################## - # Builds a hash with the DataCenter / ClusterComputeResource hierarchy - # for this VCenter. - # @return [Hash] in the form - # {dc_name [String] => ClusterComputeResources Names [Array - String]} - ######################################################################## - def hierarchy(one_client=nil) - vc_hosts = {} - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - hpool = OpenNebula::HostPool.new((one_client||@one)) - rc = hpool.info - - datacenters.each { |dc| - ccrs = VIClient.get_entities(dc.hostFolder, 'ClusterComputeResource') - vc_hosts[dc.name] = [] - ccrs.each { |c| - if !hpool["HOST[NAME=\"#{c.name}\"]"] - vc_hosts[dc.name] << c.name - end - } - } - - return vc_hosts - end - - ######################################################################## - # Builds a hash with the Datacenter / VM Templates for this VCenter - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Hash] in the form - # { dc_name [String] => Templates [Array] } - ######################################################################## - def vm_templates(one_client=nil) - vm_templates = {} - - tpool = OpenNebula::TemplatePool.new( - (one_client||@one), OpenNebula::Pool::INFO_ALL) - rc = tpool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - vms = get_entities_to_import(dc.vmFolder, 'VirtualMachine') - - tmp = vms.select { |v| v.config && (v.config.template == true) } - - one_tmp = [] - host_cache = {} - ds_cache = {} - - tmp.each { |t| - vi_tmp = VCenterVm.new(self, t) - - if !tpool["VMTEMPLATE/TEMPLATE/PUBLIC_CLOUD[\ - TYPE=\"vcenter\" \ - and VM_TEMPLATE=\"#{vi_tmp.vm.config.uuid}\"]"] - # Check cached objects - if !host_cache[vi_tmp.vm.runtime.host.to_s] - host_cache[vi_tmp.vm.runtime.host.to_s] = - VCenterCachedHost.new vi_tmp.vm.runtime.host - end - - if !ds_cache[t.datastore[0].to_s] - ds_cache[t.datastore[0].to_s] = - VCenterCachedDatastore.new t.datastore[0] - end - - host = host_cache[vi_tmp.vm.runtime.host.to_s] - ds = ds_cache[t.datastore[0].to_s] - - one_tmp << { - :name => "#{vi_tmp.vm.name} - #{host.cluster_name}", - :uuid => vi_tmp.vm.config.uuid, - :host => host.cluster_name, - :one => vi_tmp.to_one(host), - :ds => vi_tmp.to_one_ds(host, ds.name), - :default_ds => ds.name, - :rp => vi_tmp.to_one_rp(host), - :vcenter_ref => vi_tmp.vm._ref, - :vcenter_name => vi_tmp.vm.name - } - end - } - - vm_templates[dc.name] = one_tmp - } - - return vm_templates - end - - ######################################################################## - # Builds a hash with the Datacenter / CCR (Distributed)Networks - # for this VCenter - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Hash] in the form - # { dc_name [String] => Networks [Array] } - ######################################################################## - def vcenter_networks(one_client=nil) - vcenter_networks = {} - - vnpool = OpenNebula::VirtualNetworkPool.new( - (one_client||@one), OpenNebula::Pool::INFO_ALL) - rc = vnpool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - networks = VIClient.get_entities(dc.networkFolder, 'Network' ) - one_nets = [] - - networks.each { |n| - # Skip those not in cluster - next if !n[:host][0] - - # Networks can be in several cluster, create one per cluster - net_names = [] - Array(n[:host]).each{ |host_system| - net_name = "#{n.name} - #{host_system.parent.name}" - if !net_names.include?(net_name) - if !vnpool["VNET[BRIDGE=\"#{n[:name]}\"]/\ - TEMPLATE[VCENTER_TYPE=\"Port Group\"]"] - one_nets << { - :name => net_name, - :bridge => n.name, - :cluster => host_system.parent.name, - :type => "Port Group", - :one => "NAME = \"#{net_name}\"\n" \ - "BRIDGE = \"#{n[:name]}\"\n" \ - "VN_MAD = \"dummy\"\n" \ - "VCENTER_TYPE = \"Port Group\"" - } - net_names << net_name - end - end - } - } - - networks = VIClient.get_entities(dc.networkFolder, - 'DistributedVirtualPortgroup' ) - - networks.each { |n| - # Skip those not in cluster - next if !n[:host][0] - - # DistributedVirtualPortgroup can be in several cluster, - # create one per cluster - Array(n[:host][0]).each{ |host_system| - net_name = "#{n.name} - #{n[:host][0].parent.name}" - - if !vnpool["VNET[BRIDGE=\"#{n[:name]}\"]/\ - TEMPLATE[VCENTER_TYPE=\"Distributed Port Group\"]"] - vnet_template = "NAME = \"#{net_name}\"\n" \ - "BRIDGE = \"#{n[:name]}\"\n" \ - "VN_MAD = \"dummy\"\n" \ - "VCENTER_TYPE = \"Distributed Port Group\"" - - default_pc = n.config.defaultPortConfig - - has_vlan = false - vlan_str = "" - - if default_pc.methods.include? :vlan - has_vlan = default_pc.vlan.methods.include? :vlanId - end - - if has_vlan - vlan = n.config.defaultPortConfig.vlan.vlanId - - if vlan != 0 - if vlan.is_a? Array - vlan.each{|v| - vlan_str += v.start.to_s + ".." + - v.end.to_s + "," - } - vlan_str.chop! - else - vlan_str = vlan.to_s - end - end - end - - if !vlan_str.empty? - vnet_template << "VLAN_TAGGED_ID=#{vlan_str}\n" - end - - one_net = {:name => net_name, - :bridge => n.name, - :cluster => host_system.parent.name, - :type => "Distributed Port Group", - :one => vnet_template} - - one_net[:vlan] = vlan_str if !vlan_str.empty? - - one_nets << one_net - end - } - } - - vcenter_networks[dc.name] = one_nets - } - - return vcenter_networks - end - - - ######################################################################## - # Builds a hash with the Datacenter / Datastores for this VCenter - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Hash] in the form - # { dc_name [String] => Datastore [Array] of DS templates} - ######################################################################## - def vcenter_datastores(one_client=nil) - ds_templates = {} - - dspool = OpenNebula::DatastorePool.new( - (one_client||@one)) - rc = dspool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - hpool = OpenNebula::HostPool.new( - (one_client||@one)) - rc = hpool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - one_tmp = [] - datastores = VIClient.get_entities(dc.datastoreFolder, 'Datastore') - - storage_pods = VIClient.get_entities(dc.datastoreFolder, 'StoragePod') - storage_pods.each { |sp| - datastores << sp # Add StoragePod - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - datastores.each { |ds| - next if !ds.is_a? RbVmomi::VIM::Datastore and !ds.is_a? RbVmomi::VIM::StoragePod - # Find the Cluster from which to access this ds - - cluster_name = "" - if ds.is_a? RbVmomi::VIM::StoragePod - storage_pod_datastores = VIClient.get_entities(ds, 'Datastore') - storage_pod_datastores.each { |sp| - next if !sp.is_a? RbVmomi::VIM::Datastore - # Find the Cluster from which to access this ds - next if !sp.host[0] - cluster_name = sp.host[0].key.parent.name - break - } - else - next if !ds.host[0] - cluster_name = ds.host[0].key.parent.name - end - - if !dspool["DATASTORE[NAME=\"#{ds.name}\"]"] and - hpool["HOST[NAME=\"#{cluster_name}\"]"] - if ds.is_a? RbVmomi::VIM::StoragePod - one_tmp << { - :name => "#{ds.name}", - :total_mb => ((ds.summary.capacity.to_i / 1024) / 1024), - :free_mb => ((ds.summary.freeSpace.to_i / 1024) / 1024), - :cluster => cluster_name, - :one => "NAME=#{ds.name}\n"\ - "TM_MAD=vcenter\n"\ - "VCENTER_CLUSTER=#{cluster_name}\n"\ - "TYPE=SYSTEM_DS\n" # StoragePods must be set as SYSTEM_DS - } - else - one_tmp << { - :name => "#{ds.name}", - :total_mb => ((ds.summary.capacity.to_i / 1024) / 1024), - :free_mb => ((ds.summary.freeSpace.to_i / 1024) / 1024), - :cluster => cluster_name, - :one => "NAME=#{ds.name}\n"\ - "DS_MAD=vcenter\n"\ - "TM_MAD=vcenter\n"\ - "VCENTER_CLUSTER=#{cluster_name}\n" - } - end - end - } - ds_templates[dc.name] = one_tmp - } - - return ds_templates - end - - ############################################################################# - # Builds a hash with the Images for a particular datastore - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Array] of image templates - ############################################################################ - def vcenter_images(ds_name, one_client=nil) - img_types = ["FloppyImageFileInfo", - "IsoImageFileInfo", - "VmDiskFileInfo"] - - img_templates = [] - - ipool = OpenNebula::ImagePool.new((one_client||@one)) - rc = ipool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - dspool = OpenNebula::DatastorePool.new((one_client||@one)) - rc = dspool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - ds_id = dspool["DATASTORE[NAME=\"#{ds_name}\"]/ID"] - - if !ds_id - raise "Datastore not found in OpenNebula. Please import"\ - " it first and try again" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - - # Find datastore within datacenter - datastores = VIClient.get_entities(dc.datastoreFolder, 'Datastore') - - storage_pods = VIClient.get_entities(dc.datastoreFolder, 'StoragePod') - storage_pods.each { |sp| - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == ds_name}[0] - next if !ds - - # Cannot import from StoragePod directly - if ds.is_a? RbVmomi::VIM::StoragePod - raise "OpenNebula cannot import images from a StoragePod. Please import"\ - " it from the datastore which is a member of the StorageDRS cluster" - end - - # Create Search Spec - spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new - spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, - RbVmomi::VIM::IsoImageFileQuery.new] - spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, - :fileSize => true, - :fileType => true, - :modification => true) - spec.matchPattern=[] - - search_params = {'datastorePath' => "[#{ds.name}]", - 'searchSpec' => spec} - - # Perform search task and return results - search_task=ds.browser.SearchDatastoreSubFolders_Task(search_params) - search_task.wait_for_completion - - search_task.info.result.each { |image| - folderpath = "" - if image.folderPath[-1] != "]" - folderpath = image.folderPath.sub(/^\[#{ds_name}\] /, "") - end - - image = image.file[0] - - # Skip not relevant files - next if !img_types.include? image.class.to_s - - image_path = folderpath + image.path - - image_name = File.basename(image.path).reverse.sub("kdmv.","").reverse - - if !ipool["IMAGE[NAME=\"#{image_name} - #{ds_name}\"]"] - img_templates << { - :name => "#{image_name} - #{ds_name}", - :path => image_path, - :size => (image.fileSize / 1024).to_s, - :type => image.class.to_s, - :dsid => ds_id, - :one => "NAME=\"#{image_name} - #{ds_name}\"\n"\ - "PATH=\"vcenter://#{image_path}\"\n"\ - "PERSISTENT=\"YES\"\n"\ - } - - if image.class.to_s == "VmDiskFileInfo" - img_templates[-1][:one] += "TYPE=\"OS\"\n" - else - img_templates[-1][:one] += "TYPE=\"CDROM\"\n" - end - - if image.class.to_s == "VmDiskFileInfo" && - !image.diskType.nil? - img_templates[-1][:one] += "DISK_TYPE=#{image.diskType}\n" - end - end - } - } - - return img_templates - end - - def self.translate_hostname(hostname) - host_pool = OpenNebula::HostPool.new(::OpenNebula::Client.new()) - rc = host_pool.info - raise "Could not find host #{hostname}" if OpenNebula.is_error?(rc) - - host = host_pool.select {|host_element| host_element.name==hostname } - return host.first.id - end - - def self.find_ds_name(ds_id) - ds = OpenNebula::Datastore.new_with_id(ds_id, OpenNebula::Client.new) - rc = ds.info - raise "Could not find datastore #{ds_id}" if OpenNebula.is_error?(rc) - - return ds["/DATASTORE/TEMPLATE/VCENTER_NAME"] - end - - ############################################################################ - # Initialize an OpenNebula connection with the default ONE_AUTH - ############################################################################ - def initialize_one(one_client=nil) - begin - if one_client - @one = one_client - else - @one = ::OpenNebula::Client.new() - end - - system = ::OpenNebula::System.new(@one) - - config = system.get_configuration() - - if ::OpenNebula.is_error?(config) - raise "Error getting oned configuration : #{config.message}" - end - - @token = config["ONE_KEY"] - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message}" - end - end - - ############################################################################ - # Initialize a connection with vCenter. Options - # @param options[Hash] with: - # :user => The vcenter user - # :password => Password for the user - # :host => vCenter hostname or IP - # :insecure => SSL (optional, defaults to true) - ############################################################################ - def initialize_vim(user_opts={}) - opts = { - :insecure => true - }.merge(user_opts) - - @user = opts[:user] - @pass = opts[:password] - @host = opts[:host] - - begin - @vim = RbVmomi::VIM.connect(opts) - @root = @vim.root - @vdm = @vim.serviceContent.virtualDiskManager - @file_manager = @vim.serviceContent.fileManager - rescue Exception => e - raise "Error connecting to #{@host}: #{e.message}" - end - end - - ######################### Datastore Operations ############################# - - ############################################################################ - # Retrieve size for a VirtualDisk in a particular datastore - # @param ds_name [String] name of the datastore - # @param img_str [String] path to the VirtualDisk - # @return size of the file in Kb - ############################################################################ - def stat(ds_name, img_str) - img_path = File.dirname img_str - img_name = File.basename img_str - - # Find datastore within datacenter - ds = get_datastore(ds_name) - - # Create Search Spec - spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new - spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, - RbVmomi::VIM::IsoImageFileQuery.new] - spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, - :fileSize => true, - :fileType => true, - :modification => true) - spec.matchPattern=[img_name] - - search_params = {'datastorePath' => "[#{ds_name}] #{img_path}", - 'searchSpec' => spec} - - # Perform search task and return results - search_task=ds.browser.SearchDatastoreSubFolders_Task(search_params) - search_task.wait_for_completion - (search_task.info.result[0].file[0].fileSize / 1024) / 1024 - end - - ############################################################################ - # Returns Datastore information - # @param ds_name [String] name of the datastore - # @return [String] monitor information of the DS - ############################################################################ - def monitor_ds(ds_name) - # Find datastore within datacenter - ds = get_datastore(ds_name) - - total_mb = (ds.summary.capacity.to_i / 1024) / 1024 - free_mb = (ds.summary.freeSpace.to_i / 1024) / 1024 - used_mb = total_mb - free_mb - - if ds.is_a? RbVmomi::VIM::Datastore - ds_type = ds.summary.type - end - - "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" - end - - ############################################################################ - # Copy a VirtualDisk - # @param ds_name [String] name of the datastore - # @param img_str [String] path to the VirtualDisk - ############################################################################ - def copy_virtual_disk(source_path, source_ds, target_path, target_ds=nil) - target_ds = source_ds if target_ds.nil? - - copy_params= {:sourceName => "[#{source_ds}] #{source_path}", - :sourceDatacenter => @dc, - :destName => "[#{target_ds}] #{target_path}"} - - @vdm.CopyVirtualDisk_Task(copy_params).wait_for_completion - - target_path - end - - ############################################################################ - # Create a VirtualDisk - # @param img_name [String] name of the image - # @param ds_name [String] name of the datastore on which the VD will be - # created - # @param size [String] size of the new image in MB - # @param adapter_type [String] as described in - #  http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc/vim.VirtualDiskManager.VirtualDiskAdapterType.html - # @param disk_type [String] as described in - #  http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.VirtualDiskManager.VirtualDiskType.html - # @return name of the final image - ############################################################################ - def create_virtual_disk(img_name, ds_name, size, adapter_type, disk_type) - vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( - :adapterType => adapter_type, - :capacityKb => size.to_i*1024, - :diskType => disk_type - ) - - @vdm.CreateVirtualDisk_Task( - :datacenter => @dc, - :name => "[#{ds_name}] #{img_name}.vmdk", - :spec => vmdk_spec - ).wait_for_completion - - "#{img_name}.vmdk" - end - - ############################################################################ - # Delete a VirtualDisk - # @param img_name [String] name of the image - # @param ds_name [String] name of the datastore where the VD resides - ############################################################################ - def delete_virtual_disk(img_name, ds_name) - @vdm.DeleteVirtualDisk_Task( - name: "[#{ds_name}] #{img_name}", - datacenter: @dc - ).wait_for_completion - end - - ############################################################################ - # Delete a VirtualDisk - # @param directory [String] name of the new directory - # @param ds_name [String] name of the datastore where to create the dir - ############################################################################ - def create_directory(directory, ds_name) - begin - path = "[#{ds_name}] #{directory}" - @file_manager.MakeDirectory(:name => path, - :datacenter => @dc, - :createParentDirectories => true) - rescue RbVmomi::VIM::FileAlreadyExists => e - end - end - - ############################################################################ - # Silences standard output and error - ############################################################################ - def self.in_silence - begin - orig_stderr = $stderr.clone - orig_stdout = $stdout.clone - $stderr.reopen File.new('/dev/null', 'w') - $stdout.reopen File.new('/dev/null', 'w') - retval = yield - rescue Exception => e - $stdout.reopen orig_stdout - $stderr.reopen orig_stderr - raise e - ensure - $stdout.reopen orig_stdout - $stderr.reopen orig_stderr - end - retval - end - - ############################################################################ - # Silences standard output and error - ############################################################################ - def self.in_stderr_silence - begin - orig_stderr = $stderr.clone - $stderr.reopen File.new('/dev/null', 'w') - retval = yield - rescue Exception => e - $stderr.reopen orig_stderr - raise e - ensure - $stderr.reopen orig_stderr - end - retval - end + return entities end end + +end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 292368bab9..395cb55e98 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1,512 +1,108 @@ module VCenterDriver -class VCenterVm - attr_reader :vm +class VirtualMachine POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE - ############################################################################ - # Creates a new VIVm using a RbVmomi::VirtualMachine object - # @param client [VCenterClient] client to connect to vCenter - # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil - ######################################################################## - def initialize(client, vm_vi ) - @vm = vm_vi - @client = client + include Memoize - @used_cpu = 0 - @used_memory = 0 - - @netrx = 0 - @nettx = 0 - - @diskrdbytes = 0 - @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 + def initialize(item) + @item = item end - ############################################################################ - # Deploys a VM - # @xml_text XML representation of the VM - ############################################################################ - def self.deploy(xml_text, lcm_state, deploy_id, hostname, datastore = nil, - ops = {}) - if lcm_state == "BOOT" || lcm_state == "BOOT_FAILURE" - return clone_vm(xml_text, hostname, datastore, ops) + # @param vm CachedItem (of RbVmomi::VIM::VirtualMachine) + def to_one + cluster = self["runtime.host.parent.name"] + + str = %Q{ + NAME = "#{self["name"]} - #{cluster}" + CPU = "#{self["config.hardware.numCPU"]}" + vCPU = "#{self["config.hardware.numCPU"]}" + MEMORY = "#{self["config.hardware.memoryMB"]}" + + HYPERVISOR = "vcenter" + + PUBLIC_CLOUD = [ + TYPE ="vcenter", + VM_TEMPLATE ="#{self["config.uuid"]}", + VCENTER_REF ="#{self["_ref"]}", + VCENTER_NAME="#{self["name"]}", + HOST ="#{cluster}" + ] + + GRAPHICS = [ + TYPE ="vnc", + LISTEN ="0.0.0.0" + ] + + SCHED_REQUIREMENTS="NAME=\\\"#{cluster}\\\"" + + CONTEXT = [ + NETWORK = "YES", + SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]" + ] + } + + if self["config.annotation"].nil? || self["config.annotation"].empty? + str << "DESCRIPTION = \"vCenter Template imported by OpenNebula" \ + " from Cluster #{cluster}\"\n" else - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_fast(deploy_id, - ops[:ref], - ops[:name]) - xml = REXML::Document.new xml_text - - reconfigure_vm(vm, xml, false, hostname) - - vm.PowerOnVM_Task.wait_for_completion - - return vm.config.uuid - end - end - - ############################################################################ - # Cancels a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param lcm_state state of the VM - # @param keep_disks keep or not VM disks in datastore - # @param disks VM attached disks - ############################################################################ - def self.cancel(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) - - case lcm_state - when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" - shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) - when "CANCEL", "LCM_INIT", "CLEANUP_RESUBMIT", "SHUTDOWN", "CLEANUP_DELETE" - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - begin - if vm.summary.runtime.powerState == "poweredOn" - vm.PowerOffVM_Task.wait_for_completion - end - rescue - end - - if keep_disks - detach_all_disks(vm) - else - detach_attached_disks(vm, disks, hostname) if disks - end - - # If the VM was instantiated to persistent, convert the VM to - # vCenter VM Template and update the OpenNebula new - # VM Template to point to the new vCenter VM Template - if !to_template.nil? - vm.MarkAsTemplate - - new_template = OpenNebula::Template.new_with_id(to_template, - OpenNebula::Client.new) - new_template.info - - public_cloud_str = "PUBLIC_CLOUD=[" - - new_template.to_hash["VMTEMPLATE"]["TEMPLATE"]["PUBLIC_CLOUD"].each{|k,v| - if k == "VM_TEMPLATE" - public_cloud_str += "VM_TEMPLATE=\"#{deploy_id}\",\n" - else - public_cloud_str += "#{k}=\"#{v}\",\n" - end - } - - public_cloud_str = public_cloud_str + "]" - - new_template.update(public_cloud_str, true) - else - vm.Destroy_Task.wait_for_completion - end - else - raise "LCM_STATE #{lcm_state} not supported for cancel" - end - end - - - ############################################################################ - # Saves a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.save(deploy_id, hostname, lcm_state) - case lcm_state - when "SAVE_MIGRATE" - raise "Migration between vCenters cluster not supported" - when "SAVE_SUSPEND", "SAVE_STOP" - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) - - vm.SuspendVM_Task.wait_for_completion - end - end - - ############################################################################ - # Resumes a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.resume(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) - - vm.PowerOnVM_Task.wait_for_completion - end - - ############################################################################ - # Reboots a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.reboot(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.RebootGuest.wait_for_completion - end - - ############################################################################ - # Resets a VM - # @param deploy_id vcetranslate_hostnamnter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.reset(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.ResetVM_Task.wait_for_completion - end - - ############################################################################ - # Shutdown a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param lcm_state state of the VM - # @param keep_disks keep or not VM disks in datastore - # @param disks VM attached disks - # @param to_template whether this VM has been instantiated as persistent - ############################################################################ - def self.shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - case lcm_state - when "SHUTDOWN" - begin - vm.ShutdownGuest - counter = 60*10 # 10 minutes - while counter > 0 - break if vm.runtime.powerState == "poweredOff" - counter -= 1 - sleep 1 - end - rescue - end - - if vm.runtime.powerState != "poweredOff" - vm.PowerOffVM_Task.wait_for_completion - end - - if keep_disks - detach_all_disks(vm) - else - detach_attached_disks(vm, disks, hostname) if disks - end - - # If the VM was instantiated to persistent, convert the VM to - # vCenter VM Template and update the OpenNebula new - # VM Template to point to the new vCenter VM Template - if !to_template.nil? - vm.MarkAsTemplate - - new_template = OpenNebula::Template.new_with_id(to_template, - OpenNebula::Client.new) - new_template.info - - public_cloud_str = "PUBLIC_CLOUD=[" - - new_template.to_hash["VMTEMPLATE"]["TEMPLATE"]["PUBLIC_CLOUD"].each{|k,v| - if k == "VM_TEMPLATE" - public_cloud_str += "VM_TEMPLATE=\"#{deploy_id}\"\n" - else - public_cloud_str += "#{k}=\"#{v}\",\n" - end - } - - public_cloud_str = public_cloud_str + "]" - - new_template.update(public_cloud_str, true) - else - vm.Destroy_Task.wait_for_completion - end - - when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" - begin - vm.ShutdownGuest - counter = 60*10 # 10 minutes - while counter > 0 - break if vm.runtime.powerState == "poweredOff" - counter -= 1 - sleep 1 - end - rescue - end - - if vm.runtime.powerState != "poweredOff" - vm.PowerOffVM_Task.wait_for_completion - end - end - end - - ############################################################################ - # Create VM snapshot - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param snaphot_name name of the snapshot - ############################################################################ - def self.create_snapshot(deploy_id, hostname, snapshot_name) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - snapshot_hash = { - :name => snapshot_name, - :description => "OpenNebula Snapshot of VM #{deploy_id}", - :memory => true, - :quiesce => true - } - - vm = connection.find_vm_template(deploy_id) - - vm.CreateSnapshot_Task(snapshot_hash).wait_for_completion - - return snapshot_name - end - - ############################################################################ - # Find VM snapshot - # @param list root list of VM snapshots - # @param snaphot_name name of the snapshot - ############################################################################ - def self.find_snapshot(list, snapshot_name) - list.each do |i| - if i.name == snapshot_name - return i.snapshot - elsif !i.childSnapshotList.empty? - snap = find_snapshot(i.childSnapshotList, snapshot_name) - return snap if snap - end + notes = self["config.annotation"].gsub("\\", "\\\\").gsub("\"", "\\\"") + str << "DESCRIPTION = \"#{notes}\"\n" end - nil - end - - ############################################################################ - # Delete VM snapshot - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param snaphot_name name of the snapshot - ############################################################################ - def self.delete_snapshot(deploy_id, hostname, snapshot_name) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - list = vm.snapshot.rootSnapshotList - - snapshot = find_snapshot(list, snapshot_name) - return nil if !snapshot - - delete_snapshot_hash = { - :_this => snapshot, - :removeChildren => false - } - - snapshot.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion - end - - ############################################################################ - # Revert VM snapshot - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param snaphot_name name of the snapshot - ############################################################################ - def self.revert_snapshot(deploy_id, hostname, snapshot_name) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - list = vm.snapshot.rootSnapshotList - - snapshot = find_snapshot(list, snapshot_name) - return nil if !snapshot - - revert_snapshot_hash = { - :_this => snapshot - } - - snapshot.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion - end - - ############################################################################ - # Attach NIC to a VM - # @param deploy_id vcenter identifier of the VM - # @param mac MAC address of the NIC to be attached - # @param bridge name of the Network in vCenter - # @param model model of the NIC to be attached - # @param host hostname of the ESX where the VM is running - ############################################################################ - def self.attach_nic(deploy_id, mac, bridge, model, host) - hid = VIClient::translate_hostname(host) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - spec_nics = calculate_addnic_spec(vm, mac, bridge, model) - - spec_hash = {:deviceChange => [spec_nics]} - - - #B4897 track hot plugged nics - hotplugged_nics = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.hotplugged_nics" + case self["guest.guestFullName"] + when /CentOS/i + str << "LOGO=images/logos/centos.png" + when /Debian/i + str << "LOGO=images/logos/debian.png" + when /Red Hat/i + str << "LOGO=images/logos/redhat.png" + when /Ubuntu/i + str << "LOGO=images/logos/ubuntu.png" + when /Windows XP/i + str << "LOGO=images/logos/windowsxp.png" + when /Windows/i + str << "LOGO=images/logos/windows8.png" + when /Linux/i + str << "LOGO=images/logos/linux.png" end - if hotplugged_nics && !hotplugged_nics.empty? - hotplugged_nics = hotplugged_nics[0][:value].to_s - hotplugged_nics << mac.to_s << ";" if !hotplugged_nics.include?(mac) - else - hotplugged_nics = "" - hotplugged_nics << mac.to_s << ";" - end - - config_array = [{:key=>"opennebula.hotplugged_nics", - :value=>hotplugged_nics}] - extra_config_spec = {:extraConfig =>config_array} - - spec_hash.merge!(extra_config_spec) - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - + return str end - ############################################################################ - # Detach NIC from a VM - ############################################################################ - def self.detach_nic(deploy_id, mac, host) - hid = VIClient::translate_hostname(host) - connection = VIClient.new(hid) + def monitor + reset_monitor - vm = connection.find_vm_template(deploy_id) - - nic = vm.config.hardware.device.find { |d| - is_nic?(d) && (d.macAddress == mac) - } - - raise "Could not find NIC with mac address #{mac}" if nic.nil? - - #B4897 track hot plugged nics - hotplugged_nics = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.hotplugged_nics" - end - - config_array = [] - if hotplugged_nics && !hotplugged_nics.empty? - hotplugged_nics = hotplugged_nics[0][:value].to_s - hotplugged_nics.slice!(mac + ";") # remove hotplugged nic - config_array = [{:key=>"opennebula.hotplugged_nics", - :value=>hotplugged_nics}] - end - - spec = { - :deviceChange => [ - :operation => :remove, - :device => nic - ], - :extraConfig => config_array - } - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - ############################################################################ - # Reconfigures a VM (context data) - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param xml_text XML repsentation of the VM - ############################################################################ - def self.reconfigure(deploy_id, hostname, xml_text) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) - - xml = REXML::Document.new xml_text - context = xml.root.elements["//TEMPLATE/CONTEXT"] - - if context - context_text = create_context(context) - context_spec = { - :extraConfig => [ - { :key=>"guestinfo.opennebula.context", - :value=> Base64.encode64(context_text) } - ] - } - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(context_spec) - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - end - - ######################################################################## - # Initialize the vm monitor information - ######################################################################## - def monitor(host) - @summary = @vm.summary - @state = state_to_c(@summary.runtime.powerState) + @state = state_to_c(self["summary.runtime.powerState"]) if @state != VM_STATE[:active] - @used_cpu = 0 - @used_memory = 0 - - @netrx = 0 - @nettx = 0 - - @diskrdbytes = 0 - @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 + reset_monitor return end - @used_memory = @summary.quickStats.hostMemoryUsage * 1024 - cpuMhz = @vm.runtime.host.summary.hardware.cpuMhz.to_f + cpuMhz = self["runtime.host.summary.hardware.cpuMhz"].to_f - @used_cpu = - ((@summary.quickStats.overallCpuUsage.to_f / cpuMhz) * 100).to_s - @used_cpu = sprintf('%.2f',@used_cpu).to_s + @monitor[:used_memory] = self["summary.quickStats.hostMemoryUsage"] * 1024 + + used_cpu = self["summary.quickStats.overallCpuUsage"].to_f / cpuMhz + used_cpu = (used_cpu * 100).to_s + @monitor[:used_cpu] = sprintf('%.2f', used_cpu).to_s # Check for negative values - @used_memory = 0 if @used_memory.to_i < 0 - @used_cpu = 0 if @used_cpu.to_i < 0 - - @esx_host = @vm.summary.runtime.host.name - @guest_ip = @vm.guest.ipAddress - @guest_state = @vm.guest.guestState - @vmware_tools = @vm.guest.toolsRunningStatus - @vmtools_ver = @vm.guest.toolsVersion - @vmtools_verst = @vm.guest.toolsVersionStatus + @monitor[:used_memory] = 0 if @monitor[:used_memory].to_i < 0 + @monitor[:used_cpu] = 0 if @monitor[:used_cpu].to_i < 0 guest_ip_addresses = [] - - @vm.guest.net.each do |net| + self["guest.net"].each do |net| net.ipConfig.ipAddress.each do |ip| guest_ip_addresses << ip.ipAddress end if net.ipConfig && net.ipConfig.ipAddress - end if @vm.guest.net + end if self["guest.net"] @guest_ip_addresses = guest_ip_addresses.join(',') +=begin # PerfManager metrics pm = @client.vim.serviceInstance.content.perfManager @@ -618,199 +214,77 @@ class VCenterVm @diskwriops = write_iops @diskrdbytes = (read_kbpersec * 1024 * refresh_rate).to_i @diskwrbytes = (write_kbpersec * 1024 * refresh_rate).to_i - end end +=end + end ######################################################################## # Generates a OpenNebula IM Driver valid string with the monitor info ######################################################################## def info - return 'STATE=d' if @state == 'd' + return 'STATE=d' if @state == 'd' - str_info = "" + guest_ip = self["guest.ipAddress"] - str_info << "GUEST_IP=" << @guest_ip.to_s << " " if @guest_ip - if @guest_ip_addresses && !@guest_ip_addresses.empty? - str_info << "GUEST_IP_ADDRESSES=\\\"" << - @guest_ip_addresses.to_s << "\\\" " - end - str_info << "LAST_MON=" << Time.now.to_i.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:state]}=" << @state << " " - str_info << "#{POLL_ATTRIBUTE[:cpu]}=" << @used_cpu.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:memory]}=" << @used_memory.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:netrx]}=" << @netrx.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:nettx]}=" << @nettx.to_s << " " - str_info << "DISKRDBYTES=" << @diskrdbytes.to_s << " " - str_info << "DISKWRBYTES=" << @diskwrbytes.to_s << " " - str_info << "DISKRDIOPS=" << @diskrdiops.to_s << " " - str_info << "DISKWRIOPS=" << @diskwriops.to_s << " " - str_info << "ESX_HOST=\\\"" << @esx_host.to_s << "\\\" " - str_info << "GUEST_STATE=" << @guest_state.to_s << " " - str_info << "VMWARETOOLS_RUNNING_STATUS=" << @vmware_tools.to_s << " " - str_info << "VMWARETOOLS_VERSION=" << @vmtools_ver.to_s << " " - str_info << "VMWARETOOLS_VERSION_STATUS=" << @vmtools_verst.to_s << " " - str_info << "RESOURCE_POOL=\\\"" << @vm.resourcePool.name << "\\\" " + used_cpu = @monitor[:used_cpu] + used_memory = @monitor[:used_memory] + netrx = @monitor[:netrx] + nettx = @monitor[:nettx] + diskrdbytes = @monitor[:diskrdbytes] + diskwrbytes = @monitor[:diskwrbytes] + diskrdiops = @monitor[:diskrdiops] + diskwriops = @monitor[:diskwriops] + + esx_host = self["runtime.host.name"].to_s + guest_state = self["guest.guestState"].to_s + vmware_tools = self["guest.toolsRunningStatus"].to_s + vmtools_ver = self["guest.toolsVersion"].to_s + vmtools_verst = self["guest.toolsVersionStatus"].to_s + + str_info = "" + + str_info = "GUEST_IP=" << guest_ip.to_s << " " if guest_ip + + if @guest_ip_addresses && !@guest_ip_addresses.empty? + str_info << "GUEST_IP_ADDRESSES=\\\"" << @guest_ip_addresses.to_s << "\\\" " + end + + str_info << "LAST_MON=" << Time.now.to_i.to_s << " " + + str_info << "#{POLL_ATTRIBUTE[:state]}=" << @state << " " + str_info << "#{POLL_ATTRIBUTE[:cpu]}=" << used_cpu.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:memory]}=" << used_memory.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:netrx]}=" << netrx.to_s << " " + str_info << "#{POLL_ATTRIBUTE[:nettx]}=" << nettx.to_s << " " + + str_info << "DISKRDBYTES=" << diskrdbytes.to_s << " " + str_info << "DISKWRBYTES=" << diskwrbytes.to_s << " " + str_info << "DISKRDIOPS=" << diskrdiops.to_s << " " + str_info << "DISKWRIOPS=" << diskwriops.to_s << " " + + str_info << "ESX_HOST=\\\"" << esx_host << "\\\" " + str_info << "GUEST_STATE=" << guest_state << " " + str_info << "VMWARETOOLS_RUNNING_STATUS=" << vmware_tools << " " + str_info << "VMWARETOOLS_VERSION=" << vmtools_ver << " " + str_info << "VMWARETOOLS_VERSION_STATUS=" << vmtools_verst << " " + str_info << "RESOURCE_POOL=\\\"" << self["resourcePool.name"] << "\\\" " end - ######################################################################## - # Generates an OpenNebula Template for this VCenterVm - ######################################################################## - def to_one(host) - cluster_name = host.cluster_name - - str = "NAME = \"#{@vm.name} - #{cluster_name}\"\n"\ - "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ - "HYPERVISOR = \"vcenter\"\n"\ - "PUBLIC_CLOUD = [\n"\ - " TYPE =\"vcenter\",\n"\ - " VM_TEMPLATE =\"#{@vm.config.uuid}\",\n"\ - " VCENTER_REF =\"#{@vm.ref}\",\n"\ - " VCENTER_NAME=\"#{@vm.name}\",\n"\ - " HOST =\"#{cluster_name}\"\n"\ - "]\n"\ - "GRAPHICS = [\n"\ - " TYPE =\"vnc\",\n"\ - " LISTEN =\"0.0.0.0\"\n"\ - "]\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{cluster_name}\\\"\"\n"\ - "CONTEXT = ["\ - " NETWORK = \"YES\","\ - " SSH_PUBLIC_KEY = \"$USER[SSH_PUBLIC_KEY]\" ]" - - if @vm.config.annotation.nil? || @vm.config.annotation.empty? - str << "DESCRIPTION = \"vCenter Template imported by OpenNebula"\ - " from Cluster #{@vm.runtime.host.parent.name}\"\n" - else - notes = @vm.config.annotation.gsub("\\", "\\\\").gsub("\"", "\\\"") - str << "DESCRIPTION = \"#{notes}\"\n" - end - - case @vm.guest.guestFullName - when /CentOS/i - str << "LOGO=images/logos/centos.png" - when /Debian/i - str << "LOGO=images/logos/debian.png" - when /Red Hat/i - str << "LOGO=images/logos/redhat.png" - when /Ubuntu/i - str << "LOGO=images/logos/ubuntu.png" - when /Windows XP/i - str << "LOGO=images/logos/windowsxp.png" - when /Windows/i - str << "LOGO=images/logos/windows8.png" - when /Linux/i - str << "LOGO=images/logos/linux.png" - end - return str + def reset_monitor + @monitor = { + :used_cpu => 0, + :used_memory => 0, + :netrx => 0, + :nettx => 0, + :diskrdbytes => 0, + :diskwrbytes => 0, + :diskrdiops => 0, + :diskwriops => 0 + } end - ######################################################################## - # Generates a Datastore user input - ######################################################################## - def to_one_ds(host, default_ds) - # Datastores User Input - str = "" - - if host.ds_list != "" - str = "M|list|Which datastore you want this VM to run on?|"\ - << "#{host.ds_list}|#{default_ds}" - end - - return str - end - - ######################################################################## - # Generates a Resource Pool user input - ######################################################################## - def to_one_rp(host) - # Resource Pool User Input - str = "" - - if host.rp_list != "" - str = "M|list|Which resource pool you want this VM to run"\ - " in?|#{host.rp_list}|#{host.rp_list.split(",")[0]}" - end - - return str - end - - ######################################################################## - # Generates an OpenNebula VirtualMachine for this VCenterVm - # - # - ######################################################################## - def vm_to_one(host) - cluster_name = host.cluster_name - - state = case state_to_c(@summary.runtime.powerState) - when 'a' - "RUNNING" - when 'd' - "POWEROFF" - end - - str = "NAME = \"#{@vm.name} - #{cluster_name}\"\n"\ - "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ - "HYPERVISOR = \"vcenter\"\n"\ - "PUBLIC_CLOUD = [\n"\ - " TYPE =\"vcenter\",\n"\ - " VM_TEMPLATE =\"#{@vm.config.uuid}\",\n"\ - " HOST =\"#{cluster_name}\"\n"\ - "]\n"\ - "IMPORT_VM_ID = \"#{@vm.config.uuid}\"\n"\ - "IMPORT_STATE = \"#{state}\"\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{cluster_name}\\\"\"\n" - - vp = @vm.config.extraConfig.select{|v| - v[:key].downcase=="remotedisplay.vnc.port"} - keymap = @vm.config.extraConfig.select{|v| - v[:key].downcase=="remotedisplay.vnc.keymap"} - - if vp.size > 0 - str << "GRAPHICS = [\n"\ - " TYPE =\"vnc\",\n"\ - " LISTEN =\"0.0.0.0\",\n"\ - " PORT =\"#{vp[0][:value]}\"\n" - str << " ,KEYMAP =\"#{keymap[0][:value]}\"\n" if keymap[0] - str << "]\n" - end - - if @vm.config.annotation.nil? || @vm.config.annotation.empty? - str << "DESCRIPTION = \"vCenter Virtual Machine imported by"\ - " OpenNebula from Cluster #{cluster_name}\"\n" - else - notes = @vm.config.annotation.gsub("\\", "\\\\").gsub("\"", "\\\"") - str << "DESCRIPTION = \"#{notes}\"\n" - end - - case @vm.guest.guestFullName - when /CentOS/i - str << "LOGO=images/logos/centos.png" - when /Debian/i - str << "LOGO=images/logos/debian.png" - when /Red Hat/i - str << "LOGO=images/logos/redhat.png" - when /Ubuntu/i - str << "LOGO=images/logos/ubuntu.png" - when /Windows XP/i - str << "LOGO=images/logos/windowsxp.png" - when /Windows/i - str << "LOGO=images/logos/windows8.png" - when /Linux/i - str << "LOGO=images/logos/linux.png" - end - - return str - end - -private - ######################################################################## # Converts the VI string state to OpenNebula state convention # Guest states are: @@ -830,922 +304,6 @@ private VM_STATE[:unknown] end end - - ######################################################################## - # Checks if a RbVmomi::VIM::VirtualDevice is a network interface - ######################################################################## - def self.is_nic?(device) - !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? - end - - ######################################################################## - # Checks if a RbVmomi::VIM::VirtualDevice is a disk - ######################################################################## - def self.is_disk?(device) - is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? - is_cdrom = !(device.class.ancestors.index(RbVmomi::VIM::VirtualCdrom)).nil? - is_disk or is_cdrom - end - - ######################################################################## - # Returns the spec to reconfig a VM and add a NIC - ######################################################################## - def self.calculate_addnic_spec(vm, mac, bridge, model, limit=nil, rsrv=nil) - model = model.nil? ? nil : model.downcase - network = vm.runtime.host.network.select{|n| n.name==bridge} - backing = nil - - if network.empty? - raise "Network #{bridge} not found in host #{vm.runtime.host.name}" - else - network = network[0] - end - - card_num = 1 # start in one, we want the next avaliable id - - vm.config.hardware.device.each{ |dv| - card_num = card_num + 1 if is_nic?(dv) - } - - nic_card = case model - when "virtuale1000", "e1000" - RbVmomi::VIM::VirtualE1000 - when "virtuale1000e", "e1000e" - RbVmomi::VIM::VirtualE1000e - when "virtualpcnet32", "pcnet32" - RbVmomi::VIM::VirtualPCNet32 - when "virtualsriovethernetcard", "sriovethernetcard" - RbVmomi::VIM::VirtualSriovEthernetCard - when "virtualvmxnetm", "vmxnetm" - RbVmomi::VIM::VirtualVmxnetm - when "virtualvmxnet2", "vmnet2" - RbVmomi::VIM::VirtualVmxnet2 - when "virtualvmxnet3", "vmxnet3" - RbVmomi::VIM::VirtualVmxnet3 - else # If none matches, use VirtualE1000 - RbVmomi::VIM::VirtualE1000 - end - - if network.class == RbVmomi::VIM::Network - backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( - :deviceName => bridge, - :network => network) - else - port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( - :switchUuid => - network.config.distributedVirtualSwitch.uuid, - :portgroupKey => network.key) - backing = - RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( - :port => port) - end - - card_spec = { - :key => 0, - :deviceInfo => { - :label => "net" + card_num.to_s, - :summary => bridge - }, - :backing => backing, - :addressType => mac ? 'manual' : 'generated', - :macAddress => mac - } - - if (limit or rsrv) and (limit > 0) - ra_spec = Hash.new - rsrv = limit if rsrv > limit - ra_spec[:limit] = limit if limit - ra_spec[:reservation] = rsrv if rsrv - ra_spec[:share] = RbVmomi::VIM.SharesInfo({ - :level => RbVmomi::VIM.SharesLevel("normal"), - :shares => 0 - }) - card_spec[:resourceAllocation] = - RbVmomi::VIM.VirtualEthernetCardResourceAllocation(ra_spec) - end - - return { - :operation => :add, - :device => nic_card.new(card_spec) - } - end - - ######################################################################## - # Clone a vCenter VM Template and leaves it powered on - ######################################################################## - def self.clone_vm(xml_text, hostname, datastore, ops = {}) - - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - - # Retrieve hostname - - host = OpenNebula::Host.new_with_id(host_id, OpenNebula::Client.new()) - host.info # Not failing if host retrieval fails - - # Get VM prefix name - - if host["/HOST/TEMPLATE/VM_PREFIX"] and !host["/HOST/TEMPLATE/VM_PREFIX"].empty? - vmname_prefix = host["/HOST/TEMPLATE/VM_PREFIX"] - else # fall back to default value - vmname_prefix = "one-$i-" - end - - xml = REXML::Document.new xml_text - pcs = xml.root.get_elements("/VM/USER_TEMPLATE/PUBLIC_CLOUD") - - raise "Cannot find VCenter element in VM template." if pcs.nil? - - template = pcs.select { |t| - type = t.elements["TYPE"] - !type.nil? && type.text.downcase == "vcenter" - } - - # If there are multiple vCenter templates, find the right one - - if template.is_a? Array - all_vcenter_templates = template.clone - # If there is more than one coincidence, pick the first one - template = template.select {|t| - cluster_name = t.elements["HOST"] - !cluster_name.nil? && cluster_name.text == hostname - }[0] - # The template may not reference any specific CLUSTER - # (referenced to as HOST in the OpenNebula template) - # Therefore, here take the first one that does not - # specify a CLUSTER to see if we are lucky - if template.nil? - template = all_vcenter_templates.select {|t| - t.elements["HOST"].nil? - }[0] - end - end - - raise "Cannot find vCenter element in VM template." if template.nil? - - uuid = template.elements["VM_TEMPLATE"] - - raise "Cannot find VM_TEMPLATE in vCenter element." if uuid.nil? - - uuid = uuid.text - vmid = xml.root.elements["/VM/ID"].text - vmname_prefix.gsub!("$i", vmid) - vcenter_name = "#{vmname_prefix}#{xml.root.elements["/VM/NAME"].text}" - hid = xml.root.elements["/VM/HISTORY_RECORDS/HISTORY/HID"] - - raise "Cannot find host id in deployment file history." if hid.nil? - - connection = VIClient.new(hid) - vc_template = connection.find_vm_fast(uuid, ops[:ref], ops[:name]) - - # Find out requested and available resource pool - - req_rp = nil - if !xml.root.elements["/VM/USER_TEMPLATE/RESOURCE_POOL"].nil? - req_rp = xml.root.elements["/VM/USER_TEMPLATE/RESOURCE_POOL"].text - end - - if connection.rp_confined? - rp = connection.resource_pool.first - if req_rp && rp.name != req_rp - raise "Available resource pool in host [#{rp.name}]"\ - " does not match requested resource pool"\ - " [#{req_rp}]" - end - else - if req_rp # if there is requested resource pool, retrieve it - rp = connection.find_resource_pool(req_rp) - raise "Cannot find resource pool "\ - "#{template.elements["RESOURCE_POOL"].text}" if !rp - else # otherwise, get the default resource pool - rp = connection.default_resource_pool - end - end - - # Find out requested and available datastore - - if !xml.root.elements["/VM/USER_TEMPLATE/VCENTER_DATASTORE"].nil? - datastore = xml.root.elements["/VM/USER_TEMPLATE/VCENTER_DATASTORE"].text - end - - if datastore - datastores = VIClient.get_entities(connection.dc.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(connection.dc.datastoreFolder, - 'StoragePod') - - storpod = storage_pods.select{|sp| sp.name == datastore} - - storage_pods.each { |sp| - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == datastore}[0] - - raise "Cannot find datastore #{datastore}" if !ds && !storpod - - end - - relocate_spec_params = { - :pool => rp - } - - relocate_spec_params[:datastore] = ds if datastore - - relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking if ds - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - relocate_spec_params) - - # This running flag will prevent spurious poweroff states in the VM - - running_flag = [{:key=>"opennebula.vm.running",:value=>"no"}] - - running_flag_spec = RbVmomi::VIM.VirtualMachineConfigSpec( - {:extraConfig =>running_flag}) - - clone_parameters = { - :location => relocate_spec, - :powerOn => false, - :template => false, - :config => running_flag_spec - } - - customization = template.elements["CUSTOMIZATION_SPEC"] - - vim = connection.vim - - if !customization.nil? - begin - custom_spec = vim.serviceContent.customizationSpecManager. - GetCustomizationSpec(:name => customization.text) - - if custom_spec && spec=custom_spec.spec - clone_parameters[:customization] = spec - else - raise "Error getting customization spec" - end - - rescue - raise "Customization spec '#{customization.text}' not found" - end - end - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(clone_parameters) - - if storpod && !storpod.empty? && storpod[0].is_a?(RbVmomi::VIM::StoragePod) - - storage_manager = vim.serviceContent.storageResourceManager - - pod_spec = RbVmomi::VIM.StorageDrsPodSelectionSpec(storagePod: storpod[0]) - - storage_spec = RbVmomi::VIM.StoragePlacementSpec( - type: 'clone', - cloneName: vcenter_name, - folder: vc_template.parent, - podSelectionSpec: pod_spec, - vm: vc_template, - cloneSpec: clone_spec - ) - - result = storage_manager.RecommendDatastores(storageSpec: storage_spec) - - recommendation = result.recommendations[0] - - key = recommendation.key ||= '' - - if key == '' - raise "Missing Datastore recommendation for StoragePod (Storage DRS)" - end - - begin - apply_sr = storage_manager.ApplyStorageDrsRecommendation_Task(key: [key]).wait_for_completion - vm = apply_sr.vm - rescue Exception => e - raise "Cannot clone VM Template to StoragePod: #{e.message}" - end - else - - begin - vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => vcenter_name, - :spec => clone_spec).wait_for_completion - rescue Exception => e - - if !e.message.start_with?('DuplicateName') - raise "Cannot clone VM Template: #{e.message}" - end - - vm = connection.find_vm(vcenter_name) - - raise "Cannot clone VM Template" if vm.nil? - - vm.Destroy_Task.wait_for_completion - vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => vcenter_name, - :spec => clone_spec).wait_for_completion - end - - end - - reconfigure_vm(vm, xml, true, hostname) - - # Power on the VM - vm.PowerOnVM_Task.wait_for_completion - - # Set to yes the running flag - - config_array = [{:key=>"opennebula.vm.running",:value=>"yes"}] - spec = RbVmomi::VIM.VirtualMachineConfigSpec( - {:extraConfig =>config_array}) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - - return vm.config.uuid - end - - ######################################################################## - # Reconfigures a VM with new deployment description - ######################################################################## - def self.reconfigure_vm(vm, xml, newvm, hostname) - vm_uuid = vm.config.uuid - vmid = xml.root.elements["/VM/ID"].text - context = xml.root.elements["/VM/TEMPLATE/CONTEXT"] - - token = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.token" - end - - if token && !token.empty? - token = token.first[:value] - else - token = nil - end - - # Add VMID to VM's extraConfig - - config_array = [{:key=>"opennebula.vm.id",:value=>vmid}] - - # VNC Section - - vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] - vnc_listen = xml.root.elements["/VM/TEMPLATE/GRAPHICS/LISTEN"] - vnc_keymap = xml.root.elements["/VM/TEMPLATE/GRAPHICS/KEYMAP"] - - if !vnc_listen - vnc_listen = "0.0.0.0" - else - vnc_listen = vnc_listen.text - end - - context_vnc_spec = {} - - if vnc_port - config_array += - [{:key=>"remotedisplay.vnc.enabled",:value=>"TRUE"}, - {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}, - {:key=>"remotedisplay.vnc.ip", :value=>vnc_listen}] - end - - config_array += [{:key=>"remotedisplay.vnc.keymap", - :value=>vnc_keymap.text}] if vnc_keymap - - # Context section - - if context - context_text = create_context(context) - - # OneGate - onegate_token_flag = xml.root.elements["/VM/TEMPLATE/CONTEXT/TOKEN"] - - if onegate_token_flag and onegate_token_flag.text == "YES" - if token - onegate_token_64 = token - else - # Create the OneGate token string - vmid_str = xml.root.elements["/VM/ID"].text - stime_str = xml.root.elements["/VM/STIME"].text - str_to_encrypt = "#{vmid_str}:#{stime_str}" - - user_id = xml.root.elements['//CREATED_BY'].text - - if user_id.nil? - STDERR.puts {"VMID:#{vmid} CREATED_BY not present" \ - " in the VM TEMPLATE"} - return nil - end - - user = OpenNebula::User.new_with_id(user_id, - OpenNebula::Client.new) - rc = user.info - - if OpenNebula.is_error?(rc) - STDERR.puts {"VMID:#{vmid} user.info" \ - " error: #{rc.message}"} - return nil - end - - token_password = user['TEMPLATE/TOKEN_PASSWORD'] - - if token_password.nil? - STDERR.puts {"VMID:#{vmid} TOKEN_PASSWORD not present"\ - " in the USER:#{user_id} TEMPLATE"} - return nil - end - - cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") - cipher.encrypt - cipher.key = token_password - onegate_token = cipher.update(str_to_encrypt) - onegate_token << cipher.final - - onegate_token_64 = Base64.encode64(onegate_token).chop - config_array << { - :key => 'opennebula.token', - :value => onegate_token_64 - } - end - - context_text += "ONEGATE_TOKEN='#{onegate_token_64}'\n" - end - - context_text = Base64.encode64(context_text.chop) - - config_array += - [{:key=>"guestinfo.opennebula.context", - :value=>context_text}] - end - - device_change = [] - - # NIC section, build the reconfig hash - - nics = xml.root.get_elements("/VM/TEMPLATE/NIC") - - # If the VM is not new, avoid readding NiCs - if !newvm - nic_array = [] - - # Get MACs from NICs inside VM template - one_mac_addresses = Array.new - nics.each{|nic| - one_mac_addresses << nic.elements["MAC"].text - } - - # B4897 - Get mac of NICs that were hot-plugged from vCenter extraConfig - hotplugged_nics = [] - extraconfig_nics = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.hotplugged_nics" - end - - if extraconfig_nics && !extraconfig_nics.empty? - hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") - end - - vm.config.hardware.device.each{ |dv| - if is_nic?(dv) - nics.each{|nic| - if nic.elements["MAC"].text == dv.macAddress - nics.delete(nic) - end - } - - # B4897 - Remove detached NICs from vCenter that were unplugged in POWEROFF - if !one_mac_addresses.include?(dv.macAddress) && hotplugged_nics.include?(dv.macAddress) - nic_array << { :operation => :remove, :device => dv} - hotplugged_nics.delete(dv.macAddress) - config_array << { - :key => 'opennebula.hotplugged_nics', - :value => hotplugged_nics.join(";") - } - end - end - } - - device_change += nic_array - end - - if !nics.nil? - nic_array = [] - nics.each{|nic| - mac = nic.elements["MAC"].text - bridge = nic.elements["BRIDGE"].text - model = nic.elements["MODEL"] ? nic.elements["MODEL"].text : nil - limit_in = nic.elements["INBOUND_PEAK_BW"] ? nic.elements["INBOUND_PEAK_BW"].text : "" - limit_out = nic.elements["OUTBOUND_PEAK_BW"] ? nic.elements["OUTBOUND_PEAK_BW"].text : "" - limit = nil - if !limit_in.empty? or !limit_out.empty? - limit=([limit_in.to_i, limit_out.to_i].min / 1024) * 8 - end - rsrv_in = nic.elements["INBOUND_AVG_BW"] ? nic.elements["INBOUND_AVG_BW"].text : "" - rsrv_out = nic.elements["OUTBOUND_AVG_BW"] ? nic.elements["OUTBOUND_AVG_BW"].text : "" - rsrv = nil - if !rsrv_in.empty? or !rsrv_out.empty? - rsrv=([rsrv_in.to_i, rsrv_out.to_i].min / 1024) * 8 - end - nic_array << calculate_addnic_spec(vm, - mac, - bridge, - model, - limit, - rsrv) - } - - device_change += nic_array - end - - # DISK section, build the reconfig hash - - disks = xml.root.get_elements("/VM/TEMPLATE/DISK") - disk_spec = {} - - # If the VM is not new, avoid reading DISKS - if !newvm - vm.config.hardware.device.select { |d| - if is_disk?(d) - disks.each{|disk| - if d.backing.respond_to?(:fileName) && - disk.elements["SOURCE"].text == d.backing.fileName && - disks.delete(disk) - end - } - end - } - end - - if !disks.nil? - disk_array = [] - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - position = 0 - disks.each{|disk| - ds_name = disk.elements["VCENTER_NAME"].text - img_name = get_disk_img_path(disk, vmid) - type_str = disk.elements["TYPE"].text - - disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection, position)[:deviceChange] - position += 1 - } - - device_change += disk_array - end - - # Capacity section - - cpu = xml.root.elements["/VM/TEMPLATE/VCPU"] ? xml.root.elements["/VM/TEMPLATE/VCPU"].text : 1 - memory = xml.root.elements["/VM/TEMPLATE/MEMORY"].text - capacity_spec = {:numCPUs => cpu.to_i, - :memoryMB => memory } - - # Perform the VM reconfiguration - if config_array != [] - context_vnc_spec = {:extraConfig =>config_array} - end - - spec_hash = context_vnc_spec.merge(capacity_spec) - if device_change.length > 0 - spec_hash.merge!({ :deviceChange => device_change }) - end - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - ############################################################################ - # Attach disk to a VM - # @params hostname[String] vcenter cluster name in opennebula as host - # @params deploy_id[String] deploy id of the vm - # @params ds_name[String] name of the datastore - # @params img_name[String] path of the image - # @params size_kb[String] size in kb of the disk - # @params vm[RbVmomi::VIM::VirtualMachine] VM if called from instance - # @params connection[ViClient::connectoon] connection if called from instance - # @params position The number of disks to attach. Starts with 0. - ############################################################################ - def self.attach_disk(hostname, deploy_id, ds_name, img_name, type, size_kb, vm=nil, connection=nil, position=0) - only_return = true - if !vm - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - only_return = false - end - - # Find datastore within datacenter - datastores = VIClient.get_entities(connection.dc.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(connection.dc.datastoreFolder, - 'StoragePod') - storage_pods.each { |sp| - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == ds_name}[0] - - controller, new_number = find_free_controller(vm, position) - - if type == "CDROM" - vmdk_backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo( - :datastore => ds, - :fileName => "[#{ds_name}] #{img_name}" - ) - - cd = vm.config.hardware.device.select {|hw| - hw.class == RbVmomi::VIM::VirtualCdrom}.first - - # If no CDROM drive present, we need to add it - if !cd - controller, new_unit_number = find_free_controller(vm) - cdrom_drive_spec = RbVmomi::VIM.VirtualMachineConfigSpec( - :deviceChange => [{ - :operation => :add, - :device => RbVmomi::VIM::VirtualCdrom( - :backing => vmdk_backing, - :key => -1, - :controllerKey => 15000, - :unitNumber => 0, - :connectable => RbVmomi::VIM::VirtualDeviceConnectInfo( - :startConnected => true, - :connected => true, - :allowGuestControl => true - ) - )}] - ) - - vm.ReconfigVM_Task(:spec => - cdrom_drive_spec).wait_for_completion - - return - else - device = RbVmomi::VIM::VirtualCdrom( - backing: vmdk_backing, - key: cd.key, - controllerKey: cd.controllerKey, - connectable: RbVmomi::VIM::VirtualDeviceConnectInfo( - startConnected: true, - connected: true, - allowGuestControl: true - ) - ) - device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( - :device => device, - :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('edit') - ) - end - else - vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo( - :datastore => ds, - :diskMode => 'persistent', - :fileName => "[#{ds_name}] #{img_name}" - ) - - device = RbVmomi::VIM::VirtualDisk( - :backing => vmdk_backing, - :capacityInKB => size_kb, - :controllerKey => controller.key, - :key => -1, - :unitNumber => new_number - ) - - device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( - :device => device, - :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') - ) - end - - vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( - :deviceChange => [device_config_spec] - ) - - return vm_config_spec if only_return - - vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion - end - - def self.find_free_controller(vm, position=0) - free_scsi_controllers = Array.new - available_controller = nil - scsi_schema = Hash.new - - used_numbers = Array.new - available_numbers = Array.new - - vm.config.hardware.device.each{ |dev| - if dev.is_a? RbVmomi::VIM::VirtualSCSIController - if scsi_schema[dev.controllerKey].nil? - scsi_schema[dev.key] = Hash.new - scsi_schema[dev.key][:lower] = Array.new - end - used_numbers << dev.scsiCtlrUnitNumber - scsi_schema[dev.key][:device] = dev - end - - next if dev.class != RbVmomi::VIM::VirtualDisk - used_numbers << dev.unitNumber - } - - 15.times{ |scsi_id| - available_numbers << scsi_id if used_numbers.grep(scsi_id).length <= 0 - } - - scsi_schema.keys.each{|controller| - if scsi_schema[controller][:lower].length < 15 - free_scsi_controllers << scsi_schema[controller][:device].deviceInfo.label - end - } - - if free_scsi_controllers.length > 0 - available_controller_label = free_scsi_controllers[0] - else - add_new_scsi(vm, scsi_schema) - return find_free_controller(vm) - end - - controller = nil - - vm.config.hardware.device.each { |device| - (controller = device ; break) if device.deviceInfo.label == available_controller_label - } - - new_unit_number = available_numbers.sort[position] - - return controller, new_unit_number - end - - def self.add_new_scsi(vm, scsi_schema) - controller = nil - - if scsi_schema.keys.length >= 4 - raise "Cannot add a new controller, maximum is 4." - end - - if scsi_schema.keys.length == 0 - scsi_key = 0 - scsi_number = 0 - else scsi_schema.keys.length < 4 - scsi_key = scsi_schema.keys.sort[-1] + 1 - scsi_number = scsi_schema[scsi_schema.keys.sort[-1]][:device].busNumber + 1 - end - - controller_device = RbVmomi::VIM::VirtualLsiLogicController( - :key => scsi_key, - :busNumber => scsi_number, - :sharedBus => :noSharing - ) - - device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( - :device => controller_device, - :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') - ) - - vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( - :deviceChange => [device_config_spec] - ) - - vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion - - vm.config.hardware.device.each { |device| - if device.class == RbVmomi::VIM::VirtualLsiLogicController && - device.key == scsi_key - controller = device.deviceInfo.label - end - } - - return controller - end - - ############################################################################ - # Detach a specific disk from a VM - # @params hostname[String] vcenter cluster name in opennebula as host - # @params deploy_id[String] deploy id of the vm - # @params ds_name[String] name of the datastore - # @params img_path[String] path of the image - ############################################################################ - def self.detach_disk(hostname, deploy_id, ds_name, img_path) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - ds_and_img_name = "[#{ds_name}] #{img_path}" - - disk = vm.config.hardware.device.select { |d| is_disk?(d) && - d.backing.respond_to?(:fileName) && - d.backing.fileName == ds_and_img_name } - - raise "Disk #{img_path} not found." if disk.nil? - - spec = { :deviceChange => [{ - :operation => :remove, - :device => disk[0] - }]} - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - ############################################################################ - # Detach all disks from a VM - # @params vm[VCenterVm] vCenter VM - ############################################################################ - def self.detach_all_disks(vm) - disks = vm.config.hardware.device.select { |d| is_disk?(d) } - - return if disks.nil? - - spec = { :deviceChange => [] } - - disks.each{|disk| - spec[:deviceChange] << { - :operation => :remove, - :device => disk - } - } - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - def self.create_context(context) - # Remove (9) and \n (11) - context_text = "# Context variables generated by OpenNebula\n" - context.elements.each{|context_element| - next if !context_element.text - context_text += context_element.name + "='" + - context_element.text.gsub("'", "\\'") + "'\n" - } - context_text - end - - ############################################################################ - # Detach attached disks from a VM - ############################################################################ - def self.detach_attached_disks(vm, disks, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vmid = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.vm.id" - end.first.value - - spec = { :deviceChange => [] } - - disks.each{ |disk| - img_name = get_disk_img_path(disk, vmid) - ds_and_img_name = "[#{disk['VCENTER_NAME']}] #{img_name}" - - vcenter_disk = vm.config.hardware.device.select { |d| is_disk?(d) && - d.backing.respond_to?(:fileName) && - d.backing.fileName == ds_and_img_name }[0] - spec[:deviceChange] << { - :operation => :remove, - :device => vcenter_disk - } - } - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - - ############################################################################ - # Returns the source path of a disk. It will use the 'SOURCE' path if - # persistent and one-#{vm_id}-#{disk_id}.vmdk otherwise - # @param disks VM attached disks, either an REXML document, or a hash - # @param vmid The VM ID - ############################################################################ - def self.get_disk_img_path(disk, vmid) - if disk.respond_to? :elements - # It's a REXML::Document, probably coming from self.reconfigure_vm - persistent = disk.elements["PERSISTENT"].text == "YES" rescue false - - if persistent - disk.elements["SOURCE"].text - else - disk_id = disk.elements["DISK_ID"].text - "one_#{vmid}_#{disk_id}.vmdk" - end - else - # It's a hash, probably coming from self.detach_attached_disks - persistent = disk["PERSISTENT"] == "YES" - - if persistent - disk["SOURCE"] - else - disk_id = disk["DISK_ID"] - "one_#{vmid}_#{disk_id}.vmdk" - end - end - end - -end end + +end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb index 882c318f11..905569dee5 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver2.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver2.rb @@ -38,7 +38,6 @@ $: << LIB_LOCATION + '/ruby/vendors/rbvmomi/lib' $: << LIB_LOCATION + '/ruby' $: << LIB_LOCATION + '/ruby/vcenter_driver' -require 'ostruct' require 'rbvmomi' require 'yaml' require 'opennebula' @@ -49,9 +48,9 @@ require 'openssl' # vCenter Library # # ---------------------------------------------------------------------------- # -require 'rbvmomi_datastore' +require 'memoize' require 'vi_client' -require 'cached_datastore' -require 'cached_host' +require 'datacenter' require 'host' +require 'datastore' require 'virtual_machine' From 1aca1706454e2e61700bcdf700011530a7912829 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Sun, 15 Jan 2017 13:29:06 +0100 Subject: [PATCH 015/297] F #4913: Adapt vcenter.rb (run_probes) to new structure --- src/im_mad/remotes/vcenter.d/vcenter.rb | 35 ++++++++++----- .../remotes/lib/vcenter_driver/vi_client.rb | 44 +++++++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index b50077406e..3d403bd75a 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -34,19 +34,32 @@ if !host_id exit -1 end -vi_client = VCenterDriver::VIClient.new host_id +vi_client = VCenterDriver::VIClient.new_from_host(host_id) -vcenter_host = VCenterDriver::VCenterHost.new vi_client +# Get CCR reference +client = OpenNebula::Client.new +host = OpenNebula::Host.new_with_id(host_id, client) +rc = host.info +if OpenNebula::is_error? rc + STDERR.puts rc.message + exit 1 +end -cluster_info = vcenter_host.monitor_cluster -cluster_info << vcenter_host.monitor_host_systems -vm_monitor_info = vcenter_host.monitor_vms +ccr = host["TEMPLATE/VCENTER_CCR"] -cluster_info << "\nVM_POLL=YES" -cluster_info << "#{vm_monitor_info}" if !vm_monitor_info.empty? +# Get vCenter Cluster +cluster = VCenterDriver::ClusterComputeResource.new_from_ref(vi_client, ccr) -cluster_info << "\n" -cluster_info << vcenter_host.monitor_customizations -cluster_info << vcenter_host.get_available_ds +# Print monitoring info +puts cluster.monitor +puts cluster.monitor_host_systems -puts cluster_info +vm_monitor_info = cluster.monitor_vms +if !vm_monitor_info.empty? + puts "VM_POLL=YES" + puts vm_monitor_info +end + +# TODO: monitor network metrics in 'monitor_vms' +# TODO: monitor_customizations +# TODO: get_available_ds diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 66598a44bb..342cc9d0dd 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -1,3 +1,5 @@ +require 'openssl' + module VCenterDriver class VIClient @@ -25,6 +27,48 @@ class VIClient return entities end + + def self.new_from_host(host_id) + client = OpenNebula::Client.new + host = OpenNebula::Host.new_with_id(host_id, client) + rc = host.info + if OpenNebula.is_error?(rc) + puts rc.message + exit -1 + end + + password = host["TEMPLATE/VCENTER_PASSWORD"] + + system = OpenNebula::System.new(client) + config = system.get_configuration + if OpenNebula.is_error?(config) + puts "Error getting oned configuration : #{config.message}" + exit -1 + end + + token = config["ONE_KEY"] + + begin + cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") + + cipher.decrypt + cipher.key = token + + password = cipher.update(Base64::decode64(password)) + password << cipher.final + rescue + puts "Error decrypting vCenter password" + exit -1 + end + + connection = { + :host => host["TEMPLATE/VCENTER_HOST"], + :user => host["TEMPLATE/VCENTER_USER"], + :password => password + } + + self.new(connection) + end end end # module VCenterDriver From 55d90a6b7fb52861e4a599d60482c30c0013436c Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 20 Jan 2017 17:43:05 +0100 Subject: [PATCH 016/297] Add end class comments --- src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb | 2 +- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 4 ++-- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 4 ++-- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index a5468f2c69..1b7405835c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -33,7 +33,7 @@ class DatacenterFolder @items[ref.to_sym] end -end +end # class DatatacenterFolder class Datacenter attr_accessor :item diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 8c5c5ceb57..7ee84e97c3 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -33,7 +33,7 @@ class DatastoreFolder @items[ref.to_sym] end -end +end # class DatastoreFolder class Datastore attr_accessor :item @@ -51,7 +51,7 @@ class Datastore def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref)) end -end +end # class Datastore end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index b585c48094..cf3b51854b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -23,7 +23,7 @@ class HostFolder @clusters[ref.to_sym] end -end +end # class HostFolder class ClusterComputeResource attr_accessor :item @@ -242,6 +242,6 @@ class ClusterComputeResource def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref)) end -end +end # class ClusterComputeResource end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 395cb55e98..b1f09ff328 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -304,6 +304,6 @@ class VirtualMachine VM_STATE[:unknown] end end -end +end # class VirtualMachine end # module VCenterDriver From 31ecf675dcf1f9950d0c0f7ee100dbfa8b57ea1d Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Fri, 20 Jan 2017 17:52:48 +0100 Subject: [PATCH 017/297] Memoize class end comment --- src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb b/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb index deadd8e9f6..dd928b8ae8 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb @@ -41,4 +41,4 @@ module Memoize @memoize[property] = value end -end +end # module Memoize From 067e32ac9466a4aee98fa4743b7d9322b8c5aabb Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 30 Jan 2017 16:33:25 +0100 Subject: [PATCH 018/297] F #4913: Implement ds drivers: mkfs, rm and monitor --- src/datastore_mad/remotes/vcenter/mkfs | 54 ++++++++++--------- src/datastore_mad/remotes/vcenter/monitor | 21 +++----- src/datastore_mad/remotes/vcenter/rm | 44 +++++++++------ src/im_mad/remotes/vcenter.d/vcenter.rb | 5 +- .../remotes/lib/vcenter_driver/datacenter.rb | 2 +- .../remotes/lib/vcenter_driver/datastore.rb | 43 ++++++++++++++- .../remotes/lib/vcenter_driver/host.rb | 4 +- 7 files changed, 111 insertions(+), 62 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 97532ebf2c..fe9f36132a 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -31,8 +31,8 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'digest' +require 'vcenter_driver2' +require 'opennebula' ################################################################################ @@ -52,38 +52,40 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] -disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] -size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] -fs_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/FSTYPE"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_REF"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +dc_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DC_REF"] +img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] +adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] +disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] +size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] +fs_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/FSTYPE"] -str_for_target_path = Time.now.to_s + id.to_s -target_path = Digest::MD5.hexdigest(str_for_target_path) - -if fs_type == "save_as" - puts target_path + ".vmdk" - exit 0 -end - -check_valid ds_name, "ds_name" -check_valid hostname, "hostname" +check_valid img_id, "img_id" +check_valid host_id, "vcenter_cluster" check_valid adapter_type, "adapter_type" check_valid disk_type, "disk_type" check_valid size, "size" +check_valid ds_ref, "ds_ref" +check_valid dc_ref, "dc_ref" + +# TODO path in vCenter? choose a specific directory + +img_name = "one-#{img_id}" + +if fs_type == "save_as" + puts img_name + ".vmdk" + exit 0 +end begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) + dc = VCenterDriver::Datacenter.new_from_ref(vi_client, dc_ref) - puts vi_client.create_virtual_disk(img_name, - ds_name, - size, - adapter_type, - disk_type) + puts ds.create_virtual_disk(dc, img_name, size, adapter_type, disk_type) rescue Exception => e - STDERR.puts "Error creating virtual disk in #{ds_name}."\ + STDERR.puts "Error creating virtual disk #{img_src}."\ " Reason: #{e.message}" exit -1 end diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 883ea0da77..7cc9efaf0f 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -31,7 +31,8 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' +require 'opennebula' drv_action_enc = ARGV[0] id = ARGV[1] @@ -39,21 +40,15 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_NAME"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_REF"] -if ds_name.nil? || - hostname.nil? +if host_id.nil? || ds_ref.nil? STDERR.puts "Not enough information to monitor the image." exit -1 end -begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id +vi_client = VCenterDriver::VIClient.new_from_host(host_id) +ds = VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) - puts vi_client.monitor_ds(ds_name) -rescue Exception => e - STDERR.puts "Error monitoring #{ds_name}. Reason: #{e.message}" - exit -1 -end +puts ds.monitor diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 9f40353d2d..c22ee8c1c7 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -17,7 +17,7 @@ # ---------------------------------------------------------------------------- # ############################################################################### -# This script is used retrieve the file size of a disk +# This script is used retrieve the file size of a disk ############################################################################### ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) @@ -31,7 +31,20 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' +require 'opennebula' + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to delete the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ drv_action_enc = ARGV[0] id = ARGV[1] @@ -39,25 +52,24 @@ id = ARGV[1] drv_action =OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_REF"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +dc_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DC_REF"] +img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] -if ds_name.nil? || - hostname.nil? || - img_src.nil? - STDERR.puts "Not enough information to delete the image." - exit -1 -end +check_valid ds_ref, "ds_ref" +check_valid host_id, "vcenter_cluster" +check_valid img_src, "img_src" +check_valid dc_ref, "dc_ref" begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + dc = VCenterDriver::Datacenter.new_from_ref(vi_client, dc_ref) + ds = VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) - vi_client.delete_virtual_disk(img_src, - ds_name) + ds.delete_virtual_disk(dc, img_src) rescue Exception => e - STDERR.puts "Error delete virtual disk #{img_src} in #{ds_name}."\ + STDERR.puts "Error deleting virtual disk #{img_src}."\ " Reason: #{e.message}" exit -1 end diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index 3d403bd75a..0b82b0d3dc 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -26,7 +26,8 @@ end $: << RUBY_LIB_LOCATION -require 'vcenter_driver' +require 'vcenter_driver2' +require 'opennebula' host_id = ARGV[4] @@ -34,7 +35,7 @@ if !host_id exit -1 end -vi_client = VCenterDriver::VIClient.new_from_host(host_id) +vi_client = VCenterDriver::VIClient.new_from_host(host_id) # Get CCR reference client = OpenNebula::Client.new diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index 1b7405835c..3c11b6e0c2 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -15,7 +15,7 @@ class DatacenterFolder ######################################################################## def fetch! VIClient.get_entities(@vcenter_client.vim.root, "Datacenter").each do |item| - _, item_name, _ = item.to_s.split('"') + item_name = item._ref @items[item_name.to_sym] = Datacenter.new(item) end end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 7ee84e97c3..2551103da7 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -15,7 +15,7 @@ class DatastoreFolder ######################################################################## def fetch! VIClient.get_entities(@item, "Datastore").each do |item| - _, item_name, _ = item.to_s.split('"') + item_name = item._ref @items[item_name.to_sym] = Datastore.new(item) end end @@ -27,7 +27,7 @@ class DatastoreFolder ######################################################################## def get(ref) if !@items[ref.to_sym] - rbvmomi_dc = RbVmomi::VIM::Datastore.new(@vcenter_client.vim, ref) + rbvmomi_dc = RbVmomi::VIM::Datastore.new(@item._connection, ref) @items[ref.to_sym] = Datastore.new(rbvmomi_dc) end @@ -47,6 +47,45 @@ class Datastore @item = item end + def monitor + summary = @item.summary + + total_mb = (summary.capacity.to_i / 1024) / 1024 + free_mb = (summary.freeSpace.to_i / 1024) / 1024 + used_mb = total_mb - free_mb + + "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" + end + + def create_virtual_disk(dc, img_name, size, adapter_type, disk_type) + vdm = @item._connection.serviceContent.virtualDiskManager + ds_name = @item.name + + vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( + :adapterType => adapter_type, + :capacityKb => size.to_i*1024, + :diskType => disk_type + ) + + vdm.CreateVirtualDisk_Task( + :datacenter => dc.item, + :name => "[#{ds_name}] #{img_name}.vmdk", + :spec => vmdk_spec + ).wait_for_completion + + "#{img_name}.vmdk" + end + + def delete_virtual_disk(dc, img_name) + vdm = @item._connection.serviceContent.virtualDiskManager + ds_name = @item.name + + vdm.DeleteVirtualDisk_Task( + name: "[#{ds_name}] #{img_name}", + datacenter: dc.item + ).wait_for_completion + end + # This is never cached def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref)) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index cf3b51854b..dd94dd2c0b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -10,14 +10,14 @@ class HostFolder def fetch_clusters! VIClient.get_entities(@item, 'ClusterComputeResource').each do |item| - _, item_name, _ = item.to_s.split('"') + item_name = item._ref @clusters[item_name.to_sym] = ClusterComputeResource.new(item) end end def get_cluster(ref) if !@clusters[ref.to_sym] - rbvmomi_dc = RbVmomi::VIM::ClusterComputeResource.new(@vcenter_client.vim, ref) + rbvmomi_dc = RbVmomi::VIM::ClusterComputeResource.new(@item._connection, ref) @clusters[ref.to_sym] = ClusterComputeResource.new(rbvmomi_dc) end From f8341daa283e1da13136f9b83605bcc7c096a54d Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 6 Feb 2017 19:29:43 +0100 Subject: [PATCH 019/297] F #4913: Add necessary functions for virtual machine deploy --- .../remotes/lib/vcenter_driver/datacenter.rb | 4 ++++ src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 13 +++++++++++++ src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index 3c11b6e0c2..2eb2d22cce 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -55,6 +55,10 @@ class Datacenter HostFolder.new(@item.hostFolder) end + def vm_folder + VirtualMachineFolder.new(@item.vmFolder) + end + # This is never cached def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref)) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index dd94dd2c0b..e06ffb4bdd 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -239,6 +239,19 @@ class ClusterComputeResource return str_info.gsub(/^\s+/,"") end + def get_dc + item = @item + + while !item.instance_of? RbVmomi::VIM::Datacenter + item = item.parent + if item.nil? + raise "Could not find the parent Datacenter" + end + end + + Datacenter.new(item) + end + def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref)) end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 342cc9d0dd..933003b777 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -4,10 +4,18 @@ module VCenterDriver class VIClient attr_accessor :vim + attr_accessor :rp def initialize(opts) opts = {:insecure => true}.merge(opts) @vim = RbVmomi::VIM.connect(opts) + + rp_ref = opts.delete(:rp) + @rp = RbVmomi::VIM::ResourcePool(@vim, rp_ref) if rp_ref + end + + def rp_confined? + !!@rp end def self.get_entities(folder, type, entities=[]) From 5e86f4337e5cf23bc43ecc7bb42f16af451e3eb0 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 6 Feb 2017 19:31:20 +0100 Subject: [PATCH 020/297] F #4913: Virtual machine deploy work in progress --- .../lib/vcenter_driver/virtual_machine.rb | 129 +++++++++++++++++- 1 file changed, 124 insertions(+), 5 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b1f09ff328..d414607a58 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1,15 +1,129 @@ module VCenterDriver -class VirtualMachine - POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE - VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE - - include Memoize +class VirtualMachineFolder + attr_accessor :item, :items def initialize(item) @item = item + @items = {} end + ######################################################################## + # Builds a hash with Datastore-Ref / Datastore to be used as a cache + # @return [Hash] in the form + # { ds_ref [Symbol] => Datastore object } + ######################################################################## + def fetch! + VIClient.get_entities(@item, "VirtualMachine").each do |item| + item_name = item._ref + @items[item_name.to_sym] = VirtualMachine.new(item) + end + end + + ######################################################################## + # Returns a Datastore. Uses the cache if available. + # @param ref [Symbol] the vcenter ref + # @return Datastore + ######################################################################## + def get(ref) + if !@items[ref.to_sym] + rbvmomi_dc = RbVmomi::VIM::Datastore.new(@item._connection, ref) + @items[ref.to_sym] = Datastore.new(rbvmomi_dc) + end + + @items[ref.to_sym] + end +end # class VirtualMachineFolder + +class VirtualMachine + VM_PREFIX_DEFAULT = "one-$i-" + POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE + VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE + + attr_accessor :item + + # clone from template attrs + attr_accessor :vi_client + attr_accessor :vm_prefix + attr_accessor :drv_action + attr_accessor :dfile + attr_accessor :host + + include Memoize + + def initialize(item=nil) + @item = item + end + + # (used in clone_vm) + # @return ClusterComputeResource + def cluster + if @cluster.nil? + ccr_ref = @host['TEMPLATE/VCENTER_CCR'] + @cluster = ClusterComputeResource.new_from_ref(@vi_client, ccr_ref) + end + @cluster + end + + # (used in clone_vm) + # @return RbVmomi::VIM::ResourcePool + def get_rp + req_rp = @drv_action['USER_TEMPLATE/RESOURCE_POOL'] + + if @vi_client.rp_confined? + if req_rp && req_rp != @vi_client.rp + raise "Available resource pool in host [#{@vi_client.rp}]"\ + " does not match requested resource pool"\ + " [#{req_rp}]" + end + + return @vi_client.rp + else + + if req_rp + rps = cluster.resource_pools.select{|r| r._ref == req_rp } + raise "No matching resource pool found (#{req_rp})."if rps.empty? + return rps.first + else + return @cluster.item.resourcePool + end + end + end + + # (used in clone_vm) + # @return RbVmomi::VIM::Datastore + def get_ds + req_ds = @drv_action['USER_TEMPLATE/VCENTER_DATASTORE'] + + if req_ds + dc = cluster.get_dc + + # TODO: add storage pods + + ds_folder = dc.datastore_folder + ds = ds_folder.get(req_ds) + ds_item = ds.item rescue nil + + return ds_item + else + return nil + end + end + + def clone_vm + vm_prefix = @host['TEMPLATE/VM_PREFIX'] + vm_prefix = VM_PREFIX_DEFAULT if vm_prefix.nil? || vm_prefix.empty? + vm_prefix.gsub!("$i", @drv_action['ID']) + + vc_template_ref = @drv_action['USER_TEMPLATE/VCENTER_REF'] + vc_template = RbVmomi::VIM::VirtualMachine(@vi_client.vim, vc_template_ref) + + vcenter_name = vm_prefix + @drv_action['NAME'] + + rp = get_rp + ds = get_ds + + end # @param vm CachedItem (of RbVmomi::VIM::VirtualMachine) def to_one cluster = self["runtime.host.parent.name"] @@ -304,6 +418,11 @@ class VirtualMachine VM_STATE[:unknown] end end + + # TODO check with uuid + def self.new_from_ref(vi_client, ref) + self.new(RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)) + end end # class VirtualMachine end # module VCenterDriver From 6ad8853fb4d6cdc355224824b0948d5e499534bb Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 8 Feb 2017 19:15:35 +0100 Subject: [PATCH 021/297] F #4913: Fix return value problem in XMLElement --- src/oca/ruby/opennebula/xml_element.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/oca/ruby/opennebula/xml_element.rb b/src/oca/ruby/opennebula/xml_element.rb index 4ccd2f8ac7..c9c7b5fce3 100644 --- a/src/oca/ruby/opennebula/xml_element.rb +++ b/src/oca/ruby/opennebula/xml_element.rb @@ -45,6 +45,7 @@ module OpenNebula end end end + @xml end # Builds a XML document From e4e40bab06dccf8cb61760751b37773efd30d7da Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 8 Feb 2017 19:16:45 +0100 Subject: [PATCH 022/297] F #4913: Add network file to vcenter_driver2 --- .../remotes/lib/vcenter_driver/datacenter.rb | 4 ++ .../remotes/lib/vcenter_driver/network.rb | 57 +++++++++++++++++++ src/vmm_mad/remotes/lib/vcenter_driver2.rb | 1 + 3 files changed, 62 insertions(+) create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/network.rb diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index 2eb2d22cce..c1226dccdf 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -59,6 +59,10 @@ class Datacenter VirtualMachineFolder.new(@item.vmFolder) end + def network_folder + NetworkFolder.new(@item.networkFolder) + end + # This is never cached def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref)) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb new file mode 100644 index 0000000000..e427c5afba --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -0,0 +1,57 @@ +module VCenterDriver + +class NetworkFolder + attr_accessor :item, :items + + def initialize(item) + @item = item + @items = {} + end + + ######################################################################## + # Builds a hash with Network-Ref / Network to be used as a cache + # @return [Hash] in the form + # { ds_ref [Symbol] => Network object } + ######################################################################## + def fetch! + VIClient.get_entities(@item, "Network").each do |item| + item_name = item._ref + @items[item_name.to_sym] = Network.new(item) + end + end + + ######################################################################## + # Returns a Network. Uses the cache if available. + # @param ref [Symbol] the vcenter ref + # @return Network + ######################################################################## + def get(ref) + if !@items[ref.to_sym] + rbvmomi_net = RbVmomi::VIM::Network.new(@item._connection, ref) + @items[ref.to_sym] = Network.new(rbvmomi_net) + end + + @items[ref.to_sym] + end +end # class NetworkFolder + +class Network + attr_accessor :item + + def initialize(item) + if !item.instance_of? RbVmomi::VIM::Network + raise "Expecting type 'RbVmomi::VIM::Network'. " << + "Got '#{item.class} instead." + end + + @item = item + end + + # This is never cached + def self.new_from_ref(vi_client, ref) + self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref)) + end +end # class Network + +end # module VCenterDriver + diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb index 905569dee5..8cdc46cdf0 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver2.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver2.rb @@ -54,3 +54,4 @@ require 'datacenter' require 'host' require 'datastore' require 'virtual_machine' +require 'network' From 777270c0c2f00dee8f2e0042367894ea9353e1e5 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 8 Feb 2017 19:18:46 +0100 Subject: [PATCH 023/297] F #4913: virtual machine work in progress part II --- .../lib/vcenter_driver/virtual_machine.rb | 300 +++++++++++++++++- 1 file changed, 283 insertions(+), 17 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index d414607a58..5e0a330e54 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -37,24 +37,28 @@ end # class VirtualMachineFolder class VirtualMachine VM_PREFIX_DEFAULT = "one-$i-" + POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE attr_accessor :item - # clone from template attrs - attr_accessor :vi_client - attr_accessor :vm_prefix - attr_accessor :drv_action - attr_accessor :dfile - attr_accessor :host - include Memoize def initialize(item=nil) @item = item end + ############################################################################ + ############################################################################ + + # clone from template attrs + attr_accessor :vi_client + attr_accessor :vm_prefix + attr_accessor :one_item + # attr_accessor :dfile + attr_accessor :host + # (used in clone_vm) # @return ClusterComputeResource def cluster @@ -68,7 +72,7 @@ class VirtualMachine # (used in clone_vm) # @return RbVmomi::VIM::ResourcePool def get_rp - req_rp = @drv_action['USER_TEMPLATE/RESOURCE_POOL'] + req_rp = one_item['USER_TEMPLATE/RESOURCE_POOL'] if @vi_client.rp_confined? if req_rp && req_rp != @vi_client.rp @@ -82,18 +86,22 @@ class VirtualMachine if req_rp rps = cluster.resource_pools.select{|r| r._ref == req_rp } - raise "No matching resource pool found (#{req_rp})."if rps.empty? - return rps.first + + if rps.empty? + raise "No matching resource pool found (#{req_rp})." + else + return rps.first + end else - return @cluster.item.resourcePool + return cluster.item.resourcePool end end end # (used in clone_vm) - # @return RbVmomi::VIM::Datastore + # @return RbVmomi::VIM::Datastore or nil def get_ds - req_ds = @drv_action['USER_TEMPLATE/VCENTER_DATASTORE'] + req_ds = one_item['USER_TEMPLATE/VCENTER_DATASTORE'] if req_ds dc = cluster.get_dc @@ -110,20 +118,278 @@ class VirtualMachine end end + # (used in clone_vm) + # @return Customization or nil + def get_customization + xpath = "USER_TEMPLATE/VCENTER_CUSTOMIZATION_SPEC" + customization_spec = one_item[xpath] + + if customization_spec.nil? + return nil + end + + begin + custom_spec = @vi_client.vim + .serviceContent + .customizationSpecManager + .GetCustomizationSpec(:name => customization.text) + + if custom_spec && (spec = custom_spec.spec) + return spec + else + raise "Error getting customization spec" + end + rescue + raise "Customization spec '#{customization.text}' not found" + end + end + def clone_vm vm_prefix = @host['TEMPLATE/VM_PREFIX'] vm_prefix = VM_PREFIX_DEFAULT if vm_prefix.nil? || vm_prefix.empty? - vm_prefix.gsub!("$i", @drv_action['ID']) + vm_prefix.gsub!("$i", one_item['ID']) - vc_template_ref = @drv_action['USER_TEMPLATE/VCENTER_REF'] + vc_template_ref = one_item['USER_TEMPLATE/VCENTER_REF'] vc_template = RbVmomi::VIM::VirtualMachine(@vi_client.vim, vc_template_ref) - vcenter_name = vm_prefix + @drv_action['NAME'] + vcenter_name = vm_prefix + one_item['NAME'] + + # Relocate spec + relocate_spec_params = {} + + relocate_spec_params[:pool] = get_rp - rp = get_rp ds = get_ds + if ds + relocate_spec_params[:datastore] = ds + relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking + end + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + relocate_spec_params) + + # Running flag - prevents spurious poweroff states in the VM + running_flag = [{ :key => "opennebula.vm.running", :value => "no"}] + + running_flag_spec = RbVmomi::VIM.VirtualMachineConfigSpec( + {:extraConfig => running_flag}) + + clone_parameters = { + :location => relocate_spec, + :powerOn => false, + :template => false, + :config => running_flag_spec + } + + cs = get_customization + clone_parameters[:customization] = cs if cs + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(clone_parameters) + + # TODO storpod (L2575 vcenter_driver.rb) + + begin + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => vcenter_name, + :spec => clone_spec).wait_for_completion + rescue Exception => e + if !e.message.start_with?('DuplicateName') + raise "Cannot clone VM Template: #{e.message}" + end + + vm_folder = cluster.get_dc.vm_folder + vm_folder.fetch! + vm = vm_folder.items + .select{|k,v| v.item.name == vcenter_name} + .values.first.item rescue nil + + if vm + vm.Destroy_Task.wait_for_completion + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => vcenter_name, + :spec => clone_spec).wait_for_completion + else + raise "Cannot clone VM Template" + end + end + + # @item is populated + + @item = item + + reconfigure + poweron + set_running(true) + + return @item._ref end + + ############################################################################ + ############################################################################ + # these have @item populated + + + # spec_hash + # :device_change + # :numCPUs + # :memoryMB + # :extraconfig + # :vmid + # :context + # :vnc + # :opennebula.hotplugged_nics + def reconfigure + spec_hash = {} + extraconfig = [] + + # get vmid + extraconfig << spec_hash_vmid + + # get token + extraconfig << spec_hash_context + + # vnc configuration (for config_array hash) + extraconfig << spec_hash_vnc + + # extraconfig + spec_hash.merge({:extraConfig => extraconfig}) + + # device_change hash (nics) + spec_hash.merge(spec_hash_nics) + + # device_change hash (disks) + spec_hash.merge(spec_hash_disks) + + binding.pry + # + end + + def spec_hash_vmid + { :key => "opennebula.vm.id", :value => one_item['ID'] } + end + + def spec_hash_context + # TODO: migrator to 5.4 (create token.sh) + context_text = "# Context variables generated by OpenNebula\n" + one_item.each('TEMPLATE/CONTEXT/*') do |context_element| + # next if !context_element.text + context_text += context_element.name + "='" + + context_element.text.gsub("'", "\\'") + "'\n" + end + + # token + token = File.read(File.join(VAR_LOCATION, + 'vms', + one_item['ID'], + 'token.txt')).chomp rescue nil + + context_text += "ONEGATE_TOKEN='#{token}'\n" if token + + # context_text + [ + { :key => "guestinfo.opennebula.context", :value => context_text } + ] + end + + def spec_hash_vnc + vnc_port = one_item["TEMPLATE/GRAPHICS/PORT"] + vnc_listen = one_item["TEMPLATE/GRAPHICS/LISTEN"] || "0.0.0.0" + vnc_keymap = one_item["TEMPLATE/GRAPHICS/KEYMAP"] + + conf = [ {:key => "remotedisplay.vnc.enabled",:value => "TRUE"}, + {:key => "remotedisplay.vnc.port", :value => vnc_port}, + {:key => "remotedisplay.vnc.ip", :value => vnc_listen}] + + conf += [{:key => "remotedisplay.vnc.keymap", + :value => vnc_keymap}] if vnc_keymap + + conf + end + + def spec_hash_nics + nics = [] + one_item.each("TEMPLATE/NIC") { |nic| nics << nic } + + if !is_new? + # TODO: review + nic_array = [] + + # Get MACs from NICs inside VM template + one_mac_addresses = [] + + nics.each{|nic| + one_mac_addresses << nic.elements["MAC"].text + } rescue nil + + # B4897 - Get mac of NICs that were hot-plugged from vCenter extraConfig + hotplugged_nics = [] + extraconfig_nics = vm.config.extraConfig.select do |val| + val[:key] == "opennebula.hotplugged_nics" + end + + if extraconfig_nics && !extraconfig_nics.empty? + hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") + end + + vm.config.hardware.device.each{ |dv| + if is_nic?(dv) + nics.each{|nic| + if nic.elements["MAC"].text == dv.macAddress + nics.delete(nic) + end + } rescue nil + + # B4897 - Remove detached NICs from vCenter that were unplugged in POWEROFF + if !one_mac_addresses.include?(dv.macAddress) && hotplugged_nics.include?(dv.macAddress) + nic_array << { :operation => :remove, :device => dv} + hotplugged_nics.delete(dv.macAddress) + config_array << { + :key => 'opennebula.hotplugged_nics', + :value => hotplugged_nics.join(";") + } + end + end + } + + device_change += nic_array + end + + return if nics.nil? + + if nics + + end + end + + def spec_hash_disks + if is_new? + end + end + + def poweron + end + + def set_running(state) + end + + def one_item + # TODO: fetch one_item if it doesn't exist + @one_item + end + + def is_new? + vm_id = vm['config.extraConfig'].select do |o| + o.key == "opennebula.vm.id" + end.first.value rescue nil + + !vm_id + end + + ############################################################################ + ############################################################################ + # @param vm CachedItem (of RbVmomi::VIM::VirtualMachine) def to_one cluster = self["runtime.host.parent.name"] From 7107282a15f7ca02a5252a99d5f2e919d28f7908 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Thu, 9 Feb 2017 16:59:14 +0100 Subject: [PATCH 024/297] F #4913: virtual_machine.rb is now prepared for deploy --- .../lib/vcenter_driver/virtual_machine.rb | 690 ++++++++++++++---- 1 file changed, 558 insertions(+), 132 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 5e0a330e54..ce062c33b4 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -52,38 +52,79 @@ class VirtualMachine ############################################################################ ############################################################################ - # clone from template attrs - attr_accessor :vi_client - attr_accessor :vm_prefix + # VM XMLElement attr_accessor :one_item - # attr_accessor :dfile + + # OpenNebula host attr_accessor :host - # (used in clone_vm) + # Target Datastore VMware reference (must be defined when VM is new) + attr_accessor :target_ds_ref + + # Cached vi_client + # @return VIClient instance + def vi_client + if !@vi_client + @item._connection + end + @vi_client + end + + # vi_client setter (must be used when the VM does not exist in vCenter) + def vi_client=(vi_client) + @vi_client = vi_client + end + + # Cached one_item + def one_item + # TODO: fetch one_item if it doesn't exist + @one_item + end + + # one_item setter (must be used when the VM does not exist in vCenter) + def one_item=(one_item) + @one_item = one_item + end + + # Cached cluster # @return ClusterComputeResource def cluster if @cluster.nil? - ccr_ref = @host['TEMPLATE/VCENTER_CCR'] - @cluster = ClusterComputeResource.new_from_ref(@vi_client, ccr_ref) + ccr_ref = @host['TEMPLATE/VCENTER_CCR_REF'] + @cluster = ClusterComputeResource.new_from_ref(vi_client, ccr_ref) end @cluster end - # (used in clone_vm) + ############################################################################ + ############################################################################ + + # @return Boolean whether the VM exists in vCenter + def is_new? + vm_id = self['config.extraConfig'].select do |o| + o.key == "opennebula.vm.id" + end.first.value rescue nil + + !vm_id + end + + ############################################################################ + # Getters + ############################################################################ + # @return RbVmomi::VIM::ResourcePool def get_rp req_rp = one_item['USER_TEMPLATE/RESOURCE_POOL'] - if @vi_client.rp_confined? - if req_rp && req_rp != @vi_client.rp - raise "Available resource pool in host [#{@vi_client.rp}]"\ + if vi_client.rp_confined? + if req_rp && req_rp != vi_client.rp + raise "Available resource pool in host [#{vi_client.rp}]"\ " does not match requested resource pool"\ " [#{req_rp}]" end - return @vi_client.rp + return vi_client.rp else - if req_rp rps = cluster.resource_pools.select{|r| r._ref == req_rp } @@ -93,12 +134,11 @@ class VirtualMachine return rps.first end else - return cluster.item.resourcePool + return cluster['resourcePool'] end end end - # (used in clone_vm) # @return RbVmomi::VIM::Datastore or nil def get_ds req_ds = one_item['USER_TEMPLATE/VCENTER_DATASTORE'] @@ -118,7 +158,6 @@ class VirtualMachine end end - # (used in clone_vm) # @return Customization or nil def get_customization xpath = "USER_TEMPLATE/VCENTER_CUSTOMIZATION_SPEC" @@ -129,7 +168,7 @@ class VirtualMachine end begin - custom_spec = @vi_client.vim + custom_spec = vi_client.vim .serviceContent .customizationSpecManager .GetCustomizationSpec(:name => customization.text) @@ -144,50 +183,63 @@ class VirtualMachine end end - def clone_vm + # @return String image name + def get_img_name(disk) + if disk["PERSISTENT"] == "YES" + return disk["SOURCE"] + else + image_id = disk["IMAGE_ID"] + disk_id = disk["DISK_ID"] + vm_id = one_item['ID'] + + return "one-#{image_id}-#{vm_id}-#{disk_id}.vmdk" + end + end + + # @return VCenterDriver::Datastore datastore where the disk will live under + def get_effective_ds(disk) + if disk["PERSISTENT"] == "YES" + ds_ref = disk["VCENTER_DS_REF"] + else + ds_ref = @target_ds_ref + + if ds_ref.nil? + raise "target_ds_ref must be defined on this object." + end + end + + VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) + end + + # @return String vcenter name + def get_vcenter_name vm_prefix = @host['TEMPLATE/VM_PREFIX'] vm_prefix = VM_PREFIX_DEFAULT if vm_prefix.nil? || vm_prefix.empty? vm_prefix.gsub!("$i", one_item['ID']) - vc_template_ref = one_item['USER_TEMPLATE/VCENTER_REF'] - vc_template = RbVmomi::VIM::VirtualMachine(@vi_client.vim, vc_template_ref) + vm_prefix + one_item['NAME'] + end - vcenter_name = vm_prefix + one_item['NAME'] + ############################################################################ + # Crate and reconfigure VM related methods + ############################################################################ - # Relocate spec - relocate_spec_params = {} + # When creating a new these instance variables must be set beforehand + # @vi_client + # @one_item + # @host + # + # This function creates a new VM from the @one_item XML and returns the + # VMware ref + def clone_vm + vcenter_name = get_vcenter_name - relocate_spec_params[:pool] = get_rp + vc_template_ref = one_item['USER_TEMPLATE/VCENTER_TEMPLATE_REF'] + vc_template = RbVmomi::VIM::VirtualMachine(vi_client.vim, vc_template_ref) - ds = get_ds - if ds - relocate_spec_params[:datastore] = ds - relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking - end - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - relocate_spec_params) - - # Running flag - prevents spurious poweroff states in the VM - running_flag = [{ :key => "opennebula.vm.running", :value => "no"}] - - running_flag_spec = RbVmomi::VIM.VirtualMachineConfigSpec( - {:extraConfig => running_flag}) - - clone_parameters = { - :location => relocate_spec, - :powerOn => false, - :template => false, - :config => running_flag_spec - } - - cs = get_customization - clone_parameters[:customization] = cs if cs - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(clone_parameters) - - # TODO storpod (L2575 vcenter_driver.rb) + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(spec_hash_clone) + vm = nil begin vm = vc_template.CloneVM_Task( :folder => vc_template.parent, @@ -217,7 +269,7 @@ class VirtualMachine # @item is populated - @item = item + @item = vm reconfigure poweron @@ -226,51 +278,88 @@ class VirtualMachine return @item._ref end - ############################################################################ - ############################################################################ - # these have @item populated + + # @return clone parameters spec hash + def spec_hash_clone + # Relocate spec + relocate_spec_params = {} + + relocate_spec_params[:pool] = get_rp + + ds = get_ds + + if ds + relocate_spec_params[:datastore] = ds + relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking + end + + # TODO storpod (L2575 vcenter_driver.rb) + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + relocate_spec_params) + + # Running flag - prevents spurious poweroff states in the VM + running_flag = [{ :key => "opennebula.vm.running", :value => "no"}] + + running_flag_spec = RbVmomi::VIM.VirtualMachineConfigSpec( + { :extraConfig => running_flag } + ) + + clone_parameters = { + :location => relocate_spec, + :powerOn => false, + :template => false, + :config => running_flag_spec + } + + cs = get_customization + clone_parameters[:customization] = cs if cs + + clone_parameters + end - # spec_hash - # :device_change - # :numCPUs - # :memoryMB - # :extraconfig - # :vmid - # :context - # :vnc - # :opennebula.hotplugged_nics def reconfigure - spec_hash = {} - extraconfig = [] + extraconfig = [] + device_change = [] # get vmid - extraconfig << spec_hash_vmid + extraconfig += extraconfig_vmid # get token - extraconfig << spec_hash_context + extraconfig += extraconfig_context # vnc configuration (for config_array hash) - extraconfig << spec_hash_vnc - - # extraconfig - spec_hash.merge({:extraConfig => extraconfig}) + extraconfig += extraconfig_vnc # device_change hash (nics) - spec_hash.merge(spec_hash_nics) + device_change += device_change_nics # device_change hash (disks) - spec_hash.merge(spec_hash_disks) + device_change += device_change_disks - binding.pry - # + num_cpus = one_item["TEMPLATE/VCPU"] || 1 + + spec_hash = { + :numCPUs => num_cpus.to_i, + :memoryMB => one_item["TEMPLATE/MEMORY"], + :extraConfig => extraconfig + } + + spec_hash[:deviceChange] = device_change if !device_change.empty? + + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + self.item.ReconfigVM_Task(:spec => spec).wait_for_completion end - def spec_hash_vmid - { :key => "opennebula.vm.id", :value => one_item['ID'] } + def extraconfig_vmid + [ + { :key => "opennebula.vm.id", :value => one_item['ID'] } + ] end - def spec_hash_context + def extraconfig_context # TODO: migrator to 5.4 (create token.sh) context_text = "# Context variables generated by OpenNebula\n" one_item.each('TEMPLATE/CONTEXT/*') do |context_element| @@ -293,7 +382,7 @@ class VirtualMachine ] end - def spec_hash_vnc + def extraconfig_vnc vnc_port = one_item["TEMPLATE/GRAPHICS/PORT"] vnc_listen = one_item["TEMPLATE/GRAPHICS/LISTEN"] || "0.0.0.0" vnc_keymap = one_item["TEMPLATE/GRAPHICS/KEYMAP"] @@ -308,24 +397,30 @@ class VirtualMachine conf end - def spec_hash_nics + def device_change_nics + # Final list of changes to be applied in vCenter + device_change = [] + + # List of interfaces from the OpenNebula template nics = [] one_item.each("TEMPLATE/NIC") { |nic| nics << nic } + # Remove detached nics in poweroff if !is_new? - # TODO: review - nic_array = [] + # To be included in device_change + detach_nic_array = [] # Get MACs from NICs inside VM template one_mac_addresses = [] + nics.each do |nic| + one_mac_addresses << nic["MAC"] + end rescue nil - nics.each{|nic| - one_mac_addresses << nic.elements["MAC"].text - } rescue nil - - # B4897 - Get mac of NICs that were hot-plugged from vCenter extraConfig + # B4897 - Get mac of NICs that were hot-plugged from vCenter + # extraConfig + # Get opennebula.hotplugged_nics attribute from the vCenter object hotplugged_nics = [] - extraconfig_nics = vm.config.extraConfig.select do |val| + extraconfig_nics = self["config.extraConfig"].select do |val| val[:key] == "opennebula.hotplugged_nics" end @@ -333,61 +428,395 @@ class VirtualMachine hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") end - vm.config.hardware.device.each{ |dv| + self["config.hardware.device"].each do |dv| if is_nic?(dv) - nics.each{|nic| - if nic.elements["MAC"].text == dv.macAddress - nics.delete(nic) - end - } rescue nil + # nics array will contain the list of nics to be attached + nics.each do |nic| + if nic["MAC"] == dv.macAddress + nics.delete(nic) + end + end - # B4897 - Remove detached NICs from vCenter that were unplugged in POWEROFF - if !one_mac_addresses.include?(dv.macAddress) && hotplugged_nics.include?(dv.macAddress) - nic_array << { :operation => :remove, :device => dv} - hotplugged_nics.delete(dv.macAddress) - config_array << { - :key => 'opennebula.hotplugged_nics', - :value => hotplugged_nics.join(";") - } - end + # if the nic is in the list opennebula.hotplugged_nics and + # not in the list of the OpenNebula NICs we can remove it. + # B4897 - Remove detached NICs from vCenter that were unplugged + # in POWEROFF + if !one_mac_addresses.include?(dv.macAddress) && + hotplugged_nics.include?(dv.macAddress) + + detach_nic_array << { + :operation => :remove, + :device => dv + } + + hotplugged_nics.delete(dv.macAddress) + config_array << { + :key => 'opennebula.hotplugged_nics', + :value => hotplugged_nics.join(";") + } + end end + end + + device_change += detach_nic_array + end + + return if nics.empty? + + # Attach new nics (nics now contains only the interfaces not present + # in the VM in vCenter) + attach_nic_array = [] + nics.each do |nic| + attach_nic_array << calculate_add_nic_spec(nic) + end + + attach_nic_array + end + + # Returns an array of actions to be included in :deviceChange + def calculate_add_nic_spec(nic) + mac = nic["MAC"] + bridge = nic["BRIDGE"] + model = nic["MODEL"] + backing = nil + + limit_in = nic["INBOUND_PEAK_BW"] + limit_out = nic["OUTBOUND_PEAK_BW"] + limit = nil + + if limit_in && limit_out + limit=([limit_in.to_i, limit_out.to_i].min / 1024) * 8 + end + + rsrv_in = nic["INBOUND_AVG_BW"] + rsrv_out = nic["OUTBOUND_AVG_BW"] + rsrv = nil + + if rsrv_in || rsrv_out + rsrv=([rsrv_in.to_i, rsrv_out.to_i].min / 1024) * 8 + end + + network = self["runtime.host.network"].select do |n| + n.name == bridge + end + + if network.empty? + raise "Network #{bridge} not found in host #{self['runtime.host.name']}" + else + network = network.first + end + + card_num = 1 # start in one, we want the next avaliable id + + self["config.hardware.device"].each do |dv| + card_num += 1 if is_nic?(dv) + end + + nic_card = case model + when "virtuale1000", "e1000" + RbVmomi::VIM::VirtualE1000 + when "virtuale1000e", "e1000e" + RbVmomi::VIM::VirtualE1000e + when "virtualpcnet32", "pcnet32" + RbVmomi::VIM::VirtualPCNet32 + when "virtualsriovethernetcard", "sriovethernetcard" + RbVmomi::VIM::VirtualSriovEthernetCard + when "virtualvmxnetm", "vmxnetm" + RbVmomi::VIM::VirtualVmxnetm + when "virtualvmxnet2", "vmnet2" + RbVmomi::VIM::VirtualVmxnet2 + when "virtualvmxnet3", "vmxnet3" + RbVmomi::VIM::VirtualVmxnet3 + else # If none matches, use VirtualE1000 + RbVmomi::VIM::VirtualE1000 + end + + if network.class == RbVmomi::VIM::Network + backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( + :deviceName => bridge, + :network => network) + else + port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( + :switchUuid => + network.config.distributedVirtualSwitch.uuid, + :portgroupKey => network.key) + backing = + RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( + :port => port) + end + + card_spec = { + :key => 0, + :deviceInfo => { + :label => "net" + card_num.to_s, + :summary => bridge + }, + :backing => backing, + :addressType => mac ? 'manual' : 'generated', + :macAddress => mac + } + + if (limit || rsrv) && (limit > 0) + ra_spec = {} + rsrv = limit if rsrv > limit + ra_spec[:limit] = limit if limit + ra_spec[:reservation] = rsrv if rsrv + ra_spec[:share] = RbVmomi::VIM.SharesInfo({ + :level => RbVmomi::VIM.SharesLevel("normal"), + :shares => 0 + }) + card_spec[:resourceAllocation] = + RbVmomi::VIM.VirtualEthernetCardResourceAllocation(ra_spec) + end + + { + :operation => :add, + :device => nic_card.new(card_spec) + } + end + + # Checks if a RbVmomi::VIM::VirtualDevice is a network interface + def is_nic?(device) + !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? + end + + def device_change_disks + disks = [] + one_item.each("TEMPLATE/DISK") { |disk| disks << disk } + + if !is_new? + self["config.hardware.device"].each do |d| + if is_disk_or_cdrom?(d) + disks.each do |disk| + if d.backing.respond_to?(:fileName) && + get_img_name(disk) == d.backing.fileName + + disks.delete(disk) + end + end + end + end + end + + return if disks.nil? + + position = 0 + attach_disk_array = [] + disks.each do |disk| + attach_disk_array << calculate_add_disk_spec(disk) + position += 1 + end + + attach_disk_array + end + + def calculate_add_disk_spec(disk, position=0) + img_name = get_img_name(disk) + ds = get_effective_ds(disk) + + ds_name = ds['name'] + type = disk["TYPE"] + + # TODO: size_kb = 0 ?? + size_kb = 0 + + controller, new_number = find_free_controller(position) + + if type == "CDROM" + vmdk_backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo( + :datastore => ds.item, + :fileName => "[#{ds_name}] #{img_name}" + ) + + cd = self['config.hardware.device'].select do |hw| + hw.class == RbVmomi::VIM::VirtualCdrom + end.first + + # If no CDROM drive present, we need to add it + if !cd + controller, _ = find_free_controller + + device = RbVmomi::VIM::VirtualCdrom( + :backing => vmdk_backing, + :key => -1, + :controllerKey => 15000, + :unitNumber => 0, + + :connectable => RbVmomi::VIM::VirtualDeviceConnectInfo( + :startConnected => true, + :connected => true, + :allowGuestControl => true + ) + ) + + return { + :operation => :add, + :device => device + } + else + device = RbVmomi::VIM::VirtualCdrom( + backing: vmdk_backing, + key: cd.key, + controllerKey: cd.controllerKey, + connectable: RbVmomi::VIM::VirtualDeviceConnectInfo( + startConnected: true, + connected: true, + allowGuestControl: true + ) + ) + + return { + :operation => :edit, + :device => device + } + end + else + # TYPE is regular disk (not CDROM) + vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo( + :datastore => ds.item, + :diskMode => 'persistent', + :fileName => "[#{ds_name}] #{img_name}" + ) + + device = RbVmomi::VIM::VirtualDisk( + :backing => vmdk_backing, + :capacityInKB => size_kb, + :controllerKey => controller.key, + :key => -1, + :unitNumber => new_number + ) + + { + :operation => :add, + :device => device } - - device_change += nic_array - end - - return if nics.nil? - - if nics - end end - def spec_hash_disks - if is_new? + # Checks if a RbVmomi::VIM::VirtualDevice is a disk + def is_disk_or_cdrom?(device) + is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? + is_cdrom = !(device.class.ancestors.index(RbVmomi::VIM::VirtualCdrom)).nil? + is_disk || is_cdrom + end + + def find_free_controller(position=0) + free_scsi_controllers = [] + available_controller = nil + scsi_schema = {} + + used_numbers = [] + available_numbers = [] + + self["config.hardware.device"].each do |dev| + if dev.is_a? RbVmomi::VIM::VirtualSCSIController + if scsi_schema[dev.controllerKey].nil? + scsi_schema[dev.key] = {} + end + + used_numbers << dev.scsiCtlrUnitNumber + scsi_schema[dev.key][:device] = dev + end + + next if dev.class != RbVmomi::VIM::VirtualDisk + used_numbers << dev.unitNumber end + + 15.times do |scsi_id| + available_numbers << scsi_id if used_numbers.grep(scsi_id).length <= 0 + end + + scsi_schema.keys.each do |controller| + free_scsi_controllers << scsi_schema[controller][:device].deviceInfo.label + end + + if free_scsi_controllers.length > 0 + available_controller_label = free_scsi_controllers[0] + else + add_new_scsi(scsi_schema) + return find_free_controller + end + + controller = nil + + self['config.hardware.device'].each do |device| + if device.deviceInfo.label == available_controller_label + controller = device + break + end + end + + new_unit_number = available_numbers.sort[position] + + return controller, new_unit_number end - def poweron - end + def add_new_scsi(scsi_schema) + controller = nil - def set_running(state) - end + if scsi_schema.keys.length >= 4 + raise "Cannot add a new controller, maximum is 4." + end - def one_item - # TODO: fetch one_item if it doesn't exist - @one_item - end + if scsi_schema.keys.length == 0 + scsi_key = 0 + scsi_number = 0 + else scsi_schema.keys.length < 4 + scsi_key = scsi_schema.keys.sort[-1] + 1 + scsi_number = scsi_schema[scsi_schema.keys.sort[-1]][:device].busNumber + 1 + end - def is_new? - vm_id = vm['config.extraConfig'].select do |o| - o.key == "opennebula.vm.id" - end.first.value rescue nil + controller_device = RbVmomi::VIM::VirtualLsiLogicController( + :key => scsi_key, + :busNumber => scsi_number, + :sharedBus => :noSharing + ) - !vm_id + device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( + :device => controller_device, + :operation => :add + ) + + vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( + :deviceChange => [device_config_spec] + ) + + self.item.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion + + self["config.hardware.device"].each do |device| + if device.class == RbVmomi::VIM::VirtualLsiLogicController && + device.key == scsi_key + + controller = device.deviceInfo.label + end + end + + return controller end ############################################################################ + # actions + ############################################################################ + + def poweron + self.item.PowerOnVM_Task.wait_for_completion + end + + def set_running(state) + value = state ? "yes" : "no" + + config_array = [ + { :key => "opennebula.vm.running", :value => value } + ] + spec = RbVmomi::VIM.VirtualMachineConfigSpec( + { :extraConfig => config_array } + ) + + self.item.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + ############################################################################ + # monitoring ############################################################################ # @param vm CachedItem (of RbVmomi::VIM::VirtualMachine) @@ -600,9 +1029,7 @@ class VirtualMachine end - ######################################################################## # Generates a OpenNebula IM Driver valid string with the monitor info - ######################################################################## def info return 'STATE=d' if @state == 'd' @@ -665,13 +1092,11 @@ class VirtualMachine } end - ######################################################################## # Converts the VI string state to OpenNebula state convention # Guest states are: # - poweredOff The virtual machine is currently powered off. # - poweredOn The virtual machine is currently powered on. # - suspended The virtual machine is currently suspended. - ######################################################################## def state_to_c(state) case state when 'poweredOn' @@ -689,6 +1114,7 @@ class VirtualMachine def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)) end + end # class VirtualMachine end # module VCenterDriver From 343fbec9bd2431d7d6311758d986018627790b4f Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:07:36 +0100 Subject: [PATCH 025/297] F #4913: New VIHelper class (link between ONE and vCenter) --- .../remotes/lib/vcenter_driver/vi_helper.rb | 34 +++++++++++++++++++ src/vmm_mad/remotes/lib/vcenter_driver2.rb | 1 + 2 files changed, 35 insertions(+) create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb new file mode 100644 index 0000000000..65a683803c --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb @@ -0,0 +1,34 @@ +module VCenterDriver + +class VIHelper + def self.client + @@client ||= OpenNebula::Client.new + end + + def self.return_if_error(rc, item, exit_if_fail) + if OpenNebula::is_error?(rc) + if exit_if_fail + STDERR.puts rc.message + exit 1 + else + rc + end + else + item + end + end + + def self.one_item(the_class, id, exit_if_fail = true) + item = the_class.new_with_id(id, client) + rc = item.info + return_if_error(rc, item, exit_if_fail) + end + + def self.one_pool(the_class, exit_if_fail = true) + item = the_class.new(client) + rc = item.info + return_if_error(rc, item, exit_if_fail) + end +end + +end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb index 8cdc46cdf0..3dfd843648 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver2.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver2.rb @@ -50,6 +50,7 @@ require 'openssl' require 'memoize' require 'vi_client' +require 'vi_helper' require 'datacenter' require 'host' require 'datastore' From 5890dad385b9cf8fbf2851258c8b3a115b65a802 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:08:00 +0100 Subject: [PATCH 026/297] F #4913: deploy action --- src/vmm_mad/remotes/vcenter/deploy | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 31e977d1eb..7f583a59c5 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -16,7 +16,7 @@ # limitations under the License. # # ---------------------------------------------------------------------------- # -ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) +ONE_LOCATION = ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) @@ -27,38 +27,38 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' require 'opennebula' -dfile = ARGV[0] -host = ARGV[1] vm_id = ARGV[2] -drv_action_enc = STDIN.read.gsub("\n","") - drv_action = OpenNebula::XMLElement.new -drv_action.initialize_xml(Base64.decode64(drv_action_enc), - 'VM') +drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VM') -deploy_id = drv_action["/VM/DEPLOY_ID"] -lcm_state_num = drv_action["/VM/LCM_STATE"].to_i -datastore = drv_action["/VM/USER_TEMPLATE/VCENTER_DATASTORE"] -lcm_state = OpenNebula::VirtualMachine::LCM_STATE[lcm_state_num] +host_id = drv_action["/VM/HISTORY_RECORDS/HISTORY/HID"] -ops = { - :ref => drv_action["/VM/USER_TEMPLATE/PUBLIC_CLOUD/VCENTER_REF"], - :name => drv_action["/VM/USER_TEMPLATE/PUBLIC_CLOUD/VCENTER_NAME"] -} +# lcm_state_num = drv_action["/VM/LCM_STATE"].to_i +# lcm_state = OpenNebula::VirtualMachine::LCM_STATE[lcm_state_num] -begin - puts VCenterDriver::VCenterVm.deploy(File.read(dfile), - lcm_state, - deploy_id, - host, - datastore, - ops) -rescue Exception => e - STDERR.puts "Deploy of VM #{vm_id} on host #{host} with #{dfile} failed " + - "due to \"#{e.message}\"\n#{e.backtrace}" +host = OpenNebula::Host.new_with_id(host_id, OpenNebula::Client.new) +rc = host.info +if OpenNebula::is_error?(rc) + STDERR.puts rc.message exit -1 end + +vi_client = VCenterDriver::VIClient.new_from_host(host_id) + +target_ds_id = drv_action['HISTORY_RECORDS/HISTORY[last()]/DS_ID'] +target_ds_one = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) +target_ds_ref = target_ds_one['TEMPLATE/VCENTER_DS_REF'] + +# Clone from template +vm = VCenterDriver::VirtualMachine.new + +vm.vi_client = vi_client +vm.one_item = drv_action +vm.host = host +vm.target_ds_ref = target_ds_ref + +puts vm.clone_vm From d1e0edb7d806d42a01f7953ba39cf8ee8b7afbbf Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:08:22 +0100 Subject: [PATCH 027/297] F #4913: Add memoize to the host class --- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index e06ffb4bdd..e3fa80c9f4 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -28,6 +28,8 @@ end # class HostFolder class ClusterComputeResource attr_accessor :item + include Memoize + def initialize(item) @item = item end From 8aafa045f200508257645d9f1a0f4bf5163afae1 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:08:52 +0100 Subject: [PATCH 028/297] F #4913: Add file management capabilities to the Datastore class --- .../remotes/lib/vcenter_driver/datastore.rb | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 2551103da7..fe18ff1f79 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -38,6 +38,8 @@ end # class DatastoreFolder class Datastore attr_accessor :item + include Memoize + def initialize(item) if !item.instance_of? RbVmomi::VIM::Datastore raise "Expecting type 'RbVmomi::VIM::Datastore'. " << @@ -58,8 +60,7 @@ class Datastore end def create_virtual_disk(dc, img_name, size, adapter_type, disk_type) - vdm = @item._connection.serviceContent.virtualDiskManager - ds_name = @item.name + ds_name = self['name'] vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( :adapterType => adapter_type, @@ -67,7 +68,7 @@ class Datastore :diskType => disk_type ) - vdm.CreateVirtualDisk_Task( + get_vdm.CreateVirtualDisk_Task( :datacenter => dc.item, :name => "[#{ds_name}] #{img_name}.vmdk", :spec => vmdk_spec @@ -77,15 +78,48 @@ class Datastore end def delete_virtual_disk(dc, img_name) - vdm = @item._connection.serviceContent.virtualDiskManager - ds_name = @item.name + ds_name = self['name'] - vdm.DeleteVirtualDisk_Task( + get_vdm.DeleteVirtualDisk_Task( name: "[#{ds_name}] #{img_name}", datacenter: dc.item ).wait_for_completion end + # Copy a VirtualDisk + # @param ds_name [String] name of the datastore + # @param img_str [String] path to the VirtualDisk + def copy_virtual_disk(src_path, target_ds_name, target_path) + source_ds_name = self['name'] + + copy_params = { + :sourceName => "[#{source_ds_name}] #{src_path}", + :sourceDatacenter => get_dc.item, + :destName => "[#{target_ds_name}] #{target_path}" + } + + get_vdm.CopyVirtualDisk_Task(copy_params).wait_for_completion + + target_path + end + + def get_vdm + self['_connection.serviceContent.virtualDiskManager'] + end + + def get_dc + item = @item + + while !item.instance_of? RbVmomi::VIM::Datacenter + item = item.parent + if item.nil? + raise "Could not find the parent Datacenter" + end + end + + Datacenter.new(item) + end + # This is never cached def self.new_from_ref(vi_client, ref) self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref)) From e64a361a0bd2b1430459feb99a50646c6b1b505a Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:09:13 +0100 Subject: [PATCH 029/297] F #4913: tm/clone now does its work --- src/tm_mad/vcenter/clone | 80 ++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index 2ea33c32fe..1c663d7d29 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -36,8 +36,7 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'opennebula' -require 'vcenter_driver' -require 'digest' +require 'vcenter_driver2' ################################################################################ @@ -49,6 +48,18 @@ def check_valid(parameter, label) end end +def get_ds(ds_id, client) + ds = OpenNebula::Datastore.new_with_id(ds_id, client) + + rc = ds.info + if OpenNebula::is_error?(rc) + STDERR.puts(rc.message) + exit -1 + end + + ds +end + ################################################################################ src = ARGV[0] @@ -62,42 +73,41 @@ disk_id = dst.split(".")[-1] src_host, src_path = src.split ":" hostname, dst_path = dst.split ":" -client = OpenNebula::Client.new -ds_pool = OpenNebula::DatastorePool.new(client) - -rc = ds_pool.info -if OpenNebula.is_error?(rc) - puts rc.message - exit -1 -end - -xml = "/DATASTORE_POOL/DATASTORE[ID='#{source_ds_id}']/TEMPLATE/VCENTER_NAME" -source_ds = ds_pool[xml] - -xml = "/DATASTORE_POOL/DATASTORE[ID='#{target_ds_id}']/TEMPLATE/VCENTER_NAME" -target_ds = ds_pool[xml] - ################################################################################ -# Generate target path -target_path = "one_#{vm_id}_#{disk_id}.vmdk" +host_pool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool) -################################################################################ +# host_id +host = host_pool.select{|host| host['NAME'] == hostname}[0] rescue nil -# Check for errors -check_valid source_ds, "source_ds" -check_valid target_ds, "target_ds" -check_valid hostname, "hostname" -check_valid src_path, "src_path" - -################################################################################ - -begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id - - vi_client.copy_virtual_disk(src_path, source_ds, target_path, target_ds) -rescue Exception => e - STDERR.puts "Error cloning img #{src_path} size. Reason: #{e.message}" +if host.nil? + STDERR.puts "No host found (#{hostname})." exit -1 end + +host_id = host['ID'] + +# get ds_ref (source image) +source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id) +source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] + +target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) +target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] + +# calculate target path +target_path = src_path.split(".").first + "-#{vm_id}-#{disk_id}.vmdk" + +# vi_client +vi_client = VCenterDriver::VIClient.new_from_host(host_id) + +source_ds_vc = VCenterDriver::Datastore.new_from_ref(vi_client, source_ds_ref) + +if source_ds_ref == target_ds_ref + target_ds_vc = source_ds_vc +else + target_ds_vc = VCenterDriver::Datastore.new_from_ref(vi_client, target_ds_ref) +end + +target_ds_name_vc = target_ds_vc['name'] + +source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) From c9d0b35ea274a070465b37a8c1abc2c5da6d196a Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:10:02 +0100 Subject: [PATCH 030/297] F #4913: adjust the vcenter model representation --- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/datastore_mad/remotes/vcenter/monitor | 2 +- src/datastore_mad/remotes/vcenter/rm | 2 +- src/im_mad/remotes/vcenter.d/vcenter.rb | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index fe9f36132a..a0a022469a 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -52,7 +52,7 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_REF"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] dc_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DC_REF"] img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 7cc9efaf0f..ef022dccb0 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -41,7 +41,7 @@ drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_REF"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] if host_id.nil? || ds_ref.nil? STDERR.puts "Not enough information to monitor the image." diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index c22ee8c1c7..b73ea043f7 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -52,7 +52,7 @@ id = ARGV[1] drv_action =OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_REF"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] dc_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DC_REF"] img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index 0b82b0d3dc..612bcb57b1 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -46,10 +46,10 @@ if OpenNebula::is_error? rc exit 1 end -ccr = host["TEMPLATE/VCENTER_CCR"] +ccr_ref = host["TEMPLATE/VCENTER_CCR_REF"] # Get vCenter Cluster -cluster = VCenterDriver::ClusterComputeResource.new_from_ref(vi_client, ccr) +cluster = VCenterDriver::ClusterComputeResource.new_from_ref(vi_client, ccr_ref) # Print monitoring info puts cluster.monitor From 42c03f918c38d46c56b5411fb031f2087a48b8d0 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:11:19 +0100 Subject: [PATCH 031/297] F #4913: Modify inherit attributes to support the new model --- share/etc/oned.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/share/etc/oned.conf b/share/etc/oned.conf index d2058104cf..41f1ad7129 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -887,6 +887,7 @@ INHERIT_DATASTORE_ATTR = "GLUSTER_VOLUME" INHERIT_DATASTORE_ATTR = "DISK_TYPE" INHERIT_DATASTORE_ATTR = "ADAPTER_TYPE" +INHERIT_DATASTORE_ATTR = "VCENTER_DS_REF" INHERIT_IMAGE_ATTR = "DISK_TYPE" INHERIT_IMAGE_ATTR = "ADAPTER_TYPE" @@ -902,6 +903,8 @@ INHERIT_VNET_ATTR = "OUTBOUND_AVG_BW" INHERIT_VNET_ATTR = "OUTBOUND_PEAK_BW" INHERIT_VNET_ATTR = "OUTBOUND_PEAK_KB" +INHERIT_VNET_ATTR = "VCENTER_NET_REF" + #******************************************************************************* # Transfer Manager Driver Behavior Configuration #******************************************************************************* From 6214e6e9b568ec2f4c0f35ef366ac035cfbe5a02 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 11:16:17 +0100 Subject: [PATCH 032/297] F #4913: Fix vCenter client for Ruby 2.4 (crypt token must be 32bytes) --- .../server_cipher/server_cipher_auth.rb | 8 +++-- .../remotes/lib/vcenter_driver/vi_client.rb | 32 ++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb b/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb index eb99d706ca..51001698a6 100644 --- a/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb +++ b/src/authm_mad/remotes/server_cipher/server_cipher_auth.rb @@ -39,12 +39,13 @@ class OpenNebula::ServerCipherAuth @srv_passwd = srv_passwd if !srv_passwd.empty? - @key = Digest::SHA1.hexdigest(@srv_passwd) + # truncate token to 32-bytes for Ruby >= 2.4 + @key = Digest::SHA1.hexdigest(@srv_passwd)[0..31] else @key = "" end - @cipher = OpenSSL::Cipher::Cipher.new(CIPHER) + @cipher = OpenSSL::Cipher.new(CIPHER) end ########################################################################### @@ -109,7 +110,8 @@ class OpenNebula::ServerCipherAuth # auth method for auth_mad def authenticate(srv_user,srv_pass, signed_text) begin - @key = srv_pass + # truncate token to 32-bytes for Ruby >= 2.4 + @key = srv_pass[0..31] s_user, t_user, expires = decrypt(signed_text).split(':') diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 933003b777..94ac06f412 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -56,27 +56,35 @@ class VIClient token = config["ONE_KEY"] - begin - cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") - - cipher.decrypt - cipher.key = token - - password = cipher.update(Base64::decode64(password)) - password << cipher.final - rescue - puts "Error decrypting vCenter password" - exit -1 - end + password = VIClient::decrypt(password, token) connection = { :host => host["TEMPLATE/VCENTER_HOST"], :user => host["TEMPLATE/VCENTER_USER"], + :rp => host["TEMPLATE/VCENTER_RESOURCE_POOL"], :password => password } self.new(connection) end + + def self.decrypt(msg, token) + begin + cipher = OpenSSL::Cipher.new("aes-256-cbc") + + cipher.decrypt + + # Truncate for Ruby 2.4 (in previous versions this was being + # automatically truncated) + cipher.key = token[0..31] + + msg = cipher.update(Base64::decode64(msg)) + msg << cipher.final + rescue + puts "Error decrypting secret." + exit -1 + end + end end end # module VCenterDriver From ec07c889c818a063d5c56beac527a6b3b8591b19 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 12:45:44 +0100 Subject: [PATCH 033/297] F #4913: handle vi_client in a smarter way and use proper ruby syntax --- .../lib/vcenter_driver/virtual_machine.rb | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index ce062c33b4..85bbe95d84 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -61,23 +61,19 @@ class VirtualMachine # Target Datastore VMware reference (must be defined when VM is new) attr_accessor :target_ds_ref - # Cached vi_client - # @return VIClient instance - def vi_client - if !@vi_client - @item._connection - end - @vi_client - end - # vi_client setter (must be used when the VM does not exist in vCenter) - def vi_client=(vi_client) - @vi_client = vi_client - end + attr_accessor :vi_client # Cached one_item def one_item - # TODO: fetch one_item if it doesn't exist + if @one_item.nil? + vm_id = get_vm_id + + raise "Unable to find vm_id." if vm_id.nil? + + @one_item = VIHelper.one_item(OpenNebula::VirtualMachine, vm_id) + end + @one_item end @@ -101,11 +97,14 @@ class VirtualMachine # @return Boolean whether the VM exists in vCenter def is_new? + !get_vm_id + end + + # @return String the vm_id stored in vCenter + def get_vm_id vm_id = self['config.extraConfig'].select do |o| o.key == "opennebula.vm.id" end.first.value rescue nil - - !vm_id end ############################################################################ @@ -350,7 +349,7 @@ class VirtualMachine spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - self.item.ReconfigVM_Task(:spec => spec).wait_for_completion + @item.ReconfigVM_Task(:spec => spec).wait_for_completion end def extraconfig_vmid @@ -781,7 +780,7 @@ class VirtualMachine :deviceChange => [device_config_spec] ) - self.item.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion + @item.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion self["config.hardware.device"].each do |device| if device.class == RbVmomi::VIM::VirtualLsiLogicController && @@ -799,7 +798,7 @@ class VirtualMachine ############################################################################ def poweron - self.item.PowerOnVM_Task.wait_for_completion + @item.PowerOnVM_Task.wait_for_completion end def set_running(state) @@ -812,7 +811,7 @@ class VirtualMachine { :extraConfig => config_array } ) - self.item.ReconfigVM_Task(:spec => spec).wait_for_completion + @item.ReconfigVM_Task(:spec => spec).wait_for_completion end ############################################################################ From 9d16d397a4bfd0031137889c93f701a853849659 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 12:46:20 +0100 Subject: [PATCH 034/297] F #4913: Enable network performance monitor --- .../lib/vcenter_driver/virtual_machine.rb | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 85bbe95d84..aee8dab60d 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -910,35 +910,30 @@ class VirtualMachine @guest_ip_addresses = guest_ip_addresses.join(',') -=begin + ######################################################################## # PerfManager metrics - pm = @client.vim.serviceInstance.content.perfManager + ######################################################################## + require 'pry' + + pm = self['_connection'].serviceInstance.content.perfManager + + provider = pm.provider_summary(@item) - provider = pm.provider_summary [@vm].first refresh_rate = provider.refreshRate - vmid = -1 - extraconfig_vmid = @vm.config.extraConfig.select{|val| - val[:key]=="opennebula.vm.id"} - if extraconfig_vmid.size > 0 and extraconfig_vmid[0] - vmid = extraconfig_vmid[0][:value].to_i - end - - if vmid < 0 - @nettx = 0 - @netrx = 0 + if !get_vm_id + @nettx = 0 + @netrx = 0 @diskrdbytes = 0 @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 + @diskrdiops = 0 + @diskwriops = 0 else - one_vm = OpenNebula::VirtualMachine.new_with_id(vmid, OpenNebula::Client.new) - one_vm.info stats = [] - if(one_vm["MONITORING/LAST_MON"] && one_vm["MONITORING/LAST_MON"].to_i != 0 ) + if (one_item["MONITORING/LAST_MON"] && one_item["MONITORING/LAST_MON"].to_i != 0 ) #Real time data stores max 1 hour. 1 minute has 3 samples - interval = (Time.now.to_i - one_vm["MONITORING/LAST_MON"].to_i) + interval = (Time.now.to_i - one_item["MONITORING/LAST_MON"].to_i) #If last poll was more than hour ago get 3 minutes, #else calculate how many samples since last poll @@ -946,7 +941,7 @@ class VirtualMachine max_samples = samples > 0 ? samples : 1 stats = pm.retrieve_stats( - [@vm], + [@item], ['net.transmitted','net.bytesRx','net.bytesTx','net.received', 'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged', 'virtualDisk.read','virtualDisk.write'], @@ -955,7 +950,7 @@ class VirtualMachine else # First poll, get at least latest 3 minutes = 9 samples stats = pm.retrieve_stats( - [@vm], + [@item], ['net.transmitted','net.bytesRx','net.bytesTx','net.received', 'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged', 'virtualDisk.read','virtualDisk.write'], @@ -1022,10 +1017,9 @@ class VirtualMachine @diskwriops = write_iops @diskrdbytes = (read_kbpersec * 1024 * refresh_rate).to_i @diskwrbytes = (write_kbpersec * 1024 * refresh_rate).to_i + @diskwrbytes = (write_kbpersec * 1024 * refresh_rate).to_i end end -=end - end # Generates a OpenNebula IM Driver valid string with the monitor info From 9fc2bcc86f6688bb20971364d651e7ff0a27315b Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Fri, 10 Feb 2017 14:11:22 +0100 Subject: [PATCH 035/297] F #4913: monitor datastores and customizations --- src/im_mad/remotes/vcenter.d/vcenter.rb | 9 ++++++--- .../remotes/lib/vcenter_driver/datastore.rb | 15 +++++++++++++++ src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 17 +++++++++++++++++ .../remotes/lib/vcenter_driver/vi_client.rb | 1 + 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index 612bcb57b1..784c5641b1 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -61,6 +61,9 @@ if !vm_monitor_info.empty? puts vm_monitor_info end -# TODO: monitor network metrics in 'monitor_vms' -# TODO: monitor_customizations -# TODO: get_available_ds +puts cluster.monitor_customizations + +dc = cluster.get_dc +ds_folder = dc.datastore_folder +ds_folder.fetch! +puts ds_folder.monitor diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index fe18ff1f79..7d59bcb15e 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -18,6 +18,21 @@ class DatastoreFolder item_name = item._ref @items[item_name.to_sym] = Datastore.new(item) end + + VIClient.get_entities(@item, "StoragePod").each do |sp| + VIClient.get_entities(sp, "Datastore").each do |item| + item_name = item._ref + @items[item_name.to_sym] = Datastore.new(item) + end + end + end + + def monitor + monitor = "" + @items.values.each do |ds| + monitor << "VCENTER_DATASTORE=\"#{ds['name']}\"\n" + end + monitor end ######################################################################## diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index e3fa80c9f4..f7757d4f9c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -241,6 +241,23 @@ class ClusterComputeResource return str_info.gsub(/^\s+/,"") end + + def monitor_customizations + customizations = self['_connection'].serviceContent.customizationSpecManager.info + + text = '' + + customizations.each do |c| + t = "CUSTOMIZATION = [ " + t << %Q + t << %Q + + text << t + end + + text + end + def get_dc item = @item diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 94ac06f412..71e6f3c9d5 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -18,6 +18,7 @@ class VIClient !!@rp end + # @return RbVmomi::VIM:: objects def self.get_entities(folder, type, entities=[]) if folder == [] return nil From 2b84f23ef0398c755227b2d7aebdfb8c40c14361 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Sun, 12 Feb 2017 21:52:39 +0100 Subject: [PATCH 036/297] F #4913: adds retrieve_xmlelements Easy way to obtain XMLElements from an xpath --- src/oca/ruby/opennebula/xml_element.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/oca/ruby/opennebula/xml_element.rb b/src/oca/ruby/opennebula/xml_element.rb index c9c7b5fce3..2225b29f30 100644 --- a/src/oca/ruby/opennebula/xml_element.rb +++ b/src/oca/ruby/opennebula/xml_element.rb @@ -168,6 +168,23 @@ module OpenNebula end + # Iterates over every Element in the XPath and returns an array + # with XMLElements + # @return [XMLElement] + def retrieve_xmlelements(xpath_str) + collection = [] + if NOKOGIRI + @xml.xpath(xpath_str).each { |pelem| + collection << XMLElement.new(pelem) + } + else + @xml.elements.each(xpath_str) { |pelem| + collection << XMLElement.new(pelem) + } + end + collection + end + # Gets an attribute from an element # key:: _String_ xpath for the element # name:: _String_ name of the attribute From 97ce81ceb84c6c7b327f675736726ddc8450e581 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Sun, 12 Feb 2017 21:53:24 +0100 Subject: [PATCH 037/297] F #4913: adds find_by_name, to retrieve an OpenNebula element by name --- src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb index 65a683803c..b02779e973 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb @@ -29,6 +29,16 @@ class VIHelper rc = item.info return_if_error(rc, item, exit_if_fail) end + + def self.find_by_name(the_class, name, exit_if_fail = true) + pool = one_pool(the_class) + element = pool.select{|e| e['NAME'] == name }.first rescue nil + if element.nil? + raise "Could not find element '#{name}' in pool '#{the_class}'" + else + element + end + end end end From 7a270393bef822665d6d6ff50c013b28b873fb14 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Sun, 12 Feb 2017 21:54:22 +0100 Subject: [PATCH 038/297] F #4913: poweroff action --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index aee8dab60d..b2f8803de4 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -801,6 +801,10 @@ class VirtualMachine @item.PowerOnVM_Task.wait_for_completion end + def poweroff_hard + @item.PowerOffVM_Task.wait_for_completion + end + def set_running(state) value = state ? "yes" : "no" From 9897251d4ae09e04947ae8edbd828ccb85869210 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 12:41:30 +0100 Subject: [PATCH 039/297] Change mysql gem to mysql2 --- share/install_gems/Gemfile | 2 +- share/install_gems/install_gems | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/share/install_gems/Gemfile b/share/install_gems/Gemfile index 217a2bb66f..57ffa22a5f 100644 --- a/share/install_gems/Gemfile +++ b/share/install_gems/Gemfile @@ -32,7 +32,7 @@ gem 'trollop' # vmware gem 'parse-cron' # oneflow gem 'aws-sdk', '~> 2.5' # ec2_hybrid gem 'ox' # oca -gem 'mysql' # onedb +gem 'mysql2' # onedb diff --git a/share/install_gems/install_gems b/share/install_gems/install_gems index 81890f9b21..563aa12fe5 100755 --- a/share/install_gems/install_gems +++ b/share/install_gems/install_gems @@ -42,7 +42,7 @@ GROUPS={ :ec2_hybrid => 'aws-sdk --version "~> 2.5"', :oca => 'ox', :market => 'aws-sdk', - :onedb => "mysql" + :onedb => "mysql2" } PACKAGES=GROUPS.keys @@ -58,7 +58,7 @@ DISTRIBUTIONS={ :dependencies_common => ['ruby-dev', 'make'], :dependencies => { SQLITE => ['gcc', 'libsqlite3-dev'], - 'mysql' => ['gcc', 'libmysqlclient-dev'], + 'mysql2' => ['gcc', 'libmysqlclient-dev'], 'curb' => ['gcc', 'libcurl4-openssl-dev'], $nokogiri => %w{gcc rake libxml2-dev libxslt1-dev patch}, 'xmlparser' => ['gcc', 'libexpat1-dev'], @@ -76,7 +76,7 @@ DISTRIBUTIONS={ :dependencies_common => ['ruby-devel', 'make'], :dependencies => { SQLITE => ['gcc', 'sqlite-devel'], - 'mysql' => ['gcc', 'mysql-devel', 'openssl-devel'], + 'mysql2' => ['gcc', 'mysql-devel', 'openssl-devel'], 'curb' => ['gcc', 'curl-devel'], $nokogiri => %w{gcc rubygem-rake libxml2-devel libxslt-devel patch}, 'xmlparser' => ['gcc', 'expat-devel'], From e4d6106db20206e3ffa15134511e5936e72a3a06 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 14:42:14 +0100 Subject: [PATCH 040/297] F #4913: cosmetic changes --- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index f7757d4f9c..0eab37942a 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -158,15 +158,15 @@ class ClusterComputeResource host_info << "\nHOST=[" host_info << "STATE=on," - host_info << "HOSTNAME=\"" << h.name.to_s << "\"," + host_info << "HOSTNAME=\"" << h.name.to_s << "\"," host_info << "MODELNAME=\"" << hw.cpuModel.to_s << "\"," host_info << "CPUSPEED=" << hw.cpuMhz.to_s << "," - host_info << "MAX_CPU=" << total_cpu.to_s << "," - host_info << "USED_CPU=" << used_cpu.to_s << "," - host_info << "FREE_CPU=" << free_cpu.to_s << "," - host_info << "MAX_MEM=" << total_memory.to_s << "," - host_info << "USED_MEM=" << used_memory.to_s << "," - host_info << "FREE_MEM=" << free_memory.to_s + host_info << "MAX_CPU=" << total_cpu.to_s << "," + host_info << "USED_CPU=" << used_cpu.to_s << "," + host_info << "FREE_CPU=" << free_cpu.to_s << "," + host_info << "MAX_MEM=" << total_memory.to_s << "," + host_info << "USED_MEM=" << used_memory.to_s << "," + host_info << "FREE_MEM=" << free_memory.to_s host_info << "]" end From 72407d33324f44a490a4ed66ce5235122c304f74 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 14:43:25 +0100 Subject: [PATCH 041/297] F #4913: Monitoring returns the new model parameters * Public cloud is not used any more * VCENTER_REF is how a VM is identified * SCHED_REQUIREMENTS uses the OpenNebula host id instead of the name of the cluster in vCenter, which allows renaming --- .../remotes/lib/vcenter_driver/host.rb | 13 ++++++++++-- .../lib/vcenter_driver/virtual_machine.rb | 20 ++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index 0eab37942a..3b9d63daf1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -185,6 +185,14 @@ class ClusterComputeResource def monitor_vms_in_rp(rp) str_info = "" + host_pool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool) + + ccr_host = {} + host_pool.each do |host| + ccr = host['TEMPLATE/VCENTER_CCR_REF'] + ccr_host[ccr] = host['ID'] if ccr + end + rp.vm.each do |v| begin vm = VirtualMachine.new(v) @@ -218,15 +226,16 @@ class ClusterComputeResource next if !vm["config"] + str_info << %Q{ VM = [ ID="#{number}", VM_NAME="#{vm["name"]} - #{vm["runtime.host.parent.name"]}", - DEPLOY_ID="#{vm["config.uuid"]}", + DEPLOY_ID="#{vm["_ref"]}", } if number == -1 - vm_template_64 = Base64.encode64(vm.to_one).gsub("\n","") + vm_template_64 = Base64.encode64(vm.to_one(ccr_host)).gsub("\n","") str_info << "IMPORT_TEMPLATE=\"#{vm_template_64}\"," end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b2f8803de4..c9ab4b018f 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -822,10 +822,14 @@ class VirtualMachine # monitoring ############################################################################ - # @param vm CachedItem (of RbVmomi::VIM::VirtualMachine) - def to_one + # @param ccr_host Hash that holds the relationship between the vcenter's ref + # and the host in OpenNebula + def to_one(ccr_host) cluster = self["runtime.host.parent.name"] + ccr = self["runtime.host.parent._ref"] + host_id = ccr_host[ccr] + str = %Q{ NAME = "#{self["name"]} - #{cluster}" CPU = "#{self["config.hardware.numCPU"]}" @@ -834,20 +838,14 @@ class VirtualMachine HYPERVISOR = "vcenter" - PUBLIC_CLOUD = [ - TYPE ="vcenter", - VM_TEMPLATE ="#{self["config.uuid"]}", - VCENTER_REF ="#{self["_ref"]}", - VCENTER_NAME="#{self["name"]}", - HOST ="#{cluster}" - ] + VCENTER_REF ="#{self["_ref"]}" GRAPHICS = [ TYPE ="vnc", LISTEN ="0.0.0.0" ] - SCHED_REQUIREMENTS="NAME=\\\"#{cluster}\\\"" + SCHED_REQUIREMENTS="ID=\\\"#{host_id}\\\"" CONTEXT = [ NETWORK = "YES", @@ -917,8 +915,6 @@ class VirtualMachine ######################################################################## # PerfManager metrics ######################################################################## - require 'pry' - pm = self['_connection'].serviceInstance.content.perfManager provider = pm.provider_summary(@item) From d206728590528b3b6a2e801fcf290ab12e298f5a Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 14:46:28 +0100 Subject: [PATCH 042/297] F #4913: add comments --- src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb index b02779e973..16617218b3 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb @@ -39,6 +39,6 @@ class VIHelper element end end -end +end # class VIHelper -end +end # module VCenterDriver From 986fce32f06976345a45525b739cb0f83929632a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 14 Feb 2017 17:16:06 +0100 Subject: [PATCH 043/297] Fix monitor. Add nic and snapshots methods --- .../lib/vcenter_driver/virtual_machine.rb | 206 ++++++++++++++++-- 1 file changed, 184 insertions(+), 22 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index c9ab4b018f..898dccf2b7 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -140,7 +140,8 @@ class VirtualMachine # @return RbVmomi::VIM::Datastore or nil def get_ds - req_ds = one_item['USER_TEMPLATE/VCENTER_DATASTORE'] + # Todo remove this comment req_ds = one_item['USER_TEMPLATE/VCENTER_DATASTORE'] + req_ds = one_item['USER_TEMPLATE/VCENTER_DS_REF'] if req_ds dc = cluster.get_dc @@ -325,7 +326,7 @@ class VirtualMachine # get vmid extraconfig += extraconfig_vmid - # get token + # get token and context extraconfig += extraconfig_context # vnc configuration (for config_array hash) @@ -460,7 +461,7 @@ class VirtualMachine device_change += detach_nic_array end - return if nics.empty? + return [] if nics.empty? # Attach new nics (nics now contains only the interfaces not present # in the VM in vCenter) @@ -574,6 +575,89 @@ class VirtualMachine } end + # Add NIC to VM + def attach_nic(nic) + + spec_hash = {} + + # A new NIC requires a vcenter spec + attach_nic_array = [] + attach_nic_array << calculate_add_nic_spec(nic) + spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? + + # Get mac addresses plugged to the VM B#4897 + hotplugged_nics = self["config.extraConfig"].select do |val| + val[:key] == "opennebula.hotplugged_nics" + end.first[:value].to_s.split(";") rescue nil + + # Include MAC in opennebula.hotplugged_nics variable + if hotplugged_nics && !hotplugged_nics.empty? + if !hotplugged_nics.include?(nic["MAC"]) + hotplugged_nics << nic["MAC"] + end + else + hotplugged_nics = [] + hotplugged_nics << nic["MAC"] + end + + spec_hash[:extraConfig] = [{ + :key=>"opennebula.hotplugged_nics", + :value=>hotplugged_nics.join(";")}] + + # Reconfigure VM + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + begin + @item.ReconfigVM_Task(:spec => spec).wait_for_completion + rescue Exception => e + raise "Cannot attach NIC to VM: #{e.message}" + end + + end + + # Detach NIC from VM + def detach_nic(nic) + + spec_hash = {} + + mac = nic["MAC"] + + # Get VM nic element if it has a device with that mac + nic_device = self["config.hardware.device"].find do |device| + is_nic?(device) && (device.macAddress == mac) + end rescue nil + + raise "Could not find NIC with mac address #{mac}" if nic_device.nil? + + # Get mac addresses plugged to the VM B#4897 + hotplugged_nics = self["config.extraConfig"].select do |val| + val[:key] == "opennebula.hotplugged_nics" + end.first[:value].to_s.split(";") rescue nil + + # Remove MAC from opennebula.hotplugged_nics variable if included + if hotplugged_nics && + !hotplugged_nics.empty? && hotplugged_nics.include?(mac) + + hotplugged_nics.delete(mac) + + spec_hash[:extraConfig] = [{ + :key=>"opennebula.hotplugged_nics", + :value=>hotplugged_nics.join(";")}] + end + + # Remove NIC from VM in the ReconfigVM_Task + spec_hash[:deviceChange] = [ + :operation => :remove, + :device => nic_device ] + + begin + @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion + rescue Exception => e + raise "Cannot detach NIC from VM: #{e.message}" + end + + end + # Checks if a RbVmomi::VIM::VirtualDevice is a network interface def is_nic?(device) !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? @@ -597,7 +681,7 @@ class VirtualMachine end end - return if disks.nil? + return [] if disks.nil? position = 0 attach_disk_array = [] @@ -793,6 +877,72 @@ class VirtualMachine return controller end + # Create a snapshot for the VM + def create_snapshot(snapshot_name, vm_ref) + snapshot_hash = { + :name => snapshot_name, + :description => "OpenNebula Snapshot of VM #{vm_ref}", + :memory => true, + :quiesce => true + } + + begin + @item.CreateSnapshot_Task(snapshot_hash).wait_for_completion + rescue Exception => e + raise "Cannot create snapshot for VM: #{e.message}" + end + + return snapshot_name + end + + # Revert to a VM snapshot + def revert_snapshot(snapshot_name) + + snapshot_list = self["snapshot.rootSnapshotList"] + snapshot = find_snapshot_in_list(snapshot_list, snapshot_name) + + return nil if !snapshot + + begin + revert_snapshot_hash = { :_this => snapshot } + snapshot.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion + rescue Exception => e + raise "Cannot revert snapshot of VM: #{e.message}" + end + end + + # Delete VM snapshot + def delete_snapshot(snapshot_name) + + snapshot_list = self["snapshot.rootSnapshotList"] + snapshot = find_snapshot_in_list(snapshot_list, snapshot_name) + + return nil if !snapshot + + begin + delete_snapshot_hash = { + :_this => snapshot, + :removeChildren => false + } + snapshot.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion + rescue Exception => e + raise "Cannot delete snapshot of VM: #{e.message}" + end + end + + def find_snapshot_in_list(list, snapshot_name) + list.each do |i| + if i.name == snapshot_name + return i.snapshot + elsif !i.childSnapshotList.empty? + snap = find_snapshot(i.childSnapshotList, snapshot_name) + return snap if snap + end + end rescue nil + + nil + end + ############################################################################ # actions ############################################################################ @@ -830,28 +980,40 @@ class VirtualMachine ccr = self["runtime.host.parent._ref"] host_id = ccr_host[ccr] - str = %Q{ - NAME = "#{self["name"]} - #{cluster}" - CPU = "#{self["config.hardware.numCPU"]}" - vCPU = "#{self["config.hardware.numCPU"]}" - MEMORY = "#{self["config.hardware.memoryMB"]}" + str = "NAME = \"#{self["name"]} - #{cluster}\"\n"\ + "CPU = \"#{self["config.hardware.numCPU"]}\"\n"\ + "vCPU = \"#{self["config.hardware.numCPU"]}\"\n"\ + "MEMORY = \"#{self["config.hardware.memoryMB"]}\"\n"\ + "HYPERVISOR = \"vcenter\"\n"\ + "IMPORT_VM_ID =\"#{self["config.uuid"]}\"\n"\ + "IMPORT_STATE =\"#{@state}\"\n"\ + "SCHED_REQUIREMENTS=\"ID=\\\"#{host_id}\\\"\"\n"\ + "CONTEXT = [\n"\ + " NETWORK = \"YES\",\n"\ + " SSH_PUBLIC_KEY = \"$USER[SSH_PUBLIC_KEY]\"\n"\ + "]\n" - HYPERVISOR = "vcenter" + vnc_port = nil + keymap = nil + self["config.extraConfig"].select do |xtra| - VCENTER_REF ="#{self["_ref"]}" + if xtra[:key].downcase=="remotedisplay.vnc.port" + vnc_port = xtra[:value] + end - GRAPHICS = [ - TYPE ="vnc", - LISTEN ="0.0.0.0" - ] + if xtra[:key].downcase=="remotedisplay.vnc.keymap" + keymap = xtra[:value] + end + end - SCHED_REQUIREMENTS="ID=\\\"#{host_id}\\\"" - - CONTEXT = [ - NETWORK = "YES", - SSH_PUBLIC_KEY = "$USER[SSH_PUBLIC_KEY]" - ] - } + if self["config.extraConfig"].size > 0 + str << "GRAPHICS = [\n"\ + " TYPE =\"vnc\",\n"\ + " LISTEN =\"0.0.0.0\",\n" + str << " PORT =\"#{vnc_port}\",\n" if vnc_port + str << " KEYMAP =\"#{keymap}\"\n" if keymap + str << "]\n" + end if self["config.annotation"].nil? || self["config.annotation"].empty? str << "DESCRIPTION = \"vCenter Template imported by OpenNebula" \ From ff58312d3a6a72c4400eda2977b2ecbac4f44efa Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 14 Feb 2017 17:17:21 +0100 Subject: [PATCH 044/297] Add NIC attach/detach actions --- src/vmm_mad/remotes/vcenter/attach_nic | 32 ++++++++++++++++---------- src/vmm_mad/remotes/vcenter/detach_nic | 27 +++++++++++++--------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index a158d226af..1b04fbad6f 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # -------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,22 +27,30 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] +vm_ref = ARGV[0] mac = ARGV[1] bridge = ARGV[2] model = ARGV[3] -host = ARGV[-1] +vc_cluster_name = ARGV[-1] begin - VCenterDriver::VCenterVm.attach_nic(deploy_id, - mac, - bridge, - model, - host) + + vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + + nic = { + "MAC" => mac, + "BRIDGE" => bridge, + "MODEL" => model + } + + vm.attach_nic(nic) + rescue Exception => e - STDERR.puts "Attach NIC for VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" - exit -1 + STDERR.puts "Attach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ + "failed due to \"#{e.message}\"" + exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index 19b7cfafaf..f8aa0ebd04 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -27,19 +27,24 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' - -deploy_id = ARGV[0] -mac = ARGV[1] -host = ARGV[3] +require 'vcenter_driver2' +vm_ref = ARGV[0] +mac = ARGV[1] +vc_cluster_name = ARGV[3] begin - VCenterDriver::VCenterVm.detach_nic(deploy_id, - mac, - host) + + vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + + nic = { "MAC" => mac } + + vm.detach_nic(nic) + rescue Exception => e - STDERR.puts "Detach NIC for VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" - exit -1 + STDERR.puts "Detach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ + "failed due to \"#{e.message}\"" + exit(-1) end \ No newline at end of file From d8463f14d74704c6114fbfe38213cc7965850fd6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 14 Feb 2017 17:18:09 +0100 Subject: [PATCH 045/297] Add snapshot create/revert/delete actions --- src/vmm_mad/remotes/vcenter/snapshot_create | 24 +++++++++++-------- src/vmm_mad/remotes/vcenter/snapshot_delete | 26 +++++++++++++-------- src/vmm_mad/remotes/vcenter/snapshot_revert | 23 +++++++++++------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index bc998d8407..b97b7a2125 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,18 +27,22 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] +vm_ref = ARGV[0] snapshot_name = ARGV[1] -host = ARGV[3] +vc_cluster_name = ARGV[3] begin - puts VCenterDriver::VCenterVm.create_snapshot(deploy_id, - host, - snapshot_name) + + vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + + vm.create_snapshot(snapshot_name, vm_ref) + rescue Exception => e - STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" - exit -1 + STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" + exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index e05f146cf2..04ac1bccbe 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -27,18 +27,24 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] +vm_ref = ARGV[0] snapshot_name = ARGV[1] -host = ARGV[3] +vc_cluster_name = ARGV[3] begin - VCenterDriver::VCenterVm.delete_snapshot(deploy_id, - host, - snapshot_name) + + File.open('/tmp/args','w'){|f| f.puts(ARGV.join(" "))} + + vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + + vm.delete_snapshot(snapshot_name) + rescue Exception => e - STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" - exit -1 -end + STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} could not be deleted due to \"#{e.message}\"" + exit(-1) +end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index c4d7ee42f2..9b69e5c6e8 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -27,18 +27,23 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] +vm_ref = ARGV[0] snapshot_name = ARGV[1] -host = ARGV[3] +vc_cluster_name = ARGV[3] begin - VCenterDriver::VCenterVm.revert_snapshot(deploy_id, - host, - snapshot_name) + + vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + + vm.revert_snapshot(snapshot_name) + rescue Exception => e - STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} could not be " + - "reverted due to \"#{e.message}\"" - exit -1 + STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} could not be reverted due "\ + "to \"#{e.message}\"" + exit(-1) end From 74d473798f0c0a597e859cb7cb6daedaf39cdace Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 14 Feb 2017 17:18:42 +0100 Subject: [PATCH 046/297] Add VM poll action --- src/vmm_mad/remotes/vcenter/poll | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index c239d353f0..9fd4c028ff 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -28,17 +28,23 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] -host = ARGV[1] +vm_ref = ARGV[0] +vc_cluster_name = ARGV[1] -host_id = VCenterDriver::VIClient.translate_hostname(host) -vi_client = VCenterDriver::VIClient.new host_id -host = VCenterDriver::VCenterHost.new vi_client -vm = vi_client.find_vm_template(deploy_id) -vm = VCenterDriver::VCenterVm.new(vi_client, vm) +begin -vm.monitor(host) + vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) -puts vm.info + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + + vm.monitor + + puts vm.info + +rescue Exception => e + STDERR.puts "Cannot poll info for VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" + exit(-1) +end From ad3eb4fe22f5bfdc31de4c99cd8fb2eadea73c9e Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 14 Feb 2017 17:23:52 +0100 Subject: [PATCH 047/297] Add begin/rescue clauses --- src/vmm_mad/remotes/vcenter/deploy | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 7f583a59c5..94b0c5b715 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -30,6 +30,8 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' require 'opennebula' +dfile = ARGV[0] +cluster_name = ARGV[1] vm_id = ARGV[2] drv_action = OpenNebula::XMLElement.new @@ -53,12 +55,19 @@ target_ds_id = drv_action['HISTORY_RECORDS/HISTORY[last()]/DS_ID'] target_ds_one = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) target_ds_ref = target_ds_one['TEMPLATE/VCENTER_DS_REF'] -# Clone from template -vm = VCenterDriver::VirtualMachine.new +begin + # Clone from template + vm = VCenterDriver::VirtualMachine.new -vm.vi_client = vi_client -vm.one_item = drv_action -vm.host = host -vm.target_ds_ref = target_ds_ref + vm.vi_client = vi_client + vm.one_item = drv_action + vm.host = host + vm.target_ds_ref = target_ds_ref -puts vm.clone_vm + puts vm.clone_vm + +rescue Exception => e + STDERR.puts "Deploy of VM #{vm_id} on vCenter cluster #{cluster_name} " + + "with #{dfile} failed due to \"#{e.message}\"" + exit -1 +end From 351f8012b24cf09e6ee22945ff816fbb00b862ec Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 14 Feb 2017 17:28:42 +0100 Subject: [PATCH 048/297] Add method for cluster lookup by opennebula name --- .../remotes/lib/vcenter_driver/vi_client.rb | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 71e6f3c9d5..4cea9ada7b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -69,6 +69,27 @@ class VIClient self.new(connection) end + def self.new_from_hostname(hostname) + client = OpenNebula::Client.new + host_pool = OpenNebula::HostPool.new(client) + rc = host_pool.info + if OpenNebula.is_error?(rc) + puts "Error getting oned configuration : #{rc.message}" + exit -1 + end + + host_id = host_pool.select do |host_element| + host_element.name == hostname + end.first.id rescue nil + + if host_id + new_from_host(host_id) + else + puts "Could not find host_id for host: #{hostname}" + exit -1 + end + end + def self.decrypt(msg, token) begin cipher = OpenSSL::Cipher.new("aes-256-cbc") From 49abb1f059e56e01c8c6c8542449e3a2bf1e95b7 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 16:13:20 +0100 Subject: [PATCH 049/297] F #4913: It is not necessary to require the opennebula library It is being required by the vcenter_driver2 --- src/datastore_mad/remotes/vcenter/mkfs | 1 - src/datastore_mad/remotes/vcenter/monitor | 1 - src/datastore_mad/remotes/vcenter/rm | 1 - src/im_mad/remotes/vcenter.d/vcenter.rb | 1 - src/tm_mad/vcenter/clone | 1 - src/vmm_mad/remotes/vcenter/deploy | 1 - 6 files changed, 6 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index a0a022469a..0c3d6b68ec 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -32,7 +32,6 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver2' -require 'opennebula' ################################################################################ diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index ef022dccb0..9673930878 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -32,7 +32,6 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver2' -require 'opennebula' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index b73ea043f7..08775d266d 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -32,7 +32,6 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver2' -require 'opennebula' ################################################################################ diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index 784c5641b1..be561f39f9 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -27,7 +27,6 @@ end $: << RUBY_LIB_LOCATION require 'vcenter_driver2' -require 'opennebula' host_id = ARGV[4] diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index 1c663d7d29..c916b24dfb 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -35,7 +35,6 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'opennebula' require 'vcenter_driver2' ################################################################################ diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 94b0c5b715..f691d5bb11 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -28,7 +28,6 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver2' -require 'opennebula' dfile = ARGV[0] cluster_name = ARGV[1] From 156046a21a6c990cce1efa5d176efb2c9e7956d6 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 16:14:10 +0100 Subject: [PATCH 050/297] F #4913: Adds the cancel action --- src/vmm_mad/remotes/vcenter/cancel | 34 ++++++++++++------------------ 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index a6b94259ef..69f911ca8d 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -27,34 +27,28 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'opennebula' +require 'vcenter_driver2' deploy_id = ARGV[0] host = ARGV[1] vm_id = ARGV[-2] -drv_action_enc = STDIN.read.gsub("\n","") - drv_action = OpenNebula::XMLElement.new -drv_action.initialize_xml(Base64.decode64(drv_action_enc), - 'VMM_DRIVER_ACTION_DATA') +drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VMM_DRIVER_ACTION_DATA') -lcm_state_num = drv_action["/VMM_DRIVER_ACTION_DATA/VM/LCM_STATE"].to_i -lcm_state = OpenNebula::VirtualMachine::LCM_STATE[lcm_state_num] -keep_disks = !drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].nil? && - drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].downcase=="yes" -disks = [drv_action.to_hash["VMM_DRIVER_ACTION_DATA"]["VM"]["TEMPLATE"]["DISK"]].flatten.compact - -cloned_tmplt = nil -if !drv_action['/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/CLONING_TEMPLATE_ID'].nil? - cloned_tmplt = drv_action['/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/TEMPLATE_ID'] -end +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, host) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.cancel(deploy_id, host, lcm_state, keep_disks, disks, cloned_tmplt) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm_ref = drv_action['VM/DEPLOY_ID'] + + vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm.one_item = drv_action.retrieve_xmlelements('VM').first + + vm.poweroff_hard rescue Exception => e - STDERR.puts "Cancel of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"\n#{e.backtrace}" - exit -1 + STDERR.puts "Cancel VM #{deploy_id} failed due to \"#{e.message}\"" + exit(-1) end From dcbf92aa3af4a1b0d4966adc737ab3e675396734 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 17:29:04 +0100 Subject: [PATCH 051/297] F #4913: host and target_ds_ref are dynamically calculated --- .../lib/vcenter_driver/virtual_machine.rb | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 898dccf2b7..9b01406eb8 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -45,26 +45,25 @@ class VirtualMachine include Memoize - def initialize(item=nil) + def initialize(item=nil, vi_client=nil) @item = item + @vi_client = vi_client end ############################################################################ ############################################################################ - # VM XMLElement - attr_accessor :one_item + # Attributes that must be defined when the VM does not exist in vCenter + attr_writer :vi_client + attr_writer :one_item + attr_writer :host + attr_writer :target_ds_ref - # OpenNebula host - attr_accessor :host + ############################################################################ + ############################################################################ - # Target Datastore VMware reference (must be defined when VM is new) - attr_accessor :target_ds_ref - - # vi_client setter (must be used when the VM does not exist in vCenter) - attr_accessor :vi_client - - # Cached one_item + # The OpenNebula VM + # @return OpenNebula::VirtualMachine or XMLElement def one_item if @one_item.nil? vm_id = get_vm_id @@ -77,18 +76,53 @@ class VirtualMachine @one_item end - # one_item setter (must be used when the VM does not exist in vCenter) - def one_item=(one_item) - @one_item = one_item + # The OpenNebula host + # @return OpenNebula::Host or XMLElement + def host + if @host.nil? + if one_item.nil? + raise "'one_item' must be previously set to be able to " << + "access the OpenNebula host." + end + + host_id = one_item["HISTORY_RECORDS/HISTORY/HID"] + raise "No valid host_id found." if host_id.nil? + + @host = VIHelper.one_item(OpenNebula::Host, host_id) + end + + @host + end + + # Target Datastore VMware reference getter + # @return + def target_ds_ref + if @target_ds_ref.nil? + if one_item.nil? + raise "'one_item' must be previously set to be able to " << + "access the target Datastore." + end + + target_ds_id = one_item["HISTORY_RECORDS/HISTORY[last()]/DS_ID"] + raise "No valid target_ds_id found." if target_ds_id.nil? + + target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, + target_ds_id) + + @target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] + end + + @target_ds_ref end # Cached cluster # @return ClusterComputeResource def cluster if @cluster.nil? - ccr_ref = @host['TEMPLATE/VCENTER_CCR_REF'] + ccr_ref = host['TEMPLATE/VCENTER_CCR_REF'] @cluster = ClusterComputeResource.new_from_ref(vi_client, ccr_ref) end + @cluster end @@ -201,7 +235,7 @@ class VirtualMachine if disk["PERSISTENT"] == "YES" ds_ref = disk["VCENTER_DS_REF"] else - ds_ref = @target_ds_ref + ds_ref = target_ds_ref if ds_ref.nil? raise "target_ds_ref must be defined on this object." @@ -213,7 +247,7 @@ class VirtualMachine # @return String vcenter name def get_vcenter_name - vm_prefix = @host['TEMPLATE/VM_PREFIX'] + vm_prefix = host['TEMPLATE/VM_PREFIX'] vm_prefix = VM_PREFIX_DEFAULT if vm_prefix.nil? || vm_prefix.empty? vm_prefix.gsub!("$i", one_item['ID']) @@ -224,7 +258,7 @@ class VirtualMachine # Crate and reconfigure VM related methods ############################################################################ - # When creating a new these instance variables must be set beforehand + # When creating a new VM these instance variables must be set beforehand # @vi_client # @one_item # @host @@ -1267,7 +1301,7 @@ class VirtualMachine # TODO check with uuid def self.new_from_ref(vi_client, ref) - self.new(RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref)) + self.new(RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref), vi_client) end end # class VirtualMachine From 5320c65d16f3d1ef0e1889c06c1918b6624c937f Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 18:25:43 +0100 Subject: [PATCH 052/297] F #4913: Reverse the order of parameters in new_from_ref --- src/datastore_mad/remotes/vcenter/mkfs | 4 ++-- src/datastore_mad/remotes/vcenter/monitor | 2 +- src/datastore_mad/remotes/vcenter/rm | 4 ++-- src/im_mad/remotes/vcenter.d/vcenter.rb | 2 +- src/tm_mad/vcenter/clone | 4 ++-- .../remotes/lib/vcenter_driver/datacenter.rb | 16 ++++++++-------- .../remotes/lib/vcenter_driver/datastore.rb | 6 +++--- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 7 ++++--- .../remotes/lib/vcenter_driver/network.rb | 7 ++++--- .../lib/vcenter_driver/virtual_machine.rb | 6 +++--- src/vmm_mad/remotes/vcenter/attach_nic | 2 +- src/vmm_mad/remotes/vcenter/cancel | 2 +- src/vmm_mad/remotes/vcenter/detach_nic | 4 ++-- src/vmm_mad/remotes/vcenter/poll | 2 +- src/vmm_mad/remotes/vcenter/snapshot_create | 2 +- src/vmm_mad/remotes/vcenter/snapshot_delete | 4 ++-- src/vmm_mad/remotes/vcenter/snapshot_revert | 2 +- 17 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 0c3d6b68ec..1ec71a1c12 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -79,8 +79,8 @@ end begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - ds = VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) - dc = VCenterDriver::Datacenter.new_from_ref(vi_client, dc_ref) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + dc = VCenterDriver::Datacenter.new_from_ref(dc_ref, vi_client) puts ds.create_virtual_disk(dc, img_name, size, adapter_type, disk_type) rescue Exception => e diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 9673930878..ee773f57fa 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -48,6 +48,6 @@ if host_id.nil? || ds_ref.nil? end vi_client = VCenterDriver::VIClient.new_from_host(host_id) -ds = VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) +ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) puts ds.monitor diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 08775d266d..c67d91cc7b 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -63,8 +63,8 @@ check_valid dc_ref, "dc_ref" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - dc = VCenterDriver::Datacenter.new_from_ref(vi_client, dc_ref) - ds = VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) + dc = VCenterDriver::Datacenter.new_from_ref(dc_ref, vi_client) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) ds.delete_virtual_disk(dc, img_src) rescue Exception => e diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index be561f39f9..bc6615da43 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -48,7 +48,7 @@ end ccr_ref = host["TEMPLATE/VCENTER_CCR_REF"] # Get vCenter Cluster -cluster = VCenterDriver::ClusterComputeResource.new_from_ref(vi_client, ccr_ref) +cluster = VCenterDriver::ClusterComputeResource.new_from_ref(ccr_ref, vi_client) # Print monitoring info puts cluster.monitor diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index c916b24dfb..5271c5738b 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -99,12 +99,12 @@ target_path = src_path.split(".").first + "-#{vm_id}-#{disk_id}.vmdk" # vi_client vi_client = VCenterDriver::VIClient.new_from_host(host_id) -source_ds_vc = VCenterDriver::Datastore.new_from_ref(vi_client, source_ds_ref) +source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) if source_ds_ref == target_ds_ref target_ds_vc = source_ds_vc else - target_ds_vc = VCenterDriver::Datastore.new_from_ref(vi_client, target_ds_ref) + target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) end target_ds_name_vc = target_ds_vc['name'] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index c1226dccdf..4af8a94b52 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -3,8 +3,8 @@ module VCenterDriver class DatacenterFolder attr_accessor :items - def initialize(vcenter_client) - @vcenter_client = vcenter_client + def initialize(vi_client) + @vi_client = vi_client @items = {} end @@ -14,7 +14,7 @@ class DatacenterFolder # { dc_ref [Symbol] => Datacenter object } ######################################################################## def fetch! - VIClient.get_entities(@vcenter_client.vim.root, "Datacenter").each do |item| + VIClient.get_entities(@vi_client.vim.root, "Datacenter").each do |item| item_name = item._ref @items[item_name.to_sym] = Datacenter.new(item) end @@ -27,7 +27,7 @@ class DatacenterFolder ######################################################################## def get(ref) if !@items[ref.to_sym] - rbvmomi_dc = RbVmomi::VIM::Datacenter.new(@vcenter_client.vim, ref) + rbvmomi_dc = RbVmomi::VIM::Datacenter.new(@vi_client.vim, ref) @items[ref.to_sym] = Datacenter.new(rbvmomi_dc) end @@ -38,12 +38,13 @@ end # class DatatacenterFolder class Datacenter attr_accessor :item - def initialize(item) + def initialize(item, vi_client=nil) if !item.instance_of? RbVmomi::VIM::Datacenter raise "Expecting type 'RbVmomi::VIM::Datacenter'. " << "Got '#{item.class} instead." end + @vi_client = vi_client @item = item end @@ -63,9 +64,8 @@ class Datacenter NetworkFolder.new(@item.networkFolder) end - # This is never cached - def self.new_from_ref(vi_client, ref) - self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref)) + def self.new_from_ref(ref, vi_client) + self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref), vi_client) end end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 7d59bcb15e..7ffa7178fc 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -55,7 +55,7 @@ class Datastore include Memoize - def initialize(item) + def initialize(item, vi_client=nil) if !item.instance_of? RbVmomi::VIM::Datastore raise "Expecting type 'RbVmomi::VIM::Datastore'. " << "Got '#{item.class} instead." @@ -136,8 +136,8 @@ class Datastore end # This is never cached - def self.new_from_ref(vi_client, ref) - self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref)) + def self.new_from_ref(ref, vi_client) + self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref), vi_client) end end # class Datastore diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index 3b9d63daf1..29129cb73c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -30,8 +30,9 @@ class ClusterComputeResource include Memoize - def initialize(item) + def initialize(item, vi_client=nil) @item = item + @vi_client = vi_client end def fetch_resource_pools(rp, rp_array = []) @@ -280,8 +281,8 @@ class ClusterComputeResource Datacenter.new(item) end - def self.new_from_ref(vi_client, ref) - self.new(RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref)) + def self.new_from_ref(ref, vi_client) + self.new(RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref), vi_client) end end # class ClusterComputeResource diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index e427c5afba..dbc9425361 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -38,18 +38,19 @@ end # class NetworkFolder class Network attr_accessor :item - def initialize(item) + def initialize(item, vi_client=nil) if !item.instance_of? RbVmomi::VIM::Network raise "Expecting type 'RbVmomi::VIM::Network'. " << "Got '#{item.class} instead." end + @vi_client = vi_client @item = item end # This is never cached - def self.new_from_ref(vi_client, ref) - self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref)) + def self.new_from_ref(ref, vi_client) + self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref), vi_client) end end # class Network diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 9b01406eb8..662fa24ab5 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -120,7 +120,7 @@ class VirtualMachine def cluster if @cluster.nil? ccr_ref = host['TEMPLATE/VCENTER_CCR_REF'] - @cluster = ClusterComputeResource.new_from_ref(vi_client, ccr_ref) + @cluster = ClusterComputeResource.new_from_ref(ccr_ref, vi_client) end @cluster @@ -242,7 +242,7 @@ class VirtualMachine end end - VCenterDriver::Datastore.new_from_ref(vi_client, ds_ref) + VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) end # @return String vcenter name @@ -1300,7 +1300,7 @@ class VirtualMachine end # TODO check with uuid - def self.new_from_ref(vi_client, ref) + def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::VirtualMachine.new(vi_client.vim, ref), vi_client) end diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 1b04fbad6f..6e63b2257f 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -39,7 +39,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) nic = { "MAC" => mac, diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 69f911ca8d..6e3481efdd 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -44,7 +44,7 @@ begin vm_ref = drv_action['VM/DEPLOY_ID'] - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) vm.one_item = drv_action.retrieve_xmlelements('VM').first vm.poweroff_hard diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index f8aa0ebd04..02f71bce3a 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -37,7 +37,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) nic = { "MAC" => mac } @@ -47,4 +47,4 @@ rescue Exception => e STDERR.puts "Detach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"" exit(-1) -end \ No newline at end of file +end diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index 9fd4c028ff..e0b6395914 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -37,7 +37,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) vm.monitor diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index b97b7a2125..ec80a61cf2 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -37,7 +37,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) vm.create_snapshot(snapshot_name, vm_ref) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index 04ac1bccbe..a8668274a6 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -39,7 +39,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) vm.delete_snapshot(snapshot_name) @@ -47,4 +47,4 @@ rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} could not be deleted due to \"#{e.message}\"" exit(-1) -end \ No newline at end of file +end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index 9b69e5c6e8..c79ee5db10 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -37,7 +37,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) - vm = VCenterDriver::VirtualMachine.new_from_ref(vi_client, vm_ref) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) vm.revert_snapshot(snapshot_name) From 31e9fc97e3b0575927999149dcc9984e54c217ff Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 14 Feb 2017 23:57:37 +0100 Subject: [PATCH 053/297] F #4913: isolate the clone_vm from non related functionality --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 662fa24ab5..156854e3d1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -304,12 +304,7 @@ class VirtualMachine # @item is populated @item = vm - - reconfigure - poweron - set_running(true) - - return @item._ref + return self['_ref'] end From b2ca3a547c1122e8a7867dd754d9d17f1c24107f Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 15 Feb 2017 00:35:05 +0100 Subject: [PATCH 054/297] F #4913: No need to specify DC_REF in the datastore template any more --- src/datastore_mad/remotes/vcenter/mkfs | 5 +---- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 1ec71a1c12..522bf7d8fe 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -53,7 +53,6 @@ drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DAT ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -dc_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DC_REF"] img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] @@ -66,7 +65,6 @@ check_valid adapter_type, "adapter_type" check_valid disk_type, "disk_type" check_valid size, "size" check_valid ds_ref, "ds_ref" -check_valid dc_ref, "dc_ref" # TODO path in vCenter? choose a specific directory @@ -80,9 +78,8 @@ end begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - dc = VCenterDriver::Datacenter.new_from_ref(dc_ref, vi_client) - puts ds.create_virtual_disk(dc, img_name, size, adapter_type, disk_type) + puts ds.create_virtual_disk(img_name, size, adapter_type, disk_type) rescue Exception => e STDERR.puts "Error creating virtual disk #{img_src}."\ " Reason: #{e.message}" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 7ffa7178fc..5b1b067f97 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -74,7 +74,7 @@ class Datastore "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" end - def create_virtual_disk(dc, img_name, size, adapter_type, disk_type) + def create_virtual_disk(img_name, size, adapter_type, disk_type) ds_name = self['name'] vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( @@ -84,7 +84,7 @@ class Datastore ) get_vdm.CreateVirtualDisk_Task( - :datacenter => dc.item, + :datacenter => get_dc.item, :name => "[#{ds_name}] #{img_name}.vmdk", :spec => vmdk_spec ).wait_for_completion From 396cd704cd50339945c1ec91beead35c837955ad Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 15 Feb 2017 00:38:38 +0100 Subject: [PATCH 055/297] F #4913: Refactor deploy --- .../lib/vcenter_driver/virtual_machine.rb | 20 ++++---- src/vmm_mad/remotes/vcenter/deploy | 47 +++++++++---------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 156854e3d1..c7f97c0dc8 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -54,7 +54,10 @@ class VirtualMachine ############################################################################ # Attributes that must be defined when the VM does not exist in vCenter - attr_writer :vi_client + attr_accessor :vi_client + + # these have their own getter (if they aren't set, we can set them + # dynamically) attr_writer :one_item attr_writer :host attr_writer :target_ds_ref @@ -258,14 +261,15 @@ class VirtualMachine # Crate and reconfigure VM related methods ############################################################################ - # When creating a new VM these instance variables must be set beforehand - # @vi_client - # @one_item - # @host - # # This function creates a new VM from the @one_item XML and returns the # VMware ref - def clone_vm + # @param one_item OpenNebula::VirtualMachine + # @param vi_client VCenterDriver::VIClient + # @return String vmware ref + def clone_vm(one_item, vi_client) + @one_item = one_item + @vi_client = vi_client + vcenter_name = get_vcenter_name vc_template_ref = one_item['USER_TEMPLATE/VCENTER_TEMPLATE_REF'] @@ -302,8 +306,8 @@ class VirtualMachine end # @item is populated - @item = vm + return self['_ref'] end diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index f691d5bb11..cdee076d1e 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -29,42 +29,39 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -dfile = ARGV[0] -cluster_name = ARGV[1] -vm_id = ARGV[2] +dfile = ARGV[0] +cluster_name = ARGV[1] +vm_id = ARGV[2] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VM') -host_id = drv_action["/VM/HISTORY_RECORDS/HISTORY/HID"] - -# lcm_state_num = drv_action["/VM/LCM_STATE"].to_i -# lcm_state = OpenNebula::VirtualMachine::LCM_STATE[lcm_state_num] - -host = OpenNebula::Host.new_with_id(host_id, OpenNebula::Client.new) -rc = host.info -if OpenNebula::is_error?(rc) - STDERR.puts rc.message - exit -1 -end +deploy_id = drv_action["DEPLOY_ID"] +host_id = drv_action["HISTORY_RECORDS/HISTORY/HID"] vi_client = VCenterDriver::VIClient.new_from_host(host_id) -target_ds_id = drv_action['HISTORY_RECORDS/HISTORY[last()]/DS_ID'] -target_ds_one = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) -target_ds_ref = target_ds_one['TEMPLATE/VCENTER_DS_REF'] - begin - # Clone from template - vm = VCenterDriver::VirtualMachine.new + if deploy_id && !deploy_id.empty? + # VM is not new, we just need to reconfigure it and to power it on + vm = VCenterDriver::VirtualMachine.new_from_ref(deploy_id, vi_client) - vm.vi_client = vi_client - vm.one_item = drv_action - vm.host = host - vm.target_ds_ref = target_ds_ref + # Setting one_item is optional, but it saves a couple of API calls if + # we already have it + vm.one_item = drv_action + else + # VM is new + vm = VCenterDriver::VirtualMachine.new - puts vm.clone_vm + # Clone from template + vm.clone_vm(drv_action, vi_client) + end + vm.reconfigure + vm.poweron + vm.set_running(true) + + puts vm['_ref'] rescue Exception => e STDERR.puts "Deploy of VM #{vm_id} on vCenter cluster #{cluster_name} " + "with #{dfile} failed due to \"#{e.message}\"" From 5d5c260fce232f216b1439d5e1499e3a2e4c9437 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 15 Feb 2017 00:44:18 +0100 Subject: [PATCH 056/297] F #4913: Remove debugging info --- src/vmm_mad/remotes/vcenter/snapshot_delete | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index a8668274a6..2bb478f642 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -35,8 +35,6 @@ vc_cluster_name = ARGV[3] begin - File.open('/tmp/args','w'){|f| f.puts(ARGV.join(" "))} - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) From fa515050a3c233b83969d2a8e6dff0e91e2427d6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 08:22:08 +0100 Subject: [PATCH 057/297] F #4913: cosmetic changes --- src/vmm_mad/remotes/vcenter/attach_nic | 8 ++++---- src/vmm_mad/remotes/vcenter/detach_nic | 4 ++-- src/vmm_mad/remotes/vcenter/snapshot_create | 4 ++-- src/vmm_mad/remotes/vcenter/snapshot_delete | 4 ++-- src/vmm_mad/remotes/vcenter/snapshot_revert | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 6e63b2257f..4dda2d7a19 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -29,10 +29,10 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -vm_ref = ARGV[0] -mac = ARGV[1] -bridge = ARGV[2] -model = ARGV[3] +vm_ref = ARGV[0] +mac = ARGV[1] +bridge = ARGV[2] +model = ARGV[3] vc_cluster_name = ARGV[-1] begin diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index 02f71bce3a..a854c5d5fe 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -29,8 +29,8 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -vm_ref = ARGV[0] -mac = ARGV[1] +vm_ref = ARGV[0] +mac = ARGV[1] vc_cluster_name = ARGV[3] begin diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index ec80a61cf2..a11f7777d5 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -29,8 +29,8 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -vm_ref = ARGV[0] -snapshot_name = ARGV[1] +vm_ref = ARGV[0] +snapshot_name = ARGV[1] vc_cluster_name = ARGV[3] begin diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index 2bb478f642..8f717a53f4 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -29,8 +29,8 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -vm_ref = ARGV[0] -snapshot_name = ARGV[1] +vm_ref = ARGV[0] +snapshot_name = ARGV[1] vc_cluster_name = ARGV[3] begin diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index c79ee5db10..d6e374c9bd 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -29,8 +29,8 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -vm_ref = ARGV[0] -snapshot_name = ARGV[1] +vm_ref = ARGV[0] +snapshot_name = ARGV[1] vc_cluster_name = ARGV[3] begin From 2d2dbf3204e0bef3b4cfc4c492723beb55dfeb2a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 08:36:54 +0100 Subject: [PATCH 058/297] F #4913: VIClient new_from_hostname no longer needed --- .../remotes/lib/vcenter_driver/vi_client.rb | 21 ------------------- src/vmm_mad/remotes/vcenter/attach_nic | 5 ++++- src/vmm_mad/remotes/vcenter/detach_nic | 5 ++++- src/vmm_mad/remotes/vcenter/poll | 5 ++++- src/vmm_mad/remotes/vcenter/snapshot_create | 5 ++++- src/vmm_mad/remotes/vcenter/snapshot_delete | 5 ++++- src/vmm_mad/remotes/vcenter/snapshot_revert | 5 ++++- 7 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 4cea9ada7b..71e6f3c9d5 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -69,27 +69,6 @@ class VIClient self.new(connection) end - def self.new_from_hostname(hostname) - client = OpenNebula::Client.new - host_pool = OpenNebula::HostPool.new(client) - rc = host_pool.info - if OpenNebula.is_error?(rc) - puts "Error getting oned configuration : #{rc.message}" - exit -1 - end - - host_id = host_pool.select do |host_element| - host_element.name == hostname - end.first.id rescue nil - - if host_id - new_from_host(host_id) - else - puts "Could not find host_id for host: #{hostname}" - exit -1 - end - end - def self.decrypt(msg, token) begin cipher = OpenSSL::Cipher.new("aes-256-cbc") diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 4dda2d7a19..75738eec45 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -37,7 +37,10 @@ vc_cluster_name = ARGV[-1] begin - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] + + vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index a854c5d5fe..c142559bd3 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -35,7 +35,10 @@ vc_cluster_name = ARGV[3] begin - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] + + vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index e0b6395914..0e16ba8e72 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -35,7 +35,10 @@ vc_cluster_name = ARGV[1] begin - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] + + vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index a11f7777d5..a5f47acfda 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -35,7 +35,10 @@ vc_cluster_name = ARGV[3] begin - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] + + vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index 8f717a53f4..bb0e014918 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -35,7 +35,10 @@ vc_cluster_name = ARGV[3] begin - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] + + vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index d6e374c9bd..2a9d3b1742 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -35,7 +35,10 @@ vc_cluster_name = ARGV[3] begin - vi_client = VCenterDriver::VIClient.new_from_hostname(vc_cluster_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] + + vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) From 89317327dc052f3453cdddce52d5c6b72a1a0f4a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 09:23:59 +0100 Subject: [PATCH 059/297] F #4913: Moves host_id retrieval out of begin --- src/vmm_mad/remotes/vcenter/attach_nic | 7 +++---- src/vmm_mad/remotes/vcenter/detach_nic | 7 +++---- src/vmm_mad/remotes/vcenter/poll | 7 +++---- src/vmm_mad/remotes/vcenter/snapshot_create | 7 +++---- src/vmm_mad/remotes/vcenter/snapshot_delete | 7 +++---- src/vmm_mad/remotes/vcenter/snapshot_revert | 7 +++---- 6 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 75738eec45..115c6e0051 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -35,11 +35,10 @@ bridge = ARGV[2] model = ARGV[3] vc_cluster_name = ARGV[-1] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + begin - - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) - host_id = host['ID'] - vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index c142559bd3..4fefb3e5c5 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -33,11 +33,10 @@ vm_ref = ARGV[0] mac = ARGV[1] vc_cluster_name = ARGV[3] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + begin - - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) - host_id = host['ID'] - vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index 0e16ba8e72..d71a363670 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -33,11 +33,10 @@ require 'vcenter_driver2' vm_ref = ARGV[0] vc_cluster_name = ARGV[1] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + begin - - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) - host_id = host['ID'] - vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index a5f47acfda..05ad90ae13 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -33,11 +33,10 @@ vm_ref = ARGV[0] snapshot_name = ARGV[1] vc_cluster_name = ARGV[3] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + begin - - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) - host_id = host['ID'] - vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index bb0e014918..912ccc13ba 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -33,11 +33,10 @@ vm_ref = ARGV[0] snapshot_name = ARGV[1] vc_cluster_name = ARGV[3] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + begin - - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) - host_id = host['ID'] - vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index 2a9d3b1742..723b28931a 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -33,11 +33,10 @@ vm_ref = ARGV[0] snapshot_name = ARGV[1] vc_cluster_name = ARGV[3] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + begin - - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) - host_id = host['ID'] - vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) From 84858fb157a804feb642c1697df29e57214fa13a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:13:13 +0100 Subject: [PATCH 060/297] F #4913: Refactor VM reboot --- src/vmm_mad/remotes/vcenter/reboot | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index bc2fab5e73..1cadfeb286 100755 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,15 +27,23 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] -host = ARGV[1] +vm_ref = ARGV[0] +vc_cluster_name = ARGV[1] + +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.reboot(deploy_id, host) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.reboot + rescue Exception => e - STDERR.puts "Guest reboot of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" + STDERR.puts "Guest reboot of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" exit -1 -end +end \ No newline at end of file From b7ab01406534ab509f4c33e6d40f017c7a7339e5 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:13:46 +0100 Subject: [PATCH 061/297] F #4913: Refactor VM reconfigure --- src/vmm_mad/remotes/vcenter/reconfigure | 31 +++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/reconfigure b/src/vmm_mad/remotes/vcenter/reconfigure index bb8d1b48a0..1878cb7a81 100755 --- a/src/vmm_mad/remotes/vcenter/reconfigure +++ b/src/vmm_mad/remotes/vcenter/reconfigure @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,22 +27,23 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] -host = ARGV[-1] -vm_id = ARGV[-2] +vm_ref = ARGV[0] +vc_cluster_name = ARGV[-1] -vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) -vm.info - -vm_xml = vm.to_xml +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.reconfigure(deploy_id, host, vm_xml) -rescue Exception => e - STDERR.puts "Reconfiguration of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" - exit -1 -end + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.regenerate_context + +rescue Exception => e + STDERR.puts "Reconfiguration of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" + exit -1 +end \ No newline at end of file From 7fb749d17bee2eb59921fce38b1e31491990be37 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:15:52 +0100 Subject: [PATCH 062/297] F #4913: Refactor VM attach/detach disk --- .../remotes/lib/vcenter_driver/datastore.rb | 6 +-- src/vmm_mad/remotes/vcenter/attach_disk | 50 +++++++----------- src/vmm_mad/remotes/vcenter/detach_disk | 51 ++++++++----------- 3 files changed, 43 insertions(+), 64 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 5b1b067f97..9dab3bb719 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -92,12 +92,12 @@ class Datastore "#{img_name}.vmdk" end - def delete_virtual_disk(dc, img_name) + def delete_virtual_disk(img_name) ds_name = self['name'] get_vdm.DeleteVirtualDisk_Task( - name: "[#{ds_name}] #{img_name}", - datacenter: dc.item + :name => "[#{ds_name}] #{img_name}", + :datacenter => get_dc.item ).wait_for_completion end diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 08d2bccfed..92081a5e36 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -16,10 +16,6 @@ # limitations under the License. # # ---------------------------------------------------------------------------- # -############################################################################### -# This script is used retrieve the file size of a disk -############################################################################### - ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION @@ -31,39 +27,31 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'opennebula' +require 'vcenter_driver2' -deploy_id = ARGV[0] -source = ARGV[1] -target = ARGV[2] -target_index = ARGV[3] +vm_ref = ARGV[0] drv_action_enc = ARGV[4] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'VMM_DRIVER_ACTION_DATA') -hostname = drv_action["/VMM_DRIVER_ACTION_DATA/HOST"] -vm_id = drv_action["/VMM_DRIVER_ACTION_DATA/VM/ID"] -ds_name = drv_action["/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/DISK[ATTACH='YES']/DATASTORE"] -img_path = drv_action["/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/DISK[ATTACH='YES']/SOURCE"] -type = drv_action["/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/DISK[ATTACH='YES']/TYPE"] -size_kb = 0 # No volatile disk support at the moment - -if ds_name.nil? || hostname.nil? || img_path.nil? - STDERR.puts "Not enough information to attach disk, missing datastore"\ - " name or vcenter cluster name or image path." - exit -1 -end +vc_cluster_name = drv_action["/VMM_DRIVER_ACTION_DATA/HOST"] +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.attach_disk(hostname, - deploy_id, - ds_name, - img_path, - type, - size_kb) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm_ref = drv_action['/VMM_DRIVER_ACTION_DATA/DEPLOY_ID'] + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.one_item = drv_action.retrieve_xmlelements('VM').first + + vm.attach_disk + rescue Exception => e - STDERR.puts "Error attach image #{img_path}. Reason: #{e.message}" + STDERR.puts "Attach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ + "failed due to \"#{e.message}\"" exit -1 -end +end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index 887b1eb05c..414b3027b8 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -16,10 +16,6 @@ # limitations under the License. # # ---------------------------------------------------------------------------- # -############################################################################### -# This script is used retrieve the file size of a disk -############################################################################### - ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION @@ -31,37 +27,32 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'opennebula' +require 'vcenter_driver2' -deploy_id = ARGV[0] -source = ARGV[1] -target = ARGV[2] -target_index = ARGV[3] +vm_ref = ARGV[0] +vc_cluster_name = ARGV[-1] drv_action_enc = STDIN.read.gsub("\n","") - drv_action = OpenNebula::XMLElement.new -drv_action.initialize_xml(Base64.decode64(drv_action_enc), - 'VMM_DRIVER_ACTION_DATA') +drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'VMM_DRIVER_ACTION_DATA') -hostname = drv_action["/VMM_DRIVER_ACTION_DATA/HOST"] -vm_id = drv_action["/VMM_DRIVER_ACTION_DATA/VM/ID"] -img_path = drv_action["/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/DISK[ATTACH='YES']/SOURCE"] -ds_name = drv_action["/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/DISK[ATTACH='YES']/DATASTORE"] - - -if ds_name.nil? || hostname.nil? || vm_id.nil? | img_path.nil? - STDERR.puts "Not enough information to perform detach_disk." - exit -1 -end +# Get vc_cluster_name from driver action or stick with ARGV[0]? +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.detach_disk(hostname, - deploy_id, - ds_name, - img_path) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm_ref = drv_action['/VMM_DRIVER_ACTION_DATA/DEPLOY_ID'] + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.one_item = drv_action.retrieve_xmlelements('VM').first + + vm.detach_disk + rescue Exception => e - STDERR.puts "Error detaching image #{img_path}. Reason: #{e.message}" + STDERR.puts "Detach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ + "failed due to \"#{e.message}\"" exit -1 -end +end \ No newline at end of file From 9f775e8587eee7c4de004714dac5067627c83a6f Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:18:16 +0100 Subject: [PATCH 063/297] F #4913: VM Methods att/det disk, reconfig, reboot --- .../lib/vcenter_driver/virtual_machine.rb | 108 +++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index c7f97c0dc8..f18ec7b5e2 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -506,8 +506,30 @@ class VirtualMachine attach_nic_array end + # Regenerate context when devices are hot plugged (reconfigure) + def regenerate_context + extraconfig = [] + extraconfig += extraconfig_context + + File.open('/tmp/context','w'){|f| f.puts(extraconfig_context[0][:value])} + + if !extraconfig.empty? + spec_hash = { :extraConfig => extraconfig } + + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + begin + @item.ReconfigVM_Task(:spec => spec).wait_for_completion + rescue Exception => e + raise "Cannot create snapshot for VM: #{e.message}" + end + end + end + # Returns an array of actions to be included in :deviceChange def calculate_add_nic_spec(nic) + + #TODO include VCENTER_NET_REF usage it should be in one_item mac = nic["MAC"] bridge = nic["BRIDGE"] model = nic["MODEL"] @@ -704,8 +726,12 @@ class VirtualMachine self["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) disks.each do |disk| + img_name = get_img_name(disk) + ds = get_effective_ds(disk) + ds_name = ds['name'] + if d.backing.respond_to?(:fileName) && - get_img_name(disk) == d.backing.fileName + "[#{ds_name}] #{img_name}" == d.backing.fileName disks.delete(disk) end @@ -726,6 +752,82 @@ class VirtualMachine attach_disk_array end + # Attach DISK to VM (hotplug) + def attach_disk + # TODO position? and disk size for volatile? + + spec_hash = {} + disk = nil + disks = [] + device_change = [] + + # Extract disk from driver action + one_item.each("TEMPLATE/DISK[ATTACH='YES']") { |d| disks << d } + raise "Found more than one DISK element with ATTACH=YES" if disks.size != 1 + disk = disks.first + + # Check if disk being attached is already connected to the VM + raise "DISK is already connected to VM" if disk_attached_to_vm(disk) + + # Generate vCenter spec and reconfigure VM + device_change << calculate_add_disk_spec(disk) + raise "Could not generate DISK spec" if device_change.empty? + + spec_hash[:deviceChange] = device_change + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) + + begin + @item.ReconfigVM_Task(:spec => spec).wait_for_completion + rescue Exception => e + raise "Cannot attach DISK to VM: #{e.message}" + end + end + + # Detach DISK from VM (hotplug) + def detach_disk + disk = nil + disks = [] + spec_hash = {} + + # Extract disk from driver action + one_item.each("TEMPLATE/DISK[ATTACH='YES']") { |d| disks << d } + raise "Found more than one DISK element with ATTACH=YES" if disks.size != 1 + disk = disks.first + + # Check if disk being detached is connected to the VM + device = disk_attached_to_vm(disk) + raise "DISK is not connected to VM" if device.nil? + + # Generate vCenter spec and reconfigure VM + spec_hash[:deviceChange] = [{ + :operation => :remove, + :device => device + }] + + begin + @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion + rescue Exception => e + raise "Cannot detach DISK to VM: #{e.message}" + end + end + + # Get vcenter device representing DISK object (hotplug) + def disk_attached_to_vm(disk) + img_name = get_img_name(disk) + ds = get_effective_ds(disk) + ds_name = ds['name'] + + device = self["config.hardware.device"].select do |d| + is_disk_or_cdrom?(d) && + d.backing.respond_to?(:fileName) && + d.backing.fileName == "[#{ds_name}] #{img_name}" + end rescue nil + + return nil if device.empty? + + return device.first + end + def calculate_add_disk_spec(disk, position=0) img_name = get_img_name(disk) ds = get_effective_ds(disk) @@ -980,6 +1082,10 @@ class VirtualMachine # actions ############################################################################ + def reboot + @item.RebootGuest.wait_for_completion + end + def poweron @item.PowerOnVM_Task.wait_for_completion end From c03809e9247e97b6d6f374a5aa175c2ed591b3ce Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:19:15 +0100 Subject: [PATCH 064/297] F #4913: No need to specify DC_REF in rm --- src/datastore_mad/remotes/vcenter/rm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index c67d91cc7b..44a01fd75a 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -53,20 +53,18 @@ drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DAT ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -dc_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DC_REF"] img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] check_valid ds_ref, "ds_ref" check_valid host_id, "vcenter_cluster" check_valid img_src, "img_src" -check_valid dc_ref, "dc_ref" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - dc = VCenterDriver::Datacenter.new_from_ref(dc_ref, vi_client) ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - ds.delete_virtual_disk(dc, img_src) + ds.delete_virtual_disk(img_src) + rescue Exception => e STDERR.puts "Error deleting virtual disk #{img_src}."\ " Reason: #{e.message}" From f99363662c587c76a7920d760058fcc1835f1f14 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:21:18 +0100 Subject: [PATCH 065/297] F #4913: Add drv_action to attach_nic --- src/vmm_mad/exec/one_vmm_exec.rb | 2 +- src/vmm_mad/remotes/vcenter/attach_nic | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 9e84bcfca8..719fa71ade 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -895,7 +895,7 @@ class ExecDriver < VirtualMachineDriver { :driver => :vmm, :action => :attach_nic, - :parameters => [:deploy_id, mac, source, model, vn_mad, target] + :parameters => [:deploy_id, mac, source, model, vn_mad, target, xml_data] }, # Execute post-boot networking setup { diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 115c6e0051..4cdb2574ad 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -33,8 +33,12 @@ vm_ref = ARGV[0] mac = ARGV[1] bridge = ARGV[2] model = ARGV[3] +xml_data = ARGV[4] vc_cluster_name = ARGV[-1] +drv_action = OpenNebula::XMLElement.new +drv_action.initialize_xml(xml_data, 'VM') + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) host_id = host['ID'] @@ -43,6 +47,9 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + # Setting one_item with info with xml_data including NIC to be added + vm.one_item = drv_action + nic = { "MAC" => mac, "BRIDGE" => bridge, From 378c1bc7b9ae8614eb0d31ada1b620c024cb073b Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 15 Feb 2017 18:58:01 +0100 Subject: [PATCH 066/297] F #4913: Refactor VM save --- .../lib/vcenter_driver/virtual_machine.rb | 4 ++ src/vmm_mad/remotes/vcenter/save | 57 ++++++++++++++----- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index f18ec7b5e2..b672ef23e6 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1082,6 +1082,10 @@ class VirtualMachine # actions ############################################################################ + def suspend + @item.SuspendVM_Task.wait_for_completion + end + def reboot @item.RebootGuest.wait_for_completion end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 60834b895c..8a0b8e5c8f 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,27 +27,54 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'opennebula' +require 'vcenter_driver2' -deploy_id = ARGV[0] -file = ARGV[1] -host = ARGV[2] -vm_id = ARGV[-2] +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to save the VM. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + +vm_ref = ARGV[0] +vc_cluster_name = ARGV[-1] + +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] drv_action_enc = STDIN.read.gsub("\n","") - drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'VMM_DRIVER_ACTION_DATA') -lcm_state_num = drv_action["/VMM_DRIVER_ACTION_DATA/VM/LCM_STATE"].to_i -lcm_state = OpenNebula::VirtualMachine::LCM_STATE[lcm_state_num] +lcm_state = drv_action["/VMM_DRIVER_ACTION_DATA/VM/LCM_STATE"] +check_valid(lcm_state, "lcm_state") +lcm_state_str = OpenNebula::VirtualMachine::LCM_STATE[lcm_state.to_i] -begin - puts VCenterDriver::VCenterVm.save(deploy_id, host, lcm_state) -rescue Exception => e - STDERR.puts "Save of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" +if lcm_state_str == "SAVE_MIGRATE" + STDERR.puts "Migration between vCenters cluster not supported" + exit -1 +end + +if !["SAVE_SUSPEND", "SAVE_STOP"].include?(lcm_state_str) + STDERR.puts "Wrong lcm state when saving VM" + exit -1 +end + +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.suspend + +rescue Exception => e + STDERR.puts "Save of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" exit -1 end From 76a57313f483c85e97a134c590866e8a857a955b Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 16 Feb 2017 08:09:13 +0100 Subject: [PATCH 067/297] F #4913: Refactor VM restore --- src/vmm_mad/remotes/vcenter/restore | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index 7c9d24b6e5..d0325a2015 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,15 +27,23 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -host = ARGV[-1] -deploy_id = ARGV[2] +vm_ref = ARGV[2] +vc_cluster_name = ARGV[-1] + +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.resume(deploy_id, host) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.poweron + rescue Exception => e - STDERR.puts "Restore of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" + STDERR.puts "Restore of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" exit -1 end From 93b6fd4771547eae1a258b12df7fe8d4a2eed8b9 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 16 Feb 2017 08:23:01 +0100 Subject: [PATCH 068/297] F #4913: VM migrate not supported, replaced bash with ruby --- src/vmm_mad/remotes/vcenter/migrate | 50 ++++++++++++++++++----------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/migrate b/src/vmm_mad/remotes/vcenter/migrate index f0569a0284..39058c4157 100755 --- a/src/vmm_mad/remotes/vcenter/migrate +++ b/src/vmm_mad/remotes/vcenter/migrate @@ -1,20 +1,34 @@ -#!/bin/bash +#!/usr/bin/env ruby -# -------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -#--------------------------------------------------------------------------- # +# ---------------------------------------------------------------------------- # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # -SCRIPT_NAME=$(basename $0) -echo "Action $SCRIPT_NAME not supported" 1>&2 +ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) +end + +$: << RUBY_LIB_LOCATION +$: << File.dirname(__FILE__) + +require 'vcenter_driver2' + +# Not supported +STDERR.puts "Migrate action is not supportef for vCenter" +exit -1 \ No newline at end of file From a04a0ad287c9c39c0b29670e75803d5e4f91116d Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 16 Feb 2017 08:53:12 +0100 Subject: [PATCH 069/297] F #4913: Refactor VM reset --- .../lib/vcenter_driver/virtual_machine.rb | 4 ++++ src/vmm_mad/remotes/vcenter/reset | 24 ++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b672ef23e6..7aebf9e26c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1082,6 +1082,10 @@ class VirtualMachine # actions ############################################################################ + def reset + @item.ResetVM_Task.wait_for_completion + end + def suspend @item.SuspendVM_Task.wait_for_completion end diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 5d9b5296d9..b69c65ed6e 100755 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,15 +27,23 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -deploy_id = ARGV[0] -host = ARGV[1] +vm_ref = ARGV[0] +vc_cluster_name = ARGV[1] + +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] begin - VCenterDriver::VCenterVm.reset(deploy_id, host) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.reset + rescue Exception => e - STDERR.puts "Reset of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" + STDERR.puts "Reset of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to \"#{e.message}\"" exit -1 -end +end \ No newline at end of file From 706380114d6b92c6c4114edba5967470a87a7c24 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 16 Feb 2017 12:09:46 +0100 Subject: [PATCH 070/297] F #4913: Improved code for attach_disk and regenerate_context --- .../lib/vcenter_driver/virtual_machine.rb | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 7aebf9e26c..f83ddb8466 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -508,21 +508,13 @@ class VirtualMachine # Regenerate context when devices are hot plugged (reconfigure) def regenerate_context - extraconfig = [] - extraconfig += extraconfig_context + spec_hash = { :extraConfig => extraconfig_context } + spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - File.open('/tmp/context','w'){|f| f.puts(extraconfig_context[0][:value])} - - if !extraconfig.empty? - spec_hash = { :extraConfig => extraconfig } - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - - begin - @item.ReconfigVM_Task(:spec => spec).wait_for_completion - rescue Exception => e - raise "Cannot create snapshot for VM: #{e.message}" - end + begin + @item.ReconfigVM_Task(:spec => spec).wait_for_completion + rescue Exception => e + raise "Cannot create snapshot for VM: #{e.message}" end end @@ -758,13 +750,10 @@ class VirtualMachine spec_hash = {} disk = nil - disks = [] device_change = [] # Extract disk from driver action - one_item.each("TEMPLATE/DISK[ATTACH='YES']") { |d| disks << d } - raise "Found more than one DISK element with ATTACH=YES" if disks.size != 1 - disk = disks.first + disk = drv_action.retrieve_xmlelements("TEMPLATE/DISK[ATTACH='YES']").first # Check if disk being attached is already connected to the VM raise "DISK is already connected to VM" if disk_attached_to_vm(disk) From b66de4f729721f4e26b09d62c7e31b462adb6688 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 16 Feb 2017 12:29:27 +0100 Subject: [PATCH 071/297] F #4913: Fix attach_disk method --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index f83ddb8466..2287f8600c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -753,7 +753,7 @@ class VirtualMachine device_change = [] # Extract disk from driver action - disk = drv_action.retrieve_xmlelements("TEMPLATE/DISK[ATTACH='YES']").first + disk = one_item.retrieve_xmlelements("TEMPLATE/DISK[ATTACH='YES']").first # Check if disk being attached is already connected to the VM raise "DISK is already connected to VM" if disk_attached_to_vm(disk) From 5c94337f30e861a32616029b4eba1989a2d887db Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 14:39:09 +0100 Subject: [PATCH 072/297] F #4913: Add FileHelper class with methods for cp, clone... --- .../remotes/lib/vcenter_driver/file_helper.rb | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb new file mode 100644 index 0000000000..7332b82f14 --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb @@ -0,0 +1,122 @@ +require 'fileutils' +require 'tempfile' + +module VCenterDriver + +class FileHelper + + def self.get_img_name(disk) + if disk["PERSISTENT"] == "YES" + return disk["SOURCE"] + else + image_name = disk["SOURCE"].split(".").first + disk_id = disk["DISK_ID"] + vm_id = one_item['ID'] + return "#{image_name}-#{vm_id}-#{disk_id}.vmdk" + end + end + + def self.get_img_name_from_path(path, vm_id, disk_id) + return "#{path.split(".").first}-#{vm_id}-#{disk_id}.vmdk" + end + + def self.is_remote_or_needs_unpack?(file) + return is_remote?(file) || needs_unpack?(file) + end + + def self.is_remote?(file) + file.match(%r{^https?://}) + end + + def self.is_vmdk?(file) + type = %x{file #{file}} + + type.include? "VMware" + end + + def self.get_type(file) + type = %x{file -b --mime-type #{file}} + if $?.exitstatus != 0 + STDERR.puts "Can not read file #{file}" + exit(-1) + end + type.strip + end + + def self.needs_unpack?(file_path) + type = get_type(file_path) + type.gsub!(%r{^application/(x-)?}, '') + return %w{bzip2 gzip tar}.include?(type) + end + + def self.vcenter_file_info(file_path) + if File.directory?(file_path) + files = Dir["#{file_path}/*.vmdk"] + found = false + count = 0 + last = nil + + files.each do |f| + if get_type(f).strip == "text/plain" + file_path = f + found = true + break + else + count += 1 + last = f + end + end + + if !found + if count == 1 + file_path = last + found = true + else + STDERR.puts "Could not find vmdk" + exit(-1) + end + end + end + + case get_type(file_path).strip + when "application/octet-stream" + return { + :type => :standalone, + :file => file_path, + :dir => File.dirname(file_path) + } + when "application/x-iso9660-image" + return { + :type => :standalone, + :file => file_path, + :dir => File.dirname(file_path), + :extension => '.iso' + } + when "text/plain" + info = { + :type => :flat, + :file => file_path, + :dir => File.dirname(file_path) + } + + files_list = [] + descriptor = File.read(file_path).split("\n") + flat_files = descriptor.select {|l| l.start_with?("RW")} + + flat_files.each do |f| + files_list << info[:dir] + "/" + + f.split(" ")[3].chomp.chomp('"').reverse.chomp('"').reverse + end + + info[:flat_files] = files_list + + return info + else + STDERR.puts "Unrecognized file type" + exit(-1) + end + end + +end # class FileHelper + +end # module VCenterDriver \ No newline at end of file From 57a7763294cb51dc68432b9085a99084b3c0df58 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 14:58:41 +0100 Subject: [PATCH 073/297] F #4913: Add backtrace to VM actions rescue --- src/vmm_mad/remotes/vcenter/attach_disk | 2 +- src/vmm_mad/remotes/vcenter/attach_nic | 2 +- src/vmm_mad/remotes/vcenter/cancel | 3 ++- src/vmm_mad/remotes/vcenter/deploy | 2 +- src/vmm_mad/remotes/vcenter/detach_disk | 2 +- src/vmm_mad/remotes/vcenter/detach_nic | 2 +- src/vmm_mad/remotes/vcenter/poll | 3 ++- src/vmm_mad/remotes/vcenter/reboot | 3 ++- src/vmm_mad/remotes/vcenter/reconfigure | 3 ++- src/vmm_mad/remotes/vcenter/reset | 3 ++- src/vmm_mad/remotes/vcenter/restore | 3 ++- src/vmm_mad/remotes/vcenter/save | 3 ++- src/vmm_mad/remotes/vcenter/shutdown | 2 +- src/vmm_mad/remotes/vcenter/snapshot_create | 3 ++- src/vmm_mad/remotes/vcenter/snapshot_delete | 3 ++- src/vmm_mad/remotes/vcenter/snapshot_revert | 2 +- 16 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 92081a5e36..29d7c3cbfa 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -52,6 +52,6 @@ begin rescue Exception => e STDERR.puts "Attach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ - "failed due to \"#{e.message}\"" + "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 4cdb2574ad..75c8c162d6 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -60,6 +60,6 @@ begin rescue Exception => e STDERR.puts "Attach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ - "failed due to \"#{e.message}\"" + "failed due to \"#{e.message}\"\n#{e.backtrace}" exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 6e3481efdd..b9aa166ff8 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -49,6 +49,7 @@ begin vm.poweroff_hard rescue Exception => e - STDERR.puts "Cancel VM #{deploy_id} failed due to \"#{e.message}\"" + STDERR.puts "Cancel VM #{deploy_id} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index cdee076d1e..28ad912eac 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -64,6 +64,6 @@ begin puts vm['_ref'] rescue Exception => e STDERR.puts "Deploy of VM #{vm_id} on vCenter cluster #{cluster_name} " + - "with #{dfile} failed due to \"#{e.message}\"" + "with #{dfile} failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index 414b3027b8..4f0bade167 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -53,6 +53,6 @@ begin rescue Exception => e STDERR.puts "Detach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ - "failed due to \"#{e.message}\"" + "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index 4fefb3e5c5..4bf51ce7b3 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -47,6 +47,6 @@ begin rescue Exception => e STDERR.puts "Detach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ - "failed due to \"#{e.message}\"" + "failed due to \"#{e.message}\"\n#{e.backtrace}" exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index d71a363670..ede21fb202 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -47,6 +47,7 @@ begin rescue Exception => e STDERR.puts "Cannot poll info for VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index 1cadfeb286..ac64f8611a 100755 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -44,6 +44,7 @@ begin rescue Exception => e STDERR.puts "Guest reboot of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit -1 end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/reconfigure b/src/vmm_mad/remotes/vcenter/reconfigure index 1878cb7a81..15528e1330 100755 --- a/src/vmm_mad/remotes/vcenter/reconfigure +++ b/src/vmm_mad/remotes/vcenter/reconfigure @@ -44,6 +44,7 @@ begin rescue Exception => e STDERR.puts "Reconfiguration of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit -1 end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index b69c65ed6e..4c1348bf1f 100755 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -44,6 +44,7 @@ begin rescue Exception => e STDERR.puts "Reset of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit -1 end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index d0325a2015..1a15107e46 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -44,6 +44,7 @@ begin rescue Exception => e STDERR.puts "Restore of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 8a0b8e5c8f..b2280b1d6a 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -75,6 +75,7 @@ begin rescue Exception => e STDERR.puts "Save of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 0d03736d89..aa13247288 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -56,6 +56,6 @@ begin VCenterDriver::VCenterVm.shutdown(deploy_id, host, lcm_state, keep_disks, disks, cloned_tmplt) rescue Exception => e STDERR.puts "Shutdown of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"" + "due to \"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 05ad90ae13..eaed76bfbb 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -45,6 +45,7 @@ begin rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} failed due to \"#{e.message}\"" + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index 912ccc13ba..ccade6b202 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -45,6 +45,7 @@ begin rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ - "#{vc_cluster_name} could not be deleted due to \"#{e.message}\"" + "#{vc_cluster_name} could not be deleted due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit(-1) end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index 723b28931a..61c77e644b 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -46,6 +46,6 @@ begin rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} could not be reverted due "\ - "to \"#{e.message}\"" + "to \"#{e.message}\"\n#{e.backtrace}" exit(-1) end From ad42eeff3004390961324473b9b194c88d3138b2 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 14:59:45 +0100 Subject: [PATCH 074/297] F #4913: Add FileHelper to vcenter_driver2 --- src/vmm_mad/remotes/lib/vcenter_driver2.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb index 3dfd843648..a09318eec4 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver2.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver2.rb @@ -56,3 +56,4 @@ require 'host' require 'datastore' require 'virtual_machine' require 'network' +require 'file_helper' From 09dda2ab8bd288d4e6f7675628b2db8e3e7cfb4a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 15:02:53 +0100 Subject: [PATCH 075/297] F #4913: Move get_img_name to FileHelper --- .../lib/vcenter_driver/virtual_machine.rb | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 2287f8600c..977b0e27cf 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -220,19 +220,6 @@ class VirtualMachine end end - # @return String image name - def get_img_name(disk) - if disk["PERSISTENT"] == "YES" - return disk["SOURCE"] - else - image_id = disk["IMAGE_ID"] - disk_id = disk["DISK_ID"] - vm_id = one_item['ID'] - - return "one-#{image_id}-#{vm_id}-#{disk_id}.vmdk" - end - end - # @return VCenterDriver::Datastore datastore where the disk will live under def get_effective_ds(disk) if disk["PERSISTENT"] == "YES" @@ -718,7 +705,7 @@ class VirtualMachine self["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) disks.each do |disk| - img_name = get_img_name(disk) + img_name = VCenterDriver::FileHelper.get_img_name(disk) ds = get_effective_ds(disk) ds_name = ds['name'] @@ -802,7 +789,7 @@ class VirtualMachine # Get vcenter device representing DISK object (hotplug) def disk_attached_to_vm(disk) - img_name = get_img_name(disk) + img_name = VCenterDriver::FileHelper.get_img_name(disk) ds = get_effective_ds(disk) ds_name = ds['name'] @@ -818,7 +805,7 @@ class VirtualMachine end def calculate_add_disk_spec(disk, position=0) - img_name = get_img_name(disk) + img_name = VCenterDriver::FileHelper.get_img_name(disk) ds = get_effective_ds(disk) ds_name = ds['name'] From 25fbf0e051c84490330acc56882d3502ffffd9bf Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 15:10:22 +0100 Subject: [PATCH 076/297] F #4913: Add run in silence methods for uploading/downloading files --- .../remotes/lib/vcenter_driver/vi_client.rb | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 71e6f3c9d5..996686aaaf 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -86,6 +86,38 @@ class VIClient exit -1 end end + + def self.in_silence + begin + orig_stderr = $stderr.clone + orig_stdout = $stdout.clone + $stderr.reopen File.new('/dev/null', 'w') + $stdout.reopen File.new('/dev/null', 'w') + retval = yield + rescue Exception => e + $stdout.reopen orig_stdout + $stderr.reopen orig_stderr + raise e + ensure + $stdout.reopen orig_stdout + $stderr.reopen orig_stderr + end + retval + end + + def self.in_stderr_silence + begin + orig_stderr = $stderr.clone + $stderr.reopen File.new('/dev/null', 'w') + retval = yield + rescue Exception => e + $stderr.reopen orig_stderr + raise e + ensure + $stderr.reopen orig_stderr + end + retval + end end end # module VCenterDriver From 5755ba264d1fcf4f2bc7550b884972ff89b2a187 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 17:09:10 +0100 Subject: [PATCH 077/297] F #4913: Fix get_img_name --- src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb | 3 +-- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb index 7332b82f14..179b08d7ea 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb @@ -5,13 +5,12 @@ module VCenterDriver class FileHelper - def self.get_img_name(disk) + def self.get_img_name(disk, vm_id) if disk["PERSISTENT"] == "YES" return disk["SOURCE"] else image_name = disk["SOURCE"].split(".").first disk_id = disk["DISK_ID"] - vm_id = one_item['ID'] return "#{image_name}-#{vm_id}-#{disk_id}.vmdk" end end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 977b0e27cf..9d9e0c758d 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -705,7 +705,7 @@ class VirtualMachine self["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) disks.each do |disk| - img_name = VCenterDriver::FileHelper.get_img_name(disk) + img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) ds = get_effective_ds(disk) ds_name = ds['name'] @@ -789,7 +789,7 @@ class VirtualMachine # Get vcenter device representing DISK object (hotplug) def disk_attached_to_vm(disk) - img_name = VCenterDriver::FileHelper.get_img_name(disk) + img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) ds = get_effective_ds(disk) ds_name = ds['name'] @@ -805,7 +805,7 @@ class VirtualMachine end def calculate_add_disk_spec(disk, position=0) - img_name = VCenterDriver::FileHelper.get_img_name(disk) + img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) ds = get_effective_ds(disk) ds_name = ds['name'] From c1a67c2339667acb4506e5967a414eacd96ae3b1 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 17:59:47 +0100 Subject: [PATCH 078/297] F #4913: Add methods for DS and TM actions --- .../remotes/lib/vcenter_driver/datastore.rb | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 9dab3bb719..a8ed35edae 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -118,6 +118,72 @@ class Datastore target_path end + def create_directory(directory) + ds_name = self['name'] + + create_directory_params = { + :name => "[#{ds_name}] #{directory}", + :datacenter => get_dc.item, + :createParentDirectories => true + } + + begin + get_fm.MakeDirectory(create_directory_params) + rescue RbVmomi::VIM::FileAlreadyExists => e + # Do nothing if directory already exists + end + end + + def upload_file(source_path, target_path) + @item.upload(target_path, source_path) + end + + def download_file(source, target) + @item.download(url_prefix + file, temp_folder + file) + end + + # Get file size for image handling + def stat(img_str) + ds_name = self['name'] + + img_path = File.dirname img_str + img_name = File.basename img_str + + # Create Search Spec + spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new + spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, + RbVmomi::VIM::IsoImageFileQuery.new] + spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, + :fileSize => true, + :fileType => true, + :modification => true) + spec.matchPattern=[img_name] + + search_params = {'datastorePath' => "[#{ds_name}] #{img_path}", + 'searchSpec' => spec} + + # Perform search task and return results + begin + search_task = self['browser']. + SearchDatastoreSubFolders_Task(search_params) + + search_task.wait_for_completion + + file_size = search_task.info.result[0].file[0].fileSize rescue nil + + raise "Could not get file size" if file_size.nil? + + (file_size / 1024) / 1024 + + rescue + raise "Could not find file." + end + end + + def get_fm + self['_connection.serviceContent.fileManager'] + end + def get_vdm self['_connection.serviceContent.virtualDiskManager'] end @@ -135,6 +201,82 @@ class Datastore Datacenter.new(item) end + def get_dc_path + dc = get_dc + p = dc.item.parent + path = [dc.item.name] + while p.instance_of? RbVmomi::VIM::Folder + path.unshift(p.name) + p = p.parent + end + path.delete_at(0) # The first folder is the root "Datacenters" + path.join('/') + end + + def generate_file_url(path) + protocol = self[_connection.http.use_ssl?] ? 'https://' : 'http://' + hostname = self[_connection.http.address] + port = self[_connection.http.port] + dcpath = get_dc_path + + # This creates the vcenter file URL for uploading or downloading files + # e.g: + url = "#{protocol}#{hostname}:#{port}/folder/#{path}?dcPath=#{dcpath}&dsName=#{self[name]}" + return url + end + + def download_to_stdout(remote_path) + url = generate_file_url(remote_path) + pid = spawn(CURLBIN, + "-k", '--noproxy', '*', '-f', + "-b", self[_connection.cookie], + url) + + Process.waitpid(pid, 0) + fail "download failed" unless $?.success? + end + + def is_descriptor?(remote_path) + url = generate_file_url(remote_path) + + rout, wout = IO.pipe + pid = spawn(CURLBIN, + "-I", "-k", '--noproxy', '*', '-f', + "-b", _connection.cookie, + url, + :out => wout, + :err => '/dev/null') + + Process.waitpid(pid, 0) + fail "read image header failed" unless $?.success? + + wout.close + size = rout.readlines.select{|l| + l.start_with?("Content-Length") + }[0].sub("Content-Length: ","") + rout.close + size.chomp.to_i < 4096 # If <4k, then is a descriptor + end + + def get_text_file remote_path + url = generate_file_url(remote_path) + + rout, wout = IO.pipe + pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', + "-b", _connection.cookie, + url, + :out => wout, + :err => '/dev/null' + + Process.waitpid(pid, 0) + fail "get text file failed" unless $?.success? + + wout.close + output = rout.readlines + rout.close + return output + end + # This is never cached def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref), vi_client) From 7ae1436cbb3fc13586063fc0ce5f740ba797d829 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:01:29 +0100 Subject: [PATCH 079/297] F #4913: Code improvements TM clone --- src/tm_mad/vcenter/clone | 67 ++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index 5271c5738b..e30e177f88 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -47,18 +47,6 @@ def check_valid(parameter, label) end end -def get_ds(ds_id, client) - ds = OpenNebula::Datastore.new_with_id(ds_id, client) - - rc = ds.info - if OpenNebula::is_error?(rc) - STDERR.puts(rc.message) - exit -1 - end - - ds -end - ################################################################################ src = ARGV[0] @@ -66,47 +54,52 @@ dst = ARGV[1] vm_id = ARGV[2] source_ds_id = ARGV[3] +check_valid src, "src" +check_valid dst, "dst" +check_valid vm_id, "vm_id" +check_valid source_ds_id, "source_ds_id" + target_ds_id = dst.split("/")[-3] disk_id = dst.split(".")[-1] src_host, src_path = src.split ":" hostname, dst_path = dst.split ":" -################################################################################ - -host_pool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool) - -# host_id -host = host_pool.select{|host| host['NAME'] == hostname}[0] rescue nil - -if host.nil? - STDERR.puts "No host found (#{hostname})." - exit -1 -end - +# Get host ID +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) host_id = host['ID'] -# get ds_ref (source image) +# Get datastores refs source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id) source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] +check_valid source_ds_ref, "source_ds" +check_valid target_ds_ref, "target_ds" + # calculate target path -target_path = src_path.split(".").first + "-#{vm_id}-#{disk_id}.vmdk" +target_path = VCenterDriver::FileHelper.get_img_name_from_path(src_path, + vm_id, + disk_id) +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) -# vi_client -vi_client = VCenterDriver::VIClient.new_from_host(host_id) + source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) -source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) + if source_ds_ref == target_ds_ref + target_ds_vc = source_ds_vc + else + target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + end -if source_ds_ref == target_ds_ref - target_ds_vc = source_ds_vc -else - target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + target_ds_name_vc = target_ds_vc['name'] + + source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) +rescue Exception => e + STDERR.puts "Error clone virtual disk #{src_path} in "\ + "datastore #{target_ds_ref}. "\ + "Reason: #{e.message}\n#{e.backtrace}" + exit -1 end - -target_ds_name_vc = target_ds_vc['name'] - -source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) From f2621e6294d4ccacc86d90a715c4fbec5e4c4699 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:02:39 +0100 Subject: [PATCH 080/297] F #4913: Refactor TM cpds --- src/tm_mad/vcenter/cpds | 75 +++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index fe84ae4486..ec912b00c7 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -34,11 +34,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'opennebula' -require 'vcenter_driver' -require 'digest' - -client = OpenNebula::Client.new +require 'vcenter_driver2' ################################################################################ @@ -54,61 +50,52 @@ end src = ARGV[0] target_path = ARGV[1] -snap_id = ARGV[2] +snap_id = ARGV[2] #TODO snapshots? vmid = ARGV[3] target_ds_id = ARGV[4] +check_valid src,"src" +check_valid target_path,"target_path" +check_valid vmid,"vmid" +check_valid target_ds_id,"target_ds_id" + source_ds_id = src.split("/")[-3] disk_id = src.split(".")[-1] - hostname, src_path = src.split ":" -################################################################################ +# Get host ID +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) +host_id = host['ID'] -vm = OpenNebula::VirtualMachine.new_with_id(vmid, client) -rc = vm.info -if OpenNebula.is_error?(rc) - STDERR.puts rc.message - exit -1 -end - -persistent = vm["TEMPLATE/DISK[DISK_ID=#{disk_id}]/PERSISTENT"] == "YES" - -if persistent - src_path = vm["TEMPLATE/DISK[DISK_ID=#{disk_id}]/SOURCE"] -else - src_path = "one_#{vmid}_#{disk_id}.vmdk" -end - -if vm.state == 3 +# Get OpenNebula VM +one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) +disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") +src_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid) +if one_vm.state == 3 STDERR.puts "'disk-saveas' operation is not supported for running VMs." exit 1 end -################################################################################ +# Get source and target ds ref +source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id) +source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] -ds_pool = OpenNebula::DatastorePool.new(client) - -rc = ds_pool.info -if OpenNebula.is_error?(rc) - STDERR.puts rc.message - exit -1 -end - -xpath = "/DATASTORE_POOL/DATASTORE[ID='#{source_ds_id}']/TEMPLATE/VCENTER_NAME" -source_ds = ds_pool[xpath] - -xpath = "/DATASTORE_POOL/DATASTORE[ID='#{target_ds_id}']/TEMPLATE/VCENTER_NAME" -target_ds = ds_pool[xpath] - -################################################################################ +target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) +target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + vi_client = VCenterDriver::VIClient.new_from_host(host_id) - vi_client.copy_virtual_disk(src_path, source_ds, target_path, target_ds) + source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) + + target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + + target_ds_name_vc = target_ds_vc['name'] + + source_ds_vc.copy_virtual_disk(src_path, source_ds, + target_path, target_ds_name_vc) rescue Exception => e - STDERR.puts "Error cloning img #{src_path} size. Reason: #{e.message}" + STDERR.puts "Error copying img #{src_path}. "\ + "Reason: #{e.message}\n#{e.backtrace}" exit -1 end From 100e7e0a007ba4849be27e3c4ad4b559b150ab78 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:03:23 +0100 Subject: [PATCH 081/297] F #4913: Refactor TM delete --- src/tm_mad/vcenter/delete | 61 ++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index 10dbf275ad..e7be094b85 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -42,31 +42,52 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'opennebula' +require 'vcenter_driver2' -hostname, img_path = ARGV[0].split(":") -vmid = ARGV[1] -dsid = ARGV[2] +################################################################################ -client = OpenNebula::Client.new -vm = OpenNebula::VirtualMachine.new_with_id(vmid, client) -vm.info - -disk_id = img_path.split(".")[-1] - -persistent = vm["TEMPLATE/DISK[DISK_ID=#{disk_id}]/PERSISTENT"] - -if persistent != "YES" - img_path = "one_#{vmid}_#{disk_id}.vmdk" +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to delete the image. " + + "Missing '#{label}'." + exit -1 + end end -begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id - ds_name = VCenterDriver::VIClient.find_ds_name(dsid) +################################################################################ - vi_client.delete_virtual_disk(img_path, ds_name) +path = ARGV[0] +vmid = ARGV[1] +dsid = ARGV[2] + +check_valid path, "path" +check_valid vmid, "vmid" +check_valid dsid, "dsid" + +hostname, img_path = path.split(":") + +# Get host ID +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) +host_id = host['ID'] + +# Get DS ref +one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) +ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] + +check_valid ds_ref, "ds_ref" + +# Get image path +disk_id = img_path.split(".")[-1] +one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) +disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") +img_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid) + +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + ds_vc = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + + ds_vc.delete_virtual_disk(img_path) rescue Exception => e STDERR.puts "Error delete virtual disk #{img_path} in datastore #{dsid}."\ " Reason: #{e.message}\n#{e.backtrace}" From bbe7844076324f51e15c472efa5f896dbb0aafd6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:04:14 +0100 Subject: [PATCH 082/297] F #4913: Refactor TM mkimage --- src/tm_mad/vcenter/mkimage | 66 +++++++++---------- .../remotes/lib/vcenter_driver/file_helper.rb | 6 +- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index e40ba8d4ab..86f362e69f 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -35,16 +35,13 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'opennebula' -require 'vcenter_driver' - -client = OpenNebula::Client.new +require 'vcenter_driver2' ################################################################################ def check_valid(parameter, label) if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to create the volatile disk. " + + STDERR.puts "Not enough information to create the virtual disk. " + "Missing '#{label}'." exit -1 end @@ -53,46 +50,47 @@ end ################################################################################ size = ARGV[0] -fstype = ARGV[1] -hostname, img_name = ARGV[2].split(":") +path = ARGV[2] vmid = ARGV[3] dsid = ARGV[4] +check_valid size, "size" +check_valid path, "path" +check_valid vmid, "vmid" +check_valid dsid, "dsid" + +hostname, img_name = path.split(":") disk_id = img_name.split(".")[-1] -img_name = "one_#{vmid}_#{disk_id}" +img_name = "one-#{vmid}-#{disk_id}" -################################################################################ +# Get host ID +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) +host_id = host['ID'] -vm = OpenNebula::VirtualMachine.new_with_id(vmid, client) +# Get datastore ref +one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) +ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] -rc = vm.info -if OpenNebula.is_error?(rc) - puts rc.message - exit -1 -end +# Get adapter and disk type +one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) +adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/ADAPTER_TYPE"] -adapter_type = vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/ADAPTER_TYPE"] -check_valid adapter_type, "adapter_type" - -# TODO get the DISK_TYPE -# disk_type = vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/DISK_TYPE"] -# if disk_type.nil? || disk_type.empty? -# disk_type = "thin" -# end +# TODO disk_type support, that info is not coming thin, thick... +# disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/DISK_TYPE"] +# disk_type = "thin" if disk_type.nil? || disk_type.empty? disk_type = "thin" -begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id - ds_name = VCenterDriver::VIClient.find_ds_name(dsid) +check_valid adapter_type, "adapter_type" + +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + ds_vc = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + + ds_vc.create_virtual_disk(img_name, size, adapter_type, disk_type) - puts vi_client.create_virtual_disk(img_name, - ds_name, - size, - adapter_type, - disk_type) rescue Exception => e - STDERR.puts "Error creating virtual disk in #{ds_name}."\ - " Reason: #{e.message}" + STDERR.puts "Error creating virtual disk in #{ds_vc['name']}."\ + " Reason: #{e.message}\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb index 179b08d7ea..a1ea8dc3bb 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb @@ -9,7 +9,11 @@ class FileHelper if disk["PERSISTENT"] == "YES" return disk["SOURCE"] else - image_name = disk["SOURCE"].split(".").first + if disk["SOURCE"] + image_name = disk["SOURCE"].split(".").first + else + image_name = "one" #For volatile disks + end disk_id = disk["DISK_ID"] return "#{image_name}-#{vm_id}-#{disk_id}.vmdk" end From 7596dad33c0c2fc232319e9ec68a241526872559 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:06:15 +0100 Subject: [PATCH 083/297] F #4913: Refactor DS cp --- src/datastore_mad/remotes/vcenter/cp | 232 +++++------------- .../remotes/vcenter_downloader.rb | 34 ++- src/datastore_mad/remotes/vcenter_uploader.rb | 60 +---- 3 files changed, 88 insertions(+), 238 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index faae47d14c..e192779224 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -16,10 +16,6 @@ # limitations under the License. # # ---------------------------------------------------------------------------- # -############################################################################### -# This script is used retrieve the file size of a disk -############################################################################### - ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION @@ -33,124 +29,20 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'opennebula' -require 'fileutils' -require 'tempfile' +require 'vcenter_driver2' -def is_remote?(file) - file.match(%r{^https?://}) -end +################################################################################ -def is_vmdk?(file) - type = %x{file #{file}} - - type.include? "VMware" -end - -def get_type(file) - type = %x{file -b --mime-type #{file}} - if $?.exitstatus != 0 - STDERR.puts "Can not read file #{file}" - exit(-1) - end - - type.strip -end - -def needs_unpack?(file) - temp = Tempfile.new('one-') - temp.close - - file_path = file - - if is_remote?(file) - rc = system("curl --fail -sS -k -L #{file_path} | head -c 1024 > #{temp.path}") - if !rc - STDERR.puts "Can not download file #{file_path}" - exit(-1) - end - file_path = temp.path - end - - type = get_type(file_path) - type.gsub!(%r{^application/(x-)?}, '') - unpack = %w{bzip2 gzip tar}.include?(type) - - temp.unlink - - unpack -end - -def vmdk_info(file) - file_path = file - - if File.directory?(file_path) - files = Dir["#{file_path}/*.vmdk"] - found = false - count = 0 - last = nil - - files.each do |f| - if get_type(f).strip == "text/plain" - file_path = f - found = true - break - else - count += 1 - last = f - end - end - - if !found - if count == 1 - file_path = last - found = true - else - STDERR.puts "Could not find vmdk" - exit(-1) - end - end - end - - case get_type(file_path).strip - when "application/octet-stream" - return { - :type => :standalone, - :file => file_path, - :dir => File.dirname(file_path) - } - when "application/x-iso9660-image" - return { - :type => :standalone, - :file => file_path, - :dir => File.dirname(file_path), - :extension => '.iso' - } - when "text/plain" - info = { - :type => :flat, - :file => file_path, - :dir => File.dirname(file_path) - } - - files_list = [] - descriptor = File.read(file_path).split("\n") - flat_files = descriptor.select {|l| l.start_with?("RW")} - - flat_files.each do |f| - files_list << info[:dir] + "/" + - f.split(" ")[3].chomp.chomp('"').reverse.chomp('"').reverse - end - - info[:flat_files] = files_list - - return info - else - STDERR.puts "Unrecognized file type" - exit(-1) +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to clone the image. " + + "Missing '#{label}'." + exit -1 end end +################################################################################ + drv_action_enc = ARGV[0] id = ARGV[1] @@ -158,64 +50,60 @@ drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] md5 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"] sha1 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1"] nodecomp = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/NO_DECOMPRESS"] limit_bw = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/LIMIT_TRANSFER_BW"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] +check_valid img_path, "img_path" -if img_path.nil? - STDERR.puts "Not enough information to register the image,"\ - " missing image path." - exit(-1) -end - +# if image is already in a vCenter datastore return the path if img_path.start_with? "vcenter://" - # File already in the vCenter datastore - puts img_path.sub("vcenter://","") exit(0) end -downsh_args = " " -downsh_args += "--md5 #{md5} " if md5 and !md5.empty? and !md5.eql? "-" -downsh_args += "--sha1 #{sha1} " if sha1 and !sha1.empty? -downsh_args += "--nodecomp " if nodecomp and !nodecomp.empty? -downsh_args += "--limit #{limit_bw} " if limit_bw and !limit_bw.empty? +temp_file = nil +filename = File.basename(img_path) +target_path = Digest::MD5.hexdigest(Time.now.to_s + id.to_s) -downloader = "#{File.dirname(__FILE__)}/../downloader.sh #{downsh_args}" +# If image is in a remote http location it has to be downloaded +# or if is a zipped file it has to be unzipped in a temp folder -# Generate target path -str_for_target_path = Time.now.to_s + id.to_s -target_path = Digest::MD5.hexdigest(str_for_target_path) - -files_to_upload = Array.new - -file_path = img_path -skip_download = false -delete_file = false -files_to_upload = [] - -if is_remote?(file_path) || needs_unpack?(file_path) +if VCenterDriver::FileHelper.is_remote_or_needs_unpack?(img_path) temp_folder = File.join(VAR_LOCATION, "vcenter") temp_file = File.join(temp_folder, File.basename(target_path)) + + # Create tmp directory FileUtils.mkdir_p(temp_folder) if !File.directory?(temp_folder) - rc = system("#{downloader} #{file_path} #{temp_file}") + # Specify downloader args + downsh_args = " " + downsh_args += "--md5 #{md5} " if md5 and !md5.empty? and !md5.eql? "-" + downsh_args += "--sha1 #{sha1} " if sha1 and !sha1.empty? + downsh_args += "--nodecomp " if nodecomp and !nodecomp.empty? + downsh_args += "--limit #{limit_bw} " if limit_bw and !limit_bw.empty? + + downloader = "#{File.dirname(__FILE__)}/../downloader.sh #{downsh_args}" + + + rc = system("#{downloader} #{img_path} #{temp_file}") + if !rc - STDERR.puts "Error downloading #{file_path}" + STDERR.puts "Error downloading #{img_path}" FileUtils.rm_rf(temp_file) - exit(-1) + exit -1 end - delete_file = true - original_path = File.basename(file_path) - file_path = temp_file + img_path = temp_file end -info = vmdk_info(file_path) +# Time to upload files to vCenter +files_to_upload = [] + +info = VCenterDriver::FileHelper.vcenter_file_info(img_path) extension = info[:extension] || '' case info[:type] @@ -227,34 +115,35 @@ when :flat end files_to_upload.each_with_index do |f, index| - path = "#{target_path}/#{File.basename(f)}" + + path = "#{target_path}/#{File.basename(f)}" # Change path for gzipped standalone file if(target_path == File.basename(f)) - path = "#{target_path}/#{original_path}" - + path = "#{target_path}/#{filename}" + # remove gz or bz2 if part of filename - if path.end_with?("gz") and is_vmdk?(f) - path.gsub!(/gz$/,'') + if path.end_with?("gz") and VCenterDriver::FileHelper.is_vmdk?(f) + path.gsub!(/gz$/,'') end - if path.end_with?("bz2") and is_vmdk?(f) - path.gsub!(/bz2$/,'') - end - end + if path.end_with?("bz2") and VCenterDriver::FileHelper.is_vmdk?(f) + path.gsub!(/bz2$/,'') + end + end - # Change path if vmdk is part of filename - # but it's not the extension' - if /[^.]+vmdk$/.match(path) and is_vmdk?(f) + # Change path if vmdk is part of filename + # but it's not the extension' + if /[^.]+vmdk$/.match(path) and VCenterDriver::FileHelper.is_vmdk?(f) path.gsub!(/vmdk$/,'') - extension = '.vmdk' + extension = '.vmdk' end if index == files_to_upload.size - 1 - uploader_args = hostname + " " + ds_name + " " + + uploader_args = host_id + " " + ds_ref + " " + "#{path}#{extension}" + " " + f else - uploader_args = hostname + " " + ds_name + " " + + uploader_args = host_id + " " + ds_ref + " " + path + " " + f + " &> /dev/null" end @@ -262,12 +151,11 @@ files_to_upload.each_with_index do |f, index| rc = system(cmd) if !rc - STDERR.puts "Can not upload file #{f}" - FileUtils.rm_rf(temp_file) if delete_file + STDERR.puts "Cannot upload file #{f}" + FileUtils.rm_rf(temp_file) if temp_file exit(-1) end end - -FileUtils.rm_rf(temp_file) if delete_file +FileUtils.rm_rf(temp_file) if temp_file diff --git a/src/datastore_mad/remotes/vcenter_downloader.rb b/src/datastore_mad/remotes/vcenter_downloader.rb index 7beb68beb6..46d30c2b5e 100755 --- a/src/datastore_mad/remotes/vcenter_downloader.rb +++ b/src/datastore_mad/remotes/vcenter_downloader.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -29,33 +29,29 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' require 'uri' require 'cgi' require 'fileutils' -vcenter_url = ARGV[0] +vcenter_url = ARGV[0] -u = URI.parse(vcenter_url) -params = CGI.parse(u.query) +u = URI.parse(vcenter_url) +params = CGI.parse(u.query) -hostname = params["param_host"][0] -ds_name = params["param_dsname"][0] -img_src = u.host + u.path +vc_cluster_name = params["param_host"][0] +ds_name = params["param_dsname"][0] +img_src = u.host + u.path begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id - ds = vi_client.get_datastore(ds_name) + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) + host_id = host['ID'] - if ds.is_a? RbVmomi::VIM::StoragePod - STDERR.puts "Cannot download images from StoragePod #{ds_name} on #{hostname}."\ - "Reason: Not supported" - exit(-1) - end + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) - if ds.is_descriptor? img_src + if ds.is_descriptor?(img_src) descriptor_name = File.basename u.path temp_folder = VAR_LOCATION + "/vcenter/" + descriptor_name + "/" FileUtils.mkdir_p(temp_folder) if !File.directory?(temp_folder) @@ -73,7 +69,7 @@ begin VCenterDriver::VIClient.in_silence do files_to_download.each{|file| - ds.download(url_prefix + file, temp_folder + file) + ds.download_file(url_prefix + file, temp_folder + file) } end @@ -91,7 +87,7 @@ begin else # Setting "." as the source will read from the stdin VCenterDriver::VIClient.in_stderr_silence do - ds.download_to_stdout img_src + ds.download_to_stdout(img_src) end end rescue Exception => e diff --git a/src/datastore_mad/remotes/vcenter_uploader.rb b/src/datastore_mad/remotes/vcenter_uploader.rb index a5ca52245d..35901aa1d4 100755 --- a/src/datastore_mad/remotes/vcenter_uploader.rb +++ b/src/datastore_mad/remotes/vcenter_uploader.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,63 +27,29 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' -hostname = ARGV[0] -ds_name = ARGV[1] -target_path = ARGV[2] -source_path = ARGV[3] +host_id = ARGV[0] +target_ds_ref = ARGV[1] +target_path = ARGV[2] +source_path = ARGV[3] begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) - ds = vi_client.get_datastore(ds_name) + # Setting "." as the source will read from the stdin + source_path = "." if source_path.nil? - if ds.is_a? RbVmomi::VIM::StoragePod - STDERR.puts "Cannot upload image to StoragePod #{ds_name} on #{hostname}."\ - "Reason: Not supported" - exit(-1) - end - - # Monkey path datastore objects. Can not be done patching the class - # as the library redefines it when a new object is created. Using both - # the database vmodl.db and the Datastore.rb - # - # This patch fixes a bug in rbvmomi. It does not specify the path of the - # datacenter. If it is inside a folder it could not be found. - class < e - STDERR.puts "Cannot upload image to datastore #{ds_name} on #{hostname}."\ + STDERR.puts "Cannot upload image to datastore #{ds_name} "\ "Reason: #{e.message}" exit -1 end From 50ba69df990385b5927c3deff2ebed957bdfcb6c Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:07:28 +0100 Subject: [PATCH 084/297] F #4913: Refactor DS stat --- src/datastore_mad/remotes/vcenter/stat | 43 +++++++++++++++----------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index b3dab82226..618c89e8d6 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -17,7 +17,7 @@ # ---------------------------------------------------------------------------- # ############################################################################### -# This script is used retrieve the file size of a disk +# This script is used retrieve the file size of a disk ############################################################################### ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) @@ -31,7 +31,19 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' +require 'vcenter_driver2' + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to stat the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ drv_action_enc = ARGV[0] id = ARGV[1] @@ -39,24 +51,21 @@ id = ARGV[1] drv_action =OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] -if ds_name.nil? || - hostname.nil? || - img_path.nil? - STDERR.puts "Not enough information to stat the image." - exit -1 -end +check_valid ds_ref, "ds_ref" +check_valid host_id, "vcenter_cluster" +check_valid img_path, "img_path" if img_path.start_with? "vcenter://" begin - img_path = img_path.sub("vcenter://","") - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + + ds.stat(img_path) - puts vi_client.stat(ds_name, img_path) rescue Exception => e STDERR.puts "Error calculating image #{img_path} size."\ " Reason: #{e.message}" @@ -65,6 +74,4 @@ if img_path.start_with? "vcenter://" else cmd = "#{File.dirname(__FILE__)}/../fs/stat #{drv_action_enc}" system(cmd) -end - - +end \ No newline at end of file From 013979a620a239bd23809f6abb51d356113369a9 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 17 Feb 2017 18:08:06 +0100 Subject: [PATCH 085/297] F #4913: Refactor DS clone --- src/datastore_mad/remotes/vcenter/clone | 82 +++++++++++-------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index f0807acc42..e5fdd74a24 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -16,10 +16,6 @@ # limitations under the License. # # ---------------------------------------------------------------------------- # -############################################################################### -# This script is used retrieve the file size of a disk -############################################################################### - ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION @@ -31,61 +27,55 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'opennebula' -require 'vcenter_driver' +require 'vcenter_driver2' require 'digest' +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to clone the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + drv_action_enc = ARGV[0] id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -target_ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] -src_img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/CLONING_ID"] +target_ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +src_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] +src_img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/CLONING_ID"] -if target_ds_name.nil? || hostname.nil? || img_path.nil? - STDERR.puts "Not enough information to clone the image, missing datastore"\ - " name or vcenter cluster name or image path." - exit -1 -end +check_valid src_img_id, "cloning id" +check_valid host_id, "vcenter cluster" +check_valid src_path, "image path" +check_valid target_ds_ref, "target ds ref" -# Get source image -client = OpenNebula::Client.new - -src_img = OpenNebula::Image.new_with_id(src_img_id, client) - -rc = src_img.info -if OpenNebula.is_error?(rc) - STDERR.puts rc.message - exit -1 -end - -src_ds_id = src_img['DATASTORE_ID'] - -# Get the source datastore -src_ds = OpenNebula::Datastore.new_with_id(src_ds_id, client) - -rc = src_ds.info -if OpenNebula.is_error?(rc) - STDERR.puts rc.message - exit -1 -end - -src_ds_name = src_ds["TEMPLATE/VCENTER_NAME"] +# Get source ds_ref +source_img = VCenterDriver::VIHelper.one_item(OpenNebula::Image, src_img_id) +source_ds_id = source_img['DATASTORE_ID'] +source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id) +source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] # Generate target path -str_for_target_path = Time.now.to_s + id.to_s -target_path = Digest::MD5.hexdigest(str_for_target_path) + ".vmdk" +target_path = Digest::MD5.hexdigest(Time.now.to_s + id.to_s) + ".vmdk" begin - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - vi_client = VCenterDriver::VIClient.new host_id + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) - puts vi_client.copy_virtual_disk(img_path, src_ds_name, target_path, target_ds_name) + target_ds = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + target_ds_name = target_ds['name'] + + puts ds.copy_virtual_disk(src_path, target_ds_name, target_path) rescue Exception => e - STDERR.puts "Error cloning img #{img_path} size. Reason: #{e.message}" + STDERR.puts "Error cloning img #{src_path}. Reason: #{e.message}" exit -1 -end +end \ No newline at end of file From d7162d4252890fae613c5f11631a88b3ace14564 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 20 Feb 2017 10:57:36 +0100 Subject: [PATCH 086/297] F #4913: Replace and with && in if clauses (DS cp) --- src/datastore_mad/remotes/vcenter/cp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index e192779224..9b07f99878 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -81,10 +81,10 @@ if VCenterDriver::FileHelper.is_remote_or_needs_unpack?(img_path) # Specify downloader args downsh_args = " " - downsh_args += "--md5 #{md5} " if md5 and !md5.empty? and !md5.eql? "-" - downsh_args += "--sha1 #{sha1} " if sha1 and !sha1.empty? - downsh_args += "--nodecomp " if nodecomp and !nodecomp.empty? - downsh_args += "--limit #{limit_bw} " if limit_bw and !limit_bw.empty? + downsh_args += "--md5 #{md5} " if md5 && !md5.empty? && !md5.eql?("-") + downsh_args += "--sha1 #{sha1} " if sha1 && !sha1.empty? + downsh_args += "--nodecomp " if nodecomp && !nodecomp.empty? + downsh_args += "--limit #{limit_bw} " if limit_bw && !limit_bw.empty? downloader = "#{File.dirname(__FILE__)}/../downloader.sh #{downsh_args}" @@ -123,18 +123,18 @@ files_to_upload.each_with_index do |f, index| path = "#{target_path}/#{filename}" # remove gz or bz2 if part of filename - if path.end_with?("gz") and VCenterDriver::FileHelper.is_vmdk?(f) + if path.end_with?("gz") && VCenterDriver::FileHelper.is_vmdk?(f) path.gsub!(/gz$/,'') end - if path.end_with?("bz2") and VCenterDriver::FileHelper.is_vmdk?(f) + if path.end_with?("bz2") && VCenterDriver::FileHelper.is_vmdk?(f) path.gsub!(/bz2$/,'') end end # Change path if vmdk is part of filename # but it's not the extension' - if /[^.]+vmdk$/.match(path) and VCenterDriver::FileHelper.is_vmdk?(f) + if /[^.]+vmdk$/.match(path) && VCenterDriver::FileHelper.is_vmdk?(f) path.gsub!(/vmdk$/,'') extension = '.vmdk' end From 36c66e58888e30bec4bea0eb46ec3b97094199fb Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Mon, 20 Feb 2017 12:15:48 +0100 Subject: [PATCH 087/297] F #4913: Fix symlinks for dummy and not supported vmm actions --- src/vmm_mad/remotes/common/dummy.sh | 3 +- .../not_supported.sh} | 40 +++++++++++-------- src/vmm_mad/remotes/vcenter/migrate | 35 +--------------- src/vmm_mad/remotes/vcenter/preconfigure | 1 + 4 files changed, 26 insertions(+), 53 deletions(-) rename src/vmm_mad/remotes/{vcenter/prereconfigure => common/not_supported.sh} (67%) mode change 100755 => 120000 src/vmm_mad/remotes/vcenter/migrate create mode 120000 src/vmm_mad/remotes/vcenter/preconfigure diff --git a/src/vmm_mad/remotes/common/dummy.sh b/src/vmm_mad/remotes/common/dummy.sh index 2ed62a9d7b..3ee910cdd1 100755 --- a/src/vmm_mad/remotes/common/dummy.sh +++ b/src/vmm_mad/remotes/common/dummy.sh @@ -16,5 +16,4 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -SCRIPT_NAME=$(basename $0) -echo "Action $SCRIPT_NAME not supported" 1>&2 +exit 0 diff --git a/src/vmm_mad/remotes/vcenter/prereconfigure b/src/vmm_mad/remotes/common/not_supported.sh similarity index 67% rename from src/vmm_mad/remotes/vcenter/prereconfigure rename to src/vmm_mad/remotes/common/not_supported.sh index 564d84fc38..3f0a8a1be5 100755 --- a/src/vmm_mad/remotes/vcenter/prereconfigure +++ b/src/vmm_mad/remotes/common/not_supported.sh @@ -1,20 +1,26 @@ -#!/usr/bin/env ruby +#!/bin/bash -# ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -# ---------------------------------------------------------------------------- # +# -------------------------------------------------------------------------- # +# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # -exit(0) +script_name=$(basename $0) + +source $(dirname $0)/../../scripts_common.sh + +error_message "$script_name: Operation not supported" + +exit 1 diff --git a/src/vmm_mad/remotes/vcenter/migrate b/src/vmm_mad/remotes/vcenter/migrate deleted file mode 100755 index 39058c4157..0000000000 --- a/src/vmm_mad/remotes/vcenter/migrate +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env ruby - -# ---------------------------------------------------------------------------- # -# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -# ---------------------------------------------------------------------------- # - -ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) - -if !ONE_LOCATION - RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) -else - RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) -end - -$: << RUBY_LIB_LOCATION -$: << File.dirname(__FILE__) - -require 'vcenter_driver2' - -# Not supported -STDERR.puts "Migrate action is not supportef for vCenter" -exit -1 \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/migrate b/src/vmm_mad/remotes/vcenter/migrate new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/migrate @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/preconfigure b/src/vmm_mad/remotes/vcenter/preconfigure new file mode 120000 index 0000000000..300563f2ad --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/preconfigure @@ -0,0 +1 @@ +../common/dummy.sh \ No newline at end of file From 245dc56c548bd9be46771b6e90444360ed72b86d Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 20 Feb 2017 13:43:09 +0100 Subject: [PATCH 088/297] F #4913: Add missing backtrace to rescue clause in VMM/DS actions --- src/datastore_mad/remotes/vcenter/clone | 3 ++- src/datastore_mad/remotes/vcenter/cp | 2 +- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/datastore_mad/remotes/vcenter/stat | 2 +- .../remotes/vcenter_downloader.rb | 2 +- src/datastore_mad/remotes/vcenter_uploader.rb | 2 +- .../lib/vcenter_driver/virtual_machine.rb | 18 +++++++++--------- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index e5fdd74a24..6705b9e81a 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -76,6 +76,7 @@ begin puts ds.copy_virtual_disk(src_path, target_ds_name, target_path) rescue Exception => e - STDERR.puts "Error cloning img #{src_path}. Reason: #{e.message}" + STDERR.puts "Error cloning img #{src_path}."\ + " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 end \ No newline at end of file diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index 9b07f99878..8633f87a17 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -77,7 +77,7 @@ if VCenterDriver::FileHelper.is_remote_or_needs_unpack?(img_path) temp_file = File.join(temp_folder, File.basename(target_path)) # Create tmp directory - FileUtils.mkdir_p(temp_folder) if !File.directory?(temp_folder) + FileUtils.mkdir_p(temp_folder) # Specify downloader args downsh_args = " " diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 522bf7d8fe..3cec932448 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -82,6 +82,6 @@ begin puts ds.create_virtual_disk(img_name, size, adapter_type, disk_type) rescue Exception => e STDERR.puts "Error creating virtual disk #{img_src}."\ - " Reason: #{e.message}" + " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 618c89e8d6..9db2c3d02b 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -68,7 +68,7 @@ if img_path.start_with? "vcenter://" rescue Exception => e STDERR.puts "Error calculating image #{img_path} size."\ - " Reason: #{e.message}" + " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 end else diff --git a/src/datastore_mad/remotes/vcenter_downloader.rb b/src/datastore_mad/remotes/vcenter_downloader.rb index 46d30c2b5e..87077e8a25 100755 --- a/src/datastore_mad/remotes/vcenter_downloader.rb +++ b/src/datastore_mad/remotes/vcenter_downloader.rb @@ -92,6 +92,6 @@ begin end rescue Exception => e STDERR.puts "Cannot download image #{u.path} from datastore #{ds_name} "\ - "on #{hostname}. Reason: #{e.message}" + "on #{hostname}. Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/datastore_mad/remotes/vcenter_uploader.rb b/src/datastore_mad/remotes/vcenter_uploader.rb index 35901aa1d4..761ae4c870 100755 --- a/src/datastore_mad/remotes/vcenter_uploader.rb +++ b/src/datastore_mad/remotes/vcenter_uploader.rb @@ -50,7 +50,7 @@ begin puts target_path rescue Exception => e STDERR.puts "Cannot upload image to datastore #{ds_name} "\ - "Reason: #{e.message}" + "Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 9d9e0c758d..846d987ad4 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -272,7 +272,7 @@ class VirtualMachine :spec => clone_spec).wait_for_completion rescue Exception => e if !e.message.start_with?('DuplicateName') - raise "Cannot clone VM Template: #{e.message}" + raise "Cannot clone VM Template: #{e.message}\n#{e.backtrace}" end vm_folder = cluster.get_dc.vm_folder @@ -501,7 +501,7 @@ class VirtualMachine begin @item.ReconfigVM_Task(:spec => spec).wait_for_completion rescue Exception => e - raise "Cannot create snapshot for VM: #{e.message}" + raise "Cannot create snapshot for VM: #{e.message}\n#{e.backtrace}" end end @@ -644,7 +644,7 @@ class VirtualMachine begin @item.ReconfigVM_Task(:spec => spec).wait_for_completion rescue Exception => e - raise "Cannot attach NIC to VM: #{e.message}" + raise "Cannot attach NIC to VM: #{e.message}\n#{e.backtrace}" end end @@ -687,7 +687,7 @@ class VirtualMachine begin @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion rescue Exception => e - raise "Cannot detach NIC from VM: #{e.message}" + raise "Cannot detach NIC from VM: #{e.message}\n#{e.backtrace}" end end @@ -755,7 +755,7 @@ class VirtualMachine begin @item.ReconfigVM_Task(:spec => spec).wait_for_completion rescue Exception => e - raise "Cannot attach DISK to VM: #{e.message}" + raise "Cannot attach DISK to VM: #{e.message}\n#{e.backtrace}" end end @@ -783,7 +783,7 @@ class VirtualMachine begin @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion rescue Exception => e - raise "Cannot detach DISK to VM: #{e.message}" + raise "Cannot detach DISK to VM: #{e.message}\n#{e.backtrace}" end end @@ -1000,7 +1000,7 @@ class VirtualMachine begin @item.CreateSnapshot_Task(snapshot_hash).wait_for_completion rescue Exception => e - raise "Cannot create snapshot for VM: #{e.message}" + raise "Cannot create snapshot for VM: #{e.message}\n#{e.backtrace}" end return snapshot_name @@ -1018,7 +1018,7 @@ class VirtualMachine revert_snapshot_hash = { :_this => snapshot } snapshot.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion rescue Exception => e - raise "Cannot revert snapshot of VM: #{e.message}" + raise "Cannot revert snapshot of VM: #{e.message}\n#{e.backtrace}" end end @@ -1037,7 +1037,7 @@ class VirtualMachine } snapshot.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion rescue Exception => e - raise "Cannot delete snapshot of VM: #{e.message}" + raise "Cannot delete snapshot of VM: #{e.message}\n#{e.backtrace}" end end From bc63765e4e080d3c2b720960ca5c2778302ae395 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 20 Feb 2017 13:44:22 +0100 Subject: [PATCH 089/297] F #4913: Add missing backtrace to rescue clause in VMM/DS actions --- src/datastore_mad/remotes/vcenter/rm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 44a01fd75a..bbf18956ac 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -67,6 +67,6 @@ begin rescue Exception => e STDERR.puts "Error deleting virtual disk #{img_src}."\ - " Reason: #{e.message}" + " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 end From a41960b751f0949666957a870d00c71843aeab99 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 20 Feb 2017 14:05:29 +0100 Subject: [PATCH 090/297] F #4913: Replace += with << in DS cp action for a better performance --- src/datastore_mad/remotes/vcenter/cp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index 8633f87a17..b98f0485b7 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -81,10 +81,10 @@ if VCenterDriver::FileHelper.is_remote_or_needs_unpack?(img_path) # Specify downloader args downsh_args = " " - downsh_args += "--md5 #{md5} " if md5 && !md5.empty? && !md5.eql?("-") - downsh_args += "--sha1 #{sha1} " if sha1 && !sha1.empty? - downsh_args += "--nodecomp " if nodecomp && !nodecomp.empty? - downsh_args += "--limit #{limit_bw} " if limit_bw && !limit_bw.empty? + downsh_args << "--md5 #{md5} " if md5 && !md5.empty? && !md5.eql?("-") + downsh_args << "--sha1 #{sha1} " if sha1 && !sha1.empty? + downsh_args << "--nodecomp " if nodecomp && !nodecomp.empty? + downsh_args << "--limit #{limit_bw} " if limit_bw && !limit_bw.empty? downloader = "#{File.dirname(__FILE__)}/../downloader.sh #{downsh_args}" From 469ff036a748d64620f92767423cd25f324d63f6 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 10:06:49 +0100 Subject: [PATCH 091/297] F #4913: Tweak the snapshot actions Snapshot name is stored in the description field of vCenter The information is passed via STDIN and not as positional argument --- src/vmm_mad/exec/one_vmm_exec.rb | 3 ++- .../lib/vcenter_driver/virtual_machine.rb | 26 +++++++++---------- src/vmm_mad/remotes/vcenter/snapshot_create | 9 +++++-- src/vmm_mad/remotes/vcenter/snapshot_delete | 4 +-- src/vmm_mad/remotes/vcenter/snapshot_revert | 4 +-- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 719fa71ade..557437fefb 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -739,7 +739,8 @@ class ExecDriver < VirtualMachineDriver id, host, ACTION[:snapshot_create], - :script_name => "snapshot_create") + :script_name => "snapshot_create", + :stdin => xml_data) end # diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 9d9e0c758d..26d1bd16c8 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -989,12 +989,12 @@ class VirtualMachine end # Create a snapshot for the VM - def create_snapshot(snapshot_name, vm_ref) + def create_snapshot(snap_id, snap_name) snapshot_hash = { - :name => snapshot_name, - :description => "OpenNebula Snapshot of VM #{vm_ref}", - :memory => true, - :quiesce => true + :name => snap_id, + :description => snap_name, + :memory => true, + :quiesce => true } begin @@ -1003,14 +1003,14 @@ class VirtualMachine raise "Cannot create snapshot for VM: #{e.message}" end - return snapshot_name + return snap_id end # Revert to a VM snapshot - def revert_snapshot(snapshot_name) + def revert_snapshot(snap_id) snapshot_list = self["snapshot.rootSnapshotList"] - snapshot = find_snapshot_in_list(snapshot_list, snapshot_name) + snapshot = find_snapshot_in_list(snapshot_list, snap_id) return nil if !snapshot @@ -1023,10 +1023,10 @@ class VirtualMachine end # Delete VM snapshot - def delete_snapshot(snapshot_name) + def delete_snapshot(snap_id) snapshot_list = self["snapshot.rootSnapshotList"] - snapshot = find_snapshot_in_list(snapshot_list, snapshot_name) + snapshot = find_snapshot_in_list(snapshot_list, snap_id) return nil if !snapshot @@ -1041,12 +1041,12 @@ class VirtualMachine end end - def find_snapshot_in_list(list, snapshot_name) + def find_snapshot_in_list(list, snap_id) list.each do |i| - if i.name == snapshot_name + if i.name == snap_id.to_s return i.snapshot elsif !i.childSnapshotList.empty? - snap = find_snapshot(i.childSnapshotList, snapshot_name) + snap = find_snapshot(i.childSnapshotList, snap_id) return snap if snap end end rescue nil diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index eaed76bfbb..8fc488b2e7 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -30,18 +30,23 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' vm_ref = ARGV[0] -snapshot_name = ARGV[1] +snap_id = ARGV[1] vc_cluster_name = ARGV[3] +drv_action = OpenNebula::XMLElement.new +drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VMM_DRIVER_ACTION_DATA') + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) host_id = host['ID'] +snap_name = drv_action["VM/TEMPLATE/SNAPSHOT[ACTIVE='YES']/NAME"] + begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - vm.create_snapshot(snapshot_name, vm_ref) + vm.create_snapshot(snap_id, snap_name) rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index ccade6b202..f27a1e5beb 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -30,7 +30,7 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' vm_ref = ARGV[0] -snapshot_name = ARGV[1] +snap_id = ARGV[1] vc_cluster_name = ARGV[3] host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) @@ -41,7 +41,7 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - vm.delete_snapshot(snapshot_name) + vm.delete_snapshot(snap_id) rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index 61c77e644b..ad1069aece 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -30,7 +30,7 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' vm_ref = ARGV[0] -snapshot_name = ARGV[1] +snap_id = ARGV[1] vc_cluster_name = ARGV[3] host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) @@ -41,7 +41,7 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - vm.revert_snapshot(snapshot_name) + vm.revert_snapshot(snap_id) rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ From e70caf371515253547f146cddacef85e2b5a19c3 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 10:07:35 +0100 Subject: [PATCH 092/297] F #4913: Attach-nic requires the XML data of the VM This information is passed via STDIN and not as a positional argument. --- src/vmm_mad/exec/one_vmm_exec.rb | 2 +- src/vmm_mad/remotes/vcenter/attach_nic | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 557437fefb..af8e9360c3 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -896,7 +896,7 @@ class ExecDriver < VirtualMachineDriver { :driver => :vmm, :action => :attach_nic, - :parameters => [:deploy_id, mac, source, model, vn_mad, target, xml_data] + :parameters => [:deploy_id, mac, source, model, vn_mad, target] }, # Execute post-boot networking setup { diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 75c8c162d6..29cd03ba24 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -33,11 +33,12 @@ vm_ref = ARGV[0] mac = ARGV[1] bridge = ARGV[2] model = ARGV[3] -xml_data = ARGV[4] vc_cluster_name = ARGV[-1] drv_action = OpenNebula::XMLElement.new -drv_action.initialize_xml(xml_data, 'VM') +drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VMM_DRIVER_ACTION_DATA') + +vm_xml = drv_action.retrieve_xmlelements("VM").first host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) host_id = host['ID'] @@ -47,13 +48,13 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - # Setting one_item with info with xml_data including NIC to be added - vm.one_item = drv_action + # Setting one_item with info with the vm_xml including NIC to be added + vm.one_item = vm_xml nic = { - "MAC" => mac, + "MAC" => mac, "BRIDGE" => bridge, - "MODEL" => model + "MODEL" => model } vm.attach_nic(nic) From f73116758e3d4947ecc01828a9f1ad08b8c24571 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 11:16:22 +0100 Subject: [PATCH 093/297] F #4913: Remove unneeded vm_ref assignments --- src/vmm_mad/remotes/vcenter/attach_disk | 2 -- src/vmm_mad/remotes/vcenter/cancel | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 29d7c3cbfa..6d37042f62 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -42,8 +42,6 @@ host_id = host['ID'] begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - vm_ref = drv_action['/VMM_DRIVER_ACTION_DATA/DEPLOY_ID'] - vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) vm.one_item = drv_action.retrieve_xmlelements('VM').first diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index b9aa166ff8..989b8894cd 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -29,7 +29,7 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -deploy_id = ARGV[0] +vm_ref = ARGV[0] host = ARGV[1] vm_id = ARGV[-2] @@ -42,14 +42,13 @@ host_id = host['ID'] begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - vm_ref = drv_action['VM/DEPLOY_ID'] - vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + vm.one_item = drv_action.retrieve_xmlelements('VM').first vm.poweroff_hard rescue Exception => e - STDERR.puts "Cancel VM #{deploy_id} failed due to "\ + STDERR.puts "Cancel VM #{vm_ref} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit(-1) end From a15b38284681f1818ac4bab5ab29b623d56c457f Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 11:25:55 +0100 Subject: [PATCH 094/297] F #4913: Refactor VMM Shutdown --- .../lib/vcenter_driver/virtual_machine.rb | 60 +++++++++-- src/vmm_mad/remotes/vcenter/detach_disk | 10 +- src/vmm_mad/remotes/vcenter/shutdown | 101 ++++++++++++++---- 3 files changed, 136 insertions(+), 35 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 846d987ad4..4e87ade0c1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -41,6 +41,8 @@ class VirtualMachine POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE + VM_SHUTDOWN_TIMEOUT = 600 #10 minutes til poweroff hard + attr_accessor :item include Memoize @@ -760,16 +762,9 @@ class VirtualMachine end # Detach DISK from VM (hotplug) - def detach_disk - disk = nil - disks = [] + def detach_disk(disk) spec_hash = {} - # Extract disk from driver action - one_item.each("TEMPLATE/DISK[ATTACH='YES']") { |d| disks << d } - raise "Found more than one DISK element with ATTACH=YES" if disks.size != 1 - disk = disks.first - # Check if disk being detached is connected to the VM device = disk_attached_to_vm(disk) raise "DISK is not connected to VM" if device.nil? @@ -783,7 +778,30 @@ class VirtualMachine begin @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion rescue Exception => e - raise "Cannot detach DISK to VM: #{e.message}\n#{e.backtrace}" + raise "Cannot detach DISK from VM: #{e.message}\n#{e.backtrace}" + end + end + + # Detach all DISKs from VM (terminate action) + def detach_all_disks + spec_hash = {} + spec_hash[:deviceChange] = [] + + self["config.hardware.device"].each do |disk| + if is_disk_or_cdrom?(disk) + spec_hash[:deviceChange] << { + :operation => :remove, + :device => disk + } + end + end + + return nil if spec_hash[:deviceChange].empty? + + begin + @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion + rescue Exception => e + raise "Cannot detach all DISKs from VM: #{e.message}\n#{e.backtrace}" end end @@ -1058,6 +1076,30 @@ class VirtualMachine # actions ############################################################################ + def shutdown + # Ignore ShutdownGuest exceptions, maybe VM hasn't openvm tools + @item.ShutdownGuest rescue nil + + # Check if VM has been powered off + (0..VM_SHUTDOWN_TIMEOUT).each do + break if @item.runtime.powerState == "poweredOff" + sleep 1 + end + + # If VM hasn't been powered off, do it now + if @item.runtime.powerState != "poweredOff" + poweroff_hard + end + end + + def destroy + @item.Destroy_Task.wait_for_completion + end + + def mark_as_template + @item.MarkAsTemplate + end + def reset @item.ResetVM_Task.wait_for_completion end diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index 4f0bade167..3da93644e1 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -43,13 +43,15 @@ host_id = host['ID'] begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - vm_ref = drv_action['/VMM_DRIVER_ACTION_DATA/DEPLOY_ID'] - vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - vm.one_item = drv_action.retrieve_xmlelements('VM').first + disks = drv_action.retrieve_xmlelements("VM/TEMPLATE/DISK[ATTACH='YES']") - vm.detach_disk + raise "Could not find a DISK element with ATTACH=YES" if disks.size == 0 + + raise "Found more than one DISK element with ATTACH=YES" if disks.size > 1 + + vm.detach_disk(disks.first) rescue Exception => e STDERR.puts "Detach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index aa13247288..2258fefacc 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -27,35 +27,92 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver' -require 'opennebula' +require 'vcenter_driver2' -deploy_id = ARGV[0] -host = ARGV[1] -vm_id = ARGV[-2] +################################################################################ +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to shutdown the VM. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + +vm_ref = ARGV[0] +vc_cluster_name = ARGV[1] + +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] drv_action_enc = STDIN.read.gsub("\n","") - drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'VMM_DRIVER_ACTION_DATA') -lcm_state_num = drv_action["/VMM_DRIVER_ACTION_DATA/VM/LCM_STATE"].to_i -lcm_state = OpenNebula::VirtualMachine::LCM_STATE[lcm_state_num] -keep_disks = !drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].nil? && - drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].downcase=="yes" -disks = [drv_action.to_hash["VMM_DRIVER_ACTION_DATA"]["VM"]["TEMPLATE"]["DISK"]].flatten.compact +lcm_state = drv_action["/VMM_DRIVER_ACTION_DATA/VM/LCM_STATE"] +check_valid(lcm_state, "lcm_state") +lcm_state_str = OpenNebula::VirtualMachine::LCM_STATE[lcm_state.to_i] -cloned_tmplt = nil -if !drv_action['/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/CLONING_TEMPLATE_ID'].nil? - cloned_tmplt = drv_action['/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/TEMPLATE_ID'] -end - -begin - VCenterDriver::VCenterVm.shutdown(deploy_id, host, lcm_state, keep_disks, disks, cloned_tmplt) -rescue Exception => e - STDERR.puts "Shutdown of VM #{deploy_id} on host #{host} failed " + - "due to \"#{e.message}\"\n#{e.backtrace}" +if !["SHUTDOWN", "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY"].include?(lcm_state_str) + STDERR.puts "Wrong lcm state when shutting down VM" + exit -1 +end + +# Get disk elements from drv_action +disks = drv_action.retrieve_xmlelements("VM/TEMPLATE/DISK") + +## TODO keep_disks and copy_template +keep_disks = + !drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].nil? && + drv_action['/VMM_DRIVER_ACTION_DATA/VM/USER_TEMPLATE/KEEP_DISKS_ON_DONE'].downcase=="yes" + +# Manage instantiate to persistent +instantiate_to_persistent = + !drv_action['/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/CLONING_TEMPLATE_ID'].nil? + +template_id = drv_action['/VMM_DRIVER_ACTION_DATA/VM/TEMPLATE/TEMPLATE_ID'] + +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.shutdown #Undeploy, Poweroff or Terminate + + # If Terminate action has been called + if lcm_state_str == "SHUTDOWN" + + # TODO: KEEP_DISKS_ON_DONE deprecation / invisible disks + if keep_disks + # Detach all disks from VM so they are not deleted if VM is destroyed + vm.detach_all_disks + else + # Detach only DISK elements from template + disks.each do |disk| + vm.detach_disk(disk) + end + end + + # If the VM was instantiated to persistent keep the VM else destroy it + if instantiate_to_persistent + vm.mark_as_template #Convert VM to template in vCenter + + # Create new Opennebula template and set VCENTER_TEMPLATE_REF + new_template = OpenNebula::Template.new_with_id(template_id, + OpenNebula::Client.new) + new_template.info + new_template.update("VCENTER_TEMPLATE_REF= #{vm.item._ref}", true) + else + vm.destroy + end + end + +rescue Exception => e + STDERR.puts "Shutdown of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" exit -1 end From 4b7f700d75d7825abcfb0d54821dfe593afb3051 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 12:08:50 +0100 Subject: [PATCH 095/297] F #4913: Add explicit VIM close connection to avoid idle vcenter sessions --- src/datastore_mad/remotes/vcenter/clone | 2 ++ src/datastore_mad/remotes/vcenter/mkfs | 3 +++ src/datastore_mad/remotes/vcenter/monitor | 2 ++ src/datastore_mad/remotes/vcenter/rm | 2 ++ src/datastore_mad/remotes/vcenter/stat | 2 ++ src/datastore_mad/remotes/vcenter_downloader.rb | 2 ++ src/datastore_mad/remotes/vcenter_uploader.rb | 2 ++ src/im_mad/remotes/vcenter.d/vcenter.rb | 2 ++ src/tm_mad/vcenter/clone | 2 ++ src/tm_mad/vcenter/cpds | 2 ++ src/tm_mad/vcenter/mkimage | 1 + src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb | 4 ++++ src/vmm_mad/remotes/vcenter/attach_disk | 1 + src/vmm_mad/remotes/vcenter/attach_nic | 1 + src/vmm_mad/remotes/vcenter/cancel | 2 ++ src/vmm_mad/remotes/vcenter/deploy | 6 ++++-- src/vmm_mad/remotes/vcenter/detach_disk | 1 + src/vmm_mad/remotes/vcenter/detach_nic | 1 + src/vmm_mad/remotes/vcenter/poll | 1 + src/vmm_mad/remotes/vcenter/reboot | 1 + src/vmm_mad/remotes/vcenter/reconfigure | 1 + src/vmm_mad/remotes/vcenter/reset | 1 + src/vmm_mad/remotes/vcenter/restore | 1 + src/vmm_mad/remotes/vcenter/save | 1 + src/vmm_mad/remotes/vcenter/shutdown | 2 ++ src/vmm_mad/remotes/vcenter/snapshot_create | 1 + src/vmm_mad/remotes/vcenter/snapshot_delete | 1 + src/vmm_mad/remotes/vcenter/snapshot_revert | 1 + 28 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 6705b9e81a..fe5fd3606f 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -75,6 +75,8 @@ begin target_ds_name = target_ds['name'] puts ds.copy_virtual_disk(src_path, target_ds_name, target_path) + + vi_client.close_connection rescue Exception => e STDERR.puts "Error cloning img #{src_path}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 3cec932448..d99ef099b5 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -77,9 +77,12 @@ end begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) puts ds.create_virtual_disk(img_name, size, adapter_type, disk_type) + + vi_client.close_connection rescue Exception => e STDERR.puts "Error creating virtual disk #{img_src}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index ee773f57fa..1ad33a1820 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -51,3 +51,5 @@ vi_client = VCenterDriver::VIClient.new_from_host(host_id) ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) puts ds.monitor + +vi_client.close_connection diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index bbf18956ac..4ca2be1421 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -61,10 +61,12 @@ check_valid img_src, "img_src" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) ds.delete_virtual_disk(img_src) + vi_client.close_connection rescue Exception => e STDERR.puts "Error deleting virtual disk #{img_src}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 9db2c3d02b..1072c8fe7e 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -62,10 +62,12 @@ check_valid img_path, "img_path" if img_path.start_with? "vcenter://" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) ds.stat(img_path) + vi_client.close_connection rescue Exception => e STDERR.puts "Error calculating image #{img_path} size."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/datastore_mad/remotes/vcenter_downloader.rb b/src/datastore_mad/remotes/vcenter_downloader.rb index 87077e8a25..186b79c610 100755 --- a/src/datastore_mad/remotes/vcenter_downloader.rb +++ b/src/datastore_mad/remotes/vcenter_downloader.rb @@ -90,6 +90,8 @@ begin ds.download_to_stdout(img_src) end end + + vi_client.close_connection rescue Exception => e STDERR.puts "Cannot download image #{u.path} from datastore #{ds_name} "\ "on #{hostname}. Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/datastore_mad/remotes/vcenter_uploader.rb b/src/datastore_mad/remotes/vcenter_uploader.rb index 761ae4c870..1f22c8c3ca 100755 --- a/src/datastore_mad/remotes/vcenter_uploader.rb +++ b/src/datastore_mad/remotes/vcenter_uploader.rb @@ -48,6 +48,8 @@ begin end puts target_path + + vi_client.close_connection rescue Exception => e STDERR.puts "Cannot upload image to datastore #{ds_name} "\ "Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/vcenter.rb index bc6615da43..61b68f1d0e 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/vcenter.rb @@ -66,3 +66,5 @@ dc = cluster.get_dc ds_folder = dc.datastore_folder ds_folder.fetch! puts ds_folder.monitor + +vi_client.close_connection diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index e30e177f88..634c039385 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -97,6 +97,8 @@ begin target_ds_name_vc = target_ds_vc['name'] source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) + + vi_client.close_connection rescue Exception => e STDERR.puts "Error clone virtual disk #{src_path} in "\ "datastore #{target_ds_ref}. "\ diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index ec912b00c7..473800ed5d 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -94,6 +94,8 @@ begin source_ds_vc.copy_virtual_disk(src_path, source_ds, target_path, target_ds_name_vc) + + vi_client.close_connection rescue Exception => e STDERR.puts "Error copying img #{src_path}. "\ "Reason: #{e.message}\n#{e.backtrace}" diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 86f362e69f..4cfcbb9991 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -89,6 +89,7 @@ begin ds_vc.create_virtual_disk(img_name, size, adapter_type, disk_type) + vi_client.close_connection rescue Exception => e STDERR.puts "Error creating virtual disk in #{ds_vc['name']}."\ " Reason: #{e.message}\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index 996686aaaf..a2201c933e 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -18,6 +18,10 @@ class VIClient !!@rp end + def close_connection + @vim.close + end + # @return RbVmomi::VIM:: objects def self.get_entities(folder, type, entities=[]) if folder == [] diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 6d37042f62..8af88330e9 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -48,6 +48,7 @@ begin vm.attach_disk + vi_client.close_connection rescue Exception => e STDERR.puts "Attach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 29cd03ba24..e7e09cfa20 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -59,6 +59,7 @@ begin vm.attach_nic(nic) + vi_client.close_connection rescue Exception => e STDERR.puts "Attach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 989b8894cd..13faa5a3ea 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -47,6 +47,8 @@ begin vm.one_item = drv_action.retrieve_xmlelements('VM').first vm.poweroff_hard + + vi_client.close_connection rescue Exception => e STDERR.puts "Cancel VM #{vm_ref} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 28ad912eac..ae196cce2d 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -39,9 +39,9 @@ drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VM') deploy_id = drv_action["DEPLOY_ID"] host_id = drv_action["HISTORY_RECORDS/HISTORY/HID"] -vi_client = VCenterDriver::VIClient.new_from_host(host_id) - begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + if deploy_id && !deploy_id.empty? # VM is not new, we just need to reconfigure it and to power it on vm = VCenterDriver::VirtualMachine.new_from_ref(deploy_id, vi_client) @@ -62,6 +62,8 @@ begin vm.set_running(true) puts vm['_ref'] + + vi_client.close_connection rescue Exception => e STDERR.puts "Deploy of VM #{vm_id} on vCenter cluster #{cluster_name} " + "with #{dfile} failed due to \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index 3da93644e1..fd734a9307 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -53,6 +53,7 @@ begin vm.detach_disk(disks.first) + vi_client.close_connection rescue Exception => e STDERR.puts "Detach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index 4bf51ce7b3..9ff8f9910f 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -45,6 +45,7 @@ begin vm.detach_nic(nic) + vi_client.close_connection rescue Exception => e STDERR.puts "Detach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index ede21fb202..f7de851522 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -45,6 +45,7 @@ begin puts vm.info + vi_client.close_connection rescue Exception => e STDERR.puts "Cannot poll info for VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index ac64f8611a..b3363ee8c7 100755 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -42,6 +42,7 @@ begin vm.reboot + vi_client.close_connection rescue Exception => e STDERR.puts "Guest reboot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/reconfigure b/src/vmm_mad/remotes/vcenter/reconfigure index 15528e1330..5d86dab59f 100755 --- a/src/vmm_mad/remotes/vcenter/reconfigure +++ b/src/vmm_mad/remotes/vcenter/reconfigure @@ -42,6 +42,7 @@ begin vm.regenerate_context + vi_client.close_connection rescue Exception => e STDERR.puts "Reconfiguration of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 4c1348bf1f..37ddfd73b9 100755 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -42,6 +42,7 @@ begin vm.reset + vi_client.close_connection rescue Exception => e STDERR.puts "Reset of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index 1a15107e46..8d05a6786d 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -42,6 +42,7 @@ begin vm.poweron + vi_client.close_connection rescue Exception => e STDERR.puts "Restore of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index b2280b1d6a..a99bd606c1 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -73,6 +73,7 @@ begin vm.suspend + vi_client.close_connection rescue Exception => e STDERR.puts "Save of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 2258fefacc..a8c00d4ac6 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -110,6 +110,8 @@ begin end end + vi_client.close_connection + rescue Exception => e STDERR.puts "Shutdown of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 8fc488b2e7..a4982a4bee 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -48,6 +48,7 @@ begin vm.create_snapshot(snap_id, snap_name) + vi_client.close_connection rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index f27a1e5beb..8a37784731 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -43,6 +43,7 @@ begin vm.delete_snapshot(snap_id) + vi_client.close_connection rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} could not be deleted due to "\ diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index ad1069aece..db3f110d04 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -43,6 +43,7 @@ begin vm.revert_snapshot(snap_id) + vi_client.close_connection rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} could not be reverted due "\ From 3e7fb4e3e67cb543669808314a2f0d38da8c0b36 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 16:05:48 +0100 Subject: [PATCH 096/297] F #4913: Add Storpod support to DS monitor and VMM deploy actions --- src/datastore_mad/remotes/vcenter/monitor | 22 +++- .../remotes/lib/vcenter_driver/datastore.rb | 53 ++++++--- .../lib/vcenter_driver/virtual_machine.rb | 101 +++++++++++++----- 3 files changed, 135 insertions(+), 41 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 1ad33a1820..b8633b1f59 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -33,6 +33,18 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to monitor the datastore. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + drv_action_enc = ARGV[0] id = ARGV[1] @@ -41,6 +53,7 @@ drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DAT host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] +check_valid ds_ref, "ds_ref" if host_id.nil? || ds_ref.nil? STDERR.puts "Not enough information to monitor the image." @@ -48,8 +61,13 @@ if host_id.nil? || ds_ref.nil? end vi_client = VCenterDriver::VIClient.new_from_host(host_id) -ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) -puts ds.monitor +if ds_ref.start_with?('group-') + storpod = VCenterDriver::StoragePod.new_from_ref(ds_ref, vi_client) + puts storpod.monitor +else + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + puts ds.monitor +end vi_client.close_connection diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index a8ed35edae..052184bc08 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -20,6 +20,7 @@ class DatastoreFolder end VIClient.get_entities(@item, "StoragePod").each do |sp| + @items[sp._ref.to_sym] = StoragePod.new(sp) VIClient.get_entities(sp, "Datastore").each do |item| item_name = item._ref @items[item_name.to_sym] = Datastore.new(item) @@ -36,34 +37,29 @@ class DatastoreFolder end ######################################################################## - # Returns a Datastore. Uses the cache if available. + # Returns a Datastore or StoragePod. Uses the cache if available. # @param ref [Symbol] the vcenter ref # @return Datastore ######################################################################## def get(ref) if !@items[ref.to_sym] - rbvmomi_dc = RbVmomi::VIM::Datastore.new(@item._connection, ref) - @items[ref.to_sym] = Datastore.new(rbvmomi_dc) + if ref.start_with?("group-") + rbvmomi_spod = RbVmomi::VIM::StoragePod.new(@item._connection, ref) rescue nil + @items[ref.to_sym] = StoragePod.new(rbvmomi_spod) + else + rbvmomi_ds = RbVmomi::VIM::Datastore.new(@item._connection, ref) rescue nil + @items[ref.to_sym] = Datastore.new(rbvmomi_ds) + end end - @items[ref.to_sym] end end # class DatastoreFolder -class Datastore +class Storage attr_accessor :item include Memoize - def initialize(item, vi_client=nil) - if !item.instance_of? RbVmomi::VIM::Datastore - raise "Expecting type 'RbVmomi::VIM::Datastore'. " << - "Got '#{item.class} instead." - end - - @item = item - end - def monitor summary = @item.summary @@ -73,6 +69,35 @@ class Datastore "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" end +end # class Storage + +class StoragePod < Storage + + def initialize(item, vi_client=nil) + if !item.instance_of? RbVmomi::VIM::StoragePod + raise "Expecting type 'RbVmomi::VIM::StoragePod'. " << + "Got '#{item.class} instead." + end + + @item = item + end + + # This is never cached + def self.new_from_ref(ref, vi_client) + self.new(RbVmomi::VIM::StoragePod.new(vi_client.vim, ref), vi_client) + end +end # class StoragePod + +class Datastore < Storage + + def initialize(item, vi_client=nil) + if !item.instance_of? RbVmomi::VIM::Datastore + raise "Expecting type 'RbVmomi::VIM::Datastore'. " << + "Got '#{item.class} instead." + end + + @item = item + end def create_virtual_disk(img_name, size, adapter_type, disk_type) ds_name = self['name'] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index d5ffca5a48..0e7e37e0d6 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -179,7 +179,6 @@ class VirtualMachine # @return RbVmomi::VIM::Datastore or nil def get_ds - # Todo remove this comment req_ds = one_item['USER_TEMPLATE/VCENTER_DATASTORE'] req_ds = one_item['USER_TEMPLATE/VCENTER_DS_REF'] if req_ds @@ -266,34 +265,45 @@ class VirtualMachine clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(spec_hash_clone) - vm = nil - begin - vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => vcenter_name, - :spec => clone_spec).wait_for_completion - rescue Exception => e - if !e.message.start_with?('DuplicateName') - raise "Cannot clone VM Template: #{e.message}\n#{e.backtrace}" + ds = get_ds + + if ds.instance_of? RbVmomi::VIM::StoragePod + # VM is cloned using Storage Resource Manager for StoragePods + begin + vm = storagepod_clonevm_task(vc_template, vcenter_name, + clone_spec, ds) + rescue Exception => e + raise "Cannot clone VM Template to StoragePod: #{e.message}" end - - vm_folder = cluster.get_dc.vm_folder - vm_folder.fetch! - vm = vm_folder.items - .select{|k,v| v.item.name == vcenter_name} - .values.first.item rescue nil - - if vm - vm.Destroy_Task.wait_for_completion + else + vm = nil + begin vm = vc_template.CloneVM_Task( :folder => vc_template.parent, :name => vcenter_name, :spec => clone_spec).wait_for_completion - else - raise "Cannot clone VM Template" + rescue Exception => e + if !e.message.start_with?('DuplicateName') + raise "Cannot clone VM Template: #{e.message}\n#{e.backtrace}" + end + + vm_folder = cluster.get_dc.vm_folder + vm_folder.fetch! + vm = vm_folder.items + .select{|k,v| v.item.name == vcenter_name} + .values.first.item rescue nil + + if vm + vm.Destroy_Task.wait_for_completion + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => vcenter_name, + :spec => clone_spec).wait_for_completion + else + raise "Cannot clone VM Template" + end end end - # @item is populated @item = vm @@ -301,6 +311,49 @@ class VirtualMachine end + def storagepod_clonevm_task(vc_template, vcenter_name, clone_spec, storpod) + + storage_manager = vc_template + ._connection.serviceContent.storageResourceManager + + storage_spec = RbVmomi::VIM.StoragePlacementSpec( + type: 'clone', + cloneName: vcenter_name, + folder: vc_template.parent, + podSelectionSpec: RbVmomi::VIM.StorageDrsPodSelectionSpec(storagePod: storpod), + vm: vc_template, + cloneSpec: clone_spec + ) + + # Query a storage placement recommendation + result = storage_manager + .RecommendDatastores(storageSpec: storage_spec) rescue nil + + raise "Could not get placement specification for StoragePod" if result.nil? + + if !result.respond_to?(:recommendations) || result.recommendations.size == 0 + raise "Could not get placement specification for StoragePod" + end + + # Get recommendation key to be applied + key = result.recommendations.first.key ||= '' + raise "Missing Datastore recommendation for StoragePod" if key.empty? + + begin + apply_sr = storage_manager + .ApplyStorageDrsRecommendation_Task(key: [key]) + .wait_for_completion + return apply_sr.vm + rescue Exception => e + raise "Failure applying recommendation: #{e.message}" + end + end + + def get_srm(vc_template) + vcself['_connection.serviceContent.storageResourceManager'] + end + + # @return clone parameters spec hash def spec_hash_clone # Relocate spec @@ -310,13 +363,11 @@ class VirtualMachine ds = get_ds - if ds + if ds.instance_of? Datastore relocate_spec_params[:datastore] = ds relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking end - # TODO storpod (L2575 vcenter_driver.rb) - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( relocate_spec_params) From 6b450ce1ebeab600175960182592ae4fcb5eadcf Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 15:55:52 +0100 Subject: [PATCH 097/297] F #4913: tm/delete detaches each disk first and destroys the VM --- src/tm_mad/vcenter/delete | 78 +++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index e7be094b85..dfa8f72a1a 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -21,14 +21,6 @@ # - remote_system_ds is the path for the system datastore in the host # - vmid is the id of the VM # - dsid is the target datastore (0 is the system datastore) - -# Return if this has called for the whole directory, instead of for a specific -# disk. - -if !ARGV[0].match(/disk\.\d+$/) - exit(0) -end - # ---------------------------------------------------------------------------- # ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) @@ -58,7 +50,7 @@ end path = ARGV[0] vmid = ARGV[1] -dsid = ARGV[2] +dsid = ARGV[2] check_valid path, "path" check_valid vmid, "vmid" @@ -70,26 +62,64 @@ hostname, img_path = path.split(":") host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) host_id = host['ID'] -# Get DS ref -one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) -ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] - -check_valid ds_ref, "ds_ref" - -# Get image path -disk_id = img_path.split(".")[-1] +# Get VM one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) -disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") -img_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid) +vm_ref = one_vm['DEPLOY_ID'] begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) - - ds_vc = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - - ds_vc.delete_virtual_disk(img_path) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) rescue Exception => e - STDERR.puts "Error delete virtual disk #{img_path} in datastore #{dsid}."\ + vi_client.close_connection + + STDERR.puts "Error obtaining the vCenter client and VM object."\ " Reason: #{e.message}\n#{e.backtrace}" exit -1 end + +if path.match(/disk\.\d+$/) + # Detach and remove the disk + + # Get DS ref + one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) + ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] + + # Get image path + disk_id = img_path.split(".")[-1] + + disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]").first + img_path = VCenterDriver::FileHelper.get_img_name(disk, vmid) + + begin + # TODO: if the deploy has failed, the disks may exist, but the vm may + # not exist... + + # detach the disk + vm.detach_disk(disk) + + # delete the disk + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + ds.delete_virtual_disk(img_path) + rescue Exception => e + STDERR.puts "Error delete virtual disk #{img_path} in datastore #{dsid}."\ + " Reason: #{e.message}\n#{e.backtrace}" + exit -1 + ensure + vi_client.close_connection + end +else + # Remove the VM + begin + # All OpenNebula managed disks have been detached. The VM may have still + # disks that belong to the template (VCENTER_MANAGED disks). These disks + # will be deleted with the destroy operation. If the user wants to + # save them to a VM, it can be done using the disk-saveas operation. + vm.destroy + rescue Exception => e + STDERR.puts "Error unregistering vm #{vmid} (#{vm_ref})."\ + " Reason: #{e.message}\n#{e.backtrace}" + exit -1 + ensure + vi_client.close_connection + end +end From 1427e3e99224351b71502f9e0b9cc24cb1e4c92a Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 16:00:28 +0100 Subject: [PATCH 098/297] F #4913: tm/mvds detaches the disk from the VM so it does not get removed --- src/tm_mad/vcenter/mvds | 86 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) mode change 120000 => 100755 src/tm_mad/vcenter/mvds diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds deleted file mode 120000 index 300563f2ad..0000000000 --- a/src/tm_mad/vcenter/mvds +++ /dev/null @@ -1 +0,0 @@ -../common/dummy.sh \ No newline at end of file diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds new file mode 100755 index 0000000000..dd2c45b503 --- /dev/null +++ b/src/tm_mad/vcenter/mvds @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- # +# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +# mvds host:remote_system_ds/disk.i fe:SOURCE vmid dsid +# - fe is the front-end hostname +# - SOURCE is the path of the disk image in the form DS_BASE_PATH/disk +# - host is the target host to deploy the VM +# - remote_system_ds is the path for the system datastore in the host +# - vmid is the id of the VM +# - dsid is the target datastore (0 is the system datastore) + +ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) +end + +$: << RUBY_LIB_LOCATION +$: << File.dirname(__FILE__) + +require 'vcenter_driver2' + +################################################################################ + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "Not enough information to delete the image. " + + "Missing '#{label}'." + exit -1 + end +end + +################################################################################ + +path = ARGV[0] +vmid = ARGV[2] + +check_valid path, "path" +check_valid vmid, "vmid" + +hostname, img_path = path.split(":") + +# Get host ID +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) +host_id = host['ID'] + +# Get VM +one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) +vm_ref = one_vm['DEPLOY_ID'] + +# Get image path +disk_id = img_path.split(".")[-1] + +disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]").first +img_path = VCenterDriver::FileHelper.get_img_name(disk, vmid) + +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + vm.detach_disk(disk) +rescue Exception => e + STDERR.puts "Error detaching virtual disk #{img_path} from vm #{vmid}."\ + " Reason: #{e.message}\n#{e.backtrace}" + exit -1 +ensure + vi_client.close_connection +end From 30ad6b67fd829f33d0912b66359d4ff4217f88b8 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 17:03:31 +0100 Subject: [PATCH 099/297] F #4913: Move explicit VIM close connection to ensure --- src/datastore_mad/remotes/vcenter/clone | 5 ++++- src/datastore_mad/remotes/vcenter/mkfs | 3 ++- src/datastore_mad/remotes/vcenter/rm | 3 ++- src/datastore_mad/remotes/vcenter/stat | 3 ++- src/datastore_mad/remotes/vcenter_downloader.rb | 3 ++- src/datastore_mad/remotes/vcenter_uploader.rb | 3 ++- src/tm_mad/vcenter/clone | 3 ++- src/tm_mad/vcenter/cpds | 3 ++- src/tm_mad/vcenter/mkimage | 3 ++- src/vmm_mad/remotes/vcenter/attach_disk | 3 ++- src/vmm_mad/remotes/vcenter/attach_nic | 3 ++- src/vmm_mad/remotes/vcenter/cancel | 3 ++- src/vmm_mad/remotes/vcenter/deploy | 3 ++- src/vmm_mad/remotes/vcenter/detach_disk | 3 ++- src/vmm_mad/remotes/vcenter/detach_nic | 5 +++-- src/vmm_mad/remotes/vcenter/poll | 5 +++-- src/vmm_mad/remotes/vcenter/reboot | 3 ++- src/vmm_mad/remotes/vcenter/reconfigure | 3 ++- src/vmm_mad/remotes/vcenter/reset | 3 ++- src/vmm_mad/remotes/vcenter/restore | 3 ++- src/vmm_mad/remotes/vcenter/save | 3 ++- src/vmm_mad/remotes/vcenter/shutdown | 4 ++-- src/vmm_mad/remotes/vcenter/snapshot_create | 3 ++- src/vmm_mad/remotes/vcenter/snapshot_delete | 3 ++- src/vmm_mad/remotes/vcenter/snapshot_revert | 3 ++- 25 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index fe5fd3606f..4a8246f48c 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -69,16 +69,19 @@ target_path = Digest::MD5.hexdigest(Time.now.to_s + id.to_s) + ".vmdk" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) target_ds = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + target_ds_name = target_ds['name'] puts ds.copy_virtual_disk(src_path, target_ds_name, target_path) - vi_client.close_connection rescue Exception => e STDERR.puts "Error cloning img #{src_path}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end \ No newline at end of file diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index d99ef099b5..87d7a521ce 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -82,9 +82,10 @@ begin puts ds.create_virtual_disk(img_name, size, adapter_type, disk_type) - vi_client.close_connection rescue Exception => e STDERR.puts "Error creating virtual disk #{img_src}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 4ca2be1421..511868d06f 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -66,9 +66,10 @@ begin ds.delete_virtual_disk(img_src) - vi_client.close_connection rescue Exception => e STDERR.puts "Error deleting virtual disk #{img_src}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 1072c8fe7e..4e6ad9b57a 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -67,11 +67,12 @@ if img_path.start_with? "vcenter://" ds.stat(img_path) - vi_client.close_connection rescue Exception => e STDERR.puts "Error calculating image #{img_path} size."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 + ensure + vi_client.close_connection end else cmd = "#{File.dirname(__FILE__)}/../fs/stat #{drv_action_enc}" diff --git a/src/datastore_mad/remotes/vcenter_downloader.rb b/src/datastore_mad/remotes/vcenter_downloader.rb index 186b79c610..d9854c6087 100755 --- a/src/datastore_mad/remotes/vcenter_downloader.rb +++ b/src/datastore_mad/remotes/vcenter_downloader.rb @@ -91,9 +91,10 @@ begin end end - vi_client.close_connection rescue Exception => e STDERR.puts "Cannot download image #{u.path} from datastore #{ds_name} "\ "on #{hostname}. Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/datastore_mad/remotes/vcenter_uploader.rb b/src/datastore_mad/remotes/vcenter_uploader.rb index 1f22c8c3ca..63d75c91d2 100755 --- a/src/datastore_mad/remotes/vcenter_uploader.rb +++ b/src/datastore_mad/remotes/vcenter_uploader.rb @@ -49,10 +49,11 @@ begin puts target_path - vi_client.close_connection rescue Exception => e STDERR.puts "Cannot upload image to datastore #{ds_name} "\ "Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index 634c039385..5ce59f2f8d 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -98,10 +98,11 @@ begin source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) - vi_client.close_connection rescue Exception => e STDERR.puts "Error clone virtual disk #{src_path} in "\ "datastore #{target_ds_ref}. "\ "Reason: #{e.message}\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index 473800ed5d..c1f87cc899 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -95,9 +95,10 @@ begin source_ds_vc.copy_virtual_disk(src_path, source_ds, target_path, target_ds_name_vc) - vi_client.close_connection rescue Exception => e STDERR.puts "Error copying img #{src_path}. "\ "Reason: #{e.message}\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 4cfcbb9991..23fdd49585 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -89,9 +89,10 @@ begin ds_vc.create_virtual_disk(img_name, size, adapter_type, disk_type) - vi_client.close_connection rescue Exception => e STDERR.puts "Error creating virtual disk in #{ds_vc['name']}."\ " Reason: #{e.message}\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 8af88330e9..8015a9e529 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -48,9 +48,10 @@ begin vm.attach_disk - vi_client.close_connection rescue Exception => e STDERR.puts "Attach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index e7e09cfa20..e99d365f61 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -59,9 +59,10 @@ begin vm.attach_nic(nic) - vi_client.close_connection rescue Exception => e STDERR.puts "Attach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" exit(-1) +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 13faa5a3ea..607db27648 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -48,9 +48,10 @@ begin vm.poweroff_hard - vi_client.close_connection rescue Exception => e STDERR.puts "Cancel VM #{vm_ref} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit(-1) +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index ae196cce2d..1377f181f7 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -63,9 +63,10 @@ begin puts vm['_ref'] - vi_client.close_connection rescue Exception => e STDERR.puts "Deploy of VM #{vm_id} on vCenter cluster #{cluster_name} " + "with #{dfile} failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index fd734a9307..13d6865024 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -53,9 +53,10 @@ begin vm.detach_disk(disks.first) - vi_client.close_connection rescue Exception => e STDERR.puts "Detach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index 9ff8f9910f..a0d3c9aeb4 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -45,9 +45,10 @@ begin vm.detach_nic(nic) - vi_client.close_connection rescue Exception => e STDERR.puts "Detach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ "failed due to \"#{e.message}\"\n#{e.backtrace}" - exit(-1) + exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index f7de851522..38d6207b0c 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -45,10 +45,11 @@ begin puts vm.info - vi_client.close_connection rescue Exception => e STDERR.puts "Cannot poll info for VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" - exit(-1) + exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index b3363ee8c7..803f2c931c 100755 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -42,10 +42,11 @@ begin vm.reboot - vi_client.close_connection rescue Exception => e STDERR.puts "Guest reboot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/reconfigure b/src/vmm_mad/remotes/vcenter/reconfigure index 5d86dab59f..78bf1e60c0 100755 --- a/src/vmm_mad/remotes/vcenter/reconfigure +++ b/src/vmm_mad/remotes/vcenter/reconfigure @@ -42,10 +42,11 @@ begin vm.regenerate_context - vi_client.close_connection rescue Exception => e STDERR.puts "Reconfiguration of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 37ddfd73b9..8a2dcf44d2 100755 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -42,10 +42,11 @@ begin vm.reset - vi_client.close_connection rescue Exception => e STDERR.puts "Reset of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index 8d05a6786d..d8f48c61dc 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -42,10 +42,11 @@ begin vm.poweron - vi_client.close_connection rescue Exception => e STDERR.puts "Restore of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index a99bd606c1..046f93c086 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -73,10 +73,11 @@ begin vm.suspend - vi_client.close_connection rescue Exception => e STDERR.puts "Save of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index a8c00d4ac6..e144923e79 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -110,11 +110,11 @@ begin end end - vi_client.close_connection - rescue Exception => e STDERR.puts "Shutdown of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit -1 +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index a4982a4bee..174e184ac4 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -48,10 +48,11 @@ begin vm.create_snapshot(snap_id, snap_name) - vi_client.close_connection rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit(-1) +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index 8a37784731..f1deb1974b 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -43,10 +43,11 @@ begin vm.delete_snapshot(snap_id) - vi_client.close_connection rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} could not be deleted due to "\ "\"#{e.message}\"\n#{e.backtrace}" exit(-1) +ensure + vi_client.close_connection end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index db3f110d04..f34df9523c 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -43,10 +43,11 @@ begin vm.revert_snapshot(snap_id) - vi_client.close_connection rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} could not be reverted due "\ "to \"#{e.message}\"\n#{e.backtrace}" exit(-1) +ensure + vi_client.close_connection end From d996614539200e2cc927b074bbce34975b651c94 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 17:14:15 +0100 Subject: [PATCH 100/297] F #4913: use memoize to fetch summary --- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 052184bc08..b2ea1f689d 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -61,7 +61,7 @@ class Storage include Memoize def monitor - summary = @item.summary + summary = self['summary'] total_mb = (summary.capacity.to_i / 1024) / 1024 free_mb = (summary.freeSpace.to_i / 1024) / 1024 From a78e6cd3d160795b7ea64532088541d837bb9518 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 17:14:37 +0100 Subject: [PATCH 101/297] F #4913: Remove unnecessary method --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 0e7e37e0d6..d77d90c1c9 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -349,11 +349,6 @@ class VirtualMachine end end - def get_srm(vc_template) - vcself['_connection.serviceContent.storageResourceManager'] - end - - # @return clone parameters spec hash def spec_hash_clone # Relocate spec From 14188411df7e3fa49950d5924385d8136d77d776 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 21 Feb 2017 17:22:46 +0100 Subject: [PATCH 102/297] F #4913: Refactor 'check_valid' function --- src/datastore_mad/remotes/vcenter/clone | 14 +------------- src/datastore_mad/remotes/vcenter/cp | 12 ------------ src/datastore_mad/remotes/vcenter/mkfs | 12 ------------ src/datastore_mad/remotes/vcenter/monitor | 12 ------------ src/datastore_mad/remotes/vcenter/rm | 12 ------------ src/datastore_mad/remotes/vcenter/stat | 14 +------------- src/tm_mad/vcenter/clone | 12 ------------ src/tm_mad/vcenter/cpds | 12 ------------ src/tm_mad/vcenter/delete | 12 ------------ src/tm_mad/vcenter/mkimage | 12 ------------ src/tm_mad/vcenter/mvds | 12 ------------ src/vmm_mad/remotes/lib/vcenter_driver2.rb | 11 +++++++++++ src/vmm_mad/remotes/vcenter/save | 12 ------------ src/vmm_mad/remotes/vcenter/shutdown | 12 ------------ 14 files changed, 13 insertions(+), 158 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 4a8246f48c..1c50da19e2 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -30,18 +30,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' require 'digest' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to clone the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - drv_action_enc = ARGV[0] id = ARGV[1] @@ -84,4 +72,4 @@ rescue Exception => e exit -1 ensure vi_client.close_connection -end \ No newline at end of file +end diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index b98f0485b7..3b3af489bd 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -31,18 +31,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to clone the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 87d7a521ce..5325fb471b 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -33,18 +33,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to create the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index b8633b1f59..732c88ea0c 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -33,18 +33,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to monitor the datastore. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 511868d06f..7962bc5ccb 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -33,18 +33,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to delete the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 4e6ad9b57a..37fb57b8ba 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -33,18 +33,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to stat the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - drv_action_enc = ARGV[0] id = ARGV[1] @@ -77,4 +65,4 @@ if img_path.start_with? "vcenter://" else cmd = "#{File.dirname(__FILE__)}/../fs/stat #{drv_action_enc}" system(cmd) -end \ No newline at end of file +end diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index 5ce59f2f8d..bbbec30ffa 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -37,18 +37,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to clone the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - src = ARGV[0] dst = ARGV[1] vm_id = ARGV[2] diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index c1f87cc899..480951ad20 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -36,18 +36,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to perform cpds of the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - src = ARGV[0] target_path = ARGV[1] snap_id = ARGV[2] #TODO snapshots? diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index dfa8f72a1a..d21384d472 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -36,18 +36,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to delete the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - path = ARGV[0] vmid = ARGV[1] dsid = ARGV[2] diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 23fdd49585..7f4a46f871 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -37,18 +37,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to create the virtual disk. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - size = ARGV[0] path = ARGV[2] vmid = ARGV[3] diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds index dd2c45b503..b5c4e17c39 100755 --- a/src/tm_mad/vcenter/mvds +++ b/src/tm_mad/vcenter/mvds @@ -37,18 +37,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to delete the image. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - path = ARGV[0] vmid = ARGV[2] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb index a09318eec4..1d0e8aebe1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver2.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver2.rb @@ -57,3 +57,14 @@ require 'datastore' require 'virtual_machine' require 'network' require 'file_helper' + +# ---------------------------------------------------------------------------- # +# Helper functions # +# ---------------------------------------------------------------------------- # + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "The parameter '#{label}' is required for this action." + exit -1 + end +end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 046f93c086..8f714f3a31 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -29,18 +29,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to save the VM. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - vm_ref = ARGV[0] vc_cluster_name = ARGV[-1] diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index e144923e79..0be7d179b6 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -29,18 +29,6 @@ $: << File.dirname(__FILE__) require 'vcenter_driver2' -################################################################################ - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "Not enough information to shutdown the VM. " + - "Missing '#{label}'." - exit -1 - end -end - -################################################################################ - vm_ref = ARGV[0] vc_cluster_name = ARGV[1] From 1940249773fb9895b182b317cd8e15d32a2ab410 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 17:58:17 +0100 Subject: [PATCH 103/297] F #4913: Add new_from_ref to Storage class --- src/datastore_mad/remotes/vcenter/monitor | 9 ++------- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 8 ++++++++ .../remotes/lib/vcenter_driver/virtual_machine.rb | 2 -- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 732c88ea0c..0cc04f8946 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -50,12 +50,7 @@ end vi_client = VCenterDriver::VIClient.new_from_host(host_id) -if ds_ref.start_with?('group-') - storpod = VCenterDriver::StoragePod.new_from_ref(ds_ref, vi_client) - puts storpod.monitor -else - ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - puts ds.monitor -end +storage = VCenterDriver::Storage.new_from_ref(ds_ref, vi_client) +puts storage.monitor vi_client.close_connection diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index b2ea1f689d..a3abf26b4d 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -60,6 +60,14 @@ class Storage include Memoize + def self.new_from_ref(ref, vi_client) + if ref.start_with?('group-') + return VCenterDriver::StoragePod.new_from_ref(ref, vi_client) + else + return VCenterDriver::Datastore.new_from_ref(ref, vi_client) + end + end + def monitor summary = self['summary'] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index d77d90c1c9..6c793e3015 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -184,8 +184,6 @@ class VirtualMachine if req_ds dc = cluster.get_dc - # TODO: add storage pods - ds_folder = dc.datastore_folder ds = ds_folder.get(req_ds) ds_item = ds.item rescue nil From 0e406b5b1f4f48ddc9761067363f1749fb3d7f1f Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Feb 2017 19:09:46 +0100 Subject: [PATCH 104/297] F #4913: Add linked clone logic to VMM deploy (clone_vm) --- .../lib/vcenter_driver/virtual_machine.rb | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 6c793e3015..f0a91b472b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -261,10 +261,31 @@ class VirtualMachine vc_template_ref = one_item['USER_TEMPLATE/VCENTER_TEMPLATE_REF'] vc_template = RbVmomi::VIM::VirtualMachine(vi_client.vim, vc_template_ref) - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(spec_hash_clone) - ds = get_ds + # Default disk move type (Full Clone) + disk_move_type = :moveAllDiskBackingsAndDisallowSharing + + if ds.instance_of? RbVmomi::VIM::Datastore + use_linked_clones = one_item['USER_TEMPLATE/VCENTER_LINKED_CLONES'] + if use_linked_clones && use_linked_clones.downcase == "yes" + # Check if all disks in template has delta disks + disks = vc_template.config + .hardware.device.grep(RbVmomi::VIM::VirtualDisk) + + disks_no_delta = disks.select { |d| d.backing.parent == nil } + + # Can use linked clones if all disks have delta disks + if (disks_no_delta.size == 0) + disk_move_type = :moveChildMostDiskBacking + end + end + end + + spec_hash = spec_hash_clone(disk_move_type) + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(spec_hash) + if ds.instance_of? RbVmomi::VIM::StoragePod # VM is cloned using Storage Resource Manager for StoragePods begin @@ -348,18 +369,16 @@ class VirtualMachine end # @return clone parameters spec hash - def spec_hash_clone + def spec_hash_clone(disk_move_type) # Relocate spec relocate_spec_params = {} relocate_spec_params[:pool] = get_rp + relocate_spec_params[:diskMoveType] = disk_move_type ds = get_ds - if ds.instance_of? Datastore - relocate_spec_params[:datastore] = ds - relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking - end + relocate_spec_params[:datastore] = ds if ds.instance_of? Datastore relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( relocate_spec_params) From ef2235485b7d76a24882e406a802672dbb908f6d Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 22 Feb 2017 10:04:03 +0100 Subject: [PATCH 105/297] F #4913: Use a well known directory to store opennebula images --- src/datastore_mad/remotes/vcenter/clone | 3 +-- src/datastore_mad/remotes/vcenter/cp | 3 +-- src/datastore_mad/remotes/vcenter/export | 4 +--- src/datastore_mad/remotes/vcenter/mkfs | 4 ++-- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 10 ++++++++++ 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 1c50da19e2..977686c2a5 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -28,7 +28,6 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver2' -require 'digest' drv_action_enc = ARGV[0] id = ARGV[1] @@ -53,7 +52,7 @@ source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] # Generate target path -target_path = Digest::MD5.hexdigest(Time.now.to_s + id.to_s) + ".vmdk" +target_path = "one/#{id}/one-#{id}.vmdk" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index 3b3af489bd..a3fce2d39f 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -55,7 +55,7 @@ end temp_file = nil filename = File.basename(img_path) -target_path = Digest::MD5.hexdigest(Time.now.to_s + id.to_s) +target_path = "one/#{id}" # If image is in a remote http location it has to be downloaded # or if is a zipped file it has to be unzipped in a temp folder @@ -76,7 +76,6 @@ if VCenterDriver::FileHelper.is_remote_or_needs_unpack?(img_path) downloader = "#{File.dirname(__FILE__)}/../downloader.sh #{downsh_args}" - rc = system("#{downloader} #{img_path} #{temp_file}") if !rc diff --git a/src/datastore_mad/remotes/vcenter/export b/src/datastore_mad/remotes/vcenter/export index 69acfcb077..aa4f8f46f3 100755 --- a/src/datastore_mad/remotes/vcenter/export +++ b/src/datastore_mad/remotes/vcenter/export @@ -17,7 +17,7 @@ # ---------------------------------------------------------------------------- # ############################################################################### -# This script is used retrieve the file size of a disk +# This script is used retrieve the file size of a disk ############################################################################### ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) @@ -39,8 +39,6 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') - - img_source = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] img_size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] md5 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"] diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 5325fb471b..3183a91c3c 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -56,7 +56,7 @@ check_valid ds_ref, "ds_ref" # TODO path in vCenter? choose a specific directory -img_name = "one-#{img_id}" +img_name = "one/#{img_id}/one-#{img_id}" if fs_type == "save_as" puts img_name + ".vmdk" @@ -71,7 +71,7 @@ begin puts ds.create_virtual_disk(img_name, size, adapter_type, disk_type) rescue Exception => e - STDERR.puts "Error creating virtual disk #{img_src}."\ + STDERR.puts "Error creating virtual disk #{img_name}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index a3abf26b4d..538e279f88 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -108,6 +108,11 @@ class Datastore < Storage end def create_virtual_disk(img_name, size, adapter_type, disk_type) + leading_dirs = img_name.split('/')[0..-2] + if !leading_dirs.empty? + create_directory(leading_dirs.join('/')) + end + ds_name = self['name'] vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( @@ -138,6 +143,11 @@ class Datastore < Storage # @param ds_name [String] name of the datastore # @param img_str [String] path to the VirtualDisk def copy_virtual_disk(src_path, target_ds_name, target_path) + leading_dirs = target_path.split('/')[0..-2] + if !leading_dirs.empty? + create_directory(leading_dirs.join('/')) + end + source_ds_name = self['name'] copy_params = { From 5fa65cfdfcd2bbdf9cc496d5c2bc8d1fbb088f99 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 22 Feb 2017 10:09:29 +0100 Subject: [PATCH 106/297] F #4913: Directory where images are stored in vCenter datastores is configurable --- src/datastore_mad/remotes/vcenter/clone | 4 +++- src/datastore_mad/remotes/vcenter/cp | 17 +++++++++-------- src/datastore_mad/remotes/vcenter/mkfs | 3 ++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 977686c2a5..090c77c5fd 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -37,6 +37,7 @@ drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DAT target_ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" src_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] src_img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/CLONING_ID"] @@ -52,11 +53,12 @@ source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] # Generate target path -target_path = "one/#{id}/one-#{id}.vmdk" +target_path = "#{ds_image_dir}/#{id}/one-#{id}.vmdk" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + ds = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) target_ds = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index a3fce2d39f..99b75b4243 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -37,13 +37,14 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] -ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] -md5 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"] -sha1 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1"] -nodecomp = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/NO_DECOMPRESS"] -limit_bw = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/LIMIT_TRANSFER_BW"] +img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] +ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" +md5 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"] +sha1 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/SHA1"] +nodecomp = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/NO_DECOMPRESS"] +limit_bw = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/LIMIT_TRANSFER_BW"] check_valid img_path, "img_path" @@ -55,7 +56,7 @@ end temp_file = nil filename = File.basename(img_path) -target_path = "one/#{id}" +target_path = "#{ds_image_dir}/#{id}" # If image is in a remote http location it has to be downloaded # or if is a zipped file it has to be unzipped in a temp folder diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 3183a91c3c..2159dea16d 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -41,6 +41,7 @@ drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DAT ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] @@ -56,7 +57,7 @@ check_valid ds_ref, "ds_ref" # TODO path in vCenter? choose a specific directory -img_name = "one/#{img_id}/one-#{img_id}" +img_name = "#{ds_image_dir}/#{img_id}/one-#{img_id}" if fs_type == "save_as" puts img_name + ".vmdk" From 493d48ce5bd1d08a3ceb3007961acfcdcc744125 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 22 Feb 2017 11:02:25 +0100 Subject: [PATCH 107/297] F #4913: Delete empty dirs after removing an image --- src/datastore_mad/remotes/vcenter/rm | 4 ++- .../remotes/lib/vcenter_driver/datastore.rb | 27 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 7962bc5ccb..37ccf4de65 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -52,8 +52,10 @@ begin ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - ds.delete_virtual_disk(img_src) + img_dir = img_src.split('/')[0..-2].join('/') + ds.delete_virtual_disk(img_src) + ds.rm_directory(img_dir) if ds.dir_empty?(img_dir) rescue Exception => e STDERR.puts "Error deleting virtual disk #{img_src}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 538e279f88..d554262fb5 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -177,6 +177,33 @@ class Datastore < Storage end end + def rm_directory(directory) + ds_name = self['name'] + + rm_directory_params = { + :name => "[#{ds_name}] #{directory}", + :datacenter => get_dc.item + } + + get_fm.DeleteDatastoreFile_Task(rm_directory_params) + end + + def dir_empty?(path) + ds_name = self['name'] + + spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new + + search_params = { + 'datastorePath' => "[#{ds_name}] #{path}", + 'searchSpec' => spec + } + + ls = self['browser'].SearchDatastoreSubFolders_Task(search_params) + + ls.info.result && ls.info.result.length == 1 && \ + ls.info.result.first.file.length == 0 + end + def upload_file(source_path, target_path) @item.upload(target_path, source_path) end From 446490cf1a3057e5b43075e41ffcaf8f5b12e370 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 22 Feb 2017 15:52:46 +0100 Subject: [PATCH 108/297] F #4913: Proper begin/rescue clause for the monitor action --- src/datastore_mad/remotes/vcenter/monitor | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 0cc04f8946..40ab400087 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -48,9 +48,16 @@ if host_id.nil? || ds_ref.nil? exit -1 end -vi_client = VCenterDriver::VIClient.new_from_host(host_id) +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) -storage = VCenterDriver::Storage.new_from_ref(ds_ref, vi_client) -puts storage.monitor + storage = VCenterDriver::Storage.new_from_ref(ds_ref, vi_client) + puts storage.monitor -vi_client.close_connection +rescue Exception => e + STDERR.puts "Error monitoring host #{id}."\ + " Reason: \"#{e.message}\"\n#{e.backtrace}" + exit -1 +ensure + vi_client.close_connection +end From 6d00ad5a90e05a4a3201588ff51fd28a5a992a67 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 22 Feb 2017 16:17:56 +0100 Subject: [PATCH 109/297] F #4913: Install new vcenter driver --- install.sh | 23 +- src/datastore_mad/remotes/vcenter/clone | 2 +- src/datastore_mad/remotes/vcenter/cp | 2 +- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/datastore_mad/remotes/vcenter/monitor | 2 +- src/datastore_mad/remotes/vcenter/rm | 2 +- src/datastore_mad/remotes/vcenter/stat | 2 +- .../remotes/vcenter_downloader.rb | 2 +- src/datastore_mad/remotes/vcenter_uploader.rb | 2 +- .../remotes/vcenter.d/{vcenter.rb => poll} | 2 +- src/tm_mad/vcenter/clone | 2 +- src/tm_mad/vcenter/cpds | 2 +- src/tm_mad/vcenter/delete | 2 +- src/tm_mad/vcenter/mkimage | 2 +- src/tm_mad/vcenter/mvds | 2 +- src/vmm_mad/remotes/lib/vcenter_driver2.rb | 70 - src/vmm_mad/remotes/vcenter/attach_disk | 2 +- src/vmm_mad/remotes/vcenter/attach_nic | 2 +- src/vmm_mad/remotes/vcenter/cancel | 2 +- src/vmm_mad/remotes/vcenter/deploy | 2 +- src/vmm_mad/remotes/vcenter/detach_disk | 2 +- src/vmm_mad/remotes/vcenter/detach_nic | 2 +- src/vmm_mad/remotes/vcenter/poll | 2 +- src/vmm_mad/remotes/vcenter/reboot | 2 +- src/vmm_mad/remotes/vcenter/reconfigure | 2 +- src/vmm_mad/remotes/vcenter/reset | 2 +- src/vmm_mad/remotes/vcenter/restore | 2 +- src/vmm_mad/remotes/vcenter/save | 2 +- src/vmm_mad/remotes/vcenter/shutdown | 2 +- src/vmm_mad/remotes/vcenter/snapshot_create | 2 +- src/vmm_mad/remotes/vcenter/snapshot_delete | 2 +- src/vmm_mad/remotes/vcenter/snapshot_revert | 2 +- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 3223 +---------------- 33 files changed, 82 insertions(+), 3294 deletions(-) rename src/im_mad/remotes/vcenter.d/{vcenter.rb => poll} (98%) delete mode 100644 src/vmm_mad/remotes/lib/vcenter_driver2.rb diff --git a/install.sh b/install.sh index 75da5a1f3f..0e60f4acb7 100755 --- a/install.sh +++ b/install.sh @@ -236,7 +236,8 @@ LIB_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/mads \ $LIB_LOCATION/sh \ $LIB_LOCATION/ruby/cli \ - $LIB_LOCATION/ruby/cli/one_helper" + $LIB_LOCATION/ruby/cli/one_helper \ + $LIB_LOCATION/ruby/vcenter_driver" VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/im \ @@ -381,6 +382,7 @@ INSTALL_FILES=( AUTH_DUMMY_FILES:$VAR_LOCATION/remotes/auth/dummy AUTH_PLAIN_FILES:$VAR_LOCATION/remotes/auth/plain VMM_EXEC_LIB_FILES:$VAR_LOCATION/remotes/vmm/lib + VMM_EXEC_LIB_VCENTER_FILES:$LIB_LOCATION/ruby/vcenter_driver VMM_EXEC_KVM_SCRIPTS:$VAR_LOCATION/remotes/vmm/kvm VMM_EXEC_VCENTER_SCRIPTS:$VAR_LOCATION/remotes/vmm/vcenter VMM_EXEC_EC2_SCRIPTS:$VAR_LOCATION/remotes/vmm/ec2 @@ -642,6 +644,21 @@ MADS_LIB_FILES="src/mad/sh/madcommon.sh \ VMM_EXEC_LIB_FILES="src/vmm_mad/remotes/lib/poll_common.rb" +#------------------------------------------------------------------------------- +# VMM Lib vcenter files, used by the vCenter Driver to be installed in +# $REMOTES_LOCATION/vmm/lib/vcenter +#------------------------------------------------------------------------------- + +VMM_EXEC_LIB_VCENTER_FILES="src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb + src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/host.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/memoize.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/network.rb" + #------------------------------------------------------------------------------- # VMM SH Driver KVM scripts, to be installed under $REMOTES_LOCATION/vmm/kvm #------------------------------------------------------------------------------- @@ -690,7 +707,7 @@ VMM_EXEC_VCENTER_SCRIPTS="src/vmm_mad/remotes/vcenter/cancel \ src/vmm_mad/remotes/vcenter/poll \ src/vmm_mad/remotes/vcenter/shutdown \ src/vmm_mad/remotes/vcenter/reconfigure \ - src/vmm_mad/remotes/vcenter/prereconfigure" + src/vmm_mad/remotes/vcenter/preconfigure" #------------------------------------------------------------------------------ # VMM Driver EC2 scripts, to be installed under $REMOTES_LOCATION/vmm/ec2 @@ -758,7 +775,7 @@ IM_PROBES_KVM_PROBES_FILES="src/im_mad/remotes/kvm-probes.d/kvm.rb \ src/im_mad/remotes/common.d/version.sh \ src/im_mad/remotes/common.d/collectd-client-shepherd.sh" -IM_PROBES_VCENTER_FILES="src/im_mad/remotes/vcenter.d/vcenter.rb" +IM_PROBES_VCENTER_FILES="src/im_mad/remotes/vcenter.d/poll" IM_PROBES_EC2_FILES="src/im_mad/remotes/ec2.d/poll" diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 090c77c5fd..dd416e0d62 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index 99b75b4243..1ba32394c4 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -29,7 +29,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 2159dea16d..af63a095f1 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -31,7 +31,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 40ab400087..0706c98596 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -31,7 +31,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 37ccf4de65..251b95ee69 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -31,7 +31,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 37fb57b8ba..0d7fb925e6 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -31,7 +31,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' drv_action_enc = ARGV[0] id = ARGV[1] diff --git a/src/datastore_mad/remotes/vcenter_downloader.rb b/src/datastore_mad/remotes/vcenter_downloader.rb index d9854c6087..9df20d07d3 100755 --- a/src/datastore_mad/remotes/vcenter_downloader.rb +++ b/src/datastore_mad/remotes/vcenter_downloader.rb @@ -29,7 +29,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' require 'uri' require 'cgi' require 'fileutils' diff --git a/src/datastore_mad/remotes/vcenter_uploader.rb b/src/datastore_mad/remotes/vcenter_uploader.rb index 63d75c91d2..10a7f24ae7 100755 --- a/src/datastore_mad/remotes/vcenter_uploader.rb +++ b/src/datastore_mad/remotes/vcenter_uploader.rb @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' host_id = ARGV[0] target_ds_ref = ARGV[1] diff --git a/src/im_mad/remotes/vcenter.d/vcenter.rb b/src/im_mad/remotes/vcenter.d/poll similarity index 98% rename from src/im_mad/remotes/vcenter.d/vcenter.rb rename to src/im_mad/remotes/vcenter.d/poll index 61b68f1d0e..9d926f747c 100755 --- a/src/im_mad/remotes/vcenter.d/vcenter.rb +++ b/src/im_mad/remotes/vcenter.d/poll @@ -26,7 +26,7 @@ end $: << RUBY_LIB_LOCATION -require 'vcenter_driver2' +require 'vcenter_driver' host_id = ARGV[4] diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index bbbec30ffa..dc908778ac 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -35,7 +35,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' src = ARGV[0] dst = ARGV[1] diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index 480951ad20..e9d32774f9 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -34,7 +34,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' src = ARGV[0] target_path = ARGV[1] diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index d21384d472..d71bfd8f5a 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -34,7 +34,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' path = ARGV[0] vmid = ARGV[1] diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 7f4a46f871..55b6bc61c9 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -35,7 +35,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' size = ARGV[0] path = ARGV[2] diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds index b5c4e17c39..85b2e5b683 100755 --- a/src/tm_mad/vcenter/mvds +++ b/src/tm_mad/vcenter/mvds @@ -35,7 +35,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' path = ARGV[0] vmid = ARGV[2] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver2.rb b/src/vmm_mad/remotes/lib/vcenter_driver2.rb deleted file mode 100644 index 1d0e8aebe1..0000000000 --- a/src/vmm_mad/remotes/lib/vcenter_driver2.rb +++ /dev/null @@ -1,70 +0,0 @@ -# ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -# ---------------------------------------------------------------------------- # - -# ---------------------------------------------------------------------------- # -# Set up the environment for the driver # -# ---------------------------------------------------------------------------- # - -ONE_LOCATION = ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) - -if !ONE_LOCATION - BIN_LOCATION = "/usr/bin" if !defined?(BIN_LOCATION) - LIB_LOCATION = "/usr/lib/one" if !defined?(LIB_LOCATION) - ETC_LOCATION = "/etc/one/" if !defined?(ETC_LOCATION) - VAR_LOCATION = "/var/lib/one" if !defined?(VAR_LOCATION) -else - BIN_LOCATION = ONE_LOCATION + "/bin" if !defined?(BIN_LOCATION) - LIB_LOCATION = ONE_LOCATION + "/lib" if !defined?(LIB_LOCATION) - ETC_LOCATION = ONE_LOCATION + "/etc/" if !defined?(ETC_LOCATION) - VAR_LOCATION = ONE_LOCATION + "/var/" if !defined?(VAR_LOCATION) -end - -ENV['LANG'] = 'C' - -$: << LIB_LOCATION + '/ruby/vendors/rbvmomi/lib' -$: << LIB_LOCATION + '/ruby' -$: << LIB_LOCATION + '/ruby/vcenter_driver' - -require 'rbvmomi' -require 'yaml' -require 'opennebula' -require 'base64' -require 'openssl' - -# ---------------------------------------------------------------------------- # -# vCenter Library # -# ---------------------------------------------------------------------------- # - -require 'memoize' -require 'vi_client' -require 'vi_helper' -require 'datacenter' -require 'host' -require 'datastore' -require 'virtual_machine' -require 'network' -require 'file_helper' - -# ---------------------------------------------------------------------------- # -# Helper functions # -# ---------------------------------------------------------------------------- # - -def check_valid(parameter, label) - if parameter.nil? || parameter.empty? - STDERR.puts "The parameter '#{label}' is required for this action." - exit -1 - end -end diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 8015a9e529..20eab1457d 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] drv_action_enc = ARGV[4] diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index e99d365f61..9ba0b4cb48 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] mac = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 607db27648..d7495134c1 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] host = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 1377f181f7..e036b1a1ec 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' dfile = ARGV[0] cluster_name = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index 13d6865024..9aa9fabeff 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[-1] diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index a0d3c9aeb4..bf9efba2b4 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] mac = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index 38d6207b0c..56d1d49290 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -28,7 +28,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index 803f2c931c..9b3fd938e0 100755 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/reconfigure b/src/vmm_mad/remotes/vcenter/reconfigure index 78bf1e60c0..763ad3a214 100755 --- a/src/vmm_mad/remotes/vcenter/reconfigure +++ b/src/vmm_mad/remotes/vcenter/reconfigure @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[-1] diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 8a2dcf44d2..104af6ac11 100755 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index d8f48c61dc..6bd7441d8a 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[2] vc_cluster_name = ARGV[-1] diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 8f714f3a31..b48487009e 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[-1] diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 0be7d179b6..0367ff1a8a 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] vc_cluster_name = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 174e184ac4..2e3884899b 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] snap_id = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index f1deb1974b..6ece116c5f 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] snap_id = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index f34df9523c..f81a031b64 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -27,7 +27,7 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vcenter_driver2' +require 'vcenter_driver' vm_ref = ARGV[0] snap_id = ARGV[1] diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 11e9b40deb..1d0e8aebe1 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -14,9 +14,10 @@ # limitations under the License. # # ---------------------------------------------------------------------------- # -# -------------------------------------------------------------------------# -# Set up the environment for the driver # -# -------------------------------------------------------------------------# +# ---------------------------------------------------------------------------- # +# Set up the environment for the driver # +# ---------------------------------------------------------------------------- # + ONE_LOCATION = ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) if !ONE_LOCATION @@ -25,3205 +26,45 @@ if !ONE_LOCATION ETC_LOCATION = "/etc/one/" if !defined?(ETC_LOCATION) VAR_LOCATION = "/var/lib/one" if !defined?(VAR_LOCATION) else - BIN_LOCATION = ONE_LOCATION + "/bin" if !defined?(BIN_LOCATION) - LIB_LOCATION = ONE_LOCATION + "/lib" if !defined?(LIB_LOCATION) - ETC_LOCATION = ONE_LOCATION + "/etc/" if !defined?(ETC_LOCATION) + BIN_LOCATION = ONE_LOCATION + "/bin" if !defined?(BIN_LOCATION) + LIB_LOCATION = ONE_LOCATION + "/lib" if !defined?(LIB_LOCATION) + ETC_LOCATION = ONE_LOCATION + "/etc/" if !defined?(ETC_LOCATION) VAR_LOCATION = ONE_LOCATION + "/var/" if !defined?(VAR_LOCATION) end ENV['LANG'] = 'C' -$: << LIB_LOCATION+'/ruby/vendors/rbvmomi/lib' -$: << LIB_LOCATION+'/ruby' +$: << LIB_LOCATION + '/ruby/vendors/rbvmomi/lib' +$: << LIB_LOCATION + '/ruby' +$: << LIB_LOCATION + '/ruby/vcenter_driver' -require 'ostruct' require 'rbvmomi' require 'yaml' require 'opennebula' require 'base64' require 'openssl' -################################################################################ -# Monkey patch rbvmomi library with some extra functions -################################################################################ - -class RbVmomi::VIM::Datastore - - # Download a file from this datastore. - # @param remote_path [String] Source path on the datastore. - # @param local_path [String] Destination path on the local machine. - # @return [void] - def download_to_stdout remote_path - url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" - - pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', - "-b", _connection.cookie, - url - - - Process.waitpid(pid, 0) - fail "download failed" unless $?.success? - end - - def is_descriptor? remote_path - url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" - - rout, wout = IO.pipe - - pid = spawn CURLBIN, "-I", "-k", '--noproxy', '*', '-f', - "-b", _connection.cookie, - url, - :out => wout, - :err => '/dev/null' - - Process.waitpid(pid, 0) - fail "read image header failed" unless $?.success? - - wout.close - size = rout.readlines.select{|l| l.start_with?("Content-Length")}[0].sub("Content-Length: ","") - rout.close - size.chomp.to_i < 4096 # If <4k, then is a descriptor - end - - def get_text_file remote_path - url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}" - - rout, wout = IO.pipe - pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f', - "-b", _connection.cookie, - url, - :out => wout, - :err => '/dev/null' - - Process.waitpid(pid, 0) - fail "get text file failed" unless $?.success? - - wout.close - output = rout.readlines - rout.close - return output - end - -end - -module VCenterDriver - -################################################################################ -# This class represents a VCenter connection and an associated OpenNebula client -# The connection is associated to the VCenter backing a given OpenNebula host. -# For the VCenter driver each OpenNebula host represents a VCenter cluster -################################################################################ -class VIClient - attr_reader :vim, :one, :root, :cluster, :user, :pass, :host, :dc - - def self.get_entities(folder, type, entities=[]) - return nil if folder == [] - - folder.childEntity.each do |child| - name, junk = child.to_s.split('(') - - case name - when "Folder" - VIClient.get_entities(child, type, entities) - when type - entities.push(child) - end - end - - return entities - end - - # Only retrieve properties with faster search - def get_entities_to_import(folder, type) - res = folder.inventory_flat(type => :all) - objects = [] - - res.each {|k,v| - if k.to_s.split('(').first == type - obj = {} - v.propSet.each{ |dynprop| - obj[dynprop.name] = dynprop.val - } - obj[:ref] = k._ref - objects << OpenStruct.new(obj) - end - } - return objects - end - - ############################################################################ - # Initialize the VIClient, and creates an OpenNebula client. The parameters - # are obtained from the associated OpenNebula host - # @param hid [Integer] The OpenNebula host id with VCenter attributes - ############################################################################ - def initialize(hid) - - initialize_one - - @one_host = ::OpenNebula::Host.new_with_id(hid, @one) - rc = @one_host.info - - if ::OpenNebula.is_error?(rc) - raise "Error getting host information: #{rc.message}" - end - - password = @one_host["TEMPLATE/VCENTER_PASSWORD"] - - if !@token.nil? - begin - cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") - - cipher.decrypt - cipher.key = @token - - password = cipher.update(Base64::decode64(password)) - password << cipher.final - rescue - raise "Error decrypting vCenter password" - end - end - - connection = { - :host => @one_host["TEMPLATE/VCENTER_HOST"], - :user => @one_host["TEMPLATE/VCENTER_USER"], - :password => password - } - - initialize_vim(connection) - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each {|dc| - ccrs = VIClient.get_entities(dc.hostFolder, 'ClusterComputeResource') - - next if ccrs.nil? - - @cluster = ccrs.find{ |ccr| @one_host.name == ccr.name } - - (@dc = dc; break) if @cluster - } - - if @dc.nil? || @cluster.nil? - raise "Cannot find DataCenter or ClusterComputeResource for host." - end - end - - ######################################################################## - # Initialize a VIConnection based just on the VIM parameters. The - # OpenNebula client is also initialized - ######################################################################## - def self.new_connection(user_opts, one_client=nil) - - conn = allocate - - conn.initialize_one(one_client) - - conn.initialize_vim(user_opts) - - return conn - end - - ######################################################################## - # The associated cluster for this connection - ######################################################################## - def cluster - @cluster - end - - ######################################################################## - # Is this Cluster confined in a resource pool? - ######################################################################## - def rp_confined? - !@one_host["TEMPLATE/VCENTER_RESOURCE_POOL"].nil? - end - - ######################################################################## - # The associated resource pool for this connection - # @return [ResourcePool] an array of resource pools including the default - #  resource pool. If the connection is confined to a particular - #  resource pool, then return just that one - ######################################################################## - def resource_pool - rp_name = @one_host["TEMPLATE/VCENTER_RESOURCE_POOL"] - - if rp_name.nil? - rp_array = @cluster.resourcePool.resourcePool - rp_array << @cluster.resourcePool - rp_array - else - [find_resource_pool(rp_name)] - end - end - - ######################################################################## - # Get the default resource pool of the connection. Only valid if - # the connection is not confined in a resource pool - # @return ResourcePool the default resource pool - ######################################################################## - def default_resource_pool - @cluster.resourcePool - end - - ######################################################################## - # Searches the desired ResourcePool of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::ResourcePool or the default pool - # if not found - # @param rpool [String] the ResourcePool name - ######################################################################## - def find_resource_pool(poolName) - baseEntity = @cluster - - entityArray = poolName.split('/') - entityArray.each do |entityArrItem| - if entityArrItem != '' - if baseEntity.is_a? RbVmomi::VIM::Folder - baseEntity = baseEntity.childEntity.find { |f| - f.name == entityArrItem - } or return @cluster.resourcePool - elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource - baseEntity = baseEntity.resourcePool.resourcePool.find { |f| - f.name == entityArrItem - } or return @cluster.resourcePool - elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool - baseEntity = baseEntity.resourcePool.find { |f| - f.name == entityArrItem - } or return @cluster.resourcePool - else - return @cluster.resourcePool - end - end - end - - if !baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and - baseEntity.respond_to?(:resourcePool) - baseEntity = baseEntity.resourcePool - end - - baseEntity - end - - ######################################################################## - # Searches the associated vmFolder of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found - # - # Searches by moref, name, uuid and then iterates over all VMs - # - # @param uuid [String] the UUID of the VM or VM Template - # @param ref [String] VMware moref - # @param name [String] VM name in vCenter - ######################################################################## - def find_vm_fast(uuid, ref = nil, name = nil) - if ref - # It can raise ManagedObjectNotFound - begin - vm = RbVmomi::VIM::VirtualMachine.new(@dc._connection, ref) - return vm if vm.config && vm.config.uuid == uuid - rescue => e - end - end - - if name - begin - vm = @dc.vmFolder.find(name) - return vm if vm.config && vm.config.uuid == uuid - rescue - end - end - - return find_vm_template(uuid) - end - - ######################################################################## - # Searches the associated vmFolder of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found - # @param uuid [String] the UUID of the VM or VM Template - ######################################################################## - def find_vm_template(uuid) - version = @vim.serviceContent.about.version - - found_vm = nil - found_vm = @dc.vmFolder.findByUuid(uuid, RbVmomi::VIM::VirtualMachine, @dc) - return found_vm if found_vm - - vms = VIClient.get_entities(@dc.vmFolder, 'VirtualMachine') - - return vms.find do |v| - begin - v.config && v.config.uuid == uuid - rescue RbVmomi::VIM::ManagedObjectNotFound - false - end - end - end - - ######################################################################## - # Searches the associated vmFolder of the DataCenter for the current - # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found - # @param vm_name [String] the UUID of the VM or VM Template - ######################################################################## - def find_vm(vm_name) - vms = VIClient.get_entities(@dc.vmFolder, 'VirtualMachine') - - return vms.find do |v| - begin - v.name == vm_name - rescue RbVmomi::VIM::ManagedObjectNotFound - false - end - end - end - - ######################################################################## - # Searches the associated datacenter for a particular datastore - # @param ds_name [String] name of the datastore - # @returns a RbVmomi::VIM::VirtualMachine or nil if not found - ######################################################################## - def get_datastore(ds_name) - datastores = VIClient.get_entities(@dc.datastoreFolder, 'Datastore') - - storage_pods = VIClient.get_entities(@dc.datastoreFolder, 'StoragePod') - storage_pods.each { |sp| - datastores << sp #Add StoragePod - - # Add individual datastores under StoragePod - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == ds_name}[0] - end - - ######################################################################## - # Builds a hash with the DataCenter / ClusterComputeResource hierarchy - # for this VCenter. - # @return [Hash] in the form - # {dc_name [String] => ClusterComputeResources Names [Array - String]} - ######################################################################## - def hierarchy(one_client=nil) - vc_hosts = {} - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - hpool = OpenNebula::HostPool.new((one_client||@one)) - rc = hpool.info - - datacenters.each { |dc| - ccrs = VIClient.get_entities(dc.hostFolder, 'ClusterComputeResource') - vc_hosts[dc.name] = [] - ccrs.each { |c| - if !hpool["HOST[NAME=\"#{c.name}\"]"] - vc_hosts[dc.name] << c.name - end - } - } - - return vc_hosts - end - - ######################################################################## - # Builds a hash with the Datacenter / VM Templates for this VCenter - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Hash] in the form - # { dc_name [String] => Templates [Array] } - ######################################################################## - def vm_templates(one_client=nil) - vm_templates = {} - - tpool = OpenNebula::TemplatePool.new( - (one_client||@one), OpenNebula::Pool::INFO_ALL) - rc = tpool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - vms = get_entities_to_import(dc.vmFolder, 'VirtualMachine') - - tmp = vms.select { |v| v.config && (v.config.template == true) } - - one_tmp = [] - host_cache = {} - ds_cache = {} - - tmp.each { |t| - vi_tmp = VCenterVm.new(self, t) - - if !tpool["VMTEMPLATE/TEMPLATE/PUBLIC_CLOUD[\ - TYPE=\"vcenter\" \ - and VM_TEMPLATE=\"#{vi_tmp.vm.config.uuid}\"]"] - # Check cached objects - if !host_cache[vi_tmp.vm.runtime.host.to_s] - host_cache[vi_tmp.vm.runtime.host.to_s] = - VCenterCachedHost.new vi_tmp.vm.runtime.host - end - - if !ds_cache[t.datastore[0].to_s] - ds_cache[t.datastore[0].to_s] = - VCenterCachedDatastore.new t.datastore[0] - end - - host = host_cache[vi_tmp.vm.runtime.host.to_s] - ds = ds_cache[t.datastore[0].to_s] - - one_tmp << { - :name => "#{vi_tmp.vm.name} - #{host.cluster_name}", - :uuid => vi_tmp.vm.config.uuid, - :host => host.cluster_name, - :one => vi_tmp.to_one(host), - :ds => vi_tmp.to_one_ds(host, ds.name), - :default_ds => ds.name, - :rp => vi_tmp.to_one_rp(host), - :vcenter_ref => vi_tmp.vm._ref, - :vcenter_name => vi_tmp.vm.name - } - end - } - - vm_templates[dc.name] = one_tmp - } - - return vm_templates - end - - ######################################################################## - # Builds a hash with the Datacenter / CCR (Distributed)Networks - # for this VCenter - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Hash] in the form - # { dc_name [String] => Networks [Array] } - ######################################################################## - def vcenter_networks(one_client=nil) - vcenter_networks = {} - - vnpool = OpenNebula::VirtualNetworkPool.new( - (one_client||@one), OpenNebula::Pool::INFO_ALL) - rc = vnpool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - networks = VIClient.get_entities(dc.networkFolder, 'Network' ) - one_nets = [] - - networks.each { |n| - # Skip those not in cluster - next if !n[:host][0] - - # Networks can be in several cluster, create one per cluster - net_names = [] - Array(n[:host]).each{ |host_system| - net_name = "#{n.name} - #{host_system.parent.name}" - if !net_names.include?(net_name) - if !vnpool["VNET[BRIDGE=\"#{n[:name]}\"]/\ - TEMPLATE[VCENTER_TYPE=\"Port Group\"]"] - one_nets << { - :name => net_name, - :bridge => n.name, - :cluster => host_system.parent.name, - :type => "Port Group", - :one => "NAME = \"#{net_name}\"\n" \ - "BRIDGE = \"#{n[:name]}\"\n" \ - "VN_MAD = \"dummy\"\n" \ - "VCENTER_TYPE = \"Port Group\"" - } - net_names << net_name - end - end - } - } - - networks = VIClient.get_entities(dc.networkFolder, - 'DistributedVirtualPortgroup' ) - - networks.each { |n| - # Skip those not in cluster - next if !n[:host][0] - - # DistributedVirtualPortgroup can be in several cluster, - # create one per cluster - Array(n[:host][0]).each{ |host_system| - net_name = "#{n.name} - #{n[:host][0].parent.name}" - - if !vnpool["VNET[BRIDGE=\"#{n[:name]}\"]/\ - TEMPLATE[VCENTER_TYPE=\"Distributed Port Group\"]"] - vnet_template = "NAME = \"#{net_name}\"\n" \ - "BRIDGE = \"#{n[:name]}\"\n" \ - "VN_MAD = \"dummy\"\n" \ - "VCENTER_TYPE = \"Distributed Port Group\"" - - default_pc = n.config.defaultPortConfig - - has_vlan = false - vlan_str = "" - - if default_pc.methods.include? :vlan - has_vlan = default_pc.vlan.methods.include? :vlanId - end - - if has_vlan - vlan = n.config.defaultPortConfig.vlan.vlanId - - if vlan != 0 - if vlan.is_a? Array - vlan.each{|v| - vlan_str += v.start.to_s + ".." + - v.end.to_s + "," - } - vlan_str.chop! - else - vlan_str = vlan.to_s - end - end - end - - if !vlan_str.empty? - vnet_template << "VLAN_TAGGED_ID=#{vlan_str}\n" - end - - one_net = {:name => net_name, - :bridge => n.name, - :cluster => host_system.parent.name, - :type => "Distributed Port Group", - :one => vnet_template} - - one_net[:vlan] = vlan_str if !vlan_str.empty? - - one_nets << one_net - end - } - } - - vcenter_networks[dc.name] = one_nets - } - - return vcenter_networks - end - - - ######################################################################## - # Builds a hash with the Datacenter / Datastores for this VCenter - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Hash] in the form - # { dc_name [String] => Datastore [Array] of DS templates} - ######################################################################## - def vcenter_datastores(one_client=nil) - ds_templates = {} - - dspool = OpenNebula::DatastorePool.new( - (one_client||@one)) - rc = dspool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - hpool = OpenNebula::HostPool.new( - (one_client||@one)) - rc = hpool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - one_tmp = [] - datastores = VIClient.get_entities(dc.datastoreFolder, 'Datastore') - - storage_pods = VIClient.get_entities(dc.datastoreFolder, 'StoragePod') - storage_pods.each { |sp| - datastores << sp # Add StoragePod - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - datastores.each { |ds| - next if !ds.is_a? RbVmomi::VIM::Datastore and !ds.is_a? RbVmomi::VIM::StoragePod - # Find the Cluster from which to access this ds - - cluster_name = "" - if ds.is_a? RbVmomi::VIM::StoragePod - storage_pod_datastores = VIClient.get_entities(ds, 'Datastore') - storage_pod_datastores.each { |sp| - next if !sp.is_a? RbVmomi::VIM::Datastore - # Find the Cluster from which to access this ds - next if !sp.host[0] - cluster_name = sp.host[0].key.parent.name - break - } - else - next if !ds.host[0] - cluster_name = ds.host[0].key.parent.name - end - - if !dspool["DATASTORE[NAME=\"#{ds.name}\"]"] and - hpool["HOST[NAME=\"#{cluster_name}\"]"] - if ds.is_a? RbVmomi::VIM::StoragePod - one_tmp << { - :name => "#{ds.name}", - :total_mb => ((ds.summary.capacity.to_i / 1024) / 1024), - :free_mb => ((ds.summary.freeSpace.to_i / 1024) / 1024), - :cluster => cluster_name, - :one => "NAME=#{ds.name}\n"\ - "TM_MAD=vcenter\n"\ - "VCENTER_CLUSTER=#{cluster_name}\n"\ - "TYPE=SYSTEM_DS\n" # StoragePods must be set as SYSTEM_DS - } - else - one_tmp << { - :name => "#{ds.name}", - :total_mb => ((ds.summary.capacity.to_i / 1024) / 1024), - :free_mb => ((ds.summary.freeSpace.to_i / 1024) / 1024), - :cluster => cluster_name, - :one => "NAME=#{ds.name}\n"\ - "DS_MAD=vcenter\n"\ - "TM_MAD=vcenter\n"\ - "VCENTER_CLUSTER=#{cluster_name}\n" - } - end - end - } - ds_templates[dc.name] = one_tmp - } - - return ds_templates - end - - ############################################################################# - # Builds a hash with the Images for a particular datastore - # @param one_client [OpenNebula::Client] Use this client instead of @one - # @return [Array] of image templates - ############################################################################ - def vcenter_images(ds_name, one_client=nil) - img_types = ["FloppyImageFileInfo", - "IsoImageFileInfo", - "VmDiskFileInfo"] - - img_templates = [] - - ipool = OpenNebula::ImagePool.new((one_client||@one)) - rc = ipool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - dspool = OpenNebula::DatastorePool.new((one_client||@one)) - rc = dspool.info - if OpenNebula.is_error?(rc) - raise "Error contacting OpenNebula #{rc.message}" - end - - ds_id = dspool["DATASTORE[NAME=\"#{ds_name}\"]/ID"] - - if !ds_id - raise "Datastore not found in OpenNebula. Please import"\ - " it first and try again" - end - - datacenters = VIClient.get_entities(@root, 'Datacenter') - - datacenters.each { |dc| - - # Find datastore within datacenter - datastores = VIClient.get_entities(dc.datastoreFolder, 'Datastore') - - storage_pods = VIClient.get_entities(dc.datastoreFolder, 'StoragePod') - storage_pods.each { |sp| - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == ds_name}[0] - next if !ds - - # Cannot import from StoragePod directly - if ds.is_a? RbVmomi::VIM::StoragePod - raise "OpenNebula cannot import images from a StoragePod. Please import"\ - " it from the datastore which is a member of the StorageDRS cluster" - end - - # Create Search Spec - spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new - spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, - RbVmomi::VIM::IsoImageFileQuery.new] - spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, - :fileSize => true, - :fileType => true, - :modification => true) - spec.matchPattern=[] - - search_params = {'datastorePath' => "[#{ds.name}]", - 'searchSpec' => spec} - - # Perform search task and return results - search_task=ds.browser.SearchDatastoreSubFolders_Task(search_params) - search_task.wait_for_completion - - search_task.info.result.each { |image| - folderpath = "" - if image.folderPath[-1] != "]" - folderpath = image.folderPath.sub(/^\[#{ds_name}\] /, "") - end - - image = image.file[0] - - # Skip not relevant files - next if !img_types.include? image.class.to_s - - image_path = folderpath + image.path - - image_name = File.basename(image.path).reverse.sub("kdmv.","").reverse - - if !ipool["IMAGE[NAME=\"#{image_name} - #{ds_name}\"]"] - img_templates << { - :name => "#{image_name} - #{ds_name}", - :path => image_path, - :size => (image.fileSize / 1024).to_s, - :type => image.class.to_s, - :dsid => ds_id, - :one => "NAME=\"#{image_name} - #{ds_name}\"\n"\ - "PATH=\"vcenter://#{image_path}\"\n"\ - "PERSISTENT=\"YES\"\n"\ - } - - if image.class.to_s == "VmDiskFileInfo" - img_templates[-1][:one] += "TYPE=\"OS\"\n" - else - img_templates[-1][:one] += "TYPE=\"CDROM\"\n" - end - - if image.class.to_s == "VmDiskFileInfo" && - !image.diskType.nil? - img_templates[-1][:one] += "DISK_TYPE=#{image.diskType}\n" - end - end - } - } - - return img_templates - end - - def self.translate_hostname(hostname) - host_pool = OpenNebula::HostPool.new(::OpenNebula::Client.new()) - rc = host_pool.info - raise "Could not find host #{hostname}" if OpenNebula.is_error?(rc) - - host = host_pool.select {|host_element| host_element.name==hostname } - return host.first.id - end - - def self.find_ds_name(ds_id) - ds = OpenNebula::Datastore.new_with_id(ds_id, OpenNebula::Client.new) - rc = ds.info - raise "Could not find datastore #{ds_id}" if OpenNebula.is_error?(rc) - - return ds["/DATASTORE/TEMPLATE/VCENTER_NAME"] - end - - ############################################################################ - # Initialize an OpenNebula connection with the default ONE_AUTH - ############################################################################ - def initialize_one(one_client=nil) - begin - if one_client - @one = one_client - else - @one = ::OpenNebula::Client.new() - end - - system = ::OpenNebula::System.new(@one) - - config = system.get_configuration() - - if ::OpenNebula.is_error?(config) - raise "Error getting oned configuration : #{config.message}" - end - - @token = config["ONE_KEY"] - rescue Exception => e - raise "Error initializing OpenNebula client: #{e.message}" - end - end - - ############################################################################ - # Initialize a connection with vCenter. Options - # @param options[Hash] with: - # :user => The vcenter user - # :password => Password for the user - # :host => vCenter hostname or IP - # :insecure => SSL (optional, defaults to true) - ############################################################################ - def initialize_vim(user_opts={}) - opts = { - :insecure => true - }.merge(user_opts) - - @user = opts[:user] - @pass = opts[:password] - @host = opts[:host] - - begin - @vim = RbVmomi::VIM.connect(opts) - @root = @vim.root - @vdm = @vim.serviceContent.virtualDiskManager - @file_manager = @vim.serviceContent.fileManager - rescue Exception => e - raise "Error connecting to #{@host}: #{e.message}" - end - end - - ######################### Datastore Operations ############################# - - ############################################################################ - # Retrieve size for a VirtualDisk in a particular datastore - # @param ds_name [String] name of the datastore - # @param img_str [String] path to the VirtualDisk - # @return size of the file in Kb - ############################################################################ - def stat(ds_name, img_str) - img_path = File.dirname img_str - img_name = File.basename img_str - - # Find datastore within datacenter - ds = get_datastore(ds_name) - - # Create Search Spec - spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new - spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, - RbVmomi::VIM::IsoImageFileQuery.new] - spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, - :fileSize => true, - :fileType => true, - :modification => true) - spec.matchPattern=[img_name] - - search_params = {'datastorePath' => "[#{ds_name}] #{img_path}", - 'searchSpec' => spec} - - # Perform search task and return results - search_task=ds.browser.SearchDatastoreSubFolders_Task(search_params) - search_task.wait_for_completion - (search_task.info.result[0].file[0].fileSize / 1024) / 1024 - end - - ############################################################################ - # Returns Datastore information - # @param ds_name [String] name of the datastore - # @return [String] monitor information of the DS - ############################################################################ - def monitor_ds(ds_name) - # Find datastore within datacenter - ds = get_datastore(ds_name) - - total_mb = (ds.summary.capacity.to_i / 1024) / 1024 - free_mb = (ds.summary.freeSpace.to_i / 1024) / 1024 - used_mb = total_mb - free_mb - - if ds.is_a? RbVmomi::VIM::Datastore - ds_type = ds.summary.type - end - - "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" - end - - ############################################################################ - # Copy a VirtualDisk - # @param ds_name [String] name of the datastore - # @param img_str [String] path to the VirtualDisk - ############################################################################ - def copy_virtual_disk(source_path, source_ds, target_path, target_ds=nil) - target_ds = source_ds if target_ds.nil? - - copy_params= {:sourceName => "[#{source_ds}] #{source_path}", - :sourceDatacenter => @dc, - :destName => "[#{target_ds}] #{target_path}"} - - @vdm.CopyVirtualDisk_Task(copy_params).wait_for_completion - - target_path - end - - ############################################################################ - # Create a VirtualDisk - # @param img_name [String] name of the image - # @param ds_name [String] name of the datastore on which the VD will be - # created - # @param size [String] size of the new image in MB - # @param adapter_type [String] as described in - #  http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc/vim.VirtualDiskManager.VirtualDiskAdapterType.html - # @param disk_type [String] as described in - #  http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.VirtualDiskManager.VirtualDiskType.html - # @return name of the final image - ############################################################################ - def create_virtual_disk(img_name, ds_name, size, adapter_type, disk_type) - vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec( - :adapterType => adapter_type, - :capacityKb => size.to_i*1024, - :diskType => disk_type - ) - - @vdm.CreateVirtualDisk_Task( - :datacenter => @dc, - :name => "[#{ds_name}] #{img_name}.vmdk", - :spec => vmdk_spec - ).wait_for_completion - - "#{img_name}.vmdk" - end - - ############################################################################ - # Delete a VirtualDisk - # @param img_name [String] name of the image - # @param ds_name [String] name of the datastore where the VD resides - ############################################################################ - def delete_virtual_disk(img_name, ds_name) - @vdm.DeleteVirtualDisk_Task( - name: "[#{ds_name}] #{img_name}", - datacenter: @dc - ).wait_for_completion - end - - ############################################################################ - # Delete a VirtualDisk - # @param directory [String] name of the new directory - # @param ds_name [String] name of the datastore where to create the dir - ############################################################################ - def create_directory(directory, ds_name) - begin - path = "[#{ds_name}] #{directory}" - @file_manager.MakeDirectory(:name => path, - :datacenter => @dc, - :createParentDirectories => true) - rescue RbVmomi::VIM::FileAlreadyExists => e - end - end - - ############################################################################ - # Silences standard output and error - ############################################################################ - def self.in_silence - begin - orig_stderr = $stderr.clone - orig_stdout = $stdout.clone - $stderr.reopen File.new('/dev/null', 'w') - $stdout.reopen File.new('/dev/null', 'w') - retval = yield - rescue Exception => e - $stdout.reopen orig_stdout - $stderr.reopen orig_stderr - raise e - ensure - $stdout.reopen orig_stdout - $stderr.reopen orig_stderr - end - retval - end - - ############################################################################ - # Silences standard output and error - ############################################################################ - def self.in_stderr_silence - begin - orig_stderr = $stderr.clone - $stderr.reopen File.new('/dev/null', 'w') - retval = yield - rescue Exception => e - $stderr.reopen orig_stderr - raise e - ensure - $stderr.reopen orig_stderr - end - retval +# ---------------------------------------------------------------------------- # +# vCenter Library # +# ---------------------------------------------------------------------------- # + +require 'memoize' +require 'vi_client' +require 'vi_helper' +require 'datacenter' +require 'host' +require 'datastore' +require 'virtual_machine' +require 'network' +require 'file_helper' + +# ---------------------------------------------------------------------------- # +# Helper functions # +# ---------------------------------------------------------------------------- # + +def check_valid(parameter, label) + if parameter.nil? || parameter.empty? + STDERR.puts "The parameter '#{label}' is required for this action." + exit -1 end end - -################################################################################ -# Cached Classes to speed up import and monitoring -################################################################################ -class VCenterCachedHost - - def initialize(rbVmomiHost) - @host = rbVmomiHost - @attributes = Hash.new - end - - def name - if !@attributes['name'] - @attributes['name']=@host.parent.name - end - @attributes['name'] - end - - def cluster_name - if !@attributes['cluster_name'] - @attributes['cluster_name']=@host.parent.name - end - @attributes['cluster_name'] - end - - def ds_list - if !@attributes['ds_list'] - @attributes['ds_list']="" - - datacenter = @host.parent - while !datacenter.is_a? RbVmomi::VIM::Datacenter - datacenter = datacenter.parent - end - - datastores=VIClient.get_entities( - datacenter.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(datacenter.datastoreFolder, - 'StoragePod') - storage_pods.each { |sp| - datastores << sp # Add Storage Pod - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - datastores.each { |ds| - @attributes['ds_list'] += ds.name + "," - } - @attributes['ds_list']=@attributes['ds_list'][0..-2] - end - @attributes['ds_list'] - end - - def rp_list - if !@attributes['rp_list'] - @attributes['rp_list']="" - @host.parent.resourcePool.resourcePool.each{|rp| - @attributes['rp_list'] += get_child_rp_names(rp, "") - } - @attributes['rp_list']=@attributes['rp_list'][0..-2] - end - @attributes['rp_list'] - end - - def get_child_rp_names(rp, parent_prefix) - rp_str = "" - - current_rp = (parent_prefix.empty? ? "" : parent_prefix + "/") - current_rp += rp.name - - if rp.resourcePool.size != 0 - rp.resourcePool.each{|child_rp| - rp_str += get_child_rp_names(child_rp, current_rp) - } - end - - rp_str += current_rp + "," - - return rp_str - end - - def cpumhz - if !@attributes['cpumhz'] - @attributes['cpumhz']=@host.summary.hardware.cpuMhz.to_f - end - @attributes['cpumhz'] - end - -end - -class VCenterCachedDatastore - - def initialize(rbVmomiDatastore) - @ds = rbVmomiDatastore - @attributes = Hash.new - end - - def name - if !@attributes['name'] - @attributes['name']=@ds.name - end - @attributes['name'] - end - - -end - -################################################################################ -# This class is an OpenNebula hosts that abstracts a vCenter cluster. It -# includes the functionality needed to monitor the cluster and report the ESX -# hosts and VM status of the cluster. -################################################################################ -class VCenterHost < ::OpenNebula::Host - attr_reader :vc_client, :vc_root, :cluster, :host, :client - - ############################################################################ - # Initialize the VCenterHost by looking for the associated objects of the - # VIM hierarchy - # client [VIClient] to interact with the associated vCenter - ############################################################################ - def initialize(client) - @client = client - @cluster = client.cluster - - @resource_pools = client.resource_pool - end - - ######################################################################## - # Creates an OpenNebula host representing a cluster in this VCenter - # @param cluster_name[String] the name of the cluster in the vcenter - # @param client [VIClient] to create the host - # @return In case of success [0, host_id] or [-1, error_msg] - ######################################################################## - def self.to_one(cluster_name, client) - one_host = ::OpenNebula::Host.new(::OpenNebula::Host.build_xml, - client.one) - - rc = one_host.allocate(cluster_name, 'vcenter', 'vcenter', - ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) - - return -1, rc.message if ::OpenNebula.is_error?(rc) - - template = "VCENTER_HOST=\"#{client.host}\"\n"\ - "VCENTER_PASSWORD=\"#{client.pass}\"\n"\ - "VCENTER_USER=\"#{client.user}\"\n" - - rc = one_host.update(template, false) - - if ::OpenNebula.is_error?(rc) - error = rc.message - - rc = one_host.delete - - if ::OpenNebula.is_error?(rc) - error << ". Host #{cluster_name} could not be"\ - " deleted: #{rc.message}." - end - - return -1, error - end - - return 0, one_host.id - end - - ############################################################################ - # Generate an OpenNebula monitor string for this host. Reference: - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/Reference - # Guide/vim.ComputeResource.Summary.html - # - effectiveCpu: Effective CPU resources (in MHz) available to run - # VMs. This is the aggregated from all running hosts excluding hosts in - # maintenance mode or unresponsive are not counted. - # - effectiveMemory: Effective memory resources (in MB) available to run - # VMs. Equivalente to effectiveCpu. - # - numCpuCores: Number of physical CPU cores. - # - numEffectiveHosts: Total number of effective hosts. - # - numHosts:Total number of hosts. - # - totalCpu: Aggregated CPU resources of all hosts, in MHz. - # - totalMemory: Aggregated memory resources of all hosts, in bytes. - ############################################################################ - def monitor_cluster - #Load the host systems - summary = @cluster.summary - - mhz_core = summary.totalCpu.to_f / summary.numCpuCores.to_f - eff_core = summary.effectiveCpu.to_f / mhz_core - - free_cpu = sprintf('%.2f', eff_core * 100).to_f - total_cpu = summary.numCpuCores.to_f * 100 - used_cpu = sprintf('%.2f', total_cpu - free_cpu).to_f - - total_mem = summary.totalMemory.to_i / 1024 - free_mem = summary.effectiveMemory.to_i * 1024 - - str_info = "" - - # System - str_info << "HYPERVISOR=vcenter\n" - str_info << "TOTALHOST=" << summary.numHosts.to_s << "\n" - str_info << "AVAILHOST=" << summary.numEffectiveHosts.to_s << "\n" - - # CPU - str_info << "CPUSPEED=" << mhz_core.to_s << "\n" - str_info << "TOTALCPU=" << total_cpu.to_s << "\n" - str_info << "USEDCPU=" << used_cpu.to_s << "\n" - str_info << "FREECPU=" << free_cpu.to_s << "\n" - - # Memory - str_info << "TOTALMEMORY=" << total_mem.to_s << "\n" - str_info << "FREEMEMORY=" << free_mem.to_s << "\n" - str_info << "USEDMEMORY=" << (total_mem - free_mem).to_s - - str_info << monitor_resource_pools(@cluster.resourcePool, "", mhz_core) - end - - ############################################################################ - # Generate an OpenNebula monitor string for all resource pools of a cluster - # Reference: - # http://pubs.vmware.com/vsphere-60/index.jsp#com.vmware.wssdk.apiref.doc - # /vim.ResourcePool.html - ############################################################################ - def monitor_resource_pools(parent_rp, parent_prefix, mhz_core) - return "" if parent_rp.resourcePool.size == 0 - - rp_info = "" - - parent_rp.resourcePool.each{|rp| - rpcpu = rp.config.cpuAllocation - rpmem = rp.config.memoryAllocation - # CPU - cpu_expandable = rpcpu.expandableReservation ? "YES" : "NO" - cpu_limit = rpcpu.limit == "-1" ? "UNLIMITED" : rpcpu.limit - cpu_reservation = rpcpu.reservation - cpu_num = rpcpu.reservation.to_f / mhz_core - cpu_shares_level = rpcpu.shares.level - cpu_shares = rpcpu.shares.shares - - # MEMORY - mem_expandable = rpmem.expandableReservation ? "YES" : "NO" - mem_limit = rpmem.limit == "-1" ? "UNLIMITED" : rpmem.limit - mem_reservation = rpmem.reservation.to_f - mem_shares_level = rpmem.shares.level - mem_shares = rpmem.shares.shares - - rp_name = (parent_prefix.empty? ? "" : parent_prefix + "/") - rp_name += rp.name - - rp_info << "\nRESOURCE_POOL = [" - rp_info << "NAME=\"#{rp_name}\"," - rp_info << "CPU_EXPANDABLE=#{cpu_expandable}," - rp_info << "CPU_LIMIT=#{cpu_limit}," - rp_info << "CPU_RESERVATION=#{cpu_reservation}," - rp_info << "CPU_RESERVATION_NUM_CORES=#{cpu_num}," - rp_info << "CPU_SHARES=#{cpu_shares}," - rp_info << "CPU_SHARES_LEVEL=#{cpu_shares_level}," - rp_info << "MEM_EXPANDABLE=#{mem_expandable}," - rp_info << "MEM_LIMIT=#{mem_limit}," - rp_info << "MEM_RESERVATION=#{mem_reservation}," - rp_info << "MEM_SHARES=#{mem_shares}," - rp_info << "MEM_SHARES_LEVEL=#{mem_shares_level}" - rp_info << "]" - - if rp.resourcePool.size != 0 - rp_info << monitor_resource_pools(rp, rp_name, mhz_core) - end - } - - return rp_info - end - - ############################################################################ - # Generate a template with information for each ESX Host. Reference: - # http://pubs.vmware.com/vi-sdk/visdk250/ReferenceGuide/vim.HostSystem.html - # - Summary: Basic information about the host, including connection state - # - hardware: Hardware configuration of the host. This might not be - # available for a disconnected host. - # - quickStats: Basic host statistics. - ############################################################################ - def monitor_host_systems - host_info = "" - - @cluster.host.each{|h| - next if h.runtime.connectionState != "connected" - - summary = h.summary - hw = summary.hardware - stats = summary.quickStats - - total_cpu = hw.numCpuCores * 100 - used_cpu = (stats.overallCpuUsage.to_f / hw.cpuMhz.to_f) * 100 - used_cpu = sprintf('%.2f', used_cpu).to_f # Trim precission - free_cpu = total_cpu - used_cpu - - total_memory = hw.memorySize/1024 - used_memory = stats.overallMemoryUsage*1024 - free_memory = total_memory - used_memory - - host_info << "\nHOST=[" - host_info << "STATE=on," - host_info << "HOSTNAME=\"" << h.name.to_s << "\"," - host_info << "MODELNAME=\"" << hw.cpuModel.to_s << "\"," - host_info << "CPUSPEED=" << hw.cpuMhz.to_s << "," - host_info << "MAX_CPU=" << total_cpu.to_s << "," - host_info << "USED_CPU=" << used_cpu.to_s << "," - host_info << "FREE_CPU=" << free_cpu.to_s << "," - host_info << "MAX_MEM=" << total_memory.to_s << "," - host_info << "USED_MEM=" << used_memory.to_s << "," - host_info << "FREE_MEM=" << free_memory.to_s - host_info << "]" - } - - return host_info - end - - def monitor_vms - # Only monitor from top level (Resource) Resource Pool - monitor_vms_in_rp(@resource_pools[-1]) - end - - - def monitor_vms_in_rp(rp) - str_info = "" - - if rp.resourcePool.size != 0 - rp.resourcePool.each{|child_rp| - str_info += monitor_vms_in_rp(child_rp) - } - end - - host_cache = {} - - rp.vm.each { |v| - begin - # Check cached objects - if !host_cache[v.runtime.host.to_s] - host_cache[v.runtime.host.to_s] = - VCenterCachedHost.new v.runtime.host - end - - host = host_cache[v.runtime.host.to_s] - - name = v.name - number = -1 - vm_extra_config = v.config.extraConfig - - # Check the running flag - running_flag = v.config.extraConfig.select{|val| - val[:key]=="opennebula.vm.running"} - if running_flag.size > 0 and running_flag[0] - running_flag = running_flag[0][:value] - end - - next if running_flag == "no" - - # Extract vmid if possible - matches = name.match(/^one-(\d*)(-(.*))?$/) - number = matches[1] if matches - extraconfig_vmid = v.config.extraConfig.select{|val| - val[:key]=="opennebula.vm.id"} - if extraconfig_vmid.size > 0 and extraconfig_vmid[0] - number = extraconfig_vmid[0][:value] - end - vm = VCenterVm.new(@client, v) - vm.monitor(host) - next if !vm.vm.config - str_info << "\nVM = [" - str_info << "ID=#{number}," - str_info << "DEPLOY_ID=\"#{vm.vm.config.uuid}\"," - str_info << "VM_NAME=\"#{name} - "\ - "#{host.cluster_name}\"," - if number == -1 - vm_template_to_one = - Base64.encode64(vm.vm_to_one(host)).gsub("\n","") - str_info << "IMPORT_TEMPLATE=\"#{vm_template_to_one}\"," - end - str_info << "POLL=\"#{vm.info}\"]" - rescue Exception => e - STDERR.puts e.inspect - STDERR.puts e.backtrace - end - } - return str_info - end - - def monitor_customizations - customizations = client.vim.serviceContent.customizationSpecManager.info - - text = '' - - customizations.each do |c| - t = "CUSTOMIZATION = [ " - t << %Q - t << %Q - - text << t - end - - text - end - - def get_available_ds - str_info = "" - - datastores = VIClient.get_entities(client.dc.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(client.dc.datastoreFolder, - 'StoragePod') - - storage_pods.each { |sp| - datastores << sp - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - datastores.each { |ds| - str_info += "VCENTER_DATASTORE=\"#{ds.name}\"\n" - } - str_info.chomp - end -end - -################################################################################ -# This class is a high level abstraction of a VI VirtualMachine class with -# OpenNebula semantics. -################################################################################ - -class VCenterVm - attr_reader :vm - - POLL_ATTRIBUTE = OpenNebula::VirtualMachine::Driver::POLL_ATTRIBUTE - VM_STATE = OpenNebula::VirtualMachine::Driver::VM_STATE - - ############################################################################ - # Creates a new VIVm using a RbVmomi::VirtualMachine object - # @param client [VCenterClient] client to connect to vCenter - # @param vm_vi [RbVmomi::VirtualMachine] it will be used if not nil - ######################################################################## - def initialize(client, vm_vi ) - @vm = vm_vi - @client = client - - @used_cpu = 0 - @used_memory = 0 - - @netrx = 0 - @nettx = 0 - - @diskrdbytes = 0 - @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 - end - - ############################################################################ - # Deploys a VM - # @xml_text XML representation of the VM - ############################################################################ - def self.deploy(xml_text, lcm_state, deploy_id, hostname, datastore = nil, - ops = {}) - if lcm_state == "BOOT" || lcm_state == "BOOT_FAILURE" - return clone_vm(xml_text, hostname, datastore, ops) - else - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_fast(deploy_id, - ops[:ref], - ops[:name]) - xml = REXML::Document.new xml_text - - reconfigure_vm(vm, xml, false, hostname) - - vm.PowerOnVM_Task.wait_for_completion - - return vm.config.uuid - end - end - - ############################################################################ - # Cancels a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param lcm_state state of the VM - # @param keep_disks keep or not VM disks in datastore - # @param disks VM attached disks - ############################################################################ - def self.cancel(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) - - case lcm_state - when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" - shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) - when "CANCEL", "LCM_INIT", "CLEANUP_RESUBMIT", "SHUTDOWN", "CLEANUP_DELETE" - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - begin - if vm.summary.runtime.powerState == "poweredOn" - vm.PowerOffVM_Task.wait_for_completion - end - rescue - end - - if keep_disks - detach_all_disks(vm) - else - detach_attached_disks(vm, disks, hostname) if disks - end - - # If the VM was instantiated to persistent, convert the VM to - # vCenter VM Template and update the OpenNebula new - # VM Template to point to the new vCenter VM Template - if !to_template.nil? - vm.MarkAsTemplate - - new_template = OpenNebula::Template.new_with_id(to_template, - OpenNebula::Client.new) - new_template.info - - public_cloud_str = "PUBLIC_CLOUD=[" - - new_template.to_hash["VMTEMPLATE"]["TEMPLATE"]["PUBLIC_CLOUD"].each{|k,v| - if k == "VM_TEMPLATE" - public_cloud_str += "VM_TEMPLATE=\"#{deploy_id}\",\n" - else - public_cloud_str += "#{k}=\"#{v}\",\n" - end - } - - public_cloud_str = public_cloud_str + "]" - - new_template.update(public_cloud_str, true) - else - vm.Destroy_Task.wait_for_completion - end - else - raise "LCM_STATE #{lcm_state} not supported for cancel" - end - end - - - ############################################################################ - # Saves a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.save(deploy_id, hostname, lcm_state) - case lcm_state - when "SAVE_MIGRATE" - raise "Migration between vCenters cluster not supported" - when "SAVE_SUSPEND", "SAVE_STOP" - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) - - vm.SuspendVM_Task.wait_for_completion - end - end - - ############################################################################ - # Resumes a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.resume(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) - - vm.PowerOnVM_Task.wait_for_completion - end - - ############################################################################ - # Reboots a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.reboot(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.RebootGuest.wait_for_completion - end - - ############################################################################ - # Resets a VM - # @param deploy_id vcetranslate_hostnamnter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - ############################################################################ - def self.reset(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - vm.ResetVM_Task.wait_for_completion - end - - ############################################################################ - # Shutdown a VM - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param lcm_state state of the VM - # @param keep_disks keep or not VM disks in datastore - # @param disks VM attached disks - # @param to_template whether this VM has been instantiated as persistent - ############################################################################ - def self.shutdown(deploy_id, hostname, lcm_state, keep_disks, disks, to_template) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - case lcm_state - when "SHUTDOWN" - begin - vm.ShutdownGuest - counter = 60*10 # 10 minutes - while counter > 0 - break if vm.runtime.powerState == "poweredOff" - counter -= 1 - sleep 1 - end - rescue - end - - if vm.runtime.powerState != "poweredOff" - vm.PowerOffVM_Task.wait_for_completion - end - - if keep_disks - detach_all_disks(vm) - else - detach_attached_disks(vm, disks, hostname) if disks - end - - # If the VM was instantiated to persistent, convert the VM to - # vCenter VM Template and update the OpenNebula new - # VM Template to point to the new vCenter VM Template - if !to_template.nil? - vm.MarkAsTemplate - - new_template = OpenNebula::Template.new_with_id(to_template, - OpenNebula::Client.new) - new_template.info - - public_cloud_str = "PUBLIC_CLOUD=[" - - new_template.to_hash["VMTEMPLATE"]["TEMPLATE"]["PUBLIC_CLOUD"].each{|k,v| - if k == "VM_TEMPLATE" - public_cloud_str += "VM_TEMPLATE=\"#{deploy_id}\"\n" - else - public_cloud_str += "#{k}=\"#{v}\",\n" - end - } - - public_cloud_str = public_cloud_str + "]" - - new_template.update(public_cloud_str, true) - else - vm.Destroy_Task.wait_for_completion - end - - when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" - begin - vm.ShutdownGuest - counter = 60*10 # 10 minutes - while counter > 0 - break if vm.runtime.powerState == "poweredOff" - counter -= 1 - sleep 1 - end - rescue - end - - if vm.runtime.powerState != "poweredOff" - vm.PowerOffVM_Task.wait_for_completion - end - end - end - - ############################################################################ - # Create VM snapshot - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param snaphot_name name of the snapshot - ############################################################################ - def self.create_snapshot(deploy_id, hostname, snapshot_name) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - snapshot_hash = { - :name => snapshot_name, - :description => "OpenNebula Snapshot of VM #{deploy_id}", - :memory => true, - :quiesce => true - } - - vm = connection.find_vm_template(deploy_id) - - vm.CreateSnapshot_Task(snapshot_hash).wait_for_completion - - return snapshot_name - end - - ############################################################################ - # Find VM snapshot - # @param list root list of VM snapshots - # @param snaphot_name name of the snapshot - ############################################################################ - def self.find_snapshot(list, snapshot_name) - list.each do |i| - if i.name == snapshot_name - return i.snapshot - elsif !i.childSnapshotList.empty? - snap = find_snapshot(i.childSnapshotList, snapshot_name) - return snap if snap - end - end - - nil - end - - ############################################################################ - # Delete VM snapshot - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param snaphot_name name of the snapshot - ############################################################################ - def self.delete_snapshot(deploy_id, hostname, snapshot_name) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - list = vm.snapshot.rootSnapshotList - - snapshot = find_snapshot(list, snapshot_name) - return nil if !snapshot - - delete_snapshot_hash = { - :_this => snapshot, - :removeChildren => false - } - - snapshot.RemoveSnapshot_Task(delete_snapshot_hash).wait_for_completion - end - - ############################################################################ - # Revert VM snapshot - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param snaphot_name name of the snapshot - ############################################################################ - def self.revert_snapshot(deploy_id, hostname, snapshot_name) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - list = vm.snapshot.rootSnapshotList - - snapshot = find_snapshot(list, snapshot_name) - return nil if !snapshot - - revert_snapshot_hash = { - :_this => snapshot - } - - snapshot.RevertToSnapshot_Task(revert_snapshot_hash).wait_for_completion - end - - ############################################################################ - # Attach NIC to a VM - # @param deploy_id vcenter identifier of the VM - # @param mac MAC address of the NIC to be attached - # @param bridge name of the Network in vCenter - # @param model model of the NIC to be attached - # @param host hostname of the ESX where the VM is running - ############################################################################ - def self.attach_nic(deploy_id, mac, bridge, model, host) - hid = VIClient::translate_hostname(host) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - spec_nics = calculate_addnic_spec(vm, mac, bridge, model) - - spec_hash = {:deviceChange => [spec_nics]} - - - #B4897 track hot plugged nics - hotplugged_nics = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.hotplugged_nics" - end - - if hotplugged_nics && !hotplugged_nics.empty? - hotplugged_nics = hotplugged_nics[0][:value].to_s - hotplugged_nics << mac.to_s << ";" if !hotplugged_nics.include?(mac) - else - hotplugged_nics = "" - hotplugged_nics << mac.to_s << ";" - end - - config_array = [{:key=>"opennebula.hotplugged_nics", - :value=>hotplugged_nics}] - extra_config_spec = {:extraConfig =>config_array} - - spec_hash.merge!(extra_config_spec) - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - - end - - ############################################################################ - # Detach NIC from a VM - ############################################################################ - def self.detach_nic(deploy_id, mac, host) - hid = VIClient::translate_hostname(host) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - nic = vm.config.hardware.device.find { |d| - is_nic?(d) && (d.macAddress == mac) - } - - raise "Could not find NIC with mac address #{mac}" if nic.nil? - - #B4897 track hot plugged nics - hotplugged_nics = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.hotplugged_nics" - end - - config_array = [] - if hotplugged_nics && !hotplugged_nics.empty? - hotplugged_nics = hotplugged_nics[0][:value].to_s - hotplugged_nics.slice!(mac + ";") # remove hotplugged nic - config_array = [{:key=>"opennebula.hotplugged_nics", - :value=>hotplugged_nics}] - end - - spec = { - :deviceChange => [ - :operation => :remove, - :device => nic - ], - :extraConfig => config_array - } - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - ############################################################################ - # Reconfigures a VM (context data) - # @param deploy_id vcenter identifier of the VM - # @param hostname name of the host (equals the vCenter cluster) - # @param xml_text XML repsentation of the VM - ############################################################################ - def self.reconfigure(deploy_id, hostname, xml_text) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) - - xml = REXML::Document.new xml_text - context = xml.root.elements["//TEMPLATE/CONTEXT"] - - if context - context_text = create_context(context) - context_spec = { - :extraConfig => [ - { :key=>"guestinfo.opennebula.context", - :value=> Base64.encode64(context_text) } - ] - } - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(context_spec) - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - end - - ######################################################################## - # Initialize the vm monitor information - ######################################################################## - def monitor(host) - @summary = @vm.summary - @state = state_to_c(@summary.runtime.powerState) - - if @state != VM_STATE[:active] - @used_cpu = 0 - @used_memory = 0 - - @netrx = 0 - @nettx = 0 - - @diskrdbytes = 0 - @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 - return - end - - @used_memory = @summary.quickStats.hostMemoryUsage * 1024 - cpuMhz = @vm.runtime.host.summary.hardware.cpuMhz.to_f - - @used_cpu = - ((@summary.quickStats.overallCpuUsage.to_f / cpuMhz) * 100).to_s - @used_cpu = sprintf('%.2f',@used_cpu).to_s - - # Check for negative values - @used_memory = 0 if @used_memory.to_i < 0 - @used_cpu = 0 if @used_cpu.to_i < 0 - - @esx_host = @vm.summary.runtime.host.name - @guest_ip = @vm.guest.ipAddress - @guest_state = @vm.guest.guestState - @vmware_tools = @vm.guest.toolsRunningStatus - @vmtools_ver = @vm.guest.toolsVersion - @vmtools_verst = @vm.guest.toolsVersionStatus - - guest_ip_addresses = [] - - @vm.guest.net.each do |net| - net.ipConfig.ipAddress.each do |ip| - guest_ip_addresses << ip.ipAddress - end if net.ipConfig && net.ipConfig.ipAddress - end if @vm.guest.net - - @guest_ip_addresses = guest_ip_addresses.join(',') - - # PerfManager metrics - pm = @client.vim.serviceInstance.content.perfManager - - provider = pm.provider_summary [@vm].first - refresh_rate = provider.refreshRate - - vmid = -1 - extraconfig_vmid = @vm.config.extraConfig.select{|val| - val[:key]=="opennebula.vm.id"} - if extraconfig_vmid.size > 0 and extraconfig_vmid[0] - vmid = extraconfig_vmid[0][:value].to_i - end - - if vmid < 0 - @nettx = 0 - @netrx = 0 - @diskrdbytes = 0 - @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 - else - one_vm = OpenNebula::VirtualMachine.new_with_id(vmid, OpenNebula::Client.new) - one_vm.info - stats = [] - - if(one_vm["MONITORING/LAST_MON"] && one_vm["MONITORING/LAST_MON"].to_i != 0 ) - #Real time data stores max 1 hour. 1 minute has 3 samples - interval = (Time.now.to_i - one_vm["MONITORING/LAST_MON"].to_i) - - #If last poll was more than hour ago get 3 minutes, - #else calculate how many samples since last poll - samples = interval > 3600 ? 9 : (interval / refresh_rate) + 1 - max_samples = samples > 0 ? samples : 1 - - stats = pm.retrieve_stats( - [@vm], - ['net.transmitted','net.bytesRx','net.bytesTx','net.received', - 'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged', - 'virtualDisk.read','virtualDisk.write'], - {interval:refresh_rate, max_samples: max_samples} - ) - else - # First poll, get at least latest 3 minutes = 9 samples - stats = pm.retrieve_stats( - [@vm], - ['net.transmitted','net.bytesRx','net.bytesTx','net.received', - 'virtualDisk.numberReadAveraged','virtualDisk.numberWriteAveraged', - 'virtualDisk.read','virtualDisk.write'], - {interval:refresh_rate, max_samples: 9} - ) - end - - if stats.empty? || stats.first[1][:metrics].empty? - @nettx = 0 - @netrx = 0 - @diskrdbytes = 0 - @diskwrbytes = 0 - @diskrdiops = 0 - @diskwriops = 0 - else - metrics = stats.first[1][:metrics] - - nettx_kbpersec = 0 - if metrics['net.transmitted'] - metrics['net.transmitted'].each { |sample| - nettx_kbpersec += sample - } - end - - netrx_kbpersec = 0 - if metrics['net.bytesRx'] - metrics['net.bytesRx'].each { |sample| - netrx_kbpersec += sample - } - end - - read_kbpersec = 0 - if metrics['virtualDisk.read'] - metrics['virtualDisk.read'].each { |sample| - read_kbpersec += sample - } - end - - read_iops = 0 - if metrics['virtualDisk.numberReadAveraged'] - metrics['virtualDisk.numberReadAveraged'].each { |sample| - read_iops += sample - } - end - - write_kbpersec = 0 - if metrics['virtualDisk.write'] - metrics['virtualDisk.write'].each { |sample| - write_kbpersec += sample - } - end - - write_iops = 0 - if metrics['virtualDisk.numberWriteAveraged'] - metrics['virtualDisk.numberWriteAveraged'].each { |sample| - write_iops += sample - } - end - - @nettx = (nettx_kbpersec * 1024 * refresh_rate).to_i - @netrx = (netrx_kbpersec * 1024 * refresh_rate).to_i - - @diskrdiops = read_iops - @diskwriops = write_iops - @diskrdbytes = (read_kbpersec * 1024 * refresh_rate).to_i - @diskwrbytes = (write_kbpersec * 1024 * refresh_rate).to_i - - end - end - end - - ######################################################################## - # Generates a OpenNebula IM Driver valid string with the monitor info - ######################################################################## - def info - return 'STATE=d' if @state == 'd' - - str_info = "" - - str_info << "GUEST_IP=" << @guest_ip.to_s << " " if @guest_ip - if @guest_ip_addresses && !@guest_ip_addresses.empty? - str_info << "GUEST_IP_ADDRESSES=\\\"" << - @guest_ip_addresses.to_s << "\\\" " - end - str_info << "LAST_MON=" << Time.now.to_i.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:state]}=" << @state << " " - str_info << "#{POLL_ATTRIBUTE[:cpu]}=" << @used_cpu.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:memory]}=" << @used_memory.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:netrx]}=" << @netrx.to_s << " " - str_info << "#{POLL_ATTRIBUTE[:nettx]}=" << @nettx.to_s << " " - str_info << "DISKRDBYTES=" << @diskrdbytes.to_s << " " - str_info << "DISKWRBYTES=" << @diskwrbytes.to_s << " " - str_info << "DISKRDIOPS=" << @diskrdiops.to_s << " " - str_info << "DISKWRIOPS=" << @diskwriops.to_s << " " - str_info << "ESX_HOST=\\\"" << @esx_host.to_s << "\\\" " - str_info << "GUEST_STATE=" << @guest_state.to_s << " " - str_info << "VMWARETOOLS_RUNNING_STATUS=" << @vmware_tools.to_s << " " - str_info << "VMWARETOOLS_VERSION=" << @vmtools_ver.to_s << " " - str_info << "VMWARETOOLS_VERSION_STATUS=" << @vmtools_verst.to_s << " " - str_info << "RESOURCE_POOL=\\\"" << @vm.resourcePool.name << "\\\" " - end - - ######################################################################## - # Generates an OpenNebula Template for this VCenterVm - ######################################################################## - def to_one(host) - cluster_name = host.cluster_name - - str = "NAME = \"#{@vm.name} - #{cluster_name}\"\n"\ - "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ - "HYPERVISOR = \"vcenter\"\n"\ - "PUBLIC_CLOUD = [\n"\ - " TYPE =\"vcenter\",\n"\ - " VM_TEMPLATE =\"#{@vm.config.uuid}\",\n"\ - " VCENTER_REF =\"#{@vm.ref}\",\n"\ - " VCENTER_NAME=\"#{@vm.name}\",\n"\ - " HOST =\"#{cluster_name}\"\n"\ - "]\n"\ - "GRAPHICS = [\n"\ - " TYPE =\"vnc\",\n"\ - " LISTEN =\"0.0.0.0\"\n"\ - "]\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{cluster_name}\\\"\"\n"\ - "CONTEXT = ["\ - " NETWORK = \"YES\","\ - " SSH_PUBLIC_KEY = \"$USER[SSH_PUBLIC_KEY]\" ]" - - if @vm.config.annotation.nil? || @vm.config.annotation.empty? - str << "DESCRIPTION = \"vCenter Template imported by OpenNebula"\ - " from Cluster #{@vm.runtime.host.parent.name}\"\n" - else - notes = @vm.config.annotation.gsub("\\", "\\\\").gsub("\"", "\\\"") - str << "DESCRIPTION = \"#{notes}\"\n" - end - - case @vm.guest.guestFullName - when /CentOS/i - str << "LOGO=images/logos/centos.png" - when /Debian/i - str << "LOGO=images/logos/debian.png" - when /Red Hat/i - str << "LOGO=images/logos/redhat.png" - when /Ubuntu/i - str << "LOGO=images/logos/ubuntu.png" - when /Windows XP/i - str << "LOGO=images/logos/windowsxp.png" - when /Windows/i - str << "LOGO=images/logos/windows8.png" - when /Linux/i - str << "LOGO=images/logos/linux.png" - end - return str - end - - ######################################################################## - # Generates a Datastore user input - ######################################################################## - def to_one_ds(host, default_ds) - # Datastores User Input - str = "" - - if host.ds_list != "" - str = "M|list|Which datastore you want this VM to run on?|"\ - << "#{host.ds_list}|#{default_ds}" - end - - return str - end - - ######################################################################## - # Generates a Resource Pool user input - ######################################################################## - def to_one_rp(host) - # Resource Pool User Input - str = "" - - if host.rp_list != "" - str = "M|list|Which resource pool you want this VM to run"\ - " in?|#{host.rp_list}|#{host.rp_list.split(",")[0]}" - end - - return str - end - - ######################################################################## - # Generates an OpenNebula VirtualMachine for this VCenterVm - # - # - ######################################################################## - def vm_to_one(host) - cluster_name = host.cluster_name - - state = case state_to_c(@summary.runtime.powerState) - when 'a' - "RUNNING" - when 'd' - "POWEROFF" - end - - str = "NAME = \"#{@vm.name} - #{cluster_name}\"\n"\ - "CPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "vCPU = \"#{@vm.config.hardware.numCPU}\"\n"\ - "MEMORY = \"#{@vm.config.hardware.memoryMB}\"\n"\ - "HYPERVISOR = \"vcenter\"\n"\ - "PUBLIC_CLOUD = [\n"\ - " TYPE =\"vcenter\",\n"\ - " VM_TEMPLATE =\"#{@vm.config.uuid}\",\n"\ - " HOST =\"#{cluster_name}\"\n"\ - "]\n"\ - "IMPORT_VM_ID = \"#{@vm.config.uuid}\"\n"\ - "IMPORT_STATE = \"#{state}\"\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{cluster_name}\\\"\"\n" - - vp = @vm.config.extraConfig.select{|v| - v[:key].downcase=="remotedisplay.vnc.port"} - keymap = @vm.config.extraConfig.select{|v| - v[:key].downcase=="remotedisplay.vnc.keymap"} - - if vp.size > 0 - str << "GRAPHICS = [\n"\ - " TYPE =\"vnc\",\n"\ - " LISTEN =\"0.0.0.0\",\n"\ - " PORT =\"#{vp[0][:value]}\"\n" - str << " ,KEYMAP =\"#{keymap[0][:value]}\"\n" if keymap[0] - str << "]\n" - end - - if @vm.config.annotation.nil? || @vm.config.annotation.empty? - str << "DESCRIPTION = \"vCenter Virtual Machine imported by"\ - " OpenNebula from Cluster #{cluster_name}\"\n" - else - notes = @vm.config.annotation.gsub("\\", "\\\\").gsub("\"", "\\\"") - str << "DESCRIPTION = \"#{notes}\"\n" - end - - case @vm.guest.guestFullName - when /CentOS/i - str << "LOGO=images/logos/centos.png" - when /Debian/i - str << "LOGO=images/logos/debian.png" - when /Red Hat/i - str << "LOGO=images/logos/redhat.png" - when /Ubuntu/i - str << "LOGO=images/logos/ubuntu.png" - when /Windows XP/i - str << "LOGO=images/logos/windowsxp.png" - when /Windows/i - str << "LOGO=images/logos/windows8.png" - when /Linux/i - str << "LOGO=images/logos/linux.png" - end - - return str - end - -private - - ######################################################################## - # Converts the VI string state to OpenNebula state convention - # Guest states are: - # - poweredOff The virtual machine is currently powered off. - # - poweredOn The virtual machine is currently powered on. - # - suspended The virtual machine is currently suspended. - ######################################################################## - def state_to_c(state) - case state - when 'poweredOn' - VM_STATE[:active] - when 'suspended' - VM_STATE[:paused] - when 'poweredOff' - VM_STATE[:deleted] - else - VM_STATE[:unknown] - end - end - - ######################################################################## - # Checks if a RbVmomi::VIM::VirtualDevice is a network interface - ######################################################################## - def self.is_nic?(device) - !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? - end - - ######################################################################## - # Checks if a RbVmomi::VIM::VirtualDevice is a disk - ######################################################################## - def self.is_disk?(device) - is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? - is_cdrom = !(device.class.ancestors.index(RbVmomi::VIM::VirtualCdrom)).nil? - is_disk or is_cdrom - end - - ######################################################################## - # Returns the spec to reconfig a VM and add a NIC - ######################################################################## - def self.calculate_addnic_spec(vm, mac, bridge, model, limit=nil, rsrv=nil) - model = model.nil? ? nil : model.downcase - network = vm.runtime.host.network.select{|n| n.name==bridge} - backing = nil - - if network.empty? - raise "Network #{bridge} not found in host #{vm.runtime.host.name}" - else - network = network[0] - end - - card_num = 1 # start in one, we want the next avaliable id - - vm.config.hardware.device.each{ |dv| - card_num = card_num + 1 if is_nic?(dv) - } - - nic_card = case model - when "virtuale1000", "e1000" - RbVmomi::VIM::VirtualE1000 - when "virtuale1000e", "e1000e" - RbVmomi::VIM::VirtualE1000e - when "virtualpcnet32", "pcnet32" - RbVmomi::VIM::VirtualPCNet32 - when "virtualsriovethernetcard", "sriovethernetcard" - RbVmomi::VIM::VirtualSriovEthernetCard - when "virtualvmxnetm", "vmxnetm" - RbVmomi::VIM::VirtualVmxnetm - when "virtualvmxnet2", "vmnet2" - RbVmomi::VIM::VirtualVmxnet2 - when "virtualvmxnet3", "vmxnet3" - RbVmomi::VIM::VirtualVmxnet3 - else # If none matches, use VirtualE1000 - RbVmomi::VIM::VirtualE1000 - end - - if network.class == RbVmomi::VIM::Network - backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( - :deviceName => bridge, - :network => network) - else - port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( - :switchUuid => - network.config.distributedVirtualSwitch.uuid, - :portgroupKey => network.key) - backing = - RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( - :port => port) - end - - card_spec = { - :key => 0, - :deviceInfo => { - :label => "net" + card_num.to_s, - :summary => bridge - }, - :backing => backing, - :addressType => mac ? 'manual' : 'generated', - :macAddress => mac - } - - if (limit or rsrv) and (limit > 0) - ra_spec = Hash.new - rsrv = limit if rsrv > limit - ra_spec[:limit] = limit if limit - ra_spec[:reservation] = rsrv if rsrv - ra_spec[:share] = RbVmomi::VIM.SharesInfo({ - :level => RbVmomi::VIM.SharesLevel("normal"), - :shares => 0 - }) - card_spec[:resourceAllocation] = - RbVmomi::VIM.VirtualEthernetCardResourceAllocation(ra_spec) - end - - return { - :operation => :add, - :device => nic_card.new(card_spec) - } - end - - ######################################################################## - # Clone a vCenter VM Template and leaves it powered on - ######################################################################## - def self.clone_vm(xml_text, hostname, datastore, ops = {}) - - host_id = VCenterDriver::VIClient.translate_hostname(hostname) - - # Retrieve hostname - - host = OpenNebula::Host.new_with_id(host_id, OpenNebula::Client.new()) - host.info # Not failing if host retrieval fails - - # Get VM prefix name - - if host["/HOST/TEMPLATE/VM_PREFIX"] and !host["/HOST/TEMPLATE/VM_PREFIX"].empty? - vmname_prefix = host["/HOST/TEMPLATE/VM_PREFIX"] - else # fall back to default value - vmname_prefix = "one-$i-" - end - - xml = REXML::Document.new xml_text - pcs = xml.root.get_elements("/VM/USER_TEMPLATE/PUBLIC_CLOUD") - - raise "Cannot find VCenter element in VM template." if pcs.nil? - - template = pcs.select { |t| - type = t.elements["TYPE"] - !type.nil? && type.text.downcase == "vcenter" - } - - # If there are multiple vCenter templates, find the right one - - if template.is_a? Array - all_vcenter_templates = template.clone - # If there is more than one coincidence, pick the first one - template = template.select {|t| - cluster_name = t.elements["HOST"] - !cluster_name.nil? && cluster_name.text == hostname - }[0] - # The template may not reference any specific CLUSTER - # (referenced to as HOST in the OpenNebula template) - # Therefore, here take the first one that does not - # specify a CLUSTER to see if we are lucky - if template.nil? - template = all_vcenter_templates.select {|t| - t.elements["HOST"].nil? - }[0] - end - end - - raise "Cannot find vCenter element in VM template." if template.nil? - - uuid = template.elements["VM_TEMPLATE"] - - raise "Cannot find VM_TEMPLATE in vCenter element." if uuid.nil? - - uuid = uuid.text - vmid = xml.root.elements["/VM/ID"].text - vmname_prefix.gsub!("$i", vmid) - vcenter_name = "#{vmname_prefix}#{xml.root.elements["/VM/NAME"].text}" - hid = xml.root.elements["/VM/HISTORY_RECORDS/HISTORY/HID"] - - raise "Cannot find host id in deployment file history." if hid.nil? - - connection = VIClient.new(hid) - vc_template = connection.find_vm_fast(uuid, ops[:ref], ops[:name]) - - # Find out requested and available resource pool - - req_rp = nil - if !xml.root.elements["/VM/USER_TEMPLATE/RESOURCE_POOL"].nil? - req_rp = xml.root.elements["/VM/USER_TEMPLATE/RESOURCE_POOL"].text - end - - if connection.rp_confined? - rp = connection.resource_pool.first - if req_rp && rp.name != req_rp - raise "Available resource pool in host [#{rp.name}]"\ - " does not match requested resource pool"\ - " [#{req_rp}]" - end - else - if req_rp # if there is requested resource pool, retrieve it - rp = connection.find_resource_pool(req_rp) - raise "Cannot find resource pool "\ - "#{template.elements["RESOURCE_POOL"].text}" if !rp - else # otherwise, get the default resource pool - rp = connection.default_resource_pool - end - end - - # Find out requested and available datastore - - if !xml.root.elements["/VM/USER_TEMPLATE/VCENTER_DATASTORE"].nil? - datastore = xml.root.elements["/VM/USER_TEMPLATE/VCENTER_DATASTORE"].text - end - - if datastore - datastores = VIClient.get_entities(connection.dc.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(connection.dc.datastoreFolder, - 'StoragePod') - - storpod = storage_pods.select{|sp| sp.name == datastore} - - storage_pods.each { |sp| - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == datastore}[0] - - raise "Cannot find datastore #{datastore}" if !ds && !storpod - - end - - relocate_spec_params = { - :pool => rp - } - - relocate_spec_params[:datastore] = ds if datastore - - relocate_spec_params[:diskMoveType] = :moveChildMostDiskBacking if ds - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - relocate_spec_params) - - # This running flag will prevent spurious poweroff states in the VM - - running_flag = [{:key=>"opennebula.vm.running",:value=>"no"}] - - running_flag_spec = RbVmomi::VIM.VirtualMachineConfigSpec( - {:extraConfig =>running_flag}) - - clone_parameters = { - :location => relocate_spec, - :powerOn => false, - :template => false, - :config => running_flag_spec - } - - customization = template.elements["CUSTOMIZATION_SPEC"] - - vim = connection.vim - - if !customization.nil? - begin - custom_spec = vim.serviceContent.customizationSpecManager. - GetCustomizationSpec(:name => customization.text) - - if custom_spec && spec=custom_spec.spec - clone_parameters[:customization] = spec - else - raise "Error getting customization spec" - end - - rescue - raise "Customization spec '#{customization.text}' not found" - end - end - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(clone_parameters) - - if storpod && !storpod.empty? && storpod[0].is_a?(RbVmomi::VIM::StoragePod) - - storage_manager = vim.serviceContent.storageResourceManager - - pod_spec = RbVmomi::VIM.StorageDrsPodSelectionSpec(storagePod: storpod[0]) - - storage_spec = RbVmomi::VIM.StoragePlacementSpec( - type: 'clone', - cloneName: vcenter_name, - folder: vc_template.parent, - podSelectionSpec: pod_spec, - vm: vc_template, - cloneSpec: clone_spec - ) - - result = storage_manager.RecommendDatastores(storageSpec: storage_spec) - - recommendation = result.recommendations[0] - - key = recommendation.key ||= '' - - if key == '' - raise "Missing Datastore recommendation for StoragePod (Storage DRS)" - end - - begin - apply_sr = storage_manager.ApplyStorageDrsRecommendation_Task(key: [key]).wait_for_completion - vm = apply_sr.vm - rescue Exception => e - raise "Cannot clone VM Template to StoragePod: #{e.message}" - end - else - - begin - vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => vcenter_name, - :spec => clone_spec).wait_for_completion - rescue Exception => e - - if !e.message.start_with?('DuplicateName') - raise "Cannot clone VM Template: #{e.message}" - end - - vm = connection.find_vm(vcenter_name) - - raise "Cannot clone VM Template" if vm.nil? - - vm.Destroy_Task.wait_for_completion - vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => vcenter_name, - :spec => clone_spec).wait_for_completion - end - - end - - reconfigure_vm(vm, xml, true, hostname) - - # Power on the VM - vm.PowerOnVM_Task.wait_for_completion - - # Set to yes the running flag - - config_array = [{:key=>"opennebula.vm.running",:value=>"yes"}] - spec = RbVmomi::VIM.VirtualMachineConfigSpec( - {:extraConfig =>config_array}) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - - return vm.config.uuid - end - - ######################################################################## - # Reconfigures a VM with new deployment description - ######################################################################## - def self.reconfigure_vm(vm, xml, newvm, hostname) - vm_uuid = vm.config.uuid - vmid = xml.root.elements["/VM/ID"].text - context = xml.root.elements["/VM/TEMPLATE/CONTEXT"] - - token = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.token" - end - - if token && !token.empty? - token = token.first[:value] - else - token = nil - end - - # Add VMID to VM's extraConfig - - config_array = [{:key=>"opennebula.vm.id",:value=>vmid}] - - # VNC Section - - vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] - vnc_listen = xml.root.elements["/VM/TEMPLATE/GRAPHICS/LISTEN"] - vnc_keymap = xml.root.elements["/VM/TEMPLATE/GRAPHICS/KEYMAP"] - - if !vnc_listen - vnc_listen = "0.0.0.0" - else - vnc_listen = vnc_listen.text - end - - context_vnc_spec = {} - - if vnc_port - config_array += - [{:key=>"remotedisplay.vnc.enabled",:value=>"TRUE"}, - {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}, - {:key=>"remotedisplay.vnc.ip", :value=>vnc_listen}] - end - - config_array += [{:key=>"remotedisplay.vnc.keymap", - :value=>vnc_keymap.text}] if vnc_keymap - - # Context section - - if context - context_text = create_context(context) - - # OneGate - onegate_token_flag = xml.root.elements["/VM/TEMPLATE/CONTEXT/TOKEN"] - - if onegate_token_flag and onegate_token_flag.text == "YES" - if token - onegate_token_64 = token - else - # Create the OneGate token string - vmid_str = xml.root.elements["/VM/ID"].text - stime_str = xml.root.elements["/VM/STIME"].text - str_to_encrypt = "#{vmid_str}:#{stime_str}" - - user_id = xml.root.elements['//CREATED_BY'].text - - if user_id.nil? - STDERR.puts {"VMID:#{vmid} CREATED_BY not present" \ - " in the VM TEMPLATE"} - return nil - end - - user = OpenNebula::User.new_with_id(user_id, - OpenNebula::Client.new) - rc = user.info - - if OpenNebula.is_error?(rc) - STDERR.puts {"VMID:#{vmid} user.info" \ - " error: #{rc.message}"} - return nil - end - - token_password = user['TEMPLATE/TOKEN_PASSWORD'] - - if token_password.nil? - STDERR.puts {"VMID:#{vmid} TOKEN_PASSWORD not present"\ - " in the USER:#{user_id} TEMPLATE"} - return nil - end - - cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") - cipher.encrypt - cipher.key = token_password - onegate_token = cipher.update(str_to_encrypt) - onegate_token << cipher.final - - onegate_token_64 = Base64.encode64(onegate_token).chop - config_array << { - :key => 'opennebula.token', - :value => onegate_token_64 - } - end - - context_text += "ONEGATE_TOKEN='#{onegate_token_64}'\n" - end - - context_text = Base64.encode64(context_text.chop) - - config_array += - [{:key=>"guestinfo.opennebula.context", - :value=>context_text}] - end - - device_change = [] - - # NIC section, build the reconfig hash - - nics = xml.root.get_elements("/VM/TEMPLATE/NIC") - - # If the VM is not new, avoid readding NiCs - if !newvm - nic_array = [] - - # Get MACs from NICs inside VM template - one_mac_addresses = Array.new - nics.each{|nic| - one_mac_addresses << nic.elements["MAC"].text - } - - # B4897 - Get mac of NICs that were hot-plugged from vCenter extraConfig - hotplugged_nics = [] - extraconfig_nics = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.hotplugged_nics" - end - - if extraconfig_nics && !extraconfig_nics.empty? - hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") - end - - vm.config.hardware.device.each{ |dv| - if is_nic?(dv) - nics.each{|nic| - if nic.elements["MAC"].text == dv.macAddress - nics.delete(nic) - end - } - - # B4897 - Remove detached NICs from vCenter that were unplugged in POWEROFF - if !one_mac_addresses.include?(dv.macAddress) && hotplugged_nics.include?(dv.macAddress) - nic_array << { :operation => :remove, :device => dv} - hotplugged_nics.delete(dv.macAddress) - config_array << { - :key => 'opennebula.hotplugged_nics', - :value => hotplugged_nics.join(";") - } - end - end - } - - device_change += nic_array - end - - if !nics.nil? - nic_array = [] - nics.each{|nic| - mac = nic.elements["MAC"].text - bridge = nic.elements["BRIDGE"].text - model = nic.elements["MODEL"] ? nic.elements["MODEL"].text : nil - limit_in = nic.elements["INBOUND_PEAK_BW"] ? nic.elements["INBOUND_PEAK_BW"].text : "" - limit_out = nic.elements["OUTBOUND_PEAK_BW"] ? nic.elements["OUTBOUND_PEAK_BW"].text : "" - limit = nil - if !limit_in.empty? or !limit_out.empty? - limit=([limit_in.to_i, limit_out.to_i].min / 1024) * 8 - end - rsrv_in = nic.elements["INBOUND_AVG_BW"] ? nic.elements["INBOUND_AVG_BW"].text : "" - rsrv_out = nic.elements["OUTBOUND_AVG_BW"] ? nic.elements["OUTBOUND_AVG_BW"].text : "" - rsrv = nil - if !rsrv_in.empty? or !rsrv_out.empty? - rsrv=([rsrv_in.to_i, rsrv_out.to_i].min / 1024) * 8 - end - nic_array << calculate_addnic_spec(vm, - mac, - bridge, - model, - limit, - rsrv) - } - - device_change += nic_array - end - - # DISK section, build the reconfig hash - - disks = xml.root.get_elements("/VM/TEMPLATE/DISK") - disk_spec = {} - - # If the VM is not new, avoid reading DISKS - if !newvm - vm.config.hardware.device.select { |d| - if is_disk?(d) - disks.each{|disk| - if d.backing.respond_to?(:fileName) && - disk.elements["SOURCE"].text == d.backing.fileName && - disks.delete(disk) - end - } - end - } - end - - if !disks.nil? - disk_array = [] - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - position = 0 - disks.each{|disk| - ds_name = disk.elements["VCENTER_NAME"].text - img_name = get_disk_img_path(disk, vmid) - type_str = disk.elements["TYPE"].text - - disk_array += attach_disk("", "", ds_name, img_name, type_str, 0, vm, connection, position)[:deviceChange] - position += 1 - } - - device_change += disk_array - end - - # Capacity section - - cpu = xml.root.elements["/VM/TEMPLATE/VCPU"] ? xml.root.elements["/VM/TEMPLATE/VCPU"].text : 1 - memory = xml.root.elements["/VM/TEMPLATE/MEMORY"].text - capacity_spec = {:numCPUs => cpu.to_i, - :memoryMB => memory } - - # Perform the VM reconfiguration - if config_array != [] - context_vnc_spec = {:extraConfig =>config_array} - end - - spec_hash = context_vnc_spec.merge(capacity_spec) - if device_change.length > 0 - spec_hash.merge!({ :deviceChange => device_change }) - end - - spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - ############################################################################ - # Attach disk to a VM - # @params hostname[String] vcenter cluster name in opennebula as host - # @params deploy_id[String] deploy id of the vm - # @params ds_name[String] name of the datastore - # @params img_name[String] path of the image - # @params size_kb[String] size in kb of the disk - # @params vm[RbVmomi::VIM::VirtualMachine] VM if called from instance - # @params connection[ViClient::connectoon] connection if called from instance - # @params position The number of disks to attach. Starts with 0. - ############################################################################ - def self.attach_disk(hostname, deploy_id, ds_name, img_name, type, size_kb, vm=nil, connection=nil, position=0) - only_return = true - if !vm - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - only_return = false - end - - # Find datastore within datacenter - datastores = VIClient.get_entities(connection.dc.datastoreFolder, - 'Datastore') - - storage_pods = VIClient.get_entities(connection.dc.datastoreFolder, - 'StoragePod') - storage_pods.each { |sp| - storage_pod_datastores = VIClient.get_entities(sp, 'Datastore') - if not storage_pod_datastores.empty? - datastores.concat(storage_pod_datastores) - end - } - - ds = datastores.select{|ds| ds.name == ds_name}[0] - - controller, new_number = find_free_controller(vm, position) - - if type == "CDROM" - vmdk_backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo( - :datastore => ds, - :fileName => "[#{ds_name}] #{img_name}" - ) - - cd = vm.config.hardware.device.select {|hw| - hw.class == RbVmomi::VIM::VirtualCdrom}.first - - # If no CDROM drive present, we need to add it - if !cd - controller, new_unit_number = find_free_controller(vm) - cdrom_drive_spec = RbVmomi::VIM.VirtualMachineConfigSpec( - :deviceChange => [{ - :operation => :add, - :device => RbVmomi::VIM::VirtualCdrom( - :backing => vmdk_backing, - :key => -1, - :controllerKey => 15000, - :unitNumber => 0, - :connectable => RbVmomi::VIM::VirtualDeviceConnectInfo( - :startConnected => true, - :connected => true, - :allowGuestControl => true - ) - )}] - ) - - vm.ReconfigVM_Task(:spec => - cdrom_drive_spec).wait_for_completion - - return - else - device = RbVmomi::VIM::VirtualCdrom( - backing: vmdk_backing, - key: cd.key, - controllerKey: cd.controllerKey, - connectable: RbVmomi::VIM::VirtualDeviceConnectInfo( - startConnected: true, - connected: true, - allowGuestControl: true - ) - ) - device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( - :device => device, - :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('edit') - ) - end - else - vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo( - :datastore => ds, - :diskMode => 'persistent', - :fileName => "[#{ds_name}] #{img_name}" - ) - - device = RbVmomi::VIM::VirtualDisk( - :backing => vmdk_backing, - :capacityInKB => size_kb, - :controllerKey => controller.key, - :key => -1, - :unitNumber => new_number - ) - - device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( - :device => device, - :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') - ) - end - - vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( - :deviceChange => [device_config_spec] - ) - - return vm_config_spec if only_return - - vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion - end - - def self.find_free_controller(vm, position=0) - free_scsi_controllers = Array.new - available_controller = nil - scsi_schema = Hash.new - - used_numbers = Array.new - available_numbers = Array.new - - vm.config.hardware.device.each{ |dev| - if dev.is_a? RbVmomi::VIM::VirtualSCSIController - if scsi_schema[dev.controllerKey].nil? - scsi_schema[dev.key] = Hash.new - scsi_schema[dev.key][:lower] = Array.new - end - used_numbers << dev.scsiCtlrUnitNumber - scsi_schema[dev.key][:device] = dev - end - - next if dev.class != RbVmomi::VIM::VirtualDisk - used_numbers << dev.unitNumber - } - - 15.times{ |scsi_id| - available_numbers << scsi_id if used_numbers.grep(scsi_id).length <= 0 - } - - scsi_schema.keys.each{|controller| - if scsi_schema[controller][:lower].length < 15 - free_scsi_controllers << scsi_schema[controller][:device].deviceInfo.label - end - } - - if free_scsi_controllers.length > 0 - available_controller_label = free_scsi_controllers[0] - else - add_new_scsi(vm, scsi_schema) - return find_free_controller(vm) - end - - controller = nil - - vm.config.hardware.device.each { |device| - (controller = device ; break) if device.deviceInfo.label == available_controller_label - } - - new_unit_number = available_numbers.sort[position] - - return controller, new_unit_number - end - - def self.add_new_scsi(vm, scsi_schema) - controller = nil - - if scsi_schema.keys.length >= 4 - raise "Cannot add a new controller, maximum is 4." - end - - if scsi_schema.keys.length == 0 - scsi_key = 0 - scsi_number = 0 - else scsi_schema.keys.length < 4 - scsi_key = scsi_schema.keys.sort[-1] + 1 - scsi_number = scsi_schema[scsi_schema.keys.sort[-1]][:device].busNumber + 1 - end - - controller_device = RbVmomi::VIM::VirtualLsiLogicController( - :key => scsi_key, - :busNumber => scsi_number, - :sharedBus => :noSharing - ) - - device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec( - :device => controller_device, - :operation => RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add') - ) - - vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec( - :deviceChange => [device_config_spec] - ) - - vm.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion - - vm.config.hardware.device.each { |device| - if device.class == RbVmomi::VIM::VirtualLsiLogicController && - device.key == scsi_key - controller = device.deviceInfo.label - end - } - - return controller - end - - ############################################################################ - # Detach a specific disk from a VM - # @params hostname[String] vcenter cluster name in opennebula as host - # @params deploy_id[String] deploy id of the vm - # @params ds_name[String] name of the datastore - # @params img_path[String] path of the image - ############################################################################ - def self.detach_disk(hostname, deploy_id, ds_name, img_path) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vm = connection.find_vm_template(deploy_id) - - ds_and_img_name = "[#{ds_name}] #{img_path}" - - disk = vm.config.hardware.device.select { |d| is_disk?(d) && - d.backing.respond_to?(:fileName) && - d.backing.fileName == ds_and_img_name } - - raise "Disk #{img_path} not found." if disk.nil? - - spec = { :deviceChange => [{ - :operation => :remove, - :device => disk[0] - }]} - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - ############################################################################ - # Detach all disks from a VM - # @params vm[VCenterVm] vCenter VM - ############################################################################ - def self.detach_all_disks(vm) - disks = vm.config.hardware.device.select { |d| is_disk?(d) } - - return if disks.nil? - - spec = { :deviceChange => [] } - - disks.each{|disk| - spec[:deviceChange] << { - :operation => :remove, - :device => disk - } - } - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - def self.create_context(context) - # Remove (9) and \n (11) - context_text = "# Context variables generated by OpenNebula\n" - context.elements.each{|context_element| - next if !context_element.text - context_text += context_element.name + "='" + - context_element.text.gsub("'", "\\'") + "'\n" - } - context_text - end - - ############################################################################ - # Detach attached disks from a VM - ############################################################################ - def self.detach_attached_disks(vm, disks, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) - - vmid = vm.config.extraConfig.select do |val| - val[:key] == "opennebula.vm.id" - end.first.value - - spec = { :deviceChange => [] } - - disks.each{ |disk| - img_name = get_disk_img_path(disk, vmid) - ds_and_img_name = "[#{disk['VCENTER_NAME']}] #{img_name}" - - vcenter_disk = vm.config.hardware.device.select { |d| is_disk?(d) && - d.backing.respond_to?(:fileName) && - d.backing.fileName == ds_and_img_name }[0] - spec[:deviceChange] << { - :operation => :remove, - :device => vcenter_disk - } - } - - vm.ReconfigVM_Task(:spec => spec).wait_for_completion - end - - - ############################################################################ - # Returns the source path of a disk. It will use the 'SOURCE' path if - # persistent and one-#{vm_id}-#{disk_id}.vmdk otherwise - # @param disks VM attached disks, either an REXML document, or a hash - # @param vmid The VM ID - ############################################################################ - def self.get_disk_img_path(disk, vmid) - if disk.respond_to? :elements - # It's a REXML::Document, probably coming from self.reconfigure_vm - persistent = disk.elements["PERSISTENT"].text == "YES" rescue false - - if persistent - disk.elements["SOURCE"].text - else - disk_id = disk.elements["DISK_ID"].text - "one_#{vmid}_#{disk_id}.vmdk" - end - else - # It's a hash, probably coming from self.detach_attached_disks - persistent = disk["PERSISTENT"] == "YES" - - if persistent - disk["SOURCE"] - else - disk_id = disk["DISK_ID"] - "one_#{vmid}_#{disk_id}.vmdk" - end - end - end - -end -end From 3e2d663488804296b23de51d727cdbc95dc40355 Mon Sep 17 00:00:00 2001 From: Javi Fontan Date: Tue, 28 Feb 2017 16:58:49 +0100 Subject: [PATCH 110/297] B #5046: vCenter VMM poll returns escaped quotes --- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 2 +- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index 29129cb73c..d2a8f369cd 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -241,7 +241,7 @@ class ClusterComputeResource str_info << "IMPORT_TEMPLATE=\"#{vm_template_64}\"," end - str_info << "POLL=\"#{vm.info}\"]" + str_info << "POLL=\"#{vm.info.gsub('"', "\\\"")}\"]" rescue Exception => e STDERR.puts e.inspect STDERR.puts e.backtrace diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index f0a91b472b..f635e90048 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1438,7 +1438,7 @@ class VirtualMachine str_info = "GUEST_IP=" << guest_ip.to_s << " " if guest_ip if @guest_ip_addresses && !@guest_ip_addresses.empty? - str_info << "GUEST_IP_ADDRESSES=\\\"" << @guest_ip_addresses.to_s << "\\\" " + str_info << "GUEST_IP_ADDRESSES=\"" << @guest_ip_addresses.to_s << "\" " end str_info << "LAST_MON=" << Time.now.to_i.to_s << " " @@ -1454,12 +1454,12 @@ class VirtualMachine str_info << "DISKRDIOPS=" << diskrdiops.to_s << " " str_info << "DISKWRIOPS=" << diskwriops.to_s << " " - str_info << "ESX_HOST=\\\"" << esx_host << "\\\" " + str_info << "ESX_HOST=\"" << esx_host << "\" " str_info << "GUEST_STATE=" << guest_state << " " str_info << "VMWARETOOLS_RUNNING_STATUS=" << vmware_tools << " " str_info << "VMWARETOOLS_VERSION=" << vmtools_ver << " " str_info << "VMWARETOOLS_VERSION_STATUS=" << vmtools_verst << " " - str_info << "RESOURCE_POOL=\\\"" << self["resourcePool.name"] << "\\\" " + str_info << "RESOURCE_POOL=\"" << self["resourcePool.name"] << "\" " end def reset_monitor From b7aa558084a6d0ecce67844dcd609bb328a3d452 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 08:20:10 +0100 Subject: [PATCH 111/297] F #4913: Replace VCENTER_CLUSTER with VCENTER_ONE_HOST_ID --- src/datastore_mad/remotes/vcenter/clone | 2 +- src/datastore_mad/remotes/vcenter/cp | 2 +- src/datastore_mad/remotes/vcenter/export | 2 +- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/datastore_mad/remotes/vcenter/monitor | 2 +- src/datastore_mad/remotes/vcenter/rm | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index dd416e0d62..70b3af6663 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -36,7 +36,7 @@ drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') target_ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" src_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] src_img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/CLONING_ID"] diff --git a/src/datastore_mad/remotes/vcenter/cp b/src/datastore_mad/remotes/vcenter/cp index 1ba32394c4..13ff1c9688 100755 --- a/src/datastore_mad/remotes/vcenter/cp +++ b/src/datastore_mad/remotes/vcenter/cp @@ -38,7 +38,7 @@ drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" md5 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"] diff --git a/src/datastore_mad/remotes/vcenter/export b/src/datastore_mad/remotes/vcenter/export index aa4f8f46f3..ed8c1217ac 100755 --- a/src/datastore_mad/remotes/vcenter/export +++ b/src/datastore_mad/remotes/vcenter/export @@ -45,7 +45,7 @@ md5 = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/MD5"] md5 = md5.nil? ? "-" : md5 -hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +hostname = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_name = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/NAME"] diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index af63a095f1..b6c7f6244b 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -40,7 +40,7 @@ drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 0706c98596..6678cde1de 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -39,7 +39,7 @@ id = ARGV[1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] check_valid ds_ref, "ds_ref" diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 251b95ee69..8c75b1b279 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -40,7 +40,7 @@ drv_action =OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] check_valid ds_ref, "ds_ref" From 93528a8f8bd826468e9a88226c9430ba1a971644 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 08:20:48 +0100 Subject: [PATCH 112/297] F #4913: Fix datastore stat action --- src/datastore_mad/remotes/vcenter/stat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 0d7fb925e6..0320bb2984 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -40,7 +40,7 @@ drv_action =OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_CLUSTER"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] img_path = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/PATH"] check_valid ds_ref, "ds_ref" @@ -53,7 +53,7 @@ if img_path.start_with? "vcenter://" ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - ds.stat(img_path) + puts ds.stat(img_path.sub("vcenter://","")) rescue Exception => e STDERR.puts "Error calculating image #{img_path} size."\ From 347968ad3deec8b42303625b39197841c9f12326 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 08:26:01 +0100 Subject: [PATCH 113/297] F #4913: Migrate import tools --- install.sh | 1 + src/cli/onevcenter | 478 +-------------- .../remotes/lib/vcenter_driver/datacenter.rb | 273 +++++++++ .../remotes/lib/vcenter_driver/datastore.rb | 180 +++++- .../remotes/lib/vcenter_driver/host.rb | 83 ++- .../remotes/lib/vcenter_driver/importer.rb | 571 ++++++++++++++++++ .../remotes/lib/vcenter_driver/network.rb | 139 ++++- .../remotes/lib/vcenter_driver/vi_helper.rb | 23 +- .../lib/vcenter_driver/virtual_machine.rb | 96 ++- 9 files changed, 1337 insertions(+), 507 deletions(-) create mode 100644 src/vmm_mad/remotes/lib/vcenter_driver/importer.rb diff --git a/install.sh b/install.sh index 0e60f4acb7..6ce5048f08 100755 --- a/install.sh +++ b/install.sh @@ -651,6 +651,7 @@ VMM_EXEC_LIB_FILES="src/vmm_mad/remotes/lib/poll_common.rb" VMM_EXEC_LIB_VCENTER_FILES="src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb \ + src/vmm_mad/remotes/lib/vcenter_driver/importer.rb \ src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb \ src/vmm_mad/remotes/lib/vcenter_driver/host.rb \ src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb \ diff --git a/src/cli/onevcenter b/src/cli/onevcenter index 2b0f16f880..cfc4ff5c3d 100755 --- a/src/cli/onevcenter +++ b/src/cli/onevcenter @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # -------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -65,9 +65,9 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end - ######################################################################## + ############################################################################ # Global Options - ######################################################################## + ############################################################################ cmd_options=CommandParser::OPTIONS-[CommandParser::VERBOSE] set :option, cmd_options+OpenNebulaHelper::CLIENT_OPTIONS @@ -103,54 +103,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :hosts, hosts_desc, :options=>[ VCENTER, USER, PASS ] do con_ops = connection_options("Hosts", options) - begin - STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." - - vc = VCenterDriver::VIClient.new_connection(con_ops) - - STDOUT.print "done!\n\n" - - STDOUT.print "Exploring vCenter resources..." - - rs = vc.hierarchy - - STDOUT.print "done!\n\n" - - rs.each {|dc, cluster| - STDOUT.print "Do you want to process datacenter #{dc} [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - if cluster.empty? - STDOUT.puts " No new clusters found in #{dc}..." - next - end - - cluster.each{ |c| - STDOUT.print " * Import cluster #{c} [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - r, m = VCenterDriver::VCenterHost.to_one(c, vc) - - if r == 0 - STDOUT.puts " OpenNebula host #{c} with id #{m}"\ - " successfully created." - else - STDOUT.puts " Error: #{m}" - end - - STDOUT.puts - } - } - rescue Exception => e - STDOUT.puts "error: #{e.message}" - exit -1 - end + VCenterDriver::Importer.import_clusters(con_ops, options) exit 0 end + ############################################################################ + # Import templates + ############################################################################ templates_desc = <<-EOT.unindent Import vCenter VM Templates into OpenNebula EOT @@ -158,200 +118,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :templates, templates_desc, :options=>[ VCENTER, USER, PASS ] do con_ops = connection_options("VM Templates", options) - begin - STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." - - vc = VCenterDriver::VIClient.new_connection(con_ops) - - STDOUT.print "done!\n\n" - - STDOUT.print "Looking for VM Templates..." - - rs = vc.vm_templates - - STDOUT.print "done!\n" - - rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - if tmps.empty? - STDOUT.print " No new VM Templates found in #{dc}...\n\n" - next - end - - tmps.each{ |t| - STDOUT.print "\n * VM Template found:\n"\ - " - Name : #{t[:name]}\n"\ - " - UUID : #{t[:uuid]}\n"\ - " - Cluster: #{t[:host]}\n"\ - " Import this VM template [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - ds_input = "" - rp_input = "" - - # Datastores - - STDOUT.print "\n This template is currently set to be "\ - "deployed in datastore #{t[:default_ds]}."\ - "\n Press y to keep the default, n to select"\ - " a new datastore or d to delegate the choice"\ - " to the user [y/n/d]? " - - answer = STDIN.gets.strip.downcase - - case answer - when 'd' - ds_split = t[:ds].split("|") - list_of_ds = ds_split[-2] - default_ds = ds_split[-1] - ds_input = ds_split[0] + "|" + ds_split[1] + "|" + - ds_split[2] + "|" - - # Available list of datastores - - input_str = " The list of available datastores to be"\ - " presented to the user are \"#{list_of_ds}\"" - input_str+= "\n Press y to agree, or input a comma"\ - " separated list of datastores to edit "\ - "[y/comma separated list] " - STDOUT.print input_str - - answer = STDIN.gets.strip - - if answer.downcase == 'y' - ds_input += ds_split[3] + "|" - else - ds_input += answer + "|" - end - - # Default - input_str = " The default datastore presented to "\ - "the end user is set to \"#{default_ds}\"." - input_str+= "\n Press y to agree, or input a new "\ - "datastore [y/datastore name] " - STDOUT.print input_str - - answer = STDIN.gets.strip - - if answer.downcase == 'y' - ds_input += ds_split[4] - else - ds_input += answer - end - when 'n' - ds_split = t[:ds].split("|") - list_of_ds = ds_split[-2] - - input_str = " The list of available datastores is"\ - " \"#{list_of_ds}\"." - input_str+= "\n Please input the new default datastore: " - STDOUT.print input_str - - answer = STDIN.gets.strip - - t[:one] += "VCENTER_DATASTORE=\"#{answer}\"\n" - end - - # Resource Pools - - rp_split = t[:rp].split("|") - - if rp_split.size > 3 - STDOUT.print "\n This template is currently set to "\ - "launch VMs in the default resource pool."\ - "\n Press y to keep this behaviour, n to select"\ - " a new resource pool or d to delegate the choice"\ - " to the user [y/n/d]? " - - answer = STDIN.gets.strip.downcase - - case answer - when 'd' - list_of_rp = rp_split[-2] - default_rp = rp_split[-1] - rp_input = rp_split[0] + "|" + rp_split[1] + "|" + - rp_split[2] + "|" - - # Available list of resource pools - - input_str = " The list of available resource pools "\ - "to be presented to the user are "\ - "\"#{list_of_rp}\"" - input_str+= "\n Press y to agree, or input a comma"\ - " separated list of resource pools to edit "\ - "[y/comma separated list] " - STDOUT.print input_str - - answer = STDIN.gets.strip - - if answer.downcase == 'y' - rp_input += rp_split[3] + "|" - else - rp_input += answer + "|" - end - - # Default - input_str = " The default resource pool presented "\ - "to the end user is set to"\ - " \"#{default_rp}\"." - input_str+= "\n Press y to agree, or input a new "\ - "resource pool [y/resource pool name] " - STDOUT.print input_str - - answer = STDIN.gets.strip - - if answer.downcase == 'y' - rp_input += rp_split[4] - else - rp_input += answer - end - when 'n' - list_of_rp = rp_split[-2] - - input_str = " The list of available resource pools is"\ - " \"#{list_of_rp}\"." - input_str+= "\n Please input the new default resource pool: " - STDOUT.print input_str - - answer = STDIN.gets.strip - - t[:one] += "RESOURCE_POOL=\"#{answer}\"\n" - end - end - - if ds_input != "" || - rp_input != "" - t[:one] += "USER_INPUTS=[" - t[:one] += "VCENTER_DATASTORE=\"#{ds_input}\"," if ds_input != "" - t[:one] += "RESOURCE_POOL=\"#{rp_input}\"," if rp_input != "" - t[:one] = t[:one][0..-2] - t[:one] += "]" - end - - one_t = ::OpenNebula::Template.new( - ::OpenNebula::Template.build_xml, vc.one) - - rc = one_t.allocate(t[:one]) - - if ::OpenNebula.is_error?(rc) - STDOUT.puts " Error creating template: #{rc.message}\n" - else - STDOUT.puts " OpenNebula template #{one_t.id} created!\n" - end - } - } - rescue Exception => e - STDOUT.puts "error: #{e.message}" - exit -1 - end + VCenterDriver::Importer.import_templates(con_ops, options) exit 0 end + ############################################################################ + # Import vms (deprecated) + ############################################################################ vms_desc = <<-EOT.unindent Deprecated action in onevcenter, please use onehost importvm instead EOT @@ -359,10 +133,12 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :vms, vms_desc, :options=>[ VCENTER, USER, PASS ] do STDERR.puts "Deprecated action in onevcenter, please use onehost "\ "importvm instead" - exit -1 end + ############################################################################ + # Import networks + ############################################################################ network_desc = <<-EOT.unindent Import vCenter networks into OpenNebula EOT @@ -370,130 +146,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :networks, network_desc, :options=>[ VCENTER, USER, PASS ] do con_ops = connection_options("Networks", options) - begin - STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." - - vc = VCenterDriver::VIClient.new_connection(con_ops) - - STDOUT.print "done!\n\n" - - STDOUT.print "Looking for vCenter networks..." - - rs = vc.vcenter_networks - - STDOUT.print "done!\n" - - rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - if tmps.empty? - STDOUT.print " No new Networks found in #{dc}...\n\n" - next - end - - tmps.each{ |n| - print_str = "\n * Network found:\n"\ - " - Name : #{n[:name]}\n"\ - " - Type : #{n[:type]}\n" - print_str += " - VLAN ID : #{n[:vlan]}\n" if n[:vlan] - print_str += " - Cluster : #{n[:cluster]}\n" - print_str += " Import this Network [y/n]? " - - STDOUT.print print_str - - next if STDIN.gets.strip.downcase != 'y' - - # Size - - STDOUT.print " How many VMs are you planning"\ - " to fit into this network [255]? " - - size = STDIN.gets.strip - - size = "255" if size.to_i.to_s != size - - # Type - - STDOUT.print " What type of Virtual Network"\ - " do you want to create (IPv[4],IPv[6]"\ - ",[E]thernet) ?" - - type = STDIN.gets.strip - - ar_str = "\nAR=[TYPE=\"" - - case type.downcase - when "4" - ar_str += "IP4\"" - STDOUT.print " Please input the first IP "\ - "in the range: " - ip = STDIN.gets.strip - ar_str += ",IP=" + ip - - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac = STDIN.gets.strip - ar_str += ",MAC=" + mac if !mac.empty? - when "6" - ar_str += "IP6\"" - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac = STDIN.gets.strip - ar_str += ",MAC=" + mac if !mac.empty? - - STDOUT.print " Please input the GLOBAL PREFIX "\ - "[Enter for default]: " - gp = STDIN.gets.strip - ar_str += ",GLOBAL_PREFIX=" + gp if !gp.empty? - - STDOUT.print " Please input the ULA PREFIX "\ - "[Enter for default]: " - up = STDIN.gets.strip - ar_str += ",ULA_PREFIX=" + up if !up.empty? - when "e" - ar_str += "ETHER\"" - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac = STDIN.gets.strip - ar_str += ",MAC=" + mac if !mac.empty? - else - STDOUT.puts " Type [#{type}] not supported,"\ - " defaulting to Ethernet." - ar_str += "ETHER\"" - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac = STDIN.gets.strip - ar_str += ",MAC=" + mac if !mac.empty? - end - - ar_str += ",SIZE = \"#{size}\"]" - - one_vn = ::OpenNebula::VirtualNetwork.new( - ::OpenNebula::Template.build_xml, vc.one) - - vnet_template = n[:one] + ar_str - - rc = one_vn.allocate(vnet_template) - - if ::OpenNebula.is_error?(rc) - STDOUT.puts " Error creating virtual network: " + - " #{rc.message}\n" - else - STDOUT.puts " OpenNebula virtual network " + - "#{one_vn.id} created with size #{size}!\n" - end - } - } - rescue Exception => e - STDOUT.puts "error: #{e.message}" - exit -1 - end + VCenterDriver::Importer.import_networks(con_ops, options) exit 0 end + ############################################################################ + # Import datastores + ############################################################################ datastores_desc = <<-EOT.unindent Import vCenter Datastores into OpenNebula EOT @@ -501,64 +161,14 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :datastores, datastores_desc, :options=>[ VCENTER, USER, PASS ] do con_ops = connection_options("Datastores", options) - begin - STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." - - vc = VCenterDriver::VIClient.new_connection(con_ops) - - STDOUT.print "done!\n\n" - - STDOUT.print "Looking for Datastores..." - - rs = vc.vcenter_datastores - - STDOUT.print "done!\n" - - rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - if tmps.empty? - STDOUT.print " No new Datastores found in #{dc}...\n\n" - next - end - - tmps.each{ |d| - STDOUT.print "\n * Datastore found:\n"\ - " - Name : #{d[:name]}\n"\ - " - Total MB : #{d[:total_mb]}\n"\ - " - Free MB : #{d[:free_mb]}\n"\ - " - Cluster : #{d[:cluster]}\n"\ - " Import this Datastore [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - one_d = ::OpenNebula::Datastore.new( - ::OpenNebula::Datastore.build_xml, vc.one) - - rc = one_d.allocate(d[:one]) - - if ::OpenNebula.is_error?(rc) - STDOUT.puts " Error creating datastore: #{rc.message}\n"\ - " One datastore can exist only once, and "\ - "can be used in any vCenter Cluster that "\ - "has access to it. Also, no spaces allowed "\ - "in datastore name (rename it in vCenter "\ - "and try again)" - else - STDOUT.puts " OpenNebula datastore #{one_d.id} created!\n" - end - } - } - rescue Exception => e - STDOUT.puts "error: #{e.message}" - exit -1 - end + VCenterDriver::Importer.import_datastore(con_ops, options) exit 0 end + ############################################################################ + # Import images + ############################################################################ images_desc = <<-EOT.unindent Import vCenter Images into OpenNebula EOT @@ -573,49 +183,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do con_ops = connection_options("Images", options) - begin - STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." - - vc = VCenterDriver::VIClient.new_connection(con_ops) - - STDOUT.print "done!\n\n" - - STDOUT.print "Looking for Images..." - - images = vc.vcenter_images(ds_name) - - STDOUT.print "done!\n" - - images.each{ |i| - STDOUT.print "\n * Image found:\n"\ - " - Name : #{i[:name]}\n"\ - " - Path : #{i[:path]}\n"\ - " - Type : #{i[:type]}\n"\ - " Import this Image [y/n]? " - - next if STDIN.gets.strip.downcase != 'y' - - one_i = ::OpenNebula::Image.new( - ::OpenNebula::Image.build_xml, vc.one) - - rc = one_i.allocate(i[:one], i[:dsid].to_i) - - if ::OpenNebula.is_error?(rc) - STDOUT.puts "Error creating image: #{rc.message}\n" - if rc.message == "[ImageAllocate] Not enough space "\ - "in datastore" - STDOUT.puts "Please disable DATASTORE_CAPACITY_"\ - "CHECK in /etc/one/oned.conf and "\ - "restart OpenNebula." - end - else - STDOUT.puts " OpenNebula image #{one_i.id} created!\n" - end - } - rescue Exception => e - STDOUT.puts "error: #{e.message}" - exit -1 - end + VCenterDriver::Importer.import_images(con_ops, ds_name, options) exit 0 end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index 4af8a94b52..7d199d5484 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -33,6 +33,279 @@ class DatacenterFolder @items[ref.to_sym] end + + def get_vcenter_instance_uuid + @vi_client.vim.serviceContent.about.instanceUuid + end + + def get_clusters + + clusters = {} + + vcenter_uuid = get_vcenter_instance_uuid + + pool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool, false) + if pool.respond_to?(:message) + raise "Could not get OpenNebula Pool: #{pool.message}" + end + + fetch! if @items.empty? #Get datacenters + + # Add datacenter to hash and store in an array all clusters + @items.values.each do |dc| + dc_name = dc.item.name + clusters[dc_name] = [] + + host_folder = dc.host_folder + host_folder.fetch_clusters! + + host_folder.items.values.each do |ccr| + cluster = {} + cluster[:ref] = ccr['_ref'] + cluster[:name] = ccr['name'] + attribute = "TEMPLATE/VCENTER_CCR_REF" + one_host = VCenterDriver::VIHelper.find_by_ref(OpenNebula::HostPool, + attribute, + ccr['_ref'], + vcenter_uuid, + pool) + + next if one_host.nil? #Cluster hasn't been imported' + + cluster[:host_id] = one_host['ID'] + clusters[dc_name] << cluster + end + end + + clusters + end + + def get_unimported_datastores + ds_objects = {} + + vcenter_uuid = get_vcenter_instance_uuid + + pool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false) + + if pool.respond_to?(:message) + raise "Could not get OpenNebula DatastorePool: #{pool.message}" + end + + fetch! if @items.empty? #Get datacenters + + one_clusters = get_clusters + + @items.values.each do |dc| + dc_name = dc.item.name + ds_objects[dc_name] = [] + + datastore_folder = dc.datastore_folder + datastore_folder.fetch! + datastore_folder.items.values.each do |ds| + + if ds.instance_of? VCenterDriver::Datastore + hosts_in_ds = ds['host'] + clusters_in_ds = {} + + hosts_in_ds.each do |host| + if !clusters_in_ds[host.key.parent._ref.to_s] + clusters_in_ds[host.key.parent._ref.to_s] = host.key.parent.name + end + end + + clusters_in_ds.each do |ccr_ref, ccr_name| + already_image_ds = VCenterDriver::Storage.exists_one_by_ref_ccr_and_type?(ds["_ref"], ccr_ref, vcenter_uuid, "IMAGE_DS", pool) + + if !already_image_ds + object = ds.to_one_template(one_clusters[dc_name], ccr_ref, ccr_name, "IMAGE_DS", vcenter_uuid) + ds_objects[dc_name] << object if !object.nil? + end + + already_system_ds = VCenterDriver::Storage.exists_one_by_ref_ccr_and_type?(ds["_ref"], ccr_ref, vcenter_uuid, "SYSTEM_DS", pool) + + if !already_system_ds + object = ds.to_one_template(one_clusters[dc_name], ccr_ref, ccr_name, "SYSTEM_DS", vcenter_uuid) + ds_objects[dc_name] << object if !object.nil? + end + end + end + + if ds.instance_of? VCenterDriver::StoragePod + clusters_in_spod = {} + ds_in_spod = ds['children'] + + ds_in_spod.each do |sp_ds| + hosts_in_ds = sp_ds.host + hosts_in_ds.each do |host| + if !clusters_in_spod[host.key.parent._ref.to_s] + clusters_in_spod[host.key.parent._ref.to_s] = host.key.parent.name + end + end + end + + clusters_in_spod.each do |ccr_ref, ccr_name| + already_system_ds = VCenterDriver::Storage.exists_one_by_ref_ccr_and_type?(ds["_ref"], ccr_ref, vcenter_uuid, "SYSTEM_DS", pool) + + if !already_system_ds + object = ds.to_one_template(one_clusters[dc_name], ccr_ref, ccr_name, "SYSTEM_DS", vcenter_uuid) + ds_objects[dc_name] << object if !object.nil? + end + end + end + end + end + + ds_objects + end + + def get_unimported_templates(vi_client) + template_objects = {} + vcenter_uuid = get_vcenter_instance_uuid + tpool = VCenterDriver::VIHelper.one_pool(OpenNebula::TemplatePool, false) + + if tpool.respond_to?(:message) + raise "Could not get OpenNebula TemplatePool: #{tpool.message}" + end + + fetch! if @items.empty? #Get datacenters + + @items.values.each do |dc| + + dc_name = dc.item.name + template_objects[dc_name] = [] + + #Get datastores available in a datacenter + ds_list = [] + datastore_folder = dc.datastore_folder + datastore_folder.fetch! + datastore_folder.items.values.each do |ds| + ds_hash = {} + ds_hash[:name] = ds["name"] + ds_hash[:ref] = ds["_ref"] + ds_list << ds_hash + end + + #Get templates defined in a datacenter + vm_folder = dc.vm_folder + vm_folder.fetch_templates! + vm_folder.items.values.each do |template| + one_template = VCenterDriver::VIHelper.find_by_ref(OpenNebula::TemplatePool, + "TEMPLATE/VCENTER_TEMPLATE_REF", + template['_ref'], + vcenter_uuid, + tpool) + next if one_template #If the template has been already imported + + template_name = template['name'] + template_ref = template['_ref'] + template_ccr = template['runtime.host.parent'] + cluster_name = template['runtime.host.parent.name'] + + #Get DS list + ds = "" + default_ds = nil + if !ds_list.empty? + ds_name_list = [] + ds_list.each do |ds_hash| + ds_name_list << ds_hash[:name] + end + ds = "M|list|Which datastore you want this VM to run in? " + ds << "|#{ds_name_list.join(",")}" #List of DS + ds << "|#{ds_name_list.first}" #Default DS + default_ds = ds_name_list.first + end + + #Get resource pools + rp_cache = {} + if !rp_cache[template_ccr.name.to_s] + tmp_cluster = VCenterDriver::ClusterComputeResource.new_from_ref(template_ccr._ref, vi_client) + rp_list = tmp_cluster.get_resource_pool_list + rp = "" + if !rp_list.empty? + rp_name_list = [] + rp_list.each do |rp_hash| + rp_name_list << rp_hash[:name] + end + rp = "M|list|Which resource pool you want this VM to run in? " + rp << "|#{rp_name_list.join(",")}" #List of RP + rp << "|#{rp_name_list.first}" #Default RP + end + rp_cache[template_ccr.name.to_s] = rp + end + rp = rp_cache[template_ccr.name.to_s] + + object = template.to_one_template(template_name, + template_ref, + template_ccr._ref, + cluster_name, + ds, + ds_list, + default_ds, + rp, + rp_list, + vcenter_uuid) + + template_objects[dc_name] << object if !object.nil? + end #template loop + end #datacenter loop + return template_objects + end + + def get_unimported_networks + + network_objects = {} + vcenter_uuid = get_vcenter_instance_uuid + npool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool, false) + + if npool.respond_to?(:message) + raise "Could not get OpenNebula VirtualNetworkPool: #{npool.message}" + end + + fetch! if @items.empty? #Get datacenters + + @items.values.each do |dc| + + dc_name = dc.item.name + network_objects[dc_name] = [] + + #Get networks defined in a datacenter + network_folder = dc.network_folder + network_folder.fetch! + network_folder.items.values.each do |network| + + one_network = VCenterDriver::VIHelper.find_by_ref(OpenNebula::VirtualNetworkPool, + "TEMPLATE/VCENTER_NET_REF", + network['_ref'], + vcenter_uuid, + npool) + next if one_network #If the network has been already imported + + network_name = network['name'] + network_ref = network['_ref'] + + # TODO slow VLAN_ID retrieve for portgroups! set to nil + vlan_id = "" + if network.class == VCenterDriver::DistributedPortGroup + vlan_id = network.vlan_id + end + + network.clusters.each do |ccr_ref, ccr_name| + one_vnet = VCenterDriver::Network.to_one_template(network_name, + network_ref, + network.network_type, + vlan_id, + ccr_ref, + ccr_name, + vcenter_uuid) + network_objects[dc_name] << one_vnet + end #network clusters loop + end # network loop + end #datacenters loop + + return network_objects + + end + end # class DatatacenterFolder class Datacenter diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index d554262fb5..470831fb8a 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -77,6 +77,63 @@ class Storage "USED_MB=#{used_mb}\nFREE_MB=#{free_mb} \nTOTAL_MB=#{total_mb}" end + + def self.exists_one_by_ref_ccr_and_type?(ref, ccr_ref, vcenter_uuid, type, pool = nil) + pool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false) if pool.nil? + elements = pool.select{|e| + e["TEMPLATE/TYPE"] == type && + e["TEMPLATE/VCENTER_DS_REF"] == ref && + e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref && + e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid} + + return elements.size == 1 + end + + def to_one(ds_name, vcenter_uuid, ccr_ref, host_id) + one = "" + one << "NAME=\"#{ds_name}\"\n" + one << "TM_MAD=vcenter\n" + one << "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n" + one << "VCENTER_CCR_REF=\"#{ccr_ref}\"\n" + one << "VCENTER_DS_REF=\"#{self['_ref']}\"\n" + one << "VCENTER_ONE_HOST_ID=\"#{host_id}\"\n" + + return one + end + + def to_one_template(one_clusters, ccr_ref, ccr_name, type, vcenter_uuid, one) + + one_cluster = one_clusters.select { |ccr| ccr[:ref] == ccr_ref }.first rescue nil + + return nil if one_cluster.nil? + + ds_name = "" + + if type == "IMAGE_DS" + ds_name = "#{self['name']} - #{ccr_name} (IMG)" + else + ds_name = "#{self['name']} - #{ccr_name} (SYS)" + end + + one_tmp = { + :name => ds_name, + :total_mb => ((self['summary.capacity'].to_i / 1024) / 1024), + :free_mb => ((self['summary.freeSpace'].to_i / 1024) / 1024), + :cluster => ccr_name, + :one => to_one(ds_name, vcenter_uuid, ccr_ref, one_cluster[:host_id]) + } + + if type == "SYSTEM_DS" + one_tmp[:one] << "TYPE=SYSTEM_DS\n" + else + one_tmp[:one] << "DS_MAD=vcenter\n" + one_tmp[:one] << "TYPE=IMAGE_DS\n" + end + + return one_tmp + end + + end # class Storage class StoragePod < Storage @@ -215,22 +272,11 @@ class Datastore < Storage # Get file size for image handling def stat(img_str) ds_name = self['name'] - img_path = File.dirname img_str img_name = File.basename img_str # Create Search Spec - spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new - spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, - RbVmomi::VIM::IsoImageFileQuery.new] - spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, - :fileSize => true, - :fileType => true, - :modification => true) - spec.matchPattern=[img_name] - - search_params = {'datastorePath' => "[#{ds_name}] #{img_path}", - 'searchSpec' => spec} + search_params = get_search_params(ds_name, img_path, img_name) # Perform search task and return results begin @@ -250,6 +296,27 @@ class Datastore < Storage end end + def get_search_params(ds_name, img_path=nil, img_name=nil) + spec = RbVmomi::VIM::HostDatastoreBrowserSearchSpec.new + spec.query = [RbVmomi::VIM::VmDiskFileQuery.new, + RbVmomi::VIM::IsoImageFileQuery.new] + spec.details = RbVmomi::VIM::FileQueryFlags(:fileOwner => true, + :fileSize => true, + :fileType => true, + :modification => true) + + + spec.matchPattern = img_name.nil? ? [] : [img_name] + + datastore_path = "[#{ds_name}]" + datastore_path << " #{img_path}" if !img_path.nil? + + search_params = {'datastorePath' => datastore_path, + 'searchSpec' => spec} + + return search_params + end + def get_fm self['_connection.serviceContent.fileManager'] end @@ -347,6 +414,95 @@ class Datastore < Storage return output end + def get_images(vcenter_uuid) + img_templates = [] + ds_id = nil + ds_name = self['name'] + + img_types = ["FloppyImageFileInfo", + "IsoImageFileInfo", + "VmDiskFileInfo"] + + ipool = VCenterDriver::VIHelper.one_pool(OpenNebula::ImagePool, false) + if ipool.respond_to?(:message) + raise "Could not get OpenNebula ImagePool: #{pool.message}" + end + + dpool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false) + if dpool.respond_to?(:message) + raise "Could not get OpenNebula DatastorePool: #{pool.message}" + end + + begin + one_ds = VCenterDriver::VIHelper.find_by_ref(OpenNebula::DatastorePool, + "TEMPLATE/VCENTER_DS_REF", + self["_ref"], + vcenter_uuid, + dpool) + raise "Could not find OpenNebula Datastore" if one_ds.nil? + ds_id = one_ds["ID"] + rescue Exception => e + raise "Error: #{e.message}" + end + + begin + # Create Search Spec + search_params = get_search_params(ds_name) + + # Perform search task and return results + search_task = self['browser']. + SearchDatastoreSubFolders_Task(search_params) + search_task.wait_for_completion + + search_task.info.result.each { |image| + folderpath = "" + if image.folderPath[-1] != "]" + folderpath = image.folderPath.sub(/^\[#{ds_name}\] /, "") + end + + image = image.file.first + + # Skip not relevant files + next if !img_types.include? image.class.to_s + + # Get image path and name + image_path = folderpath + image_path << image.path + image_name = File.basename(image.path).reverse.sub("kdmv.","").reverse + + # Get image and disk type + image_type = image.class.to_s == "VmDiskFileInfo" ? "OS" : "CDROM" + disk_type = image.class.to_s == "VmDiskFileInfo" ? image.diskType : nil + + #Set template + one_image = "NAME=\"#{image_name} - #{ds_name}\"\n" + one_image << "PATH=\"vcenter://#{image_path}\"\n" + one_image << "PERSISTENT=\"YES\"\n" + one_image << "TYPE=\"#{image_type}\"\n" + one_image << "DISK_TYPE=\"#{disk_type}\"\n" if disk_type + + if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, + "#{image_name} - #{ds_name}", + ipool, + false).nil? + img_templates << { + :name => "#{image_name} - #{ds_name}", + :path => image_path, + :size => (image.fileSize / 1024).to_s, + :type => image.class.to_s, + :dsid => ds_id, + :one => one_image + } + end + } + + rescue + raise "Could not find images." + end + + return img_templates + end + # This is never cached def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::Datastore.new(vi_client.vim, ref), vi_client) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index d2a8f369cd..81e47d4211 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -1,27 +1,27 @@ module VCenterDriver class HostFolder - attr_accessor :item, :clusters + attr_accessor :item, :items def initialize(item) @item = item - @clusters = {} + @items = {} end def fetch_clusters! VIClient.get_entities(@item, 'ClusterComputeResource').each do |item| item_name = item._ref - @clusters[item_name.to_sym] = ClusterComputeResource.new(item) + @items[item_name.to_sym] = ClusterComputeResource.new(item) end end def get_cluster(ref) - if !@clusters[ref.to_sym] + if !@items[ref.to_sym] rbvmomi_dc = RbVmomi::VIM::ClusterComputeResource.new(@item._connection, ref) - @clusters[ref.to_sym] = ClusterComputeResource.new(rbvmomi_dc) + @items[ref.to_sym] = ClusterComputeResource.new(rbvmomi_dc) end - @clusters[ref.to_sym] + @items[ref.to_sym] end end # class HostFolder @@ -53,6 +53,38 @@ class ClusterComputeResource @resource_pools end + def get_resource_pool_list(rp = nil, parent_prefix = "", rp_array = []) + + current_rp = "" + + if rp.nil? + rp = @item.resourcePool + else + if !parent_prefix.empty? + current_rp << parent_prefix + current_rp << "/" + end + current_rp << rp.name + end + + if rp.resourcePool.size == 0 + rp_info = {} + rp_info[:name] = current_rp + rp_info[:ref] = rp._ref + rp_array << rp_info + else + rp.resourcePool.each do |child_rp| + get_resource_pool_list(child_rp, current_rp, rp_array) + end + rp_info = {} + rp_info[:name] = current_rp + rp_info[:ref] = rp._ref + rp_array << rp_info if !current_rp.empty? + end + + rp_array + end + def monitor #Load the host systems summary = @item.summary @@ -236,7 +268,7 @@ class ClusterComputeResource } if number == -1 - vm_template_64 = Base64.encode64(vm.to_one(ccr_host)).gsub("\n","") + vm_template_64 = Base64.encode64(vm.to_one).gsub("\n","") str_info << "IMPORT_TEMPLATE=\"#{vm_template_64}\"," end @@ -281,6 +313,43 @@ class ClusterComputeResource Datacenter.new(item) end + def self.to_one(name, host, user, pass, ref, vc_uuid) + + one_host = VCenterDriver::VIHelper.one_item(OpenNebula::Host) + + if OpenNebula.is_error?(one_host) + raise "Could not create host: #{one_host.message}" + end + + rc = one_host.allocate(name, 'vcenter', 'vcenter', + ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) + + if OpenNebula.is_error?(rc) + raise "Could not allocate host: #{rc.message}" + end + + template = "VCENTER_HOST=\"#{host}\"\n"\ + "VCENTER_PASSWORD=\"#{pass}\"\n"\ + "VCENTER_USER=\"#{user}\"\n"\ + "VCENTER_CCR_REF=\"#{ref}\"\n"\ + "VCENTER_INSTANCE_ID=\"#{vc_uuid}\"\n" + + rc = one_host.update(template, false) + + if OpenNebula.is_error?(rc) + update_error = rc.message + rc = one_host.delete + if OpenNebula.is_error?(rc) + raise "Could not update host: #{update_error} "\ + "and could not delete host: #{rc.message}" + else + raise "Could not update host: #{rc.message}" + end + end + + return one_host + end + def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::ClusterComputeResource.new(vi_client.vim, ref), vi_client) end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb new file mode 100644 index 0000000000..eda5bc2b2f --- /dev/null +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -0,0 +1,571 @@ +module VCenterDriver + +class Importer + +def self.import_clusters(con_ops, options) + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vi_client = VCenterDriver::VIClient.new(con_ops) + + STDOUT.print "done!\n\n" + + STDOUT.print "Exploring vCenter resources..." + + dc_folder = VCenterDriver::DatacenterFolder.new(vi_client) + + # Get vcenter intance uuid as moref is unique for each vcenter + vc_uuid = dc_folder.get_vcenter_instance_uuid + + rs = dc_folder.get_unimported_objects(OpenNebula::HostPool, vc_uuid) + + STDOUT.print "done!\n\n" + + rs.each {|dc, cluster| + STDOUT.print "Do you want to process datacenter #{dc} (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + + if cluster.empty? + STDOUT.puts " No new clusters found in #{dc}..." + next + end + + cluster.each{ |c| + imported_name = "#{c["name"]}" + STDOUT.print " * Import cluster #{imported_name} (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + + + one_host = VCenterDriver::ClusterComputeResource + .to_one(imported_name, + con_ops[:host], + con_ops[:user], + con_ops[:password], + c['_ref'], + vc_uuid) + + STDOUT.puts " OpenNebula host #{imported_name} with "\ + " id #{one_host.id} successfully created." + + + STDOUT.puts + } + } + rescue Interrupt => e + puts "\n" + exit 0 #Ctrl+C + rescue Exception => e + STDOUT.puts " Error: #{e.message}/\n#{e.backtrace}" + ensure + vi_client.close_connection if vi_client + end + +end + +def self.import_templates(con_ops, options) + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vi_client = VCenterDriver::VIClient.new(con_ops) + + STDOUT.print "done!\n\n" + + STDOUT.print "Looking for VM Templates..." + + dc_folder = VCenterDriver::DatacenterFolder.new(vi_client) + + rs = dc_folder.get_unimported_templates(vi_client) + + STDOUT.print "done!\n" + + rs.each {|dc, tmps| + STDOUT.print "\nDo you want to process datacenter #{dc}"\ + " (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + + if tmps.empty? + STDOUT.print " No new VM Templates found in #{dc}...\n\n" + next + end + + tmps.each{ |t| + + STDOUT.print "\n * VM Template found:\n"\ + " - Name : #{t[:name]}\n"\ + " - Moref : #{t[:vcenter_ref]}\n"\ + " - Cluster: #{t[:cluster_name]}\n"\ + " Import this VM template (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + + + ds_input = "" + + STDOUT.print "\n This template is currently set to be "\ + "deployed in datastore #{t[:default_ds]}."\ + "\n Press y to keep the default, n to select"\ + " a new default datastore or d to delegate "\ + " the choice to the user ([y]/n/d)? " + + answer = STDIN.gets.strip.downcase + + case answer + when 'd' + ds_split = t[:ds].split("|") + list_of_ds = ds_split[-2] + default_ds = ds_split[-1] + ds_input = ds_split[0] + "|" + ds_split[1] + "|" + + ds_split[2] + "|" + + # Available list of datastores + + input_str = " The list of available datastores to be"\ + " presented to the user are \"#{list_of_ds}\"" + input_str+= "\n Press y to agree, or input a comma"\ + " separated list of datastores to edit "\ + "[y/comma separated list] " + STDOUT.print input_str + + answer = STDIN.gets.strip + + if answer.downcase == 'y' + ds_input += ds_split[3] + "|" + else + ds_input += answer + "|" + end + + # Default + input_str = " The default datastore presented to "\ + "the end user is set to \"#{default_ds}\"." + input_str+= "\n Press y to agree, or input a new "\ + "datastore [y/datastore name] " + STDOUT.print input_str + + answer = STDIN.gets.strip + + if answer.downcase == 'y' + ds_input += ds_split[4] + else + ds_input += answer + end + when 'n' + ds_split = t[:ds].split("|") + list_of_ds = ds_split[-2] + + input_str = " The list of available datastores is:\n" + + STDOUT.print input_str + + dashes = "" + 100.times do + dashes << "-" + end + + list_str = "\n [Index] Datastore :"\ + "\n #{dashes}\n" + + STDOUT.print list_str + + index = 1 + t[:ds_list].each do |ds| + list_str = " [#{index}] #{ds[:name]}\n" + index += 1 + STDOUT.print list_str + end + + input_str = "\n Please input the new default"\ + " datastore index in the list (e.g 1): " + + STDOUT.print input_str + + answer = STDIN.gets.strip + + t[:one] += "VCENTER_DS_REF=\"#{t[:ds_list][answer.to_i - 1][:ref]}\"\n" + end + + # Resource Pools + rp_input = "" + rp_split = t[:rp].split("|") + + if rp_split.size > 3 + STDOUT.print "\n This template is currently set to "\ + "launch VMs in the default resource pool."\ + "\n Press y to keep this behaviour, n to select"\ + " a new resource pool or d to delegate the choice"\ + " to the user ([y]/n/d)? " + + answer = STDIN.gets.strip.downcase + + case answer + when 'd' + list_of_rp = rp_split[-2] + default_rp = rp_split[-1] + rp_input = rp_split[0] + "|" + rp_split[1] + "|" + + rp_split[2] + "|" + + # Available list of resource pools + input_str = " The list of available resource pools "\ + "to be presented to the user are "\ + "\"#{list_of_rp}\"" + input_str+= "\n Press y to agree, or input a comma"\ + " separated list of resource pools to edit "\ + "[y/comma separated list] " + STDOUT.print input_str + + answer = STDIN.gets.strip + + if answer.downcase == 'y' + rp_input += rp_split[3] + "|" + else + rp_input += answer + "|" + end + + # Default + input_str = " The default resource pool presented "\ + "to the end user is set to"\ + " \"#{default_rp}\"." + input_str+= "\n Press y to agree, or input a new "\ + "resource pool [y/resource pool name] " + STDOUT.print input_str + + answer = STDIN.gets.strip + + if answer.downcase == 'y' + rp_input += rp_split[4] + else + rp_input += answer + end + when 'n' + + list_of_rp = rp_split[-2] + + input_str = " The list of available resource pools is:\n" + + STDOUT.print input_str + + dashes = "" + 100.times do + dashes << "-" + end + + list_str = "\n [Index] Resource pool :"\ + "\n #{dashes}\n" + + STDOUT.print list_str + + index = 1 + t[:rp_list].each do |rp| + list_str = " [#{index}] #{rp[:name]}\n" + index += 1 + STDOUT.print list_str + end + + input_str = "\n Please input the new default"\ + " resource pool index in the list (e.g 1): " + + STDOUT.print input_str + + answer = STDIN.gets.strip + + t[:one] << "VCENTER_RP_REF=\"#{t[:rp_list][answer.to_i - 1][:ref]}\"\n" + end + end + + if !ds_input.empty? || !rp_input.empty? + t[:one] << "USER_INPUTS=[" + t[:one] << "VCENTER_DS_LIST=\"#{ds_input}\"," if !ds_input.empty? + t[:one] << "VCENTER_RP_LIST=\"#{rp_input}\"," if !rp_input.empty? + t[:one] = t[:one][0..-2] + t[:one] << "]" + end + + one_t = VCenterDriver::VIHelper.new_one_item(OpenNebula::Template) + + rc = one_t.allocate(t[:one]) + + if ::OpenNebula.is_error?(rc) + STDOUT.puts " Error creating template: #{rc.message}\n" + else + STDOUT.puts " OpenNebula template #{one_t.id} created!\n" + end + } + } + rescue Interrupt => e + puts "\n" + exit 0 #Ctrl+C + rescue Exception => e + STDOUT.puts " Error: #{e.message}/\n#{e.backtrace}" + ensure + vi_client.close_connection if vi_client + end +end + +def self.import_networks(con_ops, options) + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vi_client = VCenterDriver::VIClient.new(con_ops) + + STDOUT.print "done!\n\n" + + STDOUT.print "Looking for vCenter networks..." + + dc_folder = VCenterDriver::DatacenterFolder.new(vi_client) + + rs = dc_folder.get_unimported_networks + + STDOUT.print "done!\n" + + rs.each {|dc, tmps| + STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " + + next if STDIN.gets.strip.downcase != 'y' + + if tmps.empty? + STDOUT.print " No new Networks found in #{dc}...\n\n" + next + end + + tmps.each do |n| + print_str = "\n * Network found:\n"\ + " - Name : #{n[:name]}\n"\ + " - Type : #{n[:type]}\n" + print_str << " - VLAN ID : #{n[:vlan_id]}\n" if !n[:vlan_id].empty? + print_str << " - Cluster : #{n[:cluster]}\n" + print_str << " Import this Network (y/[n])? " + + STDOUT.print print_str + + next if STDIN.gets.strip.downcase != 'y' + + size="255" + ar_type=nil + first_ip=nil + first_mac=nil + global_prefix=nil + ula_prefix=nil + + # Size + STDOUT.print " How many VMs are you planning"\ + " to fit into this network [255]? " + size_answer = STDIN.gets.strip + if !size_answer.empty? + size = size_answer.to_i.to_s rescue "255" + end + + # Type + STDOUT.print " What type of Virtual Network"\ + " do you want to create (IPv[4],IPv[6]"\ + ",[E]thernet) ?" + + type_answer = STDIN.gets.strip + if ["4","6","e"].include?(type_answer.downcase) + ar_type = type_answer.downcase + else + ar_type = "e" + STDOUT.puts " Type [#{type_answer}] not supported,"\ + " defaulting to Ethernet." + end + + case ar_type.downcase + when "4" + STDOUT.print " Please input the first IP "\ + "in the range: " + first_ip = STDIN.gets.strip + + STDOUT.print " Please input the first MAC "\ + "in the range [Enter for default]: " + mac_answer = STDIN.gets.strip + first_mac = first_mac_answer if !mac_answer.empty? + when "6" + STDOUT.print " Please input the first MAC "\ + "in the range [Enter for default]: " + mac_answer = STDIN.gets.strip + first_mac = first_mac_answer if !mac_answer.empty? + + STDOUT.print " Please input the GLOBAL PREFIX "\ + "[Enter for default]: " + gp_answer = STDIN.gets.strip + global_prefix = gp_answer if !gp_answer.empty? + + STDOUT.print " Please input the ULA PREFIX "\ + "[Enter for default]: " + ula_answer = STDIN.gets.strip + ula_prefix = ula_answer if !ula_answer.empty? + when "e" + STDOUT.print " Please input the first MAC "\ + "in the range [Enter for default]: " + mac_answer = STDIN.gets.strip + first_mac = first_mac_answer if !mac_answer.empty? + end + + ar_str = "\nAR=[TYPE=\"" + + case ar_type + when "4" + ar_str << "IP4\"" + ar_str << ",IP=" + first_ip if first_ip + ar_str << ",MAC=" + first_mac if first_mac + when "6" + ar_str << "IP6\"" + ar_str << ",MAC=" + first_mac if first_mac + ar_str << ",GLOBAL_PREFIX=" + global_prefix if global_prefix + ar_str << ",ULA_PREFIX=" + ula_prefix if ula_prefix? + when "e" + ar_str << "ETHER\"" + ar_str << ",MAC=" + first_mac if first_mac + end + + ar_str << ",SIZE = \"#{size}\"]" + + n[:one] << ar_str + + one_vn = VCenterDriver::VIHelper.new_one_item(OpenNebula::VirtualNetwork) + + rc = one_vn.allocate(n[:one]) + + if ::OpenNebula.is_error?(rc) + STDOUT.puts " Error creating virtual network: " + + " #{rc.message}\n" + else + STDOUT.puts " OpenNebula virtual network " + + "#{one_vn.id} created with size #{size}!\n" + end + end + } + rescue Interrupt => e + puts "\n" + exit 0 #Ctrl+C + rescue Exception => e + STDOUT.puts " Error: #{e.message}/\n#{e.backtrace}" + ensure + vi_client.close_connection if vi_client + end +end + +def self.import_datastore(con_ops, options) + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vi_client = VCenterDriver::VIClient.new(con_ops) + + STDOUT.print "done!\n\n" + + STDOUT.print "Looking for Datastores..." + + dc_folder = VCenterDriver::DatacenterFolder.new(vi_client) + + rs = dc_folder.get_unimported_datastores + + STDOUT.print "done!\n" + + rs.each {|dc, tmps| + STDOUT.print "\nDo you want to process datacenter #{dc} (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + + if tmps.empty? + STDOUT.print " No new Datastores or StoragePods found in #{dc}...\n\n" + next + end + + tmps.each{ |d| + STDOUT.print "\n * Datastore found:\n"\ + " - Name : #{d[:name]}\n"\ + " - Total MB : #{d[:total_mb]}\n"\ + " - Free MB : #{d[:free_mb]}\n"\ + " - Cluster : #{d[:cluster]}\n"\ + " Import this as Datastore [y/n]? " + + next if STDIN.gets.strip.downcase != 'y' + + one_d = VCenterDriver::VIHelper.new_one_item(OpenNebula::Datastore) + + rc = one_d.allocate(d[:one]) + + if ::OpenNebula.is_error?(rc) + STDOUT.puts " Error creating datastore: #{rc.message}\n"\ + " One datastore can exist only once, and "\ + "can be used in any vCenter Cluster that "\ + "has access to it. Also, no spaces allowed "\ + "in datastore name (rename it in vCenter "\ + "and try again)" + else + STDOUT.puts " OpenNebula datastore #{one_d.id} created!\n" + end + } + } + rescue Interrupt => e + puts "\n" + exit 0 #Ctrl+C + rescue Exception => e + STDOUT.puts " Error: #{e.message}/\n#{e.backtrace}" + ensure + vi_client.close_connection if vi_client + end +end + +def self.import_images(con_ops, ds_name, options) + + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vi_client = VCenterDriver::VIClient.new(con_ops) + + STDOUT.print "done!\n\n" + + STDOUT.print "Looking for Images..." + + one_ds = VCenterDriver::VIHelper.find_by_name(OpenNebula::DatastorePool, + ds_name) + one_ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] + + ds = VCenterDriver::Datastore.new_from_ref(one_ds_ref, vi_client) + + vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid + + images = ds.get_images(vcenter_uuid) + + STDOUT.print "done!\n" + + images.each{ |i| + STDOUT.print "\n * Image found:\n"\ + " - Name : #{i[:name]}\n"\ + " - Path : #{i[:path]}\n"\ + " - Type : #{i[:type]}\n"\ + " Import this Image (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + + one_i = VCenterDriver::VIHelper.new_one_item(OpenNebula::Image) + + rc = one_i.allocate(i[:one], i[:dsid].to_i) + + if ::OpenNebula.is_error?(rc) + STDOUT.puts "Error creating image: #{rc.message}\n" + if rc.message == "[ImageAllocate] Not enough space "\ + "in datastore" + STDOUT.puts "Please disable DATASTORE_CAPACITY_"\ + "CHECK in /etc/one/oned.conf and "\ + "restart OpenNebula." + end + else + STDOUT.puts " OpenNebula image #{one_i.id} created!\n" + end + } + rescue Interrupt => e + puts "\n" + exit 0 #Ctrl+C + rescue Exception => e + STDOUT.puts " Error: #{e.message}/\n#{e.backtrace}" + ensure + vi_client.close_connection if vi_client + end +end + +end # Importer + +end # module VCenterDriver \ No newline at end of file diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index dbc9425361..feae73b5a0 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -16,7 +16,12 @@ class NetworkFolder def fetch! VIClient.get_entities(@item, "Network").each do |item| item_name = item._ref - @items[item_name.to_sym] = Network.new(item) + @items[item_name.to_sym] = PortGroup.new(item) + end + + VIClient.get_entities(@item, "DistributedVirtualPortgroup").each do |item| + item_name = item._ref + @items[item_name.to_sym] = DistributedPortGroup.new(item) end end @@ -38,8 +43,11 @@ end # class NetworkFolder class Network attr_accessor :item + include Memoize + def initialize(item, vi_client=nil) - if !item.instance_of? RbVmomi::VIM::Network + if !item.instance_of?(RbVmomi::VIM::Network) && + !item.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup ) raise "Expecting type 'RbVmomi::VIM::Network'. " << "Got '#{item.class} instead." end @@ -48,11 +56,138 @@ class Network @item = item end + + def self.to_one_template(network_name, network_ref, network_type, vlan_id, + ccr_ref, ccr_name, vcenter_uuid) + one_tmp = {} + one_tmp[:name] = "#{network_name} - #{ccr_name}" + one_tmp[:bridge] = network_name + one_tmp[:type] = network_type + one_tmp[:cluster] = ccr_name + one_tmp[:vlan_id] = vlan_id + one_tmp[:vcenter_ccr_ref] = ccr_ref + one_tmp[:one] = to_one(network_name, network_ref, network_type, vlan_id, + ccr_ref, ccr_name, vcenter_uuid) + return one_tmp + end + + def self.to_one(network_name, network_ref, network_type, vlan_id, + ccr_ref, ccr_name, vcenter_uuid) + template = "NAME=\"#{network_name} - #{ccr_name}\"\n"\ + "BRIDGE=\"#{network_name}\"\n"\ + "VN_MAD=\"dummy\"\n"\ + "VCENTER_TYPE=\"#{network_type}\"\n"\ + "VCENTER_NET_REF=\"#{network_ref}\"\n"\ + "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"\ + "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n" + + template << "VLAN_TAGGED_ID=#{vlan_id}\n" if !vlan_id.empty? + + return template + end + # This is never cached def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref), vi_client) end + end # class Network +class PortGroup < Network + + def initialize(item, vi_client=nil) + if !item.instance_of?(RbVmomi::VIM::Network) + raise "Expecting type 'RbVmomi::VIM::Network'. " << + "Got '#{item.class} instead." + end + + @vi_client = vi_client + @item = item + end + + def clusters + net_clusters = {} + host_members =@item['host'] + host_members.each do |h| + if !net_clusters.key?(h.parent._ref.to_s) + net_clusters[h.parent._ref.to_s] = h.parent.name.to_s + end + end + net_clusters + end + + def vlan_id + id = "" + host_members = self['host'] + host = host_members.first + # This is pretty slow as the host id subsystem has to be queried + cm = host.configManager + nws = cm.networkSystem + nc = nws.networkConfig + pgs = nc.portgroup + pgs.each do |pg| + if pg.spec.name == self["name"] + id << pg.spec.vlanId.to_s if pg.spec.vlanId != 0 + break + end + end + id + end + + def network_type + "Port Group" + end +end # class PortGroup + +class DistributedPortGroup < Network + + def initialize(item, vi_client=nil) + if !item.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup ) + raise "Expecting type 'RbVmomi::VIM::DistributedVirtualPortgroup'. " << + "Got '#{item.class} instead." + end + + @vi_client = vi_client + @item = item + end + + def clusters + net_clusters = {} + host_members = self['config.distributedVirtualSwitch.summary.hostMember'] + host_members.each do |h| + if !net_clusters.key?(h.parent._ref.to_s) + net_clusters[h.parent._ref.to_s] = h.parent.name.to_s + end + end + net_clusters + end + + def vlan_id + id = "" + pc = self['config.defaultPortConfig'] + if pc.respond_to?(:vlan) && pc.vlan.respond_to?(:vlanId) + + vlan = pc.vlan.vlanId + + if vlan.is_a? Array + vlan.each do |v| + id << v.start.to_s + id << ".." + id << v.end.to_s + id << "," + end + id.chop! + else + id = vlan.to_s if vlan != 0 + end + end + return id + end + + def network_type + "Distributed Port Group" + end +end # class DistributedPortGroup + end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb index 16617218b3..ff8383c680 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb @@ -24,21 +24,36 @@ class VIHelper return_if_error(rc, item, exit_if_fail) end + def self.new_one_item(the_class) + item = the_class.new(the_class.build_xml, client) + return item + end + def self.one_pool(the_class, exit_if_fail = true) item = the_class.new(client) rc = item.info return_if_error(rc, item, exit_if_fail) end - def self.find_by_name(the_class, name, exit_if_fail = true) - pool = one_pool(the_class) - element = pool.select{|e| e['NAME'] == name }.first rescue nil - if element.nil? + def self.find_by_name(the_class, name, pool = nil, raise_if_fail = true) + pool = one_pool(the_class, raise_if_fail) if pool.nil? + element = pool.select{|e| e['NAME'] == "#{name}" }.first rescue nil + if element.nil? && raise_if_fail raise "Could not find element '#{name}' in pool '#{the_class}'" else element end end + + def self.find_by_ref(the_class, attribute, ref, vcenter_uuid, pool = nil) + pool = one_pool(the_class, false) if pool.nil? + element = pool.select{|e| + e["#{attribute}"] == ref && + e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid}.first rescue nil + + return element + end + end # class VIHelper end # module VCenterDriver diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index f635e90048..2507d19f58 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -20,6 +20,15 @@ class VirtualMachineFolder end end + def fetch_templates! + VIClient.get_entities(@item, "VirtualMachine").each do |item| + if item.config.template + item_name = item._ref + @items[item_name.to_sym] = VirtualMachine.new(item) + end + end + end + ######################################################################## # Returns a Datastore. Uses the cache if available. # @param ref [Symbol] the vcenter ref @@ -152,7 +161,7 @@ class VirtualMachine # @return RbVmomi::VIM::ResourcePool def get_rp - req_rp = one_item['USER_TEMPLATE/RESOURCE_POOL'] + req_rp = one_item['USER_TEMPLATE/VCENTER_RP_REF'] if vi_client.rp_confined? if req_rp && req_rp != vi_client.rp @@ -1200,46 +1209,62 @@ class VirtualMachine # monitoring ############################################################################ - # @param ccr_host Hash that holds the relationship between the vcenter's ref - # and the host in OpenNebula - def to_one(ccr_host) - cluster = self["runtime.host.parent.name"] + def to_one(template=false) + cluster = self["runtime.host.parent.name"] + ccr_ref = self["runtime.host.parent._ref"] + vc_uuid = self["_connection.serviceContent.about.instanceUuid"] - ccr = self["runtime.host.parent._ref"] - host_id = ccr_host[ccr] + # Get info of the host where the VM/template is located + host_id = nil + one_host = VCenterDriver::VIHelper.find_by_ref(OpenNebula::HostPool, + "TEMPLATE/VCENTER_CCR_REF", + ccr_ref, + vc_uuid) + host_id = one_host["ID"] if one_host str = "NAME = \"#{self["name"]} - #{cluster}\"\n"\ "CPU = \"#{self["config.hardware.numCPU"]}\"\n"\ "vCPU = \"#{self["config.hardware.numCPU"]}\"\n"\ "MEMORY = \"#{self["config.hardware.memoryMB"]}\"\n"\ "HYPERVISOR = \"vcenter\"\n"\ - "IMPORT_VM_ID =\"#{self["config.uuid"]}\"\n"\ - "IMPORT_STATE =\"#{@state}\"\n"\ "SCHED_REQUIREMENTS=\"ID=\\\"#{host_id}\\\"\"\n"\ "CONTEXT = [\n"\ " NETWORK = \"YES\",\n"\ " SSH_PUBLIC_KEY = \"$USER[SSH_PUBLIC_KEY]\"\n"\ - "]\n" + "]\n"\ + "VCENTER_INSTANCE_ID =\"#{vc_uuid}\"\n" + + if !template + str << "IMPORT_VM_ID =\"#{self["config.uuid"]}\"\n" + str << "IMPORT_STATE =\"#{@state}\"\n" + end + + if template + str << "VCENTER_CCR_REF =\"#{ccr_ref}\"\n" + end vnc_port = nil keymap = nil - self["config.extraConfig"].select do |xtra| - if xtra[:key].downcase=="remotedisplay.vnc.port" - vnc_port = xtra[:value] - end + if !template + self["config.extraConfig"].select do |xtra| - if xtra[:key].downcase=="remotedisplay.vnc.keymap" - keymap = xtra[:value] + if xtra[:key].downcase=="remotedisplay.vnc.port" + vnc_port = xtra[:value] + end + + if xtra[:key].downcase=="remotedisplay.vnc.keymap" + keymap = xtra[:value] + end end end if self["config.extraConfig"].size > 0 str << "GRAPHICS = [\n"\ - " TYPE =\"vnc\",\n"\ - " LISTEN =\"0.0.0.0\",\n" + " TYPE =\"vnc\",\n" str << " PORT =\"#{vnc_port}\",\n" if vnc_port - str << " KEYMAP =\"#{keymap}\"\n" if keymap + str << " KEYMAP =\"#{keymap}\",\n" if keymap + str << " LISTEN =\"0.0.0.0\"\n" str << "]\n" end @@ -1253,24 +1278,41 @@ class VirtualMachine case self["guest.guestFullName"] when /CentOS/i - str << "LOGO=images/logos/centos.png" + str << "LOGO=images/logos/centos.png\n" when /Debian/i - str << "LOGO=images/logos/debian.png" + str << "LOGO=images/logos/debian.png\n" when /Red Hat/i - str << "LOGO=images/logos/redhat.png" + str << "LOGO=images/logos/redhat.png\n" when /Ubuntu/i - str << "LOGO=images/logos/ubuntu.png" + str << "LOGO=images/logos/ubuntu.png\n" when /Windows XP/i - str << "LOGO=images/logos/windowsxp.png" + str << "LOGO=images/logos/windowsxp.png\n" when /Windows/i - str << "LOGO=images/logos/windows8.png" + str << "LOGO=images/logos/windows8.png\n" when /Linux/i - str << "LOGO=images/logos/linux.png" + str << "LOGO=images/logos/linux.png\n" end return str end + def to_one_template(template_name, template_ref, template_ccr, cluster_name, + ds, ds_list, default_ds, rp, rp_list, vcenter_uuid) + one_tmp = {} + one_tmp[:name] = "#{template_name} - #{cluster_name}" + one_tmp[:vcenter_ccr_ref] = template_ccr + one_tmp[:one] = to_one(true) + one_tmp[:vcenter_ref] = template_ref + one_tmp[:vcenter_instance_uuid] = vcenter_uuid + one_tmp[:cluster_name] = cluster_name + one_tmp[:ds] = ds + one_tmp[:ds_list] = ds_list + one_tmp[:default_ds] = default_ds + one_tmp[:rp] = rp + one_tmp[:rp_list] = rp_list + return one_tmp + end + def monitor reset_monitor @@ -1459,7 +1501,7 @@ class VirtualMachine str_info << "VMWARETOOLS_RUNNING_STATUS=" << vmware_tools << " " str_info << "VMWARETOOLS_VERSION=" << vmtools_ver << " " str_info << "VMWARETOOLS_VERSION_STATUS=" << vmtools_verst << " " - str_info << "RESOURCE_POOL=\"" << self["resourcePool.name"] << "\" " + str_info << "VCENTER_RP_REF=\"" << self["resourcePool"]._ref << "\" " end def reset_monitor From 7d83ae62fe5113c3cbf02f953ded399ffca015c0 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 08:33:52 +0100 Subject: [PATCH 114/297] F #4913: Add VCENTER_NET_REF usage to calculate_add_nic_spec --- .../remotes/lib/vcenter_driver/virtual_machine.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 2507d19f58..665b6a8694 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -583,10 +583,11 @@ class VirtualMachine def calculate_add_nic_spec(nic) #TODO include VCENTER_NET_REF usage it should be in one_item - mac = nic["MAC"] - bridge = nic["BRIDGE"] - model = nic["MODEL"] - backing = nil + mac = nic["MAC"] + bridge = nic["BRIDGE"] + model = nic["MODEL"] + vnet_ref = nic["VCENTER_NET_REF"] + backing = nil limit_in = nic["INBOUND_PEAK_BW"] limit_out = nic["OUTBOUND_PEAK_BW"] @@ -605,7 +606,7 @@ class VirtualMachine end network = self["runtime.host.network"].select do |n| - n.name == bridge + n._ref == vnet_ref end if network.empty? From dd435de4e1a9b11a04c5c407e91958c55d4a73d9 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 13:52:55 +0100 Subject: [PATCH 115/297] F #4913: Replace VCENTER_TYPE with a more descriptive VCENTER_PORTGRP_TYPE --- src/vmm_mad/remotes/lib/vcenter_driver/network.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index feae73b5a0..1e5ed7ae0e 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -76,7 +76,7 @@ class Network template = "NAME=\"#{network_name} - #{ccr_name}\"\n"\ "BRIDGE=\"#{network_name}\"\n"\ "VN_MAD=\"dummy\"\n"\ - "VCENTER_TYPE=\"#{network_type}\"\n"\ + "VCENTER_PORTGRP_TYPE=\"#{network_type}\"\n"\ "VCENTER_NET_REF=\"#{network_ref}\"\n"\ "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"\ "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n" From 8682b2e3f679bc1f5f1955177d7dae2e82c39adc Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 14:18:46 +0100 Subject: [PATCH 116/297] F #4913: Replace remnants of VCENTER_RESOURCE_POOL with VCENTER_RP_REF --- src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb | 2 +- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb index a2201c933e..c30d3bc5c3 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_client.rb @@ -66,7 +66,7 @@ class VIClient connection = { :host => host["TEMPLATE/VCENTER_HOST"], :user => host["TEMPLATE/VCENTER_USER"], - :rp => host["TEMPLATE/VCENTER_RESOURCE_POOL"], + :rp => host["TEMPLATE/VCENTER_RP_REF"], :password => password } diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 665b6a8694..bdcfc8d366 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1502,7 +1502,7 @@ class VirtualMachine str_info << "VMWARETOOLS_RUNNING_STATUS=" << vmware_tools << " " str_info << "VMWARETOOLS_VERSION=" << vmtools_ver << " " str_info << "VMWARETOOLS_VERSION_STATUS=" << vmtools_verst << " " - str_info << "VCENTER_RP_REF=\"" << self["resourcePool"]._ref << "\" " + str_info << "VCENTER_RP_REF=\"" << self["resourcePool"]._ref << "\" " end def reset_monitor From d359a73da793b868db544e91e8a6d137f3aeb9f4 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 15:26:00 +0100 Subject: [PATCH 117/297] F #4913: Add importer.rb to vcenter_driver requirements --- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 1d0e8aebe1..15d63dfbf1 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -57,6 +57,7 @@ require 'datastore' require 'virtual_machine' require 'network' require 'file_helper' +require 'importer' # ---------------------------------------------------------------------------- # # Helper functions # From 33f45f29b1b1689d4e000030cc34c61e28d1d048 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 16:11:20 +0100 Subject: [PATCH 118/297] F #4913: Fix bugs in import tool --- .../remotes/lib/vcenter_driver/datacenter.rb | 35 +++++++++++++++++++ .../remotes/lib/vcenter_driver/datastore.rb | 4 +-- .../remotes/lib/vcenter_driver/host.rb | 2 +- .../remotes/lib/vcenter_driver/importer.rb | 24 ++++++------- 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index 7d199d5484..c64de7fae5 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -80,6 +80,41 @@ class DatacenterFolder clusters end + def get_unimported_hosts + host_objects = {} + + vcenter_uuid = get_vcenter_instance_uuid + + hpool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool, false) + + if hpool.respond_to?(:message) + raise "Could not get OpenNebula HostPool: #{hpool.message}" + end + + fetch! if @items.empty? #Get datacenters + + @items.values.each do |dc| + dc_name = dc.item.name + host_objects[dc_name] = [] + + host_folder = dc.host_folder + host_folder.fetch_clusters! + host_folder.items.values.each do |host| + + one_host = VCenterDriver::VIHelper.find_by_ref(OpenNebula::HostPool, + "TEMPLATE/VCENTER_CCR_REF", + host['_ref'], + vcenter_uuid, + hpool) + next if one_host #If the host has been already imported + + host_objects[dc_name] << host + end + end + + return host_objects + end + def get_unimported_datastores ds_objects = {} diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 470831fb8a..a6c61fcb93 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -31,7 +31,7 @@ class DatastoreFolder def monitor monitor = "" @items.values.each do |ds| - monitor << "VCENTER_DATASTORE=\"#{ds['name']}\"\n" + monitor << "VCENTER_DS_REF=\"#{ds['_ref']}\"\n" end monitor end @@ -101,7 +101,7 @@ class Storage return one end - def to_one_template(one_clusters, ccr_ref, ccr_name, type, vcenter_uuid, one) + def to_one_template(one_clusters, ccr_ref, ccr_name, type, vcenter_uuid) one_cluster = one_clusters.select { |ccr| ccr[:ref] == ccr_ref }.first rescue nil diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index 81e47d4211..fa24684cae 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -315,7 +315,7 @@ class ClusterComputeResource def self.to_one(name, host, user, pass, ref, vc_uuid) - one_host = VCenterDriver::VIHelper.one_item(OpenNebula::Host) + one_host = VCenterDriver::VIHelper.new_one_item(OpenNebula::Host) if OpenNebula.is_error?(one_host) raise "Could not create host: #{one_host.message}" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index eda5bc2b2f..63e18af8b2 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -17,39 +17,35 @@ def self.import_clusters(con_ops, options) # Get vcenter intance uuid as moref is unique for each vcenter vc_uuid = dc_folder.get_vcenter_instance_uuid - rs = dc_folder.get_unimported_objects(OpenNebula::HostPool, vc_uuid) + rs = dc_folder.get_unimported_hosts STDOUT.print "done!\n\n" - rs.each {|dc, cluster| + rs.each {|dc, clusters| STDOUT.print "Do you want to process datacenter #{dc} (y/[n])? " next if STDIN.gets.strip.downcase != 'y' - if cluster.empty? + if clusters.empty? STDOUT.puts " No new clusters found in #{dc}..." next end - cluster.each{ |c| + clusters.each{ |c| imported_name = "#{c["name"]}" STDOUT.print " * Import cluster #{imported_name} (y/[n])? " next if STDIN.gets.strip.downcase != 'y' - - one_host = VCenterDriver::ClusterComputeResource - .to_one(imported_name, - con_ops[:host], - con_ops[:user], - con_ops[:password], - c['_ref'], - vc_uuid) + one_host = VCenterDriver::ClusterComputeResource.to_one(imported_name, + con_ops[:host], + con_ops[:user], + con_ops[:password], + c['_ref'], + vc_uuid) STDOUT.puts " OpenNebula host #{imported_name} with "\ " id #{one_host.id} successfully created." - - STDOUT.puts } } From 6440754f22280b3062aea2de51e5d958a9de3bb7 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 17:08:32 +0100 Subject: [PATCH 119/297] F #4913: Add VCENTER_VERSION when importing clusters to track API version --- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 5 +++-- src/vmm_mad/remotes/lib/vcenter_driver/importer.rb | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index fa24684cae..12976c12a9 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -313,7 +313,7 @@ class ClusterComputeResource Datacenter.new(item) end - def self.to_one(name, host, user, pass, ref, vc_uuid) + def self.to_one(name, host, user, pass, ref, vc_uuid, vc_version) one_host = VCenterDriver::VIHelper.new_one_item(OpenNebula::Host) @@ -332,7 +332,8 @@ class ClusterComputeResource "VCENTER_PASSWORD=\"#{pass}\"\n"\ "VCENTER_USER=\"#{user}\"\n"\ "VCENTER_CCR_REF=\"#{ref}\"\n"\ - "VCENTER_INSTANCE_ID=\"#{vc_uuid}\"\n" + "VCENTER_INSTANCE_ID=\"#{vc_uuid}\"\n"\ + "VCENTER_VERSION=\"#{vc_version}\"\n"\ rc = one_host.update(template, false) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index 63e18af8b2..4a9cc693c9 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -15,7 +15,10 @@ def self.import_clusters(con_ops, options) dc_folder = VCenterDriver::DatacenterFolder.new(vi_client) # Get vcenter intance uuid as moref is unique for each vcenter - vc_uuid = dc_folder.get_vcenter_instance_uuid + vc_uuid = vi_client.vim.serviceContent.about.instanceUuid + + # Get vcenter API version + vc_version = vi_client.vim.serviceContent.about.apiVersion rs = dc_folder.get_unimported_hosts @@ -42,7 +45,8 @@ def self.import_clusters(con_ops, options) con_ops[:user], con_ops[:password], c['_ref'], - vc_uuid) + vc_uuid, + vc_version) STDOUT.puts " OpenNebula host #{imported_name} with "\ " id #{one_host.id} successfully created." From 400f5126110c4bcc9d8616b71f03866ba469f23f Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 1 Mar 2017 19:08:26 +0100 Subject: [PATCH 120/297] F #4913: Sunstone can import clusters with the new attributes --- .../public/app/utils/vcenter/clusters.js | 16 ++++++++++++---- src/sunstone/routes/vcenter.rb | 9 +++++---- .../remotes/lib/vcenter_driver/datacenter.rb | 14 +++++++++++++- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 16 ++++++++-------- .../remotes/lib/vcenter_driver/importer.rb | 16 +++++----------- 5 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/sunstone/public/app/utils/vcenter/clusters.js b/src/sunstone/public/app/utils/vcenter/clusters.js index 5d36ba4580..4757ae6bf6 100644 --- a/src/sunstone/public/app/utils/vcenter/clusters.js +++ b/src/sunstone/public/app/utils/vcenter/clusters.js @@ -100,11 +100,12 @@ define(function(require) { var newdiv = $(content).appendTo($(".vcenter_datacenter_list", context)); var tbody = $('#' + tableId + ' tbody', context); - $.each(elements, function(id, cluster_name) { + $.each(elements, function(id, cluster) { + var cluster_name = cluster.cluster_name; var opts = { name: cluster_name }; var trow = $(RowTemplate(opts)).appendTo(tbody); - $(".check_item", trow).data("cluster_name", cluster_name); + $(".check_item", trow).data("cluster", cluster); }); var elementsTable = new DomDataTable( @@ -165,7 +166,7 @@ define(function(require) { var host_json = { "host": { - "name": $(this).data("cluster_name"), + "name": $(this).data("cluster").cluster_name, "vm_mad": "vcenter", "vnm_mad": "dummy", "im_mad": "vcenter", @@ -173,6 +174,10 @@ define(function(require) { } }; + var cluster_ref = $(this).data("cluster").cluster_ref; + var vcenter_uuid = $(this).data("cluster").vcenter_uuid; + var vcenter_version = $(this).data("cluster").vcenter_version; + OpenNebulaHost.create({ timeout: true, data: host_json, @@ -185,7 +190,10 @@ define(function(require) { var template_raw = "VCENTER_USER=\"" + that.opts.vcenter_user + "\"\n" + "VCENTER_PASSWORD=\"" + that.opts.vcenter_password + "\"\n" + - "VCENTER_HOST=\"" + that.opts.vcenter_host + "\"\n"; + "VCENTER_HOST=\"" + that.opts.vcenter_host + "\"\n" + + "VCENTER_INSTANCE_ID=\"" + vcenter_uuid + "\"\n" + + "VCENTER_CCR_REF=\"" + cluster_ref + "\"\n" + + "VCENTER_VERSION=\"" + vcenter_version + "\"\n"; Sunstone.runAction("Host.update_template", response.HOST.ID, template_raw); }, diff --git a/src/sunstone/routes/vcenter.rb b/src/sunstone/routes/vcenter.rb index f144878124..0dbef77d3e 100644 --- a/src/sunstone/routes/vcenter.rb +++ b/src/sunstone/routes/vcenter.rb @@ -56,11 +56,11 @@ helpers do error 404, error.to_json end - return VCenterDriver::VIClient.new_connection({ + return VCenterDriver::VIClient.new({ :user => vuser, :password => vpass, - :host => vhost}, - ::OpenNebula::Client.new(nil,$conf[:one_xmlrpc])) + :host => vhost}) + end # def af_format_response(resp) @@ -77,7 +77,8 @@ end get '/vcenter' do begin - rs = vcenter_client.hierarchy + dc_folder = VCenterDriver::DatacenterFolder.new(vcenter_client) + rs = dc_folder.get_unimported_hosts [200, rs.to_json] rescue Exception => e logger.error("[vCenter] " + e.message) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index c64de7fae5..cfc11e3e07 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -38,6 +38,10 @@ class DatacenterFolder @vi_client.vim.serviceContent.about.instanceUuid end + def get_vcenter_api_version + @vi_client.vim.serviceContent.about.apiVersion + end + def get_clusters clusters = {} @@ -85,6 +89,8 @@ class DatacenterFolder vcenter_uuid = get_vcenter_instance_uuid + vcenter_version = get_vcenter_api_version + hpool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool, false) if hpool.respond_to?(:message) @@ -108,7 +114,13 @@ class DatacenterFolder hpool) next if one_host #If the host has been already imported - host_objects[dc_name] << host + host_info = {} + host_info[:cluster_name] = host['name'] + host_info[:cluster_ref] = host['_ref'] + host_info[:vcenter_uuid] = vcenter_uuid + host_info[:vcenter_version] = vcenter_version + + host_objects[dc_name] << host_info end end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index 12976c12a9..afb6119806 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -313,7 +313,7 @@ class ClusterComputeResource Datacenter.new(item) end - def self.to_one(name, host, user, pass, ref, vc_uuid, vc_version) + def self.to_one(cluster, con_ops) one_host = VCenterDriver::VIHelper.new_one_item(OpenNebula::Host) @@ -321,19 +321,19 @@ class ClusterComputeResource raise "Could not create host: #{one_host.message}" end - rc = one_host.allocate(name, 'vcenter', 'vcenter', + rc = one_host.allocate(cluster[:cluster_name], 'vcenter', 'vcenter', ::OpenNebula::ClusterPool::NONE_CLUSTER_ID) if OpenNebula.is_error?(rc) raise "Could not allocate host: #{rc.message}" end - template = "VCENTER_HOST=\"#{host}\"\n"\ - "VCENTER_PASSWORD=\"#{pass}\"\n"\ - "VCENTER_USER=\"#{user}\"\n"\ - "VCENTER_CCR_REF=\"#{ref}\"\n"\ - "VCENTER_INSTANCE_ID=\"#{vc_uuid}\"\n"\ - "VCENTER_VERSION=\"#{vc_version}\"\n"\ + template = "VCENTER_HOST=\"#{con_ops[:host]}\"\n"\ + "VCENTER_PASSWORD=\"#{con_ops[:password]}\"\n"\ + "VCENTER_USER=\"#{con_ops[:user]}\"\n"\ + "VCENTER_CCR_REF=\"#{cluster[:cluster_ref]}\"\n"\ + "VCENTER_INSTANCE_ID=\"#{cluster[:vcenter_uuid]}\"\n"\ + "VCENTER_VERSION=\"#{cluster[:vcenter_version]}\"\n"\ rc = one_host.update(template, false) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index 4a9cc693c9..371aec9882 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -34,21 +34,15 @@ def self.import_clusters(con_ops, options) next end - clusters.each{ |c| - imported_name = "#{c["name"]}" - STDOUT.print " * Import cluster #{imported_name} (y/[n])? " + clusters.each{ |cluster| + STDOUT.print " * Import cluster #{cluster[:cluster_name]} (y/[n])? " next if STDIN.gets.strip.downcase != 'y' - one_host = VCenterDriver::ClusterComputeResource.to_one(imported_name, - con_ops[:host], - con_ops[:user], - con_ops[:password], - c['_ref'], - vc_uuid, - vc_version) + one_host = VCenterDriver::ClusterComputeResource.to_one(cluster, + con_ops) - STDOUT.puts " OpenNebula host #{imported_name} with "\ + STDOUT.puts " OpenNebula host #{cluster[:cluster_name]} with "\ " id #{one_host.id} successfully created." STDOUT.puts } From 94b3d59e6c650052ca3c8588297a5c427e506685 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 2 Mar 2017 08:33:04 +0100 Subject: [PATCH 121/297] F #4913: Add VCENTER_NAME during host monitorization for informative purposes --- src/vmm_mad/remotes/lib/vcenter_driver/host.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb index afb6119806..8b072d7bee 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/host.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/host.rb @@ -101,6 +101,9 @@ class ClusterComputeResource str_info = "" + # Get cluster name for informative purposes + str_info << "VCENTER_NAME=" << self['name'] << "\n" + # System str_info << "HYPERVISOR=vcenter\n" str_info << "TOTALHOST=" << summary.numHosts.to_s << "\n" From c40a589966d4b8c5486de6bdb0671a0320b1c4be Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 2 Mar 2017 09:24:34 +0100 Subject: [PATCH 122/297] F #4913: Fix VCENTER_TEMPLATE_REF in template import --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index bdcfc8d366..00f0b53e10 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1241,6 +1241,7 @@ class VirtualMachine end if template + str << "VCENTER_TEMPLATE_REF =\"#{self['_ref']}\"\n" str << "VCENTER_CCR_REF =\"#{ccr_ref}\"\n" end From 512dc4c7ebade78df481549b361373cb5eb795bf Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 2 Mar 2017 16:31:36 +0100 Subject: [PATCH 123/297] F #4913: Improve image import code --- .../remotes/lib/vcenter_driver/datastore.rb | 15 ++++----------- .../remotes/lib/vcenter_driver/importer.rb | 1 + 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index a6c61fcb93..c628e5ffec 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -155,6 +155,8 @@ end # class StoragePod class Datastore < Storage + attr_accessor :one_item + def initialize(item, vi_client=nil) if !item.instance_of? RbVmomi::VIM::Datastore raise "Expecting type 'RbVmomi::VIM::Datastore'. " << @@ -162,6 +164,7 @@ class Datastore < Storage end @item = item + @one_item = {} end def create_virtual_disk(img_name, size, adapter_type, disk_type) @@ -433,17 +436,7 @@ class Datastore < Storage raise "Could not get OpenNebula DatastorePool: #{pool.message}" end - begin - one_ds = VCenterDriver::VIHelper.find_by_ref(OpenNebula::DatastorePool, - "TEMPLATE/VCENTER_DS_REF", - self["_ref"], - vcenter_uuid, - dpool) - raise "Could not find OpenNebula Datastore" if one_ds.nil? - ds_id = one_ds["ID"] - rescue Exception => e - raise "Error: #{e.message}" - end + ds_id = @one_item["ID"] begin # Create Search Spec diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index 371aec9882..1c269500cc 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -518,6 +518,7 @@ def self.import_images(con_ops, ds_name, options) one_ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] ds = VCenterDriver::Datastore.new_from_ref(one_ds_ref, vi_client) + ds.one_item = one_ds #Store opennebula template for datastore vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid From d58204a287b0fc34247200cac4d240e86f99a69a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 3 Mar 2017 13:32:01 +0100 Subject: [PATCH 124/297] F #4913: Replace remnants of VCENTER_CLUSTER with VCENTER_ONE_HOST_ID --- share/doc/xsd/oned.conf | 6 ++++-- share/etc/oned.conf | 4 +++- src/nebula/NebulaTemplate.cc | 2 +- src/oca/java/test/oned.conf | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/share/doc/xsd/oned.conf b/share/doc/xsd/oned.conf index e251b157f4..f3086626f3 100644 --- a/share/doc/xsd/oned.conf +++ b/share/doc/xsd/oned.conf @@ -371,7 +371,7 @@ IM_MAD = [ NAME="dummy", SUNSTONE_NAME="Testing", EXECUTABLE="one_im_dummy"] # # type : driver type, supported drivers: xen, kvm, xml # -# keep_snapshots: do not remove snapshots on power on/off cycles and live +# keep_snapshots: do not remove snapshots on power on/off cycles and live # migrations if the hypervisor supports that. # # imported_vms_actions : comma-separated list of actions supported @@ -957,7 +957,9 @@ DS_MAD_CONF = [ ] DS_MAD_CONF = [ - NAME = "vcenter", REQUIRED_ATTRS = "VCENTER_CLUSTER", PERSISTENT_ONLY = "YES", + NAME = "vcenter", + REQUIRED_ATTRS = "VCENTER_ONE_HOST_ID, VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_CCR_REF", + PERSISTENT_ONLY = "YES", MARKETPLACE_ACTIONS = "export" ] diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 41f1ad7129..86694cda24 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -1019,7 +1019,9 @@ DS_MAD_CONF = [ ] DS_MAD_CONF = [ - NAME = "vcenter", REQUIRED_ATTRS = "VCENTER_CLUSTER", PERSISTENT_ONLY = "NO", + NAME = "vcenter", + REQUIRED_ATTRS = "VCENTER_ONE_HOST_ID, VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_CCR_REF", + PERSISTENT_ONLY = "NO", MARKETPLACE_ACTIONS = "export" ] diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index b1f4f7469c..e95105b994 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -135,7 +135,7 @@ void OpenNebulaTemplate::set_multiple_conf_default() set_conf_ds("shared", "", "NO"); set_conf_ds("ssh", "", "NO"); set_conf_ds("vmfs", "BRIDGE_LIST", "NO"); - set_conf_ds("vcenter", "VCENTER_CLUSTER", "NO"); + set_conf_ds("vcenter", "VCENTER_ONE_HOST_ID, VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_CCR_REF", "NO"); set_conf_ds("ceph", "DISK_TYPE,BRIDGE_LIST,CEPH_HOST,CEPH_USER,CEPH_SECRET", "NO"); diff --git a/src/oca/java/test/oned.conf b/src/oca/java/test/oned.conf index c3da2c7945..f470141e1a 100644 --- a/src/oca/java/test/oned.conf +++ b/src/oca/java/test/oned.conf @@ -371,7 +371,7 @@ IM_MAD = [ # # type : driver type, supported drivers: xen, kvm, xml # -# keep_snapshots: do not remove snapshots on power on/off cycles and live +# keep_snapshots: do not remove snapshots on power on/off cycles and live # migrations if the hypervisor supports that. # # imported_vms_actions : comma-separated list of actions supported @@ -957,7 +957,9 @@ DS_MAD_CONF = [ ] DS_MAD_CONF = [ - NAME = "vcenter", REQUIRED_ATTRS = "VCENTER_CLUSTER", PERSISTENT_ONLY = "YES", + NAME = "vcenter", + REQUIRED_ATTRS = "VCENTER_ONE_HOST_ID, VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_CCR_REF", + PERSISTENT_ONLY = "YES", MARKETPLACE_ACTIONS = "export" ] From 862d54fb16b7746ed6be225b77069229461c953f Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 3 Mar 2017 13:33:27 +0100 Subject: [PATCH 125/297] F #4913: Replace remnants of VCENTER_DATASTORE with VCENTER_DS_REF --- src/oca/ruby/opennebula/virtual_machine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index 8f46d0a2e3..9952032902 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -354,7 +354,7 @@ module OpenNebula ds = OpenNebula::Datastore.new_with_id(ds_id, @client) rc = ds.info return rc if OpenNebula.is_error?(rc) - self.update("VCENTER_DATASTORE=#{ds['/DATASTORE/NAME']}", true) + self.update("VCENTER_DS_REF=#{ds['/DATASTORE/VCENTER_DS_REF']}", true) end return call(VM_METHODS[:deploy], From 918bce7733008a7f2a507b2a1add8eb44963696c Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 3 Mar 2017 13:38:10 +0100 Subject: [PATCH 126/297] F #4913: Initial support for importing disks from vcenter templates --- .../remotes/lib/vcenter_driver/datacenter.rb | 5 +- .../remotes/lib/vcenter_driver/datastore.rb | 38 ++++++ .../remotes/lib/vcenter_driver/importer.rb | 25 +++- .../lib/vcenter_driver/virtual_machine.rb | 109 +++++++++++++++++- 4 files changed, 167 insertions(+), 10 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb index cfc11e3e07..be14c09250 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datacenter.rb @@ -281,10 +281,7 @@ class DatacenterFolder end rp = rp_cache[template_ccr.name.to_s] - object = template.to_one_template(template_name, - template_ref, - template_ccr._ref, - cluster_name, + object = template.to_one_template(template, ds, ds_list, default_ds, diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index c628e5ffec..cb1906b9b9 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -68,6 +68,44 @@ class Storage end end + def self.get_image_import_template(ds_name, image_path, image_type, ipool) + one_image = "" + + # Remove ds info from path + image_path.sub!(/^\[#{ds_name}\] /, "") + + # Get image name + file_name = File.basename(image_path).reverse.sub("kdmv.","").reverse + image_name = "#{file_name} - #{ds_name}" + + #Chek if the image has already been imported + if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, + image_name, + ipool, + false).nil? + #Set template + one_image << "NAME=\"#{image_name}\"\n" + one_image << "PATH=\"vcenter://#{image_path}\"\n" + one_image << "TYPE=\"#{image_type}\"\n" + one_image << "PERSISTENT=\"NO\"\n" + one_image << "OPENNEBULA_MANAGED=\"YES\"\n" + end + + return one_image + end + + def self.get_one_image_ds_by_ref_and_ccr(ref, ccr_ref, vcenter_uuid, pool = nil) + pool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false) if pool.nil? + element = pool.select{|e| + e["TEMPLATE/TYPE"] == "IMAGE_DS" && + e["TEMPLATE/VCENTER_DS_REF"] == ref && + e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref && + e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid}.first rescue nil + + return element + end + + def monitor summary = self['summary'] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index 1c269500cc..b60f7279f1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -74,6 +74,13 @@ def self.import_templates(con_ops, options) STDOUT.print "done!\n" + # Create OpenNebula pools + dpool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool) + ipool = VCenterDriver::VIHelper.one_pool(OpenNebula::ImagePool) + + # Get vcenter intance uuid as moref is unique for each vcenter + vc_uuid = vi_client.vim.serviceContent.about.instanceUuid + rs.each {|dc, tmps| STDOUT.print "\nDo you want to process datacenter #{dc}"\ " (y/[n])? " @@ -95,7 +102,23 @@ def self.import_templates(con_ops, options) next if STDIN.gets.strip.downcase != 'y' +=begin + ## Add existing disks to template (OPENNEBULA_MANAGED) + template = t[:template] + + error, template_disks = template.import_vcenter_disks(vc_uuid, + dpool, + ipool) + if error.empty? + t[:one] << template_disks + else + STDOUT.puts error + next + end +=end + + # Datastore placement ds_input = "" STDOUT.print "\n This template is currently set to be "\ @@ -246,7 +269,7 @@ def self.import_templates(con_ops, options) end list_str = "\n [Index] Resource pool :"\ - "\n #{dashes}\n" + "\n #{dashes}\n" STDOUT.print list_str diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 00f0b53e10..b13a798b1c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -978,13 +978,104 @@ class VirtualMachine end end - # Checks if a RbVmomi::VIM::VirtualDevice is a disk + def get_vcenter_disks + disks = [] + self["config.hardware.device"].each do |device| + disk = {} + if is_disk_or_iso?(device) + disk[:datastore] = device.backing.datastore + disk[:path] = device.backing.fileName + disk[:type] = is_disk?(device) ? "OS" : "CDROM" + disks << disk + end + end + return disks + end + + def import_vcenter_disks(vc_uuid, dpool, ipool) + + disk_info = "" + error = "" + + ccr_ref = self["runtime.host.parent._ref"] + + #Get disks and info required + vc_disks = get_vcenter_disks + + # Track allocated images + allocated_images = [] + + vc_disks.each do |disk| + + datastore_found = VCenterDriver::Storage.get_one_image_ds_by_ref_and_ccr(disk[:datastore]._ref, + ccr_ref, + vc_uuid, + dpool) + if datastore_found.nil? + error = " Error datastore #{disk[:datastore].name}: has to be imported first as an image datastore!\n" + + #Rollback delete disk images + allocated_images.each do |i| + i.delete + end + + break + end + + image_template = VCenterDriver::Datastore.get_image_import_template(disk[:datastore].name, + disk[:path], + disk[:type], ipool) + if !image_template.empty? + # Then the image is created + one_i = VCenterDriver::VIHelper.new_one_item(OpenNebula::Image) + + allocated_images << one_i + + rc = one_i.allocate(image_template, datastore_found['ID'].to_i) + + if ::OpenNebula.is_error?(rc) + error = " Error creating disk from template: #{rc.message}. Cannot import the template\n" + + #Rollback delete disk images + allocated_images.each do |i| + i.delete + end + + break + end + + #Add info for One template + one_i.info + disk_info << "DISK=[\n" + disk_info << "IMAGE=\"#{one_i["NAME"]}\",\n" + disk_info << "IMAGE_UNAME=\"#{one_i["UNAME"]}\"\n" + disk_info << "]\n" + end + end + + return error, disk_info + + end + + # Checks if a RbVmomi::VIM::VirtualDevice is a disk or a cdrom def is_disk_or_cdrom?(device) is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? is_cdrom = !(device.class.ancestors.index(RbVmomi::VIM::VirtualCdrom)).nil? is_disk || is_cdrom end + # Checks if a RbVmomi::VIM::VirtualDevice is a disk or an iso file + def is_disk_or_iso?(device) + is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? + is_iso = device.backing.is_a? RbVmomi::VIM::VirtualCdromIsoBackingInfo + is_disk || is_iso + end + + # Checks if a RbVmomi::VIM::VirtualDevice is a disk + def is_disk?(device) + !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? + end + def find_free_controller(position=0) free_scsi_controllers = [] available_controller = nil @@ -1298,11 +1389,18 @@ class VirtualMachine return str end - def to_one_template(template_name, template_ref, template_ccr, cluster_name, - ds, ds_list, default_ds, rp, rp_list, vcenter_uuid) + def to_one_template(template, ds, ds_list, default_ds, + rp, rp_list, vcenter_uuid) + + template_name = template['name'] + template_ref = template['_ref'] + template_ccr = template['runtime.host.parent'] + cluster_name = template['runtime.host.parent.name'] + one_tmp = {} one_tmp[:name] = "#{template_name} - #{cluster_name}" - one_tmp[:vcenter_ccr_ref] = template_ccr + one_tmp[:template_name] = template_name + one_tmp[:vcenter_ccr_ref] = template_ccr._ref one_tmp[:one] = to_one(true) one_tmp[:vcenter_ref] = template_ref one_tmp[:vcenter_instance_uuid] = vcenter_uuid @@ -1311,7 +1409,8 @@ class VirtualMachine one_tmp[:ds_list] = ds_list one_tmp[:default_ds] = default_ds one_tmp[:rp] = rp - one_tmp[:rp_list] = rp_list + one_tmp[:rp_list] = rp_list + one_tmp[:template] = template return one_tmp end From 0dfdc9760d982066206d549ab836ecd69ff3ee56 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Fri, 3 Mar 2017 13:44:45 +0100 Subject: [PATCH 127/297] F #4913: Replace IMPORT_VM_ID uuid with vm moref --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b13a798b1c..c62d04a2dd 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1327,7 +1327,7 @@ class VirtualMachine "VCENTER_INSTANCE_ID =\"#{vc_uuid}\"\n" if !template - str << "IMPORT_VM_ID =\"#{self["config.uuid"]}\"\n" + str << "IMPORT_VM_ID =\"#{self["_ref"]}\"\n" str << "IMPORT_STATE =\"#{@state}\"\n" end From d3fddc83da6d38ed28999386cdf7115878bb6c31 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 08:30:25 +0100 Subject: [PATCH 128/297] F #4913: Replace VMM detach_disk action with dummy.sh --- src/vmm_mad/remotes/vcenter/detach_disk | 63 +------------------------ 1 file changed, 1 insertion(+), 62 deletions(-) mode change 100755 => 120000 src/vmm_mad/remotes/vcenter/detach_disk diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk deleted file mode 100755 index 9aa9fabeff..0000000000 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env ruby - -# ---------------------------------------------------------------------------- # -# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -# ---------------------------------------------------------------------------- # - -ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) - -if !ONE_LOCATION - RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) -else - RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) -end - -$: << RUBY_LIB_LOCATION -$: << File.dirname(__FILE__) - -require 'vcenter_driver' - -vm_ref = ARGV[0] -vc_cluster_name = ARGV[-1] - -drv_action_enc = STDIN.read.gsub("\n","") -drv_action = OpenNebula::XMLElement.new -drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'VMM_DRIVER_ACTION_DATA') - -# Get vc_cluster_name from driver action or stick with ARGV[0]? -host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) -host_id = host['ID'] - -begin - vi_client = VCenterDriver::VIClient.new_from_host(host_id) - - vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - - disks = drv_action.retrieve_xmlelements("VM/TEMPLATE/DISK[ATTACH='YES']") - - raise "Could not find a DISK element with ATTACH=YES" if disks.size == 0 - - raise "Found more than one DISK element with ATTACH=YES" if disks.size > 1 - - vm.detach_disk(disks.first) - -rescue Exception => e - STDERR.puts "Detach image for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ - "failed due to \"#{e.message}\"\n#{e.backtrace}" - exit -1 -ensure - vi_client.close_connection -end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk new file mode 120000 index 0000000000..300563f2ad --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -0,0 +1 @@ +../common/dummy.sh \ No newline at end of file From 0e55adba5daea73f7514e4248ffdf0ef27350af6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 08:32:30 +0100 Subject: [PATCH 129/297] F #4913: Replace VCENTER_PORTGRP_TYPE with VCENTER_PORTGROUP_TYPE --- src/vmm_mad/remotes/lib/vcenter_driver/network.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index 1e5ed7ae0e..3f0246634e 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -76,7 +76,7 @@ class Network template = "NAME=\"#{network_name} - #{ccr_name}\"\n"\ "BRIDGE=\"#{network_name}\"\n"\ "VN_MAD=\"dummy\"\n"\ - "VCENTER_PORTGRP_TYPE=\"#{network_type}\"\n"\ + "VCENTER_PORTGROUP_TYPE=\"#{network_type}\"\n"\ "VCENTER_NET_REF=\"#{network_ref}\"\n"\ "VCENTER_CCR_REF=\"#{ccr_ref}\"\n"\ "VCENTER_INSTANCE_ID=\"#{vcenter_uuid}\"\n" From db141b07697c5e2a94ac14580828045492aa487b Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 09:18:38 +0100 Subject: [PATCH 130/297] F #4913: Add VCENTER_ to some vcenter specific attributes. Replace deprecated toolsVersionStatus --- share/doc/xsd/oned.conf | 4 ++-- share/etc/oned.conf | 4 ++-- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/oca/java/test/oned.conf | 4 ++-- .../tabs/images-tab/form-panels/create-common.js | 6 +++--- src/tm_mad/vcenter/mkimage | 2 +- .../remotes/lib/vcenter_driver/virtual_machine.rb | 14 +++++++------- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/share/doc/xsd/oned.conf b/share/doc/xsd/oned.conf index f3086626f3..da228471c4 100644 --- a/share/doc/xsd/oned.conf +++ b/share/doc/xsd/oned.conf @@ -833,10 +833,10 @@ INHERIT_DATASTORE_ATTR = "GLUSTER_HOST" INHERIT_DATASTORE_ATTR = "GLUSTER_VOLUME" INHERIT_DATASTORE_ATTR = "DISK_TYPE" -INHERIT_DATASTORE_ATTR = "ADAPTER_TYPE" +INHERIT_DATASTORE_ATTR = "VCENTER_ADAPTER_TYPE" INHERIT_IMAGE_ATTR = "DISK_TYPE" -INHERIT_IMAGE_ATTR = "ADAPTER_TYPE" +INHERIT_IMAGE_ATTR = "VCENTER_ADAPTER_TYPE" INHERIT_VNET_ATTR = "VLAN_TAGGED_ID" INHERIT_VNET_ATTR = "FILTER_IP_SPOOFING" diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 86694cda24..f2121a5e86 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -886,11 +886,11 @@ INHERIT_DATASTORE_ATTR = "GLUSTER_HOST" INHERIT_DATASTORE_ATTR = "GLUSTER_VOLUME" INHERIT_DATASTORE_ATTR = "DISK_TYPE" -INHERIT_DATASTORE_ATTR = "ADAPTER_TYPE" +INHERIT_DATASTORE_ATTR = "VCENTER_ADAPTER_TYPE" INHERIT_DATASTORE_ATTR = "VCENTER_DS_REF" INHERIT_IMAGE_ATTR = "DISK_TYPE" -INHERIT_IMAGE_ATTR = "ADAPTER_TYPE" +INHERIT_IMAGE_ATTR = "VCENTER_ADAPTER_TYPE" INHERIT_VNET_ATTR = "VLAN_TAGGED_ID" INHERIT_VNET_ATTR = "FILTER_IP_SPOOFING" diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index b6c7f6244b..047e2a6f77 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -43,7 +43,7 @@ ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_ host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] -adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/ADAPTER_TYPE"] +adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE"] disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] fs_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/FSTYPE"] diff --git a/src/oca/java/test/oned.conf b/src/oca/java/test/oned.conf index f470141e1a..06abbbae09 100644 --- a/src/oca/java/test/oned.conf +++ b/src/oca/java/test/oned.conf @@ -833,10 +833,10 @@ INHERIT_DATASTORE_ATTR = "GLUSTER_HOST" INHERIT_DATASTORE_ATTR = "GLUSTER_VOLUME" INHERIT_DATASTORE_ATTR = "DISK_TYPE" -INHERIT_DATASTORE_ATTR = "ADAPTER_TYPE" +INHERIT_DATASTORE_ATTR = "VCENTER_ADAPTER_TYPE" INHERIT_IMAGE_ATTR = "DISK_TYPE" -INHERIT_IMAGE_ATTR = "ADAPTER_TYPE" +INHERIT_IMAGE_ATTR = "VCENTER_ADAPTER_TYPE" INHERIT_VNET_ATTR = "VLAN_TAGGED_ID" INHERIT_VNET_ATTR = "FILTER_IP_SPOOFING" diff --git a/src/sunstone/public/app/tabs/images-tab/form-panels/create-common.js b/src/sunstone/public/app/tabs/images-tab/form-panels/create-common.js index 88e33f7a6b..b79b159471 100644 --- a/src/sunstone/public/app/tabs/images-tab/form-panels/create-common.js +++ b/src/sunstone/public/app/tabs/images-tab/form-panels/create-common.js @@ -356,7 +356,7 @@ define(function(require) { ProgressBar.html(this.progress(), 1, fileName) ); }); } - + return false; } @@ -398,7 +398,7 @@ define(function(require) { result = ''; for( var index = 0; index < iterations; index++ ) { result += chars.charAt( Math.floor( Math.random() * chars.length ) ); - }; + }; return result; }; }; @@ -454,7 +454,7 @@ define(function(require) { if (adapter_type == "custom") { adapter_type = WizardFields.retrieveInput($('#custom_adapter_type', context)); } - img_json["ADAPTER_TYPE"] = adapter_type; + img_json["VCENTER_ADAPTER_TYPE"] = adapter_type; } switch ($('#src_path_select input:checked', context).val()){ diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 55b6bc61c9..5d233452d8 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -61,7 +61,7 @@ ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] # Get adapter and disk type one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) -adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/ADAPTER_TYPE"] +adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_ADAPTER_TYPE"] # TODO disk_type support, that info is not coming thin, thick... # disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/DISK_TYPE"] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index c62d04a2dd..d17939787e 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1574,7 +1574,7 @@ class VirtualMachine guest_state = self["guest.guestState"].to_s vmware_tools = self["guest.toolsRunningStatus"].to_s vmtools_ver = self["guest.toolsVersion"].to_s - vmtools_verst = self["guest.toolsVersionStatus"].to_s + vmtools_verst = self["guest.toolsVersionStatus2"].to_s str_info = "" @@ -1597,12 +1597,12 @@ class VirtualMachine str_info << "DISKRDIOPS=" << diskrdiops.to_s << " " str_info << "DISKWRIOPS=" << diskwriops.to_s << " " - str_info << "ESX_HOST=\"" << esx_host << "\" " - str_info << "GUEST_STATE=" << guest_state << " " - str_info << "VMWARETOOLS_RUNNING_STATUS=" << vmware_tools << " " - str_info << "VMWARETOOLS_VERSION=" << vmtools_ver << " " - str_info << "VMWARETOOLS_VERSION_STATUS=" << vmtools_verst << " " - str_info << "VCENTER_RP_REF=\"" << self["resourcePool"]._ref << "\" " + str_info << "VCENTER_ESX_HOST=\"" << esx_host << "\" " + str_info << "VCENTER_GUEST_STATE=" << guest_state << " " + str_info << "VCENTER_VMWARETOOLS_RUNNING_STATUS=" << vmware_tools << " " + str_info << "VCENTER_VMWARETOOLS_VERSION=" << vmtools_ver << " " + str_info << "VCENTER_VMWARETOOLS_VERSION_STATUS=" << vmtools_verst << " " + str_info << "VCENTER_RP_REF=\"" << self["resourcePool"]._ref << "\" " end def reset_monitor From 5de8b2fd83e8ecb15dd3650e3d8464d953ccfd83 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 09:33:44 +0100 Subject: [PATCH 131/297] F #4913: Replace ESX_HOST with VCENTER_ESX_HOST --- src/sunstone/OpenNebulaVNC.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sunstone/OpenNebulaVNC.rb b/src/sunstone/OpenNebulaVNC.rb index e0c82c909a..0932d3a08d 100644 --- a/src/sunstone/OpenNebulaVNC.rb +++ b/src/sunstone/OpenNebulaVNC.rb @@ -208,8 +208,8 @@ class OpenNebulaVNC vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT'] vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD'] - if vm_resource['MONITORING/ESX_HOST'] # It is behind a vCenter - host = vm_resource['MONITORING/ESX_HOST'] + if vm_resource['MONITORING/VCENTER_ESX_HOST'] # It is behind a vCenter + host = vm_resource['MONITORING/VCENTER_ESX_HOST'] end # Generate token random_str: host:port From 7749fd2f0bc073612d9dd43a36105cc6099177af Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 10:56:25 +0100 Subject: [PATCH 132/297] F #4913: Remove vm.destroy and deprecated detach disk from VMM shutdown --- src/vmm_mad/remotes/vcenter/shutdown | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 0367ff1a8a..337b9441fb 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -77,14 +77,9 @@ begin if keep_disks # Detach all disks from VM so they are not deleted if VM is destroyed vm.detach_all_disks - else - # Detach only DISK elements from template - disks.each do |disk| - vm.detach_disk(disk) - end end - # If the VM was instantiated to persistent keep the VM else destroy it + # If the VM was instantiated to persistent keep the VM if instantiate_to_persistent vm.mark_as_template #Convert VM to template in vCenter @@ -93,8 +88,6 @@ begin OpenNebula::Client.new) new_template.info new_template.update("VCENTER_TEMPLATE_REF= #{vm.item._ref}", true) - else - vm.destroy end end From 643e0440660163963f1893012e8cec55df422d0d Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 10:58:19 +0100 Subject: [PATCH 133/297] F #4913: Populate vm.one_item so VM ID is there when getting image file names to be removed --- src/tm_mad/vcenter/delete | 1 + src/tm_mad/vcenter/mvds | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index d71bfd8f5a..a3938ef685 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -81,6 +81,7 @@ if path.match(/disk\.\d+$/) begin # TODO: if the deploy has failed, the disks may exist, but the vm may # not exist... + vm.one_item = one_vm # detach the disk vm.detach_disk(disk) diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds index 85b2e5b683..183d46dd1e 100755 --- a/src/tm_mad/vcenter/mvds +++ b/src/tm_mad/vcenter/mvds @@ -63,6 +63,8 @@ begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + vm.one_item = one_vm + vm.detach_disk(disk) rescue Exception => e STDERR.puts "Error detaching virtual disk #{img_path} from vm #{vmid}."\ From e7c5228f10b98d44d5d0dab0ac96887751f35d1b Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 6 Mar 2017 11:01:44 +0100 Subject: [PATCH 134/297] F #4913: Fix disk_attached_to_vm --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index d17939787e..e7829d77e3 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -890,7 +890,7 @@ class VirtualMachine d.backing.fileName == "[#{ds_name}] #{img_name}" end rescue nil - return nil if device.empty? + return nil if device.nil? return device.first end From 2286c74f33e220ee9aecdb93ff54089153f4e078 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 7 Mar 2017 08:26:54 +0100 Subject: [PATCH 135/297] F #4913: Add VCENTER_DISK_TYPE attribute --- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/tm_mad/vcenter/mkimage | 5 ++--- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 047e2a6f77..c6b4e2e0da 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -44,7 +44,7 @@ host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE"] -disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/DISK_TYPE"] +disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_DISK_TYPE"] size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] fs_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/FSTYPE"] diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index 5d233452d8..b5b2d74c3e 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -64,9 +64,8 @@ one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_ADAPTER_TYPE"] # TODO disk_type support, that info is not coming thin, thick... -# disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/DISK_TYPE"] -# disk_type = "thin" if disk_type.nil? || disk_type.empty? -disk_type = "thin" +disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_DISK_TYPE"] +disk_type = "thin" if disk_type.nil? || disk_type.empty? check_valid adapter_type, "adapter_type" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index cb1906b9b9..d6f05fb365 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -510,7 +510,7 @@ class Datastore < Storage one_image << "PATH=\"vcenter://#{image_path}\"\n" one_image << "PERSISTENT=\"YES\"\n" one_image << "TYPE=\"#{image_type}\"\n" - one_image << "DISK_TYPE=\"#{disk_type}\"\n" if disk_type + one_image << "VCENTER_DISK_TYPE=\"#{disk_type}\"\n" if disk_type if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, "#{image_name} - #{ds_name}", From ced4d2748ea973dfb9cc3542016a7332724f5fc5 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 7 Mar 2017 12:39:56 +0100 Subject: [PATCH 136/297] F #4913: Fix some install files --- install.sh | 5 ++++- src/tm_mad/vcenter/monitor | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) create mode 120000 src/tm_mad/vcenter/monitor diff --git a/install.sh b/install.sh index 6ce5048f08..9c088b5349 100755 --- a/install.sh +++ b/install.sh @@ -1010,7 +1010,10 @@ TM_VCENTER_FILES="src/tm_mad/vcenter/clone \ src/tm_mad/vcenter/snap_delete \ src/tm_mad/vcenter/snap_revert \ src/tm_mad/vcenter/failmigrate \ - src/datastore_mad/remotes/vcenter/monitor \ + src/tm_mad/vcenter/context \ + src/tm_mad/vcenter/monitor \ + src/tm_mad/vcenter/mkimage \ + src/tm_mad/vcenter/mkswap \ src/tm_mad/vcenter/delete" TM_ISCSI_FILES="src/tm_mad/iscsi_libvirt/clone \ diff --git a/src/tm_mad/vcenter/monitor b/src/tm_mad/vcenter/monitor new file mode 120000 index 0000000000..5476120435 --- /dev/null +++ b/src/tm_mad/vcenter/monitor @@ -0,0 +1 @@ +../../datastore_mad/remotes/vcenter/monitor \ No newline at end of file From b39768ec65c75b13d715f5ffc5b50ac4ae933e3e Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 7 Mar 2017 12:40:09 +0100 Subject: [PATCH 137/297] F #4913: style --- src/nebula/NebulaTemplate.cc | 4 +++- .../remotes/lib/vcenter_driver/datastore.rb | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index e95105b994..d53d4ed4de 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -135,7 +135,9 @@ void OpenNebulaTemplate::set_multiple_conf_default() set_conf_ds("shared", "", "NO"); set_conf_ds("ssh", "", "NO"); set_conf_ds("vmfs", "BRIDGE_LIST", "NO"); - set_conf_ds("vcenter", "VCENTER_ONE_HOST_ID, VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_CCR_REF", "NO"); + set_conf_ds("vcenter", + "VCENTER_ONE_HOST_ID, VCENTER_INSTANCE_ID, VCENTER_DS_REF, VCENTER_CCR_REF", + "NO"); set_conf_ds("ceph", "DISK_TYPE,BRIDGE_LIST,CEPH_HOST,CEPH_USER,CEPH_SECRET", "NO"); diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index d6f05fb365..a3deadccce 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -96,11 +96,12 @@ class Storage def self.get_one_image_ds_by_ref_and_ccr(ref, ccr_ref, vcenter_uuid, pool = nil) pool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false) if pool.nil? - element = pool.select{|e| - e["TEMPLATE/TYPE"] == "IMAGE_DS" && - e["TEMPLATE/VCENTER_DS_REF"] == ref && - e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref && - e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid}.first rescue nil + element = pool.select do |e| + e["TEMPLATE/TYPE"] == "IMAGE_DS" && + e["TEMPLATE/VCENTER_DS_REF"] == ref && + e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref && + e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid + end.first rescue nil return element end @@ -118,11 +119,12 @@ class Storage def self.exists_one_by_ref_ccr_and_type?(ref, ccr_ref, vcenter_uuid, type, pool = nil) pool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool, false) if pool.nil? - elements = pool.select{|e| + elements = pool.select do |e| e["TEMPLATE/TYPE"] == type && e["TEMPLATE/VCENTER_DS_REF"] == ref && e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref && - e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid} + e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid + end return elements.size == 1 end From 88e00c610b78285278d6a9d251d575d3477e5f0f Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Tue, 7 Mar 2017 12:40:36 +0100 Subject: [PATCH 138/297] F #4913: clearer code --- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index a3deadccce..7e9b098a16 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -75,7 +75,7 @@ class Storage image_path.sub!(/^\[#{ds_name}\] /, "") # Get image name - file_name = File.basename(image_path).reverse.sub("kdmv.","").reverse + file_name = File.basename(image_path).gsub(/\.vmdk$/,"") image_name = "#{file_name} - #{ds_name}" #Chek if the image has already been imported From aa300e2b95d857999237a2aa1e43a906f9c44a61 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 7 Mar 2017 13:42:30 +0100 Subject: [PATCH 139/297] F #4913: Fix contextualization info was not enconded using Base64 --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index e7829d77e3..3d020760d9 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -472,7 +472,8 @@ class VirtualMachine # context_text [ - { :key => "guestinfo.opennebula.context", :value => context_text } + { :key => "guestinfo.opennebula.context", + :value => Base64.encode64(context_text) } ] end From 99f1c88d408b81629a8258ff8e77931b739d7dd6 Mon Sep 17 00:00:00 2001 From: Jaime Melis Date: Wed, 8 Mar 2017 10:06:36 +0100 Subject: [PATCH 140/297] F #4913: oneimage create now supports adapter_type and disk_type for vcenter --- src/cli/one_helper/oneimage_helper.rb | 41 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/cli/one_helper/oneimage_helper.rb b/src/cli/one_helper/oneimage_helper.rb index 18f68e2a67..955df981e3 100644 --- a/src/cli/one_helper/oneimage_helper.rb +++ b/src/cli/one_helper/oneimage_helper.rb @@ -103,14 +103,22 @@ class OneImageHelper < OpenNebulaHelper::OneHelper :name => "disk_type", :large => "--disk_type disk_type", :description => "Type of the image \n"<< - " "*31<<"for KVM: BLOCK, CDROM, RBD or FILE \n"<< - " "*31<<"for vCenter: THIN, TICHK, ZEOREDTHICK " << + " " * 31 << "BLOCK, CDROM, RBD or FILE \n" << "(for others, check the documentation) ", :format => String }, { - :name => "adapter_type", - :large => "--adapter_type adapter_type", + :name => "vcenter_disk_type", + :large => "--vcenter_disk_type vcenter_disk_type", + :description => "The vCenter Disk Type of the image \n"<< + " " * 31 << + "for vCenter: THIN, THICK, ZEROEDTHICK " << + "(for others, check the documentation) ", + :format => String + }, + { + :name => "vcenter_adapter_type", + :large => "--vcenter_adapter_type vcenter_adapter_type", :description => "Controller that will handle this image in " << "vCenter (lsiLogic, ide, busLogic). For other "<< "values check the documentation", @@ -358,16 +366,16 @@ class OneImageHelper < OpenNebulaHelper::OneHelper end def self.create_image_variables(options, name) - if Array===name - names=name + if Array === name + names = name else - names=[name] + names = [name] end - t='' + t = '' names.each do |n| if options[n] - t<<"#{n.to_s.upcase}=\"#{options[n]}\"\n" + t << "#{n.to_s.upcase}=\"#{options[n]}\"\n" end end @@ -375,16 +383,21 @@ class OneImageHelper < OpenNebulaHelper::OneHelper end def self.create_image_template(options) - template_options=TEMPLATE_OPTIONS.map do |o| + template_options = TEMPLATE_OPTIONS.map do |o| o[:name].to_sym end - template=create_image_variables( - options, template_options-[:persistent, :dry, :prefix]) + template = create_image_variables( + options, + template_options - [:persistent, :dry, :prefix ] + ) + + if options[:persistent] + template << "PERSISTENT=YES\n" + end - template<<"PERSISTENT=YES\n" if options[:persistent] if options[:prefix] - template<<"DEV_PREFIX=\"#{options[:prefix]}\"\n" + template << "DEV_PREFIX=\"#{options[:prefix]}\"\n" end [0, template] From 9b4f24c7e35b5820eba17007e8aac75c95da8be2 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 8 Mar 2017 10:56:21 +0100 Subject: [PATCH 141/297] F #4913: Don't raise exception if device is not found in vcenter's vm when detaching a disk --- .../lib/vcenter_driver/virtual_machine.rb | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 3d020760d9..dacf92c74b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -835,24 +835,24 @@ class VirtualMachine end end - # Detach DISK from VM (hotplug) + # Detach DISK from VM def detach_disk(disk) spec_hash = {} - # Check if disk being detached is connected to the VM + # Get vcenter device to be detached and remove if found device = disk_attached_to_vm(disk) - raise "DISK is not connected to VM" if device.nil? + if device + # Generate vCenter spec and reconfigure VM + spec_hash[:deviceChange] = [{ + :operation => :remove, + :device => device + }] - # Generate vCenter spec and reconfigure VM - spec_hash[:deviceChange] = [{ - :operation => :remove, - :device => device - }] - - begin - @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion - rescue Exception => e - raise "Cannot detach DISK from VM: #{e.message}\n#{e.backtrace}" + begin + @item.ReconfigVM_Task(:spec => spec_hash).wait_for_completion + rescue Exception => e + raise "Cannot detach DISK from VM: #{e.message}\n#{e.backtrace}" + end end end From c25a863c252333aa9578190c1bf603dcb08e59cc Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 9 Mar 2017 09:52:17 +0100 Subject: [PATCH 142/297] F #4913: Get vcenter adapter and disk types from defaults file if attributes missing in driver action --- src/datastore_mad/remotes/vcenter/mkfs | 6 ++++-- src/tm_mad/vcenter/mkimage | 10 +++++----- .../remotes/lib/vcenter_driver/vi_helper.rb | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index c6b4e2e0da..6f13b90708 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -43,8 +43,10 @@ ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_ host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] ds_image_dir = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_IMAGE_DIR"] || "one" img_id = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/ID"] -adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE"] -disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_DISK_TYPE"] +adapter_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE"] || + VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE") +disk_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_DISK_TYPE"] || + VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/VCENTER_DISK_TYPE") size = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SIZE"] fs_type = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/FSTYPE"] diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index b5b2d74c3e..a1902dca45 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -61,13 +61,13 @@ ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] # Get adapter and disk type one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) -adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_ADAPTER_TYPE"] - -# TODO disk_type support, that info is not coming thin, thick... -disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_DISK_TYPE"] -disk_type = "thin" if disk_type.nil? || disk_type.empty? +adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_ADAPTER_TYPE"] || + VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE") +disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_DISK_TYPE"] || + VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/VCENTER_DISK_TYPE") check_valid adapter_type, "adapter_type" +check_valid disk_type, "disk_type" begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb index ff8383c680..81a9ef153d 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb @@ -1,6 +1,10 @@ module VCenterDriver class VIHelper + + ETC_LOCATION = "/etc/one/" if !defined?(ETC_LOCATION) + VCENTER_DRIVER_DEFAULT = "#{ETC_LOCATION}/vcenter_driver.default" + def self.client @@client ||= OpenNebula::Client.new end @@ -54,6 +58,16 @@ class VIHelper return element end + def self.get_default(xpath) + begin + xml = OpenNebula::XMLElement.new + xml.initialize_xml(File.read(VCENTER_DRIVER_DEFAULT), 'VCENTER') + return xml[xpath] + rescue + return nil + end + end + end # class VIHelper end # module VCenterDriver From c159d840d3a120226261f82b0bda39b4d5fbf33d Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 9 Mar 2017 09:52:58 +0100 Subject: [PATCH 143/297] F #4913: Fix wrong state for disk-saveas use LCM_STATE instead --- src/tm_mad/vcenter/cpds | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index e9d32774f9..2ab65c49bd 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -59,7 +59,7 @@ host_id = host['ID'] one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") src_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid) -if one_vm.state == 3 +if one_vm['LCM_STATE'] == 26 #ACTIVE / HOTPLUG_SAVEAS STDERR.puts "'disk-saveas' operation is not supported for running VMs." exit 1 end @@ -80,8 +80,7 @@ begin target_ds_name_vc = target_ds_vc['name'] - source_ds_vc.copy_virtual_disk(src_path, source_ds, - target_path, target_ds_name_vc) + source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) rescue Exception => e STDERR.puts "Error copying img #{src_path}. "\ From 49c917a2f38ad083edfb091a065c6681850da2c6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 9 Mar 2017 09:53:45 +0100 Subject: [PATCH 144/297] F #4913: Fix attach / detach NIC use driver_action info --- src/vmm_mad/remotes/vcenter/attach_nic | 15 ++------------- src/vmm_mad/remotes/vcenter/detach_nic | 9 ++++++--- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 9ba0b4cb48..7745e8e4be 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -30,16 +30,11 @@ $: << File.dirname(__FILE__) require 'vcenter_driver' vm_ref = ARGV[0] -mac = ARGV[1] -bridge = ARGV[2] -model = ARGV[3] vc_cluster_name = ARGV[-1] drv_action = OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VMM_DRIVER_ACTION_DATA') -vm_xml = drv_action.retrieve_xmlelements("VM").first - host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) host_id = host['ID'] @@ -49,15 +44,9 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) # Setting one_item with info with the vm_xml including NIC to be added - vm.one_item = vm_xml + vm.one_item = drv_action.retrieve_xmlelements("VM").first - nic = { - "MAC" => mac, - "BRIDGE" => bridge, - "MODEL" => model - } - - vm.attach_nic(nic) + vm.attach_nic rescue Exception => e STDERR.puts "Attach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index bf9efba2b4..cac7e8219d 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -30,9 +30,11 @@ $: << File.dirname(__FILE__) require 'vcenter_driver' vm_ref = ARGV[0] -mac = ARGV[1] vc_cluster_name = ARGV[3] +drv_action = OpenNebula::XMLElement.new +drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VMM_DRIVER_ACTION_DATA') + host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) host_id = host['ID'] @@ -41,9 +43,10 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - nic = { "MAC" => mac } + # Setting one_item with info with the vm_xml including NIC to be added + vm.one_item = drv_action.retrieve_xmlelements("VM").first - vm.detach_nic(nic) + vm.detach_nic rescue Exception => e STDERR.puts "Detach NIC for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ From 4afddb837974f923e20da9d1b1899a0344c1d634 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 9 Mar 2017 09:54:12 +0100 Subject: [PATCH 145/297] F #4913: Fix style --- src/vmm_mad/remotes/vcenter/cancel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index d7495134c1..250781011a 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -29,7 +29,7 @@ $: << File.dirname(__FILE__) require 'vcenter_driver' -vm_ref = ARGV[0] +vm_ref = ARGV[0] host = ARGV[1] vm_id = ARGV[-2] From 0063235e87f0e3f99122f0955f62d5b373692443 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 9 Mar 2017 09:54:50 +0100 Subject: [PATCH 146/297] F #4913: Add running info to VM after resume --- src/vmm_mad/remotes/vcenter/restore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index 6bd7441d8a..d1a01595e3 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -42,6 +42,8 @@ begin vm.poweron + vm.set_running(true) + rescue Exception => e STDERR.puts "Restore of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ From d357afee8d3b6e0a0b39568b38bf08849db7b07a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 9 Mar 2017 09:55:15 +0100 Subject: [PATCH 147/297] F #4913: Fix attach nic and attach disk issues --- .../lib/vcenter_driver/virtual_machine.rb | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index dacf92c74b..6be3fa3901 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -583,10 +583,10 @@ class VirtualMachine # Returns an array of actions to be included in :deviceChange def calculate_add_nic_spec(nic) - #TODO include VCENTER_NET_REF usage it should be in one_item + #TODO include VCENTER_NET_MODEL usage it should be in one_item mac = nic["MAC"] bridge = nic["BRIDGE"] - model = nic["MODEL"] + model = nic["VCENTER_NET_MODEL"] vnet_ref = nic["VCENTER_NET_REF"] backing = nil @@ -686,9 +686,12 @@ class VirtualMachine end # Add NIC to VM - def attach_nic(nic) - + def attach_nic spec_hash = {} + nic = nil + + # Extract nic from driver action + nic = one_item.retrieve_xmlelements("TEMPLATE/NIC[ATTACH='YES']").first # A new NIC requires a vcenter spec attach_nic_array = [] @@ -726,9 +729,12 @@ class VirtualMachine end # Detach NIC from VM - def detach_nic(nic) - + def detach_nic spec_hash = {} + nic = nil + + # Extract nic from driver action + nic = one_item.retrieve_xmlelements("TEMPLATE/NIC[ATTACH='YES']").first mac = nic["MAC"] @@ -800,7 +806,7 @@ class VirtualMachine position = 0 attach_disk_array = [] disks.each do |disk| - attach_disk_array << calculate_add_disk_spec(disk) + attach_disk_array << calculate_add_disk_spec(disk, position) position += 1 end @@ -1093,7 +1099,7 @@ class VirtualMachine used_numbers << dev.scsiCtlrUnitNumber scsi_schema[dev.key][:device] = dev - end + end next if dev.class != RbVmomi::VIM::VirtualDisk used_numbers << dev.unitNumber From 0f51b47b1bd711307e37b2bc8c37da6f11b31005 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 13 Mar 2017 09:54:36 +0100 Subject: [PATCH 148/297] F #4913: Fix shutdown, fix disk_attached_to_vm, add has_snpashots? --- .../lib/vcenter_driver/virtual_machine.rb | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 6be3fa3901..8c340a68db 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -781,7 +781,7 @@ class VirtualMachine def device_change_disks disks = [] - one_item.each("TEMPLATE/DISK") { |disk| disks << disk } + one_item.each("TEMPLATE/DISK") { |disk| disks << disk if !disk["OPENNEBULA_MANAGED"] } if !is_new? self["config.hardware.device"].each do |d| @@ -891,15 +891,25 @@ class VirtualMachine ds = get_effective_ds(disk) ds_name = ds['name'] - device = self["config.hardware.device"].select do |d| - is_disk_or_cdrom?(d) && - d.backing.respond_to?(:fileName) && - d.backing.fileName == "[#{ds_name}] #{img_name}" - end rescue nil + device_found = nil + self["config.hardware.device"].each do |d| + if is_disk_or_cdrom?(d) + backing = d.backing - return nil if device.nil? + # Backing may be a delta disk (snapshots) + while backing.respond_to?(:parent) + break if backing.parent.nil? + backing = backing.parent + end - return device.first + if backing.respond_to?(:fileName) && backing.fileName == "[#{ds_name}] #{img_name}" + device_found = d + break + end + end + end + + return device_found end def calculate_add_disk_spec(disk, position=0) @@ -985,6 +995,10 @@ class VirtualMachine end end + def has_snapshots? + self['rootSnapshot'] && !self['rootSnapshot'].empty? + end + def get_vcenter_disks disks = [] self["config.hardware.device"].each do |device| @@ -1235,7 +1249,7 @@ class VirtualMachine if i.name == snap_id.to_s return i.snapshot elsif !i.childSnapshotList.empty? - snap = find_snapshot(i.childSnapshotList, snap_id) + snap = find_snapshot_in_list(i.childSnapshotList, snap_id) return snap if snap end end rescue nil @@ -1248,13 +1262,15 @@ class VirtualMachine ############################################################################ def shutdown - # Ignore ShutdownGuest exceptions, maybe VM hasn't openvm tools - @item.ShutdownGuest rescue nil - - # Check if VM has been powered off - (0..VM_SHUTDOWN_TIMEOUT).each do - break if @item.runtime.powerState == "poweredOff" - sleep 1 + begin + @item.ShutdownGuest + # Check if VM has been powered off + (0..VM_SHUTDOWN_TIMEOUT).each do + break if @item.runtime.powerState == "poweredOff" + sleep 1 + end + rescue + # Ignore ShutdownGuest exceptions, maybe VM hasn't openvm tools end # If VM hasn't been powered off, do it now From 50ab75276dd040314791d91c04ec1c0df620b1d6 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 13 Mar 2017 09:57:06 +0100 Subject: [PATCH 149/297] F #4913: Add system snapshots limitations. --- src/tm_mad/vcenter/cpds | 11 +++- src/tm_mad/vcenter/delete | 21 ++++---- src/tm_mad/vcenter/mvds | 2 +- src/vmm_mad/remotes/vcenter/detach_disk | 56 ++++++++++++++++++++- src/vmm_mad/remotes/vcenter/snapshot_create | 19 +++++-- 5 files changed, 94 insertions(+), 15 deletions(-) mode change 120000 => 100755 src/vmm_mad/remotes/vcenter/detach_disk diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index 2ab65c49bd..d82527ffb5 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -55,10 +55,12 @@ hostname, src_path = src.split ":" host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) host_id = host['ID'] -# Get OpenNebula VM +# Get OpenNebula VM (state, disks and deploy_id) one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") src_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid) +vm_ref = one_vm['DEPLOY_ID'] + if one_vm['LCM_STATE'] == 26 #ACTIVE / HOTPLUG_SAVEAS STDERR.puts "'disk-saveas' operation is not supported for running VMs." exit 1 @@ -74,6 +76,13 @@ target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + if vm.has_snapshots? + STDERR.puts "'disk-saveas' operation is not supported for VMs with system snapshots." + exit 1 + end + source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index a3938ef685..bf233dd88d 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -79,16 +79,19 @@ if path.match(/disk\.\d+$/) img_path = VCenterDriver::FileHelper.get_img_name(disk, vmid) begin - # TODO: if the deploy has failed, the disks may exist, but the vm may - # not exist... - vm.one_item = one_vm + if !vm.has_snapshots? + # TODO: if the deploy has failed, the disks may exist, but the vm may + # not exist... + vm.one_item = one_vm - # detach the disk - vm.detach_disk(disk) + # detach the disk + vm.detach_disk(disk) + + # delete the disk + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + ds.delete_virtual_disk(img_path) + end - # delete the disk - ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - ds.delete_virtual_disk(img_path) rescue Exception => e STDERR.puts "Error delete virtual disk #{img_path} in datastore #{dsid}."\ " Reason: #{e.message}\n#{e.backtrace}" @@ -100,7 +103,7 @@ else # Remove the VM begin # All OpenNebula managed disks have been detached. The VM may have still - # disks that belong to the template (VCENTER_MANAGED disks). These disks + # disks that belong to the template (OPENNEBULA_MANAGED disks). These disks # will be deleted with the destroy operation. If the user wants to # save them to a VM, it can be done using the disk-saveas operation. vm.destroy diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds index 183d46dd1e..db7dbf0a8d 100755 --- a/src/tm_mad/vcenter/mvds +++ b/src/tm_mad/vcenter/mvds @@ -65,7 +65,7 @@ begin vm.one_item = one_vm - vm.detach_disk(disk) + vm.detach_disk(disk) if !vm.has_snapshots? rescue Exception => e STDERR.puts "Error detaching virtual disk #{img_path} from vm #{vmid}."\ " Reason: #{e.message}\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk deleted file mode 120000 index 300563f2ad..0000000000 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ /dev/null @@ -1 +0,0 @@ -../common/dummy.sh \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk new file mode 100755 index 0000000000..cca347af8e --- /dev/null +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) +end + +$: << RUBY_LIB_LOCATION +$: << File.dirname(__FILE__) + +require 'vcenter_driver' + +vm_ref = ARGV[0] +vc_cluster_name = ARGV[-1] + +drv_action = OpenNebula::XMLElement.new +drv_action.initialize_xml(Base64.decode64(STDIN.read), 'VMM_DRIVER_ACTION_DATA') + +host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, vc_cluster_name) +host_id = host['ID'] + +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) + + raise "vCenter doesn't allow to remove a virtual disk if it's part of a "\ + "snapshot of the virtual machine." if vm.has_snapshots? + +rescue Exception => e + STDERR.puts "Detach DISK for VM #{vm_ref} on vCenter cluster #{vc_cluster_name} "\ + "failed due to \"#{e.message}\"\n#{e.backtrace}" + exit -1 +ensure + vi_client.close_connection +end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 2e3884899b..4ee862ca21 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -46,13 +46,26 @@ begin vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) - vm.create_snapshot(snap_id, snap_name) + one_vm = drv_action.retrieve_xmlelements("VM").first + + vm.one_item = one_vm + + persistent_disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[PERSISTENT=YES]") + + if !persistent_disks.empty? + STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ + "#{vc_cluster_name} cannot be performed if "\ + "it contains persistent disks" + exit 1 + end + + puts vm.create_snapshot(snap_id, snap_name) rescue Exception => e STDERR.puts "Snapshot of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ "\"#{e.message}\"\n#{e.backtrace}" - exit(-1) + exit -1 ensure vi_client.close_connection -end +end \ No newline at end of file From b951b212acdda01f9bf1741de8941746dd423763 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 08:31:21 +0100 Subject: [PATCH 150/297] F #4913: Fix some image files not found in import --- .../remotes/lib/vcenter_driver/datastore.rb | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 7e9b098a16..7557f25357 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -487,47 +487,52 @@ class Datastore < Storage SearchDatastoreSubFolders_Task(search_params) search_task.wait_for_completion - search_task.info.result.each { |image| + search_task.info.result.each do |result| + folderpath = "" - if image.folderPath[-1] != "]" - folderpath = image.folderPath.sub(/^\[#{ds_name}\] /, "") + if result.folderPath[-1] != "]" + folderpath = result.folderPath.sub(/^\[#{ds_name}\] /, "") end - image = image.file.first - # Skip not relevant files - next if !img_types.include? image.class.to_s - # Get image path and name - image_path = folderpath - image_path << image.path - image_name = File.basename(image.path).reverse.sub("kdmv.","").reverse + result.file.each do |image| - # Get image and disk type - image_type = image.class.to_s == "VmDiskFileInfo" ? "OS" : "CDROM" - disk_type = image.class.to_s == "VmDiskFileInfo" ? image.diskType : nil + image_path = "" - #Set template - one_image = "NAME=\"#{image_name} - #{ds_name}\"\n" - one_image << "PATH=\"vcenter://#{image_path}\"\n" - one_image << "PERSISTENT=\"YES\"\n" - one_image << "TYPE=\"#{image_type}\"\n" - one_image << "VCENTER_DISK_TYPE=\"#{disk_type}\"\n" if disk_type + # Skip not relevant files + next if !img_types.include? image.class.to_s - if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, - "#{image_name} - #{ds_name}", - ipool, - false).nil? - img_templates << { - :name => "#{image_name} - #{ds_name}", - :path => image_path, - :size => (image.fileSize / 1024).to_s, - :type => image.class.to_s, - :dsid => ds_id, - :one => one_image - } + # Get image path and name + image_path << folderpath << image.path + image_name = File.basename(image.path).reverse.sub("kdmv.","").reverse + + # Get image and disk type + image_type = image.class.to_s == "VmDiskFileInfo" ? "OS" : "CDROM" + disk_type = image.class.to_s == "VmDiskFileInfo" ? image.diskType : nil + + #Set template + one_image = "NAME=\"#{image_name} - #{ds_name}\"\n" + one_image << "PATH=\"vcenter://#{image_path}\"\n" + one_image << "PERSISTENT=\"YES\"\n" + one_image << "TYPE=\"#{image_type}\"\n" + one_image << "VCENTER_DISK_TYPE=\"#{disk_type}\"\n" if disk_type + + if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, + "#{image_name} - #{ds_name}", + ipool, + false).nil? + img_templates << { + :name => "#{image_name} - #{ds_name}", + :path => image_path, + :size => (image.fileSize / 1024).to_s, + :type => image.class.to_s, + :dsid => ds_id, + :one => one_image + } + end end - } + end rescue raise "Could not find images." From 681e922e346a36118643162f826aaa9554152b22 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 08:34:15 +0100 Subject: [PATCH 151/297] F #4913: Add --use-defaults flag to import actions --- src/cli/onevcenter | 19 +- .../remotes/lib/vcenter_driver/importer.rb | 448 ++++++++++-------- 2 files changed, 257 insertions(+), 210 deletions(-) diff --git a/src/cli/onevcenter b/src/cli/onevcenter index cfc4ff5c3d..2f9ea7862f 100755 --- a/src/cli/onevcenter +++ b/src/cli/onevcenter @@ -93,6 +93,13 @@ cmd=CommandParser::CmdParser.new(ARGV) do :format => String } + USE_DEFAULTS = { + :name => "defaults", + :large => "--use-defaults", + :description => "Use defaults for answers to questions", + :format => String + } + ############################################################################ # Import clusters ############################################################################ @@ -100,7 +107,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Import vCenter clusters as OpenNebula hosts EOT - command :hosts, hosts_desc, :options=>[ VCENTER, USER, PASS ] do + command :hosts, hosts_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do con_ops = connection_options("Hosts", options) VCenterDriver::Importer.import_clusters(con_ops, options) @@ -115,7 +122,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Import vCenter VM Templates into OpenNebula EOT - command :templates, templates_desc, :options=>[ VCENTER, USER, PASS ] do + command :templates, templates_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do con_ops = connection_options("VM Templates", options) VCenterDriver::Importer.import_templates(con_ops, options) @@ -130,7 +137,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Deprecated action in onevcenter, please use onehost importvm instead EOT - command :vms, vms_desc, :options=>[ VCENTER, USER, PASS ] do + command :vms, vms_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do STDERR.puts "Deprecated action in onevcenter, please use onehost "\ "importvm instead" exit -1 @@ -143,7 +150,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Import vCenter networks into OpenNebula EOT - command :networks, network_desc, :options=>[ VCENTER, USER, PASS ] do + command :networks, network_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do con_ops = connection_options("Networks", options) VCenterDriver::Importer.import_networks(con_ops, options) @@ -158,7 +165,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Import vCenter Datastores into OpenNebula EOT - command :datastores, datastores_desc, :options=>[ VCENTER, USER, PASS ] do + command :datastores, datastores_desc, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do con_ops = connection_options("Datastores", options) VCenterDriver::Importer.import_datastore(con_ops, options) @@ -173,7 +180,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do Import vCenter Images into OpenNebula EOT - command :images, images_desc, :ds_name, :options=>[ VCENTER, USER, PASS ] do + command :images, images_desc, :ds_name, :options=>[ VCENTER, USER, PASS, USE_DEFAULTS ] do ds_name = args[0] if !ds_name diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index b60f7279f1..bba1702249 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -6,6 +6,8 @@ def self.import_clusters(con_ops, options) begin STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + use_defaults = options.key?(:defaults) + vi_client = VCenterDriver::VIClient.new(con_ops) STDOUT.print "done!\n\n" @@ -25,9 +27,11 @@ def self.import_clusters(con_ops, options) STDOUT.print "done!\n\n" rs.each {|dc, clusters| - STDOUT.print "Do you want to process datacenter #{dc} (y/[n])? " - next if STDIN.gets.strip.downcase != 'y' + if !use_defaults + STDOUT.print "Do you want to process datacenter #{dc} (y/[n])? " + next if STDIN.gets.strip.downcase != 'y' + end if clusters.empty? STDOUT.puts " No new clusters found in #{dc}..." @@ -35,14 +39,15 @@ def self.import_clusters(con_ops, options) end clusters.each{ |cluster| - STDOUT.print " * Import cluster #{cluster[:cluster_name]} (y/[n])? " - - next if STDIN.gets.strip.downcase != 'y' + if !use_defaults + STDOUT.print " * Import cluster #{cluster[:cluster_name]} (y/[n])? " + next if STDIN.gets.strip.downcase != 'y' + end one_host = VCenterDriver::ClusterComputeResource.to_one(cluster, con_ops) - STDOUT.puts " OpenNebula host #{cluster[:cluster_name]} with "\ + STDOUT.puts " OpenNebula host #{cluster[:cluster_name]} with"\ " id #{one_host.id} successfully created." STDOUT.puts } @@ -62,6 +67,8 @@ def self.import_templates(con_ops, options) begin STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + use_defaults = options.key?(:defaults) + vi_client = VCenterDriver::VIClient.new(con_ops) STDOUT.print "done!\n\n" @@ -82,10 +89,13 @@ def self.import_templates(con_ops, options) vc_uuid = vi_client.vim.serviceContent.about.instanceUuid rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc}"\ - " (y/[n])? " - next if STDIN.gets.strip.downcase != 'y' + if !use_defaults + STDOUT.print "\nDo you want to process datacenter #{dc}"\ + " (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + end if tmps.empty? STDOUT.print " No new VM Templates found in #{dc}...\n\n" @@ -94,15 +104,16 @@ def self.import_templates(con_ops, options) tmps.each{ |t| - STDOUT.print "\n * VM Template found:\n"\ - " - Name : #{t[:name]}\n"\ - " - Moref : #{t[:vcenter_ref]}\n"\ - " - Cluster: #{t[:cluster_name]}\n"\ - " Import this VM template (y/[n])? " + if !use_defaults + STDOUT.print "\n * VM Template found:\n"\ + " - Name : #{t[:name]}\n"\ + " - Moref : #{t[:vcenter_ref]}\n"\ + " - Cluster: #{t[:cluster_name]}\n"\ + " Import this VM template (y/[n])? " - next if STDIN.gets.strip.downcase != 'y' + next if STDIN.gets.strip.downcase != 'y' + end -=begin ## Add existing disks to template (OPENNEBULA_MANAGED) template = t[:template] @@ -110,156 +121,71 @@ def self.import_templates(con_ops, options) error, template_disks = template.import_vcenter_disks(vc_uuid, dpool, ipool) + if error.empty? t[:one] << template_disks else STDOUT.puts error next end -=end # Datastore placement ds_input = "" - STDOUT.print "\n This template is currently set to be "\ - "deployed in datastore #{t[:default_ds]}."\ - "\n Press y to keep the default, n to select"\ - " a new default datastore or d to delegate "\ - " the choice to the user ([y]/n/d)? " - - answer = STDIN.gets.strip.downcase - - case answer - when 'd' - ds_split = t[:ds].split("|") - list_of_ds = ds_split[-2] - default_ds = ds_split[-1] - ds_input = ds_split[0] + "|" + ds_split[1] + "|" + - ds_split[2] + "|" - - # Available list of datastores - - input_str = " The list of available datastores to be"\ - " presented to the user are \"#{list_of_ds}\"" - input_str+= "\n Press y to agree, or input a comma"\ - " separated list of datastores to edit "\ - "[y/comma separated list] " - STDOUT.print input_str - - answer = STDIN.gets.strip - - if answer.downcase == 'y' - ds_input += ds_split[3] + "|" - else - ds_input += answer + "|" - end - - # Default - input_str = " The default datastore presented to "\ - "the end user is set to \"#{default_ds}\"." - input_str+= "\n Press y to agree, or input a new "\ - "datastore [y/datastore name] " - STDOUT.print input_str - - answer = STDIN.gets.strip - - if answer.downcase == 'y' - ds_input += ds_split[4] - else - ds_input += answer - end - when 'n' - ds_split = t[:ds].split("|") - list_of_ds = ds_split[-2] - - input_str = " The list of available datastores is:\n" - - STDOUT.print input_str - - dashes = "" - 100.times do - dashes << "-" - end - - list_str = "\n [Index] Datastore :"\ - "\n #{dashes}\n" - - STDOUT.print list_str - - index = 1 - t[:ds_list].each do |ds| - list_str = " [#{index}] #{ds[:name]}\n" - index += 1 - STDOUT.print list_str - end - - input_str = "\n Please input the new default"\ - " datastore index in the list (e.g 1): " - - STDOUT.print input_str - - answer = STDIN.gets.strip - - t[:one] += "VCENTER_DS_REF=\"#{t[:ds_list][answer.to_i - 1][:ref]}\"\n" - end - - # Resource Pools - rp_input = "" - rp_split = t[:rp].split("|") - - if rp_split.size > 3 - STDOUT.print "\n This template is currently set to "\ - "launch VMs in the default resource pool."\ - "\n Press y to keep this behaviour, n to select"\ - " a new resource pool or d to delegate the choice"\ - " to the user ([y]/n/d)? " + if !use_defaults + STDOUT.print "\n This template is currently set to be "\ + "deployed in datastore #{t[:default_ds]}."\ + "\n Press y to keep the default, n to select"\ + " a new default datastore or d to delegate "\ + " the choice to the user ([y]/n/d)? " answer = STDIN.gets.strip.downcase + case answer when 'd' - list_of_rp = rp_split[-2] - default_rp = rp_split[-1] - rp_input = rp_split[0] + "|" + rp_split[1] + "|" + - rp_split[2] + "|" + ds_split = t[:ds].split("|") + list_of_ds = ds_split[-2] + default_ds = ds_split[-1] + ds_input = ds_split[0] + "|" + ds_split[1] + "|" + + ds_split[2] + "|" - # Available list of resource pools - input_str = " The list of available resource pools "\ - "to be presented to the user are "\ - "\"#{list_of_rp}\"" + # Available list of datastores + + input_str = " The list of available datastores to be"\ + " presented to the user are \"#{list_of_ds}\"" input_str+= "\n Press y to agree, or input a comma"\ - " separated list of resource pools to edit "\ + " separated list of datastores to edit "\ "[y/comma separated list] " STDOUT.print input_str answer = STDIN.gets.strip if answer.downcase == 'y' - rp_input += rp_split[3] + "|" + ds_input += ds_split[3] + "|" else - rp_input += answer + "|" + ds_input += answer + "|" end # Default - input_str = " The default resource pool presented "\ - "to the end user is set to"\ - " \"#{default_rp}\"." + input_str = " The default datastore presented to "\ + "the end user is set to \"#{default_ds}\"." input_str+= "\n Press y to agree, or input a new "\ - "resource pool [y/resource pool name] " + "datastore [y/datastore name] " STDOUT.print input_str answer = STDIN.gets.strip if answer.downcase == 'y' - rp_input += rp_split[4] + ds_input += ds_split[4] else - rp_input += answer + ds_input += answer end when 'n' + ds_split = t[:ds].split("|") + list_of_ds = ds_split[-2] - list_of_rp = rp_split[-2] - - input_str = " The list of available resource pools is:\n" + input_str = " The list of available datastores is:\n" STDOUT.print input_str @@ -268,26 +194,117 @@ def self.import_templates(con_ops, options) dashes << "-" end - list_str = "\n [Index] Resource pool :"\ - "\n #{dashes}\n" + list_str = "\n [Index] Datastore :"\ + "\n #{dashes}\n" STDOUT.print list_str index = 1 - t[:rp_list].each do |rp| - list_str = " [#{index}] #{rp[:name]}\n" + t[:ds_list].each do |ds| + list_str = " [#{index}] #{ds[:name]}\n" index += 1 STDOUT.print list_str end input_str = "\n Please input the new default"\ - " resource pool index in the list (e.g 1): " + " datastore index in the list (e.g 1): " STDOUT.print input_str answer = STDIN.gets.strip - t[:one] << "VCENTER_RP_REF=\"#{t[:rp_list][answer.to_i - 1][:ref]}\"\n" + t[:one] += "VCENTER_DS_REF=\"#{t[:ds_list][answer.to_i - 1][:ref]}\"\n" + end + end + + # Resource Pools + rp_input = "" + rp_split = t[:rp].split("|") + + if !use_defaults + + if rp_split.size > 3 + STDOUT.print "\n This template is currently set to "\ + "launch VMs in the default resource pool."\ + "\n Press y to keep this behaviour, n to select"\ + " a new resource pool or d to delegate the choice"\ + " to the user ([y]/n/d)? " + + answer = STDIN.gets.strip.downcase + + case answer + when 'd' + list_of_rp = rp_split[-2] + default_rp = rp_split[-1] + rp_input = rp_split[0] + "|" + rp_split[1] + "|" + + rp_split[2] + "|" + + # Available list of resource pools + input_str = " The list of available resource pools "\ + "to be presented to the user are "\ + "\"#{list_of_rp}\"" + input_str+= "\n Press y to agree, or input a comma"\ + " separated list of resource pools to edit "\ + "[y/comma separated list] " + STDOUT.print input_str + + answer = STDIN.gets.strip + + if answer.downcase == 'y' + rp_input += rp_split[3] + "|" + else + rp_input += answer + "|" + end + + # Default + input_str = " The default resource pool presented "\ + "to the end user is set to"\ + " \"#{default_rp}\"." + input_str+= "\n Press y to agree, or input a new "\ + "resource pool [y/resource pool name] " + STDOUT.print input_str + + answer = STDIN.gets.strip + + if answer.downcase == 'y' + rp_input += rp_split[4] + else + rp_input += answer + end + when 'n' + + list_of_rp = rp_split[-2] + + input_str = " The list of available resource pools is:\n" + + STDOUT.print input_str + + dashes = "" + 100.times do + dashes << "-" + end + + list_str = "\n [Index] Resource pool :"\ + "\n #{dashes}\n" + + STDOUT.print list_str + + index = 1 + t[:rp_list].each do |rp| + list_str = " [#{index}] #{rp[:name]}\n" + index += 1 + STDOUT.print list_str + end + + input_str = "\n Please input the new default"\ + " resource pool index in the list (e.g 1): " + + STDOUT.print input_str + + answer = STDIN.gets.strip + + t[:one] << "VCENTER_RP_REF=\"#{t[:rp_list][answer.to_i - 1][:ref]}\"\n" + end end end @@ -324,6 +341,8 @@ def self.import_networks(con_ops, options) begin STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + use_defaults = options.key?(:defaults) + vi_client = VCenterDriver::VIClient.new(con_ops) STDOUT.print "done!\n\n" @@ -337,9 +356,12 @@ def self.import_networks(con_ops, options) STDOUT.print "done!\n" rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " - next if STDIN.gets.strip.downcase != 'y' + if !use_defaults + STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " + + next if STDIN.gets.strip.downcase != 'y' + end if tmps.empty? STDOUT.print " No new Networks found in #{dc}...\n\n" @@ -347,76 +369,83 @@ def self.import_networks(con_ops, options) end tmps.each do |n| - print_str = "\n * Network found:\n"\ - " - Name : #{n[:name]}\n"\ - " - Type : #{n[:type]}\n" - print_str << " - VLAN ID : #{n[:vlan_id]}\n" if !n[:vlan_id].empty? - print_str << " - Cluster : #{n[:cluster]}\n" - print_str << " Import this Network (y/[n])? " - STDOUT.print print_str + if !use_defaults + print_str = "\n * Network found:\n"\ + " - Name : #{n[:name]}\n"\ + " - Type : #{n[:type]}\n" + print_str << " - VLAN ID : #{n[:vlan_id]}\n" if !n[:vlan_id].empty? + print_str << " - Cluster : #{n[:cluster]}\n" + print_str << " Import this Network (y/[n])? " - next if STDIN.gets.strip.downcase != 'y' + STDOUT.print print_str + + next if STDIN.gets.strip.downcase != 'y' + end size="255" - ar_type=nil + ar_type="e" first_ip=nil first_mac=nil global_prefix=nil ula_prefix=nil # Size - STDOUT.print " How many VMs are you planning"\ - " to fit into this network [255]? " - size_answer = STDIN.gets.strip - if !size_answer.empty? - size = size_answer.to_i.to_s rescue "255" + if !use_defaults + STDOUT.print " How many VMs are you planning"\ + " to fit into this network [255]? " + size_answer = STDIN.gets.strip + if !size_answer.empty? + size = size_answer.to_i.to_s rescue "255" + end end # Type - STDOUT.print " What type of Virtual Network"\ - " do you want to create (IPv[4],IPv[6]"\ - ",[E]thernet) ?" + if !use_defaults + STDOUT.print " What type of Virtual Network"\ + " do you want to create (IPv[4],IPv[6]"\ + ",[E]thernet) ?" - type_answer = STDIN.gets.strip - if ["4","6","e"].include?(type_answer.downcase) - ar_type = type_answer.downcase - else - ar_type = "e" - STDOUT.puts " Type [#{type_answer}] not supported,"\ - " defaulting to Ethernet." - end + type_answer = STDIN.gets.strip + if ["4","6","e"].include?(type_answer.downcase) + ar_type = type_answer.downcase + else + ar_type = "e" + STDOUT.puts " Type [#{type_answer}] not supported,"\ + " defaulting to Ethernet." + end - case ar_type.downcase - when "4" - STDOUT.print " Please input the first IP "\ - "in the range: " - first_ip = STDIN.gets.strip + case ar_type.downcase + when "4" + STDOUT.print " Please input the first IP "\ + "in the range: " + first_ip = STDIN.gets.strip - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac_answer = STDIN.gets.strip - first_mac = first_mac_answer if !mac_answer.empty? - when "6" - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac_answer = STDIN.gets.strip - first_mac = first_mac_answer if !mac_answer.empty? + STDOUT.print " Please input the first MAC "\ + "in the range [Enter for default]: " + mac_answer = STDIN.gets.strip + first_mac = first_mac_answer if !mac_answer.empty? + when "6" + STDOUT.print " Please input the first MAC "\ + "in the range [Enter for default]: " + mac_answer = STDIN.gets.strip + first_mac = first_mac_answer if !mac_answer.empty? - STDOUT.print " Please input the GLOBAL PREFIX "\ - "[Enter for default]: " - gp_answer = STDIN.gets.strip - global_prefix = gp_answer if !gp_answer.empty? + STDOUT.print " Please input the GLOBAL PREFIX "\ + "[Enter for default]: " + gp_answer = STDIN.gets.strip + global_prefix = gp_answer if !gp_answer.empty? - STDOUT.print " Please input the ULA PREFIX "\ - "[Enter for default]: " - ula_answer = STDIN.gets.strip - ula_prefix = ula_answer if !ula_answer.empty? - when "e" - STDOUT.print " Please input the first MAC "\ - "in the range [Enter for default]: " - mac_answer = STDIN.gets.strip - first_mac = first_mac_answer if !mac_answer.empty? + STDOUT.print " Please input the ULA PREFIX "\ + "[Enter for default]: " + ula_answer = STDIN.gets.strip + ula_prefix = ula_answer if !ula_answer.empty? + when "e" + STDOUT.print " Please input the first MAC "\ + "in the range [Enter for default]: " + mac_answer = STDIN.gets.strip + first_mac = first_mac_answer if !mac_answer.empty? + end end ar_str = "\nAR=[TYPE=\"" @@ -467,6 +496,8 @@ def self.import_datastore(con_ops, options) begin STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + use_defaults = options.key?(:defaults) + vi_client = VCenterDriver::VIClient.new(con_ops) STDOUT.print "done!\n\n" @@ -480,9 +511,11 @@ def self.import_datastore(con_ops, options) STDOUT.print "done!\n" rs.each {|dc, tmps| - STDOUT.print "\nDo you want to process datacenter #{dc} (y/[n])? " + if !use_defaults + STDOUT.print "\nDo you want to process datacenter #{dc} (y/[n])? " - next if STDIN.gets.strip.downcase != 'y' + next if STDIN.gets.strip.downcase != 'y' + end if tmps.empty? STDOUT.print " No new Datastores or StoragePods found in #{dc}...\n\n" @@ -490,14 +523,16 @@ def self.import_datastore(con_ops, options) end tmps.each{ |d| - STDOUT.print "\n * Datastore found:\n"\ - " - Name : #{d[:name]}\n"\ - " - Total MB : #{d[:total_mb]}\n"\ - " - Free MB : #{d[:free_mb]}\n"\ - " - Cluster : #{d[:cluster]}\n"\ - " Import this as Datastore [y/n]? " + if !use_defaults + STDOUT.print "\n * Datastore found:\n"\ + " - Name : #{d[:name]}\n"\ + " - Total MB : #{d[:total_mb]}\n"\ + " - Free MB : #{d[:free_mb]}\n"\ + " - Cluster : #{d[:cluster]}\n"\ + " Import this as Datastore [y/n]? " - next if STDIN.gets.strip.downcase != 'y' + next if STDIN.gets.strip.downcase != 'y' + end one_d = VCenterDriver::VIHelper.new_one_item(OpenNebula::Datastore) @@ -530,6 +565,8 @@ def self.import_images(con_ops, ds_name, options) begin STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + use_defaults = options.key?(:defaults) + vi_client = VCenterDriver::VIClient.new(con_ops) STDOUT.print "done!\n\n" @@ -550,13 +587,16 @@ def self.import_images(con_ops, ds_name, options) STDOUT.print "done!\n" images.each{ |i| - STDOUT.print "\n * Image found:\n"\ - " - Name : #{i[:name]}\n"\ - " - Path : #{i[:path]}\n"\ - " - Type : #{i[:type]}\n"\ - " Import this Image (y/[n])? " - next if STDIN.gets.strip.downcase != 'y' + if !use_defaults + STDOUT.print "\n * Image found:\n"\ + " - Name : #{i[:name]}\n"\ + " - Path : #{i[:path]}\n"\ + " - Type : #{i[:type]}\n"\ + " Import this Image (y/[n])? " + + next if STDIN.gets.strip.downcase != 'y' + end one_i = VCenterDriver::VIHelper.new_one_item(OpenNebula::Image) From c41538b59da7489b69b77514a13a0f989bf23a34 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 08:51:07 +0100 Subject: [PATCH 152/297] F #4913: Add VCENTER_IMPORTED attribute and do not remove images with it set to YES --- src/datastore_mad/remotes/vcenter/rm | 20 +++++++++++-------- .../remotes/lib/vcenter_driver/datastore.rb | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 8c75b1b279..66853b7a10 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -39,23 +39,27 @@ id = ARGV[1] drv_action =OpenNebula::XMLElement.new drv_action.initialize_xml(Base64.decode64(drv_action_enc), 'DS_DRIVER_ACTION_DATA') -ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] -host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] -img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] +ds_ref = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_DS_REF"] +host_id = drv_action["/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VCENTER_ONE_HOST_ID"] +img_src = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/SOURCE"] +imported = drv_action["/DS_DRIVER_ACTION_DATA/IMAGE/TEMPLATE/VCENTER_IMPORTED"] check_valid ds_ref, "ds_ref" check_valid host_id, "vcenter_cluster" check_valid img_src, "img_src" begin - vi_client = VCenterDriver::VIClient.new_from_host(host_id) + #TODO should imported disks be deleted? + if imported.nil? || imported.empty? + vi_client = VCenterDriver::VIClient.new_from_host(host_id) - ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) + ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) - img_dir = img_src.split('/')[0..-2].join('/') + img_dir = img_src.split('/')[0..-2].join('/') - ds.delete_virtual_disk(img_src) - ds.rm_directory(img_dir) if ds.dir_empty?(img_dir) + ds.delete_virtual_disk(img_src) + ds.rm_directory(img_dir) if ds.dir_empty?(img_dir) + end rescue Exception => e STDERR.puts "Error deleting virtual disk #{img_src}."\ " Reason: \"#{e.message}\"\n#{e.backtrace}" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 7557f25357..e0b4880d85 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -517,6 +517,7 @@ class Datastore < Storage one_image << "PERSISTENT=\"YES\"\n" one_image << "TYPE=\"#{image_type}\"\n" one_image << "VCENTER_DISK_TYPE=\"#{disk_type}\"\n" if disk_type + one_image << "VCENTER_IMPORTED=\"YES\"\n" if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, "#{image_name} - #{ds_name}", From 48af366c95008e6a7a4c621030c4f81848928211 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 08:59:47 +0100 Subject: [PATCH 153/297] F #4913: Add default DEV_PREFIX to imported images. Change return info for images being imported from template --- .../remotes/lib/vcenter_driver/datastore.rb | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index e0b4880d85..9e05c6a348 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -68,8 +68,9 @@ class Storage end end - def self.get_image_import_template(ds_name, image_path, image_type, ipool) - one_image = "" + def self.get_image_import_template(ds_name, image_path, image_type, ipool) + one_image = {} + one_image[:template] = "" # Remove ds info from path image_path.sub!(/^\[#{ds_name}\] /, "") @@ -79,16 +80,21 @@ class Storage image_name = "#{file_name} - #{ds_name}" #Chek if the image has already been imported - if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, - image_name, - ipool, - false).nil? + image = VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, + image_name, + ipool, + false) + if image.nil? #Set template - one_image << "NAME=\"#{image_name}\"\n" - one_image << "PATH=\"vcenter://#{image_path}\"\n" - one_image << "TYPE=\"#{image_type}\"\n" - one_image << "PERSISTENT=\"NO\"\n" - one_image << "OPENNEBULA_MANAGED=\"YES\"\n" + one_image[:template] << "NAME=\"#{image_name}\"\n" + one_image[:template] << "PATH=\"vcenter://#{image_path}\"\n" + one_image[:template] << "TYPE=\"#{image_type}\"\n" + one_image[:template] << "PERSISTENT=\"NO\"\n" + one_image[:template] << "OPENNEBULA_MANAGED=\"NO\"\n" + one_image[:template] << "DEV_PREFIX=\"#{VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/DEV_PREFIX")}\"\n" #TODO get device prefix from vcenter info + else + # Return the image XML if it already exists + one_image[:one] = image end return one_image @@ -494,10 +500,7 @@ class Datastore < Storage folderpath = result.folderPath.sub(/^\[#{ds_name}\] /, "") end - - result.file.each do |image| - image_path = "" # Skip not relevant files @@ -518,6 +521,7 @@ class Datastore < Storage one_image << "TYPE=\"#{image_type}\"\n" one_image << "VCENTER_DISK_TYPE=\"#{disk_type}\"\n" if disk_type one_image << "VCENTER_IMPORTED=\"YES\"\n" + one_image << "DEV_PREFIX=\"#{VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/DEV_PREFIX")}\"\n" #TODO get device prefix from vcenter info if VCenterDriver::VIHelper.find_by_name(OpenNebula::ImagePool, "#{image_name} - #{ds_name}", From 7305cba916603cb5d229c7ece79ed44f91b8ee56 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:02:37 +0100 Subject: [PATCH 154/297] F #4913: Fix copy_virtual_disk must be able to create target directory --- .../remotes/lib/vcenter_driver/datastore.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 9e05c6a348..b8b448b958 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -246,15 +246,19 @@ class Datastore < Storage end # Copy a VirtualDisk - # @param ds_name [String] name of the datastore - # @param img_str [String] path to the VirtualDisk - def copy_virtual_disk(src_path, target_ds_name, target_path) - leading_dirs = target_path.split('/')[0..-2] - if !leading_dirs.empty? - create_directory(leading_dirs.join('/')) - end + def copy_virtual_disk(src_path, target_ds, target_path) source_ds_name = self['name'] + target_ds_name = target_ds['name'] + + leading_dirs = target_path.split('/')[0..-2] + if !leading_dirs.empty? + if source_ds_name == target_ds_name + create_directory(leading_dirs.join('/')) + else + target_ds.create_directory(leading_dirs.join('/')) + end + end copy_params = { :sourceName => "[#{source_ds_name}] #{src_path}", From 69732b5d2e06b329eafb5e70289808bf61af14d0 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:06:13 +0100 Subject: [PATCH 155/297] F #4913: Add volatile image directory support --- src/tm_mad/vcenter/mkimage | 15 +++++++++++---- .../remotes/lib/vcenter_driver/file_helper.rb | 9 +++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/tm_mad/vcenter/mkimage b/src/tm_mad/vcenter/mkimage index a1902dca45..fa9466f6e8 100755 --- a/src/tm_mad/vcenter/mkimage +++ b/src/tm_mad/vcenter/mkimage @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -49,7 +49,6 @@ check_valid dsid, "dsid" hostname, img_name = path.split(":") disk_id = img_name.split(".")[-1] -img_name = "one-#{vmid}-#{disk_id}" # Get host ID host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) @@ -59,8 +58,10 @@ host_id = host['ID'] one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] -# Get adapter and disk type +# Get one_vm one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) + +# Adapter and disk type from one_vm adapter_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_ADAPTER_TYPE"] || VCenterDriver::VIHelper.get_default("IMAGE/TEMPLATE/VCENTER_ADAPTER_TYPE") disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_DISK_TYPE"] || @@ -69,9 +70,15 @@ disk_type = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_DISK_TYPE"] || check_valid adapter_type, "adapter_type" check_valid disk_type, "disk_type" +# Volatile images dir from one_vm +ds_volatile_dir = one_vm["/VM/TEMPLATE/DISK[DISK_ID=#{disk_id}]/VCENTER_DS_VOLATILE_DIR"] || + "one-volatile" + begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) + img_name = "#{ds_volatile_dir}/#{vmid}/one-#{vmid}-#{disk_id}" + ds_vc = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) ds_vc.create_virtual_disk(img_name, size, adapter_type, disk_type) @@ -81,5 +88,5 @@ rescue Exception => e " Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb index a1ea8dc3bb..308d114284 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/file_helper.rb @@ -5,17 +5,18 @@ module VCenterDriver class FileHelper - def self.get_img_name(disk, vm_id) + def self.get_img_name(disk, vm_id, vm_name) if disk["PERSISTENT"] == "YES" return disk["SOURCE"] else + disk_id = disk["DISK_ID"] if disk["SOURCE"] image_name = disk["SOURCE"].split(".").first + return "#{image_name}-#{vm_id}-#{disk_id}.vmdk" else - image_name = "one" #For volatile disks + ds_volatile_dir = disk["VCENTER_DS_VOLATILE_DIR"] || "one-volatile" + return "#{ds_volatile_dir}/#{vm_id}/one-#{vm_id}-#{disk_id}.vmdk" end - disk_id = disk["DISK_ID"] - return "#{image_name}-#{vm_id}-#{disk_id}.vmdk" end end From 93f270887fe8fa37f63253d963f8579078e0c7ab Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:09:47 +0100 Subject: [PATCH 156/297] F #4913: Change arguments to copy_virtual_disk. Minor fixes --- src/datastore_mad/remotes/vcenter/clone | 10 +++++----- src/tm_mad/vcenter/cpds | 9 +++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/clone b/src/datastore_mad/remotes/vcenter/clone index 70b3af6663..3fe035ffe7 100755 --- a/src/datastore_mad/remotes/vcenter/clone +++ b/src/datastore_mad/remotes/vcenter/clone @@ -61,16 +61,16 @@ begin ds = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) - target_ds = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) - target_ds_name = target_ds['name'] + target_ds_name = target_ds_vc['name'] - puts ds.copy_virtual_disk(src_path, target_ds_name, target_path) + puts ds.copy_virtual_disk(src_path, target_ds_vc, target_path) rescue Exception => e - STDERR.puts "Error cloning img #{src_path}."\ + STDERR.puts "Error cloning img #{src_path} to #{target_ds_name}"\ " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index d82527ffb5..9093e0788f 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -58,10 +58,9 @@ host_id = host['ID'] # Get OpenNebula VM (state, disks and deploy_id) one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") -src_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid) vm_ref = one_vm['DEPLOY_ID'] -if one_vm['LCM_STATE'] == 26 #ACTIVE / HOTPLUG_SAVEAS +if one_vm['LCM_STATE'].to_i == 26 #ACTIVE / HOTPLUG_SAVEAS STDERR.puts "'disk-saveas' operation is not supported for running VMs." exit 1 end @@ -89,10 +88,12 @@ begin target_ds_name_vc = target_ds_vc['name'] - source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) + src_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid, vm['name']) + + source_ds_vc.copy_virtual_disk(src_path, target_ds_vc, target_path) rescue Exception => e - STDERR.puts "Error copying img #{src_path}. "\ + STDERR.puts "Error copying img #{src_path} to #{target_ds_name_vc} "\ "Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure From 6142c4e08e0f27767ea0774c502cf28ce122b270 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:12:08 +0100 Subject: [PATCH 157/297] F #4913: Get img_path for deletion from detach_disk action --- src/tm_mad/vcenter/delete | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index bf233dd88d..6cc0403186 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -69,14 +69,13 @@ if path.match(/disk\.\d+$/) # Detach and remove the disk # Get DS ref + dsid = img_path.split("/")[-3] # get dsid from path one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] - # Get image path + # Get disk info disk_id = img_path.split(".")[-1] - disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]").first - img_path = VCenterDriver::FileHelper.get_img_name(disk, vmid) begin if !vm.has_snapshots? @@ -85,7 +84,7 @@ if path.match(/disk\.\d+$/) vm.one_item = one_vm # detach the disk - vm.detach_disk(disk) + ds_ref, img_path = vm.detach_disk(disk) # delete the disk ds = VCenterDriver::Datastore.new_from_ref(ds_ref, vi_client) @@ -112,6 +111,6 @@ else " Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end end From b1813f28623312c5a7716395a5bc2e4de2f201ef Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:13:23 +0100 Subject: [PATCH 158/297] F #4913: Minor fixes --- src/tm_mad/vcenter/mvds | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds index db7dbf0a8d..10ae863d19 100755 --- a/src/tm_mad/vcenter/mvds +++ b/src/tm_mad/vcenter/mvds @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -57,7 +57,6 @@ vm_ref = one_vm['DEPLOY_ID'] disk_id = img_path.split(".")[-1] disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]").first -img_path = VCenterDriver::FileHelper.get_img_name(disk, vmid) begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) @@ -66,10 +65,11 @@ begin vm.one_item = one_vm vm.detach_disk(disk) if !vm.has_snapshots? + rescue Exception => e - STDERR.puts "Error detaching virtual disk #{img_path} from vm #{vmid}."\ + STDERR.puts "Error detaching virtual disk #{disk_id} from vm #{vmid}."\ " Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end From d0c6a73fb3dd8d4c36020a100d8a725f61751960 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:15:23 +0100 Subject: [PATCH 159/297] F #4913: Raise error if opennebula error and exit_if_fail is set to false --- src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb index 81a9ef153d..62b59b1661 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vi_helper.rb @@ -11,12 +11,10 @@ class VIHelper def self.return_if_error(rc, item, exit_if_fail) if OpenNebula::is_error?(rc) - if exit_if_fail - STDERR.puts rc.message - exit 1 - else - rc - end + raise rc.message if !exit_if_fail + + STDERR.puts rc.message + exit 1 else item end From c948e81f2e1bfff81e39424d6e6a67282537b8ac Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:26:15 +0100 Subject: [PATCH 160/297] F #4913: Should not use cached config info. Fix add_new_scsi --- .../lib/vcenter_driver/virtual_machine.rb | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 8c340a68db..0c1d0f8367 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -253,7 +253,7 @@ class VirtualMachine end ############################################################################ - # Crate and reconfigure VM related methods + # Create and reconfigure VM related methods ############################################################################ # This function creates a new VM from the @one_item XML and returns the @@ -515,7 +515,7 @@ class VirtualMachine # extraConfig # Get opennebula.hotplugged_nics attribute from the vCenter object hotplugged_nics = [] - extraconfig_nics = self["config.extraConfig"].select do |val| + extraconfig_nics = @item["config.extraConfig"].select do |val| val[:key] == "opennebula.hotplugged_nics" end @@ -523,7 +523,7 @@ class VirtualMachine hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") end - self["config.hardware.device"].each do |dv| + @item["config.hardware.device"].each do |dv| if is_nic?(dv) # nics array will contain the list of nics to be attached nics.each do |nic| @@ -618,7 +618,7 @@ class VirtualMachine card_num = 1 # start in one, we want the next avaliable id - self["config.hardware.device"].each do |dv| + @item["config.hardware.device"].each do |dv| card_num += 1 if is_nic?(dv) end @@ -699,7 +699,7 @@ class VirtualMachine spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? # Get mac addresses plugged to the VM B#4897 - hotplugged_nics = self["config.extraConfig"].select do |val| + hotplugged_nics = @item["config.extraConfig"].select do |val| val[:key] == "opennebula.hotplugged_nics" end.first[:value].to_s.split(";") rescue nil @@ -739,14 +739,14 @@ class VirtualMachine mac = nic["MAC"] # Get VM nic element if it has a device with that mac - nic_device = self["config.hardware.device"].find do |device| + nic_device = @item["config.hardware.device"].find do |device| is_nic?(device) && (device.macAddress == mac) end rescue nil raise "Could not find NIC with mac address #{mac}" if nic_device.nil? # Get mac addresses plugged to the VM B#4897 - hotplugged_nics = self["config.extraConfig"].select do |val| + hotplugged_nics = @item["config.extraConfig"].select do |val| val[:key] == "opennebula.hotplugged_nics" end.first[:value].to_s.split(";") rescue nil @@ -779,12 +779,12 @@ class VirtualMachine !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? end - def device_change_disks + def device_change_disks disks = [] one_item.each("TEMPLATE/DISK") { |disk| disks << disk if !disk["OPENNEBULA_MANAGED"] } if !is_new? - self["config.hardware.device"].each do |d| + @item["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) disks.each do |disk| img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) @@ -801,7 +801,7 @@ class VirtualMachine end end - return [] if disks.nil? + return [] if disks.empty? position = 0 attach_disk_array = [] @@ -867,7 +867,7 @@ class VirtualMachine spec_hash = {} spec_hash[:deviceChange] = [] - self["config.hardware.device"].each do |disk| + @item["config.hardware.device"].each do |disk| if is_disk_or_cdrom?(disk) spec_hash[:deviceChange] << { :operation => :remove, @@ -885,14 +885,14 @@ class VirtualMachine end end - # Get vcenter device representing DISK object (hotplug) +# Get vcenter device representing DISK object (hotplug) def disk_attached_to_vm(disk) img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) ds = get_effective_ds(disk) ds_name = ds['name'] device_found = nil - self["config.hardware.device"].each do |d| + @item["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) backing = d.backing @@ -913,7 +913,7 @@ class VirtualMachine end def calculate_add_disk_spec(disk, position=0) - img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) + img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID'], self['name']) ds = get_effective_ds(disk) ds_name = ds['name'] @@ -1001,9 +1001,10 @@ class VirtualMachine def get_vcenter_disks disks = [] - self["config.hardware.device"].each do |device| + @item["config.hardware.device"].each do |device| disk = {} if is_disk_or_iso?(device) + disk[:device] = device disk[:datastore] = device.backing.datastore disk[:path] = device.backing.fileName disk[:type] = is_disk?(device) ? "OS" : "CDROM" @@ -1099,13 +1100,12 @@ class VirtualMachine def find_free_controller(position=0) free_scsi_controllers = [] - available_controller = nil scsi_schema = {} used_numbers = [] available_numbers = [] - self["config.hardware.device"].each do |dev| + @item["config.hardware.device"].each do |dev| if dev.is_a? RbVmomi::VIM::VirtualSCSIController if scsi_schema[dev.controllerKey].nil? scsi_schema[dev.key] = {} @@ -1136,7 +1136,7 @@ class VirtualMachine controller = nil - self['config.hardware.device'].each do |device| + @item['config.hardware.device'].each do |device| if device.deviceInfo.label == available_controller_label controller = device break @@ -1155,10 +1155,10 @@ class VirtualMachine raise "Cannot add a new controller, maximum is 4." end - if scsi_schema.keys.length == 0 - scsi_key = 0 - scsi_number = 0 - else scsi_schema.keys.length < 4 + scsi_key = 0 + scsi_number = 0 + + if scsi_schema.keys.length > 0 && scsi_schema.keys.length < 4 scsi_key = scsi_schema.keys.sort[-1] + 1 scsi_number = scsi_schema[scsi_schema.keys.sort[-1]][:device].busNumber + 1 end @@ -1180,7 +1180,7 @@ class VirtualMachine @item.ReconfigVM_Task(:spec => vm_config_spec).wait_for_completion - self["config.hardware.device"].each do |device| + @item["config.hardware.device"].each do |device| if device.class == RbVmomi::VIM::VirtualLsiLogicController && device.key == scsi_key @@ -1338,9 +1338,9 @@ class VirtualMachine host_id = one_host["ID"] if one_host str = "NAME = \"#{self["name"]} - #{cluster}\"\n"\ - "CPU = \"#{self["config.hardware.numCPU"]}\"\n"\ - "vCPU = \"#{self["config.hardware.numCPU"]}\"\n"\ - "MEMORY = \"#{self["config.hardware.memoryMB"]}\"\n"\ + "CPU = \"#{@item["config.hardware.numCPU"]}\"\n"\ + "vCPU = \"#{@item["config.hardware.numCPU"]}\"\n"\ + "MEMORY = \"#{@item["config.hardware.memoryMB"]}\"\n"\ "HYPERVISOR = \"vcenter\"\n"\ "SCHED_REQUIREMENTS=\"ID=\\\"#{host_id}\\\"\"\n"\ "CONTEXT = [\n"\ @@ -1363,7 +1363,7 @@ class VirtualMachine keymap = nil if !template - self["config.extraConfig"].select do |xtra| + @item["config.extraConfig"].select do |xtra| if xtra[:key].downcase=="remotedisplay.vnc.port" vnc_port = xtra[:value] @@ -1375,7 +1375,7 @@ class VirtualMachine end end - if self["config.extraConfig"].size > 0 + if @item["config.extraConfig"].size > 0 str << "GRAPHICS = [\n"\ " TYPE =\"vnc\",\n" str << " PORT =\"#{vnc_port}\",\n" if vnc_port @@ -1384,11 +1384,11 @@ class VirtualMachine str << "]\n" end - if self["config.annotation"].nil? || self["config.annotation"].empty? + if @item["config.annotation"].nil? || @item["config.annotation"].empty? str << "DESCRIPTION = \"vCenter Template imported by OpenNebula" \ " from Cluster #{cluster}\"\n" else - notes = self["config.annotation"].gsub("\\", "\\\\").gsub("\"", "\\\"") + notes = @item["config.annotation"].gsub("\\", "\\\\").gsub("\"", "\\\"") str << "DESCRIPTION = \"#{notes}\"\n" end From 8ba02627288a7cb8f04250e0d5f196b03ea482d5 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:39:49 +0100 Subject: [PATCH 161/297] F #4913: Do not tm_clone unmanaged disks --- src/tm_mad/vcenter/clone | 46 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index dc908778ac..e454b78649 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -50,8 +50,8 @@ check_valid source_ds_id, "source_ds_id" target_ds_id = dst.split("/")[-3] disk_id = dst.split(".")[-1] -src_host, src_path = src.split ":" -hostname, dst_path = dst.split ":" +src_path = src.split(":")[-1] +hostname = dst.split(":").first # Get host ID host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) @@ -67,30 +67,46 @@ target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] check_valid source_ds_ref, "source_ds" check_valid target_ds_ref, "target_ds" +# Get VM info +one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vm_id) + # calculate target path target_path = VCenterDriver::FileHelper.get_img_name_from_path(src_path, vm_id, disk_id) begin - vi_client = VCenterDriver::VIClient.new_from_host(host_id) + vi_client = VCenterDriver::VIClient.new_from_host(host_id) - source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) + # Find disk info + disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[SOURCE=\"#{src_path}\"]").first rescue nil + raise "Cannot find disk element in vm template" if !disk - if source_ds_ref == target_ds_ref - target_ds_vc = source_ds_vc - else - target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + File.open('/tmp/tm_clone_3','a'){|f| f.puts("TM cloned called")} + + # Do not clone disks not managed by OPENNEBULA + if !disk['OPENNEBULA_MANAGED'] || disk['OPENNEBULA_MANAGED'].to_s != "NO" + source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) + + if source_ds_ref == target_ds_ref + target_ds_vc = source_ds_vc + else + target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) + end + + target_ds_name_vc = target_ds_vc['name'] + + File.open('/tmp/tm_clone_3','a'){|f| f.puts("src_path: #{src_path}")} + File.open('/tmp/tm_clone_3','a'){|f| f.puts("target_ds_name_vc: #{target_ds_name_vc}")} + File.open('/tmp/tm_clone_3','a'){|f| f.puts("target_path: #{target_path}")} + + source_ds_vc.copy_virtual_disk(src_path, target_ds_vc, target_path) end - target_ds_name_vc = target_ds_vc['name'] - - source_ds_vc.copy_virtual_disk(src_path, target_ds_name_vc, target_path) - rescue Exception => e STDERR.puts "Error clone virtual disk #{src_path} in "\ - "datastore #{target_ds_ref}. "\ + "datastore #{target_ds_name_vc}. "\ "Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end From 29993703dc97d42e0582033975637097863ab29c Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:44:09 +0100 Subject: [PATCH 162/297] F #4913: Remove debug code --- src/tm_mad/vcenter/clone | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index e454b78649..c6c33705cd 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -81,7 +81,6 @@ begin disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[SOURCE=\"#{src_path}\"]").first rescue nil raise "Cannot find disk element in vm template" if !disk - File.open('/tmp/tm_clone_3','a'){|f| f.puts("TM cloned called")} # Do not clone disks not managed by OPENNEBULA if !disk['OPENNEBULA_MANAGED'] || disk['OPENNEBULA_MANAGED'].to_s != "NO" @@ -95,10 +94,6 @@ begin target_ds_name_vc = target_ds_vc['name'] - File.open('/tmp/tm_clone_3','a'){|f| f.puts("src_path: #{src_path}")} - File.open('/tmp/tm_clone_3','a'){|f| f.puts("target_ds_name_vc: #{target_ds_name_vc}")} - File.open('/tmp/tm_clone_3','a'){|f| f.puts("target_path: #{target_path}")} - source_ds_vc.copy_virtual_disk(src_path, target_ds_vc, target_path) end From 27ebd60dcf76932ac0247a30d9a066f74b9f934d Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:56:34 +0100 Subject: [PATCH 163/297] F #4913: Ensure close vi_client connection IF vi_client exists --- src/datastore_mad/remotes/vcenter/mkfs | 2 +- src/datastore_mad/remotes/vcenter/monitor | 2 +- src/datastore_mad/remotes/vcenter/rm | 2 +- src/datastore_mad/remotes/vcenter/stat | 2 +- src/datastore_mad/remotes/vcenter_downloader.rb | 2 +- src/datastore_mad/remotes/vcenter_uploader.rb | 2 +- src/tm_mad/vcenter/cpds | 2 +- src/tm_mad/vcenter/delete | 4 ++-- src/vmm_mad/remotes/vcenter/attach_disk | 2 +- src/vmm_mad/remotes/vcenter/attach_nic | 2 +- src/vmm_mad/remotes/vcenter/detach_disk | 2 +- src/vmm_mad/remotes/vcenter/detach_nic | 2 +- src/vmm_mad/remotes/vcenter/poll | 2 +- src/vmm_mad/remotes/vcenter/reboot | 2 +- src/vmm_mad/remotes/vcenter/reconfigure | 2 +- src/vmm_mad/remotes/vcenter/reset | 2 +- src/vmm_mad/remotes/vcenter/restore | 2 +- src/vmm_mad/remotes/vcenter/save | 2 +- src/vmm_mad/remotes/vcenter/shutdown | 2 +- src/vmm_mad/remotes/vcenter/snapshot_create | 2 +- src/vmm_mad/remotes/vcenter/snapshot_delete | 2 +- src/vmm_mad/remotes/vcenter/snapshot_revert | 2 +- 22 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/datastore_mad/remotes/vcenter/mkfs b/src/datastore_mad/remotes/vcenter/mkfs index 6f13b90708..b91fba3630 100755 --- a/src/datastore_mad/remotes/vcenter/mkfs +++ b/src/datastore_mad/remotes/vcenter/mkfs @@ -78,5 +78,5 @@ rescue Exception => e " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/datastore_mad/remotes/vcenter/monitor b/src/datastore_mad/remotes/vcenter/monitor index 6678cde1de..90cc315971 100755 --- a/src/datastore_mad/remotes/vcenter/monitor +++ b/src/datastore_mad/remotes/vcenter/monitor @@ -59,5 +59,5 @@ rescue Exception => e " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/datastore_mad/remotes/vcenter/rm b/src/datastore_mad/remotes/vcenter/rm index 66853b7a10..1762c8e251 100755 --- a/src/datastore_mad/remotes/vcenter/rm +++ b/src/datastore_mad/remotes/vcenter/rm @@ -65,5 +65,5 @@ rescue Exception => e " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/datastore_mad/remotes/vcenter/stat b/src/datastore_mad/remotes/vcenter/stat index 0320bb2984..9d99f76ba9 100755 --- a/src/datastore_mad/remotes/vcenter/stat +++ b/src/datastore_mad/remotes/vcenter/stat @@ -60,7 +60,7 @@ if img_path.start_with? "vcenter://" " Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end else cmd = "#{File.dirname(__FILE__)}/../fs/stat #{drv_action_enc}" diff --git a/src/datastore_mad/remotes/vcenter_downloader.rb b/src/datastore_mad/remotes/vcenter_downloader.rb index 9df20d07d3..9f605f51dc 100755 --- a/src/datastore_mad/remotes/vcenter_downloader.rb +++ b/src/datastore_mad/remotes/vcenter_downloader.rb @@ -96,5 +96,5 @@ rescue Exception => e "on #{hostname}. Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/datastore_mad/remotes/vcenter_uploader.rb b/src/datastore_mad/remotes/vcenter_uploader.rb index 10a7f24ae7..4d3443ff0d 100755 --- a/src/datastore_mad/remotes/vcenter_uploader.rb +++ b/src/datastore_mad/remotes/vcenter_uploader.rb @@ -54,6 +54,6 @@ rescue Exception => e "Reason: \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index 9093e0788f..9015342327 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -97,5 +97,5 @@ rescue Exception => e "Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index 6cc0403186..240df796d0 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -58,7 +58,7 @@ begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new_from_ref(vm_ref, vi_client) rescue Exception => e - vi_client.close_connection + vi_client.close_connection if vi_client STDERR.puts "Error obtaining the vCenter client and VM object."\ " Reason: #{e.message}\n#{e.backtrace}" @@ -96,7 +96,7 @@ if path.match(/disk\.\d+$/) " Reason: #{e.message}\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end else # Remove the VM diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index 20eab1457d..1a3b7e5f83 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -53,5 +53,5 @@ rescue Exception => e "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/attach_nic b/src/vmm_mad/remotes/vcenter/attach_nic index 7745e8e4be..b81b2a231e 100755 --- a/src/vmm_mad/remotes/vcenter/attach_nic +++ b/src/vmm_mad/remotes/vcenter/attach_nic @@ -53,5 +53,5 @@ rescue Exception => e "failed due to \"#{e.message}\"\n#{e.backtrace}" exit(-1) ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/detach_disk b/src/vmm_mad/remotes/vcenter/detach_disk index cca347af8e..a4dde1b5d2 100755 --- a/src/vmm_mad/remotes/vcenter/detach_disk +++ b/src/vmm_mad/remotes/vcenter/detach_disk @@ -51,5 +51,5 @@ rescue Exception => e "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/detach_nic b/src/vmm_mad/remotes/vcenter/detach_nic index cac7e8219d..e9ce62bcb4 100755 --- a/src/vmm_mad/remotes/vcenter/detach_nic +++ b/src/vmm_mad/remotes/vcenter/detach_nic @@ -53,5 +53,5 @@ rescue Exception => e "failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/poll b/src/vmm_mad/remotes/vcenter/poll index 56d1d49290..3673373a53 100755 --- a/src/vmm_mad/remotes/vcenter/poll +++ b/src/vmm_mad/remotes/vcenter/poll @@ -51,5 +51,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index 9b3fd938e0..d0f89dedbc 100755 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -48,5 +48,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/reconfigure b/src/vmm_mad/remotes/vcenter/reconfigure index 763ad3a214..a472a46061 100755 --- a/src/vmm_mad/remotes/vcenter/reconfigure +++ b/src/vmm_mad/remotes/vcenter/reconfigure @@ -48,5 +48,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 104af6ac11..042f277c23 100755 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -48,5 +48,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index d1a01595e3..f25added6b 100755 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -50,5 +50,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index b48487009e..1db30910b9 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -67,5 +67,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 337b9441fb..2779a0fa0f 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -97,5 +97,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 4ee862ca21..c994e140cb 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -67,5 +67,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end \ No newline at end of file diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index 6ece116c5f..dab7de7b43 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -49,5 +49,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit(-1) ensure - vi_client.close_connection + vi_client.close_connection if vi_client end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_revert b/src/vmm_mad/remotes/vcenter/snapshot_revert index f81a031b64..bc630a26c9 100755 --- a/src/vmm_mad/remotes/vcenter/snapshot_revert +++ b/src/vmm_mad/remotes/vcenter/snapshot_revert @@ -49,5 +49,5 @@ rescue Exception => e "to \"#{e.message}\"\n#{e.backtrace}" exit(-1) ensure - vi_client.close_connection + vi_client.close_connection if vi_client end From 6fcc96047f9d22267c088f764f9d80c6a973f01a Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 09:57:44 +0100 Subject: [PATCH 164/297] F #4913: Ensure close vi_client connection IF vi_client exists --- src/vmm_mad/remotes/vcenter/cancel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 250781011a..0d88d679d6 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -53,5 +53,5 @@ rescue Exception => e "\"#{e.message}\"\n#{e.backtrace}" exit(-1) ensure - vi_client.close_connection + vi_client.close_connection if vi_client end From 5c404ee18355812176b8e73399a41627e82ee7dd Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 10:02:31 +0100 Subject: [PATCH 165/297] F #4913: Add begin rescue to IM poll action --- src/im_mad/remotes/vcenter.d/poll | 80 ++++++++++++++++--------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/src/im_mad/remotes/vcenter.d/poll b/src/im_mad/remotes/vcenter.d/poll index 9d926f747c..b35e10a61f 100755 --- a/src/im_mad/remotes/vcenter.d/poll +++ b/src/im_mad/remotes/vcenter.d/poll @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # ---------------------------------------------------------------------------- # -# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems # +# Copyright 2002-2017, OpenNebula Project, OpenNebula Systems # # # # Licensed under the Apache License, Version 2.0 (the "License"); you may # # not use this file except in compliance with the License. You may obtain # @@ -29,42 +29,46 @@ $: << RUBY_LIB_LOCATION require 'vcenter_driver' host_id = ARGV[4] +check_valid host_id, "host_id" -if !host_id - exit -1 +begin + vi_client = VCenterDriver::VIClient.new_from_host(host_id) + + # Get CCR reference + client = OpenNebula::Client.new + host = OpenNebula::Host.new_with_id(host_id, client) + rc = host.info + if OpenNebula::is_error? rc + STDERR.puts rc.message + exit 1 + end + + ccr_ref = host["TEMPLATE/VCENTER_CCR_REF"] + + # Get vCenter Cluster + cluster = VCenterDriver::ClusterComputeResource.new_from_ref(ccr_ref, vi_client) + + # Print monitoring info + puts cluster.monitor + puts cluster.monitor_host_systems + + vm_monitor_info = cluster.monitor_vms + if !vm_monitor_info.empty? + puts "VM_POLL=YES" + puts vm_monitor_info + end + + puts cluster.monitor_customizations + + dc = cluster.get_dc + ds_folder = dc.datastore_folder + ds_folder.fetch! + puts ds_folder.monitor + +rescue Exception => e + STDERR.puts "IM poll for vcenter cluster #{host_id} failed due to "\ + "\"#{e.message}\"\n#{e.backtrace}" + exit(-1) +ensure + vi_client.close_connection if vi_client end - -vi_client = VCenterDriver::VIClient.new_from_host(host_id) - -# Get CCR reference -client = OpenNebula::Client.new -host = OpenNebula::Host.new_with_id(host_id, client) -rc = host.info -if OpenNebula::is_error? rc - STDERR.puts rc.message - exit 1 -end - -ccr_ref = host["TEMPLATE/VCENTER_CCR_REF"] - -# Get vCenter Cluster -cluster = VCenterDriver::ClusterComputeResource.new_from_ref(ccr_ref, vi_client) - -# Print monitoring info -puts cluster.monitor -puts cluster.monitor_host_systems - -vm_monitor_info = cluster.monitor_vms -if !vm_monitor_info.empty? - puts "VM_POLL=YES" - puts vm_monitor_info -end - -puts cluster.monitor_customizations - -dc = cluster.get_dc -ds_folder = dc.datastore_folder -ds_folder.fetch! -puts ds_folder.monitor - -vi_client.close_connection From 81295aa9a88486ad63d9bb2643b24183d512660e Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 10:10:22 +0100 Subject: [PATCH 166/297] F #4913: Add support for unmanaged disks when looking for disks --- .../lib/vcenter_driver/virtual_machine.rb | 59 ++++++++++++++----- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 0c1d0f8367..624bcf43d6 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -779,7 +779,7 @@ class VirtualMachine !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? end - def device_change_disks + def device_change_disks disks = [] one_item.each("TEMPLATE/DISK") { |disk| disks << disk if !disk["OPENNEBULA_MANAGED"] } @@ -787,14 +787,31 @@ class VirtualMachine @item["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) disks.each do |disk| - img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) - ds = get_effective_ds(disk) - ds_name = ds['name'] + backing = d.backing - if d.backing.respond_to?(:fileName) && - "[#{ds_name}] #{img_name}" == d.backing.fileName + while backing.respond_to?(:parent) + break if backing.parent.nil? + backing = backing.parent + end - disks.delete(disk) + if backing.respond_to?(:fileName) + # Check if we are dealing with the unmanaged disks present in the template when cloned + if disk["OPENNEBULA_MANAGED"] && disk["OPENNEBULA_MANAGED"] == "NO" + img_name = one_item["USER_TEMPLATE/VCENTER_TEMPLATE_DISK_#{disk["DISK_ID"]}"] + if img_name && backing.fileName == img_name + disks.delete(disk) + break + end + end + + # Alright let's see if we can find other devices only with the expected image name + img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID'], self['name']) + ds = get_effective_ds(disk) + ds_name = ds['name'] + if backing.fileName == "[#{ds_name}] #{img_name}" + disks.delete(disk) + break + end end end end @@ -885,12 +902,9 @@ class VirtualMachine end end -# Get vcenter device representing DISK object (hotplug) + # Get vcenter device representing DISK object (hotplug) def disk_attached_to_vm(disk) - img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID']) - ds = get_effective_ds(disk) - ds_name = ds['name'] - + img_name = "" device_found = nil @item["config.hardware.device"].each do |d| if is_disk_or_cdrom?(d) @@ -902,9 +916,24 @@ class VirtualMachine backing = backing.parent end - if backing.respond_to?(:fileName) && backing.fileName == "[#{ds_name}] #{img_name}" - device_found = d - break + if backing.respond_to?(:fileName) + # Check if we are dealing with the unmanaged disks present in the template when cloned + if disk["OPENNEBULA_MANAGED"] && disk["OPENNEBULA_MANAGED"] == "NO" + img_name = one_item["USER_TEMPLATE/VCENTER_TEMPLATE_DISK_#{disk["DISK_ID"]}"] + if img_name && backing.fileName == img_name + device_found = d + break + end + else + # Alright let's see if we can find other devices only with the expected image name + img_name = VCenterDriver::FileHelper.get_img_name(disk, one_item['ID'], self['name']) + ds = get_effective_ds(disk) + ds_name = ds['name'] + if backing.fileName == "[#{ds_name}] #{img_name}" + device_found = d + break + end + end end end end From 8f6485058b167337284e1ac23729c4955caa61fe Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 10:11:34 +0100 Subject: [PATCH 167/297] F #4913: Return ds info when a disk is detached --- src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 624bcf43d6..a18262bf58 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -861,10 +861,14 @@ class VirtualMachine # Detach DISK from VM def detach_disk(disk) spec_hash = {} + img_path = "" + ds_ref = nil # Get vcenter device to be detached and remove if found device = disk_attached_to_vm(disk) if device + img_path << device.backing.fileName.sub(/^\[(.*?)\] /, "") + ds_ref = device.backing.datastore._ref # Generate vCenter spec and reconfigure VM spec_hash[:deviceChange] = [{ :operation => :remove, @@ -877,6 +881,8 @@ class VirtualMachine raise "Cannot detach DISK from VM: #{e.message}\n#{e.backtrace}" end end + + return ds_ref, img_path end # Detach all DISKs from VM (terminate action) From 15480d9ad70d2f8b520cd7b932a5a4cd85d78027 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 10:14:23 +0100 Subject: [PATCH 168/297] F #4913: Add reference in VM USER_TEMPLATE for unmanaged disks --- .../lib/vcenter_driver/virtual_machine.rb | 16 ++++++++++++++++ src/vmm_mad/remotes/vcenter/deploy | 11 ++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index a18262bf58..591936e6b1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -412,6 +412,22 @@ class VirtualMachine clone_parameters end + def reference_imported_disks + # Add info for existing disks in template in vm xml + xpath = "TEMPLATE/DISK[OPENNEBULA_MANAGED=\"NO\"]" + non_managed_disks = one_item.retrieve_xmlelements(xpath) + + return if non_managed_disks.empty? + + # Update VM's one_item so it can use the recent attributes + vcenter_disks = get_vcenter_disks + vcenter_disks.each_with_index do |disk, index| + rc = one_item.update("VCENTER_TEMPLATE_DISK_#{non_managed_disks[index]["DISK_ID"]} = \"#{disk[:path]}\"", true) + raise "Could not update VCENTER_TEMPLATE_DISK elements" if OpenNebula.is_error?(rc) + end + one_item.info + end + def reconfigure extraconfig = [] diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index e036b1a1ec..f97d1063b7 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -53,8 +53,13 @@ begin # VM is new vm = VCenterDriver::VirtualMachine.new - # Clone from template - vm.clone_vm(drv_action, vi_client) + # Clone the VM + vm.clone_vm(drv_action, vi_client) # Clone from template + + # Set reference to template disks in VM template + one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vm_id) + vm.one_item = one_vm + vm.reference_imported_disks end vm.reconfigure @@ -68,5 +73,5 @@ rescue Exception => e "with #{dfile} failed due to \"#{e.message}\"\n#{e.backtrace}" exit -1 ensure - vi_client.close_connection + vi_client.close_connection if vi_client end From 954a7e08f1398c28cfb4e2eb11c38879060c4022 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 10:17:58 +0100 Subject: [PATCH 169/297] F #4913: Set OPENNEBULA_MANAGED=NO for already imported images (unamanaged disks) --- .../lib/vcenter_driver/virtual_machine.rb | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 591936e6b1..36480c6264 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -1066,7 +1066,6 @@ class VirtualMachine end def import_vcenter_disks(vc_uuid, dpool, ipool) - disk_info = "" error = "" @@ -1095,16 +1094,30 @@ class VirtualMachine break end - image_template = VCenterDriver::Datastore.get_image_import_template(disk[:datastore].name, + image_import = VCenterDriver::Datastore.get_image_import_template(disk[:datastore].name, disk[:path], disk[:type], ipool) - if !image_template.empty? - # Then the image is created + #Image is already in the datastore + if image_import[:one] + one_image = image_import[:one] + # We must update XML so the OPENNEBULA_MANAGED=NO is set + rc = one_image.update("OPENNEBULA_MANAGED = \"NO\"", true) + if OpenNebula.is_error?(rc) + error = "Could not update VCENTER_TEMPLATE_DISK elements" + break + end + + # This is the disk info + disk_info << "DISK=[\n" + disk_info << "IMAGE=\"#{one_image["NAME"]}\"\n" + disk_info << "]\n" + elsif !image_import[:template].empty? + # Then the image is created as it's not in the datastore one_i = VCenterDriver::VIHelper.new_one_item(OpenNebula::Image) allocated_images << one_i - rc = one_i.allocate(image_template, datastore_found['ID'].to_i) + rc = one_i.allocate(image_import[:template], datastore_found['ID'].to_i) if ::OpenNebula.is_error?(rc) error = " Error creating disk from template: #{rc.message}. Cannot import the template\n" @@ -1127,7 +1140,6 @@ class VirtualMachine end return error, disk_info - end # Checks if a RbVmomi::VIM::VirtualDevice is a disk or a cdrom From f1cc368b901a8fd219faaeaaf09492aba42b3ab0 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Sat, 18 Mar 2017 10:22:04 +0100 Subject: [PATCH 170/297] F #4913: Fix style --- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index b8b448b958..a573f27fec 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -68,7 +68,7 @@ class Storage end end - def self.get_image_import_template(ds_name, image_path, image_type, ipool) + def self.get_image_import_template(ds_name, image_path, image_type, ipool) one_image = {} one_image[:template] = "" From b72f55bea0f4fab6421923743b2e8f87a9d9a673 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 20 Mar 2017 10:37:31 +0100 Subject: [PATCH 171/297] F #4913: Fix wrong source datastore in tm/cpds --- src/tm_mad/vcenter/cpds | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index 9015342327..c4bee2e63d 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -47,7 +47,6 @@ check_valid target_path,"target_path" check_valid vmid,"vmid" check_valid target_ds_id,"target_ds_id" -source_ds_id = src.split("/")[-3] disk_id = src.split(".")[-1] hostname, src_path = src.split ":" @@ -55,9 +54,8 @@ hostname, src_path = src.split ":" host = VCenterDriver::VIHelper.find_by_name(OpenNebula::HostPool, hostname) host_id = host['ID'] -# Get OpenNebula VM (state, disks and deploy_id) +# Get OpenNebula VM (state and deploy_id) one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) -disks = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]") vm_ref = one_vm['DEPLOY_ID'] if one_vm['LCM_STATE'].to_i == 26 #ACTIVE / HOTPLUG_SAVEAS @@ -65,13 +63,6 @@ if one_vm['LCM_STATE'].to_i == 26 #ACTIVE / HOTPLUG_SAVEAS exit 1 end -# Get source and target ds ref -source_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, source_ds_id) -source_ds_ref = source_ds['TEMPLATE/VCENTER_DS_REF'] - -target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) -target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] - begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) @@ -82,14 +73,20 @@ begin exit 1 end + # Get source and target ds ref + disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[DISK_ID=#{disk_id}]").first + source_ds_ref = disk["VCENTER_DS_REF"] source_ds_vc = VCenterDriver::Datastore.new_from_ref(source_ds_ref, vi_client) + # Get image source path + src_path = VCenterDriver::FileHelper.get_img_name(disk, vmid, vm['name']) + + # Get target ds ref + target_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, target_ds_id) + target_ds_ref = target_ds['TEMPLATE/VCENTER_DS_REF'] target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) - target_ds_name_vc = target_ds_vc['name'] - src_path = VCenterDriver::FileHelper.get_img_name(disks.first, vmid, vm['name']) - source_ds_vc.copy_virtual_disk(src_path, target_ds_vc, target_path) rescue Exception => e From a0dc0bf61aae0d637e50768564d5f7214fb7bea9 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Mon, 20 Mar 2017 21:59:47 +0100 Subject: [PATCH 172/297] F #4913: Fix attach/detach nics in poweroff with hotplugged_nics variable --- .../lib/vcenter_driver/virtual_machine.rb | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 36480c6264..67235c4193 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -442,8 +442,10 @@ class VirtualMachine # vnc configuration (for config_array hash) extraconfig += extraconfig_vnc - # device_change hash (nics) - device_change += device_change_nics + # device_change hash (nics and extraconfig) + nics, extraconfig_nics = device_change_nics + device_change += nics + extraconfig += extraconfig_nics # device_change hash (disks) device_change += device_change_disks @@ -511,6 +513,9 @@ class VirtualMachine def device_change_nics # Final list of changes to be applied in vCenter device_change = [] + config_array = [] + + hotplugged_nics = [] # List of interfaces from the OpenNebula template nics = [] @@ -521,16 +526,9 @@ class VirtualMachine # To be included in device_change detach_nic_array = [] - # Get MACs from NICs inside VM template - one_mac_addresses = [] - nics.each do |nic| - one_mac_addresses << nic["MAC"] - end rescue nil - # B4897 - Get mac of NICs that were hot-plugged from vCenter # extraConfig # Get opennebula.hotplugged_nics attribute from the vCenter object - hotplugged_nics = [] extraconfig_nics = @item["config.extraConfig"].select do |val| val[:key] == "opennebula.hotplugged_nics" end @@ -539,6 +537,16 @@ class VirtualMachine hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") end + # Get MACs from NICs inside VM template + one_mac_addresses = [] + nics.each do |nic| + one_mac_addresses << nic["MAC"] + # B4897 - Add NICs that were attached in POWEROFF + if !hotplugged_nics.include?(nic["MAC"]) + hotplugged_nics << nic["MAC"] + end + end + @item["config.hardware.device"].each do |dv| if is_nic?(dv) # nics array will contain the list of nics to be attached @@ -561,27 +569,38 @@ class VirtualMachine } hotplugged_nics.delete(dv.macAddress) - config_array << { - :key => 'opennebula.hotplugged_nics', - :value => hotplugged_nics.join(";") - } end end end - device_change += detach_nic_array - end + config_array << { :key => 'opennebula.hotplugged_nics', + :value => hotplugged_nics.join(";")} - return [] if nics.empty? + device_change += detach_nic_array + else + # B4897 - Add NICs that have been added to the VM template + # to the hotplugged_nics extraconfig so we can track what must be removed + + # Get MACs from NICs inside VM template to track NICs added by OpenNebula + nics.each{|nic| + hotplugged_nics << nic["MAC"] + } + + if !hotplugged_nics.empty? + config_array << { + :key => 'opennebula.hotplugged_nics', + :value => hotplugged_nics.join(";") + } + end + end # Attach new nics (nics now contains only the interfaces not present # in the VM in vCenter) - attach_nic_array = [] nics.each do |nic| - attach_nic_array << calculate_add_nic_spec(nic) + device_change << calculate_add_nic_spec(nic) end - attach_nic_array + return device_change, config_array end # Regenerate context when devices are hot plugged (reconfigure) From 39c6ec426ad6db85ff3170be833d463b47390f57 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Tue, 21 Mar 2017 17:49:22 +0100 Subject: [PATCH 173/297] F #4913: Add support for unmanaged and managed disks resize when instantiate VM --- src/tm_mad/vcenter/clone | 11 ++++- .../remotes/lib/vcenter_driver/datastore.rb | 14 +++++- .../lib/vcenter_driver/virtual_machine.rb | 48 ++++++++++++++++++- src/vmm_mad/remotes/vcenter/deploy | 11 +++-- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/tm_mad/vcenter/clone b/src/tm_mad/vcenter/clone index c6c33705cd..6ade2eef4d 100755 --- a/src/tm_mad/vcenter/clone +++ b/src/tm_mad/vcenter/clone @@ -81,6 +81,15 @@ begin disk = one_vm.retrieve_xmlelements("TEMPLATE/DISK[SOURCE=\"#{src_path}\"]").first rescue nil raise "Cannot find disk element in vm template" if !disk + new_size = nil + # Check if resize is needed + if disk["ORIGINAL_SIZE"] + original_size = disk["ORIGINAL_SIZE"].to_i + new_size = disk["SIZE"].to_i + + # Shrink not supported (nil). Size is in KB + new_size = new_size > original_size ? new_size * 1024 : nil + end # Do not clone disks not managed by OPENNEBULA if !disk['OPENNEBULA_MANAGED'] || disk['OPENNEBULA_MANAGED'].to_s != "NO" @@ -94,7 +103,7 @@ begin target_ds_name_vc = target_ds_vc['name'] - source_ds_vc.copy_virtual_disk(src_path, target_ds_vc, target_path) + source_ds_vc.copy_virtual_disk(src_path, target_ds_vc, target_path, new_size) end rescue Exception => e diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index a573f27fec..8181b9c0a8 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -246,8 +246,7 @@ class Datastore < Storage end # Copy a VirtualDisk - def copy_virtual_disk(src_path, target_ds, target_path) - + def copy_virtual_disk(src_path, target_ds, target_path, new_size=nil) source_ds_name = self['name'] target_ds_name = target_ds['name'] @@ -268,6 +267,17 @@ class Datastore < Storage get_vdm.CopyVirtualDisk_Task(copy_params).wait_for_completion + if new_size + resize_spec = { + :name => "[#{target_ds_name}] #{target_path}", + :datacenter => target_ds.get_dc.item, + :newCapacityKb => new_size, + :eagerZero => false + } + + get_vdm.ExtendVirtualDisk_Task(resize_spec).wait_for_completion + end + target_path end diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 67235c4193..3e0c0f2d6f 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -422,12 +422,56 @@ class VirtualMachine # Update VM's one_item so it can use the recent attributes vcenter_disks = get_vcenter_disks vcenter_disks.each_with_index do |disk, index| - rc = one_item.update("VCENTER_TEMPLATE_DISK_#{non_managed_disks[index]["DISK_ID"]} = \"#{disk[:path]}\"", true) - raise "Could not update VCENTER_TEMPLATE_DISK elements" if OpenNebula.is_error?(rc) + if !!non_managed_disks[index] + rc = one_item.update("VCENTER_TEMPLATE_DISK_#{non_managed_disks[index]["DISK_ID"]} = \"#{disk[:path]}\"", true) + raise "Could not update VCENTER_TEMPLATE_DISK elements" if OpenNebula.is_error?(rc) + end end one_item.info end + def resize_imported_disks + resize_hash = {} + device_change_disks = [] + + # Look for unmanaged disks with original size changed + xpath = "TEMPLATE/DISK[OPENNEBULA_MANAGED=\"NO\" and boolean(ORIGINAL_SIZE)]" + unmanaged_resized_disks = one_item.retrieve_xmlelements(xpath) + + return if unmanaged_resized_disks.empty? + + @item["config.hardware.device"].each do |d| + if is_disk_or_cdrom?(d) + unmanaged_resized_disks.each do |disk| + backing = d.backing + + while backing.respond_to?(:parent) + break if backing.parent.nil? + backing = backing.parent + end + + if backing.respond_to?(:fileName) + img_name = one_item["USER_TEMPLATE/VCENTER_TEMPLATE_DISK_#{disk["DISK_ID"]}"] + if img_name && backing.fileName == img_name && + disk["SIZE"].to_i > disk["ORIGINAL_SIZE"].to_i + + # Edit capacity setting new size in KB + d.capacityInKB = disk["SIZE"].to_i * 1024 + device_change_disks << { :device => d, + :operation => :edit } + break + end + end + end + end + end + + if !device_change_disks.empty? + resize_hash[:deviceChange] = device_change_disks + @item.ReconfigVM_Task(:spec => resize_hash).wait_for_completion + end + end + def reconfigure extraconfig = [] diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index f97d1063b7..df01c809b0 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -53,15 +53,18 @@ begin # VM is new vm = VCenterDriver::VirtualMachine.new - # Clone the VM - vm.clone_vm(drv_action, vi_client) # Clone from template - - # Set reference to template disks in VM template + # Clone the VM from template and provide XML info + vm.clone_vm(drv_action, vi_client) one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vm_id) vm.one_item = one_vm + + # Set reference to template disks in VM template for detach ops vm.reference_imported_disks end + # Resize cloned disks from template if needed + vm.resize_imported_disks + vm.reconfigure vm.poweron vm.set_running(true) From e295fb5752ecc09432f066b48d015aec1a0b2c0c Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 22 Mar 2017 11:22:33 +0100 Subject: [PATCH 174/297] F #4913: Remove vcenter_uuid for get_images call (not needed) --- src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb | 2 +- src/vmm_mad/remotes/lib/vcenter_driver/importer.rb | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index 8181b9c0a8..db51f38f1c 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -477,7 +477,7 @@ class Datastore < Storage return output end - def get_images(vcenter_uuid) + def get_images img_templates = [] ds_id = nil ds_name = self['name'] diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index bba1702249..e27de4eb09 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -580,9 +580,7 @@ def self.import_images(con_ops, ds_name, options) ds = VCenterDriver::Datastore.new_from_ref(one_ds_ref, vi_client) ds.one_item = one_ds #Store opennebula template for datastore - vcenter_uuid = vi_client.vim.serviceContent.about.instanceUuid - - images = ds.get_images(vcenter_uuid) + images = ds.get_images STDOUT.print "done!\n" From 9f6abc21b99dfb2d983ed2fa213eedec7d5d8c58 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Wed, 22 Mar 2017 11:23:51 +0100 Subject: [PATCH 175/297] F #4913: Add refactored importers code to vcenter routes for Sunstone importing tools --- src/sunstone/routes/vcenter.rb | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sunstone/routes/vcenter.rb b/src/sunstone/routes/vcenter.rb index 0dbef77d3e..ce9bffcc98 100644 --- a/src/sunstone/routes/vcenter.rb +++ b/src/sunstone/routes/vcenter.rb @@ -89,8 +89,9 @@ end get '/vcenter/templates' do begin - templates = vcenter_client.vm_templates( - $cloud_auth.client(session[:user], session[:active_zone_endpoint])) + dc_folder = VCenterDriver::DatacenterFolder.new(vcenter_client) + templates = dc_folder.get_unimported_templates(vcenter_client) + if templates.nil? msg = "No datacenter found" logger.error("[vCenter] " + msg) @@ -109,8 +110,9 @@ end get '/vcenter/networks' do begin - networks = vcenter_client.vcenter_networks( - $cloud_auth.client(session[:user], session[:active_zone_endpoint])) + dc_folder = VCenterDriver::DatacenterFolder.new(vcenter_client) + networks = dc_folder.get_unimported_networks + if networks.nil? msg = "No datacenter found" logger.error("[vCenter] " + msg) @@ -128,8 +130,14 @@ end get '/vcenter/images/:ds_name' do begin - images = vcenter_client.vcenter_images(params[:ds_name], - $cloud_auth.client(session[:user], session[:active_zone_endpoint])) + one_ds = VCenterDriver::VIHelper.find_by_name(OpenNebula::DatastorePool, + params[:ds_name]) + one_ds_ref = one_ds['TEMPLATE/VCENTER_DS_REF'] + + ds = VCenterDriver::Datastore.new_from_ref(one_ds_ref, vcenter_client) + ds.one_item = one_ds + + images = ds.get_images if images.nil? msg = "No datastore found" @@ -148,8 +156,8 @@ end get '/vcenter/datastores' do begin - datastores = vcenter_client.vcenter_datastores( - $cloud_auth.client(session[:user], session[:active_zone_endpoint])) + dc_folder = VCenterDriver::DatacenterFolder.new(vcenter_client) + datastores = dc_folder.get_unimported_datastores if datastores.nil? msg = "No datacenter found" logger.error("[vCenter] " + msg) From d73adc1c2425f96c4f8ef3d3eb2824d9e21b58d9 Mon Sep 17 00:00:00 2001 From: mcabrerizo Date: Thu, 23 Mar 2017 10:27:32 +0100 Subject: [PATCH 176/297] F #4913: Add support for unmanaged nics. Remove opennebula.hotplugged_nics --- .../remotes/lib/vcenter_driver/importer.rb | 16 +- .../remotes/lib/vcenter_driver/network.rb | 19 ++ .../lib/vcenter_driver/virtual_machine.rb | 269 ++++++++++-------- src/vmm_mad/remotes/vcenter/deploy | 3 + 4 files changed, 180 insertions(+), 127 deletions(-) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb index e27de4eb09..1ef8eeb17b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/importer.rb @@ -84,6 +84,7 @@ def self.import_templates(con_ops, options) # Create OpenNebula pools dpool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool) ipool = VCenterDriver::VIHelper.one_pool(OpenNebula::ImagePool) + npool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool) # Get vcenter intance uuid as moref is unique for each vcenter vc_uuid = vi_client.vim.serviceContent.about.instanceUuid @@ -118,17 +119,28 @@ def self.import_templates(con_ops, options) template = t[:template] - error, template_disks = template.import_vcenter_disks(vc_uuid, + error, template_disks_and_nics = template.import_vcenter_disks(vc_uuid, dpool, ipool) if error.empty? - t[:one] << template_disks + t[:one] << template_disks_and_nics else STDOUT.puts error next end + error, template_nics = template.import_vcenter_nics(vc_uuid, + npool) + if error.empty? + t[:one] << template_nics + else + STDOUT.puts error + next + end + + + # Datastore placement ds_input = "" diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb index 3f0246634e..047e4d710e 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/network.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/network.rb @@ -86,6 +86,25 @@ class Network return template end + def self.get_network_type(device) + if device.backing.network.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) + return "Distributed Port Group" + else + return "Port Group" + end + end + + def self.get_one_vnet_ds_by_ref_and_ccr(ref, ccr_ref, vcenter_uuid, pool = nil) + pool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool, false) if pool.nil? + element = pool.select do |e| + e["TEMPLATE/VCENTER_NET_REF"] == ref && + e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref && + e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid + end.first rescue nil + + return element + end + # This is never cached def self.new_from_ref(ref, vi_client) self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref), vi_client) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index 3e0c0f2d6f..edb190859b 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -430,9 +430,36 @@ class VirtualMachine one_item.info end + def reference_imported_nics + mac_change_hash = {} + nics = [] + + # Add info for existing disks in template in vm xml + xpath = "TEMPLATE/NIC[OPENNEBULA_MANAGED=\"NO\"]" + unmanaged_nics = one_item.retrieve_xmlelements(xpath) + + return if unmanaged_nics.empty? + + # Update vcenter VM's mac addresses with the one in OpenNebula's XML + index = 0 + @item["config.hardware.device"].each_with_index do |device| + if is_nic?(device) + # Edit capacity setting new size in KB + device.macAddress = unmanaged_nics[index]["MAC"] + nics << { :device => device, :operation => :edit } + index += 1 + end + end + + if !nics.empty? + mac_change_hash[:deviceChange] = nics + @item.ReconfigVM_Task(:spec => mac_change_hash).wait_for_completion + end + end + def resize_imported_disks resize_hash = {} - device_change_disks = [] + disks = [] # Look for unmanaged disks with original size changed xpath = "TEMPLATE/DISK[OPENNEBULA_MANAGED=\"NO\" and boolean(ORIGINAL_SIZE)]" @@ -457,8 +484,7 @@ class VirtualMachine # Edit capacity setting new size in KB d.capacityInKB = disk["SIZE"].to_i * 1024 - device_change_disks << { :device => d, - :operation => :edit } + disks << { :device => d, :operation => :edit } break end end @@ -466,8 +492,8 @@ class VirtualMachine end end - if !device_change_disks.empty? - resize_hash[:deviceChange] = device_change_disks + if !disks.empty? + resize_hash[:deviceChange] = disks @item.ReconfigVM_Task(:spec => resize_hash).wait_for_completion end end @@ -486,10 +512,8 @@ class VirtualMachine # vnc configuration (for config_array hash) extraconfig += extraconfig_vnc - # device_change hash (nics and extraconfig) - nics, extraconfig_nics = device_change_nics - device_change += nics - extraconfig += extraconfig_nics + # device_change hash (nics) + device_change += device_change_nics # device_change hash (disks) device_change += device_change_disks @@ -557,94 +581,37 @@ class VirtualMachine def device_change_nics # Final list of changes to be applied in vCenter device_change = [] - config_array = [] - hotplugged_nics = [] + # Hash of interfaces from the OpenNebula xml + nics_in_template = {} + xpath = "TEMPLATE/NIC" + one_item.each(xpath) { |nic| + nics_in_template[nic["MAC"]] = nic + } - # List of interfaces from the OpenNebula template - nics = [] - one_item.each("TEMPLATE/NIC") { |nic| nics << nic } - - # Remove detached nics in poweroff - if !is_new? - # To be included in device_change - detach_nic_array = [] - - # B4897 - Get mac of NICs that were hot-plugged from vCenter - # extraConfig - # Get opennebula.hotplugged_nics attribute from the vCenter object - extraconfig_nics = @item["config.extraConfig"].select do |val| - val[:key] == "opennebula.hotplugged_nics" - end - - if extraconfig_nics && !extraconfig_nics.empty? - hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";") - end - - # Get MACs from NICs inside VM template - one_mac_addresses = [] - nics.each do |nic| - one_mac_addresses << nic["MAC"] - # B4897 - Add NICs that were attached in POWEROFF - if !hotplugged_nics.include?(nic["MAC"]) - hotplugged_nics << nic["MAC"] + # Check nics in VM + @item["config.hardware.device"].each do |dv| + if is_nic?(dv) + if nics_in_template.key?(dv.macAddress) + # Remove nic that is already in the XML to avoid duplicate + nics_in_template.delete(dv.macAddress) + else + # B4897 - It was detached in poweroff, remove it from VM + device_change << { + :operation => :remove, + :device => dv + } end end - - @item["config.hardware.device"].each do |dv| - if is_nic?(dv) - # nics array will contain the list of nics to be attached - nics.each do |nic| - if nic["MAC"] == dv.macAddress - nics.delete(nic) - end - end - - # if the nic is in the list opennebula.hotplugged_nics and - # not in the list of the OpenNebula NICs we can remove it. - # B4897 - Remove detached NICs from vCenter that were unplugged - # in POWEROFF - if !one_mac_addresses.include?(dv.macAddress) && - hotplugged_nics.include?(dv.macAddress) - - detach_nic_array << { - :operation => :remove, - :device => dv - } - - hotplugged_nics.delete(dv.macAddress) - end - end - end - - config_array << { :key => 'opennebula.hotplugged_nics', - :value => hotplugged_nics.join(";")} - - device_change += detach_nic_array - else - # B4897 - Add NICs that have been added to the VM template - # to the hotplugged_nics extraconfig so we can track what must be removed - - # Get MACs from NICs inside VM template to track NICs added by OpenNebula - nics.each{|nic| - hotplugged_nics << nic["MAC"] - } - - if !hotplugged_nics.empty? - config_array << { - :key => 'opennebula.hotplugged_nics', - :value => hotplugged_nics.join(";") - } - end end - # Attach new nics (nics now contains only the interfaces not present - # in the VM in vCenter) - nics.each do |nic| + # Attach new nics (nics_in_template now contains only the interfaces + # not present in the VM in vCenter) + nics_in_template.each do |key, nic| device_change << calculate_add_nic_spec(nic) end - return device_change, config_array + return device_change end # Regenerate context when devices are hot plugged (reconfigure) @@ -777,25 +744,6 @@ class VirtualMachine attach_nic_array << calculate_add_nic_spec(nic) spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty? - # Get mac addresses plugged to the VM B#4897 - hotplugged_nics = @item["config.extraConfig"].select do |val| - val[:key] == "opennebula.hotplugged_nics" - end.first[:value].to_s.split(";") rescue nil - - # Include MAC in opennebula.hotplugged_nics variable - if hotplugged_nics && !hotplugged_nics.empty? - if !hotplugged_nics.include?(nic["MAC"]) - hotplugged_nics << nic["MAC"] - end - else - hotplugged_nics = [] - hotplugged_nics << nic["MAC"] - end - - spec_hash[:extraConfig] = [{ - :key=>"opennebula.hotplugged_nics", - :value=>hotplugged_nics.join(";")}] - # Reconfigure VM spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) @@ -814,32 +762,15 @@ class VirtualMachine # Extract nic from driver action nic = one_item.retrieve_xmlelements("TEMPLATE/NIC[ATTACH='YES']").first - mac = nic["MAC"] # Get VM nic element if it has a device with that mac nic_device = @item["config.hardware.device"].find do |device| - is_nic?(device) && (device.macAddress == mac) + is_nic?(device) && (device.macAddress == mac) end rescue nil raise "Could not find NIC with mac address #{mac}" if nic_device.nil? - # Get mac addresses plugged to the VM B#4897 - hotplugged_nics = @item["config.extraConfig"].select do |val| - val[:key] == "opennebula.hotplugged_nics" - end.first[:value].to_s.split(";") rescue nil - - # Remove MAC from opennebula.hotplugged_nics variable if included - if hotplugged_nics && - !hotplugged_nics.empty? && hotplugged_nics.include?(mac) - - hotplugged_nics.delete(mac) - - spec_hash[:extraConfig] = [{ - :key=>"opennebula.hotplugged_nics", - :value=>hotplugged_nics.join(";")}] - end - # Remove NIC from VM in the ReconfigVM_Task spec_hash[:deviceChange] = [ :operation => :remove, @@ -1128,6 +1059,20 @@ class VirtualMachine return disks end + def get_vcenter_nics + nics = [] + @item["config.hardware.device"].each do |device| + nic = {} + if is_nic?(device) + nic[:net_name] = device.backing.network.name + nic[:net_ref] = device.backing.network._ref + nic[:pg_type] = VCenterDriver::Network.get_network_type(device) + nics << nic + end + end + return nics + end + def import_vcenter_disks(vc_uuid, dpool, ipool) disk_info = "" error = "" @@ -1205,6 +1150,80 @@ class VirtualMachine return error, disk_info end + def import_vcenter_nics(vc_uuid, npool) + nic_info = "" + error = "" + + ccr_ref = self["runtime.host.parent._ref"] + ccr_name = self["runtime.host.parent.name"] + + #Get disks and info required + vc_nics = get_vcenter_nics + + # Track allocated networks + allocated_networks = [] + + vc_nics.each do |nic| + + network_found = VCenterDriver::Network.get_one_vnet_ds_by_ref_and_ccr(nic[:net_ref], + ccr_ref, + vc_uuid, + npool) + #Network is already in the datastore + if network_found + # This is the existing nic info + nic_info << "NIC=[\n" + nic_info << "NETWORK=\"#{network_found["NAME"]}\",\n" + nic_info << "OPENNEBULA_MANAGED=\"NO\"\n" + nic_info << "]\n" + else + # Then the network has to be created as it's not in OpenNebula + one_vn = VCenterDriver::VIHelper.new_one_item(OpenNebula::VirtualNetwork) + + allocated_networks << one_vn + + vlan_id = "" # TODO VLAN ID management + one_vnet = VCenterDriver::Network.to_one_template(nic[:net_name], + nic[:net_ref], + nic[:pg_type], + vlan_id, + ccr_ref, + ccr_name, + vc_uuid) + + # By default add an ethernet range to network size 255 + ar_str = "" + ar_str << "AR=[\n" + ar_str << "TYPE=\"ETHER\",\n" + ar_str << "SIZE=\"255\"\n" + ar_str << "]\n" + one_vnet[:one] << ar_str + + rc = one_vn.allocate(one_vnet[:one]) + + if ::OpenNebula.is_error?(rc) + error = " Error creating virtual network from template: #{rc.message}. Cannot import the template\n" + + #Rollback, delete virtual networks + allocated_networks.each do |n| + n.delete + end + + break + end + + #Add info for One template + one_vn.info + nic_info << "NIC=[\n" + nic_info << "NETWORK=\"#{one_vn["NAME"]}\",\n" + nic_info << "OPENNEBULA_MANAGED=\"NO\"\n" + nic_info << "]\n" + end + end + + return error, nic_info + end + # Checks if a RbVmomi::VIM::VirtualDevice is a disk or a cdrom def is_disk_or_cdrom?(device) is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index df01c809b0..ef50dfb79a 100755 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -60,6 +60,9 @@ begin # Set reference to template disks in VM template for detach ops vm.reference_imported_disks + + # Set reference to template nics in VM template for detach ops + vm.reference_imported_nics end # Resize cloned disks from template if needed From 2245d7d5ced0ecbbbf73bacac50dc58f1297453b Mon Sep 17 00:00:00 2001 From: juanmont Date: Fri, 24 Mar 2017 17:55:29 +0100 Subject: [PATCH 177/297] Feature #4913 (PR #231) Changes in Sunstone for new storage support in vCenter * F #4913 Replaced vCenter Template UUID with VCENTER_TEMPLATE_REF field * F #4913 Replaced CUSTOMIZATION_SPEC with VCENTER_CUSTOMIZATION_SPEC and stored that value in USER_TEMPLATE not in VCENTER_PUBLIC_CLOUD * F #4913 added posibility to instanciate MV * F #4913 Removed VCENTER_PUBLIC_CLOUD * F #4913 Used VCENTER_REF when import a template --- .../templates-tab/form-panels/create-common.js | 10 ++-------- .../form-panels/create/wizard-tabs/context.js | 8 ++++---- .../form-panels/create/wizard-tabs/general.js | 16 +++++++++------- .../create/wizard-tabs/general/html.hbs | 6 +++--- .../templates-tab/form-panels/instantiate.js | 4 ++-- src/sunstone/public/app/utils/deploy-folder.js | 2 +- .../public/app/utils/vcenter/templates/row.hbs | 4 ++-- 7 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js index cc320856b0..c41fe40aee 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js @@ -165,14 +165,8 @@ define(function(require) { // part of an array, and it is filled in different tabs, the $.extend deep // merge can't work. We define an auxiliary attribute for it. - if (templateJSON["VCENTER_PUBLIC_CLOUD"]) { - if (templateJSON['PUBLIC_CLOUD'] == undefined) { - templateJSON['PUBLIC_CLOUD'] = []; - } - - templateJSON['PUBLIC_CLOUD'].push(templateJSON["VCENTER_PUBLIC_CLOUD"]); - - delete templateJSON["VCENTER_PUBLIC_CLOUD"]; + if (templateJSON['PUBLIC_CLOUD'] == undefined) { + templateJSON['PUBLIC_CLOUD'] = []; } // PCI with TYPE=NIC is not defined in the 'other' tab. Because it is diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/context.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/context.js index 5376b7af0e..3c28a8ffe0 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/context.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/context.js @@ -190,8 +190,8 @@ define(function(require) { var customization = WizardFields.retrieveInput($('input.vcenter_customizations_value', context)); if (customization) { - templateJSON["VCENTER_PUBLIC_CLOUD"] = { - CUSTOMIZATION_SPEC : customization + templateJSON["USER_TEMPLATE"] = { + VCENTER_CUSTOMIZATION_SPEC : customization }; } } else { @@ -258,8 +258,8 @@ define(function(require) { if(this["TYPE"] == "vcenter"){ $("input#context_type_vcenter", context).click(); - if(this["CUSTOMIZATION_SPEC"]){ - WizardFields.fillInput($('input.vcenter_customizations_value', context), this["CUSTOMIZATION_SPEC"]); + if(this["VCENTER_CUSTOMIZATION_SPEC"]){ + WizardFields.fillInput($('input.vcenter_customizations_value', context), this["VCENTER_CUSTOMIZATION_SPEC"]); } else if(userInputsJSON || contextJSON) { $("input#context_type_opennebula", context).click(); } diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js index 4945e55170..1b014d8544 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js @@ -160,9 +160,9 @@ define(function(require) { $(".only_" + this.value).show(); if (this.value == "vcenter"){ - $("#vcenter_template_uuid", context).attr("required", ""); + $("#vcenter_template_ref", context).attr("required", ""); } else { - $("#vcenter_template_uuid", context).removeAttr("required"); + $("#vcenter_template_ref", context).removeAttr("required"); } // There is another listener in context.js setup }); @@ -187,10 +187,7 @@ define(function(require) { if(templateJSON["MEMORY_UNIT_COST"] == "GB") templateJSON["MEMORY_COST"] = templateJSON["MEMORY_COST"] * 1024; if (templateJSON["HYPERVISOR"] == 'vcenter') { - templateJSON["VCENTER_PUBLIC_CLOUD"] = { - 'TYPE': 'vcenter', - 'VM_TEMPLATE': WizardFields.retrieveInput($("#vcenter_template_uuid", context)) - }; + templateJSON["VCENTER_TEMPLATE_REF"] = WizardFields.retrieveInput($("#vcenter_template_ref", context)); if (Config.isFeatureEnabled("vcenter_deploy_folder")) { templateJSON["DEPLOY_FOLDER"] = WizardFields.retrieveInput($("#vcenter_deploy_folder", context)) @@ -304,7 +301,7 @@ define(function(require) { $.each(publicClouds, function(){ if(this["TYPE"] == "vcenter"){ - WizardFields.fillInput($("#vcenter_template_uuid", context), this["VM_TEMPLATE"]); + WizardFields.fillInput($("#vcenter_template_ref", context), this["VCENTER_TEMPLATE_REF"]); return false; } }); @@ -350,6 +347,11 @@ define(function(require) { delete templateJSON["RESOURCE_POOL"]; } + if(templateJSON["VCENTER_TEMPLATE_REF"]){ + WizardFields.fillInput($("#vcenter_template_ref", context), templateJSON["VCENTER_TEMPLATE_REF"]); + delete templateJSON["VCENTER_TEMPLATE_REF"]; + } + CapacityCreate.fill($("div.capacityCreate", context), templateJSON); WizardFields.fill(context, templateJSON); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs index 02414628ef..52cb042f1e 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs @@ -56,10 +56,10 @@ {{tr "vCenter"}}